]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev/udev-builtin-net_id.c
udev: net_id - update examples
[thirdparty/systemd.git] / src / udev / udev-builtin-net_id.c
CommitLineData
a660c63c
KS
1/***
2 This file is part of systemd.
3
4 Copyright 2012 Kay Sievers <kay@vrfy.org>
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
d23965a6 20/*
472780d8
KS
21 * predictable network interface device names based on:
22 * - firmware/bios-provided index numbers for on-board devices
23 * - firmware-provided pci-express hotplug slot index number
24 * - physical/geographical location of the hardware
25 * - the interface's MAC address
26 *
27 * two character prefixes based on the type of interface:
0035597a
KS
28 * en -- ethernet
29 * wl -- wlan
30 * ww -- wwan
d23965a6 31 *
472780d8
KS
32 * type of names:
33 * o<index> -- on-board device index number
34 * s<slot>[f<function>] -- hotplug slot index number
de892aea 35 * x<MAC> -- MAC address
472780d8 36 * p<bus>s<slot>[f<function>] -- PCI geographical location
f610d6de
KS
37 * p<bus>s<slot>[f<function>][u<port>][u<port>][c<config>][i<interface>]
38 * -- USB port number chain
472780d8
KS
39 *
40 * All multi-function devices will carry the [f<function>] number in the
41 * device name, including the function 0 device.
d23965a6 42 *
f610d6de 43 * PCI card with firmware index
0035597a 44 * ID_NET_NAME_ONBOARD=eno1
f610d6de
KS
45 * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
46 *
47 * PCI card
48 * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
49 * ID_NET_NAME_MAC=enx000000000466
50 * ID_NET_NAME_PATH=enp5s0
51 * ID_NET_NAME_SLOT=ens1
52 *
53 * PCI card in hotplug slot with firmware index number:
54 * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
55 * ID_NET_NAME_MAC=enx000000000466
56 * ID_NET_NAME_PATH=enp5s0
de892aea 57 * ID_NET_NAME_SLOT=ens1
f610d6de
KS
58 *
59 * PCI wlan card:
60 * /sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0
61 * ID_NET_NAME_MAC=wlx0024d7e31130
62 * ID_NET_NAME_PATH=wlp3s0
63 *
64 * USB built-in 3G modem:
65 * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
66 * ID_NET_NAME_MAC=wwx028037ec0200
67 * ID_NET_NAME_PATH=wwp0s29u1u4i6
68 *
69 * USB Android phone:
70 * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2
71 * ID_NET_NAME_MAC=enxd626b3450fb5
72 * ID_NET_NAME_PATH=enp0s29u1u2
d23965a6
KS
73 */
74
a660c63c
KS
75#include <stdio.h>
76#include <stdlib.h>
77#include <stdarg.h>
78#include <unistd.h>
79#include <string.h>
80#include <errno.h>
02609440 81#include <net/if.h>
de892aea 82#include <linux/pci_regs.h>
a660c63c
KS
83
84#include "udev.h"
85
02609440
KS
86enum netname_type{
87 NET_UNDEF,
88 NET_PCI,
89 NET_USB,
90};
91
92struct netnames {
93 enum netname_type type;
94
95 uint8_t mac[6];
96 bool mac_valid;
97
98 struct udev_device *pcidev;
99 char pci_slot[IFNAMSIZ];
100 char pci_path[IFNAMSIZ];
101 char pci_onboard[IFNAMSIZ];
102 const char *pci_onboard_label;
103
104 struct udev_device *usbdev;
105 char usb_ports[IFNAMSIZ];
106};
107
0035597a 108/* retrieve on-board index number and label from firmware */
02609440 109static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
d23965a6 110 const char *index;
0035597a 111 int idx;
a660c63c 112
0035597a 113 /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */
02609440 114 index = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
01d183dd
KS
115 /* SMBIOS type 41 -- Onboard Devices Extended Information */
116 if (!index)
02609440 117 index = udev_device_get_sysattr_value(names->pcidev, "index");
0035597a
KS
118 if (!index)
119 return -ENOENT;
120 idx = strtoul(index, NULL, 0);
121 if (idx <= 0)
122 return -EINVAL;
02609440 123 snprintf(names->pci_onboard, sizeof(names->pci_onboard), "o%d", idx);
d23965a6 124
02609440 125 names->pci_onboard_label = udev_device_get_sysattr_value(names->pcidev, "label");
0035597a
KS
126 return 0;
127}
d23965a6 128
137661d8 129/* read the 256 bytes PCI configuration space to check the multi-function bit */
de892aea
KS
130static bool is_pci_singlefunction(struct udev_device *dev) {
131 char filename[256];
132 FILE *f;
02609440 133 char config[64];
de892aea
KS
134 bool single = false;
135
136 snprintf(filename, sizeof(filename), "%s/config", udev_device_get_syspath(dev));
137 f = fopen(filename, "re");
138 if (!f)
139 goto out;
140 if (fread(&config, sizeof(config), 1, f) != 1)
141 goto out;
142
143 /* bit 0-6 header type, bit 7 multi/single function device */
144 if ((config[PCI_HEADER_TYPE] & 0x80) == 0)
145 single = true;
146out:
147 fclose(f);
148 return single;
149}
150
02609440
KS
151static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
152 struct udev *udev = udev_device_get_udev(names->pcidev);
0035597a
KS
153 unsigned int bus;
154 unsigned int slot;
155 unsigned int func;
156 struct udev_device *pci = NULL;
157 char slots[256];
158 DIR *dir;
159 struct dirent *dent;
160 char str[256];
161 int hotplug_slot = 0;
162 int err = 0;
163
164 /* compose a name based on the raw kernel's PCI bus, slot numbers */
02609440 165 if (sscanf(udev_device_get_sysname(names->pcidev), "0000:%x:%x.%d", &bus, &slot, &func) != 3)
0035597a 166 return -ENOENT;
02609440
KS
167 if (func == 0 && is_pci_singlefunction(names->pcidev))
168 snprintf(names->pci_path, sizeof(names->pci_path), "p%ds%d", bus, slot);
de892aea 169 else
02609440 170 snprintf(names->pci_path, sizeof(names->pci_path), "p%ds%df%d", bus, slot, func);
d23965a6 171
0035597a
KS
172 /* ACPI _SUN -- slot user number */
173 pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
174 if (!pci) {
175 err = -ENOENT;
176 goto out;
177 }
178 snprintf(slots, sizeof(slots), "%s/slots", udev_device_get_syspath(pci));
179 dir = opendir(slots);
180 if (!dir) {
181 err = -errno;
182 goto out;
d23965a6
KS
183 }
184
0035597a
KS
185 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
186 int i;
187 char *rest;
188 char *address;
189
190 if (dent->d_name[0] == '.')
191 continue;
192 i = strtol(dent->d_name, &rest, 10);
193 if (rest[0] != '\0')
194 continue;
195 if (i < 1)
196 continue;
197 snprintf(str, sizeof(str), "%s/%s/address", slots, dent->d_name);
198 if (read_one_line_file(str, &address) >= 0) {
199 /* match slot address with device by stripping the function */
02609440 200 if (strncmp(address, udev_device_get_sysname(names->pcidev), strlen(address)) == 0)
0035597a
KS
201 hotplug_slot = i;
202 free(address);
203 }
204
205 if (hotplug_slot > 0)
206 break;
207 }
208 closedir(dir);
d23965a6 209
0035597a 210 if (hotplug_slot > 0) {
02609440
KS
211 if (func == 0 && is_pci_singlefunction(names->pcidev))
212 snprintf(names->pci_slot, sizeof(names->pci_slot), "s%d", hotplug_slot);
de892aea 213 else
02609440 214 snprintf(names->pci_slot, sizeof(names->pci_slot), "s%df%d", hotplug_slot, func);
d23965a6 215 }
0035597a
KS
216out:
217 udev_device_unref(pci);
218 return err;
219}
220
02609440 221static int names_pci(struct udev_device *dev, struct netnames *names) {
5b8180d3 222 struct udev_device *parent;
0035597a 223
5b8180d3 224 parent = udev_device_get_parent(dev);
02609440
KS
225 if (!parent)
226 return -ENOENT;
227 /* check if our direct parent is a PCI device with no other bus in-between */
228 if (streq("pci", udev_device_get_subsystem(parent))) {
229 names->type = NET_PCI;
230 names->pcidev = parent;
231 } else {
232 names->pcidev = udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
233 if (!names->pcidev)
234 return -ENOENT;
235 }
236 dev_pci_onboard(dev, names);
237 dev_pci_slot(dev, names);
238 return 0;
239}
240
241static int names_usb(struct udev_device *dev, struct netnames *names) {
242 char name[256];
243 char *ports;
244 char *config;
245 char *interf;
246 size_t l;
247 char *s;
248
249 names->usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
250 if (!names->usbdev)
0035597a
KS
251 return -ENOENT;
252
02609440
KS
253 /* get USB port number chain, configuration, interface */
254 util_strscpy(name, sizeof(name), udev_device_get_sysname(names->usbdev));
255 s = strchr(name, '-');
256 if (!s)
257 return -EINVAL;
258 ports = s+1;
259
260 s = strchr(ports, ':');
261 if (!s)
262 return -EINVAL;
263 s[0] = '\0';
264 config = s+1;
265
266 s = strchr(config, '.');
267 if (!s)
268 return -EINVAL;
269 s[0] = '\0';
270 interf = s+1;
271
272 /* prefix every port number in the chain with "u"*/
273 s = ports;
274 while ((s = strchr(s, '.')))
275 s[0] = 'u';
276 s = names->usb_ports;
277 l = util_strpcpyl(&s, sizeof(names->usb_ports), "u", ports, NULL);
278
279 /* append USB config number, suppress the common config == 1 */
280 if (!streq(config, "1"))
281 l = util_strpcpyl(&s, sizeof(names->usb_ports), "c", config, NULL);
282
283 /* append USB interface number, suppress the interface == 0 */
284 if (!streq(interf, "0"))
285 l = util_strpcpyl(&s, sizeof(names->usb_ports), "i", interf, NULL);
286 if (l == 0)
287 return -ENAMETOOLONG;
288
289 names->type = NET_USB;
d23965a6
KS
290 return 0;
291}
292
02609440 293static int names_mac(struct udev_device *dev, struct netnames *names) {
d23965a6
KS
294 const char *s;
295 unsigned int i;
296 unsigned int a1, a2, a3, a4, a5, a6;
d23965a6
KS
297
298 /* check for NET_ADDR_PERM, skip random MAC addresses */
299 s = udev_device_get_sysattr_value(dev, "addr_assign_type");
300 if (!s)
301 return EXIT_FAILURE;
302 i = strtoul(s, NULL, 0);
303 if (i != 0)
304 return 0;
305
306 s = udev_device_get_sysattr_value(dev, "address");
307 if (!s)
308 return -ENOENT;
309 if (sscanf(s, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6)
310 return -EINVAL;
311
312 /* skip empty MAC addresses */
313 if (a1 + a2 + a3 + a4 + a5 + a6 == 0)
a660c63c
KS
314 return -EINVAL;
315
02609440
KS
316 names->mac[0] = a1;
317 names->mac[1] = a2;
318 names->mac[2] = a3;
319 names->mac[3] = a4;
320 names->mac[4] = a5;
321 names->mac[5] = a6;
322 names->mac_valid = true;
323 return 0;
324}
d23965a6 325
02609440
KS
326/* IEEE Organizationally Unique Identifier vendor string */
327static int ieee_oui(struct udev_device *dev, struct netnames *names, bool test) {
328 char str[IFNAMSIZ];
329
330 if (names->mac_valid)
331 return -ENOENT;
332 /* skip commonly misused 00:00:00 (Xerox) prefix */
333 if (memcmp(names->mac, "\0\0\0", 3) == 0)
334 return -EINVAL;
335 snprintf(str, sizeof(str), "OUI:%02X%02X%02X%02X%02X%02X",
336 names->mac[0], names->mac[1], names->mac[2],
337 names->mac[3], names->mac[4], names->mac[5]);
338 udev_builtin_hwdb_lookup(dev, str, test);
339 return 0;
a660c63c
KS
340}
341
342static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool test) {
d23965a6
KS
343 const char *s;
344 unsigned int i;
345 const char *devtype;
346 const char *prefix = "en";
02609440
KS
347 struct netnames names;
348 int err;
d23965a6
KS
349
350 /* handle only ARPHRD_ETHER devices */
351 s = udev_device_get_sysattr_value(dev, "type");
352 if (!s)
353 return EXIT_FAILURE;
354 i = strtoul(s, NULL, 0);
355 if (i != 1)
356 return 0;
357
358 devtype = udev_device_get_devtype(dev);
359 if (devtype) {
360 if (streq("wlan", devtype))
361 prefix = "wl";
362 else if (streq("wwan", devtype))
363 prefix = "ww";
364 }
365
02609440
KS
366 zero(names);
367 err = names_mac(dev, &names);
368 if (err >= 0 && names.mac_valid) {
369 char str[IFNAMSIZ];
370
371 snprintf(str, sizeof(str), "%sx%02x%02x%02x%02x%02x%02x", prefix,
372 names.mac[0], names.mac[1], names.mac[2],
373 names.mac[3], names.mac[4], names.mac[5]);
374 udev_builtin_add_property(dev, test, "ID_NET_NAME_MAC", str);
375
376 ieee_oui(dev, &names, test);
377 }
378
379 /* get PCI based path names, we compose only PCI based paths */
380 err = names_pci(dev, &names);
381 if (err < 0)
382 goto out;
383
384 /* plain PCI device */
385 if (names.type == NET_PCI) {
386 char str[IFNAMSIZ];
387
388 if (names.pci_onboard[0])
389 if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard) < (int)sizeof(str))
390 udev_builtin_add_property(dev, test, "ID_NET_NAME_ONBOARD", str);
391
392 if (names.pci_onboard_label)
393 if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard_label) < (int)sizeof(str))
394 udev_builtin_add_property(dev, test, "ID_NET_LABEL_ONBOARD", str);
395
396 if (names.pci_path[0])
397 if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_path) < (int)sizeof(str))
398 udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
399
400 if (names.pci_slot[0])
401 if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_slot) < (int)sizeof(str))
402 udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
403 goto out;
404 }
405
406 /* USB device */
407 err = names_usb(dev, &names);
408 if (err >= 0 && names.type == NET_USB) {
409 char str[IFNAMSIZ];
410
411 if (names.pci_path[0])
412 if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.usb_ports) < (int)sizeof(str))
413 udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
414
415 if (names.pci_slot[0])
416 if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.usb_ports) < (int)sizeof(str))
417 udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
418 }
419out:
a660c63c
KS
420 return EXIT_SUCCESS;
421}
422
423const struct udev_builtin udev_builtin_net_id = {
424 .name = "net_id",
425 .cmd = builtin_net_id,
426 .help = "network device properties",
427};