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