OSDN Git Service

9a29d17b2d8c6a4998e7d458ad9bc54efb97635c
[android-x86/external-wireless-tools.git] / wireless_tools / ifrename.c
1 /*
2  *      Wireless Tools
3  *
4  *              Jean II - HPL 04 -> 07
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) 2007 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  * -------------------------------------------------------
26  *
27  *      It started with a series of patches to nameif which never made
28  * into the regular version, and had some architecural 'issues' with
29  * those patches, which is the reason of this rewrite.
30  *      Difference with standard 'nameif' :
31  *      o 'nameif' has only a single selector, the interface MAC address.
32  *      o Modular selector architecture, easily add new selectors.
33  *      o Wide range of selector, including sysfs and sysfs symlinks...
34  *      o hotplug invocation support.
35  *      o module loading support.
36  *      o MAC address wildcard.
37  *      o Interface name wildcard ('eth*' or 'wlan*').
38  *      o Non-Ethernet MAC addresses (any size, not just 48 bits)
39  */
40
41 /***************************** INCLUDES *****************************/
42
43 /* This is needed to enable GNU extensions such as getline & FNM_CASEFOLD */
44 #ifndef _GNU_SOURCE 
45 #define _GNU_SOURCE
46 #endif
47
48 #include <getopt.h>             /* getopt_long() */
49 #include <linux/sockios.h>      /* SIOCSIFNAME */
50 #include <fnmatch.h>            /* fnmatch() */
51 //#include <sys/syslog.h>
52
53 #include "iwlib.h"              /* Wireless Tools library */
54
55 // This would be cool, unfortunately...
56 //#include <linux/ethtool.h>    /* Ethtool stuff -> struct ethtool_drvinfo */
57
58 /************************ CONSTANTS & MACROS ************************/
59
60 /* Our default configuration file */
61 const char DEFAULT_CONF[] =             "/etc/iftab"; 
62
63 /* Debian stuff */
64 const char DEBIAN_CONFIG_FILE[] =       "/etc/network/interfaces";
65
66 /* Backward compatibility */
67 #ifndef ifr_newname
68 #define ifr_newname ifr_ifru.ifru_slave
69 #endif
70
71 /* Types of selector we support. Must match selector_list */
72 const int SELECT_MAC            = 0;    /* Select by MAC address */
73 const int SELECT_ETHADDR        = 1;    /* Select by MAC address */
74 const int SELECT_ARP            = 2;    /* Select by ARP type */
75 const int SELECT_LINKTYPE       = 3;    /* Select by ARP type */
76 const int SELECT_DRIVER         = 4;    /* Select by Driver name */
77 const int SELECT_BUSINFO        = 5;    /* Select by Bus-Info */
78 const int SELECT_FIRMWARE       = 6;    /* Select by Firmware revision */
79 const int SELECT_BASEADDR       = 7;    /* Select by HW Base Address */
80 const int SELECT_IRQ            = 8;    /* Select by HW Irq line */
81 const int SELECT_INTERRUPT      = 9;    /* Select by HW Irq line */
82 const int SELECT_IWPROTO        = 10;   /* Select by Wireless Protocol */
83 const int SELECT_PCMCIASLOT     = 11;   /* Select by Pcmcia Slot */
84 const int SELECT_SYSFS          = 12;   /* Select by sysfs file */
85 const int SELECT_PREVNAME       = 13;   /* Select by previous interface name */
86 #define SELECT_NUM              14
87
88 #define HAS_MAC_EXACT   1
89 #define HAS_MAC_FILTER  2
90 #define MAX_MAC_LEN     16      /* Maximum lenght of MAC address */
91
92 const struct ether_addr zero_mac = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
93
94 const struct option long_opt[] =
95
96   {"config-file", 1, NULL, 'c' },
97   {"debian", 0, NULL, 'd' },
98   {"dry-run", 0, NULL, 'D' },
99   {"help", 0, NULL, '?' },
100   {"interface", 1, NULL, 'i' },
101   {"newname", 1, NULL, 'n' },
102   {"takeover", 0, NULL, 't' },
103   {"udev", 0, NULL, 'u' },
104   {"version", 0, NULL, 'v' },
105   {"verbose", 0, NULL, 'V' },
106   {NULL, 0, NULL, '\0' },
107 };
108
109 /* Pcmcia stab files */
110 #define PCMCIA_STAB1    "/var/lib/pcmcia/stab"
111 #define PCMCIA_STAB2    "/var/run/stab"
112
113 /* Max number of sysfs file types we support */
114 #define SYSFS_MAX_FILE  8
115
116 /* Userspace headers lag, fix that... */
117 #ifndef ARPHRD_IEEE1394
118 #define ARPHRD_IEEE1394 24
119 #endif
120 #ifndef ARPHRD_EUI64
121 #define ARPHRD_EUI64 27
122 #endif
123 #ifndef ARPHRD_IRDA
124 #define ARPHRD_IRDA 783
125 #endif
126
127 /* Length of various non-standard MAC addresses */
128 const int       weird_mac_len[][2] =
129 {
130   { ARPHRD_IEEE1394, 8 },
131   { ARPHRD_EUI64, 8 },
132   { ARPHRD_IRDA, 4 },
133 };
134 const int weird_mac_len_num = sizeof(weird_mac_len) / sizeof(weird_mac_len[0]);
135
136 /****************************** TYPES ******************************/
137
138 /* Cut'n'paste from ethtool.h */
139 #define ETHTOOL_BUSINFO_LEN     32
140 /* these strings are set to whatever the driver author decides... */
141 struct ethtool_drvinfo {
142         __u32   cmd;
143         char    driver[32];     /* driver short name, "tulip", "eepro100" */
144         char    version[32];    /* driver version string */
145         char    fw_version[32]; /* firmware version string, if applicable */
146         char    bus_info[ETHTOOL_BUSINFO_LEN];  /* Bus info for this IF. */
147                                 /* For PCI devices, use pci_dev->slot_name. */
148         char    reserved1[32];
149         char    reserved2[16];
150         __u32   n_stats;        /* number of u64's from ETHTOOL_GSTATS */
151         __u32   testinfo_len;
152         __u32   eedump_len;     /* Size of data from ETHTOOL_GEEPROM (bytes) */
153         __u32   regdump_len;    /* Size of data from ETHTOOL_GREGS (bytes) */
154 };
155 #define ETHTOOL_GDRVINFO        0x00000003 /* Get driver info. */
156
157 /* Description of an interface mapping */
158 typedef struct if_mapping
159
160   /* Linked list */
161   struct if_mapping *   next;
162
163   /* Name of this interface */
164   char                  ifname[IFNAMSIZ+1];
165   char *                sysfs_devpath;
166   int                   sysfs_devplen;
167
168   /* Selectors for this interface */
169   int                   active[SELECT_NUM];     /* Selectors active */
170
171   /* Selector data */
172   unsigned char         mac[MAX_MAC_LEN];       /* Exact MAC address, hex */
173   int                   mac_len;                /* Length (usually 6) */
174   char                  mac_filter[16*3 + 1];   /* WildCard, ascii */
175   unsigned short        hw_type;                /* Link/ARP type */
176   char                  driver[32];             /* driver short name */
177   char          bus_info[ETHTOOL_BUSINFO_LEN];  /* Bus info for this IF. */
178   char                  fw_version[32];         /* Firmware revision */
179   unsigned short        base_addr;              /* HW Base I/O address */ 
180   unsigned char         irq;                    /* HW irq line */
181   char                  iwproto[IFNAMSIZ + 1];  /* Wireless/protocol name */
182   int                   pcmcia_slot;            /* Pcmcia slot */
183   char *                sysfs[SYSFS_MAX_FILE];  /* sysfs selectors */
184   char                  prevname[IFNAMSIZ+1];   /* previous interface name */
185 } if_mapping;
186
187 /* Extra parsing information when adding a mapping */
188 typedef struct add_extra
189
190   char *                modif_pos;              /* Descriptor modifier */
191   size_t                modif_len;
192 } parsing_extra;
193
194 /* Prototype for adding a selector to a mapping. Return -1 if invalid value. */
195 typedef int (*mapping_add)(struct if_mapping *  ifnode,
196                            int *                active,
197                            char *               pos,
198                            size_t               len,
199                            struct add_extra *   extra,
200                            int                  linenum);
201
202 /* Prototype for comparing the selector of two mapping. Return 0 if matches. */
203 typedef int (*mapping_cmp)(struct if_mapping *  ifnode,
204                            struct if_mapping *  target);
205 /* Prototype for extracting selector value from live interface */
206 typedef int (*mapping_get)(int                  skfd,
207                            const char *         ifname,
208                            struct if_mapping *  target,
209                            int                  flag);
210
211 /* How to handle a selector */
212 typedef struct mapping_selector
213 {
214   char *        name;
215   mapping_add   add_fn;
216   mapping_cmp   cmp_fn;
217   mapping_get   get_fn;
218 } mapping_selector;
219
220 /* sysfs global data */
221 typedef struct sysfs_metadata
222 {
223   char *                root;                   /* Root of the sysfs */
224   int                   rlen;                   /* Size of it */
225   int                   filenum;                /* Number of files */
226   char *                filename[SYSFS_MAX_FILE];       /* Name of files */
227 } sysfs_metadata;
228
229 /**************************** PROTOTYPES ****************************/
230
231 static int
232         mapping_addmac(struct if_mapping *      ifnode,
233                        int *                    active,
234                        char *                   pos,
235                        size_t                   len,
236                        struct add_extra *       extra,
237                        int                      linenum);
238 static int
239         mapping_cmpmac(struct if_mapping *      ifnode,
240                        struct if_mapping *      target);
241 static int
242         mapping_getmac(int                      skfd,
243                        const char *             ifname,
244                        struct if_mapping *      target,
245                        int                      flag);
246 static int
247         mapping_addarp(struct if_mapping *      ifnode,
248                        int *                    active,
249                        char *                   pos,
250                        size_t                   len,
251                        struct add_extra *       extra,
252                        int                      linenum);
253 static int
254         mapping_cmparp(struct if_mapping *      ifnode,
255                        struct if_mapping *      target);
256 static int
257         mapping_getarp(int                      skfd,
258                        const char *             ifname,
259                        struct if_mapping *      target,
260                        int                      flag);
261 static int
262         mapping_adddriver(struct if_mapping *   ifnode,
263                           int *                 active,
264                           char *                pos,
265                           size_t                len,
266                           struct add_extra *    extra,
267                           int                   linenum);
268 static int
269         mapping_cmpdriver(struct if_mapping *   ifnode,
270                           struct if_mapping *   target);
271 static int
272         mapping_addbusinfo(struct if_mapping *  ifnode,
273                            int *                active,
274                            char *               pos,
275                            size_t               len,
276                            struct add_extra *   extra,
277                            int                  linenum);
278 static int
279         mapping_cmpbusinfo(struct if_mapping *  ifnode,
280                            struct if_mapping *  target);
281 static int
282         mapping_addfirmware(struct if_mapping * ifnode,
283                             int *               active,
284                             char *              pos,
285                             size_t              len,
286                             struct add_extra *  extra,
287                             int                 linenum);
288 static int
289         mapping_cmpfirmware(struct if_mapping * ifnode,
290                             struct if_mapping * target);
291 static int
292         mapping_getdriverbusinfo(int                    skfd,
293                                  const char *           ifname,
294                                  struct if_mapping *    target,
295                                  int                    flag);
296 static int
297         mapping_addbaseaddr(struct if_mapping * ifnode,
298                             int *               active,
299                             char *              pos,
300                             size_t              len,
301                             struct add_extra *  extra,
302                             int                 linenum);
303 static int
304         mapping_cmpbaseaddr(struct if_mapping * ifnode,
305                             struct if_mapping * target);
306 static int
307         mapping_addirq(struct if_mapping *      ifnode,
308                        int *                    active,
309                        char *                   pos,
310                        size_t                   len,
311                        struct add_extra *       extra,
312                        int                      linenum);
313 static int
314         mapping_cmpirq(struct if_mapping *      ifnode,
315                        struct if_mapping *      target);
316 static int
317         mapping_getbaseaddrirq(int                      skfd,
318                                const char *             ifname,
319                                struct if_mapping *      target,
320                                int                      flag);
321 static int
322         mapping_addiwproto(struct if_mapping *  ifnode,
323                            int *                active,
324                            char *               pos,
325                            size_t               len,
326                            struct add_extra *   extra,
327                            int                  linenum);
328 static int
329         mapping_cmpiwproto(struct if_mapping *  ifnode,
330                            struct if_mapping *  target);
331 static int
332         mapping_getiwproto(int                  skfd,
333                            const char *         ifname,
334                            struct if_mapping *  target,
335                            int                  flag);
336 static int
337         mapping_addpcmciaslot(struct if_mapping *       ifnode,
338                               int *                     active,
339                               char *                    pos,
340                               size_t                    len,
341                               struct add_extra *        extra,
342                               int                       linenum);
343 static int
344         mapping_cmppcmciaslot(struct if_mapping *       ifnode,
345                            struct if_mapping *          target);
346 static int
347         mapping_getpcmciaslot(int                       skfd,
348                               const char *              ifname,
349                               struct if_mapping *       target,
350                               int                       flag);
351 static int
352         mapping_addsysfs(struct if_mapping *    ifnode,
353                          int *                  active,
354                          char *                 pos,
355                          size_t                 len,
356                          struct add_extra *     extra,
357                          int                    linenum);
358 static int
359         mapping_cmpsysfs(struct if_mapping *    ifnode,
360                          struct if_mapping *    target);
361 static int
362         mapping_getsysfs(int                    skfd,
363                          const char *           ifname,
364                          struct if_mapping *    target,
365                          int                    flag);
366 static int
367         mapping_addprevname(struct if_mapping * ifnode,
368                            int *                active,
369                            char *               pos,
370                            size_t               len,
371                            struct add_extra *   extra,
372                            int                  linenum);
373 static int
374         mapping_cmpprevname(struct if_mapping * ifnode,
375                            struct if_mapping *  target);
376 static int
377         mapping_getprevname(int                 skfd,
378                            const char *         ifname,
379                            struct if_mapping *  target,
380                            int                  flag);
381
382 /**************************** VARIABLES ****************************/
383
384 /* List of mapping read for config file */
385 struct if_mapping *     mapping_list = NULL;
386
387 /* List of selectors we can handle */
388 const struct mapping_selector   selector_list[] =
389 {
390   /* MAC address and ARP/Link type from ifconfig */
391   { "mac", &mapping_addmac, &mapping_cmpmac, &mapping_getmac },
392   { "ethaddr", &mapping_addmac, &mapping_cmpmac, &mapping_getmac },
393   { "arp", &mapping_addarp, &mapping_cmparp, &mapping_getarp },
394   { "linktype", &mapping_addarp, &mapping_cmparp, &mapping_getarp },
395   /* Driver name, Bus-Info and firmware rev from ethtool -i */
396   { "driver", &mapping_adddriver, &mapping_cmpdriver,
397     &mapping_getdriverbusinfo },
398   { "businfo", &mapping_addbusinfo, &mapping_cmpbusinfo,
399     &mapping_getdriverbusinfo },
400   { "firmware", &mapping_addfirmware, &mapping_cmpfirmware,
401     &mapping_getdriverbusinfo },
402   /* Base Address and IRQ from ifconfig */
403   { "baseaddress", &mapping_addbaseaddr, &mapping_cmpbaseaddr,
404     &mapping_getbaseaddrirq },
405   { "irq", &mapping_addirq, &mapping_cmpirq, &mapping_getbaseaddrirq },
406   { "interrupt", &mapping_addirq, &mapping_cmpirq, &mapping_getbaseaddrirq },
407   /* Wireless Protocol from iwconfig */
408   { "iwproto", &mapping_addiwproto, &mapping_cmpiwproto, &mapping_getiwproto },
409   /* Pcmcia slot from cardmgr */
410   { "pcmciaslot", &mapping_addpcmciaslot, &mapping_cmppcmciaslot, &mapping_getpcmciaslot },
411   /* sysfs file (udev emulation) */
412   { "sysfs", &mapping_addsysfs, &mapping_cmpsysfs, &mapping_getsysfs },
413   /* previous interface name */
414   { "prevname", &mapping_addprevname, &mapping_cmpprevname, &mapping_getprevname },
415   /* The Terminator */
416   { NULL, NULL, NULL, NULL },
417 };
418 const int selector_num = sizeof(selector_list)/sizeof(selector_list[0]);
419
420 /* List of active selectors */
421 int     selector_active[SELECT_NUM];    /* Selectors active */
422
423 /*
424  * All the following flags are controlled by the command line switches...
425  * It's a bit hackish to have them all as global, so maybe we should pass
426  * them in a big struct as function arguments... More complex and
427  * probably not worth it ?
428  */
429
430 /* Invocation type */
431 int     print_newname = 0;
432 char *  new_name = NULL;
433
434 /* Takeover support */
435 int     force_takeover = 0;     /* Takeover name from other interface */
436 int     num_takeover = 0;       /* Number of takeover done */
437
438 /* Dry-run support */
439 int     dry_run = 0;            /* Just print new name, don't rename */
440
441 /* Verbose support (i.e. debugging) */
442 int     verbose = 0;
443
444 /* udev output support (print new DEVPATH) */
445 int     udev_output = 0;
446
447 /* sysfs global data */
448 struct sysfs_metadata   sysfs_global =
449 {
450   NULL, 0,
451   0, { NULL, NULL, NULL, NULL, NULL },
452 };
453
454 /******************** INTERFACE NAME MANAGEMENT ********************/
455 /*
456  * Bunch of low level function for managing interface names.
457  */
458
459 /*------------------------------------------------------------------*/
460 /*
461  * Compare two interface names, with wildcards.
462  * We can't use fnmatch() because we don't want expansion of '[...]'
463  * expressions, '\' sequences and matching of '.'.
464  * We only want to match a single '*' (converted to a %d at that point)
465  * to a numerical value (no ascii).
466  * Return 0 is matches.
467  */
468 static int
469 if_match_ifname(const char *    pattern,
470                 const char *    value)
471 {
472   const char *  p;
473   const char *  v;
474   int           n;
475   int           ret;
476
477   /* Check for a wildcard */
478   p = strchr(pattern, '*');
479
480   /* No wildcard, simple comparison */
481   if(p == NULL)
482     return(strcmp(pattern, value));
483
484   /* Check is prefixes match */
485   n = (p - pattern);
486   ret = strncmp(pattern, value, n);
487   if(ret)
488     return(ret);
489
490   /* Check that value has some digits at this point */
491   v = value + n;
492   if(!isdigit(*v))
493     return(-1);
494
495   /* Skip digits to go to value suffix */
496   do
497     v++;
498   while(isdigit(*v));
499
500   /* Pattern suffix */
501   p += 1;
502
503   /* Compare suffixes */
504   return(strcmp(p, v));
505 }
506
507 /*------------------------------------------------------------------*/
508 /*
509  * Steal interface name from another interface. This enable interface
510  * name swapping.
511  * This will work :
512  *      1) with kernel 2.6.X
513  *      2) if other interface is down
514  * Because of (2), it won't work with hotplug, but we don't need it
515  * with hotplug, only with static ifaces...
516  */
517 static int
518 if_takeover_name(int                    skfd,
519                  const char *           victimname)
520 {
521   char          autoname[IFNAMSIZ+1];
522   int           len;
523   struct ifreq  ifr;
524   int           ret;
525
526   /* Compute name for victim interface */
527   len = strlen(victimname);
528   memcpy(autoname, victimname, len + 1);
529   if(len > (IFNAMSIZ - 2))
530     len = IFNAMSIZ - 2;         /* Make sure we have at least two char */
531   len--;                        /* Convert to index */
532   while(isdigit(autoname[len]))
533     len--;                      /* Scrap all trailing digits */
534   strcpy(autoname + len + 1, "%d");
535
536   if(verbose)
537     fprintf(stderr, "Takeover : moving interface `%s' to `%s'.\n",
538             victimname, autoname);
539
540   /* Prepare request */
541   bzero(&ifr, sizeof(struct ifreq));
542   strncpy(ifr.ifr_name, victimname, IFNAMSIZ); 
543   strncpy(ifr.ifr_newname, autoname, IFNAMSIZ); 
544
545   /* Rename victim interface */
546   ret = ioctl(skfd, SIOCSIFNAME, &ifr);
547
548   if(!ret)
549     num_takeover++;
550
551   return(ret);
552 }
553
554 /*------------------------------------------------------------------*/
555 /*
556  * Ask the kernel to change the name of an interface.
557  * That's what we want to do. All the rest is to make sure we call this
558  * appropriately.
559  */
560 static int
561 if_set_name(int                 skfd,
562             const char *        oldname,
563             const char *        newname,
564             char *              retname)
565 {
566   struct ifreq  ifr;
567   char *        star;
568   int           ret;
569
570   /* The kernel doesn't check is the interface already has the correct
571    * name and may return an error, so check ourselves.
572    * In the case of wildcard, the result can be weird : if oldname='eth0'
573    * and newname='eth*', retname would be 'eth1'.
574    * So, if the oldname value matches the newname pattern, just return
575    * success. */
576   if(!if_match_ifname(newname, oldname))
577     {
578       if(verbose)
579         fprintf(stderr, "Setting : Interface `%s' already matches `%s'.\n",
580                 oldname, newname);
581
582       strcpy(retname, oldname);
583       return(0);
584     }
585
586   /* Prepare request */
587   bzero(&ifr, sizeof(struct ifreq));
588   strncpy(ifr.ifr_name, oldname, IFNAMSIZ); 
589   strncpy(ifr.ifr_newname, newname, IFNAMSIZ); 
590
591   /* Check for wildcard interface name, such as 'eth*' or 'wlan*'...
592    * This require specific kernel support (2.6.2-rc1 and later).
593    * We externally use '*', but the kernel doesn't know about that,
594    * so convert it to something it knows about... */
595   star = strchr(newname, '*');
596   if(star != NULL)
597     {
598       int       slen = star - newname;
599       /* Replace '*' with '%d' in the new buffer */
600       star = ifr.ifr_newname + slen;
601       /* Size was checked in process_rename() and mapping_create() */
602       memmove(star + 2, star + 1, IFNAMSIZ - slen - 2);
603       star[0] = '%';
604       star[1] = 'd';
605     }
606
607   /* Do it */
608   ret = ioctl(skfd, SIOCSIFNAME, &ifr);
609
610   /* Takeover support : grab interface name from another interface */
611   if(ret && (errno == EEXIST) && force_takeover)
612     {
613       /* Push things around */
614       ret = if_takeover_name(skfd, newname);
615       if(!ret)
616         /* Second try */
617         ret = ioctl(skfd, SIOCSIFNAME, &ifr);
618     }
619
620   if(!ret)
621     {
622       /* Get the real new name (in case newname is a wildcard) */
623       strcpy(retname, ifr.ifr_newname);
624
625       if(verbose)
626         fprintf(stderr, "Setting : Interface `%s' renamed to `%s'.\n",
627                 oldname, retname);
628     }
629
630   return(ret);
631 }
632
633 /************************ SELECTOR HANDLING ************************/
634 /*
635  * Handle the various selector we support
636  */
637
638 /*------------------------------------------------------------------*/
639 /*
640  * Add a MAC address selector to a mapping
641  */
642 static int
643 mapping_addmac(struct if_mapping *      ifnode,
644                int *                    active,
645                char *                   string,
646                size_t                   len,
647                struct add_extra *       extra,
648                int                      linenum)
649 {
650   size_t        n;
651
652   /* Avoid "Unused parameter" warning */
653   extra = extra;
654
655   /* Verify validity of string */
656   if(len >= sizeof(ifnode->mac_filter))
657     { 
658       fprintf(stderr, "Error : MAC address too long at line %d\n", linenum);  
659       return(-1);
660     }
661   n = strspn(string, "0123456789ABCDEFabcdef:*"); 
662   if(n < len)
663     {
664       fprintf(stderr, "Error: Invalid MAC address `%s' at line %d\n",
665               string, linenum);
666       return(-1);
667     }
668
669   /* Copy as filter in all cases */
670   memcpy(ifnode->mac_filter, string, len + 1); 
671
672   /* Check the type of MAC address */
673   if (strchr(ifnode->mac_filter, '*') != NULL)
674     {
675       /* This is a wilcard. Usual format : "01:23:45:*"
676        * Unfortunately, we can't do proper parsing. */
677       ifnode->active[SELECT_MAC] = HAS_MAC_FILTER;
678       active[SELECT_MAC] = HAS_MAC_FILTER;
679     }
680   else
681     {
682       /* Not a wildcard : "01:23:45:67:89:AB" */
683       ifnode->mac_len = iw_mac_aton(ifnode->mac_filter,
684                                     ifnode->mac, MAX_MAC_LEN);
685       if(ifnode->mac_len == 0)
686         {
687           fprintf(stderr, "Error: Invalid MAC address `%s' at line %d\n",
688                   ifnode->mac_filter, linenum);
689           return(-1);
690         }
691
692       /* Check that it's not NULL */
693       if((ifnode->mac_len == 6) && (!memcmp(&ifnode->mac, &zero_mac, 6)))
694         {
695           fprintf(stderr,
696                   "Warning: MAC address is null at line %d, this is dangerous...\n",
697                   linenum);
698         }
699
700       ifnode->active[SELECT_MAC] = HAS_MAC_EXACT;
701       if(active[SELECT_MAC] == 0)
702         active[SELECT_MAC] = HAS_MAC_EXACT;
703     }
704
705   if(verbose)
706     fprintf(stderr,
707             "Parsing : Added %s MAC address `%s' from line %d.\n",
708             ifnode->active[SELECT_MAC] == HAS_MAC_FILTER ? "filter" : "exact",
709             ifnode->mac_filter, linenum);
710
711   return(0);
712 }
713
714 /*------------------------------------------------------------------*/
715 /*
716  * Compare the mac address of two mappings
717  */
718 static int
719 mapping_cmpmac(struct if_mapping *      ifnode,
720                struct if_mapping *      target)
721 {
722   /* Check for wildcard matching */
723   if(ifnode->active[SELECT_MAC] == HAS_MAC_FILTER)
724     /* Do wildcard matching, case insensitive */
725     return(fnmatch(ifnode->mac_filter, target->mac_filter, FNM_CASEFOLD));
726   else
727     /* Exact matching, in hex */
728     return((ifnode->mac_len != target->mac_len) ||
729            memcmp(ifnode->mac, target->mac, ifnode->mac_len));
730 }
731
732 /*------------------------------------------------------------------*/
733 /*
734  * Extract the MAC address and Link Type of an interface
735  */
736 static int
737 mapping_getmac(int                      skfd,
738                const char *             ifname,
739                struct if_mapping *      target,
740                int                      flag)
741 {
742   struct ifreq  ifr;
743   int           ret;
744   int           i;
745
746   /* Get MAC address */
747   bzero(&ifr, sizeof(struct ifreq));
748   strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
749   ret = ioctl(skfd, SIOCGIFHWADDR, &ifr);
750   if(ret < 0)
751     {
752       fprintf(stderr, "Error: Can't read MAC address on interface `%s' : %s\n",
753               ifname, strerror(errno));
754       return(-1);
755     }
756
757   /* Extract ARP type */
758   target->hw_type = ifr.ifr_hwaddr.sa_family;
759   /* Calculate address length */
760   target->mac_len = 6;
761   for(i = 0; i < weird_mac_len_num; i++)
762     if(weird_mac_len[i][0] == ifr.ifr_hwaddr.sa_family)
763       {
764         target->mac_len = weird_mac_len[i][1];
765         break;
766       }
767   /* Extract MAC address bytes */
768   memcpy(target->mac, ifr.ifr_hwaddr.sa_data, target->mac_len);
769
770   /* Check the type of comparison */
771   if((flag == HAS_MAC_FILTER) || verbose)
772     {
773       /* Convert to ASCII */
774       iw_mac_ntop(target->mac, target->mac_len,
775                   target->mac_filter, sizeof(target->mac_filter));
776     }
777
778   target->active[SELECT_MAC] = flag;
779   target->active[SELECT_ARP] = 1;
780
781   if(verbose)
782     fprintf(stderr,
783             "Querying %s : Got MAC address `%s' and ARP/Link Type `%d'.\n",
784             ifname, target->mac_filter, target->hw_type);
785
786   return(0);
787 }
788
789 /*------------------------------------------------------------------*/
790 /*
791  * Add a ARP/Link type selector to a mapping
792  */
793 static int
794 mapping_addarp(struct if_mapping *      ifnode,
795                int *                    active,
796                char *                   string,
797                size_t                   len,
798                struct add_extra *       extra,
799                int                      linenum)
800 {
801   size_t        n;
802   unsigned int  type;
803
804   /* Avoid "Unused parameter" warning */
805   extra = extra;
806
807   /* Verify validity of string, convert to int */
808   n = strspn(string, "0123456789"); 
809   if((n < len) || (sscanf(string, "%d", &type) != 1))
810     {
811       fprintf(stderr, "Error: Invalid ARP/Link Type `%s' at line %d\n",
812               string, linenum);
813       return(-1);
814     }
815
816   ifnode->hw_type = (unsigned short) type;
817   ifnode->active[SELECT_ARP] = 1;
818   active[SELECT_ARP] = 1;
819
820   if(verbose)
821     fprintf(stderr, "Parsing : Added ARP/Link Type `%d' from line %d.\n",
822             ifnode->hw_type, linenum);
823
824   return(0);
825 }
826
827 /*------------------------------------------------------------------*/
828 /*
829  * Compare the ARP/Link type of two mappings
830  */
831 static int
832 mapping_cmparp(struct if_mapping *      ifnode,
833                struct if_mapping *      target)
834 {
835   return(!(ifnode->hw_type == target->hw_type));
836 }
837
838 /*------------------------------------------------------------------*/
839 /*
840  * Extract the ARP/Link type of an interface
841  */
842 static int
843 mapping_getarp(int                      skfd,
844                const char *             ifname,
845                struct if_mapping *      target,
846                int                      flag)
847 {
848   /* We may have already extracted the MAC address */
849   if(target->active[SELECT_MAC])
850     return(0);
851
852   /* Otherwise just do it */
853   return(mapping_getmac(skfd, ifname, target, flag));
854 }
855
856 /*------------------------------------------------------------------*/
857 /*
858  * Add a Driver name selector to a mapping
859  */
860 static int
861 mapping_adddriver(struct if_mapping *   ifnode,
862                   int *                 active,
863                   char *                string,
864                   size_t                len,
865                   struct add_extra *    extra,
866                   int                   linenum)
867 {
868   /* Avoid "Unused parameter" warning */
869   extra = extra;
870
871   /* Plain string, minimal verification */
872   if(len >= sizeof(ifnode->driver))
873     { 
874       fprintf(stderr, "Error: Driver name too long at line %d\n", linenum);  
875       return(-1);
876     }
877
878   /* Copy */
879   memcpy(ifnode->driver, string, len + 1); 
880
881   /* Activate */
882   ifnode->active[SELECT_DRIVER] = 1;
883   active[SELECT_DRIVER] = 1;
884
885   if(verbose)
886     fprintf(stderr,
887             "Parsing : Added Driver name `%s' from line %d.\n",
888             ifnode->driver, linenum);
889
890   return(0);
891 }
892
893 /*------------------------------------------------------------------*/
894 /*
895  * Compare the Driver name of two mappings
896  */
897 static int
898 mapping_cmpdriver(struct if_mapping *   ifnode,
899                   struct if_mapping *   target)
900 {
901   /* Do wildcard matching, case insensitive */
902   return(fnmatch(ifnode->driver, target->driver, FNM_CASEFOLD));
903 }
904
905 /*------------------------------------------------------------------*/
906 /*
907  * Add a Bus-Info selector to a mapping
908  */
909 static int
910 mapping_addbusinfo(struct if_mapping *  ifnode,
911                    int *                active,
912                    char *               string,
913                    size_t               len,
914                    struct add_extra *   extra,
915                    int                  linenum)
916 {
917 #if 0
918   size_t        n;
919 #endif
920
921   /* Avoid "Unused parameter" warning */
922   extra = extra;
923
924   /* Verify validity of string */
925   if(len >= sizeof(ifnode->bus_info))
926     { 
927       fprintf(stderr, "Bus Info too long at line %d\n", linenum);  
928       return(-1);
929     }
930 #if 0
931   /* Hum... This doesn's seem true for non-PCI bus-info */
932   n = strspn(string, "0123456789ABCDEFabcdef:.*"); 
933   if(n < len)
934     {
935       fprintf(stderr, "Error: Invalid Bus Info `%s' at line %d\n",
936               string, linenum);
937       return(-1);
938     }
939 #endif
940
941   /* Copy */
942   memcpy(ifnode->bus_info, string, len + 1); 
943
944   /* Activate */
945   ifnode->active[SELECT_BUSINFO] = 1;
946   active[SELECT_BUSINFO] = 1;
947
948   if(verbose)
949     fprintf(stderr,
950             "Parsing : Added Bus Info `%s' from line %d.\n",
951             ifnode->bus_info, linenum);
952
953   return(0);
954 }
955
956 /*------------------------------------------------------------------*/
957 /*
958  * Compare the Bus-Info of two mappings
959  */
960 static int
961 mapping_cmpbusinfo(struct if_mapping *  ifnode,
962                    struct if_mapping *  target)
963 {
964   /* Do wildcard matching, case insensitive */
965   return(fnmatch(ifnode->bus_info, target->bus_info, FNM_CASEFOLD));
966 }
967
968 /*------------------------------------------------------------------*/
969 /*
970  * Add a Firmare revision selector to a mapping
971  */
972 static int
973 mapping_addfirmware(struct if_mapping * ifnode,
974                     int *               active,
975                     char *              string,
976                     size_t              len,
977                     struct add_extra *  extra,
978                     int                 linenum)
979 {
980   /* Avoid "Unused parameter" warning */
981   extra = extra;
982
983   /* Verify validity of string */
984   if(len >= sizeof(ifnode->fw_version))
985     { 
986       fprintf(stderr, "Firmware revision too long at line %d\n", linenum);  
987       return(-1);
988     }
989
990   /* Copy */
991   memcpy(ifnode->fw_version, string, len + 1); 
992
993   /* Activate */
994   ifnode->active[SELECT_FIRMWARE] = 1;
995   active[SELECT_FIRMWARE] = 1;
996
997   if(verbose)
998     fprintf(stderr,
999             "Parsing : Added Firmware Revision `%s' from line %d.\n",
1000             ifnode->fw_version, linenum);
1001
1002   return(0);
1003 }
1004
1005 /*------------------------------------------------------------------*/
1006 /*
1007  * Compare the Bus-Info of two mappings
1008  */
1009 static int
1010 mapping_cmpfirmware(struct if_mapping * ifnode,
1011                     struct if_mapping * target)
1012 {
1013   /* Do wildcard matching, case insensitive */
1014   return(fnmatch(ifnode->fw_version, target->fw_version, FNM_CASEFOLD));
1015 }
1016
1017 /*------------------------------------------------------------------*/
1018 /*
1019  * Extract the Driver name and Bus-Info from a live interface
1020  */
1021 static int
1022 mapping_getdriverbusinfo(int                    skfd,
1023                          const char *           ifname,
1024                          struct if_mapping *    target,
1025                          int                    flag)
1026 {
1027   struct ifreq  ifr;
1028   struct ethtool_drvinfo drvinfo;
1029   int   ret;
1030
1031   /* Avoid "Unused parameter" warning */
1032   flag = flag;
1033
1034   /* We may come here twice or more, so do the job only once */
1035   if(target->active[SELECT_DRIVER] || target->active[SELECT_BUSINFO]
1036      || target->active[SELECT_FIRMWARE])
1037     return(0);
1038
1039   /* Prepare request */
1040   bzero(&ifr, sizeof(struct ifreq));
1041   bzero(&drvinfo, sizeof(struct ethtool_drvinfo));
1042   strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
1043   drvinfo.cmd = ETHTOOL_GDRVINFO;
1044   ifr.ifr_data = (caddr_t) &drvinfo;
1045
1046   /* Do it */
1047   ret = ioctl(skfd, SIOCETHTOOL, &ifr);
1048   if(ret < 0)
1049     {
1050       /* Most drivers don't support that, keep quiet for now */
1051       if(verbose)
1052         fprintf(stderr,
1053                 "Error: Can't read driver/bus-info on interface `%s' : %s\n",
1054                 ifname, strerror(errno));
1055       return(-1);
1056     }
1057
1058   /* Copy over */
1059   strcpy(target->driver, drvinfo.driver);
1060   strcpy(target->bus_info, drvinfo.bus_info);
1061   strcpy(target->fw_version, drvinfo.fw_version);
1062
1063   /* Activate */
1064   target->active[SELECT_DRIVER] = 1;
1065   target->active[SELECT_BUSINFO] = 1;
1066   target->active[SELECT_FIRMWARE] = 1;
1067
1068   if(verbose)
1069     fprintf(stderr,
1070             "Querying %s : Got Driver name `%s', Bus Info `%s' and Firmware `%s'.\n",
1071             ifname, target->driver, target->bus_info, target->fw_version);
1072
1073   return(0);
1074 }
1075
1076 /*------------------------------------------------------------------*/
1077 /*
1078  * Add a Base Address selector to a mapping
1079  */
1080 static int
1081 mapping_addbaseaddr(struct if_mapping * ifnode,
1082                     int *               active,
1083                     char *              string,
1084                     size_t              len,
1085                     struct add_extra *  extra,
1086                     int                 linenum)
1087 {
1088   size_t        n;
1089   unsigned int  address;
1090
1091   /* Avoid "Unused parameter" warning */
1092   extra = extra;
1093
1094   /* Verify validity of string */
1095   n = strspn(string, "0123456789ABCDEFabcdefx"); 
1096   if((n < len) || (sscanf(string, "0x%X", &address) != 1))
1097     {
1098       fprintf(stderr, "Error: Invalid Base Address `%s' at line %d\n",
1099               string, linenum);
1100       return(-1);
1101     }
1102
1103   /* Copy */
1104   ifnode->base_addr = (unsigned short) address;
1105
1106   /* Activate */
1107   ifnode->active[SELECT_BASEADDR] = 1;
1108   active[SELECT_BASEADDR] = 1;
1109
1110   if(verbose)
1111     fprintf(stderr,
1112             "Parsing : Added Base Address `0x%X' from line %d.\n",
1113             ifnode->base_addr, linenum);
1114
1115   return(0);
1116 }
1117
1118 /*------------------------------------------------------------------*/
1119 /*
1120  * Compare the Base Address of two mappings
1121  */
1122 static int
1123 mapping_cmpbaseaddr(struct if_mapping * ifnode,
1124                     struct if_mapping * target)
1125 {
1126   /* Do wildcard matching, case insensitive */
1127   return(!(ifnode->base_addr == target->base_addr));
1128 }
1129
1130 /*------------------------------------------------------------------*/
1131 /*
1132  * Add a IRQ selector to a mapping
1133  */
1134 static int
1135 mapping_addirq(struct if_mapping *      ifnode,
1136                int *                    active,
1137                char *                   string,
1138                size_t                   len,
1139                struct add_extra *       extra,
1140                int                      linenum)
1141 {
1142   size_t        n;
1143   unsigned int  irq;
1144
1145   /* Avoid "Unused parameter" warning */
1146   extra = extra;
1147
1148   /* Verify validity of string */
1149   n = strspn(string, "0123456789"); 
1150   if((n < len) || (sscanf(string, "%d", &irq) != 1))
1151     {
1152       fprintf(stderr, "Error: Invalid Base Address `%s' at line %d\n",
1153               string, linenum);
1154       return(-1);
1155     }
1156
1157   /* Copy */
1158   ifnode->irq = (unsigned char) irq;
1159
1160   /* Activate */
1161   ifnode->active[SELECT_IRQ] = 1;
1162   active[SELECT_IRQ] = 1;
1163
1164   if(verbose)
1165     fprintf(stderr,
1166             "Parsing : Added IRQ `%d' from line %d.\n",
1167             ifnode->irq, linenum);
1168
1169   return(0);
1170 }
1171
1172 /*------------------------------------------------------------------*/
1173 /*
1174  * Compare the IRQ of two mappings
1175  */
1176 static int
1177 mapping_cmpirq(struct if_mapping *      ifnode,
1178                struct if_mapping *      target)
1179 {
1180   /* Do wildcard matching, case insensitive */
1181   return(!(ifnode->irq == target->irq));
1182 }
1183
1184 /*------------------------------------------------------------------*/
1185 /*
1186  * Extract the Driver name and Bus-Info from a live interface
1187  */
1188 static int
1189 mapping_getbaseaddrirq(int                      skfd,
1190                        const char *             ifname,
1191                        struct if_mapping *      target,
1192                        int                      flag)
1193 {
1194   struct ifreq  ifr;
1195   struct ifmap  map;            /* hardware setup        */
1196   int   ret;
1197
1198   /* Avoid "Unused parameter" warning */
1199   flag = flag;
1200
1201   /* We may come here twice, so do the job only once */
1202   if(target->active[SELECT_BASEADDR] || target->active[SELECT_IRQ])
1203     return(0);
1204
1205   /* Prepare request */
1206   bzero(&ifr, sizeof(struct ifreq));
1207   bzero(&map, sizeof(struct ifmap));
1208   strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
1209
1210   /* Do it */
1211   ret = ioctl(skfd, SIOCGIFMAP, &ifr);
1212   if(ret < 0)
1213     {
1214       /* Don't know if every interface has that, so keep quiet... */
1215       if(verbose)
1216         fprintf(stderr,
1217                 "Error: Can't read base address/irq on interface `%s' : %s\n",
1218                 ifname, strerror(errno));
1219       return(-1);
1220     }
1221
1222   /* Copy over, activate */
1223   if(ifr.ifr_map.base_addr >= 0x100)
1224     {
1225       target->base_addr = ifr.ifr_map.base_addr;
1226       target->active[SELECT_BASEADDR] = 1;
1227     }
1228   target->irq = ifr.ifr_map.irq;
1229   target->active[SELECT_IRQ] = 1;
1230
1231   if(verbose)
1232     fprintf(stderr,
1233             "Querying %s : Got Base Address `0x%X' and IRQ `%d'.\n",
1234             ifname, target->base_addr, target->irq);
1235
1236   return(0);
1237 }
1238
1239 /*------------------------------------------------------------------*/
1240 /*
1241  * Add a Wireless Protocol selector to a mapping
1242  */
1243 static int
1244 mapping_addiwproto(struct if_mapping *  ifnode,
1245                    int *                active,
1246                    char *               string,
1247                    size_t               len,
1248                    struct add_extra *   extra,
1249                    int                  linenum)
1250 {
1251   /* Avoid "Unused parameter" warning */
1252   extra = extra;
1253
1254   /* Verify validity of string */
1255   if(len >= sizeof(ifnode->iwproto))
1256     { 
1257       fprintf(stderr, "Wireless Protocol too long at line %d\n", linenum);  
1258       return(-1);
1259     }
1260
1261   /* Copy */
1262   memcpy(ifnode->iwproto, string, len + 1); 
1263
1264   /* Activate */
1265   ifnode->active[SELECT_IWPROTO] = 1;
1266   active[SELECT_IWPROTO] = 1;
1267
1268   if(verbose)
1269     fprintf(stderr,
1270             "Parsing : Added Wireless Protocol `%s' from line %d.\n",
1271             ifnode->iwproto, linenum);
1272
1273   return(0);
1274 }
1275
1276 /*------------------------------------------------------------------*/
1277 /*
1278  * Compare the Wireless Protocol of two mappings
1279  */
1280 static int
1281 mapping_cmpiwproto(struct if_mapping *  ifnode,
1282                    struct if_mapping *  target)
1283 {
1284   /* Do wildcard matching, case insensitive */
1285   return(fnmatch(ifnode->iwproto, target->iwproto, FNM_CASEFOLD));
1286 }
1287
1288 /*------------------------------------------------------------------*/
1289 /*
1290  * Extract the Wireless Protocol from a live interface
1291  */
1292 static int
1293 mapping_getiwproto(int                  skfd,
1294                    const char *         ifname,
1295                    struct if_mapping *  target,
1296                    int                  flag)
1297 {
1298   struct iwreq          wrq;
1299
1300   /* Avoid "Unused parameter" warning */
1301   flag = flag;
1302
1303   /* Get wireless name */
1304   if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
1305     /* Don't complain about it, Ethernet cards will never support this */
1306     return(-1);
1307
1308   strncpy(target->iwproto, wrq.u.name, IFNAMSIZ);
1309   target->iwproto[IFNAMSIZ] = '\0';
1310
1311   /* Activate */
1312   target->active[SELECT_IWPROTO] = 1;
1313
1314   if(verbose)
1315     fprintf(stderr,
1316             "Querying %s : Got Wireless Protocol `%s'.\n",
1317             ifname, target->iwproto);
1318
1319   return(0);
1320 }
1321
1322 /*------------------------------------------------------------------*/
1323 /*
1324  * Add a Pcmcia Slot selector to a mapping
1325  */
1326 static int
1327 mapping_addpcmciaslot(struct if_mapping *       ifnode,
1328                       int *                     active,
1329                       char *                    string,
1330                       size_t                    len,
1331                       struct add_extra *        extra,
1332                       int                       linenum)
1333 {
1334   size_t        n;
1335
1336   /* Avoid "Unused parameter" warning */
1337   extra = extra;
1338
1339   /* Verify validity of string, convert to int */
1340   n = strspn(string, "0123456789"); 
1341   if((n < len) || (sscanf(string, "%d", &ifnode->pcmcia_slot) != 1))
1342     {
1343       fprintf(stderr, "Error: Invalid Pcmcia Slot `%s' at line %d\n",
1344               string, linenum);
1345       return(-1);
1346     }
1347
1348   ifnode->active[SELECT_PCMCIASLOT] = 1;
1349   active[SELECT_PCMCIASLOT] = 1;
1350
1351   if(verbose)
1352     fprintf(stderr, "Parsing : Added Pcmcia Slot `%d' from line %d.\n",
1353             ifnode->pcmcia_slot, linenum);
1354
1355   return(0);
1356 }
1357
1358 /*------------------------------------------------------------------*/
1359 /*
1360  * Compare the Pcmcia Slot of two mappings
1361  */
1362 static int
1363 mapping_cmppcmciaslot(struct if_mapping *       ifnode,
1364                       struct if_mapping *       target)
1365 {
1366   return(!(ifnode->pcmcia_slot == target->pcmcia_slot));
1367 }
1368
1369 /*------------------------------------------------------------------*/
1370 /*
1371  * Extract the Pcmcia Slot of an interface
1372  * Note that this works only for cards fully managed by cardmgr.
1373  * With the kernel pcmcia modules, 32 bits cards (CardBus) are not managed
1374  * by cardmgr, and therefore won't have a valid slot number. For those
1375  * cards, you should use Bus Info (when the driver exports it).
1376  * In the long term, 16 bits card as well will no longer be managed by
1377  * cardmgr. Currently, Bus Info for 16 bit cards don't have any information
1378  * enabling to locate their physical location on the system, but I hope that
1379  * this will change.
1380  * When that happen, we can drop this code...
1381  */
1382 static int
1383 mapping_getpcmciaslot(int                       skfd,
1384                       const char *              ifname,
1385                       struct if_mapping *       target,
1386                       int                       flag)
1387 {
1388   FILE *        stream;
1389   char *        linebuf = NULL;
1390   size_t        linelen = 0; 
1391   int           linenum = 0; 
1392
1393   /* Avoid "Unused parameter" warning */
1394   skfd = skfd;
1395   flag = flag;
1396
1397   /* Open the stab file for reading */
1398   stream = fopen(PCMCIA_STAB1, "r");
1399   if(!stream) 
1400     {
1401       /* Try again, alternate location */
1402       stream = fopen(PCMCIA_STAB2, "r");
1403       if(!stream) 
1404         {
1405           fprintf(stderr, "Error: Can't open PCMCIA Stab file `%s' or `%s': %s\n",
1406                   PCMCIA_STAB1, PCMCIA_STAB2, strerror(errno)); 
1407           return(-1);
1408         }
1409     }
1410
1411   /* Read each line of file
1412    * getline is a GNU extension :-( The buffer is recycled and increased
1413    * as needed by getline. */
1414   while(getline(&linebuf, &linelen, stream) > 0)
1415     {
1416       char *                    p;
1417       size_t                    n;
1418       size_t                    k;
1419       int                       pcmcia_slot;
1420       int                       i;
1421
1422       /* Keep track of line number */
1423       linenum++;
1424
1425       /* Get Pcmcia socket number */
1426       p = linebuf;
1427       while(isspace(*p))
1428         ++p; 
1429       if(*p == '\0')
1430         continue;       /* Line ended */
1431       n = strcspn(p, " \t\n");
1432       k = strspn(p, "0123456789"); 
1433       if((k < n) || (sscanf(p, "%d", &pcmcia_slot) != 1))
1434         /* Next line */
1435         continue;
1436
1437       /* Skip socket number */
1438       /* Skip socket number ; device class ; driver name ; instance */
1439       for(i = 0; i < 4; i++)
1440         {
1441           /* Skip item */
1442           p += n;
1443           /* Skip space */
1444           p += strspn(p, " \t\n"); 
1445           if(*p == '\0')
1446             break;      /* Line ended */
1447           /* Next item size */
1448           n = strcspn(p, " \t\n");
1449         }
1450       if(*p == '\0')
1451         continue;       /* Line ended */
1452
1453       /* Terminate dev name */
1454       p[n] = '\0';
1455
1456       /* Compare to interface name */
1457       if(!strcmp(p, ifname))
1458         {
1459           /* Save */
1460           target->pcmcia_slot = pcmcia_slot;
1461
1462           /* Activate */
1463           target->active[SELECT_PCMCIASLOT] = 1;
1464
1465           if(verbose)
1466             fprintf(stderr,
1467                     "Querying %s : Got Pcmcia Slot `%d'.\n",
1468                     ifname, target->pcmcia_slot);
1469           /* Exit loop, found it */
1470           break;
1471         }
1472
1473       /* Finished -> next line */
1474     }
1475
1476   /* Cleanup */
1477   free(linebuf);
1478   fclose(stream);
1479
1480   return(target->active[SELECT_PCMCIASLOT] ? 0 : -1);
1481 }
1482
1483 /*------------------------------------------------------------------*/
1484 /*
1485  * Add a sysfs selector to a mapping
1486  */
1487 static int
1488 mapping_addsysfs(struct if_mapping *    ifnode,
1489                  int *                  active,
1490                  char *                 string,
1491                  size_t                 len,
1492                  struct add_extra *     extra,
1493                  int                    linenum)
1494 {
1495   int           findex; /* filename index */
1496   char *        sdup;
1497
1498   /* Check if we have a modifier */
1499   if((extra == NULL) || (extra->modif_pos == NULL))
1500     { 
1501       fprintf(stderr, "Error: No SYSFS filename at line %d\n", linenum);  
1502       return(-1);
1503     }
1504
1505   /* Search if the filename already exist */
1506   for(findex = 0; findex < sysfs_global.filenum; findex++)
1507     {
1508       if(!strcmp(extra->modif_pos, sysfs_global.filename[findex]))
1509         break;
1510     }
1511
1512   /* If filename does not exist, creates it */
1513   if(findex == sysfs_global.filenum)
1514     {
1515       if(findex == SYSFS_MAX_FILE)
1516         {
1517           fprintf(stderr, "Error: Too many SYSFS filenames at line %d\n", linenum);  
1518           return(-1);
1519         }
1520       sdup = strndup(extra->modif_pos, extra->modif_len);
1521       if(sdup == NULL)
1522         {
1523           fprintf(stderr, "Error: Can't allocate SYSFS file\n");  
1524           return(-1);
1525         }
1526       sysfs_global.filename[findex] = sdup;
1527       sysfs_global.filenum++;
1528     }
1529
1530   /* Store value */
1531   sdup = strndup(string, len);
1532   if(sdup == NULL)
1533     {
1534       fprintf(stderr, "Error: Can't allocate SYSFS value\n");  
1535       return(-1);
1536     }
1537   ifnode->sysfs[findex] = sdup;
1538
1539   /* Activate */
1540   ifnode->active[SELECT_SYSFS] = 1;
1541   active[SELECT_SYSFS] = 1;
1542
1543   if(verbose)
1544     fprintf(stderr,
1545             "Parsing : Added SYSFS filename `%s' value `%s' from line %d.\n",
1546             sysfs_global.filename[findex], ifnode->sysfs[findex], linenum);
1547
1548   return(0);
1549 }
1550
1551 /*------------------------------------------------------------------*/
1552 /*
1553  * Compare all the sysfs values of two mappings
1554  */
1555 static int
1556 mapping_cmpsysfs(struct if_mapping *    ifnode,
1557                  struct if_mapping *    target)
1558 {
1559   int           findex; /* filename index */
1560   int           match = 1;
1561
1562   /* Loop on all sysfs selector */
1563   for(findex = 0; findex < sysfs_global.filenum; findex++)
1564     {
1565       /* If the mapping defines this sysfs selector.. */
1566       if(ifnode->sysfs[findex] != NULL)
1567         /* And if the sysfs values don't match */
1568         if((target->sysfs[findex] == NULL) ||
1569            (fnmatch(ifnode->sysfs[findex], target->sysfs[findex],
1570                     FNM_CASEFOLD)))
1571           /* Then the sysfs selector doesn't match */
1572           match = 0;
1573     }
1574
1575   return(!match);
1576 }
1577
1578 /*------------------------------------------------------------------*/
1579 /*
1580  * Extract all the sysfs values of an interface
1581  */
1582 static int
1583 mapping_getsysfs(int                    skfd,
1584                  const char *           ifname,
1585                  struct if_mapping *    target,
1586                  int                    flag)
1587 {
1588   FILE *        stream;
1589   char *        fname;
1590   int           fnsize;
1591   char *        linebuf = NULL;
1592   size_t        linelen = 0; 
1593   char *        sdup;
1594   int           findex; /* filename index */
1595
1596   /* Avoid "Unused parameter" warning */
1597   skfd = skfd;
1598   flag = flag;
1599
1600   /* Check if we know the devpath of this device */
1601   if(target->sysfs_devpath == NULL)
1602     {
1603       /* Check if we know the root of the sysfs filesystem */
1604       if(sysfs_global.root == NULL)
1605         {
1606           /* Open the mount file for reading */
1607           stream = fopen("/proc/mounts", "r");
1608           if(!stream) 
1609             {
1610               fprintf(stderr, "Error: Can't open /proc/mounts file: %s\n",
1611                       strerror(errno)); 
1612               return(-1);
1613             }
1614
1615           /* Read each line of file
1616            * getline is a GNU extension :-( The buffer is recycled and
1617            * increased as needed by getline. */
1618           while(getline(&linebuf, &linelen, stream) > 0)
1619             {
1620               int               i;
1621               char *    p;
1622               size_t    n;
1623               char *    token[3];
1624               size_t    toklen[3];
1625
1626               /* The format of /proc/mounts is similar to /etc/fstab (5).
1627                * The first argument is the device. For sysfs, there is no
1628                * associated device, so this argument is ignored.
1629                * The second argument is the mount point.
1630                * The third argument is the filesystem type.
1631                */
1632
1633               /* Extract the first 3 tokens */
1634               p = linebuf;
1635               for(i = 0; i < 3; i++)
1636                 {
1637                   while(isspace(*p))
1638                     ++p; 
1639                   token[i] = p;
1640                   n = strcspn(p, " \t\n");
1641                   toklen[i] = n;
1642                   p += n;
1643                 }
1644               /* Get the filesystem which type is "sysfs" */
1645               if((n == 5) && (!strncasecmp(token[2], "sysfs", 5)))
1646                 {
1647                   /* Get its mount point */
1648                   n = toklen[1];
1649                   sdup = strndup(token[1], n);
1650                   if((n == 0) || (sdup == NULL))
1651                     {
1652                       fprintf(stderr,
1653                               "Error: Can't parse /proc/mounts file: %s\n",
1654                               strerror(errno)); 
1655                       return(-1);
1656                     }
1657                   /* Store it */
1658                   sysfs_global.root = sdup;
1659                   sysfs_global.rlen = n;
1660                   break;
1661                 }
1662               /* Finished -> next line */
1663             }
1664
1665           /* Cleanup */
1666           fclose(stream);
1667
1668           /* Check if we found it */
1669           if(sysfs_global.root == NULL)
1670             {
1671               fprintf(stderr,
1672                       "Error: Can't find sysfs in /proc/mounts file\n");
1673               free(linebuf);
1674               return(-1);
1675             }
1676         }
1677
1678       /* Construct devpath for this interface.
1679        * Reserve enough space to replace name without realloc. */
1680       fnsize = (sysfs_global.rlen + 11 + IFNAMSIZ + 1);
1681       fname = malloc(fnsize);
1682       if(fname == NULL)
1683         {
1684           fprintf(stderr, "Error: Can't allocate SYSFS devpath\n");  
1685           return(-1);
1686         }
1687       /* Not true devpath for 2.6.20+, but this syslink should work */
1688       target->sysfs_devplen = sprintf(fname, "%s/class/net/%s",
1689                                       sysfs_global.root, ifname);
1690       target->sysfs_devpath = fname;
1691     }
1692
1693   /* Loop on all sysfs selector */
1694   for(findex = 0; findex < sysfs_global.filenum; findex++)
1695     {
1696       char *    p;
1697       ssize_t   n;
1698
1699       /* Construct complete filename for the sysfs selector */
1700       fnsize = (target->sysfs_devplen + 1 +
1701                 strlen(sysfs_global.filename[findex]) + 1);
1702       fname = malloc(fnsize);
1703       if(fname == NULL)
1704         {
1705           fprintf(stderr, "Error: Can't allocate SYSFS filename\n");  
1706           free(linebuf);
1707           return(-1);
1708         }
1709       sprintf(fname, "%s/%s", target->sysfs_devpath,
1710               sysfs_global.filename[findex]);
1711
1712       /* Open the sysfs file for reading */
1713       stream = fopen(fname, "r");
1714       if(!stream) 
1715         {
1716           /* Some sysfs attribute may no exist for some interface */
1717           if(verbose)
1718             fprintf(stderr, "Error: Can't open file `%s': %s\n", fname,
1719                     strerror(errno)); 
1720           /* Next sysfs selector */
1721           continue;
1722         }
1723
1724       /* Read file. Only one line in file. */
1725       n = getline(&linebuf, &linelen, stream);
1726       fclose(stream);
1727       if(n <= 0)
1728         {
1729           /* Some attributes are just symlinks to another directory.
1730            * We can read the attributes in that other directory
1731            * just fine, but sometimes the symlink itself gives a lot
1732            * of information.
1733            * Examples : SYSFS{device} and SYSFS{device/driver}
1734            * In such cases, get the name of the directory pointed to...
1735            */
1736           /*
1737            * I must note that the API for readlink() is very bad,
1738            * which force us to have this ugly code. Yuck !
1739            */
1740           int           allocsize = 128;        /* 256 = Good start */
1741           int           retry = 16;
1742           char *        linkpath = NULL;
1743           int           pathlen;
1744
1745           /* Try reading the link with increased buffer size */
1746           do
1747             {
1748               allocsize *= 2;
1749               linkpath = realloc(linkpath, allocsize);
1750               pathlen = readlink(fname, linkpath, allocsize);
1751               /* If we did not hit the buffer limit, success */
1752               if(pathlen < allocsize)
1753                 break;
1754             }
1755           while(retry-- > 0);
1756
1757           /* Check for error, most likely ENOENT */
1758           if(pathlen > 0)
1759             /* We have a symlink ;-) Terminate the string. */
1760             linkpath[pathlen] = '\0';
1761           else
1762             {
1763               /* Error ! */
1764               free(linkpath);
1765
1766               /* A lot of information in the sysfs is implicit, given
1767                * by the position of a file in the tree. It is therefore
1768                * important to be able to read the various components
1769                * of a path. For this reason, we resolve '..' to the
1770                * real name of the parent directory... */
1771               /* We have at least 11 char, see above */
1772               if(!strcmp(fname + fnsize - 4, "/.."))
1773                 //if(!strcmp(fname + strlen(fname) - 3, "/.."))
1774                 {
1775                   /* This procedure to get the realpath is not very
1776                    * nice, but it's the "best practice". Hmm... */
1777                   int   cwd_fd = open(".", O_RDONLY);
1778                   linkpath = NULL;
1779                   if(cwd_fd > 0)
1780                     {
1781                       int       ret = chdir(fname);
1782                       if(ret == 0)
1783                         /* Using getcwd with NULL is a GNU extension. Nice. */
1784                         linkpath = getcwd(NULL, 0);
1785                       /* This may fail, but it's not fatal */
1786                       fchdir(cwd_fd);
1787                     }
1788                   /* Check if we suceeded */
1789                   if(!linkpath)
1790                     {
1791                       free(linkpath);
1792                       if(verbose)
1793                         fprintf(stderr, "Error: Can't read parent directory `%s'\n", fname);
1794                       /* Next sysfs selector */
1795                       continue;
1796                     }
1797                 }
1798               else
1799                 {
1800                   /* Some sysfs attribute are void for some interface,
1801                    * we may have a real directory, or we may have permission
1802                    * issues... */
1803                   if(verbose)
1804                     fprintf(stderr, "Error: Can't read file `%s'\n", fname);
1805                   /* Next sysfs selector */
1806                   continue;
1807                 }
1808             }
1809
1810           /* Here, we have a link name or a parent directory name */
1811
1812           /* Keep only the last component of path name, save it */
1813           p = basename(linkpath);
1814           sdup = strdup(p);
1815           free(linkpath);
1816         }
1817       else
1818         {
1819           /* This is a regular file (well, pseudo file) */
1820           /* Get content, remove trailing '/n', save it */
1821           p = linebuf;
1822           if(p[n - 1] == '\n')
1823             n--;
1824           sdup = strndup(p, n);
1825         }
1826       if(sdup == NULL)
1827         {
1828           fprintf(stderr, "Error: Can't allocate SYSFS value\n"); 
1829           free(linebuf);
1830           return(-1);
1831         }
1832       target->sysfs[findex] = sdup;
1833
1834       /* Activate */
1835       target->active[SELECT_SYSFS] = 1;
1836
1837       if(verbose)
1838         fprintf(stderr,
1839                 "Querying %s : Got SYSFS filename `%s' value `%s'.\n",
1840                 ifname, sysfs_global.filename[findex], target->sysfs[findex]);
1841
1842       /* Finished : Next sysfs selector */
1843     }
1844
1845   /* Cleanup */
1846   free(linebuf);
1847
1848   return(target->active[SELECT_SYSFS] ? 0 : -1);
1849 }
1850
1851 /*------------------------------------------------------------------*/
1852 /*
1853  * Add a Previous Interface Name selector to a mapping
1854  */
1855 static int
1856 mapping_addprevname(struct if_mapping * ifnode,
1857                    int *                active,
1858                    char *               string,
1859                    size_t               len,
1860                    struct add_extra *   extra,
1861                    int                  linenum)
1862 {
1863   /* Avoid "Unused parameter" warning */
1864   extra = extra;
1865
1866   /* Verify validity of string */
1867   if(len >= sizeof(ifnode->prevname))
1868     { 
1869       fprintf(stderr, "Old Interface Name too long at line %d\n", linenum);  
1870       return(-1);
1871     }
1872
1873   /* Copy */
1874   memcpy(ifnode->prevname, string, len + 1); 
1875
1876   /* Activate */
1877   ifnode->active[SELECT_PREVNAME] = 1;
1878   active[SELECT_PREVNAME] = 1;
1879
1880   if(verbose)
1881     fprintf(stderr,
1882             "Parsing : Added Old Interface Name `%s' from line %d.\n",
1883             ifnode->prevname, linenum);
1884
1885   return(0);
1886 }
1887
1888 /*------------------------------------------------------------------*/
1889 /*
1890  * Compare the Previous Interface Name of two mappings
1891  * Note : this one is special.
1892  */
1893 static int
1894 mapping_cmpprevname(struct if_mapping * ifnode,
1895                    struct if_mapping *  target)
1896 {
1897   /* Do wildcard matching, case insensitive */
1898   return(fnmatch(ifnode->prevname, target->ifname, FNM_CASEFOLD));
1899 }
1900
1901 /*------------------------------------------------------------------*/
1902 /*
1903  * Extract the Previous Interface Name from a live interface
1904  */
1905 static int
1906 mapping_getprevname(int                 skfd,
1907                    const char *         ifname,
1908                    struct if_mapping *  target,
1909                    int                  flag)
1910 {
1911   /* Avoid "Unused parameter" warning */
1912   skfd = skfd; ifname = ifname; flag = flag;
1913
1914   /* Don't do anything, it's already in target->ifname ;-) */
1915
1916   /* Activate */
1917   target->active[SELECT_PREVNAME] = 1;
1918
1919   return(0);
1920 }
1921
1922
1923 /*********************** MAPPING MANAGEMENTS ***********************/
1924 /*
1925  * Manage interface mappings.
1926  * Each mapping tell us how to identify a specific interface name.
1927  * It is composed of a bunch of selector values.
1928  */
1929
1930 /*------------------------------------------------------------------*/
1931 /*
1932  * Create a new interface mapping and verify its name
1933  */
1934 static struct if_mapping *
1935 mapping_create(char *   pos,
1936                int      len,
1937                int      linenum)
1938 {
1939   struct if_mapping *   ifnode;
1940   char *                star;
1941
1942   star = memchr(pos, '*', len);
1943
1944   /* Check overflow, need one extra char for wildcard */
1945   if((len + (star != NULL)) > IFNAMSIZ)
1946     {
1947       fprintf(stderr, "Error: Interface name `%.*s' too long at line %d\n",
1948               (int) len, pos, linenum);  
1949       return(NULL);
1950     }
1951
1952   /* Create mapping, zero it */
1953   ifnode = calloc(1, sizeof(if_mapping));
1954   if(!ifnode)
1955     {
1956       fprintf(stderr, "Error: Can't allocate interface mapping.\n");  
1957       return(NULL);
1958     }
1959
1960   /* Set the name, terminates it */
1961   memcpy(ifnode->ifname, pos, len); 
1962   ifnode->ifname[len] = '\0'; 
1963
1964   /* Check the interface name and issue various pedantic warnings.
1965    * We assume people using takeover want to force interfaces to those
1966    * names and know what they are doing, so don't bother them... */
1967   if((!force_takeover) &&
1968      ((!strcmp(ifnode->ifname, "eth0")) || (!strcmp(ifnode->ifname, "wlan0"))))
1969     fprintf(stderr,
1970             "Warning: Interface name is `%s' at line %d, can't be mapped reliably.\n",
1971             ifnode->ifname, linenum);
1972   if(strchr(ifnode->ifname, ':'))
1973     fprintf(stderr, "Warning: Alias device `%s' at line %d probably can't be mapped.\n",
1974             ifnode->ifname, linenum);
1975
1976   if(verbose)
1977     fprintf(stderr, "Parsing : Added Mapping `%s' from line %d.\n",
1978             ifnode->ifname, linenum);
1979
1980   /* Done */
1981   return(ifnode);
1982 }
1983
1984 /*------------------------------------------------------------------*/
1985 /*
1986  * Find the most appropriate selector matching a given selector name
1987  */
1988 static inline const struct mapping_selector *
1989 selector_find(const char *      string,
1990               size_t            slen,
1991               int               linenum)
1992 {
1993   const struct mapping_selector *       found = NULL;
1994   int                   ambig = 0;
1995   int                   i;
1996
1997   /* Go through all selectors */
1998   for(i = 0; selector_list[i].name != NULL; ++i)
1999     {
2000       /* No match -> next one */
2001       if(strncasecmp(selector_list[i].name, string, slen) != 0)
2002         continue;
2003
2004       /* Exact match -> perfect */
2005       if(slen == strlen(selector_list[i].name))
2006         return &selector_list[i];
2007
2008       /* Partial match */
2009       if(found == NULL)
2010         /* First time */
2011         found = &selector_list[i];
2012       else
2013         /* Another time */
2014         if (selector_list[i].add_fn != found->add_fn)
2015           ambig = 1;
2016     }
2017
2018   if(found == NULL)
2019     {
2020       fprintf(stderr, "Error: Unknown selector `%.*s' at line %d.\n",
2021               (int) slen, string, linenum);
2022       return NULL;
2023     }
2024
2025   if(ambig)
2026     {
2027       fprintf(stderr, "Selector `%.*s'at line %d is ambiguous.\n",
2028               (int) slen, string, linenum);
2029       return NULL;
2030     }
2031
2032   return found;
2033 }
2034
2035 /*------------------------------------------------------------------*/
2036 /*
2037  * Read the configuration file and extract all valid mappings and their
2038  * selectors.
2039  */
2040 static int
2041 mapping_readfile(const char *   filename)
2042 {
2043   FILE *                stream;
2044   char *                linebuf = NULL;
2045   size_t                linelen = 0; 
2046   int                   linenum = 0; 
2047   struct add_extra      extrainfo;
2048
2049   /* Reset the list of filters */
2050   bzero(selector_active, sizeof(selector_active));
2051
2052   /* Check filename */
2053   if(!strcmp(filename, "-"))
2054     {
2055       /* Read from stdin */
2056       stream = stdin;
2057
2058     }
2059   else
2060     {
2061       /* Open the file for reading */
2062       stream = fopen(filename, "r");
2063       if(!stream) 
2064         {
2065           fprintf(stderr, "Error: Can't open configuration file `%s': %s\n",
2066                   filename, strerror(errno)); 
2067           return(-1);
2068         }
2069     }
2070
2071   /* Read each line of file
2072    * getline is a GNU extension :-( The buffer is recycled and increased
2073    * as needed by getline. */
2074   while(getline(&linebuf, &linelen, stream) > 0)
2075     {
2076       struct if_mapping *       ifnode;
2077       char *                    p;
2078       char *                    e;
2079       size_t                    n;
2080       int                       ret = -13;      /* Complain if no selectors */
2081
2082       /* Keep track of line number */
2083       linenum++;
2084
2085       /* Every comments terminates parsing */
2086       if((p = strchr(linebuf,'#')) != NULL)
2087         *p = '\0';
2088
2089       /* Get interface name */
2090       p = linebuf;
2091       while(isspace(*p))
2092         ++p; 
2093       if(*p == '\0')
2094         continue;       /* Line ended */
2095       n = strcspn(p, " \t\n");
2096
2097       /* Create mapping */
2098       ifnode = mapping_create(p, n, linenum);
2099       if(!ifnode)
2100         continue;       /* Ignore this line */
2101       p += n;
2102       p += strspn(p, " \t\n"); 
2103
2104       /* Loop on all selectors */
2105       while(*p != '\0')
2106         {
2107           const struct mapping_selector *       selector = NULL;
2108           struct add_extra *                    extra = NULL;
2109
2110           /* Selector name length - stop at modifier start */
2111           n = strcspn(p, " \t\n{");
2112
2113           /* Find it */
2114           selector = selector_find(p, n, linenum);
2115           if(!selector)
2116             {
2117               ret = -1;
2118               break;
2119             }
2120           p += n;
2121
2122           /* Check for modifier */
2123           if(*p == '{')
2124             {
2125               p++;
2126               /* Find end of modifier */
2127               e = strchr(p, '}');
2128               if(e == NULL)
2129                 {
2130                   fprintf(stderr,
2131                           "Error: unterminated selector modifier value on line %d\n",
2132                           linenum);
2133                   ret = -1;
2134                   break;        /* Line ended */
2135                 }
2136               /* Fill in struct and hook it */
2137               extrainfo.modif_pos = p;
2138               extrainfo.modif_len = e - p;
2139               extra = &extrainfo;
2140               /* Terminate modifier value */
2141               e[0] = '\0';
2142               /* Skip it */
2143               p = e + 1;
2144             }
2145
2146           /* Get to selector value */
2147           p += strspn(p, " \t\n"); 
2148           if(*p == '\0')
2149             {
2150               fprintf(stderr, "Error: no value for selector `%s' on line %d\n",
2151                       selector->name, linenum);
2152               ret = -1;
2153               break;    /* Line ended */
2154             }
2155           /* Check for quoted arguments */
2156           if(*p == '"')
2157             {
2158               p++;
2159               e = strchr(p, '"');
2160               if(e == NULL)
2161                 {
2162                   fprintf(stderr,
2163                           "Error: unterminated quoted value on line %d\n",
2164                           linenum);
2165                   ret = -1;
2166                   break;        /* Line ended */
2167                 }
2168               n = e - p;
2169               e++;
2170             }
2171           else
2172             {
2173               /* Just end at next blank */
2174               n = strcspn(p, " \t\n");
2175               e = p + n;
2176             }
2177           /* Make 'e' point past the '\0' we are going to add */
2178           if(*e != '\0')
2179             e++;
2180           /* Terminate selector value */
2181           p[n] = '\0';
2182
2183           /* Add it to the mapping */
2184           ret = selector->add_fn(ifnode, selector_active, p, n,
2185                                  extra, linenum);
2186           if(ret < 0)
2187             break;
2188
2189           /* Go to next selector */
2190           p = e;
2191           p += strspn(p, " \t\n"); 
2192         }
2193
2194       /* We add a mapping only if it has at least one selector and if all
2195        * selectors were parsed properly. */
2196       if(ret < 0)
2197         {
2198           /* If we have not yet printed an error, now is a good time ;-) */
2199           if(ret == -13)
2200             fprintf(stderr, "Error: Line %d ignored, no valid selectors\n",
2201                     linenum);
2202           else
2203             fprintf(stderr, "Error: Line %d ignored due to prior errors\n",
2204                     linenum);
2205
2206           free(ifnode);
2207         }
2208       else
2209         {
2210           /* Link it in the list */
2211           ifnode->next = mapping_list;
2212           mapping_list = ifnode;
2213         }
2214     }
2215
2216   /* Cleanup */
2217   free(linebuf);
2218
2219   /* Finished reading, close the file */
2220   if(stream != stdin)
2221     fclose(stream);
2222   return(0);
2223 }
2224
2225 /*------------------------------------------------------------------*/
2226 /*
2227  * Extract all the interesting selectors for the interface in consideration
2228  */
2229 static struct if_mapping *
2230 mapping_extract(int             skfd,
2231                 const char *    ifname)
2232 {
2233   struct if_mapping *   target;
2234   int                   i;
2235
2236   /* Create mapping, zero it */
2237   target = calloc(1, sizeof(if_mapping));
2238   if(!target)
2239     {
2240       fprintf(stderr, "Error: Can't allocate interface mapping.\n");  
2241       return(NULL);
2242     }
2243
2244   /* Set the interface name */
2245   strcpy(target->ifname, ifname);
2246
2247   /* Loop on all active selectors */
2248   for(i = 0; i < SELECT_NUM; i++)
2249     {
2250       /* Check if this selector is active */
2251       if(selector_active[i] != 0)
2252         {
2253           /* Extract selector */
2254           selector_list[i].get_fn(skfd, ifname, target, selector_active[i]);
2255
2256           /* Ignore errors. Some mapping may not need all selectors */
2257         }
2258     }
2259
2260   return(target);
2261
2262
2263 /*------------------------------------------------------------------*/
2264 /*
2265  * Find the first mapping in the list matching the one we want.
2266  */
2267 static struct if_mapping *
2268 mapping_find(struct if_mapping *        target)
2269 {
2270   struct if_mapping *   ifnode;
2271   int                   i;
2272
2273   /* Look over all our mappings */
2274   for(ifnode = mapping_list; ifnode != NULL; ifnode = ifnode->next)
2275     {
2276       int               matches = 1;
2277
2278       /* Look over all our selectors, all must match */
2279       for(i = 0; i < SELECT_NUM; i++)
2280         {
2281           /* Check if this selector is active */
2282           if(ifnode->active[i] != 0)
2283             {
2284               /* If this selector doesn't match, game over for this mapping */
2285               if((target->active[i] == 0) ||
2286                  (selector_list[i].cmp_fn(ifnode, target) != 0))
2287                 {
2288                   matches = 0;
2289                   break;
2290                 }
2291             }
2292         }
2293
2294       /* Check is this mapping was "the one" */
2295       if(matches)
2296         return(ifnode);
2297     }
2298
2299   /* Not found */
2300   return(NULL);
2301
2302
2303 /************************** MODULE SUPPORT **************************/
2304 /*
2305  * Load all necessary module so that interfaces do exist.
2306  * This is necessary for system that are fully modular when
2307  * doing the boot time processing, because we need to run before
2308  * 'ifup -a'.
2309  */
2310
2311 /*------------------------------------------------------------------*/
2312 /*
2313  * Probe interfaces based on our list of mappings.
2314  * This is the default, but usually not the best way to do it.
2315  */
2316 static void
2317 probe_mappings(int              skfd)
2318 {
2319   struct if_mapping *   ifnode;
2320   struct ifreq          ifr;
2321
2322   /* Look over all our mappings */
2323   for(ifnode = mapping_list; ifnode != NULL; ifnode = ifnode->next)
2324     {
2325       /* Can't load wildcards interface name :-( */
2326       if(strchr(ifnode->ifname, '%') != NULL)
2327         continue;
2328
2329       if(verbose)
2330         fprintf(stderr, "Probing : Trying to load interface [%s]\n",
2331                 ifnode->ifname);
2332
2333       /* Trick the kernel into loading the interface.
2334        * This allow us to not depend on the exact path and
2335        * name of the '/sbin/modprobe' command.
2336        * Obviously, we expect this command to 'fail', as
2337        * the interface will load with the old/wrong name.
2338        */
2339       strncpy(ifr.ifr_name, ifnode->ifname, IFNAMSIZ);
2340       ioctl(skfd, SIOCGIFHWADDR, &ifr);
2341     }
2342 }
2343
2344 /*------------------------------------------------------------------*/
2345 /*
2346  * Probe interfaces based on Debian's config files.
2347  * This allow to enly load modules for interfaces the user want active,
2348  * all built-in interfaces that should remain unconfigured won't
2349  * be probed (and can have mappings).
2350  */
2351 static void
2352 probe_debian(int                skfd)
2353 {
2354   FILE *                stream;
2355   char *                linebuf = NULL;
2356   size_t                linelen = 0; 
2357   struct ifreq          ifr;
2358
2359   /* Open Debian config file */
2360   stream = fopen(DEBIAN_CONFIG_FILE, "r");
2361   if(stream == NULL)
2362     {
2363       fprintf(stderr, "Error: can't open file [%s]\n", DEBIAN_CONFIG_FILE);
2364       return;
2365     }
2366
2367   /* Read each line of file
2368    * getline is a GNU extension :-( The buffer is recycled and increased
2369    * as needed by getline. */
2370   while(getline(&linebuf, &linelen, stream) > 0)
2371     {
2372       char *                    p;
2373       char *                    e;
2374       size_t                    n;
2375
2376       /* Check for auto keyword, ignore when commented out */
2377       if(!strncasecmp(linebuf, "auto ", 5))
2378         {
2379           /* Skip "auto" keyword */
2380           p = linebuf + 5;
2381
2382           /* Terminate at first comment */
2383           e = strchr(p, '#');
2384           if(e != NULL)
2385             *e = '\0';
2386
2387           /* Loop on all interfaces given */
2388           while(*p != '\0')
2389             {
2390               /* Interface name length */
2391               n = strcspn(p, " \t\n");
2392
2393               /* Look for end of interface name */
2394               e = p + n;
2395               /* Make 'e' point past the '\0' we are going to add */
2396               if(*e != '\0')
2397                 e++;
2398               /* Terminate interface name */
2399               p[n] = '\0';
2400
2401               if(verbose)
2402                 fprintf(stderr, "Probing : Trying to load interface [%s]\n",
2403                         p);
2404
2405               /* Load interface */
2406               strncpy(ifr.ifr_name, p, IFNAMSIZ);
2407               ioctl(skfd, SIOCGIFHWADDR, &ifr);
2408
2409               /* Go to next interface name */
2410               p = e;
2411               p += strspn(p, " \t\n"); 
2412             }
2413         }
2414     }
2415
2416   /* Done */
2417   fclose(stream);
2418   return;
2419 }
2420
2421 /**************************** MAIN LOGIC ****************************/
2422
2423 /*------------------------------------------------------------------*/
2424 /*
2425  * Rename an interface to a specified new name.
2426  */
2427 static int
2428 process_rename(int      skfd,
2429                char *   ifname,
2430                char *   newname)
2431 {
2432   char          retname[IFNAMSIZ+1];
2433   int           len;
2434   char *        star;
2435
2436   len = strlen(newname);
2437   star = strchr(newname, '*');
2438
2439   /* Check newname length, need one extra char for wildcard */
2440   if((len + (star != NULL)) > IFNAMSIZ)
2441     {
2442       fprintf(stderr, "Error: Interface name `%s' too long.\n",
2443               newname);  
2444       return(-1);
2445     }
2446
2447   /* Change the name of the interface */
2448   if(if_set_name(skfd, ifname, newname, retname) < 0)
2449     {
2450       fprintf(stderr, "Error: cannot change name of %s to %s: %s\n",
2451               ifname, newname, strerror(errno)); 
2452       return(-1);
2453     }
2454
2455   /* Always print out the *new* interface name so that
2456    * the calling script can pick it up and know where its interface
2457    * has gone. */
2458   printf("%s\n", retname);
2459
2460   /* Done */
2461   return(0);
2462 }
2463
2464 /*------------------------------------------------------------------*/
2465 /*
2466  * Process a specified interface.
2467  */
2468 static int
2469 process_ifname(int      skfd,
2470                char *   ifname,
2471                char *   args[],
2472                int      count)
2473 {
2474   struct if_mapping *           target;
2475   const struct if_mapping *     mapping;
2476   char                          retname[IFNAMSIZ+1];
2477
2478   /* Avoid "Unused parameter" warning */
2479   args = args; count = count;
2480
2481   /* Get description of this interface */
2482   target = mapping_extract(skfd, ifname);
2483   if(target == NULL)
2484     return(-1);
2485
2486   /* If udev is calling us, get the real devpath. */
2487   if(udev_output)
2488     {
2489       const char *env;
2490       /* It's passed to us as an environment variable */
2491       env = getenv("DEVPATH");
2492       if(env)
2493         {
2494           int   env_len = strlen(env);
2495           target->sysfs_devplen = env_len;
2496           /* Make enough space for new interface name */
2497           target->sysfs_devpath = malloc(env_len + IFNAMSIZ + 1);
2498           if(target->sysfs_devpath != NULL)
2499             memcpy(target->sysfs_devpath, env, env_len + 1);
2500         }
2501       /* We will get a second chance is the user has some sysfs selectors */
2502     }
2503
2504   /* Find matching mapping */
2505   mapping = mapping_find(target);
2506   if(mapping == NULL)
2507     return(-1);
2508
2509   /* If user specified a new name, keep only interfaces that would
2510    * match the new name... */
2511   if((new_name != NULL) && (if_match_ifname(mapping->ifname, new_name) != 0))
2512     return(-1);
2513
2514   /* Check if user want only dry-run.
2515    * Note that, in the case of wildcard, we don't resolve the wildcard.
2516    * That would be tricky to do... */
2517   if(dry_run)
2518     {
2519       strcpy(retname, mapping->ifname);
2520       fprintf(stderr, "Dry-run : Would rename %s to %s.\n",
2521               target->ifname, mapping->ifname);
2522     }
2523   else
2524     {
2525       /* Change the name of the interface */
2526       if(if_set_name(skfd, target->ifname, mapping->ifname, retname) < 0)
2527         {
2528           fprintf(stderr, "Error: cannot change name of %s to %s: %s\n",
2529                   target->ifname, mapping->ifname, strerror(errno)); 
2530           return(-1);
2531         }
2532     }
2533
2534   /* Check if called with an explicit interface name */
2535   if(print_newname)
2536     {
2537       if(!udev_output)
2538         /* Always print out the *new* interface name so that
2539          * the calling script can pick it up and know where its interface
2540          * has gone. */
2541         printf("%s\n", retname);
2542       else
2543         /* udev likes to call us as an IMPORT action. This means that
2544          * we need to return udev the environment variables changed.
2545          * Obviously, we don't want to return anything is nothing changed. */
2546         if(strcmp(target->ifname, retname))
2547           {
2548             char *      pos;
2549             /* Hack */
2550             if(!target->sysfs_devpath)
2551               mapping_getsysfs(skfd, ifname, target, 0);
2552             /* Update devpath. Size is large enough. */
2553             pos = strrchr(target->sysfs_devpath, '/');
2554             if((pos != NULL) && (!strcmp(target->ifname, pos + 1)))
2555               strcpy(pos + 1, retname);
2556             /* Return new environment variables */
2557             printf("DEVPATH=%s\nINTERFACE=%s\nINTERFACE_OLD=%s\n",
2558                    target->sysfs_devpath, retname, target->ifname);
2559           }
2560     }
2561
2562   /* Done */
2563   return(0);
2564 }
2565
2566 /*------------------------------------------------------------------*/
2567 /*
2568  * Process all network interface present on the system.
2569  */
2570 static inline int
2571 process_iflist(int      skfd,
2572                char *   args[],
2573                int      count)
2574 {
2575   num_takeover = 0;
2576
2577   /* Just do it */
2578   iw_enum_devices(skfd, &process_ifname, args, count);
2579
2580   /* If we do any takeover, the interface list grabbed with
2581    * iw_enum_devices() may get out of sync with the real interfaces,
2582    * and we may miss the victim interface. So, let's go through the
2583    * list again.
2584    * On the other hand, we may have ping pong between two interfaces,
2585    * each claiming the same name, so let's not do it forever...
2586    * Two time should be enough for most configs...
2587    * Jean II */
2588   if(force_takeover && num_takeover)
2589     /* Play it again, Sam... */
2590     iw_enum_devices(skfd, &process_ifname, args, count);
2591
2592   /* Done */
2593   return(0);
2594 }
2595
2596 /******************************* MAIN *******************************/
2597
2598
2599 /*------------------------------------------------------------------*/
2600 /*
2601  */
2602 static void
2603 usage(void)
2604 {
2605   fprintf(stderr, "usage: ifrename [-c configurationfile] [-i ifname] [-p] [-t] [-d] [-D]\n");
2606   exit(1); 
2607 }
2608
2609 /*------------------------------------------------------------------*/
2610 /*
2611  * The main !
2612  */
2613 int
2614 main(int        argc,
2615      char *     argv[]) 
2616 {
2617   const char *  conf_file = DEFAULT_CONF;
2618   char *        ifname = NULL;
2619   int           use_probe = 0;
2620   int           is_debian = 0;
2621   int           skfd;
2622   int           ret;
2623
2624   /* Loop over all command line options */
2625   while(1)
2626     {
2627       int c = getopt_long(argc, argv, "c:dDi:n:ptuvV", long_opt, NULL);
2628       if(c == -1)
2629         break;
2630
2631       switch(c)
2632         { 
2633         default:
2634         case '?':
2635           usage(); 
2636         case 'c':
2637           conf_file = optarg;
2638           break;
2639         case 'd':
2640           is_debian = 1;
2641           break;
2642         case 'D':
2643           dry_run = 1;
2644           break;
2645         case 'i':
2646           ifname = optarg;
2647           break;
2648         case 'n':
2649           new_name = optarg;
2650           break;
2651         case 'p':
2652           use_probe = 1;
2653           break;
2654         case 't':
2655           force_takeover = 1;
2656           break;
2657         case 'u':
2658           udev_output = 1;
2659           break;
2660         case 'v':
2661           printf("%-8.16s  Wireless-Tools version %d\n", "ifrename", WT_VERSION);
2662           return(0);
2663         case 'V':
2664           verbose = 1;
2665           break;
2666         }
2667     }
2668
2669   /* Read the specified/default config file, or stdin. */
2670   if(mapping_readfile(conf_file) < 0)
2671     return(-1);
2672
2673   /* Create a channel to the NET kernel. */
2674   if((skfd = iw_sockets_open()) < 0)
2675     {
2676       perror("socket");
2677       return(-1);
2678     }
2679
2680   /* Check if interface name was specified with -i. */
2681   if(ifname != NULL)
2682     {
2683       /* Check is target name specified */
2684       if(new_name != NULL)
2685         {
2686           /* User want to simply rename an interface to a specified name */
2687           ret = process_rename(skfd, ifname, new_name);
2688         }
2689       else
2690         {
2691           /* Rename only this interface based on mappings
2692            * Mostly used for HotPlug processing (from /etc/hotplug/net.agent)
2693            * or udev processing (from a udev IMPORT rule).
2694            * Process the network interface specified on the command line,
2695            * and return the new name on stdout.
2696            */
2697           print_newname = 1;
2698           ret = process_ifname(skfd, ifname, NULL, 0);
2699         }
2700     }
2701   else
2702     {
2703       /* Load all the necesary modules */
2704       if(use_probe)
2705         {
2706           if(is_debian)
2707             probe_debian(skfd);
2708           else
2709             probe_mappings(skfd);
2710         }
2711
2712       /* Rename all system interfaces
2713        * Mostly used for boot time processing (from init scripts).
2714        */
2715       ret = process_iflist(skfd, NULL, 0);
2716     }
2717
2718   /* Cleanup */
2719   iw_sockets_close(skfd);
2720   return(ret);
2721