]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev/udev-builtin-net_id.c
Merge pull request #2409 from snakeroot/dropin-doc-2
[thirdparty/systemd.git] / src / udev / udev-builtin-net_id.c
CommitLineData
3f65d731
ZJS
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
a660c63c
KS
3/***
4 This file is part of systemd.
5
6 Copyright 2012 Kay Sievers <kay@vrfy.org>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
d23965a6 22/*
ad37f393 23 * Predictable network interface device names based on:
472780d8
KS
24 * - firmware/bios-provided index numbers for on-board devices
25 * - firmware-provided pci-express hotplug slot index number
26 * - physical/geographical location of the hardware
27 * - the interface's MAC address
28 *
25da63b9
KS
29 * http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames
30 *
ad37f393 31 * Two character prefixes based on the type of interface:
a8eaaee7 32 * en -- Ethernet
e0d4a0ac 33 * sl -- serial line IP (slip)
0035597a
KS
34 * wl -- wlan
35 * ww -- wwan
d23965a6 36 *
ad37f393 37 * Type of names:
d4b687c9
KS
38 * b<number> -- BCMA bus core number
39 * ccw<name> -- CCW bus group name
c0a43734 40 * o<index>[d<dev_port>] -- on-board device index number
3058e017 41 * s<slot>[f<function>][d<dev_port>] -- hotplug slot index number
1328f66a 42 * x<MAC> -- MAC address
3058e017 43 * [P<domain>]p<bus>s<slot>[f<function>][d<dev_port>]
214daa72
SM
44 * -- PCI geographical location
45 * [P<domain>]p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
1328f66a 46 * -- USB port number chain
472780d8 47 *
ad37f393 48 * All multi-function PCI devices will carry the [f<function>] number in the
472780d8 49 * device name, including the function 0 device.
d23965a6 50 *
214daa72
SM
51 * When using PCI geography, The PCI domain is only prepended when it is not 0.
52 *
0d6ce923
KS
53 * For USB devices the full chain of port numbers of hubs is composed. If the
54 * name gets longer than the maximum number of 15 characters, the name is not
55 * exported.
56 * The usual USB configuration == 1 and interface == 0 values are suppressed.
ad37f393 57 *
a8eaaee7 58 * PCI Ethernet card with firmware index "1":
0035597a 59 * ID_NET_NAME_ONBOARD=eno1
f610d6de
KS
60 * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
61 *
a8eaaee7 62 * PCI Ethernet card in hotplug slot with firmware index number:
f610d6de
KS
63 * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
64 * ID_NET_NAME_MAC=enx000000000466
65 * ID_NET_NAME_PATH=enp5s0
de892aea 66 * ID_NET_NAME_SLOT=ens1
f610d6de 67 *
a8eaaee7 68 * PCI Ethernet multi-function card with 2 ports:
decd634e
KS
69 * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0
70 * ID_NET_NAME_MAC=enx78e7d1ea46da
71 * ID_NET_NAME_PATH=enp2s0f0
72 * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/net/enp2s0f1
73 * ID_NET_NAME_MAC=enx78e7d1ea46dc
74 * ID_NET_NAME_PATH=enp2s0f1
75 *
f610d6de
KS
76 * PCI wlan card:
77 * /sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0
78 * ID_NET_NAME_MAC=wlx0024d7e31130
79 * ID_NET_NAME_PATH=wlp3s0
80 *
81 * USB built-in 3G modem:
82 * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
83 * ID_NET_NAME_MAC=wwx028037ec0200
84 * ID_NET_NAME_PATH=wwp0s29u1u4i6
85 *
86 * USB Android phone:
87 * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2
88 * ID_NET_NAME_MAC=enxd626b3450fb5
89 * ID_NET_NAME_PATH=enp0s29u1u2
d23965a6
KS
90 */
91
a660c63c 92#include <errno.h>
07630cea 93#include <fcntl.h>
02609440 94#include <net/if.h>
19aa72f7 95#include <net/if_arp.h>
07630cea
LP
96#include <stdarg.h>
97#include <stdio.h>
98#include <stdlib.h>
99#include <string.h>
100#include <unistd.h>
de892aea 101#include <linux/pci_regs.h>
a660c63c 102
3ffd4af2 103#include "fd-util.h"
a5c32cff 104#include "fileio.h"
d054f0a4 105#include "stdio-util.h"
07630cea
LP
106#include "string-util.h"
107#include "udev.h"
a660c63c 108
02609440
KS
109enum netname_type{
110 NET_UNDEF,
111 NET_PCI,
112 NET_USB,
984c4348 113 NET_BCMA,
e3d56334 114 NET_VIRTIO,
e0d4a0ac 115 NET_CCWGROUP,
02609440
KS
116};
117
118struct netnames {
119 enum netname_type type;
120
121 uint8_t mac[6];
122 bool mac_valid;
123
124 struct udev_device *pcidev;
125 char pci_slot[IFNAMSIZ];
126 char pci_path[IFNAMSIZ];
127 char pci_onboard[IFNAMSIZ];
128 const char *pci_onboard_label;
129
02609440 130 char usb_ports[IFNAMSIZ];
984c4348 131 char bcma_core[IFNAMSIZ];
d4b687c9 132 char ccw_group[IFNAMSIZ];
02609440
KS
133};
134
0035597a 135/* retrieve on-board index number and label from firmware */
02609440 136static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
c0a43734
TG
137 unsigned dev_port = 0;
138 size_t l;
139 char *s;
140 const char *attr;
0035597a 141 int idx;
a660c63c 142
0035597a 143 /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */
c0a43734 144 attr = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
01d183dd 145 /* SMBIOS type 41 -- Onboard Devices Extended Information */
c0a43734
TG
146 if (!attr)
147 attr = udev_device_get_sysattr_value(names->pcidev, "index");
148 if (!attr)
0035597a 149 return -ENOENT;
c0a43734
TG
150
151 idx = strtoul(attr, NULL, 0);
0035597a
KS
152 if (idx <= 0)
153 return -EINVAL;
c0a43734 154
309b578d 155 /* kernel provided port index for multiple ports on a single PCI function */
c0a43734
TG
156 attr = udev_device_get_sysattr_value(dev, "dev_port");
157 if (attr)
158 dev_port = strtol(attr, NULL, 10);
159
160 s = names->pci_onboard;
161 l = sizeof(names->pci_onboard);
162 l = strpcpyf(&s, l, "o%d", idx);
163 if (dev_port > 0)
164 l = strpcpyf(&s, l, "d%d", dev_port);
165 if (l == 0)
166 names->pci_onboard[0] = '\0';
d23965a6 167
02609440 168 names->pci_onboard_label = udev_device_get_sysattr_value(names->pcidev, "label");
c0a43734 169
0035597a
KS
170 return 0;
171}
d23965a6 172
137661d8 173/* read the 256 bytes PCI configuration space to check the multi-function bit */
1328f66a 174static bool is_pci_multifunction(struct udev_device *dev) {
0454229c 175 _cleanup_close_ int fd = -1;
1cb5d1f3
LP
176 const char *filename;
177 uint8_t config[64];
de892aea 178
63c372cb 179 filename = strjoina(udev_device_get_syspath(dev), "/config");
0454229c
JM
180 fd = open(filename, O_RDONLY | O_CLOEXEC);
181 if (fd < 0)
1cb5d1f3 182 return false;
0454229c 183 if (read(fd, &config, sizeof(config)) != sizeof(config))
1cb5d1f3 184 return false;
de892aea
KS
185
186 /* bit 0-6 header type, bit 7 multi/single function device */
1328f66a 187 if ((config[PCI_HEADER_TYPE] & 0x80) != 0)
1cb5d1f3
LP
188 return true;
189
190 return false;
de892aea
KS
191}
192
02609440
KS
193static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
194 struct udev *udev = udev_device_get_udev(names->pcidev);
3058e017 195 unsigned domain, bus, slot, func, dev_port = 0;
1328f66a
KS
196 size_t l;
197 char *s;
198 const char *attr;
0035597a 199 struct udev_device *pci = NULL;
b5dd8148
ZJS
200 char slots[256], str[256];
201 _cleanup_closedir_ DIR *dir = NULL;
0035597a 202 struct dirent *dent;
b5dd8148 203 int hotplug_slot = 0, err = 0;
0035597a 204
b5dd8148 205 if (sscanf(udev_device_get_sysname(names->pcidev), "%x:%x:%x.%u", &domain, &bus, &slot, &func) != 4)
0035597a 206 return -ENOENT;
1328f66a 207
309b578d 208 /* kernel provided port index for multiple ports on a single PCI function */
3058e017 209 attr = udev_device_get_sysattr_value(dev, "dev_port");
1328f66a 210 if (attr)
3058e017 211 dev_port = strtol(attr, NULL, 10);
1328f66a
KS
212
213 /* compose a name based on the raw kernel's PCI bus, slot numbers */
214 s = names->pci_path;
214daa72
SM
215 l = sizeof(names->pci_path);
216 if (domain > 0)
1fa2f38f
ZJS
217 l = strpcpyf(&s, l, "P%u", domain);
218 l = strpcpyf(&s, l, "p%us%u", bus, slot);
1328f66a 219 if (func > 0 || is_pci_multifunction(names->pcidev))
1fa2f38f 220 l = strpcpyf(&s, l, "f%u", func);
3058e017 221 if (dev_port > 0)
1fa2f38f 222 l = strpcpyf(&s, l, "d%u", dev_port);
1328f66a
KS
223 if (l == 0)
224 names->pci_path[0] = '\0';
d23965a6 225
0035597a
KS
226 /* ACPI _SUN -- slot user number */
227 pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
228 if (!pci) {
229 err = -ENOENT;
230 goto out;
231 }
d054f0a4 232 xsprintf(slots, "%s/slots", udev_device_get_syspath(pci));
0035597a
KS
233 dir = opendir(slots);
234 if (!dir) {
235 err = -errno;
236 goto out;
d23965a6
KS
237 }
238
0035597a
KS
239 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
240 int i;
241 char *rest;
242 char *address;
243
244 if (dent->d_name[0] == '.')
245 continue;
246 i = strtol(dent->d_name, &rest, 10);
247 if (rest[0] != '\0')
248 continue;
249 if (i < 1)
250 continue;
d054f0a4 251 xsprintf(str, "%s/%s/address", slots, dent->d_name);
0035597a
KS
252 if (read_one_line_file(str, &address) >= 0) {
253 /* match slot address with device by stripping the function */
641906e9 254 if (strneq(address, udev_device_get_sysname(names->pcidev), strlen(address)))
0035597a
KS
255 hotplug_slot = i;
256 free(address);
257 }
258
259 if (hotplug_slot > 0)
260 break;
261 }
d23965a6 262
0035597a 263 if (hotplug_slot > 0) {
1328f66a 264 s = names->pci_slot;
214daa72
SM
265 l = sizeof(names->pci_slot);
266 if (domain > 0)
267 l = strpcpyf(&s, l, "P%d", domain);
268 l = strpcpyf(&s, l, "s%d", hotplug_slot);
1328f66a 269 if (func > 0 || is_pci_multifunction(names->pcidev))
d5a89d7d 270 l = strpcpyf(&s, l, "f%d", func);
3058e017
TLSC
271 if (dev_port > 0)
272 l = strpcpyf(&s, l, "d%d", dev_port);
1328f66a 273 if (l == 0)
16f948cb 274 names->pci_slot[0] = '\0';
d23965a6 275 }
0035597a
KS
276out:
277 udev_device_unref(pci);
278 return err;
279}
280
02609440 281static int names_pci(struct udev_device *dev, struct netnames *names) {
5b8180d3 282 struct udev_device *parent;
0035597a 283
3b64e4d4
TG
284 assert(dev);
285 assert(names);
286
5b8180d3 287 parent = udev_device_get_parent(dev);
54683f0f
TG
288
289 /* there can only ever be one virtio bus per parent device, so we can
290 safely ignore any virtio buses. see
291 <http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030331.html> */
292 while (parent && streq_ptr("virtio", udev_device_get_subsystem(parent)))
293 parent = udev_device_get_parent(parent);
294
02609440
KS
295 if (!parent)
296 return -ENOENT;
54683f0f 297
02609440 298 /* check if our direct parent is a PCI device with no other bus in-between */
bb26309d 299 if (streq_ptr("pci", udev_device_get_subsystem(parent))) {
02609440
KS
300 names->type = NET_PCI;
301 names->pcidev = parent;
302 } else {
303 names->pcidev = udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
304 if (!names->pcidev)
305 return -ENOENT;
306 }
307 dev_pci_onboard(dev, names);
308 dev_pci_slot(dev, names);
309 return 0;
310}
311
312static int names_usb(struct udev_device *dev, struct netnames *names) {
984c4348 313 struct udev_device *usbdev;
02609440
KS
314 char name[256];
315 char *ports;
316 char *config;
317 char *interf;
318 size_t l;
319 char *s;
320
3b64e4d4
TG
321 assert(dev);
322 assert(names);
323
984c4348
KS
324 usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
325 if (!usbdev)
0035597a
KS
326 return -ENOENT;
327
02609440 328 /* get USB port number chain, configuration, interface */
984c4348 329 strscpy(name, sizeof(name), udev_device_get_sysname(usbdev));
02609440
KS
330 s = strchr(name, '-');
331 if (!s)
332 return -EINVAL;
333 ports = s+1;
334
335 s = strchr(ports, ':');
336 if (!s)
337 return -EINVAL;
338 s[0] = '\0';
339 config = s+1;
340
341 s = strchr(config, '.');
342 if (!s)
343 return -EINVAL;
344 s[0] = '\0';
345 interf = s+1;
346
f7340ab2 347 /* prefix every port number in the chain with "u" */
02609440
KS
348 s = ports;
349 while ((s = strchr(s, '.')))
350 s[0] = 'u';
351 s = names->usb_ports;
d5a89d7d 352 l = strpcpyl(&s, sizeof(names->usb_ports), "u", ports, NULL);
02609440
KS
353
354 /* append USB config number, suppress the common config == 1 */
355 if (!streq(config, "1"))
d5a89d7d 356 l = strpcpyl(&s, sizeof(names->usb_ports), "c", config, NULL);
02609440
KS
357
358 /* append USB interface number, suppress the interface == 0 */
359 if (!streq(interf, "0"))
d5a89d7d 360 l = strpcpyl(&s, sizeof(names->usb_ports), "i", interf, NULL);
02609440
KS
361 if (l == 0)
362 return -ENAMETOOLONG;
363
364 names->type = NET_USB;
d23965a6
KS
365 return 0;
366}
367
984c4348
KS
368static int names_bcma(struct udev_device *dev, struct netnames *names) {
369 struct udev_device *bcmadev;
370 unsigned int core;
371
3b64e4d4
TG
372 assert(dev);
373 assert(names);
374
984c4348
KS
375 bcmadev = udev_device_get_parent_with_subsystem_devtype(dev, "bcma", NULL);
376 if (!bcmadev)
377 return -ENOENT;
378
f4ddacbd 379 /* bus num:core num */
b5dd8148 380 if (sscanf(udev_device_get_sysname(bcmadev), "bcma%*u:%u", &core) != 1)
984c4348 381 return -EINVAL;
f4ddacbd
KS
382 /* suppress the common core == 0 */
383 if (core > 0)
d054f0a4 384 xsprintf(names->bcma_core, "b%u", core);
f4ddacbd 385
984c4348
KS
386 names->type = NET_BCMA;
387 return 0;
388}
389
e0d4a0ac
HB
390static int names_ccw(struct udev_device *dev, struct netnames *names) {
391 struct udev_device *cdev;
392 const char *bus_id;
393 size_t bus_id_len;
394 int rc;
395
3b64e4d4
TG
396 assert(dev);
397 assert(names);
398
e0d4a0ac
HB
399 /* Retrieve the associated CCW device */
400 cdev = udev_device_get_parent(dev);
401 if (!cdev)
402 return -ENOENT;
403
404 /* Network devices are always grouped CCW devices */
405 if (!streq_ptr("ccwgroup", udev_device_get_subsystem(cdev)))
406 return -ENOENT;
407
408 /* Retrieve bus-ID of the grouped CCW device. The bus-ID uniquely
409 * identifies the network device on the Linux on System z channel
410 * subsystem. Note that the bus-ID contains lowercase characters.
411 */
412 bus_id = udev_device_get_sysname(cdev);
413 if (!bus_id)
414 return -ENOENT;
415
416 /* Check the length of the bus-ID. Rely on that the kernel provides
417 * a correct bus-ID; alternatively, improve this check and parse and
418 * verify each bus-ID part...
419 */
420 bus_id_len = strlen(bus_id);
421 if (!bus_id_len || bus_id_len < 8 || bus_id_len > 9)
422 return -EINVAL;
423
424 /* Store the CCW bus-ID for use as network device name */
d4b687c9
KS
425 rc = snprintf(names->ccw_group, sizeof(names->ccw_group), "ccw%s", bus_id);
426 if (rc >= 0 && rc < (int)sizeof(names->ccw_group))
e0d4a0ac
HB
427 names->type = NET_CCWGROUP;
428 return 0;
429}
430
02609440 431static int names_mac(struct udev_device *dev, struct netnames *names) {
d23965a6
KS
432 const char *s;
433 unsigned int i;
434 unsigned int a1, a2, a3, a4, a5, a6;
d23965a6
KS
435
436 /* check for NET_ADDR_PERM, skip random MAC addresses */
437 s = udev_device_get_sysattr_value(dev, "addr_assign_type");
438 if (!s)
439 return EXIT_FAILURE;
440 i = strtoul(s, NULL, 0);
441 if (i != 0)
442 return 0;
443
444 s = udev_device_get_sysattr_value(dev, "address");
445 if (!s)
446 return -ENOENT;
447 if (sscanf(s, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6)
448 return -EINVAL;
449
450 /* skip empty MAC addresses */
451 if (a1 + a2 + a3 + a4 + a5 + a6 == 0)
a660c63c
KS
452 return -EINVAL;
453
02609440
KS
454 names->mac[0] = a1;
455 names->mac[1] = a2;
456 names->mac[2] = a3;
457 names->mac[3] = a4;
458 names->mac[4] = a5;
459 names->mac[5] = a6;
460 names->mac_valid = true;
461 return 0;
462}
d23965a6 463
02609440
KS
464/* IEEE Organizationally Unique Identifier vendor string */
465static int ieee_oui(struct udev_device *dev, struct netnames *names, bool test) {
971e7fb6 466 char str[32];
02609440 467
971e7fb6 468 if (!names->mac_valid)
02609440
KS
469 return -ENOENT;
470 /* skip commonly misused 00:00:00 (Xerox) prefix */
471 if (memcmp(names->mac, "\0\0\0", 3) == 0)
472 return -EINVAL;
d054f0a4
DM
473 xsprintf(str, "OUI:%02X%02X%02X%02X%02X%02X", names->mac[0],
474 names->mac[1], names->mac[2], names->mac[3], names->mac[4],
475 names->mac[5]);
a4bbef09 476 udev_builtin_hwdb_lookup(dev, NULL, str, NULL, test);
02609440 477 return 0;
a660c63c
KS
478}
479
480static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool test) {
d23965a6 481 const char *s;
72bc96f0 482 const char *p;
d23965a6
KS
483 unsigned int i;
484 const char *devtype;
485 const char *prefix = "en";
b92bea5d 486 struct netnames names = {};
02609440 487 int err;
d23965a6 488
e0d4a0ac 489 /* handle only ARPHRD_ETHER and ARPHRD_SLIP devices */
d23965a6
KS
490 s = udev_device_get_sysattr_value(dev, "type");
491 if (!s)
492 return EXIT_FAILURE;
493 i = strtoul(s, NULL, 0);
e0d4a0ac 494 switch (i) {
19aa72f7 495 case ARPHRD_ETHER:
e0d4a0ac
HB
496 prefix = "en";
497 break;
19aa72f7 498 case ARPHRD_SLIP:
e0d4a0ac
HB
499 prefix = "sl";
500 break;
501 default:
d23965a6 502 return 0;
e0d4a0ac 503 }
d23965a6 504
72bc96f0
KS
505 /* skip stacked devices, like VLANs, ... */
506 s = udev_device_get_sysattr_value(dev, "ifindex");
507 if (!s)
508 return EXIT_FAILURE;
509 p = udev_device_get_sysattr_value(dev, "iflink");
510 if (!p)
511 return EXIT_FAILURE;
090be865 512 if (!streq(s, p))
72bc96f0
KS
513 return 0;
514
d23965a6
KS
515 devtype = udev_device_get_devtype(dev);
516 if (devtype) {
517 if (streq("wlan", devtype))
518 prefix = "wl";
519 else if (streq("wwan", devtype))
520 prefix = "ww";
521 }
522
02609440
KS
523 err = names_mac(dev, &names);
524 if (err >= 0 && names.mac_valid) {
525 char str[IFNAMSIZ];
526
d054f0a4 527 xsprintf(str, "%sx%02x%02x%02x%02x%02x%02x", prefix,
02609440
KS
528 names.mac[0], names.mac[1], names.mac[2],
529 names.mac[3], names.mac[4], names.mac[5]);
530 udev_builtin_add_property(dev, test, "ID_NET_NAME_MAC", str);
531
532 ieee_oui(dev, &names, test);
533 }
534
e0d4a0ac
HB
535 /* get path names for Linux on System z network devices */
536 err = names_ccw(dev, &names);
537 if (err >= 0 && names.type == NET_CCWGROUP) {
538 char str[IFNAMSIZ];
539
d4b687c9 540 if (snprintf(str, sizeof(str), "%s%s", prefix, names.ccw_group) < (int)sizeof(str))
e0d4a0ac
HB
541 udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
542 goto out;
543 }
544
02609440
KS
545 /* get PCI based path names, we compose only PCI based paths */
546 err = names_pci(dev, &names);
547 if (err < 0)
548 goto out;
549
550 /* plain PCI device */
551 if (names.type == NET_PCI) {
552 char str[IFNAMSIZ];
553
554 if (names.pci_onboard[0])
555 if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard) < (int)sizeof(str))
556 udev_builtin_add_property(dev, test, "ID_NET_NAME_ONBOARD", str);
557
558 if (names.pci_onboard_label)
559 if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard_label) < (int)sizeof(str))
560 udev_builtin_add_property(dev, test, "ID_NET_LABEL_ONBOARD", str);
561
562 if (names.pci_path[0])
563 if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_path) < (int)sizeof(str))
564 udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
565
566 if (names.pci_slot[0])
567 if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_slot) < (int)sizeof(str))
568 udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
569 goto out;
570 }
571
572 /* USB device */
573 err = names_usb(dev, &names);
574 if (err >= 0 && names.type == NET_USB) {
575 char str[IFNAMSIZ];
576
577 if (names.pci_path[0])
578 if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.usb_ports) < (int)sizeof(str))
579 udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
580
581 if (names.pci_slot[0])
582 if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.usb_ports) < (int)sizeof(str))
583 udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
984c4348
KS
584 goto out;
585 }
586
587 /* Broadcom bus */
588 err = names_bcma(dev, &names);
589 if (err >= 0 && names.type == NET_BCMA) {
590 char str[IFNAMSIZ];
591
592 if (names.pci_path[0])
593 if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.bcma_core) < (int)sizeof(str))
594 udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
595
596 if (names.pci_slot[0])
597 if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.bcma_core) < (int)sizeof(str))
598 udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
599 goto out;
02609440
KS
600 }
601out:
a660c63c
KS
602 return EXIT_SUCCESS;
603}
604
605const struct udev_builtin udev_builtin_net_id = {
606 .name = "net_id",
607 .cmd = builtin_net_id,
5ac0162c 608 .help = "Network device properties",
a660c63c 609};