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