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) 2004 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 * Add hotplug compatibility : ifname -i eth0. Jean II - 03.12.03
26 * Add MAC address wildcard : 01:23:45:*. Jean II - 03.12.03
27 * Add interface name wildcard : wlan*. Jean II - 03.12.03
28 * Add interface name probing for modular systems. Jean II - 18.02.03
29 * -------------------------------------------------------
31 * The last 4 patches never made it into the regular version of
32 * 'nameif', and had some 'issues', which is the reason of this rewrite.
33 * Difference with standard 'nameif' :
34 * o 'nameif' has only a single selector, the interface MAC address.
35 * o Modular selector architecture, easily add new selectors.
36 * o hotplug invocation support.
37 * o module loading support.
38 * o MAC address wildcard.
39 * o Interface name wildcard ('eth*' or 'wlan*').
42 /***************************** INCLUDES *****************************/
44 /* This is needed to enable GNU extensions such as getline & FNM_CASEFOLD */
49 #include <getopt.h> /* getopt_long() */
50 #include <linux/sockios.h> /* SIOCSIFNAME */
51 #include <fnmatch.h> /* fnmatch() */
52 //#include <sys/syslog.h>
54 #include "iwlib.h" /* Wireless Tools library */
56 // This would be cool, unfortunately...
57 //#include <linux/ethtool.h> /* Ethtool stuff -> struct ethtool_drvinfo */
59 /************************ CONSTANTS & MACROS ************************/
61 /* Our default configuration file */
62 const char DEFAULT_CONF[] = "/etc/iftab";
65 const char DEBIAN_CONFIG_FILE[] = "/etc/network/interfaces";
67 /* Backward compatibility */
69 #define ifr_newname ifr_ifru.ifru_slave
72 /* Types of selector we support. Must match selector_list */
73 const int SELECT_MAC = 0; /* Select by MAC address */
74 const int SELECT_ETHADDR = 1; /* Select by MAC address */
75 const int SELECT_ARP = 2; /* Select by ARP type */
76 const int SELECT_LINKTYPE = 3; /* Select by ARP type */
77 const int SELECT_DRIVER = 4; /* Select by Driver name */
78 const int SELECT_BUSINFO = 5; /* Select by Bus-Info */
79 const int SELECT_FIRMWARE = 6; /* Select by Firmware revision */
80 const int SELECT_BASEADDR = 7; /* Select by HW Base Address */
81 const int SELECT_IRQ = 8; /* Select by HW Irq line */
82 const int SELECT_INTERRUPT = 9; /* Select by HW Irq line */
83 const int SELECT_IWPROTO = 10; /* Select by Wireless Protocol */
84 const int SELECT_PCMCIASLOT = 11; /* Select by Wireless Protocol */
87 #define HAS_MAC_EXACT 1
88 #define HAS_MAC_FILTER 2
90 const struct ether_addr zero_mac = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
92 const struct option long_opt[] =
94 {"config-file", 1, NULL, 'c' },
95 {"debian", 0, NULL, 'd' },
96 {"dry-run", 0, NULL, 'D' },
97 {"help", 0, NULL, '?' },
98 {"interface", 1, NULL, 'i' },
99 {"newname", 1, NULL, 'n' },
100 {"takeover", 0, NULL, 't' },
101 {"version", 0, NULL, 'v' },
102 {"verbose", 0, NULL, 'V' },
103 {NULL, 0, NULL, '\0' },
106 /* Pcmcia stab files */
107 #define PCMCIA_STAB1 "/var/lib/pcmcia/stab"
108 #define PCMCIA_STAB2 "/var/run/stab"
110 /****************************** TYPES ******************************/
112 /* Cut'n'paste from ethtool.h */
113 #define ETHTOOL_BUSINFO_LEN 32
114 /* these strings are set to whatever the driver author decides... */
115 struct ethtool_drvinfo {
117 char driver[32]; /* driver short name, "tulip", "eepro100" */
118 char version[32]; /* driver version string */
119 char fw_version[32]; /* firmware version string, if applicable */
120 char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */
121 /* For PCI devices, use pci_dev->slot_name. */
124 __u32 n_stats; /* number of u64's from ETHTOOL_GSTATS */
126 __u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */
127 __u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */
129 #define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */
131 /* Description of an interface mapping */
132 typedef struct if_mapping
135 struct if_mapping * next;
137 /* Name of this interface */
138 char ifname[IFNAMSIZ+1];
140 /* Selectors for this interface */
141 int active[SELECT_NUM]; /* Selectors active */
144 struct ether_addr mac; /* Exact MAC address, hex */
145 char mac_filter[6*3 + 1]; /* WildCard, ascii */
146 unsigned short hw_type; /* Link/ARP type */
147 char driver[32]; /* driver short name */
148 char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */
149 char fw_version[32]; /* Firmware revision */
150 unsigned short base_addr; /* HW Base I/O address */
151 unsigned char irq; /* HW irq line */
152 char iwproto[IFNAMSIZ + 1]; /* Wireless/protocol name */
153 int pcmcia_slot; /* Pcmcia slot */
156 /* Prototype for adding a selector to a mapping. Return -1 if invalid value. */
157 typedef int (*mapping_add)(struct if_mapping * ifnode,
163 /* Prototype for comparing the selector of two mapping. Return 0 if matches. */
164 typedef int (*mapping_cmp)(struct if_mapping * ifnode,
165 struct if_mapping * target);
166 /* Prototype for extracting selector value from live interface */
167 typedef int (*mapping_get)(int skfd,
169 struct if_mapping * target,
172 /* How to handle a selector */
173 typedef struct mapping_selector
181 /**************************** PROTOTYPES ****************************/
184 mapping_addmac(struct if_mapping * ifnode,
190 mapping_cmpmac(struct if_mapping * ifnode,
191 struct if_mapping * target);
193 mapping_getmac(int skfd,
195 struct if_mapping * target,
198 mapping_addarp(struct if_mapping * ifnode,
204 mapping_cmparp(struct if_mapping * ifnode,
205 struct if_mapping * target);
207 mapping_getarp(int skfd,
209 struct if_mapping * target,
212 mapping_adddriver(struct if_mapping * ifnode,
218 mapping_cmpdriver(struct if_mapping * ifnode,
219 struct if_mapping * target);
221 mapping_addbusinfo(struct if_mapping * ifnode,
227 mapping_cmpbusinfo(struct if_mapping * ifnode,
228 struct if_mapping * target);
230 mapping_addfirmware(struct if_mapping * ifnode,
236 mapping_cmpfirmware(struct if_mapping * ifnode,
237 struct if_mapping * target);
239 mapping_getdriverbusinfo(int skfd,
241 struct if_mapping * target,
244 mapping_addbaseaddr(struct if_mapping * ifnode,
250 mapping_cmpbaseaddr(struct if_mapping * ifnode,
251 struct if_mapping * target);
253 mapping_addirq(struct if_mapping * ifnode,
259 mapping_cmpirq(struct if_mapping * ifnode,
260 struct if_mapping * target);
262 mapping_getbaseaddrirq(int skfd,
264 struct if_mapping * target,
267 mapping_addiwproto(struct if_mapping * ifnode,
273 mapping_cmpiwproto(struct if_mapping * ifnode,
274 struct if_mapping * target);
276 mapping_getiwproto(int skfd,
278 struct if_mapping * target,
281 mapping_addpcmciaslot(struct if_mapping * ifnode,
287 mapping_cmppcmciaslot(struct if_mapping * ifnode,
288 struct if_mapping * target);
290 mapping_getpcmciaslot(int skfd,
292 struct if_mapping * target,
295 /**************************** VARIABLES ****************************/
297 /* List of mapping read for config file */
298 struct if_mapping * mapping_list = NULL;
300 /* List of selectors we can handle */
301 const struct mapping_selector selector_list[] =
303 /* MAC address and ARP/Link type from ifconfig */
304 { "mac", &mapping_addmac, &mapping_cmpmac, &mapping_getmac },
305 { "ethaddr", &mapping_addmac, &mapping_cmpmac, &mapping_getmac },
306 { "arp", &mapping_addarp, &mapping_cmparp, &mapping_getarp },
307 { "linktype", &mapping_addarp, &mapping_cmparp, &mapping_getarp },
308 /* Driver name, Bus-Info and firmware rev from ethtool -i */
309 { "driver", &mapping_adddriver, &mapping_cmpdriver,
310 &mapping_getdriverbusinfo },
311 { "businfo", &mapping_addbusinfo, &mapping_cmpbusinfo,
312 &mapping_getdriverbusinfo },
313 { "firmware", &mapping_addfirmware, &mapping_cmpfirmware,
314 &mapping_getdriverbusinfo },
315 /* Base Address and IRQ from ifconfig */
316 { "baseaddress", &mapping_addbaseaddr, &mapping_cmpbaseaddr,
317 &mapping_getbaseaddrirq },
318 { "irq", &mapping_addirq, &mapping_cmpirq, &mapping_getbaseaddrirq },
319 { "interrupt", &mapping_addirq, &mapping_cmpirq, &mapping_getbaseaddrirq },
320 /* Wireless Protocol from iwconfig */
321 { "iwproto", &mapping_addiwproto, &mapping_cmpiwproto, &mapping_getiwproto },
322 /* Pcmcia slot from cardmgr */
323 { "pcmciaslot", &mapping_addpcmciaslot, &mapping_cmppcmciaslot, &mapping_getpcmciaslot },
325 { NULL, NULL, NULL, NULL },
327 const int selector_num = sizeof(selector_list)/sizeof(selector_list[0]);
329 /* List of active selectors */
330 int selector_active[SELECT_NUM]; /* Selectors active */
332 /* Takeover support */
333 int force_takeover = 0; /* Takeover name from other interface */
334 int num_takeover = 0; /* Number of takeover done */
336 /* Dry-run support */
337 int dry_run = 0; /* Just print new name, don't rename */
339 /* Verbose support (i.e. debugging) */
342 /******************** INTERFACE NAME MANAGEMENT ********************/
344 * Bunch of low level function for managing interface names.
347 /*------------------------------------------------------------------*/
349 * Compare two interface names, with wildcards.
350 * We can't use fnmatch() because we don't want expansion of '[...]'
351 * expressions, '\' sequences and matching of '.'.
352 * We only want to match a single '*' (converted to a %d at that point)
353 * to a numerical value (no ascii).
354 * Return 0 is matches.
357 if_match_ifname(const char * pattern,
365 /* Check for a wildcard (converted from '*' to '%d' in mapping_create()) */
366 p = strstr(pattern, "%d");
368 /* No wildcard, simple comparison */
370 return(strcmp(pattern, value));
372 /* Check is prefixes match */
374 ret = strncmp(pattern, value, n);
378 /* Check that value has some digits at this point */
383 /* Skip digits to go to value suffix */
391 /* Compare suffixes */
392 return(strcmp(p, v));
395 /*------------------------------------------------------------------*/
397 * Steal interface name from another interface. This enable interface
400 * 1) with kernel 2.6.X
401 * 2) if other interface is down
402 * Because of (2), it won't work with hotplug, but we don't need it
403 * with hotplug, only with static ifaces...
406 if_takeover_name(int skfd,
407 const char * victimname)
409 char autoname[IFNAMSIZ+1];
414 /* Compute name for victim interface */
415 len = strlen(victimname);
416 memcpy(autoname, victimname, len + 1);
417 if(len > (IFNAMSIZ - 2))
418 len = IFNAMSIZ - 2; /* Make sure we have at least two char */
419 len--; /* Convert to index */
420 while(isdigit(autoname[len]))
421 len--; /* Scrap all trailing digits */
422 strcpy(autoname + len + 1, "%d");
425 fprintf(stderr, "Takeover : moving interface `%s' to `%s'.\n",
426 victimname, autoname);
428 /* Prepare request */
429 bzero(&ifr, sizeof(struct ifreq));
430 strncpy(ifr.ifr_name, victimname, IFNAMSIZ);
431 strncpy(ifr.ifr_newname, autoname, IFNAMSIZ);
433 /* Rename victim interface */
434 ret = ioctl(skfd, SIOCSIFNAME, &ifr);
442 /*------------------------------------------------------------------*/
444 * Ask the kernel to change the name of an interface.
445 * That's what we want to do. All the rest is to make sure we call this
449 if_set_name(int skfd,
450 const char * oldname,
451 const char * newname,
457 /* The kernel doesn't check is the interface already has the correct
458 * name and may return an error, so check ourselves.
459 * In the case of wildcard, the result can be weird : if oldname='eth0'
460 * and newname='eth*', retname would be 'eth1'.
461 * So, if the oldname value matches the newname pattern, just return
463 if(!if_match_ifname(newname, oldname))
466 fprintf(stderr, "Setting : Interface `%s' already matches `%s'.\n",
469 strcpy(retname, oldname);
473 /* Prepare request */
474 bzero(&ifr, sizeof(struct ifreq));
475 strncpy(ifr.ifr_name, oldname, IFNAMSIZ);
476 strncpy(ifr.ifr_newname, newname, IFNAMSIZ);
479 ret = ioctl(skfd, SIOCSIFNAME, &ifr);
481 /* Takeover support : grab interface name from another interface */
482 if(ret && (errno == EEXIST) && force_takeover)
484 /* Push things around */
485 ret = if_takeover_name(skfd, newname);
488 ret = ioctl(skfd, SIOCSIFNAME, &ifr);
493 /* Get the real new name (in case newname is a wildcard) */
494 strcpy(retname, ifr.ifr_newname);
497 fprintf(stderr, "Setting : Interface `%s' renamed to `%s'.\n",
504 /************************ SELECTOR HANDLING ************************/
506 * Handle the various selector we support
509 /*------------------------------------------------------------------*/
511 * Add a MAC address selector to a mapping
514 mapping_addmac(struct if_mapping * ifnode,
522 /* Verify validity of string */
523 if(len >= sizeof(ifnode->mac_filter))
525 fprintf(stderr, "MAC address too long at line %d\n", linenum);
528 n = strspn(string, "0123456789ABCDEFabcdef:*");
531 fprintf(stderr, "Error: Invalid MAC address `%s' at line %d\n",
536 /* Copy as filter in all cases */
537 memcpy(ifnode->mac_filter, string, len + 1);
539 /* Check the type of MAC address */
540 if (strchr(ifnode->mac_filter, '*') != NULL)
542 /* This is a wilcard. Usual format : "01:23:45:*"
543 * Unfortunately, we can't do proper parsing. */
544 ifnode->active[SELECT_MAC] = HAS_MAC_FILTER;
545 active[SELECT_MAC] = HAS_MAC_FILTER;
549 /* Not a wildcard : "01:23:45:67:89:AB" */
550 if(iw_ether_aton(ifnode->mac_filter, &ifnode->mac) != 1)
552 fprintf(stderr, "Error: Invalid MAC address `%s' at line %d\n",
553 ifnode->mac_filter, linenum);
557 /* Check that it's not NULL */
558 if(!memcmp(&ifnode->mac, &zero_mac, 6))
561 "Warning: MAC address is null at line %d, this is dangerous...\n",
565 ifnode->active[SELECT_MAC] = HAS_MAC_EXACT;
566 if(active[SELECT_MAC] == 0)
567 active[SELECT_MAC] = HAS_MAC_EXACT;
572 "Parsing : Added %s MAC address `%s' from line %d.\n",
573 ifnode->active[SELECT_MAC] == HAS_MAC_FILTER ? "filter" : "exact",
574 ifnode->mac_filter, linenum);
579 /*------------------------------------------------------------------*/
581 * Compare the mac address of two mappings
584 mapping_cmpmac(struct if_mapping * ifnode,
585 struct if_mapping * target)
587 /* Check for wildcard matching */
588 if(ifnode->active[SELECT_MAC] == HAS_MAC_FILTER)
589 /* Do wildcard matching, case insensitive */
590 return(fnmatch(ifnode->mac_filter, target->mac_filter, FNM_CASEFOLD));
592 /* Exact matching, in hex */
593 return(memcmp(&ifnode->mac.ether_addr_octet, &target->mac.ether_addr_octet,
597 /*------------------------------------------------------------------*/
599 * Extract the MAC address and Link Type of an interface
602 mapping_getmac(int skfd,
604 struct if_mapping * target,
609 /* Extract MAC address */
610 ret = iw_get_mac_addr(skfd, ifname, &target->mac, &target->hw_type);
613 fprintf(stderr, "Error: Can't read MAC address on interface `%s' : %s\n",
614 ifname, strerror(errno));
618 /* Check the type of comparison */
619 if((flag == HAS_MAC_FILTER) || verbose)
621 /* Convert to ASCII */
622 iw_ether_ntop(&target->mac, target->mac_filter);
625 target->active[SELECT_MAC] = flag;
626 target->active[SELECT_ARP] = 1;
630 "Querying %s : Got MAC address `%s' and ARP/Link Type `%d'.\n",
631 ifname, target->mac_filter, target->hw_type);
636 /*------------------------------------------------------------------*/
638 * Add a ARP/Link type selector to a mapping
641 mapping_addarp(struct if_mapping * ifnode,
650 /* Verify validity of string, convert to int */
651 n = strspn(string, "0123456789");
652 if((n < len) || (sscanf(string, "%d", &type) != 1))
654 fprintf(stderr, "Error: Invalid ARP/Link Type `%s' at line %d\n",
659 ifnode->hw_type = (unsigned short) type;
660 ifnode->active[SELECT_ARP] = 1;
661 active[SELECT_ARP] = 1;
664 fprintf(stderr, "Parsing : Added ARP/Link Type `%d' from line %d.\n",
665 ifnode->hw_type, linenum);
670 /*------------------------------------------------------------------*/
672 * Compare the ARP/Link type of two mappings
675 mapping_cmparp(struct if_mapping * ifnode,
676 struct if_mapping * target)
678 return(!(ifnode->hw_type == target->hw_type));
681 /*------------------------------------------------------------------*/
683 * Extract the ARP/Link type of an interface
686 mapping_getarp(int skfd,
688 struct if_mapping * target,
691 /* We may have already extracted the MAC address */
692 if(target->active[SELECT_MAC])
695 /* Otherwise just do it */
696 return(mapping_getmac(skfd, ifname, target, flag));
699 /*------------------------------------------------------------------*/
701 * Add a Driver name selector to a mapping
704 mapping_adddriver(struct if_mapping * ifnode,
710 /* Plain string, minimal verification */
711 if(len >= sizeof(ifnode->driver))
713 fprintf(stderr, "Driver name too long at line %d\n", linenum);
718 memcpy(ifnode->driver, string, len + 1);
721 ifnode->active[SELECT_DRIVER] = 1;
722 active[SELECT_DRIVER] = 1;
726 "Parsing : Added Driver name `%s' from line %d.\n",
727 ifnode->driver, linenum);
732 /*------------------------------------------------------------------*/
734 * Compare the Driver name of two mappings
737 mapping_cmpdriver(struct if_mapping * ifnode,
738 struct if_mapping * target)
740 /* Do wildcard matching, case insensitive */
741 return(fnmatch(ifnode->driver, target->driver, FNM_CASEFOLD));
744 /*------------------------------------------------------------------*/
746 * Add a Bus-Info selector to a mapping
749 mapping_addbusinfo(struct if_mapping * ifnode,
759 /* Verify validity of string */
760 if(len >= sizeof(ifnode->bus_info))
762 fprintf(stderr, "Bus Info too long at line %d\n", linenum);
766 /* Hum... This doesn's seem true for non-PCI bus-info */
767 n = strspn(string, "0123456789ABCDEFabcdef:.*");
770 fprintf(stderr, "Error: Invalid Bus Info `%s' at line %d\n",
777 memcpy(ifnode->bus_info, string, len + 1);
780 ifnode->active[SELECT_BUSINFO] = 1;
781 active[SELECT_BUSINFO] = 1;
785 "Parsing : Added Bus Info `%s' from line %d.\n",
786 ifnode->bus_info, linenum);
791 /*------------------------------------------------------------------*/
793 * Compare the Bus-Info of two mappings
796 mapping_cmpbusinfo(struct if_mapping * ifnode,
797 struct if_mapping * target)
799 /* Do wildcard matching, case insensitive */
800 return(fnmatch(ifnode->bus_info, target->bus_info, FNM_CASEFOLD));
803 /*------------------------------------------------------------------*/
805 * Add a Firmare revision selector to a mapping
808 mapping_addfirmware(struct if_mapping * ifnode,
814 /* Verify validity of string */
815 if(len >= sizeof(ifnode->fw_version))
817 fprintf(stderr, "Firmware revision too long at line %d\n", linenum);
822 memcpy(ifnode->fw_version, string, len + 1);
825 ifnode->active[SELECT_FIRMWARE] = 1;
826 active[SELECT_FIRMWARE] = 1;
830 "Parsing : Added Firmware Revision `%s' from line %d.\n",
831 ifnode->fw_version, linenum);
836 /*------------------------------------------------------------------*/
838 * Compare the Bus-Info of two mappings
841 mapping_cmpfirmware(struct if_mapping * ifnode,
842 struct if_mapping * target)
844 /* Do wildcard matching, case insensitive */
845 return(fnmatch(ifnode->fw_version, target->fw_version, FNM_CASEFOLD));
848 /*------------------------------------------------------------------*/
850 * Extract the Driver name and Bus-Info from a live interface
853 mapping_getdriverbusinfo(int skfd,
855 struct if_mapping * target,
859 struct ethtool_drvinfo drvinfo;
862 /* Avoid "Unused parameter" warning */
865 /* We may come here twice or more, so do the job only once */
866 if(target->active[SELECT_DRIVER] || target->active[SELECT_BUSINFO]
867 || target->active[SELECT_FIRMWARE])
870 /* Prepare request */
871 bzero(&ifr, sizeof(struct ifreq));
872 bzero(&drvinfo, sizeof(struct ethtool_drvinfo));
873 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
874 drvinfo.cmd = ETHTOOL_GDRVINFO;
875 ifr.ifr_data = (caddr_t) &drvinfo;
878 ret = ioctl(skfd, SIOCETHTOOL, &ifr);
881 /* Most drivers don't support that, keep quiet for now */
884 "Error: Can't read driver/bus-info on interface `%s' : %s\n",
885 ifname, strerror(errno));
890 strcpy(target->driver, drvinfo.driver);
891 strcpy(target->bus_info, drvinfo.bus_info);
892 strcpy(target->fw_version, drvinfo.fw_version);
895 target->active[SELECT_DRIVER] = 1;
896 target->active[SELECT_BUSINFO] = 1;
897 target->active[SELECT_FIRMWARE] = 1;
901 "Querying %s : Got Driver name `%s', Bus Info `%s' and Firmware `%s'.\n",
902 ifname, target->driver, target->bus_info, target->fw_version);
907 /*------------------------------------------------------------------*/
909 * Add a Base Address selector to a mapping
912 mapping_addbaseaddr(struct if_mapping * ifnode,
919 unsigned int address;
921 /* Verify validity of string */
922 n = strspn(string, "0123456789ABCDEFabcdefx");
923 if((n < len) || (sscanf(string, "0x%X", &address) != 1))
925 fprintf(stderr, "Error: Invalid Base Address `%s' at line %d\n",
931 ifnode->base_addr = (unsigned short) address;
934 ifnode->active[SELECT_BASEADDR] = 1;
935 active[SELECT_BASEADDR] = 1;
939 "Parsing : Added Base Address `0x%X' from line %d.\n",
940 ifnode->base_addr, linenum);
945 /*------------------------------------------------------------------*/
947 * Compare the Base Address of two mappings
950 mapping_cmpbaseaddr(struct if_mapping * ifnode,
951 struct if_mapping * target)
953 /* Do wildcard matching, case insensitive */
954 return(!(ifnode->base_addr == target->base_addr));
957 /*------------------------------------------------------------------*/
959 * Add a IRQ selector to a mapping
962 mapping_addirq(struct if_mapping * ifnode,
971 /* Verify validity of string */
972 n = strspn(string, "0123456789");
973 if((n < len) || (sscanf(string, "%d", &irq) != 1))
975 fprintf(stderr, "Error: Invalid Base Address `%s' at line %d\n",
981 ifnode->irq = (unsigned char) irq;
984 ifnode->active[SELECT_IRQ] = 1;
985 active[SELECT_IRQ] = 1;
989 "Parsing : Added IRQ `%d' from line %d.\n",
990 ifnode->irq, linenum);
995 /*------------------------------------------------------------------*/
997 * Compare the IRQ of two mappings
1000 mapping_cmpirq(struct if_mapping * ifnode,
1001 struct if_mapping * target)
1003 /* Do wildcard matching, case insensitive */
1004 return(!(ifnode->irq == target->irq));
1007 /*------------------------------------------------------------------*/
1009 * Extract the Driver name and Bus-Info from a live interface
1012 mapping_getbaseaddrirq(int skfd,
1013 const char * ifname,
1014 struct if_mapping * target,
1018 struct ifmap map; /* hardware setup */
1021 /* Avoid "Unused parameter" warning */
1024 /* We may come here twice, so do the job only once */
1025 if(target->active[SELECT_BASEADDR] || target->active[SELECT_IRQ])
1028 /* Prepare request */
1029 bzero(&ifr, sizeof(struct ifreq));
1030 bzero(&map, sizeof(struct ifmap));
1031 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
1034 ret = ioctl(skfd, SIOCGIFMAP, &ifr);
1037 /* Don't know if every interface has that, so keep quiet... */
1040 "Error: Can't read base address/irq on interface `%s' : %s\n",
1041 ifname, strerror(errno));
1045 /* Copy over, activate */
1046 if(ifr.ifr_map.base_addr >= 0x100)
1048 target->base_addr = ifr.ifr_map.base_addr;
1049 target->active[SELECT_BASEADDR] = 1;
1051 target->irq = ifr.ifr_map.irq;
1052 target->active[SELECT_IRQ] = 1;
1056 "Querying %s : Got Base Address `0x%X' and IRQ `%d'.\n",
1057 ifname, target->base_addr, target->irq);
1062 /*------------------------------------------------------------------*/
1064 * Add a Wireless Protocol selector to a mapping
1067 mapping_addiwproto(struct if_mapping * ifnode,
1073 /* Verify validity of string */
1074 if(len >= sizeof(ifnode->iwproto))
1076 fprintf(stderr, "Wireless Protocol too long at line %d\n", linenum);
1081 memcpy(ifnode->iwproto, string, len + 1);
1084 ifnode->active[SELECT_IWPROTO] = 1;
1085 active[SELECT_IWPROTO] = 1;
1089 "Parsing : Added Wireless Protocol `%s' from line %d.\n",
1090 ifnode->iwproto, linenum);
1095 /*------------------------------------------------------------------*/
1097 * Compare the Wireless Protocol of two mappings
1100 mapping_cmpiwproto(struct if_mapping * ifnode,
1101 struct if_mapping * target)
1103 /* Do wildcard matching, case insensitive */
1104 return(fnmatch(ifnode->iwproto, target->iwproto, FNM_CASEFOLD));
1107 /*------------------------------------------------------------------*/
1109 * Extract the Wireless Protocol from a live interface
1112 mapping_getiwproto(int skfd,
1113 const char * ifname,
1114 struct if_mapping * target,
1119 /* Avoid "Unused parameter" warning */
1122 /* Get wireless name */
1123 if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
1124 /* Don't complain about it, Ethernet cards will never support this */
1127 strncpy(target->iwproto, wrq.u.name, IFNAMSIZ);
1128 target->iwproto[IFNAMSIZ] = '\0';
1131 target->active[SELECT_IWPROTO] = 1;
1135 "Querying %s : Got Wireless Protocol `%s'.\n",
1136 ifname, target->iwproto);
1141 /*------------------------------------------------------------------*/
1143 * Add a Pcmcia Slot selector to a mapping
1146 mapping_addpcmciaslot(struct if_mapping * ifnode,
1154 /* Verify validity of string, convert to int */
1155 n = strspn(string, "0123456789");
1156 if((n < len) || (sscanf(string, "%d", &ifnode->pcmcia_slot) != 1))
1158 fprintf(stderr, "Error: Invalid Pcmcia Slot `%s' at line %d\n",
1163 ifnode->active[SELECT_PCMCIASLOT] = 1;
1164 active[SELECT_PCMCIASLOT] = 1;
1167 fprintf(stderr, "Parsing : Added Pcmcia Slot `%d' from line %d.\n",
1168 ifnode->pcmcia_slot, linenum);
1173 /*------------------------------------------------------------------*/
1175 * Compare the Pcmcia Slot of two mappings
1178 mapping_cmppcmciaslot(struct if_mapping * ifnode,
1179 struct if_mapping * target)
1181 return(!(ifnode->pcmcia_slot == target->pcmcia_slot));
1184 /*------------------------------------------------------------------*/
1186 * Extract the Pcmcia Slot of an interface
1187 * Note that this works only for cards fully managed by cardmgr.
1188 * With the kernel pcmcia modules, 32 bits cards (CardBus) are not managed
1189 * by cardmgr, and therefore won't have a valid slot number. For those
1190 * cards, you should use Bus Info (when the driver exports it).
1191 * In the long term, 16 bits card as well will no longer be managed by
1192 * cardmgr. Currently, Bus Info for 16 bit cards don't have any information
1193 * enabling to locate their physical location on the system, but I hope that
1195 * When that happen, we can drop this code...
1198 mapping_getpcmciaslot(int skfd,
1199 const char * ifname,
1200 struct if_mapping * target,
1204 char * linebuf = NULL;
1208 /* Avoid "Unused parameter" warning */
1212 /* Open the stab file for reading */
1213 stream = fopen(PCMCIA_STAB1, "r");
1216 /* Try again, alternate location */
1217 stream = fopen(PCMCIA_STAB2, "r");
1220 fprintf(stderr, "Error: Can't open PCMCIA Stab file `%s' or `%s': %s\n",
1221 PCMCIA_STAB1, PCMCIA_STAB2, strerror(errno));
1226 /* Read each line of file
1227 * getline is a GNU extension :-( The buffer is recycled and increased
1228 * as needed by getline. */
1229 while(getline(&linebuf, &linelen, stream) > 0)
1237 /* Keep track of line number */
1240 /* Get Pcmcia socket number */
1245 continue; /* Line ended */
1246 n = strcspn(p, " \t\n");
1247 k = strspn(p, "0123456789");
1248 if((k < n) || (sscanf(p, "%d", &pcmcia_slot) != 1))
1252 /* Skip socket number */
1253 /* Skip socket number ; device class ; driver name ; instance */
1254 for(i = 0; i < 4; i++)
1259 p += strspn(p, " \t\n");
1261 break; /* Line ended */
1262 /* Next item size */
1263 n = strcspn(p, " \t\n");
1266 continue; /* Line ended */
1268 /* Terminate dev name */
1271 /* Compare to interface name */
1272 if(!strcmp(p, ifname))
1275 target->pcmcia_slot = pcmcia_slot;
1278 target->active[SELECT_PCMCIASLOT] = 1;
1282 "Querying %s : Got Pcmcia Slot `%d'.\n",
1283 ifname, target->pcmcia_slot);
1284 /* Exit loop, found it */
1288 /* Finished -> next line */
1294 return(target->active[SELECT_PCMCIASLOT] ? 0 : -1);
1298 /*********************** MAPPING MANAGEMENTS ***********************/
1300 * Manage interface mappings.
1301 * Each mapping tell us how to identify a specific interface name.
1302 * It is composed of a bunch of selector values.
1305 /*------------------------------------------------------------------*/
1307 * Create a new interface mapping and verify its name
1309 static struct if_mapping *
1310 mapping_create(char * pos,
1314 struct if_mapping * ifnode;
1317 /* Check overflow. */
1320 fprintf(stderr, "Error: Interface name `%.*s' too long at line %d\n",
1321 (int) len, pos, linenum);
1325 /* Create mapping, zero it */
1326 ifnode = calloc(1, sizeof(if_mapping));
1329 fprintf(stderr, "Error: Can't allocate interface mapping.\n");
1333 /* Set the name, terminates it */
1334 memcpy(ifnode->ifname, pos, len);
1335 ifnode->ifname[len] = '\0';
1337 /* Check the interface name and issue various pedantic warnings */
1338 if((!strcmp(ifnode->ifname, "eth0")) || (!strcmp(ifnode->ifname, "wlan0")))
1340 "Warning: Interface name is `%s' at line %d, can't be mapped reliably.\n",
1341 ifnode->ifname, linenum);
1342 if(strchr(ifnode->ifname, ':'))
1343 fprintf(stderr, "Warning: Alias device `%s' at line %d probably can't be mapped.\n",
1344 ifnode->ifname, linenum);
1346 /* Check for wildcard interface name, such as 'eth*' or 'wlan*'...
1347 * This require specific kernel support (2.6.2-rc1 and later).
1348 * We externally use '*', but the kernel doesn't know about that,
1349 * so convert it to something it knows about... */
1350 star = strchr(ifnode->ifname, '*');
1353 /* We need an extra char */
1357 "Error: Interface wildcard `%s' too long at line %d\n",
1358 ifnode->ifname, linenum);
1363 /* Replace '*' with '%d' */
1364 memmove(star + 2, star + 1, len + 1 - (star - ifnode->ifname));
1370 fprintf(stderr, "Parsing : Added Mapping `%s' from line %d.\n",
1371 ifnode->ifname, linenum);
1377 /*------------------------------------------------------------------*/
1379 * Find the most appropriate selector matching a given selector name
1381 static inline const struct mapping_selector *
1382 selector_find(const char * string,
1386 const struct mapping_selector * found = NULL;
1390 /* Go through all selectors */
1391 for(i = 0; selector_list[i].name != NULL; ++i)
1393 /* No match -> next one */
1394 if(strncasecmp(selector_list[i].name, string, slen) != 0)
1397 /* Exact match -> perfect */
1398 if(slen == strlen(selector_list[i].name))
1399 return &selector_list[i];
1404 found = &selector_list[i];
1407 if (selector_list[i].add_fn != found->add_fn)
1413 fprintf(stderr, "Error: Unknown selector `%.*s' at line %d.\n",
1414 (int) slen, string, linenum);
1420 fprintf(stderr, "Selector `%.*s'at line %d is ambiguous.\n",
1421 (int) slen, string, linenum);
1428 /*------------------------------------------------------------------*/
1430 * Read the configuration file and extract all valid mappings and their
1434 mapping_readfile(const char * filename)
1437 char * linebuf = NULL;
1441 /* Reset the list of filters */
1442 bzero(selector_active, sizeof(selector_active));
1444 /* Check filename */
1445 if(!strcmp(filename, "-"))
1447 /* Read from stdin */
1453 /* Open the file for reading */
1454 stream = fopen(filename, "r");
1457 fprintf(stderr, "Error: Can't open configuration file `%s': %s\n",
1458 filename, strerror(errno));
1463 /* Read each line of file
1464 * getline is a GNU extension :-( The buffer is recycled and increased
1465 * as needed by getline. */
1466 while(getline(&linebuf, &linelen, stream) > 0)
1468 struct if_mapping * ifnode;
1472 int ret = -13; /* Complain if no selectors */
1474 /* Keep track of line number */
1477 /* Every comments terminates parsing */
1478 if((p = strchr(linebuf,'#')) != NULL)
1481 /* Get interface name */
1486 continue; /* Line ended */
1487 n = strcspn(p, " \t\n");
1489 /* Create mapping */
1490 ifnode = mapping_create(p, n, linenum);
1492 continue; /* Ignore this line */
1494 p += strspn(p, " \t\n");
1496 /* Loop on all selectors */
1499 const struct mapping_selector * selector = NULL;
1501 /* Selector name length */
1502 n = strcspn(p, " \t\n");
1505 selector = selector_find(p, n, linenum);
1512 /* Get to selector value */
1514 p += strspn(p, " \t\n");
1517 fprintf(stderr, "Error: no value for selector `%s' on line %d\n",
1518 selector->name, linenum);
1520 break; /* Line ended */
1522 /* Check for quoted arguments */
1530 "Error: unterminated quoted value on line %d\n",
1533 break; /* Line ended */
1540 /* Just end at next blank */
1541 n = strcspn(p, " \t\n");
1544 /* Make 'e' point past the '\0' we are going to add */
1547 /* Terminate selector value */
1550 /* Add it to the mapping */
1551 ret = selector->add_fn(ifnode, selector_active, p, n, linenum);
1555 /* Go to next selector */
1557 p += strspn(p, " \t\n");
1560 /* We add a mapping only if it has at least one selector and if all
1561 * selectors were parsed properly. */
1564 /* If we have not yet printed an error, now is a good time ;-) */
1566 fprintf(stderr, "Error: Line %d ignored, no valid selectors\n",
1569 fprintf(stderr, "Error: Line %d ignored due to prior errors\n",
1576 /* Link it in the list */
1577 ifnode->next = mapping_list;
1578 mapping_list = ifnode;
1585 /* Finished reading, close the file */
1591 /*------------------------------------------------------------------*/
1593 * Extract all the interesting selectors for the interface in consideration
1595 static struct if_mapping *
1596 mapping_extract(int skfd,
1597 const char * ifname)
1599 struct if_mapping * target;
1602 /* Create mapping, zero it */
1603 target = calloc(1, sizeof(if_mapping));
1606 fprintf(stderr, "Error: Can't allocate interface mapping.\n");
1610 /* Set the interface name */
1611 strcpy(target->ifname, ifname);
1613 /* Loop on all active selectors */
1614 for(i = 0; i < SELECT_NUM; i++)
1616 /* Check if this selector is active */
1617 if(selector_active[i] != 0)
1619 /* Extract selector */
1620 selector_list[i].get_fn(skfd, ifname, target, selector_active[i]);
1622 /* Ignore errors. Some mapping may not need all selectors */
1629 /*------------------------------------------------------------------*/
1631 * Find the first mapping in the list matching the one we want.
1633 static struct if_mapping *
1634 mapping_find(struct if_mapping * target)
1636 struct if_mapping * ifnode;
1639 /* Look over all our mappings */
1640 for(ifnode = mapping_list; ifnode != NULL; ifnode = ifnode->next)
1644 /* Look over all our selectors, all must match */
1645 for(i = 0; i < SELECT_NUM; i++)
1647 /* Check if this selector is active */
1648 if(ifnode->active[i] != 0)
1650 /* If this selector doesn't match, game over for this mapping */
1651 if((target->active[i] == 0) ||
1652 (selector_list[i].cmp_fn(ifnode, target) != 0))
1660 /* Check is this mapping was "the one" */
1669 /************************** MODULE SUPPORT **************************/
1671 * Load all necessary module so that interfaces do exist.
1672 * This is necessary for system that are fully modular when
1673 * doing the boot time processing, because we need to run before
1677 /*------------------------------------------------------------------*/
1679 * Probe interfaces based on our list of mappings.
1680 * This is the default, but usually not the best way to do it.
1683 probe_mappings(int skfd)
1685 struct if_mapping * ifnode;
1686 struct ether_addr mac; /* Exact MAC address, hex */
1687 unsigned short hw_type;
1689 /* Look over all our mappings */
1690 for(ifnode = mapping_list; ifnode != NULL; ifnode = ifnode->next)
1692 /* Can't load wildcards interface name :-( */
1693 if(strchr(ifnode->ifname, '%') != NULL)
1697 fprintf(stderr, "Probing : Trying to load interface [%s]\n",
1700 /* Trick the kernel into loading the interface.
1701 * This allow us to not depend on the exact path and
1702 * name of the '/sbin/modprobe' command.
1703 * Obviously, we expect this command to 'fail', as
1704 * the interface will load with the old/wrong name.
1706 iw_get_mac_addr(skfd, ifnode->ifname, &mac, &hw_type);
1710 /*------------------------------------------------------------------*/
1712 * Probe interfaces based on Debian's config files.
1713 * This allow to enly load modules for interfaces the user want active,
1714 * all built-in interfaces that should remain unconfigured won't
1715 * be probed (and can have mappings).
1718 probe_debian(int skfd)
1721 char * linebuf = NULL;
1723 struct ether_addr mac; /* Exact MAC address, hex */
1724 unsigned short hw_type;
1726 /* Open Debian config file */
1727 stream = fopen(DEBIAN_CONFIG_FILE, "r");
1730 fprintf(stderr, "Error: can't open file [%s]\n", DEBIAN_CONFIG_FILE);
1734 /* Read each line of file
1735 * getline is a GNU extension :-( The buffer is recycled and increased
1736 * as needed by getline. */
1737 while(getline(&linebuf, &linelen, stream) > 0)
1743 /* Check for auto keyword, ignore when commented out */
1744 if(!strncasecmp(linebuf, "auto ", 5))
1746 /* Skip "auto" keyword */
1749 /* Terminate at first comment */
1754 /* Loop on all interfaces given */
1757 /* Interface name length */
1758 n = strcspn(p, " \t\n");
1760 /* Look for end of interface name */
1762 /* Make 'e' point past the '\0' we are going to add */
1765 /* Terminate interface name */
1769 fprintf(stderr, "Probing : Trying to load interface [%s]\n",
1773 iw_get_mac_addr(skfd, p, &mac, &hw_type);
1775 /* Go to next interface name */
1777 p += strspn(p, " \t\n");
1787 /**************************** MAIN LOGIC ****************************/
1789 /*------------------------------------------------------------------*/
1791 * Rename an interface to a specified new name.
1794 process_rename(int skfd,
1798 char newname[IFNAMSIZ+1];
1799 char retname[IFNAMSIZ+1];
1803 len = strlen(pattern);
1804 star = strchr(pattern, '*');
1806 /* Check newname length, need one extra char for wildcard */
1807 if((len + (star != NULL)) > IFNAMSIZ)
1809 fprintf(stderr, "Error: Interface name `%s' too long.\n",
1814 /* Copy to local buffer */
1815 memcpy(newname, pattern, len + 1);
1817 /* Convert wildcard to the proper format */
1820 /* Replace '*' with '%d' in the new buffer */
1821 star += newname - pattern;
1822 memmove(star + 2, star + 1, len + 1 - (star - newname));
1828 /* Change the name of the interface */
1829 if(if_set_name(skfd, ifname, newname, retname) < 0)
1831 fprintf(stderr, "Error: cannot change name of %s to %s: %s\n",
1832 ifname, newname, strerror(errno));
1836 /* Always print out the *new* interface name so that
1837 * the calling script can pick it up and know where its interface
1839 printf("%s\n", retname);
1845 /*------------------------------------------------------------------*/
1847 * Process a specified interface.
1850 process_ifname(int skfd,
1855 struct if_mapping * target;
1856 const struct if_mapping * mapping;
1857 char retname[IFNAMSIZ+1];
1859 /* Avoid "Unused parameter" warning */
1860 args = args; count = count;
1862 /* Get description of this interface */
1863 target = mapping_extract(skfd, ifname);
1867 /* Find matching mapping */
1868 mapping = mapping_find(target);
1872 /* Check if user want only dry-run.
1873 * Note that, in the case of wildcard, we don't resolve the wildcard.
1874 * That would be tricky to do... */
1877 printf("Dry-run : Would rename %s to %s.\n",
1878 target->ifname, mapping->ifname);
1882 /* Change the name of the interface */
1883 if(if_set_name(skfd, target->ifname, mapping->ifname, retname) < 0)
1885 fprintf(stderr, "Error: cannot change name of %s to %s: %s\n",
1886 target->ifname, mapping->ifname, strerror(errno));
1890 /* Check if called with an explicit interface name */
1893 /* Always print out the *new* interface name so that
1894 * the calling script can pick it up and know where its interface
1896 printf("%s\n", retname);
1903 /*------------------------------------------------------------------*/
1905 * Process all network interface present on the system.
1908 process_iflist(int skfd,
1915 iw_enum_devices(skfd, &process_ifname, args, count);
1917 /* If we do any takeover, the interface list grabbed with
1918 * iw_enum_devices() may get out of sync with the real interfaces,
1919 * and we may miss the victim interface. So, let's go through the
1921 * On the other hand, we may have ping pong between two interfaces,
1922 * each claiming the same name, so let's not do it forever...
1923 * Two time should be enough for most configs...
1925 if(force_takeover && num_takeover)
1926 /* Play it again, Sam... */
1927 iw_enum_devices(skfd, &process_ifname, args, count);
1933 /******************************* MAIN *******************************/
1936 /*------------------------------------------------------------------*/
1942 fprintf(stderr, "usage: ifrename [-c configurationfile] [-i ifname] [-p] [-t] [-d] [-D]\n");
1946 /*------------------------------------------------------------------*/
1954 const char * conf_file = DEFAULT_CONF;
1955 char * ifname = NULL;
1956 char * newname = NULL;
1962 /* Loop over all command line options */
1965 int c = getopt_long(argc, argv, "c:dDi:n:ptvV", long_opt, NULL);
1996 printf("%-8.16s Wireless-Tools version %d\n", "ifrename", WT_VERSION);
2004 /* Read the specified/default config file, or stdin. */
2005 if(mapping_readfile(conf_file) < 0)
2008 /* Create a channel to the NET kernel. */
2009 if((skfd = iw_sockets_open()) < 0)
2015 /* Check if interface name was specified with -i. */
2018 /* Check is target name specified */
2021 /* User want to simply rename an interface to a specified name */
2022 ret = process_rename(skfd, ifname, newname);
2026 /* Rename only this interface based on mappings
2027 * Mostly used for HotPlug processing (from /etc/hotplug/net.agent).
2028 * Process the network interface specified on the command line,
2029 * and return the new name on stdout.
2031 ret = process_ifname(skfd, ifname, NULL, 0);
2036 /* Load all the necesary modules */
2042 probe_mappings(skfd);
2045 /* Rename all system interfaces
2046 * Mostly used for boot time processing (from init scripts).
2048 ret = process_iflist(skfd, &newname, 1);
2052 iw_sockets_close(skfd);