4 * Jean II - HPL 04 -> 07
6 * Main code for "ifrename". This is tool allows to rename network
7 * interfaces based on various criteria (not only wireless).
8 * You need to link this code against "iwlib.c" and "-lm".
10 * This file is released under the GPL license.
11 * Copyright (c) 2007 Jean Tourrilhes <jt@hpl.hp.com>
15 * The changelog for ifrename is in the file CHANGELOG.h ;-)
17 * This work is a nearly complete rewrite of 'nameif.c'.
18 * Original CopyRight of version of 'nameif' I used is :
19 * -------------------------------------------------------
20 * Name Interfaces based on MAC address.
21 * Writen 2000 by Andi Kleen.
22 * Subject to the Gnu Public License, version 2.
23 * TODO: make it support token ring etc.
24 * $Id: nameif.c,v 1.3 2003/03/06 23:26:52 ecki Exp $
25 * -------------------------------------------------------
27 * It started with a series of patches to nameif which never made
28 * into the regular version, and had some architecural 'issues' with
29 * those patches, which is the reason of this rewrite.
30 * Difference with standard 'nameif' :
31 * o 'nameif' has only a single selector, the interface MAC address.
32 * o Modular selector architecture, easily add new selectors.
33 * o Wide range of selector, including sysfs and sysfs symlinks...
34 * o hotplug invocation support.
35 * o module loading support.
36 * o MAC address wildcard.
37 * o Interface name wildcard ('eth*' or 'wlan*').
38 * o Non-Ethernet MAC addresses (any size, not just 48 bits)
41 /***************************** INCLUDES *****************************/
43 /* This is needed to enable GNU extensions such as getline & FNM_CASEFOLD */
48 #include <getopt.h> /* getopt_long() */
49 #include <linux/sockios.h> /* SIOCSIFNAME */
50 #include <fnmatch.h> /* fnmatch() */
51 //#include <sys/syslog.h>
53 #include "iwlib.h" /* Wireless Tools library */
55 // This would be cool, unfortunately...
56 //#include <linux/ethtool.h> /* Ethtool stuff -> struct ethtool_drvinfo */
58 /************************ CONSTANTS & MACROS ************************/
60 /* Our default configuration file */
61 const char DEFAULT_CONF[] = "/etc/iftab";
64 const char DEBIAN_CONFIG_FILE[] = "/etc/network/interfaces";
66 /* Backward compatibility */
68 #define ifr_newname ifr_ifru.ifru_slave
71 /* Types of selector we support. Must match selector_list */
72 const int SELECT_MAC = 0; /* Select by MAC address */
73 const int SELECT_ETHADDR = 1; /* Select by MAC address */
74 const int SELECT_ARP = 2; /* Select by ARP type */
75 const int SELECT_LINKTYPE = 3; /* Select by ARP type */
76 const int SELECT_DRIVER = 4; /* Select by Driver name */
77 const int SELECT_BUSINFO = 5; /* Select by Bus-Info */
78 const int SELECT_FIRMWARE = 6; /* Select by Firmware revision */
79 const int SELECT_BASEADDR = 7; /* Select by HW Base Address */
80 const int SELECT_IRQ = 8; /* Select by HW Irq line */
81 const int SELECT_INTERRUPT = 9; /* Select by HW Irq line */
82 const int SELECT_IWPROTO = 10; /* Select by Wireless Protocol */
83 const int SELECT_PCMCIASLOT = 11; /* Select by Pcmcia Slot */
84 const int SELECT_SYSFS = 12; /* Select by sysfs file */
85 const int SELECT_PREVNAME = 13; /* Select by previous interface name */
88 #define HAS_MAC_EXACT 1
89 #define HAS_MAC_FILTER 2
90 #define MAX_MAC_LEN 16 /* Maximum lenght of MAC address */
92 const struct ether_addr zero_mac = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
94 const struct option long_opt[] =
96 {"config-file", 1, NULL, 'c' },
97 {"debian", 0, NULL, 'd' },
98 {"dry-run", 0, NULL, 'D' },
99 {"help", 0, NULL, '?' },
100 {"interface", 1, NULL, 'i' },
101 {"newname", 1, NULL, 'n' },
102 {"takeover", 0, NULL, 't' },
103 {"udev", 0, NULL, 'u' },
104 {"version", 0, NULL, 'v' },
105 {"verbose", 0, NULL, 'V' },
106 {NULL, 0, NULL, '\0' },
109 /* Pcmcia stab files */
110 #define PCMCIA_STAB1 "/var/lib/pcmcia/stab"
111 #define PCMCIA_STAB2 "/var/run/stab"
113 /* Max number of sysfs file types we support */
114 #define SYSFS_MAX_FILE 8
116 /* Userspace headers lag, fix that... */
117 #ifndef ARPHRD_IEEE1394
118 #define ARPHRD_IEEE1394 24
121 #define ARPHRD_EUI64 27
124 #define ARPHRD_IRDA 783
127 /* Length of various non-standard MAC addresses */
128 const int weird_mac_len[][2] =
130 { ARPHRD_IEEE1394, 8 },
134 const int weird_mac_len_num = sizeof(weird_mac_len) / sizeof(weird_mac_len[0]);
136 /****************************** TYPES ******************************/
138 /* Cut'n'paste from ethtool.h */
139 #define ETHTOOL_BUSINFO_LEN 32
140 /* these strings are set to whatever the driver author decides... */
141 struct ethtool_drvinfo {
143 char driver[32]; /* driver short name, "tulip", "eepro100" */
144 char version[32]; /* driver version string */
145 char fw_version[32]; /* firmware version string, if applicable */
146 char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */
147 /* For PCI devices, use pci_dev->slot_name. */
150 __u32 n_stats; /* number of u64's from ETHTOOL_GSTATS */
152 __u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */
153 __u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */
155 #define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */
157 /* Description of an interface mapping */
158 typedef struct if_mapping
161 struct if_mapping * next;
163 /* Name of this interface */
164 char ifname[IFNAMSIZ+1];
165 char * sysfs_devpath;
168 /* Selectors for this interface */
169 int active[SELECT_NUM]; /* Selectors active */
172 unsigned char mac[MAX_MAC_LEN]; /* Exact MAC address, hex */
173 int mac_len; /* Length (usually 6) */
174 char mac_filter[16*3 + 1]; /* WildCard, ascii */
175 unsigned short hw_type; /* Link/ARP type */
176 char driver[32]; /* driver short name */
177 char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */
178 char fw_version[32]; /* Firmware revision */
179 unsigned short base_addr; /* HW Base I/O address */
180 unsigned char irq; /* HW irq line */
181 char iwproto[IFNAMSIZ + 1]; /* Wireless/protocol name */
182 int pcmcia_slot; /* Pcmcia slot */
183 char * sysfs[SYSFS_MAX_FILE]; /* sysfs selectors */
184 char prevname[IFNAMSIZ+1]; /* previous interface name */
187 /* Extra parsing information when adding a mapping */
188 typedef struct add_extra
190 char * modif_pos; /* Descriptor modifier */
194 /* Prototype for adding a selector to a mapping. Return -1 if invalid value. */
195 typedef int (*mapping_add)(struct if_mapping * ifnode,
199 struct add_extra * extra,
202 /* Prototype for comparing the selector of two mapping. Return 0 if matches. */
203 typedef int (*mapping_cmp)(struct if_mapping * ifnode,
204 struct if_mapping * target);
205 /* Prototype for extracting selector value from live interface */
206 typedef int (*mapping_get)(int skfd,
208 struct if_mapping * target,
211 /* How to handle a selector */
212 typedef struct mapping_selector
220 /* sysfs global data */
221 typedef struct sysfs_metadata
223 char * root; /* Root of the sysfs */
224 int rlen; /* Size of it */
225 int filenum; /* Number of files */
226 char * filename[SYSFS_MAX_FILE]; /* Name of files */
229 /**************************** PROTOTYPES ****************************/
232 mapping_addmac(struct if_mapping * ifnode,
236 struct add_extra * extra,
239 mapping_cmpmac(struct if_mapping * ifnode,
240 struct if_mapping * target);
242 mapping_getmac(int skfd,
244 struct if_mapping * target,
247 mapping_addarp(struct if_mapping * ifnode,
251 struct add_extra * extra,
254 mapping_cmparp(struct if_mapping * ifnode,
255 struct if_mapping * target);
257 mapping_getarp(int skfd,
259 struct if_mapping * target,
262 mapping_adddriver(struct if_mapping * ifnode,
266 struct add_extra * extra,
269 mapping_cmpdriver(struct if_mapping * ifnode,
270 struct if_mapping * target);
272 mapping_addbusinfo(struct if_mapping * ifnode,
276 struct add_extra * extra,
279 mapping_cmpbusinfo(struct if_mapping * ifnode,
280 struct if_mapping * target);
282 mapping_addfirmware(struct if_mapping * ifnode,
286 struct add_extra * extra,
289 mapping_cmpfirmware(struct if_mapping * ifnode,
290 struct if_mapping * target);
292 mapping_getdriverbusinfo(int skfd,
294 struct if_mapping * target,
297 mapping_addbaseaddr(struct if_mapping * ifnode,
301 struct add_extra * extra,
304 mapping_cmpbaseaddr(struct if_mapping * ifnode,
305 struct if_mapping * target);
307 mapping_addirq(struct if_mapping * ifnode,
311 struct add_extra * extra,
314 mapping_cmpirq(struct if_mapping * ifnode,
315 struct if_mapping * target);
317 mapping_getbaseaddrirq(int skfd,
319 struct if_mapping * target,
322 mapping_addiwproto(struct if_mapping * ifnode,
326 struct add_extra * extra,
329 mapping_cmpiwproto(struct if_mapping * ifnode,
330 struct if_mapping * target);
332 mapping_getiwproto(int skfd,
334 struct if_mapping * target,
337 mapping_addpcmciaslot(struct if_mapping * ifnode,
341 struct add_extra * extra,
344 mapping_cmppcmciaslot(struct if_mapping * ifnode,
345 struct if_mapping * target);
347 mapping_getpcmciaslot(int skfd,
349 struct if_mapping * target,
352 mapping_addsysfs(struct if_mapping * ifnode,
356 struct add_extra * extra,
359 mapping_cmpsysfs(struct if_mapping * ifnode,
360 struct if_mapping * target);
362 mapping_getsysfs(int skfd,
364 struct if_mapping * target,
367 mapping_addprevname(struct if_mapping * ifnode,
371 struct add_extra * extra,
374 mapping_cmpprevname(struct if_mapping * ifnode,
375 struct if_mapping * target);
377 mapping_getprevname(int skfd,
379 struct if_mapping * target,
382 /**************************** VARIABLES ****************************/
384 /* List of mapping read for config file */
385 struct if_mapping * mapping_list = NULL;
387 /* List of selectors we can handle */
388 const struct mapping_selector selector_list[] =
390 /* MAC address and ARP/Link type from ifconfig */
391 { "mac", &mapping_addmac, &mapping_cmpmac, &mapping_getmac },
392 { "ethaddr", &mapping_addmac, &mapping_cmpmac, &mapping_getmac },
393 { "arp", &mapping_addarp, &mapping_cmparp, &mapping_getarp },
394 { "linktype", &mapping_addarp, &mapping_cmparp, &mapping_getarp },
395 /* Driver name, Bus-Info and firmware rev from ethtool -i */
396 { "driver", &mapping_adddriver, &mapping_cmpdriver,
397 &mapping_getdriverbusinfo },
398 { "businfo", &mapping_addbusinfo, &mapping_cmpbusinfo,
399 &mapping_getdriverbusinfo },
400 { "firmware", &mapping_addfirmware, &mapping_cmpfirmware,
401 &mapping_getdriverbusinfo },
402 /* Base Address and IRQ from ifconfig */
403 { "baseaddress", &mapping_addbaseaddr, &mapping_cmpbaseaddr,
404 &mapping_getbaseaddrirq },
405 { "irq", &mapping_addirq, &mapping_cmpirq, &mapping_getbaseaddrirq },
406 { "interrupt", &mapping_addirq, &mapping_cmpirq, &mapping_getbaseaddrirq },
407 /* Wireless Protocol from iwconfig */
408 { "iwproto", &mapping_addiwproto, &mapping_cmpiwproto, &mapping_getiwproto },
409 /* Pcmcia slot from cardmgr */
410 { "pcmciaslot", &mapping_addpcmciaslot, &mapping_cmppcmciaslot, &mapping_getpcmciaslot },
411 /* sysfs file (udev emulation) */
412 { "sysfs", &mapping_addsysfs, &mapping_cmpsysfs, &mapping_getsysfs },
413 /* previous interface name */
414 { "prevname", &mapping_addprevname, &mapping_cmpprevname, &mapping_getprevname },
416 { NULL, NULL, NULL, NULL },
418 const int selector_num = sizeof(selector_list)/sizeof(selector_list[0]);
420 /* List of active selectors */
421 int selector_active[SELECT_NUM]; /* Selectors active */
424 * All the following flags are controlled by the command line switches...
425 * It's a bit hackish to have them all as global, so maybe we should pass
426 * them in a big struct as function arguments... More complex and
427 * probably not worth it ?
430 /* Invocation type */
431 int print_newname = 0;
432 char * new_name = NULL;
434 /* Takeover support */
435 int force_takeover = 0; /* Takeover name from other interfaces */
436 int num_takeover = 0; /* Number of takeover done */
438 /* Number of mapping matched */
439 int num_mapping_match = 0;
441 /* Dry-run support */
442 int dry_run = 0; /* Just print new name, don't rename */
444 /* Verbose support (i.e. debugging) */
447 /* udev output support (print new DEVPATH) */
450 /* sysfs global data */
451 struct sysfs_metadata sysfs_global =
454 0, { NULL, NULL, NULL, NULL, NULL },
457 /******************** INTERFACE NAME MANAGEMENT ********************/
459 * Bunch of low level function for managing interface names.
462 /*------------------------------------------------------------------*/
464 * Compare two interface names, with wildcards.
465 * We can't use fnmatch() because we don't want expansion of '[...]'
466 * expressions, '\' sequences and matching of '.'.
467 * We only want to match a single '*' (converted to a %d at that point)
468 * to a numerical value (no ascii).
469 * Return 0 is matches.
472 if_match_ifname(const char * pattern,
480 /* Check for a wildcard */
481 p = strchr(pattern, '*');
483 /* No wildcard, simple comparison */
485 return(strcmp(pattern, value));
487 /* Check is prefixes match */
489 ret = strncmp(pattern, value, n);
493 /* Check that value has some digits at this point */
498 /* Skip digits to go to value suffix */
506 /* Compare suffixes */
507 return(strcmp(p, v));
510 /*------------------------------------------------------------------*/
512 * Steal interface name from another interface. This enable interface
515 * 1) with kernel 2.6.X
516 * 2) if other interface is down
517 * Because of (2), it won't work with hotplug, but we don't need it
518 * with hotplug, only with static ifaces...
521 if_takeover_name(int skfd,
522 const char * victimname)
524 char autoname[IFNAMSIZ+1];
529 /* Compute name for victim interface */
530 len = strlen(victimname);
531 memcpy(autoname, victimname, len + 1);
532 if(len > (IFNAMSIZ - 2))
533 len = IFNAMSIZ - 2; /* Make sure we have at least two char */
534 len--; /* Convert to index */
535 while(isdigit(autoname[len]))
536 len--; /* Scrap all trailing digits */
537 strcpy(autoname + len + 1, "%d");
540 fprintf(stderr, "Takeover : moving interface `%s' to `%s'.\n",
541 victimname, autoname);
543 /* Prepare request */
544 bzero(&ifr, sizeof(struct ifreq));
545 strncpy(ifr.ifr_name, victimname, IFNAMSIZ);
546 strncpy(ifr.ifr_newname, autoname, IFNAMSIZ);
548 /* Rename victim interface */
549 ret = ioctl(skfd, SIOCSIFNAME, &ifr);
557 /*------------------------------------------------------------------*/
559 * Ask the kernel to change the name of an interface.
560 * That's what we want to do. All the rest is to make sure we call this
564 if_set_name(int skfd,
565 const char * oldname,
566 const char * newname,
573 /* The kernel doesn't check is the interface already has the correct
574 * name and may return an error, so check ourselves.
575 * In the case of wildcard, the result can be weird : if oldname='eth0'
576 * and newname='eth*', retname would be 'eth1'.
577 * So, if the oldname value matches the newname pattern, just return
579 if(!if_match_ifname(newname, oldname))
582 fprintf(stderr, "Setting : Interface `%s' already matches `%s'.\n",
585 strcpy(retname, oldname);
589 /* Prepare request */
590 bzero(&ifr, sizeof(struct ifreq));
591 strncpy(ifr.ifr_name, oldname, IFNAMSIZ);
592 strncpy(ifr.ifr_newname, newname, IFNAMSIZ);
594 /* Check for wildcard interface name, such as 'eth*' or 'wlan*'...
595 * This require specific kernel support (2.6.2-rc1 and later).
596 * We externally use '*', but the kernel doesn't know about that,
597 * so convert it to something it knows about... */
598 star = strchr(newname, '*');
601 int slen = star - newname;
602 /* Replace '*' with '%d' in the new buffer */
603 star = ifr.ifr_newname + slen;
604 /* Size was checked in process_rename() and mapping_create() */
605 memmove(star + 2, star + 1, IFNAMSIZ - slen - 2);
611 ret = ioctl(skfd, SIOCSIFNAME, &ifr);
613 /* Takeover support : grab interface name from another interface */
614 if(ret && (errno == EEXIST) && force_takeover)
616 /* Push things around */
617 ret = if_takeover_name(skfd, newname);
620 ret = ioctl(skfd, SIOCSIFNAME, &ifr);
625 /* Get the real new name (in case newname is a wildcard) */
626 strcpy(retname, ifr.ifr_newname);
629 fprintf(stderr, "Setting : Interface `%s' renamed to `%s'.\n",
636 /************************ SELECTOR HANDLING ************************/
638 * Handle the various selector we support
641 /*------------------------------------------------------------------*/
643 * Add a MAC address selector to a mapping
646 mapping_addmac(struct if_mapping * ifnode,
650 struct add_extra * extra,
655 /* Avoid "Unused parameter" warning */
658 /* Verify validity of string */
659 if(len >= sizeof(ifnode->mac_filter))
661 fprintf(stderr, "Error : MAC address too long at line %d\n", linenum);
664 n = strspn(string, "0123456789ABCDEFabcdef:*");
667 fprintf(stderr, "Error: Invalid MAC address `%s' at line %d\n",
672 /* Copy as filter in all cases */
673 memcpy(ifnode->mac_filter, string, len + 1);
675 /* Check the type of MAC address */
676 if (strchr(ifnode->mac_filter, '*') != NULL)
678 /* This is a wilcard. Usual format : "01:23:45:*"
679 * Unfortunately, we can't do proper parsing. */
680 ifnode->active[SELECT_MAC] = HAS_MAC_FILTER;
681 active[SELECT_MAC] = HAS_MAC_FILTER;
685 /* Not a wildcard : "01:23:45:67:89:AB" */
686 ifnode->mac_len = iw_mac_aton(ifnode->mac_filter,
687 ifnode->mac, MAX_MAC_LEN);
688 if(ifnode->mac_len == 0)
690 fprintf(stderr, "Error: Invalid MAC address `%s' at line %d\n",
691 ifnode->mac_filter, linenum);
695 /* Check that it's not NULL */
696 if((ifnode->mac_len == 6) && (!memcmp(&ifnode->mac, &zero_mac, 6)))
699 "Warning: MAC address is null at line %d, this is dangerous...\n",
703 ifnode->active[SELECT_MAC] = HAS_MAC_EXACT;
704 if(active[SELECT_MAC] == 0)
705 active[SELECT_MAC] = HAS_MAC_EXACT;
710 "Parsing : Added %s MAC address `%s' from line %d.\n",
711 ifnode->active[SELECT_MAC] == HAS_MAC_FILTER ? "filter" : "exact",
712 ifnode->mac_filter, linenum);
717 /*------------------------------------------------------------------*/
719 * Compare the mac address of two mappings
722 mapping_cmpmac(struct if_mapping * ifnode,
723 struct if_mapping * target)
725 /* Check for wildcard matching */
726 if(ifnode->active[SELECT_MAC] == HAS_MAC_FILTER)
727 /* Do wildcard matching, case insensitive */
728 return(fnmatch(ifnode->mac_filter, target->mac_filter, FNM_CASEFOLD));
730 /* Exact matching, in hex */
731 return((ifnode->mac_len != target->mac_len) ||
732 memcmp(ifnode->mac, target->mac, ifnode->mac_len));
735 /*------------------------------------------------------------------*/
737 * Extract the MAC address and Link Type of an interface
740 mapping_getmac(int skfd,
742 struct if_mapping * target,
749 /* Get MAC address */
750 bzero(&ifr, sizeof(struct ifreq));
751 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
752 ret = ioctl(skfd, SIOCGIFHWADDR, &ifr);
755 fprintf(stderr, "Error: Can't read MAC address on interface `%s' : %s\n",
756 ifname, strerror(errno));
760 /* Extract ARP type */
761 target->hw_type = ifr.ifr_hwaddr.sa_family;
762 /* Calculate address length */
764 for(i = 0; i < weird_mac_len_num; i++)
765 if(weird_mac_len[i][0] == ifr.ifr_hwaddr.sa_family)
767 target->mac_len = weird_mac_len[i][1];
770 /* Extract MAC address bytes */
771 memcpy(target->mac, ifr.ifr_hwaddr.sa_data, target->mac_len);
773 /* Check the type of comparison */
774 if((flag == HAS_MAC_FILTER) || verbose)
776 /* Convert to ASCII */
777 iw_mac_ntop(target->mac, target->mac_len,
778 target->mac_filter, sizeof(target->mac_filter));
781 target->active[SELECT_MAC] = flag;
782 target->active[SELECT_ARP] = 1;
786 "Querying %s : Got MAC address `%s' and ARP/Link Type `%d'.\n",
787 ifname, target->mac_filter, target->hw_type);
792 /*------------------------------------------------------------------*/
794 * Add a ARP/Link type selector to a mapping
797 mapping_addarp(struct if_mapping * ifnode,
801 struct add_extra * extra,
807 /* Avoid "Unused parameter" warning */
810 /* Verify validity of string, convert to int */
811 n = strspn(string, "0123456789");
812 if((n < len) || (sscanf(string, "%d", &type) != 1))
814 fprintf(stderr, "Error: Invalid ARP/Link Type `%s' at line %d\n",
819 ifnode->hw_type = (unsigned short) type;
820 ifnode->active[SELECT_ARP] = 1;
821 active[SELECT_ARP] = 1;
824 fprintf(stderr, "Parsing : Added ARP/Link Type `%d' from line %d.\n",
825 ifnode->hw_type, linenum);
830 /*------------------------------------------------------------------*/
832 * Compare the ARP/Link type of two mappings
835 mapping_cmparp(struct if_mapping * ifnode,
836 struct if_mapping * target)
838 return(!(ifnode->hw_type == target->hw_type));
841 /*------------------------------------------------------------------*/
843 * Extract the ARP/Link type of an interface
846 mapping_getarp(int skfd,
848 struct if_mapping * target,
851 /* We may have already extracted the MAC address */
852 if(target->active[SELECT_MAC])
855 /* Otherwise just do it */
856 return(mapping_getmac(skfd, ifname, target, flag));
859 /*------------------------------------------------------------------*/
861 * Add a Driver name selector to a mapping
864 mapping_adddriver(struct if_mapping * ifnode,
868 struct add_extra * extra,
871 /* Avoid "Unused parameter" warning */
874 /* Plain string, minimal verification */
875 if(len >= sizeof(ifnode->driver))
877 fprintf(stderr, "Error: Driver name too long at line %d\n", linenum);
882 memcpy(ifnode->driver, string, len + 1);
885 ifnode->active[SELECT_DRIVER] = 1;
886 active[SELECT_DRIVER] = 1;
890 "Parsing : Added Driver name `%s' from line %d.\n",
891 ifnode->driver, linenum);
896 /*------------------------------------------------------------------*/
898 * Compare the Driver name of two mappings
901 mapping_cmpdriver(struct if_mapping * ifnode,
902 struct if_mapping * target)
904 /* Do wildcard matching, case insensitive */
905 return(fnmatch(ifnode->driver, target->driver, FNM_CASEFOLD));
908 /*------------------------------------------------------------------*/
910 * Add a Bus-Info selector to a mapping
913 mapping_addbusinfo(struct if_mapping * ifnode,
917 struct add_extra * extra,
924 /* Avoid "Unused parameter" warning */
927 /* Verify validity of string */
928 if(len >= sizeof(ifnode->bus_info))
930 fprintf(stderr, "Bus Info too long at line %d\n", linenum);
934 /* Hum... This doesn's seem true for non-PCI bus-info */
935 n = strspn(string, "0123456789ABCDEFabcdef:.*");
938 fprintf(stderr, "Error: Invalid Bus Info `%s' at line %d\n",
945 memcpy(ifnode->bus_info, string, len + 1);
948 ifnode->active[SELECT_BUSINFO] = 1;
949 active[SELECT_BUSINFO] = 1;
953 "Parsing : Added Bus Info `%s' from line %d.\n",
954 ifnode->bus_info, linenum);
959 /*------------------------------------------------------------------*/
961 * Compare the Bus-Info of two mappings
964 mapping_cmpbusinfo(struct if_mapping * ifnode,
965 struct if_mapping * target)
967 /* Do wildcard matching, case insensitive */
968 return(fnmatch(ifnode->bus_info, target->bus_info, FNM_CASEFOLD));
971 /*------------------------------------------------------------------*/
973 * Add a Firmare revision selector to a mapping
976 mapping_addfirmware(struct if_mapping * ifnode,
980 struct add_extra * extra,
983 /* Avoid "Unused parameter" warning */
986 /* Verify validity of string */
987 if(len >= sizeof(ifnode->fw_version))
989 fprintf(stderr, "Firmware revision too long at line %d\n", linenum);
994 memcpy(ifnode->fw_version, string, len + 1);
997 ifnode->active[SELECT_FIRMWARE] = 1;
998 active[SELECT_FIRMWARE] = 1;
1002 "Parsing : Added Firmware Revision `%s' from line %d.\n",
1003 ifnode->fw_version, linenum);
1008 /*------------------------------------------------------------------*/
1010 * Compare the Bus-Info of two mappings
1013 mapping_cmpfirmware(struct if_mapping * ifnode,
1014 struct if_mapping * target)
1016 /* Do wildcard matching, case insensitive */
1017 return(fnmatch(ifnode->fw_version, target->fw_version, FNM_CASEFOLD));
1020 /*------------------------------------------------------------------*/
1022 * Extract the Driver name and Bus-Info from a live interface
1025 mapping_getdriverbusinfo(int skfd,
1026 const char * ifname,
1027 struct if_mapping * target,
1031 struct ethtool_drvinfo drvinfo;
1034 /* Avoid "Unused parameter" warning */
1037 /* We may come here twice or more, so do the job only once */
1038 if(target->active[SELECT_DRIVER] || target->active[SELECT_BUSINFO]
1039 || target->active[SELECT_FIRMWARE])
1042 /* Prepare request */
1043 bzero(&ifr, sizeof(struct ifreq));
1044 bzero(&drvinfo, sizeof(struct ethtool_drvinfo));
1045 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
1046 drvinfo.cmd = ETHTOOL_GDRVINFO;
1047 ifr.ifr_data = (caddr_t) &drvinfo;
1050 ret = ioctl(skfd, SIOCETHTOOL, &ifr);
1053 /* Most drivers don't support that, keep quiet for now */
1056 "Error: Can't read driver/bus-info on interface `%s' : %s\n",
1057 ifname, strerror(errno));
1062 strcpy(target->driver, drvinfo.driver);
1063 strcpy(target->bus_info, drvinfo.bus_info);
1064 strcpy(target->fw_version, drvinfo.fw_version);
1067 target->active[SELECT_DRIVER] = 1;
1068 target->active[SELECT_BUSINFO] = 1;
1069 target->active[SELECT_FIRMWARE] = 1;
1073 "Querying %s : Got Driver name `%s', Bus Info `%s' and Firmware `%s'.\n",
1074 ifname, target->driver, target->bus_info, target->fw_version);
1079 /*------------------------------------------------------------------*/
1081 * Add a Base Address selector to a mapping
1084 mapping_addbaseaddr(struct if_mapping * ifnode,
1088 struct add_extra * extra,
1092 unsigned int address;
1094 /* Avoid "Unused parameter" warning */
1097 /* Verify validity of string */
1098 n = strspn(string, "0123456789ABCDEFabcdefx");
1099 if((n < len) || (sscanf(string, "0x%X", &address) != 1))
1101 fprintf(stderr, "Error: Invalid Base Address `%s' at line %d\n",
1107 ifnode->base_addr = (unsigned short) address;
1110 ifnode->active[SELECT_BASEADDR] = 1;
1111 active[SELECT_BASEADDR] = 1;
1115 "Parsing : Added Base Address `0x%X' from line %d.\n",
1116 ifnode->base_addr, linenum);
1121 /*------------------------------------------------------------------*/
1123 * Compare the Base Address of two mappings
1126 mapping_cmpbaseaddr(struct if_mapping * ifnode,
1127 struct if_mapping * target)
1129 /* Do wildcard matching, case insensitive */
1130 return(!(ifnode->base_addr == target->base_addr));
1133 /*------------------------------------------------------------------*/
1135 * Add a IRQ selector to a mapping
1138 mapping_addirq(struct if_mapping * ifnode,
1142 struct add_extra * extra,
1148 /* Avoid "Unused parameter" warning */
1151 /* Verify validity of string */
1152 n = strspn(string, "0123456789");
1153 if((n < len) || (sscanf(string, "%d", &irq) != 1))
1155 fprintf(stderr, "Error: Invalid Base Address `%s' at line %d\n",
1161 ifnode->irq = (unsigned char) irq;
1164 ifnode->active[SELECT_IRQ] = 1;
1165 active[SELECT_IRQ] = 1;
1169 "Parsing : Added IRQ `%d' from line %d.\n",
1170 ifnode->irq, linenum);
1175 /*------------------------------------------------------------------*/
1177 * Compare the IRQ of two mappings
1180 mapping_cmpirq(struct if_mapping * ifnode,
1181 struct if_mapping * target)
1183 /* Do wildcard matching, case insensitive */
1184 return(!(ifnode->irq == target->irq));
1187 /*------------------------------------------------------------------*/
1189 * Extract the Driver name and Bus-Info from a live interface
1192 mapping_getbaseaddrirq(int skfd,
1193 const char * ifname,
1194 struct if_mapping * target,
1198 struct ifmap map; /* hardware setup */
1201 /* Avoid "Unused parameter" warning */
1204 /* We may come here twice, so do the job only once */
1205 if(target->active[SELECT_BASEADDR] || target->active[SELECT_IRQ])
1208 /* Prepare request */
1209 bzero(&ifr, sizeof(struct ifreq));
1210 bzero(&map, sizeof(struct ifmap));
1211 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
1214 ret = ioctl(skfd, SIOCGIFMAP, &ifr);
1217 /* Don't know if every interface has that, so keep quiet... */
1220 "Error: Can't read base address/irq on interface `%s' : %s\n",
1221 ifname, strerror(errno));
1225 /* Copy over, activate */
1226 if(ifr.ifr_map.base_addr >= 0x100)
1228 target->base_addr = ifr.ifr_map.base_addr;
1229 target->active[SELECT_BASEADDR] = 1;
1231 target->irq = ifr.ifr_map.irq;
1232 target->active[SELECT_IRQ] = 1;
1236 "Querying %s : Got Base Address `0x%X' and IRQ `%d'.\n",
1237 ifname, target->base_addr, target->irq);
1242 /*------------------------------------------------------------------*/
1244 * Add a Wireless Protocol selector to a mapping
1247 mapping_addiwproto(struct if_mapping * ifnode,
1251 struct add_extra * extra,
1254 /* Avoid "Unused parameter" warning */
1257 /* Verify validity of string */
1258 if(len >= sizeof(ifnode->iwproto))
1260 fprintf(stderr, "Wireless Protocol too long at line %d\n", linenum);
1265 memcpy(ifnode->iwproto, string, len + 1);
1268 ifnode->active[SELECT_IWPROTO] = 1;
1269 active[SELECT_IWPROTO] = 1;
1273 "Parsing : Added Wireless Protocol `%s' from line %d.\n",
1274 ifnode->iwproto, linenum);
1279 /*------------------------------------------------------------------*/
1281 * Compare the Wireless Protocol of two mappings
1284 mapping_cmpiwproto(struct if_mapping * ifnode,
1285 struct if_mapping * target)
1287 /* Do wildcard matching, case insensitive */
1288 return(fnmatch(ifnode->iwproto, target->iwproto, FNM_CASEFOLD));
1291 /*------------------------------------------------------------------*/
1293 * Extract the Wireless Protocol from a live interface
1296 mapping_getiwproto(int skfd,
1297 const char * ifname,
1298 struct if_mapping * target,
1303 /* Avoid "Unused parameter" warning */
1306 /* Get wireless name */
1307 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
1308 /* Don't complain about it, Ethernet cards will never support this */
1311 strncpy(target->iwproto, wrq.u.name, IFNAMSIZ);
1312 target->iwproto[IFNAMSIZ] = '\0';
1315 target->active[SELECT_IWPROTO] = 1;
1319 "Querying %s : Got Wireless Protocol `%s'.\n",
1320 ifname, target->iwproto);
1325 /*------------------------------------------------------------------*/
1327 * Add a Pcmcia Slot selector to a mapping
1330 mapping_addpcmciaslot(struct if_mapping * ifnode,
1334 struct add_extra * extra,
1339 /* Avoid "Unused parameter" warning */
1342 /* Verify validity of string, convert to int */
1343 n = strspn(string, "0123456789");
1344 if((n < len) || (sscanf(string, "%d", &ifnode->pcmcia_slot) != 1))
1346 fprintf(stderr, "Error: Invalid Pcmcia Slot `%s' at line %d\n",
1351 ifnode->active[SELECT_PCMCIASLOT] = 1;
1352 active[SELECT_PCMCIASLOT] = 1;
1355 fprintf(stderr, "Parsing : Added Pcmcia Slot `%d' from line %d.\n",
1356 ifnode->pcmcia_slot, linenum);
1361 /*------------------------------------------------------------------*/
1363 * Compare the Pcmcia Slot of two mappings
1366 mapping_cmppcmciaslot(struct if_mapping * ifnode,
1367 struct if_mapping * target)
1369 return(!(ifnode->pcmcia_slot == target->pcmcia_slot));
1372 /*------------------------------------------------------------------*/
1374 * Extract the Pcmcia Slot of an interface
1375 * Note that this works only for cards fully managed by cardmgr.
1376 * With the kernel pcmcia modules, 32 bits cards (CardBus) are not managed
1377 * by cardmgr, and therefore won't have a valid slot number. For those
1378 * cards, you should use Bus Info (when the driver exports it).
1379 * In the long term, 16 bits card as well will no longer be managed by
1380 * cardmgr. Currently, Bus Info for 16 bit cards don't have any information
1381 * enabling to locate their physical location on the system, but I hope that
1383 * When that happen, we can drop this code...
1386 mapping_getpcmciaslot(int skfd,
1387 const char * ifname,
1388 struct if_mapping * target,
1392 char * linebuf = NULL;
1396 /* Avoid "Unused parameter" warning */
1400 /* Open the stab file for reading */
1401 stream = fopen(PCMCIA_STAB1, "r");
1404 /* Try again, alternate location */
1405 stream = fopen(PCMCIA_STAB2, "r");
1408 fprintf(stderr, "Error: Can't open PCMCIA Stab file `%s' or `%s': %s\n",
1409 PCMCIA_STAB1, PCMCIA_STAB2, strerror(errno));
1414 /* Read each line of file
1415 * getline is a GNU extension :-( The buffer is recycled and increased
1416 * as needed by getline. */
1417 while(getline(&linebuf, &linelen, stream) > 0)
1425 /* Keep track of line number */
1428 /* Get Pcmcia socket number */
1433 continue; /* Line ended */
1434 n = strcspn(p, " \t\n");
1435 k = strspn(p, "0123456789");
1436 if((k < n) || (sscanf(p, "%d", &pcmcia_slot) != 1))
1440 /* Skip socket number */
1441 /* Skip socket number ; device class ; driver name ; instance */
1442 for(i = 0; i < 4; i++)
1447 p += strspn(p, " \t\n");
1449 break; /* Line ended */
1450 /* Next item size */
1451 n = strcspn(p, " \t\n");
1454 continue; /* Line ended */
1456 /* Terminate dev name */
1459 /* Compare to interface name */
1460 if(!strcmp(p, ifname))
1463 target->pcmcia_slot = pcmcia_slot;
1466 target->active[SELECT_PCMCIASLOT] = 1;
1470 "Querying %s : Got Pcmcia Slot `%d'.\n",
1471 ifname, target->pcmcia_slot);
1472 /* Exit loop, found it */
1476 /* Finished -> next line */
1483 return(target->active[SELECT_PCMCIASLOT] ? 0 : -1);
1486 /*------------------------------------------------------------------*/
1488 * Add a sysfs selector to a mapping
1491 mapping_addsysfs(struct if_mapping * ifnode,
1495 struct add_extra * extra,
1498 int findex; /* filename index */
1501 /* Check if we have a modifier */
1502 if((extra == NULL) || (extra->modif_pos == NULL))
1504 fprintf(stderr, "Error: No SYSFS filename at line %d\n", linenum);
1508 /* Search if the filename already exist */
1509 for(findex = 0; findex < sysfs_global.filenum; findex++)
1511 if(!strcmp(extra->modif_pos, sysfs_global.filename[findex]))
1515 /* If filename does not exist, creates it */
1516 if(findex == sysfs_global.filenum)
1518 if(findex == SYSFS_MAX_FILE)
1520 fprintf(stderr, "Error: Too many SYSFS filenames at line %d\n", linenum);
1523 sdup = strndup(extra->modif_pos, extra->modif_len);
1526 fprintf(stderr, "Error: Can't allocate SYSFS file\n");
1529 sysfs_global.filename[findex] = sdup;
1530 sysfs_global.filenum++;
1534 sdup = strndup(string, len);
1537 fprintf(stderr, "Error: Can't allocate SYSFS value\n");
1540 ifnode->sysfs[findex] = sdup;
1543 ifnode->active[SELECT_SYSFS] = 1;
1544 active[SELECT_SYSFS] = 1;
1548 "Parsing : Added SYSFS filename `%s' value `%s' from line %d.\n",
1549 sysfs_global.filename[findex], ifnode->sysfs[findex], linenum);
1554 /*------------------------------------------------------------------*/
1556 * Compare all the sysfs values of two mappings
1559 mapping_cmpsysfs(struct if_mapping * ifnode,
1560 struct if_mapping * target)
1562 int findex; /* filename index */
1565 /* Loop on all sysfs selector */
1566 for(findex = 0; findex < sysfs_global.filenum; findex++)
1568 /* If the mapping defines this sysfs selector.. */
1569 if(ifnode->sysfs[findex] != NULL)
1570 /* And if the sysfs values don't match */
1571 if((target->sysfs[findex] == NULL) ||
1572 (fnmatch(ifnode->sysfs[findex], target->sysfs[findex],
1574 /* Then the sysfs selector doesn't match */
1581 /*------------------------------------------------------------------*/
1583 * Extract all the sysfs values of an interface
1586 mapping_getsysfs(int skfd,
1587 const char * ifname,
1588 struct if_mapping * target,
1594 char * linebuf = NULL;
1597 int findex; /* filename index */
1599 /* Avoid "Unused parameter" warning */
1603 /* Check if we know the devpath of this device */
1604 if(target->sysfs_devpath == NULL)
1606 /* Check if we know the root of the sysfs filesystem */
1607 if(sysfs_global.root == NULL)
1609 /* Open the mount file for reading */
1610 stream = fopen("/proc/mounts", "r");
1613 fprintf(stderr, "Error: Can't open /proc/mounts file: %s\n",
1618 /* Read each line of file
1619 * getline is a GNU extension :-( The buffer is recycled and
1620 * increased as needed by getline. */
1621 while(getline(&linebuf, &linelen, stream) > 0)
1629 /* The format of /proc/mounts is similar to /etc/fstab (5).
1630 * The first argument is the device. For sysfs, there is no
1631 * associated device, so this argument is ignored.
1632 * The second argument is the mount point.
1633 * The third argument is the filesystem type.
1636 /* Extract the first 3 tokens */
1638 for(i = 0; i < 3; i++)
1643 n = strcspn(p, " \t\n");
1647 /* Get the filesystem which type is "sysfs" */
1648 if((n == 5) && (!strncasecmp(token[2], "sysfs", 5)))
1650 /* Get its mount point */
1652 sdup = strndup(token[1], n);
1653 if((n == 0) || (sdup == NULL))
1656 "Error: Can't parse /proc/mounts file: %s\n",
1661 sysfs_global.root = sdup;
1662 sysfs_global.rlen = n;
1665 /* Finished -> next line */
1671 /* Check if we found it */
1672 if(sysfs_global.root == NULL)
1675 "Error: Can't find sysfs in /proc/mounts file\n");
1681 /* Construct devpath for this interface.
1682 * Reserve enough space to replace name without realloc. */
1683 fnsize = (sysfs_global.rlen + 11 + IFNAMSIZ + 1);
1684 fname = malloc(fnsize);
1687 fprintf(stderr, "Error: Can't allocate SYSFS devpath\n");
1690 /* Not true devpath for 2.6.20+, but this syslink should work */
1691 target->sysfs_devplen = sprintf(fname, "%s/class/net/%s",
1692 sysfs_global.root, ifname);
1693 target->sysfs_devpath = fname;
1696 /* Loop on all sysfs selector */
1697 for(findex = 0; findex < sysfs_global.filenum; findex++)
1702 /* Construct complete filename for the sysfs selector */
1703 fnsize = (target->sysfs_devplen + 1 +
1704 strlen(sysfs_global.filename[findex]) + 1);
1705 fname = malloc(fnsize);
1708 fprintf(stderr, "Error: Can't allocate SYSFS filename\n");
1712 sprintf(fname, "%s/%s", target->sysfs_devpath,
1713 sysfs_global.filename[findex]);
1715 /* Open the sysfs file for reading */
1716 stream = fopen(fname, "r");
1719 /* Some sysfs attribute may no exist for some interface */
1721 fprintf(stderr, "Error: Can't open file `%s': %s\n", fname,
1723 /* Next sysfs selector */
1727 /* Read file. Only one line in file. */
1728 n = getline(&linebuf, &linelen, stream);
1732 /* Some attributes are just symlinks to another directory.
1733 * We can read the attributes in that other directory
1734 * just fine, but sometimes the symlink itself gives a lot
1736 * Examples : SYSFS{device} and SYSFS{device/driver}
1737 * In such cases, get the name of the directory pointed to...
1740 * I must note that the API for readlink() is very bad,
1741 * which force us to have this ugly code. Yuck !
1743 int allocsize = 128; /* 256 = Good start */
1745 char * linkpath = NULL;
1748 /* Try reading the link with increased buffer size */
1752 linkpath = realloc(linkpath, allocsize);
1753 pathlen = readlink(fname, linkpath, allocsize);
1754 /* If we did not hit the buffer limit, success */
1755 if(pathlen < allocsize)
1760 /* Check for error, most likely ENOENT */
1762 /* We have a symlink ;-) Terminate the string. */
1763 linkpath[pathlen] = '\0';
1769 /* A lot of information in the sysfs is implicit, given
1770 * by the position of a file in the tree. It is therefore
1771 * important to be able to read the various components
1772 * of a path. For this reason, we resolve '..' to the
1773 * real name of the parent directory... */
1774 /* We have at least 11 char, see above */
1775 if(!strcmp(fname + fnsize - 4, "/.."))
1776 //if(!strcmp(fname + strlen(fname) - 3, "/.."))
1778 /* This procedure to get the realpath is not very
1779 * nice, but it's the "best practice". Hmm... */
1780 int cwd_fd = open(".", O_RDONLY);
1784 int ret = chdir(fname);
1786 /* Using getcwd with NULL is a GNU extension. Nice. */
1787 linkpath = getcwd(NULL, 0);
1788 /* This may fail, but it's not fatal */
1791 /* Check if we suceeded */
1796 fprintf(stderr, "Error: Can't read parent directory `%s'\n", fname);
1797 /* Next sysfs selector */
1803 /* Some sysfs attribute are void for some interface,
1804 * we may have a real directory, or we may have permission
1807 fprintf(stderr, "Error: Can't read file `%s'\n", fname);
1808 /* Next sysfs selector */
1813 /* Here, we have a link name or a parent directory name */
1815 /* Keep only the last component of path name, save it */
1816 p = basename(linkpath);
1822 /* This is a regular file (well, pseudo file) */
1823 /* Get content, remove trailing '/n', save it */
1825 if(p[n - 1] == '\n')
1827 sdup = strndup(p, n);
1831 fprintf(stderr, "Error: Can't allocate SYSFS value\n");
1835 target->sysfs[findex] = sdup;
1838 target->active[SELECT_SYSFS] = 1;
1842 "Querying %s : Got SYSFS filename `%s' value `%s'.\n",
1843 ifname, sysfs_global.filename[findex], target->sysfs[findex]);
1845 /* Finished : Next sysfs selector */
1851 return(target->active[SELECT_SYSFS] ? 0 : -1);
1854 /*------------------------------------------------------------------*/
1856 * Add a Previous Interface Name selector to a mapping
1859 mapping_addprevname(struct if_mapping * ifnode,
1863 struct add_extra * extra,
1866 /* Avoid "Unused parameter" warning */
1869 /* Verify validity of string */
1870 if(len >= sizeof(ifnode->prevname))
1872 fprintf(stderr, "Old Interface Name too long at line %d\n", linenum);
1877 memcpy(ifnode->prevname, string, len + 1);
1880 ifnode->active[SELECT_PREVNAME] = 1;
1881 active[SELECT_PREVNAME] = 1;
1885 "Parsing : Added Old Interface Name `%s' from line %d.\n",
1886 ifnode->prevname, linenum);
1891 /*------------------------------------------------------------------*/
1893 * Compare the Previous Interface Name of two mappings
1894 * Note : this one is special.
1897 mapping_cmpprevname(struct if_mapping * ifnode,
1898 struct if_mapping * target)
1900 /* Do wildcard matching, case insensitive */
1901 return(fnmatch(ifnode->prevname, target->ifname, FNM_CASEFOLD));
1904 /*------------------------------------------------------------------*/
1906 * Extract the Previous Interface Name from a live interface
1909 mapping_getprevname(int skfd,
1910 const char * ifname,
1911 struct if_mapping * target,
1914 /* Avoid "Unused parameter" warning */
1915 skfd = skfd; ifname = ifname; flag = flag;
1917 /* Don't do anything, it's already in target->ifname ;-) */
1920 target->active[SELECT_PREVNAME] = 1;
1926 /*********************** MAPPING MANAGEMENTS ***********************/
1928 * Manage interface mappings.
1929 * Each mapping tell us how to identify a specific interface name.
1930 * It is composed of a bunch of selector values.
1933 /*------------------------------------------------------------------*/
1935 * Create a new interface mapping and verify its name
1937 static struct if_mapping *
1938 mapping_create(char * pos,
1942 struct if_mapping * ifnode;
1945 star = memchr(pos, '*', len);
1947 /* Check overflow, need one extra char for wildcard */
1948 if((len + (star != NULL)) > IFNAMSIZ)
1950 fprintf(stderr, "Error: Interface name `%.*s' too long at line %d\n",
1951 (int) len, pos, linenum);
1955 /* Create mapping, zero it */
1956 ifnode = calloc(1, sizeof(if_mapping));
1959 fprintf(stderr, "Error: Can't allocate interface mapping.\n");
1963 /* Set the name, terminates it */
1964 memcpy(ifnode->ifname, pos, len);
1965 ifnode->ifname[len] = '\0';
1967 /* Check the interface name and issue various pedantic warnings.
1968 * We assume people using takeover want to force interfaces to those
1969 * names and know what they are doing, so don't bother them... */
1970 if((!force_takeover) &&
1971 ((!strcmp(ifnode->ifname, "eth0")) || (!strcmp(ifnode->ifname, "wlan0"))))
1973 "Warning: Interface name is `%s' at line %d, can't be mapped reliably.\n",
1974 ifnode->ifname, linenum);
1975 if(strchr(ifnode->ifname, ':'))
1976 fprintf(stderr, "Warning: Alias device `%s' at line %d probably can't be mapped.\n",
1977 ifnode->ifname, linenum);
1980 fprintf(stderr, "Parsing : Added Mapping `%s' from line %d.\n",
1981 ifnode->ifname, linenum);
1987 /*------------------------------------------------------------------*/
1989 * Find the most appropriate selector matching a given selector name
1991 static inline const struct mapping_selector *
1992 selector_find(const char * string,
1996 const struct mapping_selector * found = NULL;
2000 /* Go through all selectors */
2001 for(i = 0; selector_list[i].name != NULL; ++i)
2003 /* No match -> next one */
2004 if(strncasecmp(selector_list[i].name, string, slen) != 0)
2007 /* Exact match -> perfect */
2008 if(slen == strlen(selector_list[i].name))
2009 return &selector_list[i];
2014 found = &selector_list[i];
2017 if (selector_list[i].add_fn != found->add_fn)
2023 fprintf(stderr, "Error: Unknown selector `%.*s' at line %d.\n",
2024 (int) slen, string, linenum);
2030 fprintf(stderr, "Selector `%.*s'at line %d is ambiguous.\n",
2031 (int) slen, string, linenum);
2038 /*------------------------------------------------------------------*/
2040 * Read the configuration file and extract all valid mappings and their
2044 mapping_readfile(const char * filename)
2047 char * linebuf = NULL;
2050 struct add_extra extrainfo;
2052 /* Reset the list of filters */
2053 bzero(selector_active, sizeof(selector_active));
2055 /* Check filename */
2056 if(!strcmp(filename, "-"))
2058 /* Read from stdin */
2064 /* Open the file for reading */
2065 stream = fopen(filename, "r");
2068 fprintf(stderr, "Error: Can't open configuration file `%s': %s\n",
2069 filename, strerror(errno));
2074 /* Read each line of file
2075 * getline is a GNU extension :-( The buffer is recycled and increased
2076 * as needed by getline. */
2077 while(getline(&linebuf, &linelen, stream) > 0)
2079 struct if_mapping * ifnode;
2083 int ret = -13; /* Complain if no selectors */
2085 /* Keep track of line number */
2088 /* Every comments terminates parsing */
2089 if((p = strchr(linebuf,'#')) != NULL)
2092 /* Get interface name */
2097 continue; /* Line ended */
2098 n = strcspn(p, " \t\n");
2100 /* Create mapping */
2101 ifnode = mapping_create(p, n, linenum);
2103 continue; /* Ignore this line */
2105 p += strspn(p, " \t\n");
2107 /* Loop on all selectors */
2110 const struct mapping_selector * selector = NULL;
2111 struct add_extra * extra = NULL;
2113 /* Selector name length - stop at modifier start */
2114 n = strcspn(p, " \t\n{");
2117 selector = selector_find(p, n, linenum);
2125 /* Check for modifier */
2129 /* Find end of modifier */
2134 "Error: unterminated selector modifier value on line %d\n",
2137 break; /* Line ended */
2139 /* Fill in struct and hook it */
2140 extrainfo.modif_pos = p;
2141 extrainfo.modif_len = e - p;
2143 /* Terminate modifier value */
2149 /* Get to selector value */
2150 p += strspn(p, " \t\n");
2153 fprintf(stderr, "Error: no value for selector `%s' on line %d\n",
2154 selector->name, linenum);
2156 break; /* Line ended */
2158 /* Check for quoted arguments */
2166 "Error: unterminated quoted value on line %d\n",
2169 break; /* Line ended */
2176 /* Just end at next blank */
2177 n = strcspn(p, " \t\n");
2180 /* Make 'e' point past the '\0' we are going to add */
2183 /* Terminate selector value */
2186 /* Add it to the mapping */
2187 ret = selector->add_fn(ifnode, selector_active, p, n,
2192 /* Go to next selector */
2194 p += strspn(p, " \t\n");
2197 /* We add a mapping only if it has at least one selector and if all
2198 * selectors were parsed properly. */
2201 /* If we have not yet printed an error, now is a good time ;-) */
2203 fprintf(stderr, "Error: Line %d ignored, no valid selectors\n",
2206 fprintf(stderr, "Error: Line %d ignored due to prior errors\n",
2213 /* Link it in the list */
2214 ifnode->next = mapping_list;
2215 mapping_list = ifnode;
2222 /* Finished reading, close the file */
2228 /*------------------------------------------------------------------*/
2230 * Extract all the interesting selectors for the interface in consideration
2232 static struct if_mapping *
2233 mapping_extract(int skfd,
2234 const char * ifname)
2236 struct if_mapping * target;
2239 /* Create mapping, zero it */
2240 target = calloc(1, sizeof(if_mapping));
2243 fprintf(stderr, "Error: Can't allocate interface mapping.\n");
2247 /* Set the interface name */
2248 strcpy(target->ifname, ifname);
2250 /* Loop on all active selectors */
2251 for(i = 0; i < SELECT_NUM; i++)
2253 /* Check if this selector is active */
2254 if(selector_active[i] != 0)
2256 /* Extract selector */
2257 selector_list[i].get_fn(skfd, ifname, target, selector_active[i]);
2259 /* Ignore errors. Some mapping may not need all selectors */
2266 /*------------------------------------------------------------------*/
2268 * Find the first mapping in the list matching the one we want.
2270 static struct if_mapping *
2271 mapping_find(struct if_mapping * target)
2273 struct if_mapping * ifnode;
2276 /* Look over all our mappings */
2277 for(ifnode = mapping_list; ifnode != NULL; ifnode = ifnode->next)
2281 /* Look over all our selectors, all must match */
2282 for(i = 0; i < SELECT_NUM; i++)
2284 /* Check if this selector is active */
2285 if(ifnode->active[i] != 0)
2287 /* If this selector doesn't match, game over for this mapping */
2288 if((target->active[i] == 0) ||
2289 (selector_list[i].cmp_fn(ifnode, target) != 0))
2297 /* Check is this mapping was "the one" */
2306 /************************** MODULE SUPPORT **************************/
2308 * Load all necessary module so that interfaces do exist.
2309 * This is necessary for system that are fully modular when
2310 * doing the boot time processing, because we need to run before
2314 /*------------------------------------------------------------------*/
2316 * Probe interfaces based on our list of mappings.
2317 * This is the default, but usually not the best way to do it.
2320 probe_mappings(int skfd)
2322 struct if_mapping * ifnode;
2325 /* Look over all our mappings */
2326 for(ifnode = mapping_list; ifnode != NULL; ifnode = ifnode->next)
2328 /* Can't load wildcards interface name :-( */
2329 if(strchr(ifnode->ifname, '*') != NULL)
2333 fprintf(stderr, "Probing : Trying to load/probe interface [%s]\n",
2336 /* Trick the kernel into loading the interface.
2337 * This allow us to not depend on the exact path and
2338 * name of the '/sbin/modprobe' command.
2339 * Obviously, we expect this command to 'fail', as
2340 * the interface will load with the old/wrong name.
2342 strncpy(ifr.ifr_name, ifnode->ifname, IFNAMSIZ);
2343 ioctl(skfd, SIOCGIFHWADDR, &ifr);
2347 /*------------------------------------------------------------------*/
2349 * Probe interfaces based on Debian's config files.
2350 * This allow to enly load modules for interfaces the user want active,
2351 * all built-in interfaces that should remain unconfigured won't
2352 * be probed (and can have mappings).
2355 probe_debian(int skfd)
2358 char * linebuf = NULL;
2362 /* Open Debian config file */
2363 stream = fopen(DEBIAN_CONFIG_FILE, "r");
2366 fprintf(stderr, "Error: can't open file [%s]\n", DEBIAN_CONFIG_FILE);
2370 /* Read each line of file
2371 * getline is a GNU extension :-( The buffer is recycled and increased
2372 * as needed by getline. */
2373 while(getline(&linebuf, &linelen, stream) > 0)
2379 /* Check for auto keyword, ignore when commented out */
2380 if(!strncasecmp(linebuf, "auto ", 5))
2382 /* Skip "auto" keyword */
2385 /* Terminate at first comment */
2390 /* Loop on all interfaces given */
2393 /* Interface name length */
2394 n = strcspn(p, " \t\n");
2396 /* Look for end of interface name */
2398 /* Make 'e' point past the '\0' we are going to add */
2401 /* Terminate interface name */
2405 fprintf(stderr, "Probing : Trying to load interface [%s]\n",
2408 /* Load interface */
2409 strncpy(ifr.ifr_name, p, IFNAMSIZ);
2410 ioctl(skfd, SIOCGIFHWADDR, &ifr);
2412 /* Go to next interface name */
2414 p += strspn(p, " \t\n");
2424 /**************************** MAIN LOGIC ****************************/
2426 /*------------------------------------------------------------------*/
2428 * Rename an interface to a specified new name.
2431 process_rename(int skfd,
2435 char retname[IFNAMSIZ+1];
2439 len = strlen(newname);
2440 star = strchr(newname, '*');
2442 /* Check newname length, need one extra char for wildcard */
2443 if((len + (star != NULL)) > IFNAMSIZ)
2445 fprintf(stderr, "Error: Interface name `%s' too long.\n",
2450 /* Change the name of the interface */
2451 if(if_set_name(skfd, ifname, newname, retname) < 0)
2453 fprintf(stderr, "Error: cannot change name of %s to %s: %s\n",
2454 ifname, newname, strerror(errno));
2458 /* Always print out the *new* interface name so that
2459 * the calling script can pick it up and know where its interface
2461 printf("%s\n", retname);
2467 /*------------------------------------------------------------------*/
2469 * Process a specified interface.
2472 process_ifname(int skfd,
2477 struct if_mapping * target;
2478 const struct if_mapping * mapping;
2479 char retname[IFNAMSIZ+1];
2481 /* Avoid "Unused parameter" warning */
2482 args = args; count = count;
2484 /* Get description of this interface */
2485 target = mapping_extract(skfd, ifname);
2489 /* If udev is calling us, get the real devpath. */
2493 /* It's passed to us as an environment variable */
2494 env = getenv("DEVPATH");
2497 int env_len = strlen(env);
2498 target->sysfs_devplen = env_len;
2499 /* Make enough space for new interface name */
2500 target->sysfs_devpath = malloc(env_len + IFNAMSIZ + 1);
2501 if(target->sysfs_devpath != NULL)
2502 memcpy(target->sysfs_devpath, env, env_len + 1);
2504 /* We will get a second chance is the user has some sysfs selectors */
2507 /* Find matching mapping */
2508 mapping = mapping_find(target);
2512 /* If user specified a new name, keep only interfaces that would
2513 * match the new name... */
2514 if((new_name != NULL) && (if_match_ifname(mapping->ifname, new_name) != 0))
2517 /* Check if user want only dry-run.
2518 * Note that, in the case of wildcard, we don't resolve the wildcard.
2519 * That would be tricky to do... */
2522 strcpy(retname, mapping->ifname);
2523 fprintf(stderr, "Dry-run : Would rename %s to %s.\n",
2524 target->ifname, mapping->ifname);
2528 /* Change the name of the interface */
2529 if(if_set_name(skfd, target->ifname, mapping->ifname, retname) < 0)
2531 fprintf(stderr, "Error: cannot change name of %s to %s: %s\n",
2532 target->ifname, mapping->ifname, strerror(errno));
2537 /* This one matched */
2538 num_mapping_match++;
2540 /* Check if called with an explicit interface name */
2544 /* Always print out the *new* interface name so that
2545 * the calling script can pick it up and know where its interface
2547 printf("%s\n", retname);
2549 /* udev likes to call us as an IMPORT action. This means that
2550 * we need to return udev the environment variables changed.
2551 * Obviously, we don't want to return anything is nothing changed. */
2552 if(strcmp(target->ifname, retname))
2556 if(!target->sysfs_devpath)
2557 mapping_getsysfs(skfd, ifname, target, 0);
2558 /* Update devpath. Size is large enough. */
2559 pos = strrchr(target->sysfs_devpath, '/');
2560 if((pos != NULL) && (!strcmp(target->ifname, pos + 1)))
2561 strcpy(pos + 1, retname);
2562 /* Return new environment variables */
2563 printf("DEVPATH=%s\nINTERFACE=%s\nINTERFACE_OLD=%s\n",
2564 target->sysfs_devpath, retname, target->ifname);
2572 /*------------------------------------------------------------------*/
2574 * Process all network interface present on the system.
2577 process_iflist(int skfd,
2584 num_mapping_match = 0;
2586 /* Load all the necesary modules */
2592 probe_mappings(skfd);
2596 iw_enum_devices(skfd, &process_ifname, args, count);
2602 /******************************* MAIN *******************************/
2605 /*------------------------------------------------------------------*/
2611 fprintf(stderr, "usage: ifrename [-c configurationfile] [-i ifname] [-p] [-t] [-d] [-D]\n");
2615 /*------------------------------------------------------------------*/
2623 const char * conf_file = DEFAULT_CONF;
2624 char * ifname = NULL;
2625 int use_probe = 0; /* Probe for modules */
2626 int is_debian = 0; /* Debian quirks (probing) */
2627 int print_num_match = 0; /* Print/Return num of matches */
2631 /* Loop over all command line options */
2634 int c = getopt_long(argc, argv, "c:CdDi:n:ptuvV", long_opt, NULL);
2647 print_num_match = 1;
2671 printf("%-8.16s Wireless-Tools version %d\n", "ifrename", WT_VERSION);
2679 /* Create a channel to the NET kernel. */
2680 if((skfd = iw_sockets_open()) < 0)
2686 /* Check if interface name was specified with -i. */
2689 /* Check is target name specified */
2690 if(new_name != NULL)
2692 /* User want to simply rename an interface to a specified name */
2693 ret = process_rename(skfd, ifname, new_name);
2697 /* Read the specified/default config file, or stdin. */
2698 if(mapping_readfile(conf_file) < 0)
2701 /* Rename only this interface based on mappings
2702 * Mostly used for HotPlug processing (from /etc/hotplug/net.agent)
2703 * or udev processing (from a udev IMPORT rule).
2704 * Process the network interface specified on the command line,
2705 * and return the new name on stdout.
2708 ret = process_ifname(skfd, ifname, NULL, 0);
2713 /* Read the specified/default config file, or stdin. */
2714 if(mapping_readfile(conf_file) < 0)
2717 /* Rename all system interfaces
2718 * Mostly used for boot time processing (from init scripts).
2720 ret = process_iflist(skfd, NULL, 0, use_probe, is_debian);
2722 /* If we do any takeover, the interface list grabbed with
2723 * iw_enum_devices() may get out of sync with the real interfaces,
2724 * and we may miss the victim interface. So, let's go through the
2726 * On the other hand, we may have ping pong between two interfaces,
2727 * each claiming the same name, so let's not do it forever...
2728 * Two time should be enough for most configs...
2729 * Note also that takeover is usually done with eth0, and many time
2730 * we fail to probe eth0 because an unrenamed interface was using it,
2731 * so we redo everything also when probing...
2733 if(force_takeover && (num_takeover || use_probe))
2735 /* Play it again, Sam... */
2736 ret = process_iflist(skfd, NULL, 0, use_probe, is_debian);
2739 /* Print number of mapping that matched */
2742 fprintf(stderr, "Setting : %d mapping matched.\n", num_mapping_match);
2743 ret = num_mapping_match;
2748 iw_sockets_close(skfd);