nexmon – Blame information for rev 1
?pathlinks?
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 | } |