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