udev-builtin-net_id.c revision 3c123e0899b56c0587db36420da5e049c56d9e19
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/***
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2012 Kay Sievers <kay@vrfy.org>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering***/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * Predictable network interface device names based on:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * - firmware/bios-provided index numbers for on-board devices
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * - firmware-provided pci-express hotplug slot index number
a0166609f782da91710dea9183d1bf138538db37Tom Gundersen * - physical/geographical location of the hardware
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen * - the interface's MAC address
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * Two character prefixes based on the type of interface:
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering * en -- ethernet
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen * wl -- wlan
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen * ww -- wwan
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering *
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering * Type of names:
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering * o<index> -- on-board device index number
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering * s<slot>[f<function>][d<dev_id>] -- hotplug slot index number
51323288fc628a5cac50914df915545d685b793eLennart Poettering * x<MAC> -- MAC address
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen * p<bus>s<slot>[f<function>][d<dev_id>] -- PCI geographical location
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen * p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen * -- USB port number chain
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering * All multi-function PCI devices will carry the [f<function>] number in the
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering * device name, including the function 0 device.
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering *
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering * For USB devices the full chain of port numbers of hubs is composed. If the
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering * name gets longer than the maximum number of 15 characters, the name is not
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering * exported.
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering * The usual USB configuration == 1 and interface == 0 values are suppressed.
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering *
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * PCI ethernet card with firmware index "1":
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_ONBOARD=eno1
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * PCI ethernet card in hotplug slot with firmware index number:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_MAC=enx000000000466
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_PATH=enp5s0
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_SLOT=ens1
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *
a0166609f782da91710dea9183d1bf138538db37Tom Gundersen * PCI ethernet multi-function card with 2 ports:
c73ce96b569e2f10dff64b7dc0bd271972674c2aLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0
c73ce96b569e2f10dff64b7dc0bd271972674c2aLennart Poettering * ID_NET_NAME_MAC=enx78e7d1ea46da
c73ce96b569e2f10dff64b7dc0bd271972674c2aLennart Poettering * ID_NET_NAME_PATH=enp2s0f0
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/net/enp2s0f1
c73ce96b569e2f10dff64b7dc0bd271972674c2aLennart Poettering * ID_NET_NAME_MAC=enx78e7d1ea46dc
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering * ID_NET_NAME_PATH=enp2s0f1
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering *
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering * PCI wlan card:
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_MAC=wlx0024d7e31130
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_PATH=wlp3s0
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * USB built-in 3G modem:
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_MAC=wwx028037ec0200
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * ID_NET_NAME_PATH=wwp0s29u1u4i6
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * USB Android phone:
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * ID_NET_NAME_MAC=enxd626b3450fb5
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * ID_NET_NAME_PATH=enp0s29u1u2
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering */
dc61b7e45d89a69f0469ab7b3289cdde7fcc55abTorstein Husebø
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering#include <stdio.h>
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering#include <stdlib.h>
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering#include <stdarg.h>
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering#include <unistd.h>
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering#include <string.h>
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering#include <errno.h>
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering#include <net/if.h>
f6a5fec6b971e2a8c69d92ab20ed13693be82ddbLennart Poettering#include <linux/pci_regs.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "udev.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringenum netname_type{
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering NET_UNDEF,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering NET_PCI,
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering NET_USB,
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering};
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstruct netnames {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering enum netname_type type;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering uint8_t mac[6];
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering bool mac_valid;
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering struct udev_device *pcidev;
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack char pci_slot[IFNAMSIZ];
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering char pci_path[IFNAMSIZ];
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack char pci_onboard[IFNAMSIZ];
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack const char *pci_onboard_label;
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack struct udev_device *usbdev;
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack char usb_ports[IFNAMSIZ];
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack};
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack/* retrieve on-board index number and label from firmware */
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mackstatic int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
8b757a38611006a751c90933d1810cccaa47e1afDaniel Mack const char *index;
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering int idx;
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering index = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering /* SMBIOS type 41 -- Onboard Devices Extended Information */
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering if (!index)
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering index = udev_device_get_sysattr_value(names->pcidev, "index");
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering if (!index)
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering return -ENOENT;
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering idx = strtoul(index, NULL, 0);
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering if (idx <= 0)
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering return -EINVAL;
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering snprintf(names->pci_onboard, sizeof(names->pci_onboard), "o%d", idx);
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering
f0258e473667f44f4656dde49597b2badb9f598aLennart Poettering names->pci_onboard_label = udev_device_get_sysattr_value(names->pcidev, "label");
3cb10d3a0b1b6a7c44f307f2abb5215104e16941Lennart Poettering return 0;
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering}
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering/* read the 256 bytes PCI configuration space to check the multi-function bit */
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poetteringstatic bool is_pci_multifunction(struct udev_device *dev) {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering char filename[256];
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering FILE *f = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char config[64];
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering bool multi = false;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering snprintf(filename, sizeof(filename), "%s/config", udev_device_get_syspath(dev));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering f = fopen(filename, "re");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!f)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto out;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (fread(&config, sizeof(config), 1, f) != 1)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto out;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* bit 0-6 header type, bit 7 multi/single function device */
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if ((config[PCI_HEADER_TYPE] & 0x80) != 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering multi = true;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poetteringout:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if(f)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering fclose(f);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return multi;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering struct udev *udev = udev_device_get_udev(names->pcidev);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering unsigned int bus;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering unsigned int slot;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering unsigned int func;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering unsigned int dev_id = 0;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering size_t l;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char *s;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const char *attr;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering struct udev_device *pci = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char slots[256];
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering DIR *dir;
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering struct dirent *dent;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering char str[256];
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int hotplug_slot = 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int err = 0;
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering if (sscanf(udev_device_get_sysname(names->pcidev), "0000:%x:%x.%d", &bus, &slot, &func) != 3)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -ENOENT;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* kernel provided multi-device index */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering attr = udev_device_get_sysattr_value(dev, "dev_id");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (attr)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering dev_id = strtol(attr, NULL, 16);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* compose a name based on the raw kernel's PCI bus, slot numbers */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering s = names->pci_path;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering l = util_strpcpyf(&s, sizeof(names->pci_path), "p%ds%d", bus, slot);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (func > 0 || is_pci_multifunction(names->pcidev))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering l = util_strpcpyf(&s, l, "f%d", func);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (dev_id > 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering l = util_strpcpyf(&s, l, "d%d", dev_id);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (l == 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering names->pci_path[0] = '\0';
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* ACPI _SUN -- slot user number */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!pci) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering err = -ENOENT;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto out;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering snprintf(slots, sizeof(slots), "%s/slots", udev_device_get_syspath(pci));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering dir = opendir(slots);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!dir) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering err = -errno;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto out;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering }
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering int i;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering char *rest;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering char *address;
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek if (dent->d_name[0] == '.')
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek continue;
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek i = strtol(dent->d_name, &rest, 10);
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek if (rest[0] != '\0')
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek continue;
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek if (i < 1)
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek continue;
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek snprintf(str, sizeof(str), "%s/%s/address", slots, dent->d_name);
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek if (read_one_line_file(str, &address) >= 0) {
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek /* match slot address with device by stripping the function */
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek if (strncmp(address, udev_device_get_sysname(names->pcidev), strlen(address)) == 0)
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek hotplug_slot = i;
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek free(address);
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek }
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen if (hotplug_slot > 0)
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen break;
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek }
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek closedir(dir);
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek if (hotplug_slot > 0) {
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek s = names->pci_slot;
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek l = util_strpcpyf(&s, sizeof(names->pci_slot), "s%d", hotplug_slot);
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek if (func > 0 || is_pci_multifunction(names->pcidev))
ff3d6560bead6879a2fed1bf99bfe8273b3723f1Zbigniew Jędrzejewski-Szmek l = util_strpcpyf(&s, l, "f%d", func);
51323288fc628a5cac50914df915545d685b793eLennart Poettering if (dev_id > 0)
51323288fc628a5cac50914df915545d685b793eLennart Poettering l = util_strpcpyf(&s, l, "d%d", dev_id);
51323288fc628a5cac50914df915545d685b793eLennart Poettering if (l == 0)
51323288fc628a5cac50914df915545d685b793eLennart Poettering names->pci_path[0] = '\0';
51323288fc628a5cac50914df915545d685b793eLennart Poettering }
106784ebb7b303ae471851100a773ad2aebf5b80Daniel Mackout:
106784ebb7b303ae471851100a773ad2aebf5b80Daniel Mack udev_device_unref(pci);
51323288fc628a5cac50914df915545d685b793eLennart Poettering return err;
51323288fc628a5cac50914df915545d685b793eLennart Poettering}
106784ebb7b303ae471851100a773ad2aebf5b80Daniel Mack
51323288fc628a5cac50914df915545d685b793eLennart Poetteringstatic int names_pci(struct udev_device *dev, struct netnames *names) {
51323288fc628a5cac50914df915545d685b793eLennart Poettering struct udev_device *parent;
106784ebb7b303ae471851100a773ad2aebf5b80Daniel Mack
106784ebb7b303ae471851100a773ad2aebf5b80Daniel Mack parent = udev_device_get_parent(dev);
106784ebb7b303ae471851100a773ad2aebf5b80Daniel Mack if (!parent)
106784ebb7b303ae471851100a773ad2aebf5b80Daniel Mack return -ENOENT;
51323288fc628a5cac50914df915545d685b793eLennart Poettering /* check if our direct parent is a PCI device with no other bus in-between */
51323288fc628a5cac50914df915545d685b793eLennart Poettering if (streq("pci", udev_device_get_subsystem(parent))) {
names->type = NET_PCI;
names->pcidev = parent;
} else {
names->pcidev = udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
if (!names->pcidev)
return -ENOENT;
}
dev_pci_onboard(dev, names);
dev_pci_slot(dev, names);
return 0;
}
static int names_usb(struct udev_device *dev, struct netnames *names) {
char name[256];
char *ports;
char *config;
char *interf;
size_t l;
char *s;
names->usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
if (!names->usbdev)
return -ENOENT;
/* get USB port number chain, configuration, interface */
util_strscpy(name, sizeof(name), udev_device_get_sysname(names->usbdev));
s = strchr(name, '-');
if (!s)
return -EINVAL;
ports = s+1;
s = strchr(ports, ':');
if (!s)
return -EINVAL;
s[0] = '\0';
config = s+1;
s = strchr(config, '.');
if (!s)
return -EINVAL;
s[0] = '\0';
interf = s+1;
/* prefix every port number in the chain with "u"*/
s = ports;
while ((s = strchr(s, '.')))
s[0] = 'u';
s = names->usb_ports;
l = util_strpcpyl(&s, sizeof(names->usb_ports), "u", ports, NULL);
/* append USB config number, suppress the common config == 1 */
if (!streq(config, "1"))
l = util_strpcpyl(&s, sizeof(names->usb_ports), "c", config, NULL);
/* append USB interface number, suppress the interface == 0 */
if (!streq(interf, "0"))
l = util_strpcpyl(&s, sizeof(names->usb_ports), "i", interf, NULL);
if (l == 0)
return -ENAMETOOLONG;
names->type = NET_USB;
return 0;
}
static int names_mac(struct udev_device *dev, struct netnames *names) {
const char *s;
unsigned int i;
unsigned int a1, a2, a3, a4, a5, a6;
/* check for NET_ADDR_PERM, skip random MAC addresses */
s = udev_device_get_sysattr_value(dev, "addr_assign_type");
if (!s)
return EXIT_FAILURE;
i = strtoul(s, NULL, 0);
if (i != 0)
return 0;
s = udev_device_get_sysattr_value(dev, "address");
if (!s)
return -ENOENT;
if (sscanf(s, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6)
return -EINVAL;
/* skip empty MAC addresses */
if (a1 + a2 + a3 + a4 + a5 + a6 == 0)
return -EINVAL;
names->mac[0] = a1;
names->mac[1] = a2;
names->mac[2] = a3;
names->mac[3] = a4;
names->mac[4] = a5;
names->mac[5] = a6;
names->mac_valid = true;
return 0;
}
/* IEEE Organizationally Unique Identifier vendor string */
static int ieee_oui(struct udev_device *dev, struct netnames *names, bool test) {
char str[32];
if (!names->mac_valid)
return -ENOENT;
/* skip commonly misused 00:00:00 (Xerox) prefix */
if (memcmp(names->mac, "\0\0\0", 3) == 0)
return -EINVAL;
snprintf(str, sizeof(str), "OUI:%02X%02X%02X%02X%02X%02X",
names->mac[0], names->mac[1], names->mac[2],
names->mac[3], names->mac[4], names->mac[5]);
udev_builtin_hwdb_lookup(dev, str, test);
return 0;
}
static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool test) {
const char *s;
const char *p;
unsigned int i;
const char *devtype;
const char *prefix = "en";
struct netnames names;
int err;
/* handle only ARPHRD_ETHER devices */
s = udev_device_get_sysattr_value(dev, "type");
if (!s)
return EXIT_FAILURE;
i = strtoul(s, NULL, 0);
if (i != 1)
return 0;
/* skip stacked devices, like VLANs, ... */
s = udev_device_get_sysattr_value(dev, "ifindex");
if (!s)
return EXIT_FAILURE;
p = udev_device_get_sysattr_value(dev, "iflink");
if (!p)
return EXIT_FAILURE;
if (strcmp(s, p) != 0)
return 0;
devtype = udev_device_get_devtype(dev);
if (devtype) {
if (streq("wlan", devtype))
prefix = "wl";
else if (streq("wwan", devtype))
prefix = "ww";
}
zero(names);
err = names_mac(dev, &names);
if (err >= 0 && names.mac_valid) {
char str[IFNAMSIZ];
snprintf(str, sizeof(str), "%sx%02x%02x%02x%02x%02x%02x", prefix,
names.mac[0], names.mac[1], names.mac[2],
names.mac[3], names.mac[4], names.mac[5]);
udev_builtin_add_property(dev, test, "ID_NET_NAME_MAC", str);
ieee_oui(dev, &names, test);
}
/* get PCI based path names, we compose only PCI based paths */
err = names_pci(dev, &names);
if (err < 0)
goto out;
/* plain PCI device */
if (names.type == NET_PCI) {
char str[IFNAMSIZ];
if (names.pci_onboard[0])
if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard) < (int)sizeof(str))
udev_builtin_add_property(dev, test, "ID_NET_NAME_ONBOARD", str);
if (names.pci_onboard_label)
if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard_label) < (int)sizeof(str))
udev_builtin_add_property(dev, test, "ID_NET_LABEL_ONBOARD", str);
if (names.pci_path[0])
if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_path) < (int)sizeof(str))
udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
if (names.pci_slot[0])
if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_slot) < (int)sizeof(str))
udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
goto out;
}
/* USB device */
err = names_usb(dev, &names);
if (err >= 0 && names.type == NET_USB) {
char str[IFNAMSIZ];
if (names.pci_path[0])
if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.usb_ports) < (int)sizeof(str))
udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
if (names.pci_slot[0])
if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.usb_ports) < (int)sizeof(str))
udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
}
out:
return EXIT_SUCCESS;
}
const struct udev_builtin udev_builtin_net_id = {
.name = "net_id",
.cmd = builtin_net_id,
.help = "network device properties",
};