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 interface */
436 int num_takeover = 0; /* Number of takeover done */
438 /* Dry-run support */
439 int dry_run = 0; /* Just print new name, don't rename */
441 /* Verbose support (i.e. debugging) */
444 /* udev output support (print new DEVPATH) */
447 /* sysfs global data */
448 struct sysfs_metadata sysfs_global =
451 0, { NULL, NULL, NULL, NULL, NULL },
454 /******************** INTERFACE NAME MANAGEMENT ********************/
456 * Bunch of low level function for managing interface names.
459 /*------------------------------------------------------------------*/
461 * Compare two interface names, with wildcards.
462 * We can't use fnmatch() because we don't want expansion of '[...]'
463 * expressions, '\' sequences and matching of '.'.
464 * We only want to match a single '*' (converted to a %d at that point)
465 * to a numerical value (no ascii).
466 * Return 0 is matches.
469 if_match_ifname(const char * pattern,
477 /* Check for a wildcard */
478 p = strchr(pattern, '*');
480 /* No wildcard, simple comparison */
482 return(strcmp(pattern, value));
484 /* Check is prefixes match */
486 ret = strncmp(pattern, value, n);
490 /* Check that value has some digits at this point */
495 /* Skip digits to go to value suffix */
503 /* Compare suffixes */
504 return(strcmp(p, v));
507 /*------------------------------------------------------------------*/
509 * Steal interface name from another interface. This enable interface
512 * 1) with kernel 2.6.X
513 * 2) if other interface is down
514 * Because of (2), it won't work with hotplug, but we don't need it
515 * with hotplug, only with static ifaces...
518 if_takeover_name(int skfd,
519 const char * victimname)
521 char autoname[IFNAMSIZ+1];
526 /* Compute name for victim interface */
527 len = strlen(victimname);
528 memcpy(autoname, victimname, len + 1);
529 if(len > (IFNAMSIZ - 2))
530 len = IFNAMSIZ - 2; /* Make sure we have at least two char */
531 len--; /* Convert to index */
532 while(isdigit(autoname[len]))
533 len--; /* Scrap all trailing digits */
534 strcpy(autoname + len + 1, "%d");
537 fprintf(stderr, "Takeover : moving interface `%s' to `%s'.\n",
538 victimname, autoname);
540 /* Prepare request */
541 bzero(&ifr, sizeof(struct ifreq));
542 strncpy(ifr.ifr_name, victimname, IFNAMSIZ);
543 strncpy(ifr.ifr_newname, autoname, IFNAMSIZ);
545 /* Rename victim interface */
546 ret = ioctl(skfd, SIOCSIFNAME, &ifr);
554 /*------------------------------------------------------------------*/
556 * Ask the kernel to change the name of an interface.
557 * That's what we want to do. All the rest is to make sure we call this
561 if_set_name(int skfd,
562 const char * oldname,
563 const char * newname,
570 /* The kernel doesn't check is the interface already has the correct
571 * name and may return an error, so check ourselves.
572 * In the case of wildcard, the result can be weird : if oldname='eth0'
573 * and newname='eth*', retname would be 'eth1'.
574 * So, if the oldname value matches the newname pattern, just return
576 if(!if_match_ifname(newname, oldname))
579 fprintf(stderr, "Setting : Interface `%s' already matches `%s'.\n",
582 strcpy(retname, oldname);
586 /* Prepare request */
587 bzero(&ifr, sizeof(struct ifreq));
588 strncpy(ifr.ifr_name, oldname, IFNAMSIZ);
589 strncpy(ifr.ifr_newname, newname, IFNAMSIZ);
591 /* Check for wildcard interface name, such as 'eth*' or 'wlan*'...
592 * This require specific kernel support (2.6.2-rc1 and later).
593 * We externally use '*', but the kernel doesn't know about that,
594 * so convert it to something it knows about... */
595 star = strchr(newname, '*');
598 int slen = star - newname;
599 /* Replace '*' with '%d' in the new buffer */
600 star = ifr.ifr_newname + slen;
601 /* Size was checked in process_rename() and mapping_create() */
602 memmove(star + 2, star + 1, IFNAMSIZ - slen - 2);
608 ret = ioctl(skfd, SIOCSIFNAME, &ifr);
610 /* Takeover support : grab interface name from another interface */
611 if(ret && (errno == EEXIST) && force_takeover)
613 /* Push things around */
614 ret = if_takeover_name(skfd, newname);
617 ret = ioctl(skfd, SIOCSIFNAME, &ifr);
622 /* Get the real new name (in case newname is a wildcard) */
623 strcpy(retname, ifr.ifr_newname);
626 fprintf(stderr, "Setting : Interface `%s' renamed to `%s'.\n",
633 /************************ SELECTOR HANDLING ************************/
635 * Handle the various selector we support
638 /*------------------------------------------------------------------*/
640 * Add a MAC address selector to a mapping
643 mapping_addmac(struct if_mapping * ifnode,
647 struct add_extra * extra,
652 /* Avoid "Unused parameter" warning */
655 /* Verify validity of string */
656 if(len >= sizeof(ifnode->mac_filter))
658 fprintf(stderr, "Error : MAC address too long at line %d\n", linenum);
661 n = strspn(string, "0123456789ABCDEFabcdef:*");
664 fprintf(stderr, "Error: Invalid MAC address `%s' at line %d\n",
669 /* Copy as filter in all cases */
670 memcpy(ifnode->mac_filter, string, len + 1);
672 /* Check the type of MAC address */
673 if (strchr(ifnode->mac_filter, '*') != NULL)
675 /* This is a wilcard. Usual format : "01:23:45:*"
676 * Unfortunately, we can't do proper parsing. */
677 ifnode->active[SELECT_MAC] = HAS_MAC_FILTER;
678 active[SELECT_MAC] = HAS_MAC_FILTER;
682 /* Not a wildcard : "01:23:45:67:89:AB" */
683 ifnode->mac_len = iw_mac_aton(ifnode->mac_filter,
684 ifnode->mac, MAX_MAC_LEN);
685 if(ifnode->mac_len == 0)
687 fprintf(stderr, "Error: Invalid MAC address `%s' at line %d\n",
688 ifnode->mac_filter, linenum);
692 /* Check that it's not NULL */
693 if((ifnode->mac_len == 6) && (!memcmp(&ifnode->mac, &zero_mac, 6)))
696 "Warning: MAC address is null at line %d, this is dangerous...\n",
700 ifnode->active[SELECT_MAC] = HAS_MAC_EXACT;
701 if(active[SELECT_MAC] == 0)
702 active[SELECT_MAC] = HAS_MAC_EXACT;
707 "Parsing : Added %s MAC address `%s' from line %d.\n",
708 ifnode->active[SELECT_MAC] == HAS_MAC_FILTER ? "filter" : "exact",
709 ifnode->mac_filter, linenum);
714 /*------------------------------------------------------------------*/
716 * Compare the mac address of two mappings
719 mapping_cmpmac(struct if_mapping * ifnode,
720 struct if_mapping * target)
722 /* Check for wildcard matching */
723 if(ifnode->active[SELECT_MAC] == HAS_MAC_FILTER)
724 /* Do wildcard matching, case insensitive */
725 return(fnmatch(ifnode->mac_filter, target->mac_filter, FNM_CASEFOLD));
727 /* Exact matching, in hex */
728 return((ifnode->mac_len != target->mac_len) ||
729 memcmp(ifnode->mac, target->mac, ifnode->mac_len));
732 /*------------------------------------------------------------------*/
734 * Extract the MAC address and Link Type of an interface
737 mapping_getmac(int skfd,
739 struct if_mapping * target,
746 /* Get MAC address */
747 bzero(&ifr, sizeof(struct ifreq));
748 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
749 ret = ioctl(skfd, SIOCGIFHWADDR, &ifr);
752 fprintf(stderr, "Error: Can't read MAC address on interface `%s' : %s\n",
753 ifname, strerror(errno));
757 /* Extract ARP type */
758 target->hw_type = ifr.ifr_hwaddr.sa_family;
759 /* Calculate address length */
761 for(i = 0; i < weird_mac_len_num; i++)
762 if(weird_mac_len[i][0] == ifr.ifr_hwaddr.sa_family)
764 target->mac_len = weird_mac_len[i][1];
767 /* Extract MAC address bytes */
768 memcpy(target->mac, ifr.ifr_hwaddr.sa_data, target->mac_len);
770 /* Check the type of comparison */
771 if((flag == HAS_MAC_FILTER) || verbose)
773 /* Convert to ASCII */
774 iw_mac_ntop(target->mac, target->mac_len,
775 target->mac_filter, sizeof(target->mac_filter));
778 target->active[SELECT_MAC] = flag;
779 target->active[SELECT_ARP] = 1;
783 "Querying %s : Got MAC address `%s' and ARP/Link Type `%d'.\n",
784 ifname, target->mac_filter, target->hw_type);
789 /*------------------------------------------------------------------*/
791 * Add a ARP/Link type selector to a mapping
794 mapping_addarp(struct if_mapping * ifnode,
798 struct add_extra * extra,
804 /* Avoid "Unused parameter" warning */
807 /* Verify validity of string, convert to int */
808 n = strspn(string, "0123456789");
809 if((n < len) || (sscanf(string, "%d", &type) != 1))
811 fprintf(stderr, "Error: Invalid ARP/Link Type `%s' at line %d\n",
816 ifnode->hw_type = (unsigned short) type;
817 ifnode->active[SELECT_ARP] = 1;
818 active[SELECT_ARP] = 1;
821 fprintf(stderr, "Parsing : Added ARP/Link Type `%d' from line %d.\n",
822 ifnode->hw_type, linenum);
827 /*------------------------------------------------------------------*/
829 * Compare the ARP/Link type of two mappings
832 mapping_cmparp(struct if_mapping * ifnode,
833 struct if_mapping * target)
835 return(!(ifnode->hw_type == target->hw_type));
838 /*------------------------------------------------------------------*/
840 * Extract the ARP/Link type of an interface
843 mapping_getarp(int skfd,
845 struct if_mapping * target,
848 /* We may have already extracted the MAC address */
849 if(target->active[SELECT_MAC])
852 /* Otherwise just do it */
853 return(mapping_getmac(skfd, ifname, target, flag));
856 /*------------------------------------------------------------------*/
858 * Add a Driver name selector to a mapping
861 mapping_adddriver(struct if_mapping * ifnode,
865 struct add_extra * extra,
868 /* Avoid "Unused parameter" warning */
871 /* Plain string, minimal verification */
872 if(len >= sizeof(ifnode->driver))
874 fprintf(stderr, "Error: Driver name too long at line %d\n", linenum);
879 memcpy(ifnode->driver, string, len + 1);
882 ifnode->active[SELECT_DRIVER] = 1;
883 active[SELECT_DRIVER] = 1;
887 "Parsing : Added Driver name `%s' from line %d.\n",
888 ifnode->driver, linenum);
893 /*------------------------------------------------------------------*/
895 * Compare the Driver name of two mappings
898 mapping_cmpdriver(struct if_mapping * ifnode,
899 struct if_mapping * target)
901 /* Do wildcard matching, case insensitive */
902 return(fnmatch(ifnode->driver, target->driver, FNM_CASEFOLD));
905 /*------------------------------------------------------------------*/
907 * Add a Bus-Info selector to a mapping
910 mapping_addbusinfo(struct if_mapping * ifnode,
914 struct add_extra * extra,
921 /* Avoid "Unused parameter" warning */
924 /* Verify validity of string */
925 if(len >= sizeof(ifnode->bus_info))
927 fprintf(stderr, "Bus Info too long at line %d\n", linenum);
931 /* Hum... This doesn's seem true for non-PCI bus-info */
932 n = strspn(string, "0123456789ABCDEFabcdef:.*");
935 fprintf(stderr, "Error: Invalid Bus Info `%s' at line %d\n",
942 memcpy(ifnode->bus_info, string, len + 1);
945 ifnode->active[SELECT_BUSINFO] = 1;
946 active[SELECT_BUSINFO] = 1;
950 "Parsing : Added Bus Info `%s' from line %d.\n",
951 ifnode->bus_info, linenum);
956 /*------------------------------------------------------------------*/
958 * Compare the Bus-Info of two mappings
961 mapping_cmpbusinfo(struct if_mapping * ifnode,
962 struct if_mapping * target)
964 /* Do wildcard matching, case insensitive */
965 return(fnmatch(ifnode->bus_info, target->bus_info, FNM_CASEFOLD));
968 /*------------------------------------------------------------------*/
970 * Add a Firmare revision selector to a mapping
973 mapping_addfirmware(struct if_mapping * ifnode,
977 struct add_extra * extra,
980 /* Avoid "Unused parameter" warning */
983 /* Verify validity of string */
984 if(len >= sizeof(ifnode->fw_version))
986 fprintf(stderr, "Firmware revision too long at line %d\n", linenum);
991 memcpy(ifnode->fw_version, string, len + 1);
994 ifnode->active[SELECT_FIRMWARE] = 1;
995 active[SELECT_FIRMWARE] = 1;
999 "Parsing : Added Firmware Revision `%s' from line %d.\n",
1000 ifnode->fw_version, linenum);
1005 /*------------------------------------------------------------------*/
1007 * Compare the Bus-Info of two mappings
1010 mapping_cmpfirmware(struct if_mapping * ifnode,
1011 struct if_mapping * target)
1013 /* Do wildcard matching, case insensitive */
1014 return(fnmatch(ifnode->fw_version, target->fw_version, FNM_CASEFOLD));
1017 /*------------------------------------------------------------------*/
1019 * Extract the Driver name and Bus-Info from a live interface
1022 mapping_getdriverbusinfo(int skfd,
1023 const char * ifname,
1024 struct if_mapping * target,
1028 struct ethtool_drvinfo drvinfo;
1031 /* Avoid "Unused parameter" warning */
1034 /* We may come here twice or more, so do the job only once */
1035 if(target->active[SELECT_DRIVER] || target->active[SELECT_BUSINFO]
1036 || target->active[SELECT_FIRMWARE])
1039 /* Prepare request */
1040 bzero(&ifr, sizeof(struct ifreq));
1041 bzero(&drvinfo, sizeof(struct ethtool_drvinfo));
1042 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
1043 drvinfo.cmd = ETHTOOL_GDRVINFO;
1044 ifr.ifr_data = (caddr_t) &drvinfo;
1047 ret = ioctl(skfd, SIOCETHTOOL, &ifr);
1050 /* Most drivers don't support that, keep quiet for now */
1053 "Error: Can't read driver/bus-info on interface `%s' : %s\n",
1054 ifname, strerror(errno));
1059 strcpy(target->driver, drvinfo.driver);
1060 strcpy(target->bus_info, drvinfo.bus_info);
1061 strcpy(target->fw_version, drvinfo.fw_version);
1064 target->active[SELECT_DRIVER] = 1;
1065 target->active[SELECT_BUSINFO] = 1;
1066 target->active[SELECT_FIRMWARE] = 1;
1070 "Querying %s : Got Driver name `%s', Bus Info `%s' and Firmware `%s'.\n",
1071 ifname, target->driver, target->bus_info, target->fw_version);
1076 /*------------------------------------------------------------------*/
1078 * Add a Base Address selector to a mapping
1081 mapping_addbaseaddr(struct if_mapping * ifnode,
1085 struct add_extra * extra,
1089 unsigned int address;
1091 /* Avoid "Unused parameter" warning */
1094 /* Verify validity of string */
1095 n = strspn(string, "0123456789ABCDEFabcdefx");
1096 if((n < len) || (sscanf(string, "0x%X", &address) != 1))
1098 fprintf(stderr, "Error: Invalid Base Address `%s' at line %d\n",
1104 ifnode->base_addr = (unsigned short) address;
1107 ifnode->active[SELECT_BASEADDR] = 1;
1108 active[SELECT_BASEADDR] = 1;
1112 "Parsing : Added Base Address `0x%X' from line %d.\n",
1113 ifnode->base_addr, linenum);
1118 /*------------------------------------------------------------------*/
1120 * Compare the Base Address of two mappings
1123 mapping_cmpbaseaddr(struct if_mapping * ifnode,
1124 struct if_mapping * target)
1126 /* Do wildcard matching, case insensitive */
1127 return(!(ifnode->base_addr == target->base_addr));
1130 /*------------------------------------------------------------------*/
1132 * Add a IRQ selector to a mapping
1135 mapping_addirq(struct if_mapping * ifnode,
1139 struct add_extra * extra,
1145 /* Avoid "Unused parameter" warning */
1148 /* Verify validity of string */
1149 n = strspn(string, "0123456789");
1150 if((n < len) || (sscanf(string, "%d", &irq) != 1))
1152 fprintf(stderr, "Error: Invalid Base Address `%s' at line %d\n",
1158 ifnode->irq = (unsigned char) irq;
1161 ifnode->active[SELECT_IRQ] = 1;
1162 active[SELECT_IRQ] = 1;
1166 "Parsing : Added IRQ `%d' from line %d.\n",
1167 ifnode->irq, linenum);
1172 /*------------------------------------------------------------------*/
1174 * Compare the IRQ of two mappings
1177 mapping_cmpirq(struct if_mapping * ifnode,
1178 struct if_mapping * target)
1180 /* Do wildcard matching, case insensitive */
1181 return(!(ifnode->irq == target->irq));
1184 /*------------------------------------------------------------------*/
1186 * Extract the Driver name and Bus-Info from a live interface
1189 mapping_getbaseaddrirq(int skfd,
1190 const char * ifname,
1191 struct if_mapping * target,
1195 struct ifmap map; /* hardware setup */
1198 /* Avoid "Unused parameter" warning */
1201 /* We may come here twice, so do the job only once */
1202 if(target->active[SELECT_BASEADDR] || target->active[SELECT_IRQ])
1205 /* Prepare request */
1206 bzero(&ifr, sizeof(struct ifreq));
1207 bzero(&map, sizeof(struct ifmap));
1208 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
1211 ret = ioctl(skfd, SIOCGIFMAP, &ifr);
1214 /* Don't know if every interface has that, so keep quiet... */
1217 "Error: Can't read base address/irq on interface `%s' : %s\n",
1218 ifname, strerror(errno));
1222 /* Copy over, activate */
1223 if(ifr.ifr_map.base_addr >= 0x100)
1225 target->base_addr = ifr.ifr_map.base_addr;
1226 target->active[SELECT_BASEADDR] = 1;
1228 target->irq = ifr.ifr_map.irq;
1229 target->active[SELECT_IRQ] = 1;
1233 "Querying %s : Got Base Address `0x%X' and IRQ `%d'.\n",
1234 ifname, target->base_addr, target->irq);
1239 /*------------------------------------------------------------------*/
1241 * Add a Wireless Protocol selector to a mapping
1244 mapping_addiwproto(struct if_mapping * ifnode,
1248 struct add_extra * extra,
1251 /* Avoid "Unused parameter" warning */
1254 /* Verify validity of string */
1255 if(len >= sizeof(ifnode->iwproto))
1257 fprintf(stderr, "Wireless Protocol too long at line %d\n", linenum);
1262 memcpy(ifnode->iwproto, string, len + 1);
1265 ifnode->active[SELECT_IWPROTO] = 1;
1266 active[SELECT_IWPROTO] = 1;
1270 "Parsing : Added Wireless Protocol `%s' from line %d.\n",
1271 ifnode->iwproto, linenum);
1276 /*------------------------------------------------------------------*/
1278 * Compare the Wireless Protocol of two mappings
1281 mapping_cmpiwproto(struct if_mapping * ifnode,
1282 struct if_mapping * target)
1284 /* Do wildcard matching, case insensitive */
1285 return(fnmatch(ifnode->iwproto, target->iwproto, FNM_CASEFOLD));
1288 /*------------------------------------------------------------------*/
1290 * Extract the Wireless Protocol from a live interface
1293 mapping_getiwproto(int skfd,
1294 const char * ifname,
1295 struct if_mapping * target,
1300 /* Avoid "Unused parameter" warning */
1303 /* Get wireless name */
1304 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
1305 /* Don't complain about it, Ethernet cards will never support this */
1308 strncpy(target->iwproto, wrq.u.name, IFNAMSIZ);
1309 target->iwproto[IFNAMSIZ] = '\0';
1312 target->active[SELECT_IWPROTO] = 1;
1316 "Querying %s : Got Wireless Protocol `%s'.\n",
1317 ifname, target->iwproto);
1322 /*------------------------------------------------------------------*/
1324 * Add a Pcmcia Slot selector to a mapping
1327 mapping_addpcmciaslot(struct if_mapping * ifnode,
1331 struct add_extra * extra,
1336 /* Avoid "Unused parameter" warning */
1339 /* Verify validity of string, convert to int */
1340 n = strspn(string, "0123456789");
1341 if((n < len) || (sscanf(string, "%d", &ifnode->pcmcia_slot) != 1))
1343 fprintf(stderr, "Error: Invalid Pcmcia Slot `%s' at line %d\n",
1348 ifnode->active[SELECT_PCMCIASLOT] = 1;
1349 active[SELECT_PCMCIASLOT] = 1;
1352 fprintf(stderr, "Parsing : Added Pcmcia Slot `%d' from line %d.\n",
1353 ifnode->pcmcia_slot, linenum);
1358 /*------------------------------------------------------------------*/
1360 * Compare the Pcmcia Slot of two mappings
1363 mapping_cmppcmciaslot(struct if_mapping * ifnode,
1364 struct if_mapping * target)
1366 return(!(ifnode->pcmcia_slot == target->pcmcia_slot));
1369 /*------------------------------------------------------------------*/
1371 * Extract the Pcmcia Slot of an interface
1372 * Note that this works only for cards fully managed by cardmgr.
1373 * With the kernel pcmcia modules, 32 bits cards (CardBus) are not managed
1374 * by cardmgr, and therefore won't have a valid slot number. For those
1375 * cards, you should use Bus Info (when the driver exports it).
1376 * In the long term, 16 bits card as well will no longer be managed by
1377 * cardmgr. Currently, Bus Info for 16 bit cards don't have any information
1378 * enabling to locate their physical location on the system, but I hope that
1380 * When that happen, we can drop this code...
1383 mapping_getpcmciaslot(int skfd,
1384 const char * ifname,
1385 struct if_mapping * target,
1389 char * linebuf = NULL;
1393 /* Avoid "Unused parameter" warning */
1397 /* Open the stab file for reading */
1398 stream = fopen(PCMCIA_STAB1, "r");
1401 /* Try again, alternate location */
1402 stream = fopen(PCMCIA_STAB2, "r");
1405 fprintf(stderr, "Error: Can't open PCMCIA Stab file `%s' or `%s': %s\n",
1406 PCMCIA_STAB1, PCMCIA_STAB2, strerror(errno));
1411 /* Read each line of file
1412 * getline is a GNU extension :-( The buffer is recycled and increased
1413 * as needed by getline. */
1414 while(getline(&linebuf, &linelen, stream) > 0)
1422 /* Keep track of line number */
1425 /* Get Pcmcia socket number */
1430 continue; /* Line ended */
1431 n = strcspn(p, " \t\n");
1432 k = strspn(p, "0123456789");
1433 if((k < n) || (sscanf(p, "%d", &pcmcia_slot) != 1))
1437 /* Skip socket number */
1438 /* Skip socket number ; device class ; driver name ; instance */
1439 for(i = 0; i < 4; i++)
1444 p += strspn(p, " \t\n");
1446 break; /* Line ended */
1447 /* Next item size */
1448 n = strcspn(p, " \t\n");
1451 continue; /* Line ended */
1453 /* Terminate dev name */
1456 /* Compare to interface name */
1457 if(!strcmp(p, ifname))
1460 target->pcmcia_slot = pcmcia_slot;
1463 target->active[SELECT_PCMCIASLOT] = 1;
1467 "Querying %s : Got Pcmcia Slot `%d'.\n",
1468 ifname, target->pcmcia_slot);
1469 /* Exit loop, found it */
1473 /* Finished -> next line */
1480 return(target->active[SELECT_PCMCIASLOT] ? 0 : -1);
1483 /*------------------------------------------------------------------*/
1485 * Add a sysfs selector to a mapping
1488 mapping_addsysfs(struct if_mapping * ifnode,
1492 struct add_extra * extra,
1495 int findex; /* filename index */
1498 /* Check if we have a modifier */
1499 if((extra == NULL) || (extra->modif_pos == NULL))
1501 fprintf(stderr, "Error: No SYSFS filename at line %d\n", linenum);
1505 /* Search if the filename already exist */
1506 for(findex = 0; findex < sysfs_global.filenum; findex++)
1508 if(!strcmp(extra->modif_pos, sysfs_global.filename[findex]))
1512 /* If filename does not exist, creates it */
1513 if(findex == sysfs_global.filenum)
1515 if(findex == SYSFS_MAX_FILE)
1517 fprintf(stderr, "Error: Too many SYSFS filenames at line %d\n", linenum);
1520 sdup = strndup(extra->modif_pos, extra->modif_len);
1523 fprintf(stderr, "Error: Can't allocate SYSFS file\n");
1526 sysfs_global.filename[findex] = sdup;
1527 sysfs_global.filenum++;
1531 sdup = strndup(string, len);
1534 fprintf(stderr, "Error: Can't allocate SYSFS value\n");
1537 ifnode->sysfs[findex] = sdup;
1540 ifnode->active[SELECT_SYSFS] = 1;
1541 active[SELECT_SYSFS] = 1;
1545 "Parsing : Added SYSFS filename `%s' value `%s' from line %d.\n",
1546 sysfs_global.filename[findex], ifnode->sysfs[findex], linenum);
1551 /*------------------------------------------------------------------*/
1553 * Compare all the sysfs values of two mappings
1556 mapping_cmpsysfs(struct if_mapping * ifnode,
1557 struct if_mapping * target)
1559 int findex; /* filename index */
1562 /* Loop on all sysfs selector */
1563 for(findex = 0; findex < sysfs_global.filenum; findex++)
1565 /* If the mapping defines this sysfs selector.. */
1566 if(ifnode->sysfs[findex] != NULL)
1567 /* And if the sysfs values don't match */
1568 if((target->sysfs[findex] == NULL) ||
1569 (fnmatch(ifnode->sysfs[findex], target->sysfs[findex],
1571 /* Then the sysfs selector doesn't match */
1578 /*------------------------------------------------------------------*/
1580 * Extract all the sysfs values of an interface
1583 mapping_getsysfs(int skfd,
1584 const char * ifname,
1585 struct if_mapping * target,
1591 char * linebuf = NULL;
1594 int findex; /* filename index */
1596 /* Avoid "Unused parameter" warning */
1600 /* Check if we know the devpath of this device */
1601 if(target->sysfs_devpath == NULL)
1603 /* Check if we know the root of the sysfs filesystem */
1604 if(sysfs_global.root == NULL)
1606 /* Open the mount file for reading */
1607 stream = fopen("/proc/mounts", "r");
1610 fprintf(stderr, "Error: Can't open /proc/mounts file: %s\n",
1615 /* Read each line of file
1616 * getline is a GNU extension :-( The buffer is recycled and
1617 * increased as needed by getline. */
1618 while(getline(&linebuf, &linelen, stream) > 0)
1626 /* The format of /proc/mounts is similar to /etc/fstab (5).
1627 * The first argument is the device. For sysfs, there is no
1628 * associated device, so this argument is ignored.
1629 * The second argument is the mount point.
1630 * The third argument is the filesystem type.
1633 /* Extract the first 3 tokens */
1635 for(i = 0; i < 3; i++)
1640 n = strcspn(p, " \t\n");
1644 /* Get the filesystem which type is "sysfs" */
1645 if((n == 5) && (!strncasecmp(token[2], "sysfs", 5)))
1647 /* Get its mount point */
1649 sdup = strndup(token[1], n);
1650 if((n == 0) || (sdup == NULL))
1653 "Error: Can't parse /proc/mounts file: %s\n",
1658 sysfs_global.root = sdup;
1659 sysfs_global.rlen = n;
1662 /* Finished -> next line */
1668 /* Check if we found it */
1669 if(sysfs_global.root == NULL)
1672 "Error: Can't find sysfs in /proc/mounts file\n");
1678 /* Construct devpath for this interface.
1679 * Reserve enough space to replace name without realloc. */
1680 fnsize = (sysfs_global.rlen + 11 + IFNAMSIZ + 1);
1681 fname = malloc(fnsize);
1684 fprintf(stderr, "Error: Can't allocate SYSFS devpath\n");
1687 /* Not true devpath for 2.6.20+, but this syslink should work */
1688 target->sysfs_devplen = sprintf(fname, "%s/class/net/%s",
1689 sysfs_global.root, ifname);
1690 target->sysfs_devpath = fname;
1693 /* Loop on all sysfs selector */
1694 for(findex = 0; findex < sysfs_global.filenum; findex++)
1699 /* Construct complete filename for the sysfs selector */
1700 fnsize = (target->sysfs_devplen + 1 +
1701 strlen(sysfs_global.filename[findex]) + 1);
1702 fname = malloc(fnsize);
1705 fprintf(stderr, "Error: Can't allocate SYSFS filename\n");
1709 sprintf(fname, "%s/%s", target->sysfs_devpath,
1710 sysfs_global.filename[findex]);
1712 /* Open the sysfs file for reading */
1713 stream = fopen(fname, "r");
1716 /* Some sysfs attribute may no exist for some interface */
1718 fprintf(stderr, "Error: Can't open file `%s': %s\n", fname,
1720 /* Next sysfs selector */
1724 /* Read file. Only one line in file. */
1725 n = getline(&linebuf, &linelen, stream);
1729 /* Some attributes are just symlinks to another directory.
1730 * We can read the attributes in that other directory
1731 * just fine, but sometimes the symlink itself gives a lot
1733 * Examples : SYSFS{device} and SYSFS{device/driver}
1734 * In such cases, get the name of the directory pointed to...
1737 * I must note that the API for readlink() is very bad,
1738 * which force us to have this ugly code. Yuck !
1740 int allocsize = 128; /* 256 = Good start */
1742 char * linkpath = NULL;
1745 /* Try reading the link with increased buffer size */
1749 linkpath = realloc(linkpath, allocsize);
1750 pathlen = readlink(fname, linkpath, allocsize);
1751 /* If we did not hit the buffer limit, success */
1752 if(pathlen < allocsize)
1757 /* Check for error, most likely ENOENT */
1759 /* We have a symlink ;-) Terminate the string. */
1760 linkpath[pathlen] = '\0';
1766 /* A lot of information in the sysfs is implicit, given
1767 * by the position of a file in the tree. It is therefore
1768 * important to be able to read the various components
1769 * of a path. For this reason, we resolve '..' to the
1770 * real name of the parent directory... */
1771 /* We have at least 11 char, see above */
1772 if(!strcmp(fname + fnsize - 4, "/.."))
1773 //if(!strcmp(fname + strlen(fname) - 3, "/.."))
1775 /* This procedure to get the realpath is not very
1776 * nice, but it's the "best practice". Hmm... */
1777 int cwd_fd = open(".", O_RDONLY);
1781 int ret = chdir(fname);
1783 /* Using getcwd with NULL is a GNU extension. Nice. */
1784 linkpath = getcwd(NULL, 0);
1785 /* This may fail, but it's not fatal */
1788 /* Check if we suceeded */
1793 fprintf(stderr, "Error: Can't read parent directory `%s'\n", fname);
1794 /* Next sysfs selector */
1800 /* Some sysfs attribute are void for some interface,
1801 * we may have a real directory, or we may have permission
1804 fprintf(stderr, "Error: Can't read file `%s'\n", fname);
1805 /* Next sysfs selector */
1810 /* Here, we have a link name or a parent directory name */
1812 /* Keep only the last component of path name, save it */
1813 p = basename(linkpath);
1819 /* This is a regular file (well, pseudo file) */
1820 /* Get content, remove trailing '/n', save it */
1822 if(p[n - 1] == '\n')
1824 sdup = strndup(p, n);
1828 fprintf(stderr, "Error: Can't allocate SYSFS value\n");
1832 target->sysfs[findex] = sdup;
1835 target->active[SELECT_SYSFS] = 1;
1839 "Querying %s : Got SYSFS filename `%s' value `%s'.\n",
1840 ifname, sysfs_global.filename[findex], target->sysfs[findex]);
1842 /* Finished : Next sysfs selector */
1848 return(target->active[SELECT_SYSFS] ? 0 : -1);
1851 /*------------------------------------------------------------------*/
1853 * Add a Previous Interface Name selector to a mapping
1856 mapping_addprevname(struct if_mapping * ifnode,
1860 struct add_extra * extra,
1863 /* Avoid "Unused parameter" warning */
1866 /* Verify validity of string */
1867 if(len >= sizeof(ifnode->prevname))
1869 fprintf(stderr, "Old Interface Name too long at line %d\n", linenum);
1874 memcpy(ifnode->prevname, string, len + 1);
1877 ifnode->active[SELECT_PREVNAME] = 1;
1878 active[SELECT_PREVNAME] = 1;
1882 "Parsing : Added Old Interface Name `%s' from line %d.\n",
1883 ifnode->prevname, linenum);
1888 /*------------------------------------------------------------------*/
1890 * Compare the Previous Interface Name of two mappings
1891 * Note : this one is special.
1894 mapping_cmpprevname(struct if_mapping * ifnode,
1895 struct if_mapping * target)
1897 /* Do wildcard matching, case insensitive */
1898 return(fnmatch(ifnode->prevname, target->ifname, FNM_CASEFOLD));
1901 /*------------------------------------------------------------------*/
1903 * Extract the Previous Interface Name from a live interface
1906 mapping_getprevname(int skfd,
1907 const char * ifname,
1908 struct if_mapping * target,
1911 /* Avoid "Unused parameter" warning */
1912 skfd = skfd; ifname = ifname; flag = flag;
1914 /* Don't do anything, it's already in target->ifname ;-) */
1917 target->active[SELECT_PREVNAME] = 1;
1923 /*********************** MAPPING MANAGEMENTS ***********************/
1925 * Manage interface mappings.
1926 * Each mapping tell us how to identify a specific interface name.
1927 * It is composed of a bunch of selector values.
1930 /*------------------------------------------------------------------*/
1932 * Create a new interface mapping and verify its name
1934 static struct if_mapping *
1935 mapping_create(char * pos,
1939 struct if_mapping * ifnode;
1942 star = memchr(pos, '*', len);
1944 /* Check overflow, need one extra char for wildcard */
1945 if((len + (star != NULL)) > IFNAMSIZ)
1947 fprintf(stderr, "Error: Interface name `%.*s' too long at line %d\n",
1948 (int) len, pos, linenum);
1952 /* Create mapping, zero it */
1953 ifnode = calloc(1, sizeof(if_mapping));
1956 fprintf(stderr, "Error: Can't allocate interface mapping.\n");
1960 /* Set the name, terminates it */
1961 memcpy(ifnode->ifname, pos, len);
1962 ifnode->ifname[len] = '\0';
1964 /* Check the interface name and issue various pedantic warnings.
1965 * We assume people using takeover want to force interfaces to those
1966 * names and know what they are doing, so don't bother them... */
1967 if((!force_takeover) &&
1968 ((!strcmp(ifnode->ifname, "eth0")) || (!strcmp(ifnode->ifname, "wlan0"))))
1970 "Warning: Interface name is `%s' at line %d, can't be mapped reliably.\n",
1971 ifnode->ifname, linenum);
1972 if(strchr(ifnode->ifname, ':'))
1973 fprintf(stderr, "Warning: Alias device `%s' at line %d probably can't be mapped.\n",
1974 ifnode->ifname, linenum);
1977 fprintf(stderr, "Parsing : Added Mapping `%s' from line %d.\n",
1978 ifnode->ifname, linenum);
1984 /*------------------------------------------------------------------*/
1986 * Find the most appropriate selector matching a given selector name
1988 static inline const struct mapping_selector *
1989 selector_find(const char * string,
1993 const struct mapping_selector * found = NULL;
1997 /* Go through all selectors */
1998 for(i = 0; selector_list[i].name != NULL; ++i)
2000 /* No match -> next one */
2001 if(strncasecmp(selector_list[i].name, string, slen) != 0)
2004 /* Exact match -> perfect */
2005 if(slen == strlen(selector_list[i].name))
2006 return &selector_list[i];
2011 found = &selector_list[i];
2014 if (selector_list[i].add_fn != found->add_fn)
2020 fprintf(stderr, "Error: Unknown selector `%.*s' at line %d.\n",
2021 (int) slen, string, linenum);
2027 fprintf(stderr, "Selector `%.*s'at line %d is ambiguous.\n",
2028 (int) slen, string, linenum);
2035 /*------------------------------------------------------------------*/
2037 * Read the configuration file and extract all valid mappings and their
2041 mapping_readfile(const char * filename)
2044 char * linebuf = NULL;
2047 struct add_extra extrainfo;
2049 /* Reset the list of filters */
2050 bzero(selector_active, sizeof(selector_active));
2052 /* Check filename */
2053 if(!strcmp(filename, "-"))
2055 /* Read from stdin */
2061 /* Open the file for reading */
2062 stream = fopen(filename, "r");
2065 fprintf(stderr, "Error: Can't open configuration file `%s': %s\n",
2066 filename, strerror(errno));
2071 /* Read each line of file
2072 * getline is a GNU extension :-( The buffer is recycled and increased
2073 * as needed by getline. */
2074 while(getline(&linebuf, &linelen, stream) > 0)
2076 struct if_mapping * ifnode;
2080 int ret = -13; /* Complain if no selectors */
2082 /* Keep track of line number */
2085 /* Every comments terminates parsing */
2086 if((p = strchr(linebuf,'#')) != NULL)
2089 /* Get interface name */
2094 continue; /* Line ended */
2095 n = strcspn(p, " \t\n");
2097 /* Create mapping */
2098 ifnode = mapping_create(p, n, linenum);
2100 continue; /* Ignore this line */
2102 p += strspn(p, " \t\n");
2104 /* Loop on all selectors */
2107 const struct mapping_selector * selector = NULL;
2108 struct add_extra * extra = NULL;
2110 /* Selector name length - stop at modifier start */
2111 n = strcspn(p, " \t\n{");
2114 selector = selector_find(p, n, linenum);
2122 /* Check for modifier */
2126 /* Find end of modifier */
2131 "Error: unterminated selector modifier value on line %d\n",
2134 break; /* Line ended */
2136 /* Fill in struct and hook it */
2137 extrainfo.modif_pos = p;
2138 extrainfo.modif_len = e - p;
2140 /* Terminate modifier value */
2146 /* Get to selector value */
2147 p += strspn(p, " \t\n");
2150 fprintf(stderr, "Error: no value for selector `%s' on line %d\n",
2151 selector->name, linenum);
2153 break; /* Line ended */
2155 /* Check for quoted arguments */
2163 "Error: unterminated quoted value on line %d\n",
2166 break; /* Line ended */
2173 /* Just end at next blank */
2174 n = strcspn(p, " \t\n");
2177 /* Make 'e' point past the '\0' we are going to add */
2180 /* Terminate selector value */
2183 /* Add it to the mapping */
2184 ret = selector->add_fn(ifnode, selector_active, p, n,
2189 /* Go to next selector */
2191 p += strspn(p, " \t\n");
2194 /* We add a mapping only if it has at least one selector and if all
2195 * selectors were parsed properly. */
2198 /* If we have not yet printed an error, now is a good time ;-) */
2200 fprintf(stderr, "Error: Line %d ignored, no valid selectors\n",
2203 fprintf(stderr, "Error: Line %d ignored due to prior errors\n",
2210 /* Link it in the list */
2211 ifnode->next = mapping_list;
2212 mapping_list = ifnode;
2219 /* Finished reading, close the file */
2225 /*------------------------------------------------------------------*/
2227 * Extract all the interesting selectors for the interface in consideration
2229 static struct if_mapping *
2230 mapping_extract(int skfd,
2231 const char * ifname)
2233 struct if_mapping * target;
2236 /* Create mapping, zero it */
2237 target = calloc(1, sizeof(if_mapping));
2240 fprintf(stderr, "Error: Can't allocate interface mapping.\n");
2244 /* Set the interface name */
2245 strcpy(target->ifname, ifname);
2247 /* Loop on all active selectors */
2248 for(i = 0; i < SELECT_NUM; i++)
2250 /* Check if this selector is active */
2251 if(selector_active[i] != 0)
2253 /* Extract selector */
2254 selector_list[i].get_fn(skfd, ifname, target, selector_active[i]);
2256 /* Ignore errors. Some mapping may not need all selectors */
2263 /*------------------------------------------------------------------*/
2265 * Find the first mapping in the list matching the one we want.
2267 static struct if_mapping *
2268 mapping_find(struct if_mapping * target)
2270 struct if_mapping * ifnode;
2273 /* Look over all our mappings */
2274 for(ifnode = mapping_list; ifnode != NULL; ifnode = ifnode->next)
2278 /* Look over all our selectors, all must match */
2279 for(i = 0; i < SELECT_NUM; i++)
2281 /* Check if this selector is active */
2282 if(ifnode->active[i] != 0)
2284 /* If this selector doesn't match, game over for this mapping */
2285 if((target->active[i] == 0) ||
2286 (selector_list[i].cmp_fn(ifnode, target) != 0))
2294 /* Check is this mapping was "the one" */
2303 /************************** MODULE SUPPORT **************************/
2305 * Load all necessary module so that interfaces do exist.
2306 * This is necessary for system that are fully modular when
2307 * doing the boot time processing, because we need to run before
2311 /*------------------------------------------------------------------*/
2313 * Probe interfaces based on our list of mappings.
2314 * This is the default, but usually not the best way to do it.
2317 probe_mappings(int skfd)
2319 struct if_mapping * ifnode;
2322 /* Look over all our mappings */
2323 for(ifnode = mapping_list; ifnode != NULL; ifnode = ifnode->next)
2325 /* Can't load wildcards interface name :-( */
2326 if(strchr(ifnode->ifname, '%') != NULL)
2330 fprintf(stderr, "Probing : Trying to load interface [%s]\n",
2333 /* Trick the kernel into loading the interface.
2334 * This allow us to not depend on the exact path and
2335 * name of the '/sbin/modprobe' command.
2336 * Obviously, we expect this command to 'fail', as
2337 * the interface will load with the old/wrong name.
2339 strncpy(ifr.ifr_name, ifnode->ifname, IFNAMSIZ);
2340 ioctl(skfd, SIOCGIFHWADDR, &ifr);
2344 /*------------------------------------------------------------------*/
2346 * Probe interfaces based on Debian's config files.
2347 * This allow to enly load modules for interfaces the user want active,
2348 * all built-in interfaces that should remain unconfigured won't
2349 * be probed (and can have mappings).
2352 probe_debian(int skfd)
2355 char * linebuf = NULL;
2359 /* Open Debian config file */
2360 stream = fopen(DEBIAN_CONFIG_FILE, "r");
2363 fprintf(stderr, "Error: can't open file [%s]\n", DEBIAN_CONFIG_FILE);
2367 /* Read each line of file
2368 * getline is a GNU extension :-( The buffer is recycled and increased
2369 * as needed by getline. */
2370 while(getline(&linebuf, &linelen, stream) > 0)
2376 /* Check for auto keyword, ignore when commented out */
2377 if(!strncasecmp(linebuf, "auto ", 5))
2379 /* Skip "auto" keyword */
2382 /* Terminate at first comment */
2387 /* Loop on all interfaces given */
2390 /* Interface name length */
2391 n = strcspn(p, " \t\n");
2393 /* Look for end of interface name */
2395 /* Make 'e' point past the '\0' we are going to add */
2398 /* Terminate interface name */
2402 fprintf(stderr, "Probing : Trying to load interface [%s]\n",
2405 /* Load interface */
2406 strncpy(ifr.ifr_name, p, IFNAMSIZ);
2407 ioctl(skfd, SIOCGIFHWADDR, &ifr);
2409 /* Go to next interface name */
2411 p += strspn(p, " \t\n");
2421 /**************************** MAIN LOGIC ****************************/
2423 /*------------------------------------------------------------------*/
2425 * Rename an interface to a specified new name.
2428 process_rename(int skfd,
2432 char retname[IFNAMSIZ+1];
2436 len = strlen(newname);
2437 star = strchr(newname, '*');
2439 /* Check newname length, need one extra char for wildcard */
2440 if((len + (star != NULL)) > IFNAMSIZ)
2442 fprintf(stderr, "Error: Interface name `%s' too long.\n",
2447 /* Change the name of the interface */
2448 if(if_set_name(skfd, ifname, newname, retname) < 0)
2450 fprintf(stderr, "Error: cannot change name of %s to %s: %s\n",
2451 ifname, newname, strerror(errno));
2455 /* Always print out the *new* interface name so that
2456 * the calling script can pick it up and know where its interface
2458 printf("%s\n", retname);
2464 /*------------------------------------------------------------------*/
2466 * Process a specified interface.
2469 process_ifname(int skfd,
2474 struct if_mapping * target;
2475 const struct if_mapping * mapping;
2476 char retname[IFNAMSIZ+1];
2478 /* Avoid "Unused parameter" warning */
2479 args = args; count = count;
2481 /* Get description of this interface */
2482 target = mapping_extract(skfd, ifname);
2486 /* If udev is calling us, get the real devpath. */
2490 /* It's passed to us as an environment variable */
2491 env = getenv("DEVPATH");
2494 int env_len = strlen(env);
2495 target->sysfs_devplen = env_len;
2496 /* Make enough space for new interface name */
2497 target->sysfs_devpath = malloc(env_len + IFNAMSIZ + 1);
2498 if(target->sysfs_devpath != NULL)
2499 memcpy(target->sysfs_devpath, env, env_len + 1);
2501 /* We will get a second chance is the user has some sysfs selectors */
2504 /* Find matching mapping */
2505 mapping = mapping_find(target);
2509 /* If user specified a new name, keep only interfaces that would
2510 * match the new name... */
2511 if((new_name != NULL) && (if_match_ifname(mapping->ifname, new_name) != 0))
2514 /* Check if user want only dry-run.
2515 * Note that, in the case of wildcard, we don't resolve the wildcard.
2516 * That would be tricky to do... */
2519 strcpy(retname, mapping->ifname);
2520 fprintf(stderr, "Dry-run : Would rename %s to %s.\n",
2521 target->ifname, mapping->ifname);
2525 /* Change the name of the interface */
2526 if(if_set_name(skfd, target->ifname, mapping->ifname, retname) < 0)
2528 fprintf(stderr, "Error: cannot change name of %s to %s: %s\n",
2529 target->ifname, mapping->ifname, strerror(errno));
2534 /* Check if called with an explicit interface name */
2538 /* Always print out the *new* interface name so that
2539 * the calling script can pick it up and know where its interface
2541 printf("%s\n", retname);
2543 /* udev likes to call us as an IMPORT action. This means that
2544 * we need to return udev the environment variables changed.
2545 * Obviously, we don't want to return anything is nothing changed. */
2546 if(strcmp(target->ifname, retname))
2550 if(!target->sysfs_devpath)
2551 mapping_getsysfs(skfd, ifname, target, 0);
2552 /* Update devpath. Size is large enough. */
2553 pos = strrchr(target->sysfs_devpath, '/');
2554 if((pos != NULL) && (!strcmp(target->ifname, pos + 1)))
2555 strcpy(pos + 1, retname);
2556 /* Return new environment variables */
2557 printf("DEVPATH=%s\nINTERFACE=%s\nINTERFACE_OLD=%s\n",
2558 target->sysfs_devpath, retname, target->ifname);
2566 /*------------------------------------------------------------------*/
2568 * Process all network interface present on the system.
2571 process_iflist(int skfd,
2578 iw_enum_devices(skfd, &process_ifname, args, count);
2580 /* If we do any takeover, the interface list grabbed with
2581 * iw_enum_devices() may get out of sync with the real interfaces,
2582 * and we may miss the victim interface. So, let's go through the
2584 * On the other hand, we may have ping pong between two interfaces,
2585 * each claiming the same name, so let's not do it forever...
2586 * Two time should be enough for most configs...
2588 if(force_takeover && num_takeover)
2589 /* Play it again, Sam... */
2590 iw_enum_devices(skfd, &process_ifname, args, count);
2596 /******************************* MAIN *******************************/
2599 /*------------------------------------------------------------------*/
2605 fprintf(stderr, "usage: ifrename [-c configurationfile] [-i ifname] [-p] [-t] [-d] [-D]\n");
2609 /*------------------------------------------------------------------*/
2617 const char * conf_file = DEFAULT_CONF;
2618 char * ifname = NULL;
2624 /* Loop over all command line options */
2627 int c = getopt_long(argc, argv, "c:dDi:n:ptuvV", long_opt, NULL);
2661 printf("%-8.16s Wireless-Tools version %d\n", "ifrename", WT_VERSION);
2669 /* Read the specified/default config file, or stdin. */
2670 if(mapping_readfile(conf_file) < 0)
2673 /* Create a channel to the NET kernel. */
2674 if((skfd = iw_sockets_open()) < 0)
2680 /* Check if interface name was specified with -i. */
2683 /* Check is target name specified */
2684 if(new_name != NULL)
2686 /* User want to simply rename an interface to a specified name */
2687 ret = process_rename(skfd, ifname, new_name);
2691 /* Rename only this interface based on mappings
2692 * Mostly used for HotPlug processing (from /etc/hotplug/net.agent)
2693 * or udev processing (from a udev IMPORT rule).
2694 * Process the network interface specified on the command line,
2695 * and return the new name on stdout.
2698 ret = process_ifname(skfd, ifname, NULL, 0);
2703 /* Load all the necesary modules */
2709 probe_mappings(skfd);
2712 /* Rename all system interfaces
2713 * Mostly used for boot time processing (from init scripts).
2715 ret = process_iflist(skfd, NULL, 0);
2719 iw_sockets_close(skfd);