-
Notifications
You must be signed in to change notification settings - Fork 39
/
ifrename.c
2750 lines (2421 loc) · 70.1 KB
/
ifrename.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Wireless Tools
*
* Jean II - HPL 04 -> 07
*
* Main code for "ifrename". This is tool allows to rename network
* interfaces based on various criteria (not only wireless).
* You need to link this code against "iwlib.c" and "-lm".
*
* This file is released under the GPL license.
* Copyright (c) 2007 Jean Tourrilhes <[email protected]>
*/
/*
* The changelog for ifrename is in the file CHANGELOG.h ;-)
*
* This work is a nearly complete rewrite of 'nameif.c'.
* Original CopyRight of version of 'nameif' I used is :
* -------------------------------------------------------
* Name Interfaces based on MAC address.
* Writen 2000 by Andi Kleen.
* Subject to the Gnu Public License, version 2.
* TODO: make it support token ring etc.
* $Id: nameif.c,v 1.3 2003/03/06 23:26:52 ecki Exp $
* -------------------------------------------------------
*
* It started with a series of patches to nameif which never made
* into the regular version, and had some architecural 'issues' with
* those patches, which is the reason of this rewrite.
* Difference with standard 'nameif' :
* o 'nameif' has only a single selector, the interface MAC address.
* o Modular selector architecture, easily add new selectors.
* o Wide range of selector, including sysfs and sysfs symlinks...
* o hotplug invocation support.
* o module loading support.
* o MAC address wildcard.
* o Interface name wildcard ('eth*' or 'wlan*').
* o Non-Ethernet MAC addresses (any size, not just 48 bits)
*/
/***************************** INCLUDES *****************************/
/* This is needed to enable GNU extensions such as getline & FNM_CASEFOLD */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <getopt.h> /* getopt_long() */
#include <linux/sockios.h> /* SIOCSIFNAME */
#include <fnmatch.h> /* fnmatch() */
//#include <sys/syslog.h>
#include "iwlib.h" /* Wireless Tools library */
// This would be cool, unfortunately...
//#include <linux/ethtool.h> /* Ethtool stuff -> struct ethtool_drvinfo */
/************************ CONSTANTS & MACROS ************************/
/* Our default configuration file */
const char DEFAULT_CONF[] = "/etc/iftab";
/* Debian stuff */
const char DEBIAN_CONFIG_FILE[] = "/etc/network/interfaces";
/* Backward compatibility */
#ifndef ifr_newname
#define ifr_newname ifr_ifru.ifru_slave
#endif
/* Types of selector we support. Must match selector_list */
const int SELECT_MAC = 0; /* Select by MAC address */
const int SELECT_ETHADDR = 1; /* Select by MAC address */
const int SELECT_ARP = 2; /* Select by ARP type */
const int SELECT_LINKTYPE = 3; /* Select by ARP type */
const int SELECT_DRIVER = 4; /* Select by Driver name */
const int SELECT_BUSINFO = 5; /* Select by Bus-Info */
const int SELECT_FIRMWARE = 6; /* Select by Firmware revision */
const int SELECT_BASEADDR = 7; /* Select by HW Base Address */
const int SELECT_IRQ = 8; /* Select by HW Irq line */
const int SELECT_INTERRUPT = 9; /* Select by HW Irq line */
const int SELECT_IWPROTO = 10; /* Select by Wireless Protocol */
const int SELECT_PCMCIASLOT = 11; /* Select by Pcmcia Slot */
const int SELECT_SYSFS = 12; /* Select by sysfs file */
const int SELECT_PREVNAME = 13; /* Select by previous interface name */
#define SELECT_NUM 14
#define HAS_MAC_EXACT 1
#define HAS_MAC_FILTER 2
#define MAX_MAC_LEN 16 /* Maximum lenght of MAC address */
const struct ether_addr zero_mac = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
const struct option long_opt[] =
{
{"config-file", 1, NULL, 'c' },
{"debian", 0, NULL, 'd' },
{"dry-run", 0, NULL, 'D' },
{"help", 0, NULL, '?' },
{"interface", 1, NULL, 'i' },
{"newname", 1, NULL, 'n' },
{"takeover", 0, NULL, 't' },
{"udev", 0, NULL, 'u' },
{"version", 0, NULL, 'v' },
{"verbose", 0, NULL, 'V' },
{NULL, 0, NULL, '\0' },
};
/* Pcmcia stab files */
#define PCMCIA_STAB1 "/var/lib/pcmcia/stab"
#define PCMCIA_STAB2 "/var/run/stab"
/* Max number of sysfs file types we support */
#define SYSFS_MAX_FILE 8
/* Userspace headers lag, fix that... */
#ifndef ARPHRD_IEEE1394
#define ARPHRD_IEEE1394 24
#endif
#ifndef ARPHRD_EUI64
#define ARPHRD_EUI64 27
#endif
#ifndef ARPHRD_IRDA
#define ARPHRD_IRDA 783
#endif
/* Length of various non-standard MAC addresses */
const int weird_mac_len[][2] =
{
{ ARPHRD_IEEE1394, 8 },
{ ARPHRD_EUI64, 8 },
{ ARPHRD_IRDA, 4 },
};
const int weird_mac_len_num = sizeof(weird_mac_len) / sizeof(weird_mac_len[0]);
/****************************** TYPES ******************************/
/* Cut'n'paste from ethtool.h */
#define ETHTOOL_BUSINFO_LEN 32
/* these strings are set to whatever the driver author decides... */
struct ethtool_drvinfo {
__u32 cmd;
char driver[32]; /* driver short name, "tulip", "eepro100" */
char version[32]; /* driver version string */
char fw_version[32]; /* firmware version string, if applicable */
char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */
/* For PCI devices, use pci_dev->slot_name. */
char reserved1[32];
char reserved2[16];
__u32 n_stats; /* number of u64's from ETHTOOL_GSTATS */
__u32 testinfo_len;
__u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */
__u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */
};
#define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */
/* Description of an interface mapping */
typedef struct if_mapping
{
/* Linked list */
struct if_mapping * next;
/* Name of this interface */
char ifname[IFNAMSIZ+1];
char * sysfs_devpath;
int sysfs_devplen;
/* Selectors for this interface */
int active[SELECT_NUM]; /* Selectors active */
/* Selector data */
unsigned char mac[MAX_MAC_LEN]; /* Exact MAC address, hex */
int mac_len; /* Length (usually 6) */
char mac_filter[16*3 + 1]; /* WildCard, ascii */
unsigned short hw_type; /* Link/ARP type */
char driver[32]; /* driver short name */
char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */
char fw_version[32]; /* Firmware revision */
unsigned short base_addr; /* HW Base I/O address */
unsigned char irq; /* HW irq line */
char iwproto[IFNAMSIZ + 1]; /* Wireless/protocol name */
int pcmcia_slot; /* Pcmcia slot */
char * sysfs[SYSFS_MAX_FILE]; /* sysfs selectors */
char prevname[IFNAMSIZ+1]; /* previous interface name */
} if_mapping;
/* Extra parsing information when adding a mapping */
typedef struct add_extra
{
char * modif_pos; /* Descriptor modifier */
size_t modif_len;
} parsing_extra;
/* Prototype for adding a selector to a mapping. Return -1 if invalid value. */
typedef int (*mapping_add)(struct if_mapping * ifnode,
int * active,
char * pos,
size_t len,
struct add_extra * extra,
int linenum);
/* Prototype for comparing the selector of two mapping. Return 0 if matches. */
typedef int (*mapping_cmp)(struct if_mapping * ifnode,
struct if_mapping * target);
/* Prototype for extracting selector value from live interface */
typedef int (*mapping_get)(int skfd,
const char * ifname,
struct if_mapping * target,
int flag);
/* How to handle a selector */
typedef struct mapping_selector
{
char * name;
mapping_add add_fn;
mapping_cmp cmp_fn;
mapping_get get_fn;
} mapping_selector;
/* sysfs global data */
typedef struct sysfs_metadata
{
char * root; /* Root of the sysfs */
int rlen; /* Size of it */
int filenum; /* Number of files */
char * filename[SYSFS_MAX_FILE]; /* Name of files */
} sysfs_metadata;
/**************************** PROTOTYPES ****************************/
static int
mapping_addmac(struct if_mapping * ifnode,
int * active,
char * pos,
size_t len,
struct add_extra * extra,
int linenum);
static int
mapping_cmpmac(struct if_mapping * ifnode,
struct if_mapping * target);
static int
mapping_getmac(int skfd,
const char * ifname,
struct if_mapping * target,
int flag);
static int
mapping_addarp(struct if_mapping * ifnode,
int * active,
char * pos,
size_t len,
struct add_extra * extra,
int linenum);
static int
mapping_cmparp(struct if_mapping * ifnode,
struct if_mapping * target);
static int
mapping_getarp(int skfd,
const char * ifname,
struct if_mapping * target,
int flag);
static int
mapping_adddriver(struct if_mapping * ifnode,
int * active,
char * pos,
size_t len,
struct add_extra * extra,
int linenum);
static int
mapping_cmpdriver(struct if_mapping * ifnode,
struct if_mapping * target);
static int
mapping_addbusinfo(struct if_mapping * ifnode,
int * active,
char * pos,
size_t len,
struct add_extra * extra,
int linenum);
static int
mapping_cmpbusinfo(struct if_mapping * ifnode,
struct if_mapping * target);
static int
mapping_addfirmware(struct if_mapping * ifnode,
int * active,
char * pos,
size_t len,
struct add_extra * extra,
int linenum);
static int
mapping_cmpfirmware(struct if_mapping * ifnode,
struct if_mapping * target);
static int
mapping_getdriverbusinfo(int skfd,
const char * ifname,
struct if_mapping * target,
int flag);
static int
mapping_addbaseaddr(struct if_mapping * ifnode,
int * active,
char * pos,
size_t len,
struct add_extra * extra,
int linenum);
static int
mapping_cmpbaseaddr(struct if_mapping * ifnode,
struct if_mapping * target);
static int
mapping_addirq(struct if_mapping * ifnode,
int * active,
char * pos,
size_t len,
struct add_extra * extra,
int linenum);
static int
mapping_cmpirq(struct if_mapping * ifnode,
struct if_mapping * target);
static int
mapping_getbaseaddrirq(int skfd,
const char * ifname,
struct if_mapping * target,
int flag);
static int
mapping_addiwproto(struct if_mapping * ifnode,
int * active,
char * pos,
size_t len,
struct add_extra * extra,
int linenum);
static int
mapping_cmpiwproto(struct if_mapping * ifnode,
struct if_mapping * target);
static int
mapping_getiwproto(int skfd,
const char * ifname,
struct if_mapping * target,
int flag);
static int
mapping_addpcmciaslot(struct if_mapping * ifnode,
int * active,
char * pos,
size_t len,
struct add_extra * extra,
int linenum);
static int
mapping_cmppcmciaslot(struct if_mapping * ifnode,
struct if_mapping * target);
static int
mapping_getpcmciaslot(int skfd,
const char * ifname,
struct if_mapping * target,
int flag);
static int
mapping_addsysfs(struct if_mapping * ifnode,
int * active,
char * pos,
size_t len,
struct add_extra * extra,
int linenum);
static int
mapping_cmpsysfs(struct if_mapping * ifnode,
struct if_mapping * target);
static int
mapping_getsysfs(int skfd,
const char * ifname,
struct if_mapping * target,
int flag);
static int
mapping_addprevname(struct if_mapping * ifnode,
int * active,
char * pos,
size_t len,
struct add_extra * extra,
int linenum);
static int
mapping_cmpprevname(struct if_mapping * ifnode,
struct if_mapping * target);
static int
mapping_getprevname(int skfd,
const char * ifname,
struct if_mapping * target,
int flag);
/**************************** VARIABLES ****************************/
/* List of mapping read for config file */
struct if_mapping * mapping_list = NULL;
/* List of selectors we can handle */
const struct mapping_selector selector_list[] =
{
/* MAC address and ARP/Link type from ifconfig */
{ "mac", &mapping_addmac, &mapping_cmpmac, &mapping_getmac },
{ "ethaddr", &mapping_addmac, &mapping_cmpmac, &mapping_getmac },
{ "arp", &mapping_addarp, &mapping_cmparp, &mapping_getarp },
{ "linktype", &mapping_addarp, &mapping_cmparp, &mapping_getarp },
/* Driver name, Bus-Info and firmware rev from ethtool -i */
{ "driver", &mapping_adddriver, &mapping_cmpdriver,
&mapping_getdriverbusinfo },
{ "businfo", &mapping_addbusinfo, &mapping_cmpbusinfo,
&mapping_getdriverbusinfo },
{ "firmware", &mapping_addfirmware, &mapping_cmpfirmware,
&mapping_getdriverbusinfo },
/* Base Address and IRQ from ifconfig */
{ "baseaddress", &mapping_addbaseaddr, &mapping_cmpbaseaddr,
&mapping_getbaseaddrirq },
{ "irq", &mapping_addirq, &mapping_cmpirq, &mapping_getbaseaddrirq },
{ "interrupt", &mapping_addirq, &mapping_cmpirq, &mapping_getbaseaddrirq },
/* Wireless Protocol from iwconfig */
{ "iwproto", &mapping_addiwproto, &mapping_cmpiwproto, &mapping_getiwproto },
/* Pcmcia slot from cardmgr */
{ "pcmciaslot", &mapping_addpcmciaslot, &mapping_cmppcmciaslot, &mapping_getpcmciaslot },
/* sysfs file (udev emulation) */
{ "sysfs", &mapping_addsysfs, &mapping_cmpsysfs, &mapping_getsysfs },
/* previous interface name */
{ "prevname", &mapping_addprevname, &mapping_cmpprevname, &mapping_getprevname },
/* The Terminator */
{ NULL, NULL, NULL, NULL },
};
const int selector_num = sizeof(selector_list)/sizeof(selector_list[0]);
/* List of active selectors */
int selector_active[SELECT_NUM]; /* Selectors active */
/*
* All the following flags are controlled by the command line switches...
* It's a bit hackish to have them all as global, so maybe we should pass
* them in a big struct as function arguments... More complex and
* probably not worth it ?
*/
/* Invocation type */
int print_newname = 0;
char * new_name = NULL;
/* Takeover support */
int force_takeover = 0; /* Takeover name from other interfaces */
int num_takeover = 0; /* Number of takeover done */
/* Number of mapping matched */
int num_mapping_match = 0;
/* Dry-run support */
int dry_run = 0; /* Just print new name, don't rename */
/* Verbose support (i.e. debugging) */
int verbose = 0;
/* udev output support (print new DEVPATH) */
int udev_output = 0;
/* sysfs global data */
struct sysfs_metadata sysfs_global =
{
NULL, 0,
0, { NULL, NULL, NULL, NULL, NULL },
};
/******************** INTERFACE NAME MANAGEMENT ********************/
/*
* Bunch of low level function for managing interface names.
*/
/*------------------------------------------------------------------*/
/*
* Compare two interface names, with wildcards.
* We can't use fnmatch() because we don't want expansion of '[...]'
* expressions, '\' sequences and matching of '.'.
* We only want to match a single '*' (converted to a %d at that point)
* to a numerical value (no ascii).
* Return 0 is matches.
*/
static int
if_match_ifname(const char * pattern,
const char * value)
{
const char * p;
const char * v;
int n;
int ret;
/* Check for a wildcard */
p = strchr(pattern, '*');
/* No wildcard, simple comparison */
if(p == NULL)
return(strcmp(pattern, value));
/* Check is prefixes match */
n = (p - pattern);
ret = strncmp(pattern, value, n);
if(ret)
return(ret);
/* Check that value has some digits at this point */
v = value + n;
if(!isdigit(*v))
return(-1);
/* Skip digits to go to value suffix */
do
v++;
while(isdigit(*v));
/* Pattern suffix */
p += 1;
/* Compare suffixes */
return(strcmp(p, v));
}
/*------------------------------------------------------------------*/
/*
* Steal interface name from another interface. This enable interface
* name swapping.
* This will work :
* 1) with kernel 2.6.X
* 2) if other interface is down
* Because of (2), it won't work with hotplug, but we don't need it
* with hotplug, only with static ifaces...
*/
static int
if_takeover_name(int skfd,
const char * victimname)
{
char autoname[IFNAMSIZ+1];
int len;
struct ifreq ifr;
int ret;
/* Compute name for victim interface */
len = strlen(victimname);
memcpy(autoname, victimname, len + 1);
if(len > (IFNAMSIZ - 2))
len = IFNAMSIZ - 2; /* Make sure we have at least two char */
len--; /* Convert to index */
while(isdigit(autoname[len]))
len--; /* Scrap all trailing digits */
strcpy(autoname + len + 1, "%d");
if(verbose)
fprintf(stderr, "Takeover : moving interface `%s' to `%s'.\n",
victimname, autoname);
/* Prepare request */
bzero(&ifr, sizeof(struct ifreq));
strncpy(ifr.ifr_name, victimname, IFNAMSIZ);
strncpy(ifr.ifr_newname, autoname, IFNAMSIZ);
/* Rename victim interface */
ret = ioctl(skfd, SIOCSIFNAME, &ifr);
if(!ret)
num_takeover++;
return(ret);
}
/*------------------------------------------------------------------*/
/*
* Ask the kernel to change the name of an interface.
* That's what we want to do. All the rest is to make sure we call this
* appropriately.
*/
static int
if_set_name(int skfd,
const char * oldname,
const char * newname,
char * retname)
{
struct ifreq ifr;
char * star;
int ret;
/* The kernel doesn't check is the interface already has the correct
* name and may return an error, so check ourselves.
* In the case of wildcard, the result can be weird : if oldname='eth0'
* and newname='eth*', retname would be 'eth1'.
* So, if the oldname value matches the newname pattern, just return
* success. */
if(!if_match_ifname(newname, oldname))
{
if(verbose)
fprintf(stderr, "Setting : Interface `%s' already matches `%s'.\n",
oldname, newname);
strcpy(retname, oldname);
return(0);
}
/* Prepare request */
bzero(&ifr, sizeof(struct ifreq));
strncpy(ifr.ifr_name, oldname, IFNAMSIZ);
strncpy(ifr.ifr_newname, newname, IFNAMSIZ);
/* Check for wildcard interface name, such as 'eth*' or 'wlan*'...
* This require specific kernel support (2.6.2-rc1 and later).
* We externally use '*', but the kernel doesn't know about that,
* so convert it to something it knows about... */
star = strchr(newname, '*');
if(star != NULL)
{
int slen = star - newname;
/* Replace '*' with '%d' in the new buffer */
star = ifr.ifr_newname + slen;
/* Size was checked in process_rename() and mapping_create() */
memmove(star + 2, star + 1, IFNAMSIZ - slen - 2);
star[0] = '%';
star[1] = 'd';
}
/* Do it */
ret = ioctl(skfd, SIOCSIFNAME, &ifr);
/* Takeover support : grab interface name from another interface */
if(ret && (errno == EEXIST) && force_takeover)
{
/* Push things around */
ret = if_takeover_name(skfd, newname);
if(!ret)
/* Second try */
ret = ioctl(skfd, SIOCSIFNAME, &ifr);
}
if(!ret)
{
/* Get the real new name (in case newname is a wildcard) */
strcpy(retname, ifr.ifr_newname);
if(verbose)
fprintf(stderr, "Setting : Interface `%s' renamed to `%s'.\n",
oldname, retname);
}
return(ret);
}
/************************ SELECTOR HANDLING ************************/
/*
* Handle the various selector we support
*/
/*------------------------------------------------------------------*/
/*
* Add a MAC address selector to a mapping
*/
static int
mapping_addmac(struct if_mapping * ifnode,
int * active,
char * string,
size_t len,
struct add_extra * extra,
int linenum)
{
size_t n;
/* Avoid "Unused parameter" warning */
extra = extra;
/* Verify validity of string */
if(len >= sizeof(ifnode->mac_filter))
{
fprintf(stderr, "Error : MAC address too long at line %d\n", linenum);
return(-1);
}
n = strspn(string, "0123456789ABCDEFabcdef:*");
if(n < len)
{
fprintf(stderr, "Error: Invalid MAC address `%s' at line %d\n",
string, linenum);
return(-1);
}
/* Copy as filter in all cases */
memcpy(ifnode->mac_filter, string, len + 1);
/* Check the type of MAC address */
if (strchr(ifnode->mac_filter, '*') != NULL)
{
/* This is a wilcard. Usual format : "01:23:45:*"
* Unfortunately, we can't do proper parsing. */
ifnode->active[SELECT_MAC] = HAS_MAC_FILTER;
active[SELECT_MAC] = HAS_MAC_FILTER;
}
else
{
/* Not a wildcard : "01:23:45:67:89:AB" */
ifnode->mac_len = iw_mac_aton(ifnode->mac_filter,
ifnode->mac, MAX_MAC_LEN);
if(ifnode->mac_len == 0)
{
fprintf(stderr, "Error: Invalid MAC address `%s' at line %d\n",
ifnode->mac_filter, linenum);
return(-1);
}
/* Check that it's not NULL */
if((ifnode->mac_len == 6) && (!memcmp(&ifnode->mac, &zero_mac, 6)))
{
fprintf(stderr,
"Warning: MAC address is null at line %d, this is dangerous...\n",
linenum);
}
ifnode->active[SELECT_MAC] = HAS_MAC_EXACT;
if(active[SELECT_MAC] == 0)
active[SELECT_MAC] = HAS_MAC_EXACT;
}
if(verbose)
fprintf(stderr,
"Parsing : Added %s MAC address `%s' from line %d.\n",
ifnode->active[SELECT_MAC] == HAS_MAC_FILTER ? "filter" : "exact",
ifnode->mac_filter, linenum);
return(0);
}
/*------------------------------------------------------------------*/
/*
* Compare the mac address of two mappings
*/
static int
mapping_cmpmac(struct if_mapping * ifnode,
struct if_mapping * target)
{
/* Check for wildcard matching */
if(ifnode->active[SELECT_MAC] == HAS_MAC_FILTER)
/* Do wildcard matching, case insensitive */
return(fnmatch(ifnode->mac_filter, target->mac_filter, FNM_CASEFOLD));
else
/* Exact matching, in hex */
return((ifnode->mac_len != target->mac_len) ||
memcmp(ifnode->mac, target->mac, ifnode->mac_len));
}
/*------------------------------------------------------------------*/
/*
* Extract the MAC address and Link Type of an interface
*/
static int
mapping_getmac(int skfd,
const char * ifname,
struct if_mapping * target,
int flag)
{
struct ifreq ifr;
int ret;
int i;
/* Get MAC address */
bzero(&ifr, sizeof(struct ifreq));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ret = ioctl(skfd, SIOCGIFHWADDR, &ifr);
if(ret < 0)
{
fprintf(stderr, "Error: Can't read MAC address on interface `%s' : %s\n",
ifname, strerror(errno));
return(-1);
}
/* Extract ARP type */
target->hw_type = ifr.ifr_hwaddr.sa_family;
/* Calculate address length */
target->mac_len = 6;
for(i = 0; i < weird_mac_len_num; i++)
if(weird_mac_len[i][0] == ifr.ifr_hwaddr.sa_family)
{
target->mac_len = weird_mac_len[i][1];
break;
}
/* Extract MAC address bytes */
memcpy(target->mac, ifr.ifr_hwaddr.sa_data, target->mac_len);
/* Check the type of comparison */
if((flag == HAS_MAC_FILTER) || verbose)
{
/* Convert to ASCII */
iw_mac_ntop(target->mac, target->mac_len,
target->mac_filter, sizeof(target->mac_filter));
}
target->active[SELECT_MAC] = flag;
target->active[SELECT_ARP] = 1;
if(verbose)
fprintf(stderr,
"Querying %s : Got MAC address `%s' and ARP/Link Type `%d'.\n",
ifname, target->mac_filter, target->hw_type);
return(0);
}
/*------------------------------------------------------------------*/
/*
* Add a ARP/Link type selector to a mapping
*/
static int
mapping_addarp(struct if_mapping * ifnode,
int * active,
char * string,
size_t len,
struct add_extra * extra,
int linenum)
{
size_t n;
unsigned int type;
/* Avoid "Unused parameter" warning */
extra = extra;
/* Verify validity of string, convert to int */
n = strspn(string, "0123456789");
if((n < len) || (sscanf(string, "%d", &type) != 1))
{
fprintf(stderr, "Error: Invalid ARP/Link Type `%s' at line %d\n",
string, linenum);
return(-1);
}
ifnode->hw_type = (unsigned short) type;
ifnode->active[SELECT_ARP] = 1;
active[SELECT_ARP] = 1;
if(verbose)
fprintf(stderr, "Parsing : Added ARP/Link Type `%d' from line %d.\n",
ifnode->hw_type, linenum);
return(0);
}
/*------------------------------------------------------------------*/
/*
* Compare the ARP/Link type of two mappings
*/
static int
mapping_cmparp(struct if_mapping * ifnode,
struct if_mapping * target)
{
return(!(ifnode->hw_type == target->hw_type));
}
/*------------------------------------------------------------------*/
/*
* Extract the ARP/Link type of an interface
*/
static int
mapping_getarp(int skfd,
const char * ifname,
struct if_mapping * target,
int flag)
{
/* We may have already extracted the MAC address */
if(target->active[SELECT_MAC])
return(0);
/* Otherwise just do it */
return(mapping_getmac(skfd, ifname, target, flag));
}
/*------------------------------------------------------------------*/
/*
* Add a Driver name selector to a mapping
*/
static int
mapping_adddriver(struct if_mapping * ifnode,
int * active,
char * string,
size_t len,
struct add_extra * extra,
int linenum)
{
/* Avoid "Unused parameter" warning */
extra = extra;
/* Plain string, minimal verification */
if(len >= sizeof(ifnode->driver))
{
fprintf(stderr, "Error: Driver name too long at line %d\n", linenum);
return(-1);
}
/* Copy */
memcpy(ifnode->driver, string, len + 1);
/* Activate */
ifnode->active[SELECT_DRIVER] = 1;
active[SELECT_DRIVER] = 1;
if(verbose)
fprintf(stderr,
"Parsing : Added Driver name `%s' from line %d.\n",
ifnode->driver, linenum);
return(0);
}
/*------------------------------------------------------------------*/
/*
* Compare the Driver name of two mappings
*/
static int
mapping_cmpdriver(struct if_mapping * ifnode,
struct if_mapping * target)
{
/* Do wildcard matching, case insensitive */
return(fnmatch(ifnode->driver, target->driver, FNM_CASEFOLD));
}
/*------------------------------------------------------------------*/
/*
* Add a Bus-Info selector to a mapping
*/
static int
mapping_addbusinfo(struct if_mapping * ifnode,
int * active,
char * string,
size_t len,
struct add_extra * extra,
int linenum)
{
#if 0
size_t n;
#endif
/* Avoid "Unused parameter" warning */
extra = extra;
/* Verify validity of string */
if(len >= sizeof(ifnode->bus_info))
{
fprintf(stderr, "Bus Info too long at line %d\n", linenum);
return(-1);
}
#if 0
/* Hum... This doesn's seem true for non-PCI bus-info */
n = strspn(string, "0123456789ABCDEFabcdef:.*");
if(n < len)
{
fprintf(stderr, "Error: Invalid Bus Info `%s' at line %d\n",
string, linenum);
return(-1);
}
#endif
/* Copy */
memcpy(ifnode->bus_info, string, len + 1);
/* Activate */
ifnode->active[SELECT_BUSINFO] = 1;
active[SELECT_BUSINFO] = 1;
if(verbose)
fprintf(stderr,
"Parsing : Added Bus Info `%s' from line %d.\n",
ifnode->bus_info, linenum);
return(0);
}
/*------------------------------------------------------------------*/
/*
* Compare the Bus-Info of two mappings
*/
static int
mapping_cmpbusinfo(struct if_mapping * ifnode,
struct if_mapping * target)
{
/* Do wildcard matching, case insensitive */
return(fnmatch(ifnode->bus_info, target->bus_info, FNM_CASEFOLD));
}
/*------------------------------------------------------------------*/
/*
* Add a Firmare revision selector to a mapping
*/
static int
mapping_addfirmware(struct if_mapping * ifnode,
int * active,
char * string,
size_t len,
struct add_extra * extra,
int linenum)
{
/* Avoid "Unused parameter" warning */
extra = extra;
/* Verify validity of string */
if(len >= sizeof(ifnode->fw_version))
{
fprintf(stderr, "Firmware revision too long at line %d\n", linenum);
return(-1);
}
/* Copy */
memcpy(ifnode->fw_version, string, len + 1);
/* Activate */
ifnode->active[SELECT_FIRMWARE] = 1;
active[SELECT_FIRMWARE] = 1;
if(verbose)