/ src / core / network.cc
network.cc
  1  /*
  2   * network.cc
  3   *
  4   * This scan uses the same IOCTLs as ethtool, ifconfig or mii-diag to report
  5   * information about network interfaces like:
  6   * - medium type (ethernet, token ring, PPP, etc.)
  7   * - hardware address (MAC address)
  8   * - link status (link detected, in error, etc.)
  9   * - speed (10Mbits, 100Mbits, etc.)
 10   * - IP addressing
 11   *
 12   * As network interfaces can be plugged on PCI, PCMCIA, ISA, USB, etc. this
 13   * scan should be executed after all bus-related scans.
 14   *
 15   */
 16  
 17  #include "version.h"
 18  #include "config.h"
 19  #include "network.h"
 20  #include "osutils.h"
 21  #include "sysfs.h"
 22  #include "options.h"
 23  #include "heuristics.h"
 24  #include <sys/socket.h>
 25  #include <sys/ioctl.h>
 26  #include <netinet/in.h>
 27  #include <arpa/inet.h>
 28  #include <net/if_arp.h>
 29  #include <linux/sockios.h>
 30  #include <net/if.h>
 31  #include <fcntl.h>
 32  #include <unistd.h>
 33  #include <stdio.h>
 34  #include <stdint.h>
 35  #include <string.h>
 36  #include <string>
 37  #include <sys/types.h>
 38  using namespace std;
 39  
 40  __ID("@(#) $Id$");
 41  
 42  #ifndef ARPHRD_IEEE1394
 43  #define ARPHRD_IEEE1394 24
 44  #endif
 45  #ifndef ARPHRD_SIT
 46  #define ARPHRD_SIT  776
 47  #endif
 48  
 49  #ifndef SIOCETHTOOL
 50  #define SIOCETHTOOL     0x8946
 51  #endif
 52  typedef unsigned long long u64;
 53  typedef uint32_t u32;
 54  typedef uint16_t u16;
 55  typedef uint8_t u8;
 56  typedef int8_t s8;
 57  
 58  struct ethtool_cmd
 59  {
 60    u32 cmd;
 61    u32 supported;                                  /* Features this interface supports */
 62    u32 advertising;                                /* Features this interface advertises */
 63    u16 speed;                                      /* The forced speed, 10Mb, 100Mb, gigabit */
 64    u8 duplex;                                      /* Duplex, half or full */
 65    u8 port;                                        /* Which connector port */
 66    u8 phy_address;
 67    u8 transceiver;                                 /* Which tranceiver to use */
 68    u8 autoneg;                                     /* Enable or disable autonegotiation */
 69    u32 maxtxpkt;                                   /* Tx pkts before generating tx int */
 70    u32 maxrxpkt;                                   /* Rx pkts before generating rx int */
 71    u32 reserved[4];
 72  };
 73  
 74  #define MAX_LINK_MODE_MASK_SIZE 64
 75  struct ethtool_link_settings
 76  {
 77    u32 cmd;
 78    u32 speed;                                      /* The forced speed, 10Mb, 100Mb, gigabit */
 79    u8 duplex;                                      /* Duplex, half or full */
 80    u8 port;                                        /* Which connector port */
 81    u8 phy_address;
 82    u8 autoneg;                                     /* Enable or disable autonegotiation */
 83    u8 mdio_support;
 84    u8 eth_tp_mdix;
 85    u8 eth_tp_mdix_ctrl;
 86    s8 link_mode_masks_nwords;
 87    u8 transceiver;                                 /* Which tranceiver to use */
 88    u8 master_slave_cfg;
 89    u8 master_slave_state;
 90    u8 reserved1[1];
 91    u32 reserved[7];
 92    u32 link_mode_masks[3 * MAX_LINK_MODE_MASK_SIZE]; /* Link mode mask fields for modes:
 93                                                         supported, advertised, peer advertised. */
 94  };
 95  
 96  /* Recognized module eeprom standards. */
 97  #define ETH_MODULE_SFF_8079     0x1
 98  #define ETH_MODULE_SFF_8472     0x2
 99  #define ETH_MODULE_SFF_8636     0x3
