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