udev-builtin-net_id.c revision decd634e801bee2c554edb35383cc9d43417a850
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
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * - physical/geographical location of the hardware
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * - the interface's MAC address
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen *
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen * Two character prefixes based on the type of interface:
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering * en -- ethernet
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering * wl -- wlan
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering * ww -- wwan
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * Type of names:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * o<index> -- on-board device index number
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering * s<slot>[f<function>] -- hotplug slot index number
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * x<MAC> -- MAC address
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * p<bus>s<slot>[f<function>] -- PCI geographical location
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * p<bus>s<slot>[f<function>][u<port>][...][c<config>][i<interface>]
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * -- USB port number chain
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering *
b93312f5960b276bae915906ccde36f545bae3e0Zbigniew Jędrzejewski-Szmek * All multi-function PCI devices will carry the [f<function>] number in the
b93312f5960b276bae915906ccde36f545bae3e0Zbigniew Jędrzejewski-Szmek * device name, including the function 0 device.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * For USB devices the full chain of port numbers of hubs is composed. If the
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * name gets longer than the maximum number of 15 characters, the name is not
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * exported.
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * The usual USB configuration == 1 and interface == 0 values are suppressed.
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering *
23502de3b0891455c8ce499a9eb61b69d060a829Daniel Mack * PCI ethernet card with firmware index "1":
23502de3b0891455c8ce499a9eb61b69d060a829Daniel Mack * ID_NET_NAME_ONBOARD=eno1
23502de3b0891455c8ce499a9eb61b69d060a829Daniel Mack * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering *
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * PCI ethernet card in hotplug slot with firmware index number:
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_MAC=enx000000000466
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_PATH=enp5s0
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_SLOT=ens1
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering *
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * PCI ethernet multi-function card with 2 ports:
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_MAC=enx78e7d1ea46da
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_PATH=enp2s0f0
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/net/enp2s0f1
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_MAC=enx78e7d1ea46dc
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_PATH=enp2s0f1
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering *
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * PCI wlan card:
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * /sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_MAC=wlx0024d7e31130
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_PATH=wlp3s0
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering *
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * USB built-in 3G modem:
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_MAC=wwx028037ec0200
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * ID_NET_NAME_PATH=wwp0s29u1u4i6
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering *
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * USB Android phone:
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * ID_NET_NAME_MAC=enxd626b3450fb5
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * ID_NET_NAME_PATH=enp0s29u1u2
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
23502de3b0891455c8ce499a9eb61b69d060a829Daniel Mack#include <stdio.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <stdlib.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <stdarg.h>
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poettering#include <unistd.h>
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poettering#include <string.h>
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poettering#include <errno.h>
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poettering#include <net/if.h>
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poettering#include <linux/pci_regs.h>
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poettering
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poettering#include "udev.h"
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poettering
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poetteringenum netname_type{
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poettering NET_UNDEF,
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poettering NET_PCI,
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poettering NET_USB,
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poettering};
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poetteringstruct netnames {
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering enum netname_type type;
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering uint8_t mac[6];
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering bool mac_valid;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering struct udev_device *pcidev;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering char pci_slot[IFNAMSIZ];
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char pci_path[IFNAMSIZ];
a8812dd7f161a3e459c1730ac92ff2bbc9986ff1Lennart Poettering char pci_onboard[IFNAMSIZ];
a8812dd7f161a3e459c1730ac92ff2bbc9986ff1Lennart Poettering const char *pci_onboard_label;
a8812dd7f161a3e459c1730ac92ff2bbc9986ff1Lennart Poettering
a8812dd7f161a3e459c1730ac92ff2bbc9986ff1Lennart Poettering struct udev_device *usbdev;
a8812dd7f161a3e459c1730ac92ff2bbc9986ff1Lennart Poettering char usb_ports[IFNAMSIZ];
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering};
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/* retrieve on-board index number and label from firmware */
f5430a3ef308f3a102899fcaf7fbece757082f2aLennart Poetteringstatic int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
d75acfb059ece4512278b8820a9103664996f1e5Lennart Poettering const char *index;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int idx;
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering index = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering /* SMBIOS type 41 -- Onboard Devices Extended Information */
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering if (!index)
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering index = udev_device_get_sysattr_value(names->pcidev, "index");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!index)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -ENOENT;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering idx = strtoul(index, NULL, 0);
8ac4e9e1e54397f6d1745c2a7a806132418c7da2Lennart Poettering if (idx <= 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EINVAL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering snprintf(names->pci_onboard, sizeof(names->pci_onboard), "o%d", idx);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering names->pci_onboard_label = udev_device_get_sysattr_value(names->pcidev, "label");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
2e276efc7b0398a3086629a52970bdd4ab7252f9Zbigniew Jędrzejewski-Szmek
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering/* read the 256 bytes PCI configuration space to check the multi-function bit */
c0eb11cfd016381fe02875a4ef29c1ade00c94e7Lennart Poetteringstatic bool is_pci_singlefunction(struct udev_device *dev) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char filename[256];
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering FILE *f;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char config[64];
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering bool single = false;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering snprintf(filename, sizeof(filename), "%s/config", udev_device_get_syspath(dev));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering f = fopen(filename, "re");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (!f)
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering goto out;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering if (fread(&config, sizeof(config), 1, f) != 1)
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering goto out;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering /* bit 0-6 header type, bit 7 multi/single function device */
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering if ((config[PCI_HEADER_TYPE] & 0x80) == 0)
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering single = true;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poetteringout:
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering fclose(f);
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering return single;
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek}
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmekstatic int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek struct udev *udev = udev_device_get_udev(names->pcidev);
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek unsigned int bus;
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek unsigned int slot;
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek unsigned int func;
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek struct udev_device *pci = NULL;
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek char slots[256];
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek DIR *dir;
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek struct dirent *dent;
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek char str[256];
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek int hotplug_slot = 0;
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek int err = 0;
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering /* compose a name based on the raw kernel's PCI bus, slot numbers */
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen if (sscanf(udev_device_get_sysname(names->pcidev), "0000:%x:%x.%d", &bus, &slot, &func) != 3)
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen return -ENOENT;
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen if (func == 0 && is_pci_singlefunction(names->pcidev))
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen snprintf(names->pci_path, sizeof(names->pci_path), "p%ds%d", bus, slot);
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen else
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen snprintf(names->pci_path, sizeof(names->pci_path), "p%ds%df%d", bus, slot, func);
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen /* ACPI _SUN -- slot user number */
549c1a2564b56f2bb38f1203d59c747ea15817f3Tom Gundersen pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering if (!pci) {
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering err = -ENOENT;
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering goto out;
549c1a2564b56f2bb38f1203d59c747ea15817f3Tom Gundersen }
549c1a2564b56f2bb38f1203d59c747ea15817f3Tom Gundersen snprintf(slots, sizeof(slots), "%s/slots", udev_device_get_syspath(pci));
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering dir = opendir(slots);
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek if (!dir) {
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek err = -errno;
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek goto out;
f91dc2400dc33e9a0745ecaaef7489af116dca38Lennart Poettering }
f91dc2400dc33e9a0745ecaaef7489af116dca38Lennart Poettering
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek int i;
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek char *rest;
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek char *address;
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek if (dent->d_name[0] == '.')
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek continue;
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek i = strtol(dent->d_name, &rest, 10);
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek if (rest[0] != '\0')
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek continue;
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek if (i < 1)
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek continue;
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek snprintf(str, sizeof(str), "%s/%s/address", slots, dent->d_name);
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek if (read_one_line_file(str, &address) >= 0) {
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek /* match slot address with device by stripping the function */
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek if (strncmp(address, udev_device_get_sysname(names->pcidev), strlen(address)) == 0)
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek hotplug_slot = i;
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek free(address);
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen }
9ead3519c54b6d1b79b35541873b5cf7c8b3a7d3Lennart Poettering
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen if (hotplug_slot > 0)
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen break;
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen }
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen closedir(dir);
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen if (hotplug_slot > 0) {
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen if (func == 0 && is_pci_singlefunction(names->pcidev))
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen snprintf(names->pci_slot, sizeof(names->pci_slot), "s%d", hotplug_slot);
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen else
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen snprintf(names->pci_slot, sizeof(names->pci_slot), "s%df%d", hotplug_slot, func);
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen }
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersenout:
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen udev_device_unref(pci);
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen return err;
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int names_pci(struct udev_device *dev, struct netnames *names) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering struct udev_device *parent;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering parent = udev_device_get_parent(dev);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (!parent)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return -ENOENT;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* check if our direct parent is a PCI device with no other bus in-between */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (streq("pci", udev_device_get_subsystem(parent))) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering names->type = NET_PCI;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering names->pcidev = parent;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering } else {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering names->pcidev = udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (!names->pcidev)
36d9205d669bcdcb04fa730d1f3549a9fc9a9001Tom Gundersen return -ENOENT;
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering }
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering dev_pci_onboard(dev, names);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering dev_pci_slot(dev, names);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return 0;
28b9b7640603f88cb49f95609331fa5072715f15Lennart Poettering}
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
105e151299dc1208855380be2b22d0db2d66ebc6Lennart Poetteringstatic int names_usb(struct udev_device *dev, struct netnames *names) {
5d27351f8546530cf779847b0b04b0172c09f9d0Tom Gundersen char name[256];
547973dea7abd6c124ff6c79fe2bbe322a7314aeLennart Poettering char *ports;
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering char *config;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering char *interf;
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering size_t l;
7778dffff3d8bd7438fe19a248c16203668324c9Daniel Mack char *s;
7778dffff3d8bd7438fe19a248c16203668324c9Daniel Mack
7778dffff3d8bd7438fe19a248c16203668324c9Daniel Mack names->usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
7778dffff3d8bd7438fe19a248c16203668324c9Daniel Mack if (!names->usbdev)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return -ENOENT;
8bf52d3d17d364438191077d0750b8b80b5dc53aLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* get USB port number chain, configuration, interface */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering util_strscpy(name, sizeof(name), udev_device_get_sysname(names->usbdev));
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering s = strchr(name, '-');
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering if (!s)
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering return -EINVAL;
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering ports = s+1;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering s = strchr(ports, ':');
a8812dd7f161a3e459c1730ac92ff2bbc9986ff1Lennart Poettering if (!s)
a8812dd7f161a3e459c1730ac92ff2bbc9986ff1Lennart Poettering return -EINVAL;
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering s[0] = '\0';
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering config = s+1;
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering s = strchr(config, '.');
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering if (!s)
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt return -EINVAL;
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt s[0] = '\0';
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering interf = s+1;
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering /* prefix every port number in the chain with "u"*/
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering s = ports;
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering while ((s = strchr(s, '.')))
8730bccfc59fe507bd3e0a3abcf411b497ac4f0eLennart Poettering 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;
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;
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",
};