]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev/udev-builtin-net_id.c
Merge pull request #2466 from poettering/nspawn-journal
[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
6c1e69f9
LP
109#define ONBOARD_INDEX_MAX (16*1024-1)
110
02609440
KS
111enum netname_type{
112 NET_UNDEF,
113 NET_PCI,
114 NET_USB,
984c4348 115 NET_BCMA,
e3d56334 116 NET_VIRTIO,
e0d4a0ac 117 NET_CCWGROUP,
02609440
KS
118};
119
120struct netnames {
121 enum netname_type type;
122
123 uint8_t mac[6];
124 bool mac_valid;
125
126 struct udev_device *pcidev;
127 char pci_slot[IFNAMSIZ];
128 char pci_path[IFNAMSIZ];
129 char pci_onboard[IFNAMSIZ];
130 const char *pci_onboard_label;
131
02609440 132 char usb_ports[IFNAMSIZ];
984c4348 133 char bcma_core[IFNAMSIZ];
d4b687c9 134 char ccw_group[IFNAMSIZ];
02609440
KS
135};
136
0035597a 137/* retrieve on-board index number and label from firmware */
02609440 138static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
c0a43734
TG
139 unsigned dev_port = 0;
140 size_t l;
141 char *s;
142 const char *attr;
0035597a 143 int idx;
a660c63c 144
0035597a 145 /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */
c0a43734 146 attr = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
01d183dd 147 /* SMBIOS type 41 -- Onboard Devices Extended Information */
c0a43734
TG
148 if (!attr)
149 attr = udev_device_get_sysattr_value(names->pcidev, "index");
150 if (!attr)
0035597a 151 return -ENOENT;
c0a43734
TG
152
153 idx = strtoul(attr, NULL, 0);
0035597a
KS
154 if (idx <= 0)
155 return -EINVAL;
c0a43734 156
6c1e69f9
LP
157 /* Some BIOSes report rubbish indexes that are excessively high (2^24-1 is an index VMware likes to report for
158 * example). Let's define a cut-off where we don't consider the index reliable anymore. We pick some arbitrary
159 * cut-off, which is somewhere beyond the realistic number of physical network interface a system might
160 * have. Ideally the kernel would already filter his crap for us, but it doesn't currently. */
161 if (idx > ONBOARD_INDEX_MAX)
162 return -ENOENT;
163
309b578d 164 /* kernel provided port index for multiple ports on a single PCI function */
c0a43734
TG
165 attr = udev_device_get_sysattr_value(dev, "dev_port");
166 if (attr)
167 dev_port = strtol(attr, NULL, 10);
168
169 s = names->pci_onboard;
170 l = sizeof(names->pci_onboard);
171 l = strpcpyf(&s, l, "o%d", idx);
172 if (dev_port > 0)
173 l = strpcpyf(&s, l, "d%d", dev_port);
174 if (l == 0)
175 names->pci_onboard[0] = '\0';
d23965a6 176
02609440 177 names->pci_onboard_label = udev_device_get_sysattr_value(names->pcidev, "label");
c0a43734 178
0035597a
KS
179 return 0;
180}
d23965a6 181
137661d8 182/* read the 256 bytes PCI configuration space to check the multi-function bit */
1328f66a 183static bool is_pci_multifunction(struct udev_device *dev) {
0454229c 184 _cleanup_close_ int fd = -1;
1cb5d1f3
LP
185 const char *filename;
186 uint8_t config[64];
de892aea 187
63c372cb 188 filename = strjoina(udev_device_get_syspath(dev), "/config");
0454229c
JM
189 fd = open(filename, O_RDONLY | O_CLOEXEC);
190 if (fd < 0)
1cb5d1f3 191 return false;
0454229c 192 if (read(fd, &config, sizeof(config)) != sizeof(config))
1cb5d1f3 193 return false;
de892aea
KS
194
195 /* bit 0-6 header type, bit 7 multi/single function device */
1328f66a 196 if ((config[PCI_HEADER_TYPE] & 0x80) != 0)
1cb5d1f3
LP
197 return true;
198
199 return false;
de892aea
KS
200}
201
02609440
KS
202static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
203 struct udev *udev = udev_device_get_udev(names->pcidev);
3058e017 204 unsigned domain, bus, slot, func, dev_port = 0;
1328f66a
KS
205 size_t l;
206 char *s;
207 const char *attr;
0035597a 208 struct udev_device *pci = NULL;
b5dd8148
ZJS
209 char slots[256], str[256];
210 _cleanup_closedir_ DIR *dir = NULL;
0035597a 211 struct dirent *dent;
b5dd8148 212 int hotplug_slot = 0, err = 0;
0035597a 213
b5dd8148 214 if (sscanf(udev_device_get_sysname(names->pcidev), "%x:%x:%x.%u", &domain, &bus, &slot, &func) != 4)
0035597a 215 return -ENOENT;
1328f66a 216
309b578d 217 /* kernel provided port index for multiple ports on a single PCI function */
3058e017 218 attr = udev_device_get_sysattr_value(dev, "dev_port");
1328f66a 219 if (attr)
3058e017 220 dev_port = strtol(attr, NULL, 10);
1328f66a
KS
221
222 /* compose a name based on the raw kernel's PCI bus, slot numbers */
223 s = names->pci_path;
214daa72
SM
224 l = sizeof(names->pci_path);
225 if (domain > 0)
1fa2f38f
ZJS
226 l = strpcpyf(&s, l, "P%u", domain);
227 l = strpcpyf(&s, l, "p%us%u", bus, slot);
1328f66a 228 if (func > 0 || is_pci_multifunction(names->pcidev))
1fa2f38f 229 l = strpcpyf(&s, l, "f%u", func);
3058e017 230 if (dev_port > 0)
1fa2f38f 231 l = strpcpyf(&s, l, "d%u", dev_port);
1328f66a
KS
232 if (l == 0)
233 names->pci_path[0] = '\0';
d23965a6 234
0035597a
KS
235 /* ACPI _SUN -- slot user number */
236 pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
237 if (!pci) {
238 err = -ENOENT;
239 goto out;
240 }
d054f0a4 241 xsprintf(slots, "%s/slots", udev_device_get_syspath(pci));
0035597a
KS
242 dir = opendir(slots);
243 if (!dir) {
244 err = -errno;
245 goto out;
d23965a6
KS
246 }
247
0035597a
KS
248 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
249 int i;
250 char *rest;
251 char *address;
252
253 if (dent->d_name[0] == '.')
254 continue;
255 i = strtol(dent->d_name, &rest, 10);
256 if (rest[0] != '\0')
257 continue;
258 if (i < 1)
259 continue;
d054f0a4 260 xsprintf(str, "%s/%s/address", slots, dent->d_name);
0035597a
KS
261 if (read_one_line_file(str, &address) >= 0) {
262 /* match slot address with device by stripping the function */
641906e9 263 if (strneq(address, udev_device_get_sysname(names->pcidev), strlen(address)))
0035597a
KS
264 hotplug_slot = i;
265 free(address);
266 }
267
268 if (hotplug_slot > 0)
269 break;
270 }
d23965a6 271
0035597a 272 if (hotplug_slot > 0) {
1328f66a 273 s = names->pci_slot;
214daa72
SM
274 l = sizeof(names->pci_slot);
275 if (domain > 0)
276 l = strpcpyf(&s, l, "P%d", domain);
277 l = strpcpyf(&s, l, "s%d", hotplug_slot);
1328f66a 278 if (func > 0 || is_pci_multifunction(names->pcidev))
d5a89d7d 279 l = strpcpyf(&s, l, "f%d", func);
3058e017
TLSC
280 if (dev_port > 0)
281 l = strpcpyf(&s, l, "d%d", dev_port);
1328f66a 282 if (l == 0)
16f948cb 283 names->pci_slot[0] = '\0';
d23965a6 284 }
0035597a
KS
285out:
286 udev_device_unref(pci);
287 return err;
288}
289
02609440 290static int names_pci(struct udev_device *dev, struct netnames *names) {
5b8180d3 291 struct udev_device *parent;
0035597a 292
3b64e4d4
TG
293 assert(dev);
294 assert(names);
295
5b8180d3 296 parent = udev_device_get_parent(dev);
54683f0f
TG
297
298 /* there can only ever be one virtio bus per parent device, so we can
299 safely ignore any virtio buses. see
300 <http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030331.html> */
301 while (parent && streq_ptr("virtio", udev_device_get_subsystem(parent)))
302 parent = udev_device_get_parent(parent);
303
02609440
KS
304 if (!parent)
305 return -ENOENT;
54683f0f 306
02609440 307 /* check if our direct parent is a PCI device with no other bus in-between */
bb26309d 308 if (streq_ptr("pci", udev_device_get_subsystem(parent))) {
02609440
KS
309 names->type = NET_PCI;
310 names->pcidev = parent;
311 } else {
312 names->pcidev = udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
313 if (!names->pcidev)
314 return -ENOENT;
315 }
316 dev_pci_onboard(dev, names);
317 dev_pci_slot(dev, names);
318 return 0;
319}
320
321static int names_usb(struct udev_device *dev, struct netnames *names) {
984c4348 322 struct udev_device *usbdev;
02609440
KS
323 char name[256];
324 char *ports;
325 char *config;
326 char *interf;
327 size_t l;
328 char *s;
329
3b64e4d4
TG
330 assert(dev);
331 assert(names);
332
984c4348
KS
333 usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
334 if (!usbdev)
0035597a
KS
335 return -ENOENT;
336
02609440 337 /* get USB port number chain, configuration, interface */
984c4348 338 strscpy(name, sizeof(name), udev_device_get_sysname(usbdev));
02609440
KS
339 s = strchr(name, '-');
340 if (!s)
341 return -EINVAL;
342 ports = s+1;
343
344 s = strchr(ports, ':');
345 if (!s)
346 return -EINVAL;
347 s[0] = '\0';
348 config = s+1;
349
350 s = strchr(config, '.');
351 if (!s)
352 return -EINVAL;
353 s[0] = '\0';
354 interf = s+1;
355
f7340ab2 356 /* prefix every port number in the chain with "u" */
02609440
KS
357 s = ports;
358 while ((s = strchr(s, '.')))
359 s[0] = 'u';
360 s = names->usb_ports;
d5a89d7d 361 l = strpcpyl(&s, sizeof(names->usb_ports), "u", ports, NULL);
02609440
KS
362
363 /* append USB config number, suppress the common config == 1 */
364 if (!streq(config, "1"))
d5a89d7d 365 l = strpcpyl(&s, sizeof(names->usb_ports), "c", config, NULL);
02609440
KS
366
367 /* append USB interface number, suppress the interface == 0 */
368 if (!streq(interf, "0"))
d5a89d7d 369 l = strpcpyl(&s, sizeof(names->usb_ports), "i", interf, NULL);
02609440
KS
370 if (l == 0)
371 return -ENAMETOOLONG;
372
373 names->type = NET_USB;
d23965a6
KS
374 return 0;
375}
376
984c4348
KS
377static int names_bcma(struct udev_device *dev, struct netnames *names) {
378 struct udev_device *bcmadev;
379 unsigned int core;
380
3b64e4d4
TG
381 assert(dev);
382 assert(names);
383
984c4348
KS
384 bcmadev = udev_device_get_parent_with_subsystem_devtype(dev, "bcma", NULL);
385 if (!bcmadev)
386 return -ENOENT;
387
f4ddacbd 388 /* bus num:core num */
b5dd8148 389 if (sscanf(udev_device_get_sysname(bcmadev), "bcma%*u:%u", &core) != 1)
984c4348 390 return -EINVAL;
f4ddacbd
KS
391 /* suppress the common core == 0 */
392 if (core > 0)
d054f0a4 393 xsprintf(names->bcma_core, "b%u", core);
f4ddacbd 394
984c4348
KS
395 names->type = NET_BCMA;
396 return 0;
397}
398
e0d4a0ac
HB
399static int names_ccw(struct udev_device *dev, struct netnames *names) {
400 struct udev_device *cdev;
401 const char *bus_id;
402 size_t bus_id_len;
403 int rc;
404
3b64e4d4
TG
405 assert(dev);
406 assert(names);
407
e0d4a0ac
HB
408 /* Retrieve the associated CCW device */
409 cdev = udev_device_get_parent(dev);
410 if (!cdev)
411 return -ENOENT;
412
413 /* Network devices are always grouped CCW devices */
414 if (!streq_ptr("ccwgroup", udev_device_get_subsystem(cdev)))
415 return -ENOENT;
416
417 /* Retrieve bus-ID of the grouped CCW device. The bus-ID uniquely
418 * identifies the network device on the Linux on System z channel
419 * subsystem. Note that the bus-ID contains lowercase characters.
420 */
421 bus_id = udev_device_get_sysname(cdev);
422 if (!bus_id)
423 return -ENOENT;
424
425 /* Check the length of the bus-ID. Rely on that the kernel provides
426 * a correct bus-ID; alternatively, improve this check and parse and
427 * verify each bus-ID part...
428 */
429 bus_id_len = strlen(bus_id);
430 if (!bus_id_len || bus_id_len < 8 || bus_id_len > 9)
431 return -EINVAL;
432
433 /* Store the CCW bus-ID for use as network device name */
d4b687c9
KS
434 rc = snprintf(names->ccw_group, sizeof(names->ccw_group), "ccw%s", bus_id);
435 if (rc >= 0 && rc < (int)sizeof(names->ccw_group))
e0d4a0ac
HB
436 names->type = NET_CCWGROUP;
437 return 0;
438}
439
02609440 440static int names_mac(struct udev_device *dev, struct netnames *names) {
d23965a6
KS
441 const char *s;
442 unsigned int i;
443 unsigned int a1, a2, a3, a4, a5, a6;
d23965a6
KS
444
445 /* check for NET_ADDR_PERM, skip random MAC addresses */
446 s = udev_device_get_sysattr_value(dev, "addr_assign_type");
447 if (!s)
448 return EXIT_FAILURE;
449 i = strtoul(s, NULL, 0);
450 if (i != 0)
451 return 0;
452
453 s = udev_device_get_sysattr_value(dev, "address");
454 if (!s)
455 return -ENOENT;
456 if (sscanf(s, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6)
457 return -EINVAL;
458
459 /* skip empty MAC addresses */
460 if (a1 + a2 + a3 + a4 + a5 + a6 == 0)
a660c63c
KS
461 return -EINVAL;
462
02609440
KS
463 names->mac[0] = a1;
464 names->mac[1] = a2;
465 names->mac[2] = a3;
466 names->mac[3] = a4;
467 names->mac[4] = a5;
468 names->mac[5] = a6;
469 names->mac_valid = true;
470 return 0;
471}
d23965a6 472
02609440
KS
473/* IEEE Organizationally Unique Identifier vendor string */
474static int ieee_oui(struct udev_device *dev, struct netnames *names, bool test) {
971e7fb6 475 char str[32];
02609440 476
971e7fb6 477 if (!names->mac_valid)
02609440
KS
478 return -ENOENT;
479 /* skip commonly misused 00:00:00 (Xerox) prefix */
480 if (memcmp(names->mac, "\0\0\0", 3) == 0)
481 return -EINVAL;
d054f0a4
DM
482 xsprintf(str, "OUI:%02X%02X%02X%02X%02X%02X", names->mac[0],
483 names->mac[1], names->mac[2], names->mac[3], names->mac[4],
484 names->mac[5]);
a4bbef09 485 udev_builtin_hwdb_lookup(dev, NULL, str, NULL, test);
02609440 486 return 0;
a660c63c
KS
487}
488
489static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool test) {
d23965a6 490 const char *s;
72bc96f0 491 const char *p;
d23965a6
KS
492 unsigned int i;
493 const char *devtype;
494 const char *prefix = "en";
b92bea5d 495 struct netnames names = {};
02609440 496 int err;
d23965a6 497
e0d4a0ac 498 /* handle only ARPHRD_ETHER and ARPHRD_SLIP devices */
d23965a6
KS
499 s = udev_device_get_sysattr_value(dev, "type");
500 if (!s)
501 return EXIT_FAILURE;
502 i = strtoul(s, NULL, 0);
e0d4a0ac 503 switch (i) {
19aa72f7 504 case ARPHRD_ETHER:
e0d4a0ac
HB
505 prefix = "en";
506 break;
19aa72f7 507 case ARPHRD_SLIP:
e0d4a0ac
HB
508 prefix = "sl";
509 break;
510 default:
d23965a6 511 return 0;
e0d4a0ac 512 }
d23965a6 513
72bc96f0
KS
514 /* skip stacked devices, like VLANs, ... */
515 s = udev_device_get_sysattr_value(dev, "ifindex");
516 if (!s)
517 return EXIT_FAILURE;
518 p = udev_device_get_sysattr_value(dev, "iflink");
519 if (!p)
520 return EXIT_FAILURE;
090be865 521 if (!streq(s, p))
72bc96f0
KS
522 return 0;
523
d23965a6
KS
524 devtype = udev_device_get_devtype(dev);
525 if (devtype) {
526 if (streq("wlan", devtype))
527 prefix = "wl";
528 else if (streq("wwan", devtype))
529 prefix = "ww";
530 }
531
02609440
KS
532 err = names_mac(dev, &names);
533 if (err >= 0 && names.mac_valid) {
534 char str[IFNAMSIZ];
535
d054f0a4 536 xsprintf(str, "%sx%02x%02x%02x%02x%02x%02x", prefix,
02609440
KS
537 names.mac[0], names.mac[1], names.mac[2],
538 names.mac[3], names.mac[4], names.mac[5]);
539 udev_builtin_add_property(dev, test, "ID_NET_NAME_MAC", str);
540
541 ieee_oui(dev, &names, test);
542 }
543
e0d4a0ac
HB
544 /* get path names for Linux on System z network devices */
545 err = names_ccw(dev, &names);
546 if (err >= 0 && names.type == NET_CCWGROUP) {
547 char str[IFNAMSIZ];
548
d4b687c9 549 if (snprintf(str, sizeof(str), "%s%s", prefix, names.ccw_group) < (int)sizeof(str))
e0d4a0ac
HB
550 udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
551 goto out;
552 }
553
02609440
KS
554 /* get PCI based path names, we compose only PCI based paths */
555 err = names_pci(dev, &names);
556 if (err < 0)
557 goto out;
558
559 /* plain PCI device */
560 if (names.type == NET_PCI) {
561 char str[IFNAMSIZ];
562
563 if (names.pci_onboard[0])
564 if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard) < (int)sizeof(str))
565 udev_builtin_add_property(dev, test, "ID_NET_NAME_ONBOARD", str);
566
567 if (names.pci_onboard_label)
568 if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard_label) < (int)sizeof(str))
569 udev_builtin_add_property(dev, test, "ID_NET_LABEL_ONBOARD", str);
570
571 if (names.pci_path[0])
572 if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_path) < (int)sizeof(str))
573 udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
574
575 if (names.pci_slot[0])
576 if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_slot) < (int)sizeof(str))
577 udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
578 goto out;
579 }
580
581 /* USB device */
582 err = names_usb(dev, &names);
583 if (err >= 0 && names.type == NET_USB) {
584 char str[IFNAMSIZ];
585
586 if (names.pci_path[0])
587 if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.usb_ports) < (int)sizeof(str))
588 udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
589
590 if (names.pci_slot[0])
591 if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.usb_ports) < (int)sizeof(str))
592 udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
984c4348
KS
593 goto out;
594 }
595
596 /* Broadcom bus */
597 err = names_bcma(dev, &names);
598 if (err >= 0 && names.type == NET_BCMA) {
599 char str[IFNAMSIZ];
600
601 if (names.pci_path[0])
602 if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.bcma_core) < (int)sizeof(str))
603 udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
604
605 if (names.pci_slot[0])
606 if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.bcma_core) < (int)sizeof(str))
607 udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
608 goto out;
02609440
KS
609 }
610out:
a660c63c
KS
611 return EXIT_SUCCESS;
612}
613
614const struct udev_builtin udev_builtin_net_id = {
615 .name = "net_id",
616 .cmd = builtin_net_id,
5ac0162c 617 .help = "Network device properties",
a660c63c 618};