This commit was manufactured by cvs2svn to create tag
[opensuse:hwinfo.git] / 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
21 #include "hd.h"
22 #include "hd_int.h"
23 #include "net.h"
24
25 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
26  * gather network interface info
27  *
28  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
29  */
30
31 static void get_driverinfo(hd_data_t *hd_data, hd_t *hd);
32 static void add_xpnet(hd_data_t *hdata);
33 static void add_iseries(hd_data_t *hdata);
34 static void add_uml(hd_data_t *hdata);
35
36 /*
37  * This is independent of the other scans.
38  */
39
40 void hd_scan_net(hd_data_t *hd_data)
41 {
42   unsigned u;
43   hd_t *hd, *hd2;
44 #if 0
45 #if defined(__s390__) || defined(__s390x__)
46   hd_t *hd0;
47 #endif
48 #endif
49   char *s, *hw_addr;
50   hd_res_t *res, *res1;
51
52   struct sysfs_class *sf_class;
53   struct sysfs_class_device *sf_cdev;
54   struct sysfs_device *sf_dev;
55   struct sysfs_driver *sf_drv;
56   struct dlist *sf_cdev_list;
57
58   if(!hd_probe_feature(hd_data, pr_net)) return;
59
60   hd_data->module = mod_net;
61
62   /* some clean-up */
63   remove_hd_entries(hd_data);
64   hd_data->net = free_str_list(hd_data->net);
65
66   PROGRESS(1, 0, "get network data");
67
68   sf_class = sysfs_open_class("net");
69
70   if(!sf_class) {
71     ADD2LOG("sysfs: no such class: net\n");
72     return;
73   }
74
75   sf_cdev_list = sysfs_get_class_devices(sf_class);
76   if(sf_cdev_list) dlist_for_each_data(sf_cdev_list, sf_cdev, struct sysfs_class_device) {
77     ADD2LOG(
78       "  net interface: name = %s, classname = %s, path = %s\n",
79       sf_cdev->name,
80       sf_cdev->classname,
81       hd_sysfs_id(sf_cdev->path)
82     );
83
84     hw_addr = NULL;
85     if((s = hd_attr_str(sysfs_get_classdev_attr(sf_cdev, "address")))) {
86       hw_addr = canon_str(s, strlen(s));
87       ADD2LOG("    hw_addr = %s\n", hw_addr);
88     }
89
90     sf_dev = sysfs_get_classdev_device(sf_cdev);
91     if(sf_dev) {
92       ADD2LOG("    net device: path = %s\n", hd_sysfs_id(sf_dev->path));
93     }
94
95     sf_drv = sysfs_get_classdev_driver(sf_cdev);
96     if(sf_drv) {
97       ADD2LOG(
98         "    net driver: name = %s, path = %s\n",
99         sf_drv->name,
100         hd_sysfs_id(sf_drv->path)
101       );
102     }
103
104     hd = add_hd_entry(hd_data, __LINE__, 0);
105     hd->base_class.id = bc_network_interface;
106
107     res1 = NULL;
108     if(hw_addr && strspn(hw_addr, "0:") != strlen(hw_addr)) {
109       res1 = new_mem(sizeof *res1);
110       res1->hwaddr.type = res_hwaddr;
111       res1->hwaddr.addr = new_str(hw_addr);
112       add_res_entry(&hd->res, res1);
113     }
114
115     hw_addr = free_mem(hw_addr);
116
117     hd->unix_dev_name = new_str(sf_cdev->name);
118     hd->sysfs_id = new_str(hd_sysfs_id(sf_cdev->path));
119
120     if(sf_drv) {
121       add_str_list(&hd->drivers, sf_drv->name);
122     }
123     else if(hd->res) {
124       get_driverinfo(hd_data, hd);
125     }
126
127     if(sf_dev) {
128       hd->sysfs_device_link = new_str(hd_sysfs_id(sf_dev->path)); 
129
130       hd2 = hd_find_sysfs_id(hd_data, hd_sysfs_id(sf_dev->path));
131       if(hd2) {
132         hd->attached_to = hd2->idx;
133         /* add hw addr to network card */
134         if(res1) {
135           u = 0;
136           for(res = hd2->res; res; res = res->next) {
137             if(
138               res->any.type == res_hwaddr &&
139               !strcmp(res->hwaddr.addr, res1->hwaddr.addr)
140             ) {
141               u = 1;
142               break;
143             }
144           }
145           if(!u) {
146             res = new_mem(sizeof *res);
147             res->hwaddr.type = res_hwaddr;
148             res->hwaddr.addr = new_str(res1->hwaddr.addr);
149             add_res_entry(&hd2->res, res);
150           }
151         }
152       }
153     }
154
155     if(!strcmp(hd->unix_dev_name, "lo")) {
156       hd->sub_class.id = sc_nif_loopback;
157     }
158     else if(sscanf(hd->unix_dev_name, "eth%u", &u) == 1) {
159       hd->sub_class.id = sc_nif_ethernet;
160       hd->slot = u;
161     }
162     else if(sscanf(hd->unix_dev_name, "tr%u", &u) == 1) {
163       hd->sub_class.id = sc_nif_tokenring;
164       hd->slot = u;
165     }
166     else if(sscanf(hd->unix_dev_name, "fddi%u", &u) == 1) {
167       hd->sub_class.id = sc_nif_fddi;
168       hd->slot = u;
169     }
170     else if(sscanf(hd->unix_dev_name, "ctc%u", &u) == 1) {
171       hd->sub_class.id = sc_nif_ctc;
172       hd->slot = u;
173     }
174     else if(sscanf(hd->unix_dev_name, "iucv%u", &u) == 1) {
175       hd->sub_class.id = sc_nif_iucv;
176       hd->slot = u;
177     }
178     else if(sscanf(hd->unix_dev_name, "hsi%u", &u) == 1) {
179       hd->sub_class.id = sc_nif_hsi;
180       hd->slot = u;
181     }
182     else if(sscanf(hd->unix_dev_name, "qeth%u", &u) == 1) {
183       hd->sub_class.id = sc_nif_qeth;
184       hd->slot = u;
185     }
186     else if(sscanf(hd->unix_dev_name, "escon%u", &u) == 1) {
187       hd->sub_class.id = sc_nif_escon;
188       hd->slot = u;
189     }
190     else if(sscanf(hd->unix_dev_name, "myri%u", &u) == 1) {
191       hd->sub_class.id = sc_nif_myrinet;
192       hd->slot = u;
193     }
194     else if(sscanf(hd->unix_dev_name, "sit%u", &u) == 1) {
195       hd->sub_class.id = sc_nif_sit;    /* ipv6 over ipv4 tunnel */
196       hd->slot = u;
197     }
198     else if(sscanf(hd->unix_dev_name, "wlan%u", &u) == 1) {
199       hd->sub_class.id = sc_nif_wlan;
200       hd->slot = u;
201     }
202     else if(sscanf(hd->unix_dev_name, "xp%u", &u) == 1) {
203       hd->sub_class.id = sc_nif_xp;
204       hd->slot = u;
205     }
206     /* ##### add more interface names here */
207     else {
208       hd->sub_class.id = sc_nif_other;
209     }
210
211     hd->bus.id = bus_none;
212   }
213
214   sysfs_close_class(sf_class);
215
216   if(hd_is_sgi_altix(hd_data)) add_xpnet(hd_data);
217   if(hd_is_iseries(hd_data)) add_iseries(hd_data);
218   add_uml(hd_data);
219
220 #if 0
221
222 #if defined(__s390__) || defined(__s390x__)
223       if(
224         hd->sub_class.id != sc_nif_loopback &&
225         hd->sub_class.id != sc_nif_sit && hd->sub_class.id != sc_nif_ethernet && hd->sub_class.id != sc_nif_qeth &&
226         hd->sub_class.id != sc_nif_ctc
227       ) {
228         hd0 = hd;
229         hd = add_hd_entry(hd_data, __LINE__, 0);
230         hd->base_class.id = bc_network;
231         hd->unix_dev_name = new_str(hd0->unix_dev_name);
232         hd->slot = hd0->slot;
233         hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x6001);   // IBM
234         switch(hd0->sub_class.id) {
235           case sc_nif_tokenring:
236             hd->sub_class.id = 1;
237             hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0001);
238             str_printf(&hd->device.name, 0, "Token ring card %d", hd->slot);
239             break;
240           case sc_nif_ctc:
241             hd->sub_class.id = 0x04;
242             hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0004);
243             str_printf(&hd->device.name, 0, "CTC %d", hd->slot);
244             break;
245           case sc_nif_iucv:
246             hd->sub_class.id = 0x05;
247             hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0005);
248             str_printf(&hd->device.name, 0, "IUCV %d", hd->slot);
249             break;
250           case sc_nif_hsi:
251             hd->sub_class.id = 0x06;
252             hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0006);
253             str_printf(&hd->device.name, 0, "HSI %d", hd->slot);
254             break;
255           case sc_nif_escon:
256             hd->sub_class.id = 0x08;
257             hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0008);
258             str_printf(&hd->device.name, 0, "ESCON %d", hd->slot);
259             break;
260           default:
261             hd->sub_class.id = 0x80;
262             hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0080);
263         }
264       }
265 #endif
266
267 #endif
268
269
270 }
271
272
273 /*
274  * Get it the classical way, for drivers that don't support sysfs (veth).
275  */
276 void get_driverinfo(hd_data_t *hd_data, hd_t *hd)
277 {
278   int fd;
279   struct ethtool_drvinfo drvinfo = { cmd:ETHTOOL_GDRVINFO };
280   struct ifreq ifr;
281
282   if(!hd->unix_dev_name) return;
283
284   if(strlen(hd->unix_dev_name) > sizeof ifr.ifr_name - 1) return;
285
286   if((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) return;
287
288   /* get driver info */
289   memset(&ifr, 0, sizeof ifr);
290   strcpy(ifr.ifr_name, hd->unix_dev_name);
291   ifr.ifr_data = (caddr_t) &drvinfo;
292   if(ioctl(fd, SIOCETHTOOL, &ifr) == 0) {
293     ADD2LOG("    ethtool driver: %s\n", drvinfo.driver);
294     ADD2LOG("    ethtool    bus: %s\n", drvinfo.bus_info);
295
296     add_str_list(&hd->drivers, drvinfo.driver);
297   }
298   else {
299     ADD2LOG("    ethtool error: %s\n", strerror(errno));
300   }
301
302   close(fd);
303 }
304
305
306 /*
307  * SGI Altix cross partition network.
308  */
309 void add_xpnet(hd_data_t *hd_data)
310 {
311   hd_t *hd, *hd_card;
312   hd_res_t *res, *res2;
313
314   hd_card = add_hd_entry(hd_data, __LINE__, 0);
315   hd_card->base_class.id = bc_network;
316   hd_card->sub_class.id = 0x83;
317
318   hd_card->vendor.id = MAKE_ID(TAG_SPECIAL, 0x4002);
319   hd_card->device.id = MAKE_ID(TAG_SPECIAL, 1);
320
321   if(hd_module_is_active(hd_data, "xpnet")) {
322     add_str_list(&hd_card->drivers, "xpnet");
323   }
324
325   for(hd = hd_data->hd ; hd; hd = hd->next) {
326     if(
327       hd->module == hd_data->module &&
328       hd->base_class.id == bc_network_interface &&
329       hd->sub_class.id == sc_nif_xp
330     ) {
331       hd->attached_to = hd_card->idx;
332
333       for(res = hd->res; res; res = res->next) {
334         if(res->any.type == res_hwaddr) break;
335       }
336
337       if(res) {
338         res2 = new_mem(sizeof *res2);
339         res2->hwaddr.type = res_hwaddr;
340         res2->hwaddr.addr = new_str(res->hwaddr.addr);
341         add_res_entry(&hd_card->res, res2);
342       }
343
344       break;
345     }
346   }
347 }
348
349
350 /*
351  * iSeries veth devices.
352  */
353 void add_iseries(hd_data_t *hd_data)
354 {
355   hd_t *hd, *hd_card;
356   hd_res_t *res, *res2;
357   unsigned card_cnt = 0;
358
359   for(hd = hd_data->hd ; hd; hd = hd->next) {
360     if(
361       hd->module == hd_data->module &&
362       hd->base_class.id == bc_network_interface &&
363       search_str_list(hd->drivers, "veth")
364     ) {
365       hd_card = add_hd_entry(hd_data, __LINE__, 0);
366       hd_card->base_class.id = bc_network;
367       hd_card->sub_class.id = 0x00;
368       hd_card->vendor.id = MAKE_ID(TAG_SPECIAL, 0x6001);        // IBM
369       hd_card->device.id = MAKE_ID(TAG_SPECIAL, 0x1000);
370       hd_card->slot = card_cnt++;
371       str_printf(&hd_card->device.name, 0, "Virtual Ethernet card %d", hd_card->slot);
372       add_str_list(&hd_card->drivers, "veth");
373
374       hd->attached_to = hd_card->idx;
375
376       for(res = hd->res; res; res = res->next) {
377         if(res->any.type == res_hwaddr) break;
378       }
379
380       if(res) {
381         res2 = new_mem(sizeof *res2);
382         res2->hwaddr.type = res_hwaddr;
383         res2->hwaddr.addr = new_str(res->hwaddr.addr);
384         add_res_entry(&hd_card->res, res2);
385       }
386     }
387   }
388 }
389
390
391 /*
392  * UML veth devices.
393  */
394 void add_uml(hd_data_t *hd_data)
395 {
396   hd_t *hd, *hd_card;
397   hd_res_t *res, *res2;
398   unsigned card_cnt = 0;
399
400   for(hd = hd_data->hd ; hd; hd = hd->next) {
401     if(
402       hd->module == hd_data->module &&
403       hd->base_class.id == bc_network_interface &&
404       !search_str_list(hd->drivers, "uml virtual ethernet")
405     ) {
406       hd_card = add_hd_entry(hd_data, __LINE__, 0);
407       hd_card->base_class.id = bc_network;
408       hd_card->sub_class.id = 0x00;
409       hd_card->vendor.id = MAKE_ID(TAG_SPECIAL, 0x6010);        // UML
410       hd_card->device.id = MAKE_ID(TAG_SPECIAL, 0x0001);
411       hd_card->slot = card_cnt++;
412       str_printf(&hd_card->device.name, 0, "Virtual Ethernet card %d", hd_card->slot);
413 //      add_str_list(&hd_card->drivers, "veth");
414
415       hd->attached_to = hd_card->idx;
416
417       for(res = hd->res; res; res = res->next) {
418         if(res->any.type == res_hwaddr) break;
419       }
420
421       if(res) {
422         res2 = new_mem(sizeof *res2);
423         res2->hwaddr.type = res_hwaddr;
424         res2->hwaddr.addr = new_str(res->hwaddr.addr);
425         add_res_entry(&hd_card->res, res2);
426       }
427     }
428   }
429 }
430
431