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