LCOV - code coverage report
Current view: top level - udev - udev-builtin-net_id.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 482 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 16 0.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : /*
       4             :  * Predictable network interface device names based on:
       5             :  *  - firmware/bios-provided index numbers for on-board devices
       6             :  *  - firmware-provided pci-express hotplug slot index number
       7             :  *  - physical/geographical location of the hardware
       8             :  *  - the interface's MAC address
       9             :  *
      10             :  * http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames
      11             :  *
      12             :  * When the code here is changed, man/systemd.net-naming-scheme.xml must be updated too.
      13             :  */
      14             : 
      15             : #include <errno.h>
      16             : #include <fcntl.h>
      17             : #include <net/if.h>
      18             : #include <net/if_arp.h>
      19             : #include <stdarg.h>
      20             : #include <stdio.h>
      21             : #include <stdlib.h>
      22             : #include <string.h>
      23             : #include <unistd.h>
      24             : #include <linux/pci_regs.h>
      25             : 
      26             : #include "alloc-util.h"
      27             : #include "dirent-util.h"
      28             : #include "fd-util.h"
      29             : #include "fileio.h"
      30             : #include "fs-util.h"
      31             : #include "naming-scheme.h"
      32             : #include "parse-util.h"
      33             : #include "proc-cmdline.h"
      34             : #include "stdio-util.h"
      35             : #include "string-util.h"
      36             : #include "strv.h"
      37             : #include "strxcpyx.h"
      38             : #include "udev-builtin.h"
      39             : 
      40             : #define ONBOARD_INDEX_MAX (16*1024-1)
      41             : 
      42             : enum netname_type{
      43             :         NET_UNDEF,
      44             :         NET_PCI,
      45             :         NET_USB,
      46             :         NET_BCMA,
      47             :         NET_VIRTIO,
      48             :         NET_CCW,
      49             :         NET_VIO,
      50             :         NET_PLATFORM,
      51             :         NET_NETDEVSIM,
      52             : };
      53             : 
      54             : struct netnames {
      55             :         enum netname_type type;
      56             : 
      57             :         uint8_t mac[6];
      58             :         bool mac_valid;
      59             : 
      60             :         sd_device *pcidev;
      61             :         char pci_slot[IFNAMSIZ];
      62             :         char pci_path[IFNAMSIZ];
      63             :         char pci_onboard[IFNAMSIZ];
      64             :         const char *pci_onboard_label;
      65             : 
      66             :         char usb_ports[IFNAMSIZ];
      67             :         char bcma_core[IFNAMSIZ];
      68             :         char ccw_busid[IFNAMSIZ];
      69             :         char vio_slot[IFNAMSIZ];
      70             :         char platform_path[IFNAMSIZ];
      71             :         char netdevsim_path[IFNAMSIZ];
      72             : };
      73             : 
      74             : struct virtfn_info {
      75             :         sd_device *physfn_pcidev;
      76             :         char suffix[IFNAMSIZ];
      77             : };
      78             : 
      79             : /* skip intermediate virtio devices */
      80           0 : static sd_device *skip_virtio(sd_device *dev) {
      81             :         sd_device *parent;
      82             : 
      83             :         /* there can only ever be one virtio bus per parent device, so we can
      84             :          * safely ignore any virtio buses. see
      85             :          * http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030331.html */
      86           0 :         for (parent = dev; parent; ) {
      87             :                 const char *subsystem;
      88             : 
      89           0 :                 if (sd_device_get_subsystem(parent, &subsystem) < 0)
      90           0 :                         break;
      91             : 
      92           0 :                 if (!streq(subsystem, "virtio"))
      93           0 :                         break;
      94             : 
      95           0 :                 if (sd_device_get_parent(parent, &parent) < 0)
      96           0 :                         return NULL;
      97             :         }
      98             : 
      99           0 :         return parent;
     100             : }
     101             : 
     102           0 : static int get_virtfn_info(sd_device *dev, struct netnames *names, struct virtfn_info *ret) {
     103           0 :         _cleanup_(sd_device_unrefp) sd_device *physfn_pcidev = NULL;
     104             :         const char *physfn_link_file, *syspath;
     105           0 :         _cleanup_free_ char *physfn_pci_syspath = NULL;
     106           0 :         _cleanup_free_ char *virtfn_pci_syspath = NULL;
     107             :         struct dirent *dent;
     108           0 :         _cleanup_closedir_ DIR *dir = NULL;
     109             :         char suffix[IFNAMSIZ];
     110             :         int r;
     111             : 
     112           0 :         assert(dev);
     113           0 :         assert(names);
     114           0 :         assert(ret);
     115             : 
     116           0 :         r = sd_device_get_syspath(names->pcidev, &syspath);
     117           0 :         if (r < 0)
     118           0 :                 return r;
     119             : 
     120             :         /* Check if this is a virtual function. */
     121           0 :         physfn_link_file = strjoina(syspath, "/physfn");
     122           0 :         r = chase_symlinks(physfn_link_file, NULL, 0, &physfn_pci_syspath);
     123           0 :         if (r < 0)
     124           0 :                 return r;
     125             : 
     126             :         /* Get physical function's pci device. */
     127           0 :         r = sd_device_new_from_syspath(&physfn_pcidev, physfn_pci_syspath);
     128           0 :         if (r < 0)
     129           0 :                 return r;
     130             : 
     131             :         /* Find the virtual function number by finding the right virtfn link. */
     132           0 :         dir = opendir(physfn_pci_syspath);
     133           0 :         if (!dir)
     134           0 :                 return -errno;
     135             : 
     136           0 :         FOREACH_DIRENT_ALL(dent, dir, break) {
     137           0 :                 _cleanup_free_ char *virtfn_link_file = NULL;
     138             : 
     139           0 :                 if (!startswith(dent->d_name, "virtfn"))
     140           0 :                         continue;
     141             : 
     142           0 :                 virtfn_link_file = path_join(physfn_pci_syspath, dent->d_name);
     143           0 :                 if (!virtfn_link_file)
     144           0 :                         return -ENOMEM;
     145             : 
     146           0 :                 if (chase_symlinks(virtfn_link_file, NULL, 0, &virtfn_pci_syspath) < 0)
     147           0 :                         continue;
     148             : 
     149           0 :                 if (streq(syspath, virtfn_pci_syspath)) {
     150           0 :                         if (!snprintf_ok(suffix, sizeof(suffix), "v%s", &dent->d_name[6]))
     151           0 :                                 return -ENOENT;
     152             : 
     153           0 :                         break;
     154             :                 }
     155             :         }
     156           0 :         if (isempty(suffix))
     157           0 :                 return -ENOENT;
     158             : 
     159           0 :         ret->physfn_pcidev = TAKE_PTR(physfn_pcidev);
     160           0 :         strncpy(ret->suffix, suffix, sizeof(ret->suffix));
     161             : 
     162           0 :         return 0;
     163             : }
     164             : 
     165             : /* retrieve on-board index number and label from firmware */
     166           0 : static int dev_pci_onboard(sd_device *dev, struct netnames *names) {
     167           0 :         unsigned long idx, dev_port = 0;
     168           0 :         const char *attr, *port_name = NULL;
     169             :         size_t l;
     170             :         char *s;
     171             :         int r;
     172             : 
     173             :         /* ACPI _DSM — device specific method for naming a PCI or PCI Express device */
     174           0 :         if (sd_device_get_sysattr_value(names->pcidev, "acpi_index", &attr) < 0) {
     175             :                 /* SMBIOS type 41 — Onboard Devices Extended Information */
     176           0 :                 r = sd_device_get_sysattr_value(names->pcidev, "index", &attr);
     177           0 :                 if (r < 0)
     178           0 :                         return r;
     179             :         }
     180             : 
     181           0 :         r = safe_atolu(attr, &idx);
     182           0 :         if (r < 0)
     183           0 :                 return r;
     184           0 :         if (idx == 0 && !naming_scheme_has(NAMING_ZERO_ACPI_INDEX))
     185           0 :                 return -EINVAL;
     186             : 
     187             :         /* Some BIOSes report rubbish indexes that are excessively high (2^24-1 is an index VMware likes to
     188             :          * report for example). Let's define a cut-off where we don't consider the index reliable anymore. We
     189             :          * pick some arbitrary cut-off, which is somewhere beyond the realistic number of physical network
     190             :          * interface a system might have. Ideally the kernel would already filter his crap for us, but it
     191             :          * doesn't currently. */
     192           0 :         if (idx > ONBOARD_INDEX_MAX)
     193           0 :                 return -ENOENT;
     194             : 
     195             :         /* kernel provided port index for multiple ports on a single PCI function */
     196           0 :         if (sd_device_get_sysattr_value(dev, "dev_port", &attr) >= 0)
     197           0 :                 dev_port = strtoul(attr, NULL, 10);
     198             : 
     199             :         /* kernel provided front panel port name for multiple port PCI device */
     200           0 :         (void) sd_device_get_sysattr_value(dev, "phys_port_name", &port_name);
     201             : 
     202           0 :         s = names->pci_onboard;
     203           0 :         l = sizeof(names->pci_onboard);
     204           0 :         l = strpcpyf(&s, l, "o%lu", idx);
     205           0 :         if (port_name)
     206           0 :                 l = strpcpyf(&s, l, "n%s", port_name);
     207           0 :         else if (dev_port > 0)
     208           0 :                 l = strpcpyf(&s, l, "d%lu", dev_port);
     209           0 :         if (l == 0)
     210           0 :                 names->pci_onboard[0] = '\0';
     211             : 
     212           0 :         if (sd_device_get_sysattr_value(names->pcidev, "label", &names->pci_onboard_label) < 0)
     213           0 :                 names->pci_onboard_label = NULL;
     214             : 
     215           0 :         return 0;
     216             : }
     217             : 
     218             : /* read the 256 bytes PCI configuration space to check the multi-function bit */
     219           0 : static bool is_pci_multifunction(sd_device *dev) {
     220           0 :         _cleanup_close_ int fd = -1;
     221             :         const char *filename, *syspath;
     222             :         uint8_t config[64];
     223             : 
     224           0 :         if (sd_device_get_syspath(dev, &syspath) < 0)
     225           0 :                 return false;
     226             : 
     227           0 :         filename = strjoina(syspath, "/config");
     228           0 :         fd = open(filename, O_RDONLY | O_CLOEXEC);
     229           0 :         if (fd < 0)
     230           0 :                 return false;
     231           0 :         if (read(fd, &config, sizeof(config)) != sizeof(config))
     232           0 :                 return false;
     233             : 
     234             :         /* bit 0-6 header type, bit 7 multi/single function device */
     235           0 :         return config[PCI_HEADER_TYPE] & 0x80;
     236             : }
     237             : 
     238           0 : static bool is_pci_ari_enabled(sd_device *dev) {
     239             :         const char *a;
     240             : 
     241           0 :         if (sd_device_get_sysattr_value(dev, "ari_enabled", &a) < 0)
     242           0 :                 return false;
     243             : 
     244           0 :         return streq(a, "1");
     245             : }
     246             : 
     247           0 : static int dev_pci_slot(sd_device *dev, struct netnames *names) {
     248           0 :         unsigned long dev_port = 0;
     249           0 :         unsigned domain, bus, slot, func, hotplug_slot = 0;
     250             :         size_t l;
     251             :         char *s;
     252           0 :         const char *sysname, *attr, *port_name = NULL, *syspath;
     253           0 :         _cleanup_(sd_device_unrefp) sd_device *pci = NULL;
     254             :         sd_device *hotplug_slot_dev;
     255             :         char slots[PATH_MAX];
     256           0 :         _cleanup_closedir_ DIR *dir = NULL;
     257             :         struct dirent *dent;
     258             :         int r;
     259             : 
     260           0 :         r = sd_device_get_sysname(names->pcidev, &sysname);
     261           0 :         if (r < 0)
     262           0 :                 return r;
     263             : 
     264           0 :         if (sscanf(sysname, "%x:%x:%x.%u", &domain, &bus, &slot, &func) != 4)
     265           0 :                 return -ENOENT;
     266             : 
     267           0 :         if (naming_scheme_has(NAMING_NPAR_ARI) &&
     268           0 :             is_pci_ari_enabled(names->pcidev))
     269             :                 /* ARI devices support up to 256 functions on a single device ("slot"), and interpret the
     270             :                  * traditional 5-bit slot and 3-bit function number as a single 8-bit function number,
     271             :                  * where the slot makes up the upper 5 bits. */
     272           0 :                 func += slot * 8;
     273             : 
     274             :         /* kernel provided port index for multiple ports on a single PCI function */
     275           0 :         if (sd_device_get_sysattr_value(dev, "dev_port", &attr) >= 0) {
     276           0 :                 dev_port = strtoul(attr, NULL, 10);
     277             :                 /* With older kernels IP-over-InfiniBand network interfaces sometimes erroneously
     278             :                  * provide the port number in the 'dev_id' sysfs attribute instead of 'dev_port',
     279             :                  * which thus stays initialized as 0. */
     280           0 :                 if (dev_port == 0 &&
     281           0 :                     sd_device_get_sysattr_value(dev, "type", &attr) >= 0) {
     282             :                         unsigned long type;
     283             : 
     284           0 :                         type = strtoul(attr, NULL, 10);
     285           0 :                         if (type == ARPHRD_INFINIBAND &&
     286           0 :                             sd_device_get_sysattr_value(dev, "dev_id", &attr) >= 0)
     287           0 :                                 dev_port = strtoul(attr, NULL, 16);
     288             :                 }
     289             :         }
     290             : 
     291             :         /* kernel provided front panel port name for multi-port PCI device */
     292           0 :         (void) sd_device_get_sysattr_value(dev, "phys_port_name", &port_name);
     293             : 
     294             :         /* compose a name based on the raw kernel's PCI bus, slot numbers */
     295           0 :         s = names->pci_path;
     296           0 :         l = sizeof(names->pci_path);
     297           0 :         if (domain > 0)
     298           0 :                 l = strpcpyf(&s, l, "P%u", domain);
     299           0 :         l = strpcpyf(&s, l, "p%us%u", bus, slot);
     300           0 :         if (func > 0 || is_pci_multifunction(names->pcidev))
     301           0 :                 l = strpcpyf(&s, l, "f%u", func);
     302           0 :         if (port_name)
     303           0 :                 l = strpcpyf(&s, l, "n%s", port_name);
     304           0 :         else if (dev_port > 0)
     305           0 :                 l = strpcpyf(&s, l, "d%lu", dev_port);
     306           0 :         if (l == 0)
     307           0 :                 names->pci_path[0] = '\0';
     308             : 
     309             :         /* ACPI _SUN — slot user number */
     310           0 :         r = sd_device_new_from_subsystem_sysname(&pci, "subsystem", "pci");
     311           0 :         if (r < 0)
     312           0 :                 return r;
     313             : 
     314           0 :         r = sd_device_get_syspath(pci, &syspath);
     315           0 :         if (r < 0)
     316           0 :                 return r;
     317           0 :         if (!snprintf_ok(slots, sizeof slots, "%s/slots", syspath))
     318           0 :                 return -ENAMETOOLONG;
     319             : 
     320           0 :         dir = opendir(slots);
     321           0 :         if (!dir)
     322           0 :                 return -errno;
     323             : 
     324           0 :         hotplug_slot_dev = names->pcidev;
     325           0 :         while (hotplug_slot_dev) {
     326           0 :                 if (sd_device_get_sysname(hotplug_slot_dev, &sysname) < 0)
     327           0 :                         continue;
     328             : 
     329           0 :                 FOREACH_DIRENT_ALL(dent, dir, break) {
     330             :                         unsigned i;
     331             :                         char str[PATH_MAX];
     332           0 :                         _cleanup_free_ char *address = NULL;
     333             : 
     334           0 :                         if (dent->d_name[0] == '.')
     335           0 :                                 continue;
     336           0 :                         r = safe_atou_full(dent->d_name, 10, &i);
     337           0 :                         if (r < 0 || i <= 0)
     338           0 :                                 continue;
     339             : 
     340             :                         /* match slot address with device by stripping the function */
     341           0 :                         if (snprintf_ok(str, sizeof str, "%s/%s/address", slots, dent->d_name) &&
     342           0 :                             read_one_line_file(str, &address) >= 0 &&
     343           0 :                             startswith(sysname, address)) {
     344           0 :                                 hotplug_slot = i;
     345           0 :                                 break;
     346             :                         }
     347             :                 }
     348           0 :                 if (hotplug_slot > 0)
     349           0 :                         break;
     350           0 :                 if (sd_device_get_parent_with_subsystem_devtype(hotplug_slot_dev, "pci", NULL, &hotplug_slot_dev) < 0)
     351           0 :                         break;
     352           0 :                 rewinddir(dir);
     353             :         }
     354             : 
     355           0 :         if (hotplug_slot > 0) {
     356           0 :                 s = names->pci_slot;
     357           0 :                 l = sizeof(names->pci_slot);
     358           0 :                 if (domain > 0)
     359           0 :                         l = strpcpyf(&s, l, "P%d", domain);
     360           0 :                 l = strpcpyf(&s, l, "s%d", hotplug_slot);
     361           0 :                 if (func > 0 || is_pci_multifunction(names->pcidev))
     362           0 :                         l = strpcpyf(&s, l, "f%d", func);
     363           0 :                 if (port_name)
     364           0 :                         l = strpcpyf(&s, l, "n%s", port_name);
     365           0 :                 else if (dev_port > 0)
     366           0 :                         l = strpcpyf(&s, l, "d%lu", dev_port);
     367           0 :                 if (l == 0)
     368           0 :                         names->pci_slot[0] = '\0';
     369             :         }
     370             : 
     371           0 :         return 0;
     372             : }
     373             : 
     374           0 : static int names_vio(sd_device *dev, struct netnames *names) {
     375             :         sd_device *parent;
     376             :         unsigned busid, slotid, ethid;
     377             :         const char *syspath, *subsystem;
     378             :         int r;
     379             : 
     380             :         /* check if our direct parent is a VIO device with no other bus in-between */
     381           0 :         r = sd_device_get_parent(dev, &parent);
     382           0 :         if (r < 0)
     383           0 :                 return r;
     384             : 
     385           0 :         r = sd_device_get_subsystem(parent, &subsystem);
     386           0 :         if (r < 0)
     387           0 :                 return r;
     388           0 :         if (!streq("vio", subsystem))
     389           0 :                 return -ENOENT;
     390             : 
     391             :         /* The devices' $DEVPATH number is tied to (virtual) hardware (slot id
     392             :          * selected in the HMC), thus this provides a reliable naming (e.g.
     393             :          * "/devices/vio/30000002/net/eth1"); we ignore the bus number, as
     394             :          * there should only ever be one bus, and then remove leading zeros. */
     395           0 :         r = sd_device_get_syspath(dev, &syspath);
     396           0 :         if (r < 0)
     397           0 :                 return r;
     398             : 
     399           0 :         if (sscanf(syspath, "/sys/devices/vio/%4x%4x/net/eth%u", &busid, &slotid, &ethid) != 3)
     400           0 :                 return -EINVAL;
     401             : 
     402           0 :         xsprintf(names->vio_slot, "v%u", slotid);
     403           0 :         names->type = NET_VIO;
     404           0 :         return 0;
     405             : }
     406             : 
     407             : #define _PLATFORM_TEST "/sys/devices/platform/vvvvPPPP"
     408             : #define _PLATFORM_PATTERN4 "/sys/devices/platform/%4s%4x:%2x/net/eth%u"
     409             : #define _PLATFORM_PATTERN3 "/sys/devices/platform/%3s%4x:%2x/net/eth%u"
     410             : 
     411           0 : static int names_platform(sd_device *dev, struct netnames *names, bool test) {
     412             :         sd_device *parent;
     413             :         char vendor[5];
     414             :         unsigned model, instance, ethid;
     415             :         const char *syspath, *pattern, *validchars, *subsystem;
     416             :         int r;
     417             : 
     418             :         /* check if our direct parent is a platform device with no other bus in-between */
     419           0 :         r = sd_device_get_parent(dev, &parent);
     420           0 :         if (r < 0)
     421           0 :                 return r;
     422             : 
     423           0 :         r = sd_device_get_subsystem(parent, &subsystem);
     424           0 :         if (r < 0)
     425           0 :                 return r;
     426             : 
     427           0 :         if (!streq("platform", subsystem))
     428           0 :                  return -ENOENT;
     429             : 
     430           0 :         r = sd_device_get_syspath(dev, &syspath);
     431           0 :         if (r < 0)
     432           0 :                 return r;
     433             : 
     434             :         /* syspath is too short, to have a valid ACPI instance */
     435           0 :         if (strlen(syspath) < sizeof _PLATFORM_TEST)
     436           0 :                 return -EINVAL;
     437             : 
     438             :         /* Vendor ID can be either PNP ID (3 chars A-Z) or ACPI ID (4 chars A-Z and numerals) */
     439           0 :         if (syspath[sizeof _PLATFORM_TEST - 1] == ':') {
     440           0 :                 pattern = _PLATFORM_PATTERN4;
     441           0 :                 validchars = UPPERCASE_LETTERS DIGITS;
     442             :         } else {
     443           0 :                 pattern = _PLATFORM_PATTERN3;
     444           0 :                 validchars = UPPERCASE_LETTERS;
     445             :         }
     446             : 
     447             :         /* Platform devices are named after ACPI table match, and instance id
     448             :          * eg. "/sys/devices/platform/HISI00C2:00");
     449             :          * The Vendor (3 or 4 char), followed by hexdecimal model number : instance id.
     450             :          */
     451             : 
     452             : #pragma GCC diagnostic push
     453             : #pragma GCC diagnostic ignored "-Wformat-nonliteral"
     454           0 :         if (sscanf(syspath, pattern, vendor, &model, &instance, &ethid) != 4)
     455           0 :                 return -EINVAL;
     456             : #pragma GCC diagnostic pop
     457             : 
     458           0 :         if (!in_charset(vendor, validchars))
     459           0 :                 return -ENOENT;
     460             : 
     461           0 :         ascii_strlower(vendor);
     462             : 
     463           0 :         xsprintf(names->platform_path, "a%s%xi%u", vendor, model, instance);
     464           0 :         names->type = NET_PLATFORM;
     465           0 :         return 0;
     466             : }
     467             : 
     468           0 : static int names_pci(sd_device *dev, struct netnames *names) {
     469             :         sd_device *parent;
     470           0 :         struct netnames vf_names = {};
     471           0 :         struct virtfn_info vf_info = {};
     472             :         const char *subsystem;
     473             :         int r;
     474             : 
     475           0 :         assert(dev);
     476           0 :         assert(names);
     477             : 
     478           0 :         r = sd_device_get_parent(dev, &parent);
     479           0 :         if (r < 0)
     480           0 :                 return r;
     481             :         /* skip virtio subsystem if present */
     482           0 :         parent = skip_virtio(parent);
     483             : 
     484           0 :         if (!parent)
     485           0 :                 return -ENOENT;
     486             : 
     487             :         /* check if our direct parent is a PCI device with no other bus in-between */
     488           0 :         if (sd_device_get_subsystem(parent, &subsystem) >= 0 &&
     489           0 :             streq("pci", subsystem)) {
     490           0 :                 names->type = NET_PCI;
     491           0 :                 names->pcidev = parent;
     492             :         } else {
     493           0 :                 r = sd_device_get_parent_with_subsystem_devtype(dev, "pci", NULL, &names->pcidev);
     494           0 :                 if (r < 0)
     495           0 :                         return r;
     496             :         }
     497             : 
     498           0 :         if (naming_scheme_has(NAMING_SR_IOV_V) &&
     499           0 :             get_virtfn_info(dev, names, &vf_info) >= 0) {
     500             :                 /* If this is an SR-IOV virtual device, get base name using physical device and add virtfn suffix. */
     501           0 :                 vf_names.pcidev = vf_info.physfn_pcidev;
     502           0 :                 dev_pci_onboard(dev, &vf_names);
     503           0 :                 dev_pci_slot(dev, &vf_names);
     504           0 :                 if (vf_names.pci_onboard[0])
     505           0 :                         if (strlen(vf_names.pci_onboard) + strlen(vf_info.suffix) < sizeof(names->pci_onboard))
     506           0 :                                 strscpyl(names->pci_onboard, sizeof(names->pci_onboard),
     507             :                                          vf_names.pci_onboard, vf_info.suffix, NULL);
     508           0 :                 if (vf_names.pci_slot[0])
     509           0 :                         if (strlen(vf_names.pci_slot) + strlen(vf_info.suffix) < sizeof(names->pci_slot))
     510           0 :                                 strscpyl(names->pci_slot, sizeof(names->pci_slot),
     511             :                                          vf_names.pci_slot, vf_info.suffix, NULL);
     512           0 :                 if (vf_names.pci_path[0])
     513           0 :                         if (strlen(vf_names.pci_path) + strlen(vf_info.suffix) < sizeof(names->pci_path))
     514           0 :                                 strscpyl(names->pci_path, sizeof(names->pci_path),
     515             :                                          vf_names.pci_path, vf_info.suffix, NULL);
     516           0 :                 sd_device_unref(vf_info.physfn_pcidev);
     517             :         } else {
     518           0 :                 dev_pci_onboard(dev, names);
     519           0 :                 dev_pci_slot(dev, names);
     520             :         }
     521             : 
     522           0 :         return 0;
     523             : }
     524             : 
     525           0 : static int names_usb(sd_device *dev, struct netnames *names) {
     526             :         sd_device *usbdev;
     527             :         char name[256], *ports, *config, *interf, *s;
     528             :         const char *sysname;
     529             :         size_t l;
     530             :         int r;
     531             : 
     532           0 :         assert(dev);
     533           0 :         assert(names);
     534             : 
     535           0 :         r = sd_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface", &usbdev);
     536           0 :         if (r < 0)
     537           0 :                 return r;
     538             : 
     539           0 :         r = sd_device_get_sysname(usbdev, &sysname);
     540           0 :         if (r < 0)
     541           0 :                 return r;
     542             : 
     543             :         /* get USB port number chain, configuration, interface */
     544           0 :         strscpy(name, sizeof(name), sysname);
     545           0 :         s = strchr(name, '-');
     546           0 :         if (!s)
     547           0 :                 return -EINVAL;
     548           0 :         ports = s+1;
     549             : 
     550           0 :         s = strchr(ports, ':');
     551           0 :         if (!s)
     552           0 :                 return -EINVAL;
     553           0 :         s[0] = '\0';
     554           0 :         config = s+1;
     555             : 
     556           0 :         s = strchr(config, '.');
     557           0 :         if (!s)
     558           0 :                 return -EINVAL;
     559           0 :         s[0] = '\0';
     560           0 :         interf = s+1;
     561             : 
     562             :         /* prefix every port number in the chain with "u" */
     563           0 :         s = ports;
     564           0 :         while ((s = strchr(s, '.')))
     565           0 :                 s[0] = 'u';
     566           0 :         s = names->usb_ports;
     567           0 :         l = strpcpyl(&s, sizeof(names->usb_ports), "u", ports, NULL);
     568             : 
     569             :         /* append USB config number, suppress the common config == 1 */
     570           0 :         if (!streq(config, "1"))
     571           0 :                 l = strpcpyl(&s, sizeof(names->usb_ports), "c", config, NULL);
     572             : 
     573             :         /* append USB interface number, suppress the interface == 0 */
     574           0 :         if (!streq(interf, "0"))
     575           0 :                 l = strpcpyl(&s, sizeof(names->usb_ports), "i", interf, NULL);
     576           0 :         if (l == 0)
     577           0 :                 return -ENAMETOOLONG;
     578             : 
     579           0 :         names->type = NET_USB;
     580           0 :         return 0;
     581             : }
     582             : 
     583           0 : static int names_bcma(sd_device *dev, struct netnames *names) {
     584             :         sd_device *bcmadev;
     585             :         unsigned core;
     586             :         const char *sysname;
     587             :         int r;
     588             : 
     589           0 :         assert(dev);
     590           0 :         assert(names);
     591             : 
     592           0 :         r = sd_device_get_parent_with_subsystem_devtype(dev, "bcma", NULL, &bcmadev);
     593           0 :         if (r < 0)
     594           0 :                 return r;
     595             : 
     596           0 :         r = sd_device_get_sysname(bcmadev, &sysname);
     597           0 :         if (r < 0)
     598           0 :                 return r;
     599             : 
     600             :         /* bus num:core num */
     601           0 :         if (sscanf(sysname, "bcma%*u:%u", &core) != 1)
     602           0 :                 return -EINVAL;
     603             :         /* suppress the common core == 0 */
     604           0 :         if (core > 0)
     605           0 :                 xsprintf(names->bcma_core, "b%u", core);
     606             : 
     607           0 :         names->type = NET_BCMA;
     608           0 :         return 0;
     609             : }
     610             : 
     611           0 : static int names_ccw(sd_device *dev, struct netnames *names) {
     612             :         sd_device *cdev;
     613             :         const char *bus_id, *subsys;
     614             :         size_t bus_id_len;
     615             :         size_t bus_id_start;
     616             :         int r;
     617             : 
     618           0 :         assert(dev);
     619           0 :         assert(names);
     620             : 
     621             :         /* Retrieve the associated CCW device */
     622           0 :         r = sd_device_get_parent(dev, &cdev);
     623           0 :         if (r < 0)
     624           0 :                 return r;
     625             : 
     626             :         /* skip virtio subsystem if present */
     627           0 :         cdev = skip_virtio(cdev);
     628           0 :         if (!cdev)
     629           0 :                 return -ENOENT;
     630             : 
     631           0 :         r = sd_device_get_subsystem(cdev, &subsys);
     632           0 :         if (r < 0)
     633           0 :                 return r;
     634             : 
     635             :         /* Network devices are either single or grouped CCW devices */
     636           0 :         if (!STR_IN_SET(subsys, "ccwgroup", "ccw"))
     637           0 :                 return -ENOENT;
     638             : 
     639             :         /* Retrieve bus-ID of the CCW device.  The bus-ID uniquely
     640             :          * identifies the network device on the Linux on System z channel
     641             :          * subsystem.  Note that the bus-ID contains lowercase characters.
     642             :          */
     643           0 :         r = sd_device_get_sysname(cdev, &bus_id);
     644           0 :         if (r < 0)
     645           0 :                 return r;
     646             : 
     647             :         /* Check the length of the bus-ID. Rely on the fact that the kernel provides a correct bus-ID;
     648             :          * alternatively, improve this check and parse and verify each bus-ID part...
     649             :          */
     650           0 :         bus_id_len = strlen(bus_id);
     651           0 :         if (!IN_SET(bus_id_len, 8, 9))
     652           0 :                 return -EINVAL;
     653             : 
     654             :         /* Strip leading zeros from the bus id for aesthetic purposes. This
     655             :          * keeps the ccw names stable, yet much shorter in general case of
     656             :          * bus_id 0.0.0600 -> 600. This is similar to e.g. how PCI domain is
     657             :          * not prepended when it is zero. Preserve the last 0 for 0.0.0000.
     658             :          */
     659           0 :         bus_id_start = strspn(bus_id, ".0");
     660           0 :         bus_id += bus_id_start < bus_id_len ? bus_id_start : bus_id_len - 1;
     661             : 
     662             :         /* Store the CCW bus-ID for use as network device name */
     663           0 :         if (snprintf_ok(names->ccw_busid, sizeof(names->ccw_busid), "c%s", bus_id))
     664           0 :                 names->type = NET_CCW;
     665             : 
     666           0 :         return 0;
     667             : }
     668             : 
     669           0 : static int names_mac(sd_device *dev, struct netnames *names) {
     670             :         const char *s;
     671             :         unsigned long i;
     672             :         unsigned a1, a2, a3, a4, a5, a6;
     673             :         int r;
     674             : 
     675             :         /* Some kinds of devices tend to have hardware addresses
     676             :          * that are impossible to use in an iface name.
     677             :          */
     678           0 :         r = sd_device_get_sysattr_value(dev, "type", &s);
     679           0 :         if (r < 0)
     680           0 :                 return r;
     681             : 
     682           0 :         i = strtoul(s, NULL, 0);
     683           0 :         switch (i) {
     684             :         /* The persistent part of a hardware address of an InfiniBand NIC
     685             :          * is 8 bytes long. We cannot fit this much in an iface name.
     686             :          */
     687           0 :         case ARPHRD_INFINIBAND:
     688           0 :                 return -EINVAL;
     689           0 :         default:
     690           0 :                 break;
     691             :         }
     692             : 
     693             :         /* check for NET_ADDR_PERM, skip random MAC addresses */
     694           0 :         r = sd_device_get_sysattr_value(dev, "addr_assign_type", &s);
     695           0 :         if (r < 0)
     696           0 :                 return r;
     697           0 :         i = strtoul(s, NULL, 0);
     698           0 :         if (i != 0)
     699           0 :                 return 0;
     700             : 
     701           0 :         r = sd_device_get_sysattr_value(dev, "address", &s);
     702           0 :         if (r < 0)
     703           0 :                 return r;
     704           0 :         if (sscanf(s, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6)
     705           0 :                 return -EINVAL;
     706             : 
     707             :         /* skip empty MAC addresses */
     708           0 :         if (a1 + a2 + a3 + a4 + a5 + a6 == 0)
     709           0 :                 return -EINVAL;
     710             : 
     711           0 :         names->mac[0] = a1;
     712           0 :         names->mac[1] = a2;
     713           0 :         names->mac[2] = a3;
     714           0 :         names->mac[3] = a4;
     715           0 :         names->mac[4] = a5;
     716           0 :         names->mac[5] = a6;
     717           0 :         names->mac_valid = true;
     718           0 :         return 0;
     719             : }
     720             : 
     721           0 : static int names_netdevsim(sd_device *dev, struct netnames *names) {
     722             :         sd_device *netdevsimdev;
     723             :         const char *sysname;
     724             :         unsigned addr;
     725           0 :         const char *port_name = NULL;
     726             :         int r;
     727             :         bool ok;
     728             : 
     729           0 :         if (!naming_scheme_has(NAMING_NETDEVSIM))
     730           0 :                 return 0;
     731             : 
     732           0 :         assert(dev);
     733           0 :         assert(names);
     734             : 
     735           0 :         r = sd_device_get_parent_with_subsystem_devtype(dev, "netdevsim", NULL, &netdevsimdev);
     736           0 :         if (r < 0)
     737           0 :                 return r;
     738           0 :         r = sd_device_get_sysname(netdevsimdev, &sysname);
     739           0 :         if (r < 0)
     740           0 :                 return r;
     741             : 
     742           0 :         if (sscanf(sysname, "netdevsim%u", &addr) != 1)
     743           0 :                 return -EINVAL;
     744             : 
     745           0 :         r = sd_device_get_sysattr_value(dev, "phys_port_name", &port_name);
     746           0 :         if (r < 0)
     747           0 :                 return r;
     748             : 
     749           0 :         ok = snprintf_ok(names->netdevsim_path, sizeof(names->netdevsim_path), "i%un%s", addr, port_name);
     750           0 :         if (!ok)
     751           0 :                 return -ENOBUFS;
     752             : 
     753           0 :         names->type = NET_NETDEVSIM;
     754             : 
     755           0 :         return 0;
     756             : }
     757             : 
     758             : /* IEEE Organizationally Unique Identifier vendor string */
     759           0 : static int ieee_oui(sd_device *dev, struct netnames *names, bool test) {
     760             :         char str[32];
     761             : 
     762           0 :         if (!names->mac_valid)
     763           0 :                 return -ENOENT;
     764             :         /* skip commonly misused 00:00:00 (Xerox) prefix */
     765           0 :         if (memcmp(names->mac, "\0\0\0", 3) == 0)
     766           0 :                 return -EINVAL;
     767           0 :         xsprintf(str, "OUI:%02X%02X%02X%02X%02X%02X", names->mac[0],
     768             :                  names->mac[1], names->mac[2], names->mac[3], names->mac[4],
     769             :                  names->mac[5]);
     770           0 :         udev_builtin_hwdb_lookup(dev, NULL, str, NULL, test);
     771           0 :         return 0;
     772             : }
     773             : 
     774           0 : static int builtin_net_id(sd_device *dev, int argc, char *argv[], bool test) {
     775           0 :         const char *s, *p, *devtype, *prefix = "en";
     776           0 :         struct netnames names = {};
     777             :         unsigned long i;
     778             :         int r;
     779             : 
     780             :         /* handle only ARPHRD_ETHER, ARPHRD_SLIP and ARPHRD_INFINIBAND devices */
     781           0 :         r = sd_device_get_sysattr_value(dev, "type", &s);
     782           0 :         if (r < 0)
     783           0 :                 return r;
     784             : 
     785           0 :         i = strtoul(s, NULL, 0);
     786           0 :         switch (i) {
     787           0 :         case ARPHRD_ETHER:
     788           0 :                 prefix = "en";
     789           0 :                 break;
     790           0 :         case ARPHRD_INFINIBAND:
     791           0 :                 if (naming_scheme_has(NAMING_INFINIBAND))
     792           0 :                         prefix = "ib";
     793             :                 else
     794           0 :                         return 0;
     795           0 :                 break;
     796           0 :         case ARPHRD_SLIP:
     797           0 :                 prefix = "sl";
     798           0 :                 break;
     799           0 :         default:
     800           0 :                 return 0;
     801             :         }
     802             : 
     803             :         /* skip stacked devices, like VLANs, ... */
     804           0 :         r = sd_device_get_sysattr_value(dev, "ifindex", &s);
     805           0 :         if (r < 0)
     806           0 :                 return r;
     807           0 :         r = sd_device_get_sysattr_value(dev, "iflink", &p);
     808           0 :         if (r < 0)
     809           0 :                 return r;
     810           0 :         if (!streq(s, p))
     811           0 :                 return 0;
     812             : 
     813           0 :         if (sd_device_get_devtype(dev, &devtype) >= 0) {
     814           0 :                 if (streq("wlan", devtype))
     815           0 :                         prefix = "wl";
     816           0 :                 else if (streq("wwan", devtype))
     817           0 :                         prefix = "ww";
     818             :         }
     819             : 
     820           0 :         udev_builtin_add_property(dev, test, "ID_NET_NAMING_SCHEME", naming_scheme()->name);
     821             : 
     822           0 :         r = names_mac(dev, &names);
     823           0 :         if (r >= 0 && names.mac_valid) {
     824             :                 char str[IFNAMSIZ];
     825             : 
     826           0 :                 xsprintf(str, "%sx%02x%02x%02x%02x%02x%02x", prefix,
     827             :                          names.mac[0], names.mac[1], names.mac[2],
     828             :                          names.mac[3], names.mac[4], names.mac[5]);
     829           0 :                 udev_builtin_add_property(dev, test, "ID_NET_NAME_MAC", str);
     830             : 
     831           0 :                 ieee_oui(dev, &names, test);
     832             :         }
     833             : 
     834             :         /* get path names for Linux on System z network devices */
     835           0 :         if (names_ccw(dev, &names) >= 0 && names.type == NET_CCW) {
     836             :                 char str[IFNAMSIZ];
     837             : 
     838           0 :                 if (snprintf_ok(str, sizeof str, "%s%s", prefix, names.ccw_busid))
     839           0 :                         udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
     840           0 :                 return 0;
     841             :         }
     842             : 
     843             :         /* get ibmveth/ibmvnic slot-based names. */
     844           0 :         if (names_vio(dev, &names) >= 0 && names.type == NET_VIO) {
     845             :                 char str[IFNAMSIZ];
     846             : 
     847           0 :                 if (snprintf_ok(str, sizeof str, "%s%s", prefix, names.vio_slot))
     848           0 :                         udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
     849           0 :                 return 0;
     850             :         }
     851             : 
     852             :         /* get ACPI path names for ARM64 platform devices */
     853           0 :         if (names_platform(dev, &names, test) >= 0 && names.type == NET_PLATFORM) {
     854             :                 char str[IFNAMSIZ];
     855             : 
     856           0 :                 if (snprintf_ok(str, sizeof str, "%s%s", prefix, names.platform_path))
     857           0 :                         udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
     858           0 :                 return 0;
     859             :         }
     860             : 
     861             :         /* get netdevsim path names */
     862           0 :         if (names_netdevsim(dev, &names) >= 0 && names.type == NET_NETDEVSIM) {
     863             :                 char str[IFNAMSIZ];
     864             : 
     865           0 :                 if (snprintf_ok(str, sizeof str, "%s%s", prefix, names.netdevsim_path))
     866           0 :                         udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
     867             : 
     868           0 :                 return 0;
     869             :         }
     870             : 
     871             :         /* get PCI based path names, we compose only PCI based paths */
     872           0 :         if (names_pci(dev, &names) < 0)
     873           0 :                 return 0;
     874             : 
     875             :         /* plain PCI device */
     876           0 :         if (names.type == NET_PCI) {
     877             :                 char str[IFNAMSIZ];
     878             : 
     879           0 :                 if (names.pci_onboard[0] &&
     880           0 :                     snprintf_ok(str, sizeof str, "%s%s", prefix, names.pci_onboard))
     881           0 :                         udev_builtin_add_property(dev, test, "ID_NET_NAME_ONBOARD", str);
     882             : 
     883           0 :                 if (names.pci_onboard_label &&
     884           0 :                     snprintf_ok(str, sizeof str, "%s%s",
     885             :                                 naming_scheme_has(NAMING_LABEL_NOPREFIX) ? "" : prefix,
     886             :                                 names.pci_onboard_label))
     887           0 :                         udev_builtin_add_property(dev, test, "ID_NET_LABEL_ONBOARD", str);
     888             : 
     889           0 :                 if (names.pci_path[0] &&
     890           0 :                     snprintf_ok(str, sizeof str, "%s%s", prefix, names.pci_path))
     891           0 :                         udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
     892             : 
     893           0 :                 if (names.pci_slot[0] &&
     894           0 :                     snprintf_ok(str, sizeof str, "%s%s", prefix, names.pci_slot))
     895           0 :                         udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
     896           0 :                 return 0;
     897             :         }
     898             : 
     899             :         /* USB device */
     900           0 :         if (names_usb(dev, &names) >= 0 && names.type == NET_USB) {
     901             :                 char str[IFNAMSIZ];
     902             : 
     903           0 :                 if (names.pci_path[0] &&
     904           0 :                     snprintf_ok(str, sizeof str, "%s%s%s", prefix, names.pci_path, names.usb_ports))
     905           0 :                         udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
     906             : 
     907           0 :                 if (names.pci_slot[0] &&
     908           0 :                     snprintf_ok(str, sizeof str, "%s%s%s", prefix, names.pci_slot, names.usb_ports))
     909           0 :                         udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
     910           0 :                 return 0;
     911             :         }
     912             : 
     913             :         /* Broadcom bus */
     914           0 :         if (names_bcma(dev, &names) >= 0 && names.type == NET_BCMA) {
     915             :                 char str[IFNAMSIZ];
     916             : 
     917           0 :                 if (names.pci_path[0] &&
     918           0 :                     snprintf_ok(str, sizeof str, "%s%s%s", prefix, names.pci_path, names.bcma_core))
     919           0 :                         udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
     920             : 
     921           0 :                 if (names.pci_slot[0] &&
     922           0 :                     snprintf(str, sizeof str, "%s%s%s", prefix, names.pci_slot, names.bcma_core))
     923           0 :                         udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
     924           0 :                 return 0;
     925             :         }
     926             : 
     927           0 :         return 0;
     928             : }
     929             : 
     930             : const UdevBuiltin udev_builtin_net_id = {
     931             :         .name = "net_id",
     932             :         .cmd = builtin_net_id,
     933             :         .help = "Network device properties",
     934             : };

Generated by: LCOV version 1.14