10
#include <sys/ioctl.h>
11
#include <sys/socket.h>
18
#include <linux/sockios.h>
19
#include <linux/ethtool.h>
20
#include <linux/if_arp.h>
27
* @defgroup NETint Network devices
28
* @ingroup libhdDEVint
29
* @brief Network device scan functions
31
* Gather network interface info
36
static void get_driverinfo(hd_data_t *hd_data, hd_t *hd);
37
static void get_linkstate(hd_data_t *hd_data, hd_t *hd);
38
static void add_xpnet(hd_data_t *hdata);
39
static void add_mv(hd_data_t *hdata);
40
static void add_iseries(hd_data_t *hdata);
41
static void add_uml(hd_data_t *hdata);
42
static void add_kma(hd_data_t *hdata);
43
static void add_xen(hd_data_t *hdata);
44
static void add_if_name(hd_t *hd_card, hd_t *hd);
47
* This is independent of the other scans.
50
void hd_scan_net(hd_data_t *hd_data)
58
str_list_t *sf_class, *sf_class_e;
59
char *sf_cdev = NULL, *sf_dev = NULL;
60
char *sf_drv_name, *sf_drv;
62
if(!hd_probe_feature(hd_data, pr_net)) return;
64
hd_data->module = mod_net;
67
remove_hd_entries(hd_data);
68
hd_data->net = free_str_list(hd_data->net);
70
PROGRESS(1, 0, "get network data");
72
sf_class = reverse_str_list(read_dir("/sys/class/net", 'd'));
75
ADD2LOG("sysfs: no such class: net\n");
79
for(sf_class_e = sf_class; sf_class_e; sf_class_e = sf_class_e->next) {
80
str_printf(&sf_cdev, 0, "/sys/class/net/%s", sf_class_e->str);
85
" net interface: name = %s, path = %s\n",
91
if(hd_attr_uint(get_sysfs_attr_by_path(sf_cdev, "type"), &ul0, 0)) {
93
ADD2LOG(" type = %d\n", if_type);
97
if((s = get_sysfs_attr_by_path(sf_cdev, "address"))) {
98
hw_addr = canon_str(s, strlen(s));
99
ADD2LOG(" hw_addr = %s\n", hw_addr);
102
sf_dev = new_str(hd_read_sysfs_link(sf_cdev, "device"));
104
ADD2LOG(" net device: path = %s\n", hd_sysfs_id(sf_dev));
108
sf_drv = hd_read_sysfs_link(sf_dev, "driver");
110
sf_drv_name = strrchr(sf_drv, '/');
111
if(sf_drv_name) sf_drv_name++;
113
" net driver: name = %s, path = %s\n",
119
hd = add_hd_entry(hd_data, __LINE__, 0);
120
hd->base_class.id = bc_network_interface;
121
hd->sub_class.id = sc_nif_other;
124
if(hw_addr && strspn(hw_addr, "0:") != strlen(hw_addr)) {
125
res1 = new_mem(sizeof *res1);
126
res1->hwaddr.type = res_hwaddr;
127
res1->hwaddr.addr = new_str(hw_addr);
128
add_res_entry(&hd->res, res1);
131
hw_addr = free_mem(hw_addr);
133
hd->unix_dev_name = new_str(sf_class_e->str);
134
hd->sysfs_id = new_str(hd_sysfs_id(sf_cdev));
137
add_str_list(&hd->drivers, sf_drv_name);
140
get_driverinfo(hd_data, hd);
144
hd->sysfs_device_link = new_str(hd_sysfs_id(sf_dev));
146
hd_card = hd_find_sysfs_id(hd_data, hd_sysfs_id(sf_dev));
148
hd->attached_to = hd_card->idx;
150
/* for cards with strange pci classes */
151
hd_set_hw_class(hd_card, hw_network_ctrl);
153
/* add hw addr to network card */
156
for(res = hd_card->res; res; res = res->next) {
158
res->any.type == res_hwaddr &&
159
!strcmp(res->hwaddr.addr, res1->hwaddr.addr)
166
res = new_mem(sizeof *res);
167
res->hwaddr.type = res_hwaddr;
168
res->hwaddr.addr = new_str(res1->hwaddr.addr);
169
add_res_entry(&hd_card->res, res);
172
/* add interface names */
173
add_if_name(hd_card, hd);
183
"myri" sc_nif_myrinet
190
case ARPHRD_ETHER: /* eth */
191
hd->sub_class.id = sc_nif_ethernet;
193
case ARPHRD_LOOPBACK: /* lo */
194
hd->sub_class.id = sc_nif_loopback;
196
case ARPHRD_SIT: /* sit */
197
hd->sub_class.id = sc_nif_sit;
199
case ARPHRD_FDDI: /* fddi */
200
hd->sub_class.id = sc_nif_fddi;
202
case ARPHRD_IEEE802_TR: /* tr */
203
hd->sub_class.id = sc_nif_tokenring;
206
case ARPHRD_IEEE802: /* fc */
207
hd->sub_class.id = sc_nif_fc;
212
if(!strcmp(hd->unix_dev_name, "lo")) {
213
hd->sub_class.id = sc_nif_loopback;
215
else if(sscanf(hd->unix_dev_name, "eth%u", &u) == 1) {
216
hd->sub_class.id = sc_nif_ethernet;
219
else if(sscanf(hd->unix_dev_name, "tr%u", &u) == 1) {
220
hd->sub_class.id = sc_nif_tokenring;
223
else if(sscanf(hd->unix_dev_name, "fddi%u", &u) == 1) {
224
hd->sub_class.id = sc_nif_fddi;
227
else if(sscanf(hd->unix_dev_name, "ctc%u", &u) == 1) {
228
hd->sub_class.id = sc_nif_ctc;
231
else if(sscanf(hd->unix_dev_name, "iucv%u", &u) == 1) {
232
hd->sub_class.id = sc_nif_iucv;
235
else if(sscanf(hd->unix_dev_name, "hsi%u", &u) == 1) {
236
hd->sub_class.id = sc_nif_hsi;
239
else if(sscanf(hd->unix_dev_name, "qeth%u", &u) == 1) {
240
hd->sub_class.id = sc_nif_qeth;
243
else if(sscanf(hd->unix_dev_name, "escon%u", &u) == 1) {
244
hd->sub_class.id = sc_nif_escon;
247
else if(sscanf(hd->unix_dev_name, "myri%u", &u) == 1) {
248
hd->sub_class.id = sc_nif_myrinet;
251
else if(sscanf(hd->unix_dev_name, "sit%u", &u) == 1) {
252
hd->sub_class.id = sc_nif_sit; /* ipv6 over ipv4 tunnel */
255
else if(sscanf(hd->unix_dev_name, "wlan%u", &u) == 1) {
256
hd->sub_class.id = sc_nif_wlan;
259
else if(sscanf(hd->unix_dev_name, "xp%u", &u) == 1) {
260
hd->sub_class.id = sc_nif_xp;
263
else if(sscanf(hd->unix_dev_name, "usb%u", &u) == 1) {
264
hd->sub_class.id = sc_nif_usb;
267
/* ##### add more interface names here */
269
hd->bus.id = bus_none;
274
(hd_card->base_class.id == 0 && hd_card->sub_class.id == 0) ||
275
(hd_card->base_class.id == bc_network && hd_card->sub_class.id == 0x80)
277
switch(hd->sub_class.id) {
278
case sc_nif_ethernet:
279
hd_card->base_class.id = bc_network;
280
hd_card->sub_class.id = 0;
284
hd_card->base_class.id = bc_network;
285
hd_card->sub_class.id = 0x91;
291
sf_dev = free_mem(sf_dev);
294
sf_cdev = free_mem(sf_cdev);
295
sf_class = free_str_list(sf_class);
297
if(hd_is_sgi_altix(hd_data)) add_xpnet(hd_data);
298
if(hd_is_iseries(hd_data)) add_iseries(hd_data);
304
/* add link status info */
305
for(hd = hd_data->hd ; hd; hd = hd->next) {
307
hd->module == hd_data->module &&
308
hd->base_class.id == bc_network_interface
310
get_linkstate(hd_data, hd);
312
if(!(hd_card = hd_get_device_by_idx(hd_data, hd->attached_to))) continue;
314
for(res = hd->res; res; res = res->next) {
315
if(res->any.type == res_link) break;
319
for(res1 = hd_card->res; res1; res1 = res1->next) {
320
if(res1->any.type == res_link) break;
323
res1 = new_mem(sizeof *res1);
324
res1->link.type = res_link;
325
res1->link.state = res->link.state;
326
add_res_entry(&hd_card->res, res1);
335
* Get it the classical way, for drivers that don't support sysfs (veth).
337
void get_driverinfo(hd_data_t *hd_data, hd_t *hd)
340
struct ethtool_drvinfo drvinfo = { cmd:ETHTOOL_GDRVINFO };
343
if(!hd->unix_dev_name) return;
345
if(strlen(hd->unix_dev_name) > sizeof ifr.ifr_name - 1) return;
347
if((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) return;
349
/* get driver info */
350
memset(&ifr, 0, sizeof ifr);
351
strcpy(ifr.ifr_name, hd->unix_dev_name);
352
ifr.ifr_data = (caddr_t) &drvinfo;
353
if(ioctl(fd, SIOCETHTOOL, &ifr) == 0) {
354
ADD2LOG(" ethtool driver: %s\n", drvinfo.driver);
355
ADD2LOG(" ethtool bus: %s\n", drvinfo.bus_info);
357
add_str_list(&hd->drivers, drvinfo.driver);
360
ADD2LOG(" GDRVINFO ethtool error: %s\n", strerror(errno));
368
* Check network link status.
370
void get_linkstate(hd_data_t *hd_data, hd_t *hd)
373
struct ethtool_value linkstatus = { cmd:ETHTOOL_GLINK };
377
if(!hd->unix_dev_name) return;
379
if(strlen(hd->unix_dev_name) > sizeof ifr.ifr_name - 1) return;
381
if((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) return;
383
/* get driver info */
384
memset(&ifr, 0, sizeof ifr);
385
strcpy(ifr.ifr_name, hd->unix_dev_name);
386
ifr.ifr_data = (caddr_t) &linkstatus;
387
if(ioctl(fd, SIOCETHTOOL, &ifr) == 0) {
388
ADD2LOG(" %s: ethtool link state: %d\n", hd->unix_dev_name, linkstatus.data);
389
res = new_mem(sizeof *res);
390
res->link.type = res_link;
391
res->link.state = linkstatus.data ? 1 : 0;
392
add_res_entry(&hd->res, res);
395
ADD2LOG(" %s: GLINK ethtool error: %s\n", hd->unix_dev_name, strerror(errno));
403
* SGI Altix cross partition network.
405
void add_xpnet(hd_data_t *hd_data)
408
hd_res_t *res, *res2;
410
hd_card = add_hd_entry(hd_data, __LINE__, 0);
411
hd_card->base_class.id = bc_network;
412
hd_card->sub_class.id = 0x83;
414
hd_card->vendor.id = MAKE_ID(TAG_SPECIAL, 0x4002);
415
hd_card->device.id = MAKE_ID(TAG_SPECIAL, 1);
417
if(hd_module_is_active(hd_data, "xpnet")) {
418
add_str_list(&hd_card->drivers, "xpnet");
421
for(hd = hd_data->hd ; hd; hd = hd->next) {
423
hd->module == hd_data->module &&
424
hd->base_class.id == bc_network_interface &&
425
hd->sub_class.id == sc_nif_xp
427
hd->attached_to = hd_card->idx;
429
for(res = hd->res; res; res = res->next) {
430
if(res->any.type == res_hwaddr) break;
434
res2 = new_mem(sizeof *res2);
435
res2->hwaddr.type = res_hwaddr;
436
res2->hwaddr.addr = new_str(res->hwaddr.addr);
437
add_res_entry(&hd_card->res, res2);
440
add_if_name(hd_card, hd);
449
* Marvell Gigabit Ethernet thing
451
void add_mv(hd_data_t *hd_data)
454
hd_res_t *res, *res2;
456
char *s, *sf_dev, *sf_dev_name, *module;
459
* Actually there are two (.0 & .1), but only one seems to be used - so we
462
sf_dev = "/sys/devices/platform/mv643xx_eth.0";
463
sf_dev_name = "mv643xx_eth.0";
464
module = "mv643xx_eth";
466
if(stat(sf_dev, &sbuf) || !S_ISDIR(sbuf.st_mode)) return;
468
for(hd = hd_data->hd ; hd; hd = hd->next) {
470
hd->vendor.id == MAKE_ID(TAG_PCI, 0x11ab) &&
471
hd->device.id == MAKE_ID(TAG_PCI, 0x6460)
475
hd_card = add_hd_entry(hd_data, __LINE__, 0);
476
hd_card->base_class.id = bc_network;
477
hd_card->sub_class.id = 0;
479
hd_card->sysfs_id = new_str(hd_sysfs_id(sf_dev));
480
hd_card->sysfs_bus_id = new_str(sf_dev_name);
482
if((s = get_sysfs_attr_by_path(sf_dev, "modalias"))) {
483
hd_card->modalias = canon_str(s, strlen(s));
484
ADD2LOG(" modalias = \"%s\"\n", hd_card->modalias);
487
hd_card->modalias = new_str(module);
491
hd_card->attached_to = hd->idx;
492
hd_card->vendor.id = hd->vendor.id;
493
hd_card->device.id = hd->device.id;
496
hd_card->vendor.name = new_str("Marvell");
497
hd_card->device.name = new_str("Gigabit Ethernet");
500
if(hd_module_is_active(hd_data, module)) {
501
add_str_list(&hd_card->drivers, module);
504
for(hd = hd_data->hd ; hd; hd = hd->next) {
506
hd->module == hd_data->module &&
507
hd->base_class.id == bc_network_interface &&
508
hd->sub_class.id == sc_nif_ethernet &&
509
search_str_list(hd->drivers, "mv643xx_eth")
511
hd->attached_to = hd_card->idx;
513
for(res = hd->res; res; res = res->next) {
514
if(res->any.type == res_hwaddr) break;
518
res2 = new_mem(sizeof *res2);
519
res2->hwaddr.type = res_hwaddr;
520
res2->hwaddr.addr = new_str(res->hwaddr.addr);
521
add_res_entry(&hd_card->res, res2);
524
add_if_name(hd_card, hd);
533
* iSeries veth devices.
535
void add_iseries(hd_data_t *hd_data)
538
hd_res_t *res, *res2;
539
unsigned i, cardmask = 0, card_cnt = 0;
540
str_list_t *sl0, *sl;
542
for(hd = hd_data->hd ; hd; hd = hd->next) {
544
hd->module == hd_data->module &&
545
hd->base_class.id == bc_network_interface &&
547
search_str_list(hd->drivers, "veth") ||
548
search_str_list(hd->drivers, "iseries_veth")
551
hd_card = add_hd_entry(hd_data, __LINE__, 0);
552
hd_card->base_class.id = bc_network;
553
hd_card->sub_class.id = 0x00;
554
hd_card->vendor.id = MAKE_ID(TAG_SPECIAL, 0x6001); // IBM
555
hd_card->device.id = MAKE_ID(TAG_SPECIAL, 0x1000);
556
add_str_list(&hd_card->drivers, "iseries_veth");
557
hd_card->slot = card_cnt++;
558
str_printf(&hd_card->device.name, 0, "Virtual Ethernet card");
559
hd->attached_to = hd_card->idx;
561
for(res = hd->res; res; res = res->next) {
562
if(res->any.type == res_hwaddr) break;
568
res2 = new_mem(sizeof *res2);
569
res2->hwaddr.type = res_hwaddr;
570
res2->hwaddr.addr = new_str(res->hwaddr.addr);
571
add_res_entry(&hd_card->res, res2);
572
if (sscanf(res->hwaddr.addr, "02:01:ff:%x:ff:", &slotno)) {
573
hd_card->slot = slotno;
574
str_printf(&hd_card->device.name, 0, "Virtual Ethernet card %d", hd_card->slot);
578
add_if_name(hd_card, hd);
583
sl0 = read_file("/proc/iSeries/config", 0, 0);
584
for(sl = sl0; sl; sl = sl->next) {
585
if(sscanf(sl->str, "AVAILABLE_VETH=%x", &cardmask) == 1)
590
for (i = 0; i < 16; i++) {
591
if ((0x8000 >> i) & cardmask) {
592
hd_card = add_hd_entry(hd_data, __LINE__, 0);
593
hd_card->base_class.id = bc_network;
594
hd_card->sub_class.id = 0x00;
595
hd_card->vendor.id = MAKE_ID(TAG_SPECIAL, 0x6001); // IBM
596
hd_card->device.id = MAKE_ID(TAG_SPECIAL, 0x1000);
598
str_printf(&hd_card->device.name, 0, "Virtual Ethernet card %d", i);
608
void add_uml(hd_data_t *hd_data)
611
hd_res_t *res, *res2;
612
unsigned card_cnt = 0;
614
for(hd = hd_data->hd ; hd; hd = hd->next) {
616
hd->module == hd_data->module &&
617
hd->base_class.id == bc_network_interface &&
618
search_str_list(hd->drivers, "uml virtual ethernet")
620
hd_card = add_hd_entry(hd_data, __LINE__, 0);
621
hd_card->base_class.id = bc_network;
622
hd_card->sub_class.id = 0x00;
623
hd_card->vendor.id = MAKE_ID(TAG_SPECIAL, 0x6010); // UML
624
hd_card->device.id = MAKE_ID(TAG_SPECIAL, 0x0001);
625
hd_card->slot = card_cnt++;
626
str_printf(&hd_card->device.name, 0, "Virtual Ethernet card %d", hd_card->slot);
628
hd->attached_to = hd_card->idx;
630
for(res = hd->res; res; res = res->next) {
631
if(res->any.type == res_hwaddr) break;
635
res2 = new_mem(sizeof *res2);
636
res2->hwaddr.type = res_hwaddr;
637
res2->hwaddr.addr = new_str(res->hwaddr.addr);
638
add_res_entry(&hd_card->res, res2);
641
add_if_name(hd_card, hd);
650
void add_kma(hd_data_t *hd_data)
653
hd_res_t *res, *res2;
654
unsigned card_cnt = 0;
656
for(hd = hd_data->hd ; hd; hd = hd->next) {
658
hd->module == hd_data->module &&
659
hd->base_class.id == bc_network_interface &&
660
search_str_list(hd->drivers, "kveth2")
662
hd_card = add_hd_entry(hd_data, __LINE__, 0);
663
hd_card->base_class.id = bc_network;
664
hd_card->sub_class.id = 0x00;
665
hd_card->vendor.id = MAKE_ID(TAG_SPECIAL, 0x6012); // VirtualIron
666
hd_card->device.id = MAKE_ID(TAG_SPECIAL, 0x0001);
667
hd_card->slot = card_cnt++;
668
str_printf(&hd_card->device.name, 0, "Ethernet card %d", hd_card->slot);
670
hd->attached_to = hd_card->idx;
672
for(res = hd->res; res; res = res->next) {
673
if(res->any.type == res_hwaddr) break;
677
res2 = new_mem(sizeof *res2);
678
res2->hwaddr.type = res_hwaddr;
679
res2->hwaddr.addr = new_str(res->hwaddr.addr);
680
add_res_entry(&hd_card->res, res2);
683
add_if_name(hd_card, hd);
692
void add_xen(hd_data_t *hd_data)
695
hd_res_t *res, *res2;
696
unsigned card_cnt = 0;
700
for(hd = hd_data->hd ; hd; hd = hd->next) {
702
hd->module == hd_data->module &&
703
hd->base_class.id == bc_network_interface
705
str_printf(&s, 0, "/proc/xen/net/%s", hd->unix_dev_name);
706
if(stat(s, &sbuf) || !S_ISDIR(sbuf.st_mode)) continue;
708
hd_card = add_hd_entry(hd_data, __LINE__, 0);
709
hd_card->base_class.id = bc_network;
710
hd_card->sub_class.id = 0x00;
711
hd_card->vendor.id = MAKE_ID(TAG_SPECIAL, 0x6011); // Xen
712
hd_card->device.id = MAKE_ID(TAG_SPECIAL, 0x0001);
713
hd_card->slot = card_cnt++;
714
str_printf(&hd_card->device.name, 0, "Virtual Ethernet card %d", hd_card->slot);
716
hd->attached_to = hd_card->idx;
718
for(res = hd->res; res; res = res->next) {
719
if(res->any.type == res_hwaddr) break;
723
res2 = new_mem(sizeof *res2);
724
res2->hwaddr.type = res_hwaddr;
725
res2->hwaddr.addr = new_str(res->hwaddr.addr);
726
add_res_entry(&hd_card->res, res2);
729
add_if_name(hd_card, hd);
738
* add interface name to card
740
void add_if_name(hd_t *hd_card, hd_t *hd)
742
if(hd->unix_dev_name) {
743
if(!search_str_list(hd_card->unix_dev_names, hd->unix_dev_name)) {
744
add_str_list(&hd_card->unix_dev_names, hd->unix_dev_name);
746
if(!hd_card->unix_dev_name) {
747
hd_card->unix_dev_name = new_str(hd->unix_dev_name);