OSDN Git Service

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