]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/hwinfo/src/hd/net.c
Kleiner netter neuer Versuch.
[people/pmueller/ipfire-2.x.git] / src / hwinfo / src / hd / net.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <inttypes.h>
7 #include <errno.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <sys/ioctl.h>
11 #include <sys/socket.h>
12
13 #define u8 uint8_t
14 #define u16 uint16_t
15 #define u32 uint32_t
16 #define u64 uint64_t
17 #include <linux/if.h>
18 #include <linux/sockios.h>
19 #include <linux/ethtool.h>
20 #include <linux/if_arp.h>
21
22 #include "hd.h"
23 #include "hd_int.h"
24 #include "net.h"
25
26 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
27 * gather network interface info
28 *
29 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
30 */
31
32 static void get_driverinfo(hd_data_t *hd_data, hd_t *hd);
33 static void get_linkstate(hd_data_t *hd_data, hd_t *hd);
34 static void add_xpnet(hd_data_t *hdata);
35 static void add_iseries(hd_data_t *hdata);
36 static void add_uml(hd_data_t *hdata);
37
38 /*
39 * This is independent of the other scans.
40 */
41
42 void hd_scan_net(hd_data_t *hd_data)
43 {
44 unsigned u;
45 int if_type;
46 hd_t *hd, *hd_card;
47 char *s, *hw_addr;
48 hd_res_t *res, *res1;
49 uint64_t ul0;
50
51 struct sysfs_class *sf_class;
52 struct sysfs_class_device *sf_cdev;
53 struct sysfs_device *sf_dev;
54 struct sysfs_driver *sf_drv;
55 struct dlist *sf_cdev_list;
56
57 if(!hd_probe_feature(hd_data, pr_net)) return;
58
59 hd_data->module = mod_net;
60
61 /* some clean-up */
62 remove_hd_entries(hd_data);
63 hd_data->net = free_str_list(hd_data->net);
64
65 PROGRESS(1, 0, "get network data");
66
67 sf_class = sysfs_open_class("net");
68
69 if(!sf_class) {
70 ADD2LOG("sysfs: no such class: net\n");
71 return;
72 }
73
74 sf_cdev_list = sysfs_get_class_devices(sf_class);
75 if(sf_cdev_list) dlist_for_each_data(sf_cdev_list, sf_cdev, struct sysfs_class_device) {
76 hd_card = NULL;
77
78 ADD2LOG(
79 " net interface: name = %s, classname = %s, path = %s\n",
80 sf_cdev->name,
81 sf_cdev->classname,
82 hd_sysfs_id(sf_cdev->path)
83 );
84
85 if_type = -1;
86 if(hd_attr_uint(sysfs_get_classdev_attr(sf_cdev, "type"), &ul0, 0)) {
87 if_type = ul0;
88 ADD2LOG(" type = %d\n", if_type);
89 }
90
91 hw_addr = NULL;
92 if((s = hd_attr_str(sysfs_get_classdev_attr(sf_cdev, "address")))) {
93 hw_addr = canon_str(s, strlen(s));
94 ADD2LOG(" hw_addr = %s\n", hw_addr);
95 }
96
97 sf_dev = sysfs_get_classdev_device(sf_cdev);
98 if(sf_dev) {
99 ADD2LOG(" net device: path = %s\n", hd_sysfs_id(sf_dev->path));
100 }
101
102 sf_drv = sysfs_get_classdev_driver(sf_cdev);
103 if(sf_drv) {
104 ADD2LOG(
105 " net driver: name = %s, path = %s\n",
106 sf_drv->name,
107 hd_sysfs_id(sf_drv->path)
108 );
109 }
110
111 hd = add_hd_entry(hd_data, __LINE__, 0);
112 hd->base_class.id = bc_network_interface;
113 hd->sub_class.id = sc_nif_other;
114
115 res1 = NULL;
116 if(hw_addr && strspn(hw_addr, "0:") != strlen(hw_addr)) {
117 res1 = new_mem(sizeof *res1);
118 res1->hwaddr.type = res_hwaddr;
119 res1->hwaddr.addr = new_str(hw_addr);
120 add_res_entry(&hd->res, res1);
121 }
122
123 hw_addr = free_mem(hw_addr);
124
125 hd->unix_dev_name = new_str(sf_cdev->name);
126 hd->sysfs_id = new_str(hd_sysfs_id(sf_cdev->path));
127
128 if(sf_drv) {
129 add_str_list(&hd->drivers, sf_drv->name);
130 }
131 else if(hd->res) {
132 get_driverinfo(hd_data, hd);
133 }
134
135 if(sf_dev) {
136 hd->sysfs_device_link = new_str(hd_sysfs_id(sf_dev->path));
137
138 hd_card = hd_find_sysfs_id(hd_data, hd_sysfs_id(sf_dev->path));
139 if(hd_card) {
140 hd->attached_to = hd_card->idx;
141
142 /* for cards with strange pci classes */
143 hd_set_hw_class(hd_card, hw_network_ctrl);
144
145 /* add hw addr to network card */
146 if(res1) {
147 u = 0;
148 for(res = hd_card->res; res; res = res->next) {
149 if(
150 res->any.type == res_hwaddr &&
151 !strcmp(res->hwaddr.addr, res1->hwaddr.addr)
152 ) {
153 u = 1;
154 break;
155 }
156 }
157 if(!u) {
158 res = new_mem(sizeof *res);
159 res->hwaddr.type = res_hwaddr;
160 res->hwaddr.addr = new_str(res1->hwaddr.addr);
161 add_res_entry(&hd_card->res, res);
162 }
163 }
164 /* add interface names */
165 if(hd->unix_dev_name) {
166 if(!search_str_list(hd_card->unix_dev_names, hd->unix_dev_name)) {
167 add_str_list(&hd_card->unix_dev_names, hd->unix_dev_name);
168 }
169 if(!hd_card->unix_dev_name) {
170 hd_card->unix_dev_name = new_str(hd->unix_dev_name);
171 }
172 }
173 }
174 }
175
176 #if 0
177 "ctc" sc_nif_ctc
178 "iucv" sc_nif_iucv
179 "hsi" sc_nif_hsi
180 "qeth" sc_nif_qeth
181 "escon" sc_nif_escon
182 "myri" sc_nif_myrinet
183 "wlan" sc_nif_wlan
184 "xp" sc_nif_xp
185 "usb" sc_nif_usb
186 #endif
187 switch(if_type) {
188 case ARPHRD_ETHER: /* eth */
189 hd->sub_class.id = sc_nif_ethernet;
190 break;
191 case ARPHRD_LOOPBACK: /* lo */
192 hd->sub_class.id = sc_nif_loopback;
193 break;
194 case ARPHRD_SIT: /* sit */
195 hd->sub_class.id = sc_nif_sit;
196 break;
197 case ARPHRD_FDDI: /* fddi */
198 hd->sub_class.id = sc_nif_fddi;
199 break;
200 case ARPHRD_IEEE802_TR: /* tr */
201 hd->sub_class.id = sc_nif_tokenring;
202 break;
203 #if 0
204 case ARPHRD_IEEE802: /* fc */
205 hd->sub_class.id = sc_nif_fc;
206 break;
207 #endif
208 }
209
210 if(!strcmp(hd->unix_dev_name, "lo")) {
211 hd->sub_class.id = sc_nif_loopback;
212 }
213 else if(sscanf(hd->unix_dev_name, "eth%u", &u) == 1) {
214 hd->sub_class.id = sc_nif_ethernet;
215 hd->slot = u;
216 }
217 else if(sscanf(hd->unix_dev_name, "tr%u", &u) == 1) {
218 hd->sub_class.id = sc_nif_tokenring;
219 hd->slot = u;
220 }
221 else if(sscanf(hd->unix_dev_name, "fddi%u", &u) == 1) {
222 hd->sub_class.id = sc_nif_fddi;
223 hd->slot = u;
224 }
225 else if(sscanf(hd->unix_dev_name, "ctc%u", &u) == 1) {
226 hd->sub_class.id = sc_nif_ctc;
227 hd->slot = u;
228 }
229 else if(sscanf(hd->unix_dev_name, "iucv%u", &u) == 1) {
230 hd->sub_class.id = sc_nif_iucv;
231 hd->slot = u;
232 }
233 else if(sscanf(hd->unix_dev_name, "hsi%u", &u) == 1) {
234 hd->sub_class.id = sc_nif_hsi;
235 hd->slot = u;
236 }
237 else if(sscanf(hd->unix_dev_name, "qeth%u", &u) == 1) {
238 hd->sub_class.id = sc_nif_qeth;
239 hd->slot = u;
240 }
241 else if(sscanf(hd->unix_dev_name, "escon%u", &u) == 1) {
242 hd->sub_class.id = sc_nif_escon;
243 hd->slot = u;
244 }
245 else if(sscanf(hd->unix_dev_name, "myri%u", &u) == 1) {
246 hd->sub_class.id = sc_nif_myrinet;
247 hd->slot = u;
248 }
249 else if(sscanf(hd->unix_dev_name, "sit%u", &u) == 1) {
250 hd->sub_class.id = sc_nif_sit; /* ipv6 over ipv4 tunnel */
251 hd->slot = u;
252 }
253 else if(sscanf(hd->unix_dev_name, "wlan%u", &u) == 1) {
254 hd->sub_class.id = sc_nif_wlan;
255 hd->slot = u;
256 }
257 else if(sscanf(hd->unix_dev_name, "xp%u", &u) == 1) {
258 hd->sub_class.id = sc_nif_xp;
259 hd->slot = u;
260 }
261 else if(sscanf(hd->unix_dev_name, "usb%u", &u) == 1) {
262 hd->sub_class.id = sc_nif_usb;
263 hd->slot = u;
264 }
265 /* ##### add more interface names here */
266
267 hd->bus.id = bus_none;
268
269 /* fix card type */
270 if(hd_card) {
271 if(
272 (hd_card->base_class.id == 0 && hd_card->sub_class.id == 0) ||
273 (hd_card->base_class.id == bc_network && hd_card->sub_class.id == 0x80)
274 ) {
275 switch(hd->sub_class.id) {
276 case sc_nif_ethernet:
277 hd_card->base_class.id = bc_network;
278 hd_card->sub_class.id = 0;
279 break;
280
281 case sc_nif_usb:
282 hd_card->base_class.id = bc_network;
283 hd_card->sub_class.id = 0x91;
284 break;
285 }
286 }
287 }
288 }
289
290 sysfs_close_class(sf_class);
291
292 if(hd_is_sgi_altix(hd_data)) add_xpnet(hd_data);
293 if(hd_is_iseries(hd_data)) add_iseries(hd_data);
294 add_uml(hd_data);
295
296 /* add link status info */
297 for(hd = hd_data->hd ; hd; hd = hd->next) {
298 if(
299 hd->module == hd_data->module &&
300 hd->base_class.id == bc_network_interface
301 ) {
302 get_linkstate(hd_data, hd);
303
304 if(!(hd_card = hd_get_device_by_idx(hd_data, hd->attached_to))) continue;
305
306 for(res = hd->res; res; res = res->next) {
307 if(res->any.type == res_link) break;
308 }
309
310 if(res) {
311 for(res1 = hd_card->res; res1; res1 = res1->next) {
312 if(res1->any.type == res_link) break;
313 }
314 if(res && !res1) {
315 res1 = new_mem(sizeof *res1);
316 res1->link.type = res_link;
317 res1->link.state = res->link.state;
318 add_res_entry(&hd_card->res, res1);
319 }
320 }
321 }
322 }
323 }
324
325
326 /*
327 * Get it the classical way, for drivers that don't support sysfs (veth).
328 */
329 void get_driverinfo(hd_data_t *hd_data, hd_t *hd)
330 {
331 int fd;
332 struct ethtool_drvinfo drvinfo = { cmd:ETHTOOL_GDRVINFO };
333 struct ifreq ifr;
334
335 if(!hd->unix_dev_name) return;
336
337 if(strlen(hd->unix_dev_name) > sizeof ifr.ifr_name - 1) return;
338
339 if((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) return;
340
341 /* get driver info */
342 memset(&ifr, 0, sizeof ifr);
343 strcpy(ifr.ifr_name, hd->unix_dev_name);
344 ifr.ifr_data = (caddr_t) &drvinfo;
345 if(ioctl(fd, SIOCETHTOOL, &ifr) == 0) {
346 ADD2LOG(" ethtool driver: %s\n", drvinfo.driver);
347 ADD2LOG(" ethtool bus: %s\n", drvinfo.bus_info);
348
349 add_str_list(&hd->drivers, drvinfo.driver);
350 }
351 else {
352 ADD2LOG(" GDRVINFO ethtool error: %s\n", strerror(errno));
353 }
354
355 close(fd);
356 }
357
358
359 /*
360 * Check network link status.
361 */
362 void get_linkstate(hd_data_t *hd_data, hd_t *hd)
363 {
364 int fd;
365 struct ethtool_value linkstatus = { cmd:ETHTOOL_GLINK };
366 struct ifreq ifr;
367 hd_res_t *res;
368
369 if(!hd->unix_dev_name) return;
370
371 if(strlen(hd->unix_dev_name) > sizeof ifr.ifr_name - 1) return;
372
373 if((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) return;
374
375 /* get driver info */
376 memset(&ifr, 0, sizeof ifr);
377 strcpy(ifr.ifr_name, hd->unix_dev_name);
378 ifr.ifr_data = (caddr_t) &linkstatus;
379 if(ioctl(fd, SIOCETHTOOL, &ifr) == 0) {
380 ADD2LOG(" %s: ethtool link state: %d\n", hd->unix_dev_name, linkstatus.data);
381 res = new_mem(sizeof *res);
382 res->link.type = res_link;
383 res->link.state = linkstatus.data ? 1 : 0;
384 add_res_entry(&hd->res, res);
385 }
386 else {
387 ADD2LOG(" %s: GLINK ethtool error: %s\n", hd->unix_dev_name, strerror(errno));
388 }
389
390 close(fd);
391 }
392
393
394 /*
395 * SGI Altix cross partition network.
396 */
397 void add_xpnet(hd_data_t *hd_data)
398 {
399 hd_t *hd, *hd_card;
400 hd_res_t *res, *res2;
401
402 hd_card = add_hd_entry(hd_data, __LINE__, 0);
403 hd_card->base_class.id = bc_network;
404 hd_card->sub_class.id = 0x83;
405
406 hd_card->vendor.id = MAKE_ID(TAG_SPECIAL, 0x4002);
407 hd_card->device.id = MAKE_ID(TAG_SPECIAL, 1);
408
409 if(hd_module_is_active(hd_data, "xpnet")) {
410 add_str_list(&hd_card->drivers, "xpnet");
411 }
412
413 for(hd = hd_data->hd ; hd; hd = hd->next) {
414 if(
415 hd->module == hd_data->module &&
416 hd->base_class.id == bc_network_interface &&
417 hd->sub_class.id == sc_nif_xp
418 ) {
419 hd->attached_to = hd_card->idx;
420
421 for(res = hd->res; res; res = res->next) {
422 if(res->any.type == res_hwaddr) break;
423 }
424
425 if(res) {
426 res2 = new_mem(sizeof *res2);
427 res2->hwaddr.type = res_hwaddr;
428 res2->hwaddr.addr = new_str(res->hwaddr.addr);
429 add_res_entry(&hd_card->res, res2);
430 }
431
432 break;
433 }
434 }
435 }
436
437
438 /*
439 * iSeries veth devices.
440 */
441 void add_iseries(hd_data_t *hd_data)
442 {
443 hd_t *hd, *hd_card;
444 hd_res_t *res, *res2;
445 unsigned i, cardmask = 0, card_cnt = 0;
446 str_list_t *sl0, *sl;
447
448 for(hd = hd_data->hd ; hd; hd = hd->next) {
449 if(
450 hd->module == hd_data->module &&
451 hd->base_class.id == bc_network_interface &&
452 search_str_list(hd->drivers, "veth")
453 ) {
454 hd_card = add_hd_entry(hd_data, __LINE__, 0);
455 hd_card->base_class.id = bc_network;
456 hd_card->sub_class.id = 0x00;
457 hd_card->vendor.id = MAKE_ID(TAG_SPECIAL, 0x6001); // IBM
458 hd_card->device.id = MAKE_ID(TAG_SPECIAL, 0x1000);
459 add_str_list(&hd_card->drivers, "iseries_veth");
460 hd_card->slot = card_cnt++;
461 str_printf(&hd_card->device.name, 0, "Virtual Ethernet card");
462 hd->attached_to = hd_card->idx;
463
464 for(res = hd->res; res; res = res->next) {
465 if(res->any.type == res_hwaddr) break;
466 }
467
468 if(res) {
469 unsigned int slotno;
470
471 res2 = new_mem(sizeof *res2);
472 res2->hwaddr.type = res_hwaddr;
473 res2->hwaddr.addr = new_str(res->hwaddr.addr);
474 add_res_entry(&hd_card->res, res2);
475 if (sscanf(res->hwaddr.addr, "02:01:ff:%x:ff:", &slotno)) {
476 hd_card->slot = slotno;
477 str_printf(&hd_card->device.name, 0, "Virtual Ethernet card %d", hd_card->slot);
478 }
479 }
480 }
481 }
482
483 if(!card_cnt) {
484 sl0 = read_file("/proc/iSeries/config", 0, 0);
485 for(sl = sl0; sl; sl = sl->next) {
486 if(sscanf(sl->str, "AVAILABLE_VETH=%x", &cardmask) == 1)
487 break;
488 }
489 free_str_list(sl0);
490
491 for (i = 0; i < 16; i++) {
492 if ((0x8000 >> i) & cardmask) {
493 hd_card = add_hd_entry(hd_data, __LINE__, 0);
494 hd_card->base_class.id = bc_network;
495 hd_card->sub_class.id = 0x00;
496 hd_card->vendor.id = MAKE_ID(TAG_SPECIAL, 0x6001); // IBM
497 hd_card->device.id = MAKE_ID(TAG_SPECIAL, 0x1000);
498 hd_card->slot = i;
499 str_printf(&hd_card->device.name, 0, "Virtual Ethernet card %d", i);
500 }
501 }
502 }
503 }
504
505
506 /*
507 * UML veth devices.
508 */
509 void add_uml(hd_data_t *hd_data)
510 {
511 hd_t *hd, *hd_card;
512 hd_res_t *res, *res2;
513 unsigned card_cnt = 0;
514
515 for(hd = hd_data->hd ; hd; hd = hd->next) {
516 if(
517 hd->module == hd_data->module &&
518 hd->base_class.id == bc_network_interface &&
519 search_str_list(hd->drivers, "uml virtual ethernet")
520 ) {
521 hd_card = add_hd_entry(hd_data, __LINE__, 0);
522 hd_card->base_class.id = bc_network;
523 hd_card->sub_class.id = 0x00;
524 hd_card->vendor.id = MAKE_ID(TAG_SPECIAL, 0x6010); // UML
525 hd_card->device.id = MAKE_ID(TAG_SPECIAL, 0x0001);
526 hd_card->slot = card_cnt++;
527 str_printf(&hd_card->device.name, 0, "Virtual Ethernet card %d", hd_card->slot);
528 // add_str_list(&hd_card->drivers, "veth");
529
530 hd->attached_to = hd_card->idx;
531
532 for(res = hd->res; res; res = res->next) {
533 if(res->any.type == res_hwaddr) break;
534 }
535
536 if(res) {
537 res2 = new_mem(sizeof *res2);
538 res2->hwaddr.type = res_hwaddr;
539 res2->hwaddr.addr = new_str(res->hwaddr.addr);
540 add_res_entry(&hd_card->res, res2);
541 }
542 }
543 }
544 }
545
546