100  #define ETH_MODULE_SFF_8436     0x4
101  
102  struct ethtool_modinfo {
103    u32 cmd;
104    u32 type;                                       /* SFF standard used in module */
105    u32 eeprom_len;                                 /* Length of module eeprom */
106    u32 reserved[8];
107  };
108  
109  /* Known id types. */
110  #define SFF_8024_ID_SOLDERED                    0x2
111  #define SFF_8024_ID_SFP                         0x3
112  #define SFF_8024_EXT_ID_DEFINED_BY_2WIRE_ID     0x4
113  
114  /* Common connector types. */
115  #define SFF_8024_CONNECTOR_SC                   0x1
116  #define SFF_8024_CONNECTOR_LC                   0x7
117  #define SFF_8024_CONNECTOR_OPTICAL_PIGTAIL      0xb
118  #define SFF_8024_CONNECTOR_COPPER_PIGTAIL       0x21
119  #define SFF_8024_CONNECTOR_RJ45                 0x22
120  #define SFF_8024_CONNECTOR_NON_SEPARABLE        0x23
121  
122  #define MAX_EEPROM_SIZE 256
123  struct ethtool_eeprom {
124    u32 cmd;
125    u32 magic;                                      /* Only used for eeprom writes */
126    u32 offset;                                     /* Read or write offset */
127    u32 len;                                        /* Length of read/write */
128    u8 data[MAX_EEPROM_SIZE];                       /* Buffer */
129  };
130  
131  #ifndef IFNAMSIZ
132  #define IFNAMSIZ 32
133  #endif
134  #define SIOCGIWNAME     0x8B01                    /* get name == wireless protocol */
135  /* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
136   * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"... */
137  
138  #define ETHTOOL_BUSINFO_LEN     32
139  /* these strings are set to whatever the driver author decides... */
140  struct ethtool_drvinfo
141  {
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  /*
148   * For PCI devices, use pci_dev->slot_name.
149   */
150    char reserved1[32];
151    char reserved2[16];
152    u32 n_stats;                                    /* number of u64's from ETHTOOL_GSTATS */
153    u32 testinfo_len;
154    u32 eedump_len;                                 /* Size of data from ETHTOOL_GEEPROM (bytes) */
155    u32 regdump_len;                                /* Size of data from ETHTOOL_GREGS (bytes) */
156  };
157  
158  /* for passing single values */
159  struct ethtool_value
160  {
161    u32 cmd;
162    u32 data;
163  };
164  
165  /* CMDs currently supported */
166  #define ETHTOOL_GSET            0x00000001        /* Get settings. */
167  #define ETHTOOL_GDRVINFO        0x00000003        /* Get driver info. */
168  #define ETHTOOL_GLINK           0x0000000a        /* Get link status (ethtool_value) */
169  #define ETHTOOL_GMODULEINFO     0x00000042        /* Get plug-in module information */
170  #define ETHTOOL_GMODULEEEPROM   0x00000043        /* Get plug-in module eeprom */
171  #define ETHTOOL_GLINKSETTINGS   0x0000004c        /* Get link mode settings. */
172  
173  /* Indicates what features are supported by the interface. */
174  #define SUPPORTED_10baseT_Half          (1 << 0)
175  #define SUPPORTED_10baseT_Full          (1 << 1)
176  #define SUPPORTED_100baseT_Half         (1 << 2)
177  #define SUPPORTED_100baseT_Full         (1 << 3)
178  #define SUPPORTED_1000baseT_Half        (1 << 4)
179  #define SUPPORTED_1000baseT_Full        (1 << 5)
180  #define SUPPORTED_Autoneg               (1 << 6)
181  #define SUPPORTED_TP                    (1 << 7)
182  #define SUPPORTED_AUI                   (1 << 8)
183  #define SUPPORTED_MII                   (1 << 9)
184  #define SUPPORTED_FIBRE                 (1 << 10)
185  #define SUPPORTED_BNC                   (1 << 11)
186  #define SUPPORTED_10000baseT_Full       (1 << 12)
187  #define SUPPORTED_2500baseX_Full        (1 << 15)
188  #define SUPPORTED_1000baseKX_Full       (1 << 17)
189  #define SUPPORTED_10000baseKX4_Full     (1 << 18)
190  #define SUPPORTED_10000baseKR_Full      (1 << 19)
191  #define SUPPORTED_10000baseR_FEC        (1 << 20)
192  #define SUPPORTED_20000baseMLD2_Full    (1 << 21)
193  #define SUPPORTED_20000baseKR2_Full     (1 << 22)
194  #define SUPPORTED_40000baseKR4_Full     (1 << 23)
195  #define SUPPORTED_40000baseCR4_Full     (1 << 24)
196  #define SUPPORTED_40000baseSR4_Full     (1 << 25)
197  #define SUPPORTED_40000baseLR4_Full     (1 << 26)
198  #define SUPPORTED_56000baseKR4_Full     (1 << 27)
199  #define SUPPORTED_56000baseCR4_Full     (1 << 28)
200  #define SUPPORTED_56000baseSR4_Full     (1 << 29)
201  #define SUPPORTED_56000baseLR4_Full     (1 << 30)
202  #define SUPPORTED_25000baseCR_Full      (1 << 31)
203  #define SUPPORTED_25000baseKR_Full      (1 << 32)
204  #define SUPPORTED_25000baseSR_Full      (1 << 33)
205  #define SUPPORTED_50000baseCR2_Full     (1 << 34)
206  #define SUPPORTED_50000baseKR2_Full     (1 << 35)
207  #define SUPPORTED_100000baseKR4_Full    (1 << 36)
208  #define SUPPORTED_100000baseSR4_Full    (1 << 37)
209  #define SUPPORTED_100000baseCR4_Full    (1 << 38)
210  #define SUPPORTED_100000baseLR4_ER4_Full (1 << 39)
211  #define SUPPORTED_50000baseSR2_Full     (1 << 40)
212  #define SUPPORTED_1000baseX_Full        (1 << 41)
213  #define SUPPORTED_10000baseCR_Full      (1 << 42)
214  #define SUPPORTED_10000baseSR_Full      (1 << 43)
215  #define SUPPORTED_10000baseLR_Full      (1 << 44)
216  #define SUPPORTED_10000baseLRM_Full     (1 << 45)
217  #define SUPPORTED_10000baseER_Full      (1 << 46)
218  #define SUPPORTED_2500baseT_Full        (1 << 47)
219  #define SUPPORTED_5000baseT_Full        (1 << 48)
220  
221  /* Indicates what features are supported by the interface,
222   * in the second word of the extended bitmap. */
223  #define SUPPORTED2_25000baseKR_Full         (1 << 0)
224  #define SUPPORTED2_25000baseSR_Full         (1 << 1)
225  #define SUPPORTED2_100000baseKR4_Full       (1 << 4)
226  #define SUPPORTED2_100000baseSR4_Full       (1 << 5)
227  #define SUPPORTED2_100000baseCR4_Full       (1 << 6)
228  #define SUPPORTED2_100000baseLR4_ER4_Full   (1 << 7)
229  #define SUPPORTED2_1000baseX_Full           (1 << 9)
230  #define SUPPORTED2_10000baseCR_Full         (1 << 10)
231  #define SUPPORTED2_10000baseSR_Full         (1 << 11)
232  #define SUPPORTED2_10000baseLR_Full         (1 << 12)
233  #define SUPPORTED2_10000baseLRM_Full        (1 << 13)
234  #define SUPPORTED2_10000baseER_Full         (1 << 14)
235  #define SUPPORTED2_2500baseT_Full           (1 << 15)
236  #define SUPPORTED2_5000baseT_Full           (1 << 16)
237  
238  /* The forced speed, 10Mb, 100Mb, gigabit, 2.5GbE, 5GbE, 10GbE and up. */
239  #define SPEED_10                10
240  #define SPEED_100               100
241  #define SPEED_1000              1000
242  #define SPEED_2500              2500
243  #define SPEED_5000              5000
244  #define SPEED_10000             10000
245  #define SPEED_25000             25000
246  #define SPEED_40000             40000
247  #define SPEED_100000            100000
248  
249  /* Duplex, half or full. */
250  #define DUPLEX_HALF             0x00
251  #define DUPLEX_FULL             0x01
252  
253  /* Which connector port. */
254  #define PORT_TP                 0x00
255  #define PORT_AUI                0x01
256  #define PORT_MII                0x02
257  #define PORT_FIBRE              0x03
258  #define PORT_BNC                0x04
259  
260  /* Which tranceiver to use. */
261  #define XCVR_INTERNAL           0x00
262  #define XCVR_EXTERNAL           0x01
263  #define XCVR_DUMMY1             0x02
264  #define XCVR_DUMMY2             0x03
265  #define XCVR_DUMMY3             0x04
266  
267  #define AUTONEG_DISABLE         0x00
268  #define AUTONEG_ENABLE          0x01
269  
270  bool load_interfaces(vector < string > &interfaces)
271  {
272    vector < string > procnetdev;
273  
274    interfaces.clear();
275    if (!loadfile("/proc/net/dev", procnetdev))
276      return false;
277  
278    if (procnetdev.size() <= 2)
279      return false;
280  
281  // get rid of header (2 lines)
282    procnetdev.erase(procnetdev.begin());
283    procnetdev.erase(procnetdev.begin());
284  
285    for (unsigned int i = 0; i < procnetdev.size(); i++)
286    {
287  // extract interfaces names
288      size_t pos = procnetdev[i].find(':');
289  
290      if (pos != string::npos)
291        interfaces.push_back(hw::strip(procnetdev[i].substr(0, pos)));
292    }
293  
294    return true;
295  }
296  
297  static int maclen(unsigned family = ARPHRD_ETHER)
298  {
299    switch(family)
300    {
301      case ARPHRD_INFINIBAND:
302        return 20;
303      case ARPHRD_ETHER:
304        return 6;
305      default:
306        return 14;
307    }
308  }
309  
310  static string getmac(const unsigned char *mac, unsigned family = ARPHRD_ETHER)
311  {
312    char buff[5];
313    string result = "";
314    bool valid = false;
315  
316    for (int i = 0; i < maclen(family); i++)
317    {
318      snprintf(buff, sizeof(buff), "%02x", mac[i]);
319  
320      valid |= (mac[i] != 0);
321  
322      if (i == 0)
323        result = string(buff);
324      else
325        result += ":" + string(buff);
326    }
327  
328    if (valid)
329      return result;
330    else
331      return "";
332  }
333  
334  
335  static const char *hwname(int t)
336  {
337    switch (t)
338    {
339      case ARPHRD_ETHER:
340        return _("Ethernet");
341      case ARPHRD_SLIP:
342        return _("SLIP");
343      case ARPHRD_LOOPBACK:
344        return _("loopback");
345      case ARPHRD_FDDI:
346        return _("FDDI");
347      case ARPHRD_IEEE1394:
348        return _("IEEE1394");
349      case ARPHRD_IRDA:
350        return _("IRDA");
351      case ARPHRD_PPP:
352        return _("PPP");
353      case ARPHRD_X25:
354        return _("X25");
355      case ARPHRD_TUNNEL:
356        return _("IPtunnel");
357      case ARPHRD_DLCI:
358        return _("Framerelay.DLCI");
359      case ARPHRD_FRAD:
360        return _("Framerelay.AD");
361      case ARPHRD_TUNNEL6:
362        return _("IP6tunnel");
363      case ARPHRD_SIT:
364        return _("IP6inIP4");
365      default:
366        return "";
367    }
368  }
369  
370  
371  static string print_ip(struct sockaddr_in *in)
372  {
373    return string(inet_ntoa(in->sin_addr));
374  }
375  
376  
377  static void scan_ip(hwNode & interface)
378  {
379    int fd = socket(AF_INET, SOCK_DGRAM, 0);
380  
381    if (fd >= 0)
382    {
383      struct ifreq ifr;
384  
385  // get IP address
386      memset(&ifr, 0, sizeof(ifr));
387      strcpy(ifr.ifr_name, interface.getLogicalName().c_str());
388      ifr.ifr_addr.sa_family = AF_INET;
389      if (ioctl(fd, SIOCGIFADDR, &ifr) == 0)
390      {
391  // IP address is in ifr.ifr_addr
392        interface.setConfig("ip", ::enabled("output:sanitize")?REMOVED:print_ip((sockaddr_in *) (&ifr.ifr_addr)));
393        strcpy(ifr.ifr_name, interface.getLogicalName().c_str());
394        if ((interface.getConfig("point-to-point") == "yes")
395          && (ioctl(fd, SIOCGIFDSTADDR, &ifr) == 0))
396        {
397  // remote PPP address is in ifr.ifr_dstaddr
398          interface.setConfig("remoteip",
399            print_ip((sockaddr_in *) & ifr.ifr_dstaddr));
400        }
401      }
402  
403      close(fd);
404    }
405  }
406  
407  
408  static bool isVirtual(const string & MAC)
409  {
410    if (MAC.length() < 8)
411      return false;
412  
413    string manufacturer = uppercase(MAC.substr(0, 8));
414  
415    if ((manufacturer == "00:05:69") ||
416      (manufacturer == "00:0C:29") || (manufacturer == "00:50:56"))
417      return true;	// VMware
418    if (manufacturer == "00:1C:42")
419      return true;	// Parallels
420    if (manufacturer == "0A:00:27")
421      return true;	// VirtualBox
422  
423    return false;
424  }
425  
426  
427  // Get data for connected transceiver module.
428  static void scan_module(hwNode & interface, int fd)
429  {
430    struct ifreq ifr;
431    struct ethtool_modinfo emodinfo;
432    struct ethtool_eeprom eeeprom;
433  
434    emodinfo.cmd = ETHTOOL_GMODULEINFO;
435    memset(&ifr, 0, sizeof(ifr));
436    strcpy(ifr.ifr_name, interface.getLogicalName().c_str());
437    ifr.ifr_data = (caddr_t) &emodinfo;
438    // Skip interface if module info not supported.
439    if (ioctl(fd, SIOCETHTOOL, &ifr) != 0)
440      return;
441  
442    eeeprom.cmd = ETHTOOL_GMODULEEEPROM;
443    eeeprom.offset = 0;
444    eeeprom.len = emodinfo.eeprom_len;
445    if (eeeprom.len > MAX_EEPROM_SIZE)
446      eeeprom.len = MAX_EEPROM_SIZE;
447    memset(&ifr, 0, sizeof(ifr));
448    strcpy(ifr.ifr_name, interface.getLogicalName().c_str());
449    ifr.ifr_data = (caddr_t) &eeeprom;
450    if (ioctl(fd, SIOCETHTOOL, &ifr) != 0)
451      return;
452  
453    switch (emodinfo.type)
454    {
455      /* SFF 8472 eeprom layout starts with same data as SFF 8079. */
456      case ETH_MODULE_SFF_8079:
457      case ETH_MODULE_SFF_8472:
458        if ((eeeprom.data[0] == SFF_8024_ID_SOLDERED || eeeprom.data[0] == SFF_8024_ID_SFP) &&
459            eeeprom.data[1] == SFF_8024_EXT_ID_DEFINED_BY_2WIRE_ID)
460        {
461          char buffer[32];
462          /* Get part number (padded with space). String is stripped inside setConfig. */
463          interface.setConfig("module", string((const char*)&eeeprom.data[40], 16));
464          int wavelength = eeeprom.data[60] << 8 | eeeprom.data[61];
465          /* Skip wavelength for SFP+ cables, they use byte 60 for other data. */
466          if ((eeeprom.data[8] & 0x0C) == 0 && wavelength > 0)
467          {
468            snprintf(buffer, sizeof(buffer), "%dnm", wavelength);
469            interface.setConfig("wavelength", buffer);
470          }
471          int max_length = 0;
472          int length;
473          length = eeeprom.data[14] * 1000; /* SMF, km */
474          if (length > max_length) max_length = length;
475          length = eeeprom.data[15] * 100; /* SMF, meter */
476          if (length > max_length) max_length = length;
477          length = eeeprom.data[16] * 10; /* 50um (OM2), meter */
478          if (length > max_length) max_length = length;
479          length = eeeprom.data[17] * 10; /* 62.5um (OM1), meter */
480          if (length > max_length) max_length = length;
481          length = eeeprom.data[18]; /* Copper, meter */
482          if (length > max_length) max_length = length;
483          length = eeeprom.data[19] * 10; /* OM3, meter */
484          if (length > max_length) max_length = length;
485          if (max_length > 0)
486          {
487            snprintf(buffer, sizeof(buffer), "%dm", max_length);
488            interface.setConfig("maxlength", buffer);
489          }
490          switch (eeeprom.data[2])
491          {
492            case SFF_8024_CONNECTOR_SC:
493              interface.setConfig("connector", "SC");
494              break;
495            case SFF_8024_CONNECTOR_LC:
496              interface.setConfig("connector", "LC");
497              break;
498            case SFF_8024_CONNECTOR_OPTICAL_PIGTAIL:
499              interface.setConfig("connector", "optical pigtail");
500              break;
501            case SFF_8024_CONNECTOR_COPPER_PIGTAIL:
502              interface.setConfig("connector", "copper pigtail");
503              break;
504            case SFF_8024_CONNECTOR_RJ45:
505              interface.setConfig("connector", "RJ45");
506              break;
507            case SFF_8024_CONNECTOR_NON_SEPARABLE:
508              interface.setConfig("connector", "non separable");
509              break;
510          }
511        }
512        break;
513    }
514  }
515  
516  
517  static void updateCapabilities(hwNode & interface, u32 supported, u32 supported2, u32 speed, u8 duplex, u8 port, u8 autoneg)
518  {
519    if(supported & SUPPORTED_TP)
520      interface.addCapability("tp", _("twisted pair"));
521    if(supported & SUPPORTED_AUI)
522      interface.addCapability("aui", _("AUI"));
523    if(supported & SUPPORTED_BNC)
524      interface.addCapability("bnc", _("BNC"));
525    if(supported & SUPPORTED_MII)
526      interface.addCapability("mii", _("Media Independent Interface"));
527    if(supported & SUPPORTED_FIBRE)
528      interface.addCapability("fibre",_( "optical fibre"));
529    if(supported & SUPPORTED_10baseT_Half)
530    {
531      interface.addCapability("10bt", _("10Mbit/s"));
532      interface.setCapacity(10000000ULL);
533    }
534    if(supported & SUPPORTED_10baseT_Full)
535    {
536      interface.addCapability("10bt-fd", _("10Mbit/s (full duplex)"));
537      interface.setCapacity(10000000ULL);
538    }
539    if(supported & SUPPORTED_100baseT_Half)
540    {
541      interface.addCapability("100bt", _("100Mbit/s"));
542      interface.setCapacity(100000000ULL);
543    }
544    if(supported & SUPPORTED_100baseT_Full)
545    {
546      interface.addCapability("100bt-fd", _("100Mbit/s (full duplex)"));
547      interface.setCapacity(100000000ULL);
548    }
549    if(supported & SUPPORTED_1000baseT_Half)
550    {
551      interface.addCapability("1000bt", "1Gbit/s");
552      interface.setCapacity(1000000000ULL);
553    }
554    if(supported & SUPPORTED_1000baseT_Full)
555    {
556      interface.addCapability("1000bt-fd", _("1Gbit/s (full duplex)"));
557      interface.setCapacity(1000000000ULL);
558    }
559    if((supported & SUPPORTED_1000baseKX_Full) || (supported2 & SUPPORTED2_1000baseX_Full))
560    {
561      interface.addCapability("1000bx-fd", _("1Gbit/s (full duplex)"));
562      interface.setCapacity(1000000000ULL);
563    }
564    if(supported & SUPPORTED_2500baseX_Full)
565    {
566      interface.addCapability("2500bx-fd", _("2.5Gbit/s (full duplex)"));
567      interface.setCapacity(2500000000ULL);
568    }
569    if(supported & SUPPORTED_2500baseT_Full)
570    {
571      interface.addCapability("2500bt-fd", _("2500Mbit/s (full duplex)"));
572      interface.setCapacity(2500000000ULL);
573    }
574    if(supported & SUPPORTED_5000baseT_Full)
575    {
576      interface.addCapability("5000bt-fd", _("5Gbit/s (full duplex)"));
577      interface.setCapacity(5000000000ULL);
578    }
579    if(supported2 & SUPPORTED2_2500baseT_Full)
580    {
581      interface.addCapability("2500bt-fd", _("2.5Gbit/s (full duplex)"));
582      interface.setCapacity(2500000000ULL);
583    }
584    if(supported2 & SUPPORTED2_5000baseT_Full)
585    {
586      interface.addCapability("5000bt-fd", _("5Gbit/s (full duplex)"));
587      interface.setCapacity(5000000000ULL);
588    }
589    if(supported & SUPPORTED_10000baseT_Full)
590    {
591      interface.addCapability("10000bt-fd", _("10Gbit/s (full duplex)"));
592      interface.setCapacity(10000000000ULL);
593    }
594    if((supported & (SUPPORTED_10000baseKX4_Full | SUPPORTED_10000baseKR_Full)) ||
595       (supported2 & (SUPPORTED2_10000baseCR_Full | SUPPORTED2_10000baseSR_Full | SUPPORTED2_10000baseLR_Full |
596                      SUPPORTED2_10000baseLRM_Full | SUPPORTED2_10000baseER_Full)))
597    {
598      interface.addCapability("10000bx-fd", _("10Gbit/s (full duplex)"));
599      interface.setCapacity(10000000000ULL);
600    }
601    if(supported & SUPPORTED_10000baseR_FEC)
602    {
603      interface.addCapability("10000bt-fd", _("10Gbit/s (full duplex)"));
604      interface.setCapacity(10000000000ULL);
605    }
606    if(supported & SUPPORTED_10000baseCR_Full)
607    {
608      interface.addCapability("10000bt-fd", _("10Gbit/s (full duplex)"));
609      interface.setCapacity(10000000000ULL);
610    }
611    if(supported & SUPPORTED_10000baseSR_Full)
612    {
613      interface.addCapability("10000bt-fd", _("10Gbit/s (full duplex)"));
614      interface.setCapacity(10000000000ULL);
615    }
616    if(supported & SUPPORTED_10000baseLR_Full)
617    {
618      interface.addCapability("10000bt-fd", _("10Gbit/s (full duplex)"));
619      interface.setCapacity(10000000000ULL);
620    }
621    if(supported & SUPPORTED_10000baseLRM_Full)
622    {
623      interface.addCapability("10000bt-fd", _("10Gbit/s (full duplex)"));
624      interface.setCapacity(10000000000ULL);
625    }
626    if(supported & SUPPORTED_10000baseER_Full)
627    {
628      interface.addCapability("10000bt-fd", _("10Gbit/s (full duplex)"));
629      interface.setCapacity(10000000000ULL);
630    }
631    if(supported & SUPPORTED_20000baseMLD2_Full)
632    {
633      interface.addCapability("20000bt-fd", _("20Gbit/s (full duplex)"));
634      interface.setCapacity(20000000000ULL);
635    }
636    if(supported & SUPPORTED_20000baseKR2_Full)
637    {
638      interface.addCapability("20000bt-fd", _("20Gbit/s (full duplex)"));
639      interface.setCapacity(20000000000ULL);
640    }
641    if((supported & SUPPORTED_25000baseCR_Full) ||
642       (supported2 & (SUPPORTED2_25000baseKR_Full | SUPPORTED2_25000baseSR_Full)))
643    {
644      interface.addCapability("25000bx-fd", _("25Gbit/s (full duplex)"));
645      interface.setCapacity(25000000000ULL);
646    }
647    if(supported & SUPPORTED_25000baseKR_Full)
648    {
649      interface.addCapability("25000bt-fd", _("25Gbit/s (full duplex)"));
650      interface.setCapacity(25000000000ULL);
651    }
652    if(supported & SUPPORTED_25000baseSR_Full)
653    {
654      interface.addCapability("25000bt-fd", _("25Gbit/s (full duplex)"));
655      interface.setCapacity(25000000000ULL);
656    }
657    if(supported & (SUPPORTED_40000baseKR4_Full | SUPPORTED_40000baseCR4_Full |
658                    SUPPORTED_40000baseSR4_Full | SUPPORTED_40000baseLR4_Full))
659    {
660      interface.addCapability("40000bx-fd", _("40Gbit/s (full duplex)"));
661      interface.setCapacity(40000000000ULL);
662    }
663    if(supported & (SUPPORTED_50000baseCR2_Full | SUPPORTED_50000baseKR2_Full |
664                    SUPPORTED_50000baseSR2_Full))
665    {
666      interface.addCapability("50000bt-fd", _("50Gbit/s (full duplex)"));
667      interface.setCapacity(50000000000ULL);
668    }
669    if(supported & (SUPPORTED_56000baseCR4_Full | SUPPORTED_56000baseSR4_Full |
670                    SUPPORTED_56000baseLR4_Full | SUPPORTED_56000baseKR4_Full))
671    {
672      interface.addCapability("56000bt-fd", _("56Gbit/s (full duplex)"));
673      interface.setCapacity(56000000000ULL);
674    }
675    if(supported2 & (SUPPORTED2_100000baseKR4_Full | SUPPORTED2_100000baseSR4_Full |
676                     SUPPORTED2_100000baseCR4_Full | SUPPORTED2_100000baseLR4_ER4_Full))
677    {
678      interface.addCapability("100000bx-fd", _("100Gbit/s (full duplex)"));
679      interface.setCapacity(100000000000ULL);
680    }
681    if(supported & SUPPORTED_Autoneg)
682      interface.addCapability("autonegotiation", _("Auto-negotiation"));
683  
684    switch(speed)
685    {
686      case SPEED_10:
687        interface.setConfig("speed", "10Mbit/s");
688        interface.setSize(10000000ULL);
689        break;
690      case SPEED_100:
691        interface.setConfig("speed", "100Mbit/s");
692        interface.setSize(100000000ULL);
693        break;
694      case SPEED_1000:
695        interface.setConfig("speed", "1Gbit/s");
696        interface.setSize(1000000000ULL);
697        break;
698      case SPEED_2500:
699        interface.setConfig("speed", "2.5Gbit/s");
700        interface.setSize(2500000000ULL);
701        break;
702      case SPEED_5000:
703        interface.setConfig("speed", "5Gbit/s");
704        interface.setSize(5000000000ULL);
705        break;
706      case SPEED_10000:
707        interface.setConfig("speed", "10Gbit/s");
708        interface.setSize(10000000000ULL);
709        break;
710      case SPEED_25000:
711        interface.setConfig("speed", "25Gbit/s");
712        interface.setSize(25000000000ULL);
713        break;
714      case SPEED_40000:
715        interface.setConfig("speed", "40Gbit/s");
716        interface.setSize(40000000000ULL);
717        break;
718      case SPEED_100000:
719        interface.setConfig("speed", "100Gbit/s");
720        interface.setSize(100000000000ULL);
721        break;
722    }
723    switch(duplex)
724    {
725      case DUPLEX_HALF:
726        interface.setConfig("duplex", "half");
727        break;
728      case DUPLEX_FULL:
729        interface.setConfig("duplex", "full");
730        break;
731    }
732    switch(port)
733    {
734      case PORT_TP:
735        interface.setConfig("port", "twisted pair");
736        break;
737      case PORT_AUI:
738        interface.setConfig("port", "AUI");
739        break;
740      case PORT_BNC:
741        interface.setConfig("port", "BNC");
742        break;
743      case PORT_MII:
744        interface.setConfig("port", "MII");
745        break;
746      case PORT_FIBRE:
747        interface.setConfig("port", "fibre");
748        break;
749    }
750    interface.setConfig("autonegotiation", (autoneg == AUTONEG_DISABLE) ?  "off" : "on");
751  }
752  
753  
754  static void scan_modes(hwNode & interface, int fd)
755  {
756    struct ifreq ifr;
757    struct ethtool_cmd ecmd;
758    struct ethtool_link_settings elink;
759    s8 mask_size;
760  
761    elink.cmd = ETHTOOL_GLINKSETTINGS;
762    elink.link_mode_masks_nwords = 0;
763    memset(&ifr, 0, sizeof(ifr));
764    strcpy(ifr.ifr_name, interface.getLogicalName().c_str());
765    ifr.ifr_data = (caddr_t) &elink;
766    // Probe link mode mask count.
767    if (ioctl(fd, SIOCETHTOOL, &ifr) == 0)
768    {
769      mask_size = -elink.link_mode_masks_nwords;
770      if (mask_size > 1 && mask_size <= MAX_LINK_MODE_MASK_SIZE)
771      {
772        elink.cmd = ETHTOOL_GLINKSETTINGS;
773        elink.link_mode_masks_nwords = mask_size;
774        memset(&ifr, 0, sizeof(ifr));
775        strcpy(ifr.ifr_name, interface.getLogicalName().c_str());
776        ifr.ifr_data = (caddr_t) &elink;
777        // Read link mode settings.
778        if (ioctl(fd, SIOCETHTOOL, &ifr) == 0)
779        {
780          updateCapabilities(interface, elink.link_mode_masks[0], elink.link_mode_masks[1],
781            elink.speed, elink.duplex, elink.port, elink.autoneg);
782          return;
783        }
784      }
785    }
786  
787    ecmd.cmd = ETHTOOL_GSET;
788    memset(&ifr, 0, sizeof(ifr));
789    strcpy(ifr.ifr_name, interface.getLogicalName().c_str());
790    ifr.ifr_data = (caddr_t) &ecmd;
791    if (ioctl(fd, SIOCETHTOOL, &ifr) == 0)
792    {
793      updateCapabilities(interface, ecmd.supported, 0, ecmd.speed, ecmd.duplex, ecmd.port, ecmd.autoneg);
794    }
795  }
796  
797  
798  bool scan_network(hwNode & n)
799  {
800    vector < string > interfaces;
801    char buffer[2 * IFNAMSIZ + 1];
802  
803    if (!load_interfaces(interfaces))
804      return false;
805  
806    int fd = socket(PF_INET, SOCK_DGRAM, 0);
807  
808    if (fd >= 0)
809    {
810      struct ifreq ifr;
811      struct ethtool_drvinfo drvinfo;
812      struct ethtool_value edata;
813  
814      for (unsigned int i = 0; i < interfaces.size(); i++)
815      {
816        hwNode *existing;
817        hwNode interface("network",
818          hw::network);
819  
820        interface.setLogicalName(interfaces[i]);
821        interface.claim();
822        interface.addHint("icon", string("network"));
823  
824        string businfo = sysfs::entry::byClass("net", interface.getLogicalName()).leaf().businfo();
825        if (businfo!="")
826          interface.setBusInfo(businfo);
827        interface.setModalias(sysfs::entry::byClass("net", interface.getLogicalName()).leaf().modalias());
828  
829  //scan_mii(fd, interface);
830        scan_ip(interface);
831  
832        memset(&ifr, 0, sizeof(ifr));
833        strcpy(ifr.ifr_name, interfaces[i].c_str());
834        if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
835        {
836  #ifdef IFF_PORTSEL
837          if (ifr.ifr_flags & IFF_PORTSEL)
838          {
839            if (ifr.ifr_flags & IFF_AUTOMEDIA)
840              interface.setConfig("automedia", "yes");
841          }
842  #endif
843  
844          if (ifr.ifr_flags & IFF_UP)
845            interface.enable();
846          else
847            interface.disable();
848          if (ifr.ifr_flags & IFF_BROADCAST)
849            interface.setConfig("broadcast", "yes");
850          if (ifr.ifr_flags & IFF_DEBUG)
851            interface.setConfig("debug", "yes");
852          if (ifr.ifr_flags & IFF_LOOPBACK)
853            interface.setConfig("loopback", "yes");
854          if (ifr.ifr_flags & IFF_POINTOPOINT)
855            interface.setConfig("point-to-point", "yes");
856          if (ifr.ifr_flags & IFF_PROMISC)
857            interface.setConfig("promiscuous", "yes");
858          if (ifr.ifr_flags & IFF_SLAVE)
859            interface.setConfig("slave", "yes");
860          if (ifr.ifr_flags & IFF_MASTER)
861            interface.setConfig("master", "yes");
862          if (ifr.ifr_flags & IFF_MULTICAST)
863            interface.setConfig("multicast", "yes");
864        }
865  
866        memset(&ifr, 0, sizeof(ifr));
867        strcpy(ifr.ifr_name, interfaces[i].c_str());
868  // get MAC address
869        if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0)
870        {
871          string hwaddr = getmac((unsigned char *) ifr.ifr_hwaddr.sa_data, ifr.ifr_hwaddr.sa_family);
872          interface.addCapability(hwname(ifr.ifr_hwaddr.sa_family));
873          if (ifr.ifr_hwaddr.sa_family >= 256)
874            interface.addCapability("logical", _("Logical interface"));
875          else
876            interface.addCapability("physical", _("Physical interface"));
877          interface.setDescription(string(hwname(ifr.ifr_hwaddr.sa_family)) +
878            " interface");
879          interface.setSerial(hwaddr);
880  
881          if (isVirtual(interface.getSerial()))
882            interface.addCapability("logical", _("Logical interface"));
883        }
884  
885  // check for wireless extensions
886        memset(buffer, 0, sizeof(buffer));
887        strncpy(buffer, interfaces[i].c_str(), sizeof(buffer));
888        if (ioctl(fd, SIOCGIWNAME, &buffer) == 0)
889        {
890          interface.addCapability("wireless", _("Wireless-LAN"));
891          interface.setConfig("wireless", hw::strip(buffer + IFNAMSIZ));
892          interface.setDescription(_("Wireless interface"));
893          interface.addHint("icon", string("wifi"));
894          interface.addHint("bus.icon", string("radio"));
895        }
896  
897        edata.cmd = ETHTOOL_GLINK;
898        memset(&ifr, 0, sizeof(ifr));
899        strcpy(ifr.ifr_name, interfaces[i].c_str());
900        ifr.ifr_data = (caddr_t) &edata;
901        if (ioctl(fd, SIOCETHTOOL, &ifr) == 0)
902        {
903          interface.setConfig("link", edata.data ? "yes":"no");
904        }
905  
906        scan_modes(interface, fd);
907        scan_module(interface, fd);
908  
909        drvinfo.cmd = ETHTOOL_GDRVINFO;
910        memset(&ifr, 0, sizeof(ifr));
911        strcpy(ifr.ifr_name, interfaces[i].c_str());
912        ifr.ifr_data = (caddr_t) & drvinfo;
913        if (ioctl(fd, SIOCETHTOOL, &ifr) == 0)
914        {
915          interface.setConfig("driver", drvinfo.driver);
916          interface.setConfig("driverversion", drvinfo.version);
917          interface.setConfig("firmware", drvinfo.fw_version);
918          if (interface.getBusInfo() == "")
919            interface.setBusInfo(guessBusInfo(drvinfo.bus_info));
920        }
921  
922        if(sysfs::entry::byClass("net", interface.getLogicalName()).isvirtual())
923          interface.addCapability("logical", _("Logical interface"));
924  
925        existing = n.findChildByBusInfo(interface.getBusInfo());
926        // Multiple NICs can exist on one PCI function.
927  
928        if (existing && !existing->getBusInfo().empty() && (interface.getBusInfo() == existing->getBusInfo()) && interface.getProduct().empty())
929          interface.setProduct(existing->getProduct());
930  
931        // Only merge if MACs also match.
932        if (existing && (existing->getSerial() == "" || interface.getSerial() == existing->getSerial()))
933        {
934          existing->merge(interface);
935          if(interface.getDescription()!="")
936            existing->setDescription(interface.getDescription());
937        }
938        else
939        {
940          existing = n.findChildByLogicalName(interface.getLogicalName());
941          if (existing)
942          {
943            existing->merge(interface);
944          }
945          else
946          {
947  // we don't care about loopback and "logical" interfaces
948            if (!interface.isCapable("loopback") &&
949              !interface.isCapable("logical"))
950              n.addChild(interface);
951          }
952        }
953      }
954  
955      close(fd);
956      return true;
957    }
958    else
959      return false;
960  }