OSDN Git Service

v27
[android-x86/external-wireless-tools.git] / wireless_tools / ifrename.c
1 /*
2  *      Wireless Tools
3  *
4  *              Jean II - HPL 04
5  *
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".
9  *
10  * This file is released under the GPL license.
11  *     Copyright (c) 2004 Jean Tourrilhes <jt@hpl.hp.com>
12  */
13
14 /* 
15  * The changelog for ifrename is in the file CHANGELOG.h ;-)
16  *
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  * -------------------------------------------------------
30  *
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*').
40  */
41
42 /***************************** INCLUDES *****************************/
43
44 /* This is needed to enable GNU extensions such as getline & FNM_CASEFOLD */
45 #ifndef _GNU_SOURCE 
46 #define _GNU_SOURCE
47 #endif
48
49 #include <getopt.h>             /* getopt_long() */
50 #include <linux/sockios.h>      /* SIOCSIFNAME */
51 #include <fnmatch.h>            /* fnmatch() */
52 //#include <sys/syslog.h>
53
54 #include "iwlib.h"              /* Wireless Tools library */
55
56 // This would be cool, unfortunately...
57 //#include <linux/ethtool.h>    /* Ethtool stuff -> struct ethtool_drvinfo */
58
59 /************************ CONSTANTS & MACROS ************************/
60
61 /* Our default configuration file */
62 const char DEFAULT_CONF[] =             "/etc/iftab"; 
63
64 /* Debian stuff */
65 const char DEBIAN_CONFIG_FILE[] =       "/etc/network/interfaces";
66
67 /* Backward compatibility */
68 #ifndef ifr_newname
69 #define ifr_newname ifr_ifru.ifru_slave
70 #endif
71
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 */
85 #define SELECT_NUM              12
86
87 #define HAS_MAC_EXACT   1
88 #define HAS_MAC_FILTER  2
89
90 const struct ether_addr zero_mac = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
91
92 const struct option long_opt[] =
93
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' },
104 };
105
106 /* Pcmcia stab files */
107 #define PCMCIA_STAB1    "/var/lib/pcmcia/stab"
108 #define PCMCIA_STAB2    "/var/run/stab"
109
110 /****************************** TYPES ******************************/
111
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 {
116         __u32   cmd;
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. */
122         char    reserved1[32];
123         char    reserved2[16];
124         __u32   n_stats;        /* number of u64's from ETHTOOL_GSTATS */
125         __u32   testinfo_len;
126         __u32   eedump_len;     /* Size of data from ETHTOOL_GEEPROM (bytes) */
127         __u32   regdump_len;    /* Size of data from ETHTOOL_GREGS (bytes) */
128 };
129 #define ETHTOOL_GDRVINFO        0x00000003 /* Get driver info. */
130
131 /* Description of an interface mapping */
132 typedef struct if_mapping
133
134   /* Linked list */
135   struct if_mapping *   next;
136
137   /* Name of this interface */
138   char                  ifname[IFNAMSIZ+1];
139
140   /* Selectors for this interface */
141   int                   active[SELECT_NUM];     /* Selectors active */
142
143   /* Selector data */
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 */
154 } if_mapping; 
155
156 /* Prototype for adding a selector to a mapping. Return -1 if invalid value. */
157 typedef int (*mapping_add)(struct if_mapping *  ifnode,
158                            int *                active,
159                            char *               pos,
160                            size_t               len,
161                            int                  linenum);
162
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,
168                            const char *         ifname,
169                            struct if_mapping *  target,
170                            int                  flag);
171
172 /* How to handle a selector */
173 typedef struct mapping_selector
174 {
175   char *        name;
176   mapping_add   add_fn;
177   mapping_cmp   cmp_fn;
178   mapping_get   get_fn;
179 } mapping_selector;
180
181 /**************************** PROTOTYPES ****************************/
182
183 static int
184         mapping_addmac(struct if_mapping *      ifnode,
185                        int *                    active,
186                        char *                   pos,
187                        size_t                   len,
188                        int                      linenum);
189 static int
190         mapping_cmpmac(struct if_mapping *      ifnode,
191                        struct if_mapping *      target);
192 static int
193         mapping_getmac(int                      skfd,
194                        const char *             ifname,
195                        struct if_mapping *      target,
196                        int                      flag);
197 static int
198         mapping_addarp(struct if_mapping *      ifnode,
199                        int *                    active,
200                        char *                   pos,
201                        size_t                   len,
202                        int                      linenum);
203 static int
204         mapping_cmparp(struct if_mapping *      ifnode,
205                        struct if_mapping *      target);
206 static int
207         mapping_getarp(int                      skfd,
208                        const char *             ifname,
209                        struct if_mapping *      target,
210                        int                      flag);
211 static int
212         mapping_adddriver(struct if_mapping *   ifnode,
213                           int *                 active,
214                           char *                pos,
215                           size_t                len,
216                           int                   linenum);
217 static int
218         mapping_cmpdriver(struct if_mapping *   ifnode,
219                           struct if_mapping *   target);
220 static int
221         mapping_addbusinfo(struct if_mapping *  ifnode,
222                            int *                active,
223                            char *               pos,
224                            size_t               len,
225                            int                  linenum);
226 static int
227         mapping_cmpbusinfo(struct if_mapping *  ifnode,
228                            struct if_mapping *  target);
229 static int
230         mapping_addfirmware(struct if_mapping * ifnode,
231                             int *               active,
232                             char *              pos,
233                             size_t              len,
234                             int                 linenum);
235 static int
236         mapping_cmpfirmware(struct if_mapping * ifnode,
237                             struct if_mapping * target);
238 static int
239         mapping_getdriverbusinfo(int                    skfd,
240                                  const char *           ifname,
241                                  struct if_mapping *    target,
242                                  int                    flag);
243 static int
244         mapping_addbaseaddr(struct if_mapping * ifnode,
245                             int *               active,
246                             char *              pos,
247                             size_t              len,
248                             int                 linenum);
249 static int
250         mapping_cmpbaseaddr(struct if_mapping * ifnode,
251                             struct if_mapping * target);
252 static int
253         mapping_addirq(struct if_mapping *      ifnode,
254                        int *                    active,
255                        char *                   pos,
256                        size_t                   len,
257                        int                      linenum);
258 static int
259         mapping_cmpirq(struct if_mapping *      ifnode,
260                        struct if_mapping *      target);
261 static int
262         mapping_getbaseaddrirq(int                      skfd,
263                                const char *             ifname,
264                                struct if_mapping *      target,
265                                int                      flag);
266 static int
267         mapping_addiwproto(struct if_mapping *  ifnode,
268                            int *                active,
269                            char *               pos,
270                            size_t               len,
271                            int                  linenum);
272 static int
273         mapping_cmpiwproto(struct if_mapping *  ifnode,
274                            struct if_mapping *  target);
275 static int
276         mapping_getiwproto(int                  skfd,
277                            const char *         ifname,
278                            struct if_mapping *  target,
279                            int                  flag);
280 static int
281         mapping_addpcmciaslot(struct if_mapping *       ifnode,
282                               int *                     active,
283                               char *                    pos,
284                               size_t                    len,
285                               int                       linenum);
286 static int
287         mapping_cmppcmciaslot(struct if_mapping *       ifnode,
288                            struct if_mapping *          target);
289 static int
290         mapping_getpcmciaslot(int                       skfd,
291                               const char *              ifname,
292                               struct if_mapping *       target,
293                               int                       flag);
294
295 /**************************** VARIABLES ****************************/
296
297 /* List of mapping read for config file */
298 struct if_mapping *     mapping_list = NULL;
299
300 /* List of selectors we can handle */
301 const struct mapping_selector   selector_list[] =
302 {
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 },
324   /* The Terminator */
325   { NULL, NULL, NULL, NULL },
326 };
327 const int selector_num = sizeof(selector_list)/sizeof(selector_list[0]);
328
329 /* List of active selectors */
330 int     selector_active[SELECT_NUM];    /* Selectors active */
331
332 /* Takeover support */
333 int     force_takeover = 0;     /* Takeover name from other interface */
334 int     num_takeover = 0;       /* Number of takeover done */
335
336 /* Dry-run support */
337 int     dry_run = 0;            /* Just print new name, don't rename */
338
339 /* Verbose support (i.e. debugging) */
340 int     verbose = 0;
341
342 /******************** INTERFACE NAME MANAGEMENT ********************/
343 /*
344  * Bunch of low level function for managing interface names.
345  */
346
347 /*------------------------------------------------------------------*/
348 /*
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.
355  */
356 static int
357 if_match_ifname(const char *    pattern,
358                 const char *    value)
359 {
360   const char *  p;
361   const char *  v;
362   int           n;
363   int           ret;
364
365   /* Check for a wildcard (converted from '*' to '%d' in mapping_create()) */
366   p = strstr(pattern, "%d");
367
368   /* No wildcard, simple comparison */
369   if(p == NULL)
370     return(strcmp(pattern, value));
371
372   /* Check is prefixes match */
373   n = (p - pattern);
374   ret = strncmp(pattern, value, n);
375   if(ret)
376     return(ret);
377
378   /* Check that value has some digits at this point */
379   v = value + n;
380   if(!isdigit(*v))
381     return(-1);
382
383   /* Skip digits to go to value suffix */
384   do
385     v++;
386   while(isdigit(*v));
387
388   /* Pattern suffix */
389   p += 2;
390
391   /* Compare suffixes */
392   return(strcmp(p, v));
393 }
394
395 /*------------------------------------------------------------------*/
396 /*
397  * Steal interface name from another interface. This enable interface
398  * name swapping.
399  * This will work :
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...
404  */
405 static int
406 if_takeover_name(int                    skfd,
407                  const char *           victimname)
408 {
409   char          autoname[IFNAMSIZ+1];
410   int           len;
411   struct ifreq  ifr;
412   int           ret;
413
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");
423
424   if(verbose)
425     fprintf(stderr, "Takeover : moving interface `%s' to `%s'.\n",
426             victimname, autoname);
427
428   /* Prepare request */
429   bzero(&ifr, sizeof(struct ifreq));
430   strncpy(ifr.ifr_name, victimname, IFNAMSIZ); 
431   strncpy(ifr.ifr_newname, autoname, IFNAMSIZ); 
432
433   /* Rename victim interface */
434   ret = ioctl(skfd, SIOCSIFNAME, &ifr);
435
436   if(!ret)
437     num_takeover++;
438
439   return(ret);
440 }
441
442 /*------------------------------------------------------------------*/
443 /*
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
446  * appropriately.
447  */
448 static int
449 if_set_name(int                 skfd,
450             const char *        oldname,
451             const char *        newname,
452             char *              retname)
453 {
454   struct ifreq  ifr;
455   int           ret;
456
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
462    * success. */
463   if(!if_match_ifname(newname, oldname))
464     {
465       if(verbose)
466         fprintf(stderr, "Setting : Interface `%s' already matches `%s'.\n",
467                 oldname, newname);
468
469       strcpy(retname, oldname);
470       return(0);
471     }
472
473   /* Prepare request */
474   bzero(&ifr, sizeof(struct ifreq));
475   strncpy(ifr.ifr_name, oldname, IFNAMSIZ); 
476   strncpy(ifr.ifr_newname, newname, IFNAMSIZ); 
477
478   /* Do it */
479   ret = ioctl(skfd, SIOCSIFNAME, &ifr);
480
481   /* Takeover support : grab interface name from another interface */
482   if(ret && (errno == EEXIST) && force_takeover)
483     {
484       /* Push things around */
485       ret = if_takeover_name(skfd, newname);
486       if(!ret)
487         /* Second try */
488         ret = ioctl(skfd, SIOCSIFNAME, &ifr);
489     }
490
491   if(!ret)
492     {
493       /* Get the real new name (in case newname is a wildcard) */
494       strcpy(retname, ifr.ifr_newname);
495
496       if(verbose)
497         fprintf(stderr, "Setting : Interface `%s' renamed to `%s'.\n",
498                 oldname, retname);
499     }
500
501   return(ret);
502 }
503
504 /************************ SELECTOR HANDLING ************************/
505 /*
506  * Handle the various selector we support
507  */
508
509 /*------------------------------------------------------------------*/
510 /*
511  * Add a MAC address selector to a mapping
512  */
513 static int
514 mapping_addmac(struct if_mapping *      ifnode,
515                int *                    active,
516                char *                   string,
517                size_t                   len,
518                int                      linenum)
519 {
520   size_t        n;
521
522   /* Verify validity of string */
523   if(len >= sizeof(ifnode->mac_filter))
524     { 
525       fprintf(stderr, "MAC address too long at line %d\n", linenum);  
526       return(-1);
527     }
528   n = strspn(string, "0123456789ABCDEFabcdef:*"); 
529   if(n < len)
530     {
531       fprintf(stderr, "Error: Invalid MAC address `%s' at line %d\n",
532               string, linenum);
533       return(-1);
534     }
535
536   /* Copy as filter in all cases */
537   memcpy(ifnode->mac_filter, string, len + 1); 
538
539   /* Check the type of MAC address */
540   if (strchr(ifnode->mac_filter, '*') != NULL)
541     {
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;
546     }
547   else
548     {
549       /* Not a wildcard : "01:23:45:67:89:AB" */
550       if(iw_ether_aton(ifnode->mac_filter, &ifnode->mac) != 1)
551         {
552           fprintf(stderr, "Error: Invalid MAC address `%s' at line %d\n",
553                   ifnode->mac_filter, linenum);
554           return(-1);
555         }
556
557       /* Check that it's not NULL */
558       if(!memcmp(&ifnode->mac, &zero_mac, 6))
559         {
560           fprintf(stderr,
561                   "Warning: MAC address is null at line %d, this is dangerous...\n",
562                   linenum);
563         }
564
565       ifnode->active[SELECT_MAC] = HAS_MAC_EXACT;
566       if(active[SELECT_MAC] == 0)
567         active[SELECT_MAC] = HAS_MAC_EXACT;
568     }
569
570   if(verbose)
571     fprintf(stderr,
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);
575
576   return(0);
577 }
578
579 /*------------------------------------------------------------------*/
580 /*
581  * Compare the mac address of two mappings
582  */
583 static int
584 mapping_cmpmac(struct if_mapping *      ifnode,
585                struct if_mapping *      target)
586 {
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));
591   else
592     /* Exact matching, in hex */
593     return(memcmp(&ifnode->mac.ether_addr_octet, &target->mac.ether_addr_octet,
594                   6));
595 }
596
597 /*------------------------------------------------------------------*/
598 /*
599  * Extract the MAC address and Link Type of an interface
600  */
601 static int
602 mapping_getmac(int                      skfd,
603                const char *             ifname,
604                struct if_mapping *      target,
605                int                      flag)
606 {
607   int   ret;
608
609   /* Extract MAC address */
610   ret = iw_get_mac_addr(skfd, ifname, &target->mac, &target->hw_type);
611   if(ret < 0)
612     {
613       fprintf(stderr, "Error: Can't read MAC address on interface `%s' : %s\n",
614               ifname, strerror(errno));
615       return(-1);
616     }
617
618   /* Check the type of comparison */
619   if((flag == HAS_MAC_FILTER) || verbose)
620     {
621       /* Convert to ASCII */
622       iw_ether_ntop(&target->mac, target->mac_filter);
623     }
624
625   target->active[SELECT_MAC] = flag;
626   target->active[SELECT_ARP] = 1;
627
628   if(verbose)
629     fprintf(stderr,
630             "Querying %s : Got MAC address `%s' and ARP/Link Type `%d'.\n",
631             ifname, target->mac_filter, target->hw_type);
632
633   return(0);
634 }
635
636 /*------------------------------------------------------------------*/
637 /*
638  * Add a ARP/Link type selector to a mapping
639  */
640 static int
641 mapping_addarp(struct if_mapping *      ifnode,
642                int *                    active,
643                char *                   string,
644                size_t                   len,
645                int                      linenum)
646 {
647   size_t        n;
648   unsigned int  type;
649
650   /* Verify validity of string, convert to int */
651   n = strspn(string, "0123456789"); 
652   if((n < len) || (sscanf(string, "%d", &type) != 1))
653     {
654       fprintf(stderr, "Error: Invalid ARP/Link Type `%s' at line %d\n",
655               string, linenum);
656       return(-1);
657     }
658
659   ifnode->hw_type = (unsigned short) type;
660   ifnode->active[SELECT_ARP] = 1;
661   active[SELECT_ARP] = 1;
662
663   if(verbose)
664     fprintf(stderr, "Parsing : Added ARP/Link Type `%d' from line %d.\n",
665             ifnode->hw_type, linenum);
666
667   return(0);
668 }
669
670 /*------------------------------------------------------------------*/
671 /*
672  * Compare the ARP/Link type of two mappings
673  */
674 static int
675 mapping_cmparp(struct if_mapping *      ifnode,
676                struct if_mapping *      target)
677 {
678   return(!(ifnode->hw_type == target->hw_type));
679 }
680
681 /*------------------------------------------------------------------*/
682 /*
683  * Extract the ARP/Link type of an interface
684  */
685 static int
686 mapping_getarp(int                      skfd,
687                const char *             ifname,
688                struct if_mapping *      target,
689                int                      flag)
690 {
691   /* We may have already extracted the MAC address */
692   if(target->active[SELECT_MAC])
693     return(0);
694
695   /* Otherwise just do it */
696   return(mapping_getmac(skfd, ifname, target, flag));
697 }
698
699 /*------------------------------------------------------------------*/
700 /*
701  * Add a Driver name selector to a mapping
702  */
703 static int
704 mapping_adddriver(struct if_mapping *   ifnode,
705                   int *                 active,
706                   char *                string,
707                   size_t                len,
708                   int                   linenum)
709 {
710   /* Plain string, minimal verification */
711   if(len >= sizeof(ifnode->driver))
712     { 
713       fprintf(stderr, "Driver name too long at line %d\n", linenum);  
714       return(-1);
715     }
716
717   /* Copy */
718   memcpy(ifnode->driver, string, len + 1); 
719
720   /* Activate */
721   ifnode->active[SELECT_DRIVER] = 1;
722   active[SELECT_DRIVER] = 1;
723
724   if(verbose)
725     fprintf(stderr,
726             "Parsing : Added Driver name `%s' from line %d.\n",
727             ifnode->driver, linenum);
728
729   return(0);
730 }
731
732 /*------------------------------------------------------------------*/
733 /*
734  * Compare the Driver name of two mappings
735  */
736 static int
737 mapping_cmpdriver(struct if_mapping *   ifnode,
738                   struct if_mapping *   target)
739 {
740   /* Do wildcard matching, case insensitive */
741   return(fnmatch(ifnode->driver, target->driver, FNM_CASEFOLD));
742 }
743
744 /*------------------------------------------------------------------*/
745 /*
746  * Add a Bus-Info selector to a mapping
747  */
748 static int
749 mapping_addbusinfo(struct if_mapping *  ifnode,
750                    int *                active,
751                    char *               string,
752                    size_t               len,
753                    int                  linenum)
754 {
755 #if 0
756   size_t        n;
757 #endif
758
759   /* Verify validity of string */
760   if(len >= sizeof(ifnode->bus_info))
761     { 
762       fprintf(stderr, "Bus Info too long at line %d\n", linenum);  
763       return(-1);
764     }
765 #if 0
766   /* Hum... This doesn's seem true for non-PCI bus-info */
767   n = strspn(string, "0123456789ABCDEFabcdef:.*"); 
768   if(n < len)
769     {
770       fprintf(stderr, "Error: Invalid Bus Info `%s' at line %d\n",
771               string, linenum);
772       return(-1);
773     }
774 #endif
775
776   /* Copy */
777   memcpy(ifnode->bus_info, string, len + 1); 
778
779   /* Activate */
780   ifnode->active[SELECT_BUSINFO] = 1;
781   active[SELECT_BUSINFO] = 1;
782
783   if(verbose)
784     fprintf(stderr,
785             "Parsing : Added Bus Info `%s' from line %d.\n",
786             ifnode->bus_info, linenum);
787
788   return(0);
789 }
790
791 /*------------------------------------------------------------------*/
792 /*
793  * Compare the Bus-Info of two mappings
794  */
795 static int
796 mapping_cmpbusinfo(struct if_mapping *  ifnode,
797                    struct if_mapping *  target)
798 {
799   /* Do wildcard matching, case insensitive */
800   return(fnmatch(ifnode->bus_info, target->bus_info, FNM_CASEFOLD));
801 }
802
803 /*------------------------------------------------------------------*/
804 /*
805  * Add a Firmare revision selector to a mapping
806  */
807 static int
808 mapping_addfirmware(struct if_mapping * ifnode,
809                     int *               active,
810                     char *              string,
811                     size_t              len,
812                     int                 linenum)
813 {
814   /* Verify validity of string */
815   if(len >= sizeof(ifnode->fw_version))
816     { 
817       fprintf(stderr, "Firmware revision too long at line %d\n", linenum);  
818       return(-1);
819     }
820
821   /* Copy */
822   memcpy(ifnode->fw_version, string, len + 1); 
823
824   /* Activate */
825   ifnode->active[SELECT_FIRMWARE] = 1;
826   active[SELECT_FIRMWARE] = 1;
827
828   if(verbose)
829     fprintf(stderr,
830             "Parsing : Added Firmware Revision `%s' from line %d.\n",
831             ifnode->fw_version, linenum);
832
833   return(0);
834 }
835
836 /*------------------------------------------------------------------*/
837 /*
838  * Compare the Bus-Info of two mappings
839  */
840 static int
841 mapping_cmpfirmware(struct if_mapping * ifnode,
842                     struct if_mapping * target)
843 {
844   /* Do wildcard matching, case insensitive */
845   return(fnmatch(ifnode->fw_version, target->fw_version, FNM_CASEFOLD));
846 }
847
848 /*------------------------------------------------------------------*/
849 /*
850  * Extract the Driver name and Bus-Info from a live interface
851  */
852 static int
853 mapping_getdriverbusinfo(int                    skfd,
854                          const char *           ifname,
855                          struct if_mapping *    target,
856                          int                    flag)
857 {
858   struct ifreq  ifr;
859   struct ethtool_drvinfo drvinfo;
860   int   ret;
861
862   /* Avoid "Unused parameter" warning */
863   flag = flag;
864
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])
868     return(0);
869
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;
876
877   /* Do it */
878   ret = ioctl(skfd, SIOCETHTOOL, &ifr);
879   if(ret < 0)
880     {
881       /* Most drivers don't support that, keep quiet for now */
882       if(verbose)
883         fprintf(stderr,
884                 "Error: Can't read driver/bus-info on interface `%s' : %s\n",
885                 ifname, strerror(errno));
886       return(-1);
887     }
888
889   /* Copy over */
890   strcpy(target->driver, drvinfo.driver);
891   strcpy(target->bus_info, drvinfo.bus_info);
892   strcpy(target->fw_version, drvinfo.fw_version);
893
894   /* Activate */
895   target->active[SELECT_DRIVER] = 1;
896   target->active[SELECT_BUSINFO] = 1;
897   target->active[SELECT_FIRMWARE] = 1;
898
899   if(verbose)
900     fprintf(stderr,
901             "Querying %s : Got Driver name `%s', Bus Info `%s' and Firmware `%s'.\n",
902             ifname, target->driver, target->bus_info, target->fw_version);
903
904   return(0);
905 }
906
907 /*------------------------------------------------------------------*/
908 /*
909  * Add a Base Address selector to a mapping
910  */
911 static int
912 mapping_addbaseaddr(struct if_mapping * ifnode,
913                     int *               active,
914                     char *              string,
915                     size_t              len,
916                     int                 linenum)
917 {
918   size_t        n;
919   unsigned int  address;
920
921   /* Verify validity of string */
922   n = strspn(string, "0123456789ABCDEFabcdefx"); 
923   if((n < len) || (sscanf(string, "0x%X", &address) != 1))
924     {
925       fprintf(stderr, "Error: Invalid Base Address `%s' at line %d\n",
926               string, linenum);
927       return(-1);
928     }
929
930   /* Copy */
931   ifnode->base_addr = (unsigned short) address;
932
933   /* Activate */
934   ifnode->active[SELECT_BASEADDR] = 1;
935   active[SELECT_BASEADDR] = 1;
936
937   if(verbose)
938     fprintf(stderr,
939             "Parsing : Added Base Address `0x%X' from line %d.\n",
940             ifnode->base_addr, linenum);
941
942   return(0);
943 }
944
945 /*------------------------------------------------------------------*/
946 /*
947  * Compare the Base Address of two mappings
948  */
949 static int
950 mapping_cmpbaseaddr(struct if_mapping * ifnode,
951                     struct if_mapping * target)
952 {
953   /* Do wildcard matching, case insensitive */
954   return(!(ifnode->base_addr == target->base_addr));
955 }
956
957 /*------------------------------------------------------------------*/
958 /*
959  * Add a IRQ selector to a mapping
960  */
961 static int
962 mapping_addirq(struct if_mapping *      ifnode,
963                int *                    active,
964                char *                   string,
965                size_t                   len,
966                int                      linenum)
967 {
968   size_t        n;
969   unsigned int  irq;
970
971   /* Verify validity of string */
972   n = strspn(string, "0123456789"); 
973   if((n < len) || (sscanf(string, "%d", &irq) != 1))
974     {
975       fprintf(stderr, "Error: Invalid Base Address `%s' at line %d\n",
976               string, linenum);
977       return(-1);
978     }
979
980   /* Copy */
981   ifnode->irq = (unsigned char) irq;
982
983   /* Activate */
984   ifnode->active[SELECT_IRQ] = 1;
985   active[SELECT_IRQ] = 1;
986
987   if(verbose)
988     fprintf(stderr,
989             "Parsing : Added IRQ `%d' from line %d.\n",
990             ifnode->irq, linenum);
991
992   return(0);
993 }
994
995 /*------------------------------------------------------------------*/
996 /*
997  * Compare the IRQ of two mappings
998  */
999 static int
1000 mapping_cmpirq(struct if_mapping *      ifnode,
1001                struct if_mapping *      target)
1002 {
1003   /* Do wildcard matching, case insensitive */
1004   return(!(ifnode->irq == target->irq));
1005 }
1006
1007 /*------------------------------------------------------------------*/
1008 /*
1009  * Extract the Driver name and Bus-Info from a live interface
1010  */
1011 static int
1012 mapping_getbaseaddrirq(int                      skfd,
1013                        const char *             ifname,
1014                        struct if_mapping *      target,
1015                        int                      flag)
1016 {
1017   struct ifreq  ifr;
1018   struct ifmap  map;            /* hardware setup        */
1019   int   ret;
1020
1021   /* Avoid "Unused parameter" warning */
1022   flag = flag;
1023
1024   /* We may come here twice, so do the job only once */
1025   if(target->active[SELECT_BASEADDR] || target->active[SELECT_IRQ])
1026     return(0);
1027
1028   /* Prepare request */
1029   bzero(&ifr, sizeof(struct ifreq));
1030   bzero(&map, sizeof(struct ifmap));
1031   strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
1032
1033   /* Do it */
1034   ret = ioctl(skfd, SIOCGIFMAP, &ifr);
1035   if(ret < 0)
1036     {
1037       /* Don't know if every interface has that, so keep quiet... */
1038       if(verbose)
1039         fprintf(stderr,
1040                 "Error: Can't read base address/irq on interface `%s' : %s\n",
1041                 ifname, strerror(errno));
1042       return(-1);
1043     }
1044
1045   /* Copy over, activate */
1046   if(ifr.ifr_map.base_addr >= 0x100)
1047     {
1048       target->base_addr = ifr.ifr_map.base_addr;
1049       target->active[SELECT_BASEADDR] = 1;
1050     }
1051   target->irq = ifr.ifr_map.irq;
1052   target->active[SELECT_IRQ] = 1;
1053
1054   if(verbose)
1055     fprintf(stderr,
1056             "Querying %s : Got Base Address `0x%X' and IRQ `%d'.\n",
1057             ifname, target->base_addr, target->irq);
1058
1059   return(0);
1060 }
1061
1062 /*------------------------------------------------------------------*/
1063 /*
1064  * Add a Wireless Protocol selector to a mapping
1065  */
1066 static int
1067 mapping_addiwproto(struct if_mapping *  ifnode,
1068                    int *                active,
1069                    char *               string,
1070                    size_t               len,
1071                    int                  linenum)
1072 {
1073   /* Verify validity of string */
1074   if(len >= sizeof(ifnode->iwproto))
1075     { 
1076       fprintf(stderr, "Wireless Protocol too long at line %d\n", linenum);  
1077       return(-1);
1078     }
1079
1080   /* Copy */
1081   memcpy(ifnode->iwproto, string, len + 1); 
1082
1083   /* Activate */
1084   ifnode->active[SELECT_IWPROTO] = 1;
1085   active[SELECT_IWPROTO] = 1;
1086
1087   if(verbose)
1088     fprintf(stderr,
1089             "Parsing : Added Wireless Protocol `%s' from line %d.\n",
1090             ifnode->iwproto, linenum);
1091
1092   return(0);
1093 }
1094
1095 /*------------------------------------------------------------------*/
1096 /*
1097  * Compare the Wireless Protocol of two mappings
1098  */
1099 static int
1100 mapping_cmpiwproto(struct if_mapping *  ifnode,
1101                    struct if_mapping *  target)
1102 {
1103   /* Do wildcard matching, case insensitive */
1104   return(fnmatch(ifnode->iwproto, target->iwproto, FNM_CASEFOLD));
1105 }
1106
1107 /*------------------------------------------------------------------*/
1108 /*
1109  * Extract the Wireless Protocol from a live interface
1110  */
1111 static int
1112 mapping_getiwproto(int                  skfd,
1113                    const char *         ifname,
1114                    struct if_mapping *  target,
1115                    int                  flag)
1116 {
1117   struct iwreq          wrq;
1118
1119   /* Avoid "Unused parameter" warning */
1120   flag = flag;
1121
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 */
1125     return(-1);
1126
1127   strncpy(target->iwproto, wrq.u.name, IFNAMSIZ);
1128   target->iwproto[IFNAMSIZ] = '\0';
1129
1130   /* Activate */
1131   target->active[SELECT_IWPROTO] = 1;
1132
1133   if(verbose)
1134     fprintf(stderr,
1135             "Querying %s : Got Wireless Protocol `%s'.\n",
1136             ifname, target->iwproto);
1137
1138   return(0);
1139 }
1140
1141 /*------------------------------------------------------------------*/
1142 /*
1143  * Add a Pcmcia Slot selector to a mapping
1144  */
1145 static int
1146 mapping_addpcmciaslot(struct if_mapping *       ifnode,
1147                int *                    active,
1148                char *                   string,
1149                size_t                   len,
1150                int                      linenum)
1151 {
1152   size_t        n;
1153
1154   /* Verify validity of string, convert to int */
1155   n = strspn(string, "0123456789"); 
1156   if((n < len) || (sscanf(string, "%d", &ifnode->pcmcia_slot) != 1))
1157     {
1158       fprintf(stderr, "Error: Invalid Pcmcia Slot `%s' at line %d\n",
1159               string, linenum);
1160       return(-1);
1161     }
1162
1163   ifnode->active[SELECT_PCMCIASLOT] = 1;
1164   active[SELECT_PCMCIASLOT] = 1;
1165
1166   if(verbose)
1167     fprintf(stderr, "Parsing : Added Pcmcia Slot `%d' from line %d.\n",
1168             ifnode->pcmcia_slot, linenum);
1169
1170   return(0);
1171 }
1172
1173 /*------------------------------------------------------------------*/
1174 /*
1175  * Compare the Pcmcia Slot of two mappings
1176  */
1177 static int
1178 mapping_cmppcmciaslot(struct if_mapping *       ifnode,
1179                struct if_mapping *      target)
1180 {
1181   return(!(ifnode->pcmcia_slot == target->pcmcia_slot));
1182 }
1183
1184 /*------------------------------------------------------------------*/
1185 /*
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
1194  * this will change.
1195  * When that happen, we can drop this code...
1196  */
1197 static int
1198 mapping_getpcmciaslot(int                       skfd,
1199                       const char *              ifname,
1200                       struct if_mapping *       target,
1201                       int                       flag)
1202 {
1203   FILE *        stream;
1204   char *        linebuf = NULL;
1205   size_t        linelen = 0; 
1206   int           linenum = 0; 
1207
1208   /* Avoid "Unused parameter" warning */
1209   skfd = skfd;
1210   flag = flag;
1211
1212   /* Open the stab file for reading */
1213   stream = fopen(PCMCIA_STAB1, "r");
1214   if(!stream) 
1215     {
1216       /* Try again, alternate location */
1217       stream = fopen(PCMCIA_STAB2, "r");
1218       if(!stream) 
1219         {
1220           fprintf(stderr, "Error: Can't open PCMCIA Stab file `%s' or `%s': %s\n",
1221                   PCMCIA_STAB1, PCMCIA_STAB2, strerror(errno)); 
1222           return(-1);
1223         }
1224     }
1225
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)
1230     {
1231       char *                    p;
1232       size_t                    n;
1233       size_t                    k;
1234       int                       pcmcia_slot;
1235       int                       i;
1236
1237       /* Keep track of line number */
1238       linenum++;
1239
1240       /* Get Pcmcia socket number */
1241       p = linebuf;
1242       while(isspace(*p))
1243         ++p; 
1244       if(*p == '\0')
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))
1249         /* Next line */
1250         continue;
1251
1252       /* Skip socket number */
1253       /* Skip socket number ; device class ; driver name ; instance */
1254       for(i = 0; i < 4; i++)
1255         {
1256           /* Skip item */
1257           p += n;
1258           /* Skip space */
1259           p += strspn(p, " \t\n"); 
1260           if(*p == '\0')
1261             break;      /* Line ended */
1262           /* Next item size */
1263           n = strcspn(p, " \t\n");
1264         }
1265       if(*p == '\0')
1266         continue;       /* Line ended */
1267
1268       /* Terminate dev name */
1269       p[n] = '\0';
1270
1271       /* Compare to interface name */
1272       if(!strcmp(p, ifname))
1273         {
1274           /* Save */
1275           target->pcmcia_slot = pcmcia_slot;
1276
1277           /* Activate */
1278           target->active[SELECT_PCMCIASLOT] = 1;
1279
1280           if(verbose)
1281             fprintf(stderr,
1282                     "Querying %s : Got Pcmcia Slot `%d'.\n",
1283                     ifname, target->pcmcia_slot);
1284           /* Exit loop, found it */
1285           break;
1286         }
1287
1288       /* Finished -> next line */
1289     }
1290
1291   /* Cleanup */
1292   free(linebuf);
1293
1294   return(target->active[SELECT_PCMCIASLOT] ? 0 : -1);
1295 }
1296
1297
1298 /*********************** MAPPING MANAGEMENTS ***********************/
1299 /*
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.
1303  */
1304
1305 /*------------------------------------------------------------------*/
1306 /*
1307  * Create a new interface mapping and verify its name
1308  */
1309 static struct if_mapping *
1310 mapping_create(char *   pos,
1311                int      len,
1312                int      linenum)
1313 {
1314   struct if_mapping *   ifnode;
1315   char *                star;
1316
1317   /* Check overflow. */
1318   if(len > IFNAMSIZ)
1319     {
1320       fprintf(stderr, "Error: Interface name `%.*s' too long at line %d\n",
1321               (int) len, pos, linenum);  
1322       return(NULL);
1323     }
1324
1325   /* Create mapping, zero it */
1326   ifnode = calloc(1, sizeof(if_mapping));
1327   if(!ifnode)
1328     {
1329       fprintf(stderr, "Error: Can't allocate interface mapping.\n");  
1330       return(NULL);
1331     }
1332
1333   /* Set the name, terminates it */
1334   memcpy(ifnode->ifname, pos, len); 
1335   ifnode->ifname[len] = '\0'; 
1336
1337   /* Check the interface name and issue various pedantic warnings */
1338   if((!strcmp(ifnode->ifname, "eth0")) || (!strcmp(ifnode->ifname, "wlan0")))
1339     fprintf(stderr,
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);
1345
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, '*');
1351   if(star != NULL)
1352     {
1353       /* We need an extra char */
1354       if(len >= IFNAMSIZ)
1355         {
1356           fprintf(stderr,
1357                   "Error: Interface wildcard `%s' too long at line %d\n",
1358                   ifnode->ifname, linenum);  
1359           free(ifnode);
1360           return(NULL);
1361         }
1362
1363       /* Replace '*' with '%d' */
1364       memmove(star + 2, star + 1, len + 1 - (star - ifnode->ifname));
1365       star[0] = '%';
1366       star[1] = 'd';
1367     }
1368
1369   if(verbose)
1370     fprintf(stderr, "Parsing : Added Mapping `%s' from line %d.\n",
1371             ifnode->ifname, linenum);
1372
1373   /* Done */
1374   return(ifnode);
1375 }
1376
1377 /*------------------------------------------------------------------*/
1378 /*
1379  * Find the most appropriate selector matching a given selector name
1380  */
1381 static inline const struct mapping_selector *
1382 selector_find(const char *      string,
1383               size_t            slen,
1384               int               linenum)
1385 {
1386   const struct mapping_selector *       found = NULL;
1387   int                   ambig = 0;
1388   int                   i;
1389
1390   /* Go through all selectors */
1391   for(i = 0; selector_list[i].name != NULL; ++i)
1392     {
1393       /* No match -> next one */
1394       if(strncasecmp(selector_list[i].name, string, slen) != 0)
1395         continue;
1396
1397       /* Exact match -> perfect */
1398       if(slen == strlen(selector_list[i].name))
1399         return &selector_list[i];
1400
1401       /* Partial match */
1402       if(found == NULL)
1403         /* First time */
1404         found = &selector_list[i];
1405       else
1406         /* Another time */
1407         if (selector_list[i].add_fn != found->add_fn)
1408           ambig = 1;
1409     }
1410
1411   if(found == NULL)
1412     {
1413       fprintf(stderr, "Error: Unknown selector `%.*s' at line %d.\n",
1414               (int) slen, string, linenum);
1415       return NULL;
1416     }
1417
1418   if(ambig)
1419     {
1420       fprintf(stderr, "Selector `%.*s'at line %d is ambiguous.\n",
1421               (int) slen, string, linenum);
1422       return NULL;
1423     }
1424
1425   return found;
1426 }
1427
1428 /*------------------------------------------------------------------*/
1429 /*
1430  * Read the configuration file and extract all valid mappings and their
1431  * selectors.
1432  */
1433 static int
1434 mapping_readfile(const char *   filename)
1435 {
1436   FILE *        stream;
1437   char *        linebuf = NULL;
1438   size_t        linelen = 0; 
1439   int           linenum = 0; 
1440
1441   /* Reset the list of filters */
1442   bzero(selector_active, sizeof(selector_active));
1443
1444   /* Check filename */
1445   if(!strcmp(filename, "-"))
1446     {
1447       /* Read from stdin */
1448       stream = stdin;
1449
1450     }
1451   else
1452     {
1453       /* Open the file for reading */
1454       stream = fopen(filename, "r");
1455       if(!stream) 
1456         {
1457           fprintf(stderr, "Error: Can't open configuration file `%s': %s\n",
1458                   filename, strerror(errno)); 
1459           return(-1);
1460         }
1461     }
1462
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)
1467     {
1468       struct if_mapping *       ifnode;
1469       char *                    p;
1470       char *                    e;
1471       size_t                    n;
1472       int                       ret = -13;      /* Complain if no selectors */
1473
1474       /* Keep track of line number */
1475       linenum++;
1476
1477       /* Every comments terminates parsing */
1478       if((p = strchr(linebuf,'#')) != NULL)
1479         *p = '\0';
1480
1481       /* Get interface name */
1482       p = linebuf;
1483       while(isspace(*p))
1484         ++p; 
1485       if(*p == '\0')
1486         continue;       /* Line ended */
1487       n = strcspn(p, " \t\n");
1488
1489       /* Create mapping */
1490       ifnode = mapping_create(p, n, linenum);
1491       if(!ifnode)
1492         continue;       /* Ignore this line */
1493       p += n;
1494       p += strspn(p, " \t\n"); 
1495
1496       /* Loop on all selectors */
1497       while(*p != '\0')
1498         {
1499           const struct mapping_selector *       selector = NULL;
1500
1501           /* Selector name length */
1502           n = strcspn(p, " \t\n");
1503
1504           /* Find it */
1505           selector = selector_find(p, n, linenum);
1506           if(!selector)
1507             {
1508               ret = -1;
1509               break;
1510             }
1511
1512           /* Get to selector value */
1513           p += n;
1514           p += strspn(p, " \t\n"); 
1515           if(*p == '\0')
1516             {
1517               fprintf(stderr, "Error: no value for selector `%s' on line %d\n",
1518                       selector->name, linenum);
1519               ret = -1;
1520               break;    /* Line ended */
1521             }
1522           /* Check for quoted arguments */
1523           if(*p == '"')
1524             {
1525               p++;
1526               e = strchr(p, '"');
1527               if(e == NULL)
1528                 {
1529                   fprintf(stderr,
1530                           "Error: unterminated quoted value on line %d\n",
1531                           linenum);
1532                   ret = -1;
1533                   break;        /* Line ended */
1534                 }
1535               n = e - p;
1536               e++;
1537             }
1538           else
1539             {
1540               /* Just end at next blank */
1541               n = strcspn(p, " \t\n");
1542               e = p + n;
1543             }
1544           /* Make 'e' point past the '\0' we are going to add */
1545           if(*e != '\0')
1546             e++;
1547           /* Terminate selector value */
1548           p[n] = '\0';
1549
1550           /* Add it to the mapping */
1551           ret = selector->add_fn(ifnode, selector_active, p, n, linenum);
1552           if(ret < 0)
1553             break;
1554
1555           /* Go to next selector */
1556           p = e;
1557           p += strspn(p, " \t\n"); 
1558         }
1559
1560       /* We add a mapping only if it has at least one selector and if all
1561        * selectors were parsed properly. */
1562       if(ret < 0)
1563         {
1564           /* If we have not yet printed an error, now is a good time ;-) */
1565           if(ret == -13)
1566             fprintf(stderr, "Error: Line %d ignored, no valid selectors\n",
1567                     linenum);
1568           else
1569             fprintf(stderr, "Error: Line %d ignored due to prior errors\n",
1570                     linenum);
1571
1572           free(ifnode);
1573         }
1574       else
1575         {
1576           /* Link it in the list */
1577           ifnode->next = mapping_list;
1578           mapping_list = ifnode;
1579         }
1580     }
1581
1582   /* Cleanup */
1583   free(linebuf);
1584
1585   /* Finished reading, close the file */
1586   if(stream != stdin)
1587     fclose(stream);
1588   return(0);
1589 }
1590
1591 /*------------------------------------------------------------------*/
1592 /*
1593  * Extract all the interesting selectors for the interface in consideration
1594  */
1595 static struct if_mapping *
1596 mapping_extract(int             skfd,
1597                 const char *    ifname)
1598 {
1599   struct if_mapping *   target;
1600   int                   i;
1601
1602   /* Create mapping, zero it */
1603   target = calloc(1, sizeof(if_mapping));
1604   if(!target)
1605     {
1606       fprintf(stderr, "Error: Can't allocate interface mapping.\n");  
1607       return(NULL);
1608     }
1609
1610   /* Set the interface name */
1611   strcpy(target->ifname, ifname);
1612
1613   /* Loop on all active selectors */
1614   for(i = 0; i < SELECT_NUM; i++)
1615     {
1616       /* Check if this selector is active */
1617       if(selector_active[i] != 0)
1618         {
1619           /* Extract selector */
1620           selector_list[i].get_fn(skfd, ifname, target, selector_active[i]);
1621
1622           /* Ignore errors. Some mapping may not need all selectors */
1623         }
1624     }
1625
1626   return(target);
1627
1628
1629 /*------------------------------------------------------------------*/
1630 /*
1631  * Find the first mapping in the list matching the one we want.
1632  */
1633 static struct if_mapping *
1634 mapping_find(struct if_mapping *        target)
1635 {
1636   struct if_mapping *   ifnode;
1637   int                   i;
1638
1639   /* Look over all our mappings */
1640   for(ifnode = mapping_list; ifnode != NULL; ifnode = ifnode->next)
1641     {
1642       int               matches = 1;
1643
1644       /* Look over all our selectors, all must match */
1645       for(i = 0; i < SELECT_NUM; i++)
1646         {
1647           /* Check if this selector is active */
1648           if(ifnode->active[i] != 0)
1649             {
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))
1653                 {
1654                   matches = 0;
1655                   break;
1656                 }
1657             }
1658         }
1659
1660       /* Check is this mapping was "the one" */
1661       if(matches)
1662         return(ifnode);
1663     }
1664
1665   /* Not found */
1666   return(NULL);
1667
1668
1669 /************************** MODULE SUPPORT **************************/
1670 /*
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
1674  * 'ifup -a'.
1675  */
1676
1677 /*------------------------------------------------------------------*/
1678 /*
1679  * Probe interfaces based on our list of mappings.
1680  * This is the default, but usually not the best way to do it.
1681  */
1682 static void
1683 probe_mappings(int              skfd)
1684 {
1685   struct if_mapping *   ifnode;
1686   struct ether_addr     mac;                    /* Exact MAC address, hex */
1687   unsigned short        hw_type;
1688
1689   /* Look over all our mappings */
1690   for(ifnode = mapping_list; ifnode != NULL; ifnode = ifnode->next)
1691     {
1692       /* Can't load wildcards interface name :-( */
1693       if(strchr(ifnode->ifname, '%') != NULL)
1694         continue;
1695
1696       if(verbose)
1697         fprintf(stderr, "Probing : Trying to load interface [%s]\n",
1698                 ifnode->ifname);
1699
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.
1705        */
1706       iw_get_mac_addr(skfd, ifnode->ifname, &mac, &hw_type);
1707     }
1708 }
1709
1710 /*------------------------------------------------------------------*/
1711 /*
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).
1716  */
1717 static void
1718 probe_debian(int                skfd)
1719 {
1720   FILE *                stream;
1721   char *                linebuf = NULL;
1722   size_t                linelen = 0; 
1723   struct ether_addr     mac;                    /* Exact MAC address, hex */
1724   unsigned short        hw_type;
1725
1726   /* Open Debian config file */
1727   stream = fopen(DEBIAN_CONFIG_FILE, "r");
1728   if(stream == NULL)
1729     {
1730       fprintf(stderr, "Error: can't open file [%s]\n", DEBIAN_CONFIG_FILE);
1731       return;
1732     }
1733
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)
1738     {
1739       char *                    p;
1740       char *                    e;
1741       size_t                    n;
1742
1743       /* Check for auto keyword, ignore when commented out */
1744       if(!strncasecmp(linebuf, "auto ", 5))
1745         {
1746           /* Skip "auto" keyword */
1747           p = linebuf + 5;
1748
1749           /* Terminate at first comment */
1750           e = strchr(p, '#');
1751           if(e != NULL)
1752             *e = '\0';
1753
1754           /* Loop on all interfaces given */
1755           while(*p != '\0')
1756             {
1757               /* Interface name length */
1758               n = strcspn(p, " \t\n");
1759
1760               /* Look for end of interface name */
1761               e = p + n;
1762               /* Make 'e' point past the '\0' we are going to add */
1763               if(*e != '\0')
1764                 e++;
1765               /* Terminate interface name */
1766               p[n] = '\0';
1767
1768               if(verbose)
1769                 fprintf(stderr, "Probing : Trying to load interface [%s]\n",
1770                         p);
1771
1772               /* Do it ! */
1773               iw_get_mac_addr(skfd, p, &mac, &hw_type);
1774
1775               /* Go to next interface name */
1776               p = e;
1777               p += strspn(p, " \t\n"); 
1778             }
1779         }
1780     }
1781
1782   /* Done */
1783   fclose(stream);
1784   return;
1785 }
1786
1787 /**************************** MAIN LOGIC ****************************/
1788
1789 /*------------------------------------------------------------------*/
1790 /*
1791  * Rename an interface to a specified new name.
1792  */
1793 static int
1794 process_rename(int      skfd,
1795                char *   ifname,
1796                char *   pattern)
1797 {
1798   char          newname[IFNAMSIZ+1];
1799   char          retname[IFNAMSIZ+1];
1800   int           len;
1801   char *        star;
1802
1803   len = strlen(pattern);
1804   star = strchr(pattern, '*');
1805
1806   /* Check newname length, need one extra char for wildcard */
1807   if((len + (star != NULL)) > IFNAMSIZ)
1808     {
1809       fprintf(stderr, "Error: Interface name `%s' too long.\n",
1810               pattern);  
1811       return(-1);
1812     }
1813
1814   /* Copy to local buffer */
1815   memcpy(newname, pattern, len + 1);
1816
1817   /* Convert wildcard to the proper format */
1818   if(star != NULL)
1819     {
1820       /* Replace '*' with '%d' in the new buffer */
1821       star += newname - pattern;
1822       memmove(star + 2, star + 1, len + 1 - (star - newname));
1823       star[0] = '%';
1824       star[1] = 'd';
1825     }
1826
1827
1828   /* Change the name of the interface */
1829   if(if_set_name(skfd, ifname, newname, retname) < 0)
1830     {
1831       fprintf(stderr, "Error: cannot change name of %s to %s: %s\n",
1832               ifname, newname, strerror(errno)); 
1833       return(-1);
1834     }
1835
1836   /* Always print out the *new* interface name so that
1837    * the calling script can pick it up and know where its interface
1838    * has gone. */
1839   printf("%s\n", retname);
1840
1841   /* Done */
1842   return(0);
1843 }
1844
1845 /*------------------------------------------------------------------*/
1846 /*
1847  * Process a specified interface.
1848  */
1849 static int
1850 process_ifname(int      skfd,
1851                char *   ifname,
1852                char *   args[],
1853                int      count)
1854 {
1855   struct if_mapping *           target;
1856   const struct if_mapping *     mapping;
1857   char                          retname[IFNAMSIZ+1];
1858
1859   /* Avoid "Unused parameter" warning */
1860   args = args; count = count;
1861
1862   /* Get description of this interface */
1863   target = mapping_extract(skfd, ifname);
1864   if(target == NULL)
1865     return(-1);
1866
1867   /* Find matching mapping */
1868   mapping = mapping_find(target);
1869   if(mapping == NULL)
1870     return(-1);
1871
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... */
1875   if(dry_run)
1876     {
1877       printf("Dry-run : Would rename %s to %s.\n",
1878              target->ifname, mapping->ifname);
1879       return(0);
1880     }
1881
1882   /* Change the name of the interface */
1883   if(if_set_name(skfd, target->ifname, mapping->ifname, retname) < 0)
1884     {
1885       fprintf(stderr, "Error: cannot change name of %s to %s: %s\n",
1886               target->ifname, mapping->ifname, strerror(errno)); 
1887       return(-1);
1888     }
1889
1890   /* Check if called with an explicit interface name */
1891   if(!count)
1892     {
1893       /* Always print out the *new* interface name so that
1894        * the calling script can pick it up and know where its interface
1895        * has gone. */
1896       printf("%s\n", retname);
1897     }
1898
1899   /* Done */
1900   return(0);
1901 }
1902
1903 /*------------------------------------------------------------------*/
1904 /*
1905  * Process all network interface present on the system.
1906  */
1907 static inline int
1908 process_iflist(int      skfd,
1909                char *   args[],
1910                int      count)
1911 {
1912   num_takeover = 0;
1913
1914   /* Just do it */
1915   iw_enum_devices(skfd, &process_ifname, args, count);
1916
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
1920    * list again.
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...
1924    * Jean II */
1925   if(force_takeover && num_takeover)
1926     /* Play it again, Sam... */
1927     iw_enum_devices(skfd, &process_ifname, args, count);
1928
1929   /* Done */
1930   return(0);
1931 }
1932
1933 /******************************* MAIN *******************************/
1934
1935
1936 /*------------------------------------------------------------------*/
1937 /*
1938  */
1939 static void
1940 usage(void)
1941 {
1942   fprintf(stderr, "usage: ifrename [-c configurationfile] [-i ifname] [-p] [-t] [-d] [-D]\n");
1943   exit(1); 
1944 }
1945
1946 /*------------------------------------------------------------------*/
1947 /*
1948  * The main !
1949  */
1950 int
1951 main(int        argc,
1952      char *     argv[]) 
1953 {
1954   const char *  conf_file = DEFAULT_CONF;
1955   char *        ifname = NULL;
1956   char *        newname = NULL;
1957   int           use_probe = 0;
1958   int           is_debian = 0;
1959   int           skfd;
1960   int           ret;
1961
1962   /* Loop over all command line options */
1963   while(1)
1964     {
1965       int c = getopt_long(argc, argv, "c:dDi:n:ptvV", long_opt, NULL);
1966       if(c == -1)
1967         break;
1968
1969       switch(c)
1970         { 
1971         default:
1972         case '?':
1973           usage(); 
1974         case 'c':
1975           conf_file = optarg;
1976           break;
1977         case 'd':
1978           is_debian = 1;
1979           break;
1980         case 'D':
1981           dry_run = 1;
1982           break;
1983         case 'i':
1984           ifname = optarg;
1985           break;
1986         case 'n':
1987           newname = optarg;
1988           break;
1989         case 'p':
1990           use_probe = 1;
1991           break;
1992         case 't':
1993           force_takeover = 1;
1994           break;
1995         case 'v':
1996           printf("%-8.16s  Wireless-Tools version %d\n", "ifrename", WT_VERSION);
1997           return(0);
1998         case 'V':
1999           verbose = 1;
2000           break;
2001         }
2002     }
2003
2004   /* Read the specified/default config file, or stdin. */
2005   if(mapping_readfile(conf_file) < 0)
2006     return(-1);
2007
2008   /* Create a channel to the NET kernel. */
2009   if((skfd = iw_sockets_open()) < 0)
2010     {
2011       perror("socket");
2012       return(-1);
2013     }
2014
2015   /* Check if interface name was specified with -i. */
2016   if(ifname)
2017     {
2018       /* Check is target name specified */
2019       if(newname != NULL)
2020         {
2021           /* User want to simply rename an interface to a specified name */
2022           ret = process_rename(skfd, ifname, newname);
2023         }
2024       else
2025         {
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.
2030            */
2031           ret = process_ifname(skfd, ifname, NULL, 0);
2032         }
2033     }
2034   else
2035     {
2036       /* Load all the necesary modules */
2037       if(use_probe)
2038         {
2039           if(is_debian)
2040             probe_debian(skfd);
2041           else
2042             probe_mappings(skfd);
2043         }
2044
2045       /* Rename all system interfaces
2046        * Mostly used for boot time processing (from init scripts).
2047        */
2048       ret = process_iflist(skfd, &newname, 1);
2049     }
2050
2051   /* Cleanup */
2052   iw_sockets_close(skfd);
2053   return(ret);
2054