nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 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 }