1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2012 Kay Sievers <kay@vrfy.org>
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.
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.
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/>.
22 * Predictable network interface device names based on:
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
28 * http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames
30 * Two character prefixes based on the type of interface:
32 * sl — serial line IP (slip)
37 * b<number> — BCMA bus core number
38 * c<bus_id> — bus id of a grouped CCW or CCW device,
39 * with all leading zeros stripped [s390]
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
44 * x<MAC> — MAC address
45 * [P<domain>]p<bus>s<slot>[f<function>][n<phys_port_name>|d<dev_port>]
46 * — PCI geographical location
47 * [P<domain>]p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
48 * — USB port number chain
49 * v<slot> - VIO slot number (IBM PowerVM)
50 * a<vendor><model>i<instance> — Platform bus ACPI instance id
52 * All multi-function PCI devices will carry the [f<function>] number in the
53 * device name, including the function 0 device.
55 * When using PCI geography, The PCI domain is only prepended when it is not 0.
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
60 * The usual USB configuration == 1 and interface == 0 values are suppressed.
62 * PCI Ethernet card with firmware index "1":
63 * ID_NET_NAME_ONBOARD=eno1
64 * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
66 * PCI Ethernet card in hotplug slot with firmware index number:
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
70 * ID_NET_NAME_SLOT=ens1
72 * PCI Ethernet multi-function card with 2 ports:
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
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
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
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
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
104 #include <net/if_arp.h>
110 #include <linux/pci_regs.h>
112 #include "dirent-util.h"
115 #include "stdio-util.h"
116 #include "string-util.h"
119 #define ONBOARD_INDEX_MAX (16*1024-1)
133 enum netname_type type
;
138 struct udev_device
*pcidev
;
139 char pci_slot
[IFNAMSIZ
];
140 char pci_path
[IFNAMSIZ
];
141 char pci_onboard
[IFNAMSIZ
];
142 const char *pci_onboard_label
;
144 char usb_ports
[IFNAMSIZ
];
145 char bcma_core
[IFNAMSIZ
];
146 char ccw_busid
[IFNAMSIZ
];
147 char vio_slot
[IFNAMSIZ
];
148 char platform_path
[IFNAMSIZ
];
151 /* skip intermediate virtio devices */
152 static struct udev_device
*skip_virtio(struct udev_device
*dev
) {
153 struct udev_device
*parent
= dev
;
155 /* there can only ever be one virtio bus per parent device, so we can
156 safely ignore any virtio buses. see
157 <http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030331.html> */
158 while (parent
&& streq_ptr("virtio", udev_device_get_subsystem(parent
)))
159 parent
= udev_device_get_parent(parent
);
163 /* retrieve on-board index number and label from firmware */
164 static int dev_pci_onboard(struct udev_device
*dev
, struct netnames
*names
) {
165 unsigned dev_port
= 0;
168 const char *attr
, *port_name
;
171 /* ACPI _DSM — device specific method for naming a PCI or PCI Express device */
172 attr
= udev_device_get_sysattr_value(names
->pcidev
, "acpi_index");
173 /* SMBIOS type 41 — Onboard Devices Extended Information */
175 attr
= udev_device_get_sysattr_value(names
->pcidev
, "index");
179 idx
= strtoul(attr
, NULL
, 0);
183 /* Some BIOSes report rubbish indexes that are excessively high (2^24-1 is an index VMware likes to report for
184 * example). Let's define a cut-off where we don't consider the index reliable anymore. We pick some arbitrary
185 * cut-off, which is somewhere beyond the realistic number of physical network interface a system might
186 * have. Ideally the kernel would already filter his crap for us, but it doesn't currently. */
187 if (idx
> ONBOARD_INDEX_MAX
)
190 /* kernel provided port index for multiple ports on a single PCI function */
191 attr
= udev_device_get_sysattr_value(dev
, "dev_port");
193 dev_port
= strtol(attr
, NULL
, 10);
195 /* kernel provided front panel port name for multiple port PCI device */
196 port_name
= udev_device_get_sysattr_value(dev
, "phys_port_name");
198 s
= names
->pci_onboard
;
199 l
= sizeof(names
->pci_onboard
);
200 l
= strpcpyf(&s
, l
, "o%d", idx
);
202 l
= strpcpyf(&s
, l
, "n%s", port_name
);
203 else if (dev_port
> 0)
204 l
= strpcpyf(&s
, l
, "d%d", dev_port
);
206 names
->pci_onboard
[0] = '\0';
208 names
->pci_onboard_label
= udev_device_get_sysattr_value(names
->pcidev
, "label");
213 /* read the 256 bytes PCI configuration space to check the multi-function bit */
214 static bool is_pci_multifunction(struct udev_device
*dev
) {
215 _cleanup_close_
int fd
= -1;
216 const char *filename
;
219 filename
= strjoina(udev_device_get_syspath(dev
), "/config");
220 fd
= open(filename
, O_RDONLY
| O_CLOEXEC
);
223 if (read(fd
, &config
, sizeof(config
)) != sizeof(config
))
226 /* bit 0-6 header type, bit 7 multi/single function device */
227 if ((config
[PCI_HEADER_TYPE
] & 0x80) != 0)
233 static int dev_pci_slot(struct udev_device
*dev
, struct netnames
*names
) {
234 struct udev
*udev
= udev_device_get_udev(names
->pcidev
);
235 unsigned domain
, bus
, slot
, func
, dev_port
= 0;
238 const char *attr
, *port_name
;
239 struct udev_device
*pci
= NULL
;
240 char slots
[PATH_MAX
];
241 _cleanup_closedir_
DIR *dir
= NULL
;
243 int hotplug_slot
= 0, err
= 0;
245 if (sscanf(udev_device_get_sysname(names
->pcidev
), "%x:%x:%x.%u", &domain
, &bus
, &slot
, &func
) != 4)
248 /* kernel provided port index for multiple ports on a single PCI function */
249 attr
= udev_device_get_sysattr_value(dev
, "dev_port");
251 dev_port
= strtol(attr
, NULL
, 10);
253 /* kernel provided front panel port name for multiple port PCI device */
254 port_name
= udev_device_get_sysattr_value(dev
, "phys_port_name");
256 /* compose a name based on the raw kernel's PCI bus, slot numbers */
258 l
= sizeof(names
->pci_path
);
260 l
= strpcpyf(&s
, l
, "P%u", domain
);
261 l
= strpcpyf(&s
, l
, "p%us%u", bus
, slot
);
262 if (func
> 0 || is_pci_multifunction(names
->pcidev
))
263 l
= strpcpyf(&s
, l
, "f%u", func
);
265 l
= strpcpyf(&s
, l
, "n%s", port_name
);
266 else if (dev_port
> 0)
267 l
= strpcpyf(&s
, l
, "d%u", dev_port
);
269 names
->pci_path
[0] = '\0';
271 /* ACPI _SUN — slot user number */
272 pci
= udev_device_new_from_subsystem_sysname(udev
, "subsystem", "pci");
278 xsprintf(slots
, "%s/slots", udev_device_get_syspath(pci
));
279 dir
= opendir(slots
);
285 FOREACH_DIRENT_ALL(dent
, dir
, break) {
287 char *rest
, *address
, str
[PATH_MAX
];
289 if (dent
->d_name
[0] == '.')
291 i
= strtol(dent
->d_name
, &rest
, 10);
297 xsprintf(str
, "%s/%s/address", slots
, dent
->d_name
);
298 if (read_one_line_file(str
, &address
) >= 0) {
299 /* match slot address with device by stripping the function */
300 if (strneq(address
, udev_device_get_sysname(names
->pcidev
), strlen(address
)))
305 if (hotplug_slot
> 0)
309 if (hotplug_slot
> 0) {
311 l
= sizeof(names
->pci_slot
);
313 l
= strpcpyf(&s
, l
, "P%d", domain
);
314 l
= strpcpyf(&s
, l
, "s%d", hotplug_slot
);
315 if (func
> 0 || is_pci_multifunction(names
->pcidev
))
316 l
= strpcpyf(&s
, l
, "f%d", func
);
318 l
= strpcpyf(&s
, l
, "n%s", port_name
);
319 else if (dev_port
> 0)
320 l
= strpcpyf(&s
, l
, "d%d", dev_port
);
322 names
->pci_slot
[0] = '\0';
325 udev_device_unref(pci
);
329 static int names_vio(struct udev_device
*dev
, struct netnames
*names
) {
330 struct udev_device
*parent
;
331 unsigned busid
, slotid
, ethid
;
334 /* check if our direct parent is a VIO device with no other bus in-between */
335 parent
= udev_device_get_parent(dev
);
339 if (!streq_ptr("vio", udev_device_get_subsystem(parent
)))
342 /* The devices' $DEVPATH number is tied to (virtual) hardware (slot id
343 * selected in the HMC), thus this provides a reliable naming (e.g.
344 * "/devices/vio/30000002/net/eth1"); we ignore the bus number, as
345 * there should only ever be one bus, and then remove leading zeros. */
346 syspath
= udev_device_get_syspath(dev
);
348 if (sscanf(syspath
, "/sys/devices/vio/%4x%4x/net/eth%u", &busid
, &slotid
, ðid
) != 3)
351 xsprintf(names
->vio_slot
, "v%u", slotid
);
352 names
->type
= NET_VIO
;
356 #define _PLATFORM_TEST "/sys/devices/platform/vvvvPPPP"
357 #define _PLATFORM_PATTERN4 "/sys/devices/platform/%4s%4x:%2x/net/eth%u"
358 #define _PLATFORM_PATTERN3 "/sys/devices/platform/%3s%4x:%2x/net/eth%u"
360 static int names_platform(struct udev_device
*dev
, struct netnames
*names
, bool test
) {
361 struct udev_device
*parent
;
363 unsigned model
, instance
, ethid
;
364 const char *syspath
, *pattern
, *validchars
;
366 /* check if our direct parent is a platform device with no other bus in-between */
367 parent
= udev_device_get_parent(dev
);
371 if (!streq_ptr("platform", udev_device_get_subsystem(parent
)))
374 syspath
= udev_device_get_syspath(dev
);
376 /* syspath is too short, to have a valid ACPI instance */
377 if (strlen(syspath
) < sizeof _PLATFORM_TEST
)
380 /* Vendor ID can be either PNP ID (3 chars A-Z) or ACPI ID (4 chars A-Z and numerals) */
381 if (syspath
[sizeof _PLATFORM_TEST
- 1] == ':') {
382 pattern
= _PLATFORM_PATTERN4
;
383 validchars
= UPPERCASE_LETTERS DIGITS
;
385 pattern
= _PLATFORM_PATTERN3
;
386 validchars
= UPPERCASE_LETTERS
;
389 /* Platform devices are named after ACPI table match, and instance id
390 * eg. "/sys/devices/platform/HISI00C2:00");
391 * The Vendor (3 or 4 char), followed by hexdecimal model number : instance id.
394 #pragma GCC diagnostic push
395 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
396 if (sscanf(syspath
, pattern
, vendor
, &model
, &instance
, ðid
) != 4)
398 #pragma GCC diagnostic pop
400 if (!in_charset(vendor
, validchars
))
403 ascii_strlower(vendor
);
405 xsprintf(names
->platform_path
, "a%s%xi%u", vendor
, model
, instance
);
406 names
->type
= NET_PLATFORM
;
410 static int names_pci(struct udev_device
*dev
, struct netnames
*names
) {
411 struct udev_device
*parent
;
416 parent
= udev_device_get_parent(dev
);
417 /* skip virtio subsystem if present */
418 parent
= skip_virtio(parent
);
423 /* check if our direct parent is a PCI device with no other bus in-between */
424 if (streq_ptr("pci", udev_device_get_subsystem(parent
))) {
425 names
->type
= NET_PCI
;
426 names
->pcidev
= parent
;
428 names
->pcidev
= udev_device_get_parent_with_subsystem_devtype(dev
, "pci", NULL
);
432 dev_pci_onboard(dev
, names
);
433 dev_pci_slot(dev
, names
);
437 static int names_usb(struct udev_device
*dev
, struct netnames
*names
) {
438 struct udev_device
*usbdev
;
449 usbdev
= udev_device_get_parent_with_subsystem_devtype(dev
, "usb", "usb_interface");
453 /* get USB port number chain, configuration, interface */
454 strscpy(name
, sizeof(name
), udev_device_get_sysname(usbdev
));
455 s
= strchr(name
, '-');
460 s
= strchr(ports
, ':');
466 s
= strchr(config
, '.');
472 /* prefix every port number in the chain with "u" */
474 while ((s
= strchr(s
, '.')))
476 s
= names
->usb_ports
;
477 l
= strpcpyl(&s
, sizeof(names
->usb_ports
), "u", ports
, NULL
);
479 /* append USB config number, suppress the common config == 1 */
480 if (!streq(config
, "1"))
481 l
= strpcpyl(&s
, sizeof(names
->usb_ports
), "c", config
, NULL
);
483 /* append USB interface number, suppress the interface == 0 */
484 if (!streq(interf
, "0"))
485 l
= strpcpyl(&s
, sizeof(names
->usb_ports
), "i", interf
, NULL
);
487 return -ENAMETOOLONG
;
489 names
->type
= NET_USB
;
493 static int names_bcma(struct udev_device
*dev
, struct netnames
*names
) {
494 struct udev_device
*bcmadev
;
500 bcmadev
= udev_device_get_parent_with_subsystem_devtype(dev
, "bcma", NULL
);
504 /* bus num:core num */
505 if (sscanf(udev_device_get_sysname(bcmadev
), "bcma%*u:%u", &core
) != 1)
507 /* suppress the common core == 0 */
509 xsprintf(names
->bcma_core
, "b%u", core
);
511 names
->type
= NET_BCMA
;
515 static int names_ccw(struct udev_device
*dev
, struct netnames
*names
) {
516 struct udev_device
*cdev
;
517 const char *bus_id
, *subsys
;
525 /* Retrieve the associated CCW device */
526 cdev
= udev_device_get_parent(dev
);
527 /* skip virtio subsystem if present */
528 cdev
= skip_virtio(cdev
);
532 /* Network devices are either single or grouped CCW devices */
533 subsys
= udev_device_get_subsystem(cdev
);
534 if (!STRPTR_IN_SET(subsys
, "ccwgroup", "ccw"))
537 /* Retrieve bus-ID of the CCW device. The bus-ID uniquely
538 * identifies the network device on the Linux on System z channel
539 * subsystem. Note that the bus-ID contains lowercase characters.
541 bus_id
= udev_device_get_sysname(cdev
);
545 /* Check the length of the bus-ID. Rely on that the kernel provides
546 * a correct bus-ID; alternatively, improve this check and parse and
547 * verify each bus-ID part...
549 bus_id_len
= strlen(bus_id
);
550 if (!bus_id_len
|| bus_id_len
< 8 || bus_id_len
> 9)
553 /* Strip leading zeros from the bus id for aesthetic purposes. This
554 * keeps the ccw names stable, yet much shorter in general case of
555 * bus_id 0.0.0600 -> 600. This is similar to e.g. how PCI domain is
556 * not prepended when it is zero. Preserve the last 0 for 0.0.0000.
558 bus_id_start
= strspn(bus_id
, ".0");
559 bus_id
+= bus_id_start
< bus_id_len
? bus_id_start
: bus_id_len
- 1;
561 /* Store the CCW bus-ID for use as network device name */
562 rc
= snprintf(names
->ccw_busid
, sizeof(names
->ccw_busid
), "c%s", bus_id
);
563 if (rc
>= 0 && rc
< (int)sizeof(names
->ccw_busid
))
564 names
->type
= NET_CCW
;
568 static int names_mac(struct udev_device
*dev
, struct netnames
*names
) {
571 unsigned int a1
, a2
, a3
, a4
, a5
, a6
;
573 /* check for NET_ADDR_PERM, skip random MAC addresses */
574 s
= udev_device_get_sysattr_value(dev
, "addr_assign_type");
577 i
= strtoul(s
, NULL
, 0);
581 s
= udev_device_get_sysattr_value(dev
, "address");
584 if (sscanf(s
, "%x:%x:%x:%x:%x:%x", &a1
, &a2
, &a3
, &a4
, &a5
, &a6
) != 6)
587 /* skip empty MAC addresses */
588 if (a1
+ a2
+ a3
+ a4
+ a5
+ a6
== 0)
597 names
->mac_valid
= true;
601 /* IEEE Organizationally Unique Identifier vendor string */
602 static int ieee_oui(struct udev_device
*dev
, struct netnames
*names
, bool test
) {
605 if (!names
->mac_valid
)
607 /* skip commonly misused 00:00:00 (Xerox) prefix */
608 if (memcmp(names
->mac
, "\0\0\0", 3) == 0)
610 xsprintf(str
, "OUI:%02X%02X%02X%02X%02X%02X", names
->mac
[0],
611 names
->mac
[1], names
->mac
[2], names
->mac
[3], names
->mac
[4],
613 udev_builtin_hwdb_lookup(dev
, NULL
, str
, NULL
, test
);
617 static int builtin_net_id(struct udev_device
*dev
, int argc
, char *argv
[], bool test
) {
622 const char *prefix
= "en";
623 struct netnames names
= {};
626 /* handle only ARPHRD_ETHER and ARPHRD_SLIP devices */
627 s
= udev_device_get_sysattr_value(dev
, "type");
630 i
= strtoul(s
, NULL
, 0);
642 /* skip stacked devices, like VLANs, ... */
643 s
= udev_device_get_sysattr_value(dev
, "ifindex");
646 p
= udev_device_get_sysattr_value(dev
, "iflink");
652 devtype
= udev_device_get_devtype(dev
);
654 if (streq("wlan", devtype
))
656 else if (streq("wwan", devtype
))
660 err
= names_mac(dev
, &names
);
661 if (err
>= 0 && names
.mac_valid
) {
664 xsprintf(str
, "%sx%02x%02x%02x%02x%02x%02x", prefix
,
665 names
.mac
[0], names
.mac
[1], names
.mac
[2],
666 names
.mac
[3], names
.mac
[4], names
.mac
[5]);
667 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_MAC", str
);
669 ieee_oui(dev
, &names
, test
);
672 /* get path names for Linux on System z network devices */
673 err
= names_ccw(dev
, &names
);
674 if (err
>= 0 && names
.type
== NET_CCW
) {
677 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.ccw_busid
) < (int)sizeof(str
))
678 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
682 /* get ibmveth/ibmvnic slot-based names. */
683 err
= names_vio(dev
, &names
);
684 if (err
>= 0 && names
.type
== NET_VIO
) {
687 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.vio_slot
) < (int)sizeof(str
))
688 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
692 /* get ACPI path names for ARM64 platform devices */
693 err
= names_platform(dev
, &names
, test
);
694 if (err
>= 0 && names
.type
== NET_PLATFORM
) {
697 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.platform_path
) < (int)sizeof(str
))
698 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
702 /* get PCI based path names, we compose only PCI based paths */
703 err
= names_pci(dev
, &names
);
707 /* plain PCI device */
708 if (names
.type
== NET_PCI
) {
711 if (names
.pci_onboard
[0])
712 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.pci_onboard
) < (int)sizeof(str
))
713 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_ONBOARD", str
);
715 if (names
.pci_onboard_label
)
716 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.pci_onboard_label
) < (int)sizeof(str
))
717 udev_builtin_add_property(dev
, test
, "ID_NET_LABEL_ONBOARD", str
);
719 if (names
.pci_path
[0])
720 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.pci_path
) < (int)sizeof(str
))
721 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
723 if (names
.pci_slot
[0])
724 if (snprintf(str
, sizeof(str
), "%s%s", prefix
, names
.pci_slot
) < (int)sizeof(str
))
725 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
730 err
= names_usb(dev
, &names
);
731 if (err
>= 0 && names
.type
== NET_USB
) {
734 if (names
.pci_path
[0])
735 if (snprintf(str
, sizeof(str
), "%s%s%s", prefix
, names
.pci_path
, names
.usb_ports
) < (int)sizeof(str
))
736 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
738 if (names
.pci_slot
[0])
739 if (snprintf(str
, sizeof(str
), "%s%s%s", prefix
, names
.pci_slot
, names
.usb_ports
) < (int)sizeof(str
))
740 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
745 err
= names_bcma(dev
, &names
);
746 if (err
>= 0 && names
.type
== NET_BCMA
) {
749 if (names
.pci_path
[0])
750 if (snprintf(str
, sizeof(str
), "%s%s%s", prefix
, names
.pci_path
, names
.bcma_core
) < (int)sizeof(str
))
751 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_PATH", str
);
753 if (names
.pci_slot
[0])
754 if (snprintf(str
, sizeof(str
), "%s%s%s", prefix
, names
.pci_slot
, names
.bcma_core
) < (int)sizeof(str
))
755 udev_builtin_add_property(dev
, test
, "ID_NET_NAME_SLOT", str
);
762 const struct udev_builtin udev_builtin_net_id
= {
764 .cmd
= builtin_net_id
,
765 .help
= "Network device properties",