a660c63c551b88136ac6176855b5907cc533e848Kay Sievers/***
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers This file is part of systemd.
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers Copyright 2012 Kay Sievers <kay@vrfy.org>
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers systemd is free software; you can redistribute it and/or modify it
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers under the terms of the GNU Lesser General Public License as published by
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers the Free Software Foundation; either version 2.1 of the License, or
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers (at your option) any later version.
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers systemd is distributed in the hope that it will be useful, but
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers WITHOUT ANY WARRANTY; without even the implied warranty of
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers Lesser General Public License for more details.
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers You should have received a copy of the GNU Lesser General Public License
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers along with systemd; If not, see <http://www.gnu.org/licenses/>.
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers***/
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers/*
ad37f393fa97f4274cc3bf97a0d8c388a429037eKay Sievers * Predictable network interface device names based on:
472780d8b1ec3f3f4ff78eb21a013136e5aa1cfeKay Sievers * - firmware/bios-provided index numbers for on-board devices
472780d8b1ec3f3f4ff78eb21a013136e5aa1cfeKay Sievers * - firmware-provided pci-express hotplug slot index number
472780d8b1ec3f3f4ff78eb21a013136e5aa1cfeKay Sievers * - physical/geographical location of the hardware
472780d8b1ec3f3f4ff78eb21a013136e5aa1cfeKay Sievers * - the interface's MAC address
472780d8b1ec3f3f4ff78eb21a013136e5aa1cfeKay Sievers *
25da63b9dac8f166ebf390ca92d1de18fbfc9d11Kay Sievers * http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames
25da63b9dac8f166ebf390ca92d1de18fbfc9d11Kay Sievers *
ad37f393fa97f4274cc3bf97a0d8c388a429037eKay Sievers * Two character prefixes based on the type of interface:
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt * en -- Ethernet
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner * sl -- serial line IP (slip)
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * wl -- wlan
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * ww -- wwan
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers *
ad37f393fa97f4274cc3bf97a0d8c388a429037eKay Sievers * Type of names:
d4b687c96adf207f0878aebf3ce3371f6160687fKay Sievers * b<number> -- BCMA bus core number
0037a669ac9a2bbedccdb2f483111351e8ff4659Dimitri John Ledkov * c<bus_id> -- CCW bus group name, without leading zeros [s390]
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen * o<index>[d<dev_port>] -- on-board device index number
3058e017fced6d5c8712e10c8c1477421bc1e960Thadeu Lima de Souza Cascardo * s<slot>[f<function>][d<dev_port>] -- hotplug slot index number
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers * x<MAC> -- MAC address
3058e017fced6d5c8712e10c8c1477421bc1e960Thadeu Lima de Souza Cascardo * [P<domain>]p<bus>s<slot>[f<function>][d<dev_port>]
214daa72cb0c72ea78d1eccd5ffe630a1e04b2f7Sean McGovern * -- PCI geographical location
214daa72cb0c72ea78d1eccd5ffe630a1e04b2f7Sean McGovern * [P<domain>]p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers * -- USB port number chain
472780d8b1ec3f3f4ff78eb21a013136e5aa1cfeKay Sievers *
ad37f393fa97f4274cc3bf97a0d8c388a429037eKay Sievers * All multi-function PCI devices will carry the [f<function>] number in the
472780d8b1ec3f3f4ff78eb21a013136e5aa1cfeKay Sievers * device name, including the function 0 device.
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers *
214daa72cb0c72ea78d1eccd5ffe630a1e04b2f7Sean McGovern * When using PCI geography, The PCI domain is only prepended when it is not 0.
214daa72cb0c72ea78d1eccd5ffe630a1e04b2f7Sean McGovern *
0d6ce9236f61cb991d7e8f2359d818e41ead0cf5Kay Sievers * For USB devices the full chain of port numbers of hubs is composed. If the
0d6ce9236f61cb991d7e8f2359d818e41ead0cf5Kay Sievers * name gets longer than the maximum number of 15 characters, the name is not
0d6ce9236f61cb991d7e8f2359d818e41ead0cf5Kay Sievers * exported.
0d6ce9236f61cb991d7e8f2359d818e41ead0cf5Kay Sievers * The usual USB configuration == 1 and interface == 0 values are suppressed.
ad37f393fa97f4274cc3bf97a0d8c388a429037eKay Sievers *
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt * PCI Ethernet card with firmware index "1":
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers * ID_NET_NAME_ONBOARD=eno1
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers *
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt * PCI Ethernet card in hotplug slot with firmware index number:
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers * ID_NET_NAME_MAC=enx000000000466
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers * ID_NET_NAME_PATH=enp5s0
de892aea1c486b59e04884268b612081d1660514Kay Sievers * ID_NET_NAME_SLOT=ens1
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers *
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt * PCI Ethernet multi-function card with 2 ports:
decd634e801bee2c554edb35383cc9d43417a850Kay Sievers * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0
decd634e801bee2c554edb35383cc9d43417a850Kay Sievers * ID_NET_NAME_MAC=enx78e7d1ea46da
decd634e801bee2c554edb35383cc9d43417a850Kay Sievers * ID_NET_NAME_PATH=enp2s0f0
decd634e801bee2c554edb35383cc9d43417a850Kay Sievers * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/net/enp2s0f1
decd634e801bee2c554edb35383cc9d43417a850Kay Sievers * ID_NET_NAME_MAC=enx78e7d1ea46dc
decd634e801bee2c554edb35383cc9d43417a850Kay Sievers * ID_NET_NAME_PATH=enp2s0f1
decd634e801bee2c554edb35383cc9d43417a850Kay Sievers *
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers * PCI wlan card:
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers * /sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers * ID_NET_NAME_MAC=wlx0024d7e31130
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers * ID_NET_NAME_PATH=wlp3s0
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers *
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers * USB built-in 3G modem:
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers * ID_NET_NAME_MAC=wwx028037ec0200
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers * ID_NET_NAME_PATH=wwp0s29u1u4i6
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers *
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers * USB Android phone:
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers * ID_NET_NAME_MAC=enxd626b3450fb5
f610d6de38119b372b377ec41b2a6089872d3294Kay Sievers * ID_NET_NAME_PATH=enp0s29u1u2
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers#include <errno.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <fcntl.h>
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers#include <net/if.h>
19aa72f74e41045510b4af3f1415b419d42ff20bTom Gundersen#include <net/if_arp.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <stdarg.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <stdio.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <stdlib.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <string.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <unistd.h>
de892aea1c486b59e04884268b612081d1660514Kay Sievers#include <linux/pci_regs.h>
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "fd-util.h"
a5c32cff1f56afe6f0c6c70d91a88a7a8238b2d7Harald Hoyer#include "fileio.h"
d054f0a4d451120c26494263fc4dc175bfd405b1Daniel Mack#include "stdio-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "string-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "udev.h"
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers
6c1e69f9456d022f14dd00737126cfa4d9cca10cLennart Poettering#define ONBOARD_INDEX_MAX (16*1024-1)
6c1e69f9456d022f14dd00737126cfa4d9cca10cLennart Poettering
0260944060426d54d9ecb40930baad985cbd02a1Kay Sieversenum netname_type{
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers NET_UNDEF,
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers NET_PCI,
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers NET_USB,
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers NET_BCMA,
e3d563346c4237af23335cc6904e0662efdf62adTom Gundersen NET_VIRTIO,
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner NET_CCWGROUP,
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers};
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sieversstruct netnames {
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers enum netname_type type;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers uint8_t mac[6];
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers bool mac_valid;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers struct udev_device *pcidev;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers char pci_slot[IFNAMSIZ];
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers char pci_path[IFNAMSIZ];
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers char pci_onboard[IFNAMSIZ];
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers const char *pci_onboard_label;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers char usb_ports[IFNAMSIZ];
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers char bcma_core[IFNAMSIZ];
d4b687c96adf207f0878aebf3ce3371f6160687fKay Sievers char ccw_group[IFNAMSIZ];
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers};
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers/* retrieve on-board index number and label from firmware */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sieversstatic int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen unsigned dev_port = 0;
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen size_t l;
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen char *s;
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen const char *attr;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers int idx;
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen attr = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
01d183ddae6fb3445c4519cf1d90c6575f17292eKay Sievers /* SMBIOS type 41 -- Onboard Devices Extended Information */
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen if (!attr)
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen attr = udev_device_get_sysattr_value(names->pcidev, "index");
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen if (!attr)
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers return -ENOENT;
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen idx = strtoul(attr, NULL, 0);
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers if (idx <= 0)
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers return -EINVAL;
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen
6c1e69f9456d022f14dd00737126cfa4d9cca10cLennart Poettering /* Some BIOSes report rubbish indexes that are excessively high (2^24-1 is an index VMware likes to report for
6c1e69f9456d022f14dd00737126cfa4d9cca10cLennart Poettering * example). Let's define a cut-off where we don't consider the index reliable anymore. We pick some arbitrary
6c1e69f9456d022f14dd00737126cfa4d9cca10cLennart Poettering * cut-off, which is somewhere beyond the realistic number of physical network interface a system might
6c1e69f9456d022f14dd00737126cfa4d9cca10cLennart Poettering * have. Ideally the kernel would already filter his crap for us, but it doesn't currently. */
6c1e69f9456d022f14dd00737126cfa4d9cca10cLennart Poettering if (idx > ONBOARD_INDEX_MAX)
6c1e69f9456d022f14dd00737126cfa4d9cca10cLennart Poettering return -ENOENT;
6c1e69f9456d022f14dd00737126cfa4d9cca10cLennart Poettering
309b578d313b363974b99e48f0e378111cc1fa91Tom Gundersen /* kernel provided port index for multiple ports on a single PCI function */
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen attr = udev_device_get_sysattr_value(dev, "dev_port");
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen if (attr)
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen dev_port = strtol(attr, NULL, 10);
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen s = names->pci_onboard;
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen l = sizeof(names->pci_onboard);
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen l = strpcpyf(&s, l, "o%d", idx);
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen if (dev_port > 0)
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen l = strpcpyf(&s, l, "d%d", dev_port);
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen if (l == 0)
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen names->pci_onboard[0] = '\0';
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers names->pci_onboard_label = udev_device_get_sysattr_value(names->pcidev, "label");
c0a43734ca84a3c9170d4a2d7f4d329b9ef47abcTom Gundersen
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers return 0;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers}
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers
137661d87525a3c339afd2804e577532d58d3fbcKay Sievers/* read the 256 bytes PCI configuration space to check the multi-function bit */
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sieversstatic bool is_pci_multifunction(struct udev_device *dev) {
0454229c100a2113ba82df55703436d6cb2c492bJason S. McMullan _cleanup_close_ int fd = -1;
1cb5d1f31909c731d93568eb4838cb86e033d783Lennart Poettering const char *filename;
1cb5d1f31909c731d93568eb4838cb86e033d783Lennart Poettering uint8_t config[64];
de892aea1c486b59e04884268b612081d1660514Kay Sievers
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering filename = strjoina(udev_device_get_syspath(dev), "/config");
0454229c100a2113ba82df55703436d6cb2c492bJason S. McMullan fd = open(filename, O_RDONLY | O_CLOEXEC);
0454229c100a2113ba82df55703436d6cb2c492bJason S. McMullan if (fd < 0)
1cb5d1f31909c731d93568eb4838cb86e033d783Lennart Poettering return false;
0454229c100a2113ba82df55703436d6cb2c492bJason S. McMullan if (read(fd, &config, sizeof(config)) != sizeof(config))
1cb5d1f31909c731d93568eb4838cb86e033d783Lennart Poettering return false;
de892aea1c486b59e04884268b612081d1660514Kay Sievers
de892aea1c486b59e04884268b612081d1660514Kay Sievers /* bit 0-6 header type, bit 7 multi/single function device */
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers if ((config[PCI_HEADER_TYPE] & 0x80) != 0)
1cb5d1f31909c731d93568eb4838cb86e033d783Lennart Poettering return true;
1cb5d1f31909c731d93568eb4838cb86e033d783Lennart Poettering
1cb5d1f31909c731d93568eb4838cb86e033d783Lennart Poettering return false;
de892aea1c486b59e04884268b612081d1660514Kay Sievers}
de892aea1c486b59e04884268b612081d1660514Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sieversstatic int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers struct udev *udev = udev_device_get_udev(names->pcidev);
3058e017fced6d5c8712e10c8c1477421bc1e960Thadeu Lima de Souza Cascardo unsigned domain, bus, slot, func, dev_port = 0;
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers size_t l;
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers char *s;
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers const char *attr;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers struct udev_device *pci = NULL;
b5dd8148730db080b48b874c214f8f74ae787d6bZbigniew Jędrzejewski-Szmek char slots[256], str[256];
b5dd8148730db080b48b874c214f8f74ae787d6bZbigniew Jędrzejewski-Szmek _cleanup_closedir_ DIR *dir = NULL;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers struct dirent *dent;
b5dd8148730db080b48b874c214f8f74ae787d6bZbigniew Jędrzejewski-Szmek int hotplug_slot = 0, err = 0;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers
b5dd8148730db080b48b874c214f8f74ae787d6bZbigniew Jędrzejewski-Szmek if (sscanf(udev_device_get_sysname(names->pcidev), "%x:%x:%x.%u", &domain, &bus, &slot, &func) != 4)
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers return -ENOENT;
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers
309b578d313b363974b99e48f0e378111cc1fa91Tom Gundersen /* kernel provided port index for multiple ports on a single PCI function */
3058e017fced6d5c8712e10c8c1477421bc1e960Thadeu Lima de Souza Cascardo attr = udev_device_get_sysattr_value(dev, "dev_port");
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers if (attr)
3058e017fced6d5c8712e10c8c1477421bc1e960Thadeu Lima de Souza Cascardo dev_port = strtol(attr, NULL, 10);
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers /* compose a name based on the raw kernel's PCI bus, slot numbers */
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers s = names->pci_path;
214daa72cb0c72ea78d1eccd5ffe630a1e04b2f7Sean McGovern l = sizeof(names->pci_path);
214daa72cb0c72ea78d1eccd5ffe630a1e04b2f7Sean McGovern if (domain > 0)
1fa2f38f0f011010bf57522b42fcc168856a7003Zbigniew Jędrzejewski-Szmek l = strpcpyf(&s, l, "P%u", domain);
1fa2f38f0f011010bf57522b42fcc168856a7003Zbigniew Jędrzejewski-Szmek l = strpcpyf(&s, l, "p%us%u", bus, slot);
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers if (func > 0 || is_pci_multifunction(names->pcidev))
1fa2f38f0f011010bf57522b42fcc168856a7003Zbigniew Jędrzejewski-Szmek l = strpcpyf(&s, l, "f%u", func);
3058e017fced6d5c8712e10c8c1477421bc1e960Thadeu Lima de Souza Cascardo if (dev_port > 0)
1fa2f38f0f011010bf57522b42fcc168856a7003Zbigniew Jędrzejewski-Szmek l = strpcpyf(&s, l, "d%u", dev_port);
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers if (l == 0)
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers names->pci_path[0] = '\0';
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers /* ACPI _SUN -- slot user number */
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers if (!pci) {
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers err = -ENOENT;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers goto out;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers }
d054f0a4d451120c26494263fc4dc175bfd405b1Daniel Mack xsprintf(slots, "%s/slots", udev_device_get_syspath(pci));
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers dir = opendir(slots);
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers if (!dir) {
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers err = -errno;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers goto out;
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers }
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers int i;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers char *rest;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers char *address;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers if (dent->d_name[0] == '.')
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers continue;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers i = strtol(dent->d_name, &rest, 10);
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers if (rest[0] != '\0')
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers continue;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers if (i < 1)
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers continue;
d054f0a4d451120c26494263fc4dc175bfd405b1Daniel Mack xsprintf(str, "%s/%s/address", slots, dent->d_name);
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers if (read_one_line_file(str, &address) >= 0) {
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers /* match slot address with device by stripping the function */
641906e9366891e0ad3e6e38b7396a427678c4cfThomas Hindoe Paaboel Andersen if (strneq(address, udev_device_get_sysname(names->pcidev), strlen(address)))
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers hotplug_slot = i;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers free(address);
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers }
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers if (hotplug_slot > 0)
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers break;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers }
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers if (hotplug_slot > 0) {
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers s = names->pci_slot;
214daa72cb0c72ea78d1eccd5ffe630a1e04b2f7Sean McGovern l = sizeof(names->pci_slot);
214daa72cb0c72ea78d1eccd5ffe630a1e04b2f7Sean McGovern if (domain > 0)
214daa72cb0c72ea78d1eccd5ffe630a1e04b2f7Sean McGovern l = strpcpyf(&s, l, "P%d", domain);
214daa72cb0c72ea78d1eccd5ffe630a1e04b2f7Sean McGovern l = strpcpyf(&s, l, "s%d", hotplug_slot);
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers if (func > 0 || is_pci_multifunction(names->pcidev))
d5a89d7dc17a5ba5cf4fc71f82963c5c94a31c3dKay Sievers l = strpcpyf(&s, l, "f%d", func);
3058e017fced6d5c8712e10c8c1477421bc1e960Thadeu Lima de Souza Cascardo if (dev_port > 0)
3058e017fced6d5c8712e10c8c1477421bc1e960Thadeu Lima de Souza Cascardo l = strpcpyf(&s, l, "d%d", dev_port);
1328f66ad16b5afeb5684858c27e121a46c1959eKay Sievers if (l == 0)
16f948cb208f1db9a1665f07ac9b22e416dc19d4Tom Gundersen names->pci_slot[0] = '\0';
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers }
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sieversout:
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers udev_device_unref(pci);
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers return err;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers}
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sieversstatic int names_pci(struct udev_device *dev, struct netnames *names) {
5b8180d3f6598a1b2f296645690de41d726fd5abKay Sievers struct udev_device *parent;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers
3b64e4d4f40baac56148c7d333d6a0053358ec7aTom Gundersen assert(dev);
3b64e4d4f40baac56148c7d333d6a0053358ec7aTom Gundersen assert(names);
3b64e4d4f40baac56148c7d333d6a0053358ec7aTom Gundersen
5b8180d3f6598a1b2f296645690de41d726fd5abKay Sievers parent = udev_device_get_parent(dev);
54683f0f9b97a8f88aaf4fbb45b4d729057b101cTom Gundersen
54683f0f9b97a8f88aaf4fbb45b4d729057b101cTom Gundersen /* there can only ever be one virtio bus per parent device, so we can
54683f0f9b97a8f88aaf4fbb45b4d729057b101cTom Gundersen safely ignore any virtio buses. see
54683f0f9b97a8f88aaf4fbb45b4d729057b101cTom Gundersen <http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030331.html> */
54683f0f9b97a8f88aaf4fbb45b4d729057b101cTom Gundersen while (parent && streq_ptr("virtio", udev_device_get_subsystem(parent)))
54683f0f9b97a8f88aaf4fbb45b4d729057b101cTom Gundersen parent = udev_device_get_parent(parent);
54683f0f9b97a8f88aaf4fbb45b4d729057b101cTom Gundersen
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (!parent)
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers return -ENOENT;
54683f0f9b97a8f88aaf4fbb45b4d729057b101cTom Gundersen
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers /* check if our direct parent is a PCI device with no other bus in-between */
bb26309dd042c79de907f103d83f398b9436cde0Rob Clark if (streq_ptr("pci", udev_device_get_subsystem(parent))) {
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers names->type = NET_PCI;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers names->pcidev = parent;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers } else {
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers names->pcidev = udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (!names->pcidev)
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers return -ENOENT;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers }
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers dev_pci_onboard(dev, names);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers dev_pci_slot(dev, names);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers return 0;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers}
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sieversstatic int names_usb(struct udev_device *dev, struct netnames *names) {
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers struct udev_device *usbdev;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers char name[256];
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers char *ports;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers char *config;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers char *interf;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers size_t l;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers char *s;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
3b64e4d4f40baac56148c7d333d6a0053358ec7aTom Gundersen assert(dev);
3b64e4d4f40baac56148c7d333d6a0053358ec7aTom Gundersen assert(names);
3b64e4d4f40baac56148c7d333d6a0053358ec7aTom Gundersen
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers if (!usbdev)
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers return -ENOENT;
0035597a30d120f70df2dd7da3d6128fb8ba6051Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers /* get USB port number chain, configuration, interface */
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers strscpy(name, sizeof(name), udev_device_get_sysname(usbdev));
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers s = strchr(name, '-');
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (!s)
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers return -EINVAL;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers ports = s+1;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers s = strchr(ports, ':');
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (!s)
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers return -EINVAL;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers s[0] = '\0';
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers config = s+1;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers s = strchr(config, '.');
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (!s)
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers return -EINVAL;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers s[0] = '\0';
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers interf = s+1;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
f7340ab269828d917cd1281e33e6dd4fdfee67b3Torstein Husebø /* prefix every port number in the chain with "u" */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers s = ports;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers while ((s = strchr(s, '.')))
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers s[0] = 'u';
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers s = names->usb_ports;
d5a89d7dc17a5ba5cf4fc71f82963c5c94a31c3dKay Sievers l = strpcpyl(&s, sizeof(names->usb_ports), "u", ports, NULL);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers /* append USB config number, suppress the common config == 1 */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (!streq(config, "1"))
d5a89d7dc17a5ba5cf4fc71f82963c5c94a31c3dKay Sievers l = strpcpyl(&s, sizeof(names->usb_ports), "c", config, NULL);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers /* append USB interface number, suppress the interface == 0 */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (!streq(interf, "0"))
d5a89d7dc17a5ba5cf4fc71f82963c5c94a31c3dKay Sievers l = strpcpyl(&s, sizeof(names->usb_ports), "i", interf, NULL);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (l == 0)
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers return -ENAMETOOLONG;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers names->type = NET_USB;
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers return 0;
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers}
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sieversstatic int names_bcma(struct udev_device *dev, struct netnames *names) {
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers struct udev_device *bcmadev;
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers unsigned int core;
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers
3b64e4d4f40baac56148c7d333d6a0053358ec7aTom Gundersen assert(dev);
3b64e4d4f40baac56148c7d333d6a0053358ec7aTom Gundersen assert(names);
3b64e4d4f40baac56148c7d333d6a0053358ec7aTom Gundersen
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers bcmadev = udev_device_get_parent_with_subsystem_devtype(dev, "bcma", NULL);
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers if (!bcmadev)
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers return -ENOENT;
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers
f4ddacbd4de0f159ec598f8ad690466a84787ec5Kay Sievers /* bus num:core num */
b5dd8148730db080b48b874c214f8f74ae787d6bZbigniew Jędrzejewski-Szmek if (sscanf(udev_device_get_sysname(bcmadev), "bcma%*u:%u", &core) != 1)
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers return -EINVAL;
f4ddacbd4de0f159ec598f8ad690466a84787ec5Kay Sievers /* suppress the common core == 0 */
f4ddacbd4de0f159ec598f8ad690466a84787ec5Kay Sievers if (core > 0)
d054f0a4d451120c26494263fc4dc175bfd405b1Daniel Mack xsprintf(names->bcma_core, "b%u", core);
f4ddacbd4de0f159ec598f8ad690466a84787ec5Kay Sievers
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers names->type = NET_BCMA;
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers return 0;
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers}
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Bruecknerstatic int names_ccw(struct udev_device *dev, struct netnames *names) {
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner struct udev_device *cdev;
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner const char *bus_id;
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner size_t bus_id_len;
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner int rc;
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner
3b64e4d4f40baac56148c7d333d6a0053358ec7aTom Gundersen assert(dev);
3b64e4d4f40baac56148c7d333d6a0053358ec7aTom Gundersen assert(names);
3b64e4d4f40baac56148c7d333d6a0053358ec7aTom Gundersen
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner /* Retrieve the associated CCW device */
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner cdev = udev_device_get_parent(dev);
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner if (!cdev)
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner return -ENOENT;
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner /* Network devices are always grouped CCW devices */
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner if (!streq_ptr("ccwgroup", udev_device_get_subsystem(cdev)))
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner return -ENOENT;
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner /* Retrieve bus-ID of the grouped CCW device. The bus-ID uniquely
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner * identifies the network device on the Linux on System z channel
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner * subsystem. Note that the bus-ID contains lowercase characters.
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner */
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner bus_id = udev_device_get_sysname(cdev);
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner if (!bus_id)
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner return -ENOENT;
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner /* Check the length of the bus-ID. Rely on that the kernel provides
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner * a correct bus-ID; alternatively, improve this check and parse and
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner * verify each bus-ID part...
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner */
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner bus_id_len = strlen(bus_id);
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner if (!bus_id_len || bus_id_len < 8 || bus_id_len > 9)
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner return -EINVAL;
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner
0037a669ac9a2bbedccdb2f483111351e8ff4659Dimitri John Ledkov /* Strip leading zeros from the bus id for aesthetic purposes. This
0037a669ac9a2bbedccdb2f483111351e8ff4659Dimitri John Ledkov * keeps the ccw names stable, yet much shorter in general case of
0037a669ac9a2bbedccdb2f483111351e8ff4659Dimitri John Ledkov * bus_id 0.0.0600 -> 600. This is similar to e.g. how PCI domain is
0037a669ac9a2bbedccdb2f483111351e8ff4659Dimitri John Ledkov * not prepended when it is zero.
0037a669ac9a2bbedccdb2f483111351e8ff4659Dimitri John Ledkov */
0037a669ac9a2bbedccdb2f483111351e8ff4659Dimitri John Ledkov bus_id += strspn(bus_id, ".0");
0037a669ac9a2bbedccdb2f483111351e8ff4659Dimitri John Ledkov
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner /* Store the CCW bus-ID for use as network device name */
0037a669ac9a2bbedccdb2f483111351e8ff4659Dimitri John Ledkov rc = snprintf(names->ccw_group, sizeof(names->ccw_group), "c%s", bus_id);
d4b687c96adf207f0878aebf3ce3371f6160687fKay Sievers if (rc >= 0 && rc < (int)sizeof(names->ccw_group))
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner names->type = NET_CCWGROUP;
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner return 0;
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner}
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner
0260944060426d54d9ecb40930baad985cbd02a1Kay Sieversstatic int names_mac(struct udev_device *dev, struct netnames *names) {
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers const char *s;
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers unsigned int i;
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers unsigned int a1, a2, a3, a4, a5, a6;
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers /* check for NET_ADDR_PERM, skip random MAC addresses */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers s = udev_device_get_sysattr_value(dev, "addr_assign_type");
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers if (!s)
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers return EXIT_FAILURE;
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers i = strtoul(s, NULL, 0);
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers if (i != 0)
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers return 0;
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers s = udev_device_get_sysattr_value(dev, "address");
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers if (!s)
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers return -ENOENT;
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers if (sscanf(s, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6)
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers return -EINVAL;
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers /* skip empty MAC addresses */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers if (a1 + a2 + a3 + a4 + a5 + a6 == 0)
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers return -EINVAL;
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers names->mac[0] = a1;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers names->mac[1] = a2;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers names->mac[2] = a3;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers names->mac[3] = a4;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers names->mac[4] = a5;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers names->mac[5] = a6;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers names->mac_valid = true;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers return 0;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers}
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers/* IEEE Organizationally Unique Identifier vendor string */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sieversstatic int ieee_oui(struct udev_device *dev, struct netnames *names, bool test) {
971e7fb62548f2c9c4e32684bb13409e6579dc6aKay Sievers char str[32];
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
971e7fb62548f2c9c4e32684bb13409e6579dc6aKay Sievers if (!names->mac_valid)
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers return -ENOENT;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers /* skip commonly misused 00:00:00 (Xerox) prefix */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (memcmp(names->mac, "\0\0\0", 3) == 0)
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers return -EINVAL;
d054f0a4d451120c26494263fc4dc175bfd405b1Daniel Mack xsprintf(str, "OUI:%02X%02X%02X%02X%02X%02X", names->mac[0],
d054f0a4d451120c26494263fc4dc175bfd405b1Daniel Mack names->mac[1], names->mac[2], names->mac[3], names->mac[4],
d054f0a4d451120c26494263fc4dc175bfd405b1Daniel Mack names->mac[5]);
a4bbef099209d4e3bccd913cd30da536f8971064Kay Sievers udev_builtin_hwdb_lookup(dev, NULL, str, NULL, test);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers return 0;
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers}
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers
a660c63c551b88136ac6176855b5907cc533e848Kay Sieversstatic int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool test) {
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers const char *s;
72bc96f07868d532596477604b6fb41633ebd124Kay Sievers const char *p;
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers unsigned int i;
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers const char *devtype;
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers const char *prefix = "en";
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek struct netnames names = {};
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers int err;
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner /* handle only ARPHRD_ETHER and ARPHRD_SLIP devices */
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers s = udev_device_get_sysattr_value(dev, "type");
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers if (!s)
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers return EXIT_FAILURE;
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers i = strtoul(s, NULL, 0);
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner switch (i) {
19aa72f74e41045510b4af3f1415b419d42ff20bTom Gundersen case ARPHRD_ETHER:
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner prefix = "en";
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner break;
19aa72f74e41045510b4af3f1415b419d42ff20bTom Gundersen case ARPHRD_SLIP:
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner prefix = "sl";
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner break;
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner default:
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers return 0;
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner }
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers
72bc96f07868d532596477604b6fb41633ebd124Kay Sievers /* skip stacked devices, like VLANs, ... */
72bc96f07868d532596477604b6fb41633ebd124Kay Sievers s = udev_device_get_sysattr_value(dev, "ifindex");
72bc96f07868d532596477604b6fb41633ebd124Kay Sievers if (!s)
72bc96f07868d532596477604b6fb41633ebd124Kay Sievers return EXIT_FAILURE;
72bc96f07868d532596477604b6fb41633ebd124Kay Sievers p = udev_device_get_sysattr_value(dev, "iflink");
72bc96f07868d532596477604b6fb41633ebd124Kay Sievers if (!p)
72bc96f07868d532596477604b6fb41633ebd124Kay Sievers return EXIT_FAILURE;
090be8653471e1abe3f1cdd32eaad0fbd65f85cdThomas Hindoe Paaboel Andersen if (!streq(s, p))
72bc96f07868d532596477604b6fb41633ebd124Kay Sievers return 0;
72bc96f07868d532596477604b6fb41633ebd124Kay Sievers
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers devtype = udev_device_get_devtype(dev);
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers if (devtype) {
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers if (streq("wlan", devtype))
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers prefix = "wl";
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers else if (streq("wwan", devtype))
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers prefix = "ww";
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers }
d23965a64eb5c2c97b839dc2e3e79fc1613994f1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers err = names_mac(dev, &names);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (err >= 0 && names.mac_valid) {
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers char str[IFNAMSIZ];
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
d054f0a4d451120c26494263fc4dc175bfd405b1Daniel Mack xsprintf(str, "%sx%02x%02x%02x%02x%02x%02x", prefix,
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers names.mac[0], names.mac[1], names.mac[2],
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers names.mac[3], names.mac[4], names.mac[5]);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers udev_builtin_add_property(dev, test, "ID_NET_NAME_MAC", str);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers ieee_oui(dev, &names, test);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers }
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner /* get path names for Linux on System z network devices */
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner err = names_ccw(dev, &names);
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner if (err >= 0 && names.type == NET_CCWGROUP) {
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner char str[IFNAMSIZ];
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner
d4b687c96adf207f0878aebf3ce3371f6160687fKay Sievers if (snprintf(str, sizeof(str), "%s%s", prefix, names.ccw_group) < (int)sizeof(str))
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner goto out;
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner }
e0d4a0ac06afb856c9370c5c256f0f7bb7efdc8eHendrik Brueckner
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers /* get PCI based path names, we compose only PCI based paths */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers err = names_pci(dev, &names);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (err < 0)
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers goto out;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers /* plain PCI device */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (names.type == NET_PCI) {
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers char str[IFNAMSIZ];
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (names.pci_onboard[0])
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard) < (int)sizeof(str))
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers udev_builtin_add_property(dev, test, "ID_NET_NAME_ONBOARD", str);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (names.pci_onboard_label)
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard_label) < (int)sizeof(str))
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers udev_builtin_add_property(dev, test, "ID_NET_LABEL_ONBOARD", str);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (names.pci_path[0])
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_path) < (int)sizeof(str))
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (names.pci_slot[0])
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_slot) < (int)sizeof(str))
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers goto out;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers }
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers /* USB device */
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers err = names_usb(dev, &names);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (err >= 0 && names.type == NET_USB) {
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers char str[IFNAMSIZ];
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (names.pci_path[0])
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.usb_ports) < (int)sizeof(str))
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (names.pci_slot[0])
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.usb_ports) < (int)sizeof(str))
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers goto out;
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers }
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers /* Broadcom bus */
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers err = names_bcma(dev, &names);
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers if (err >= 0 && names.type == NET_BCMA) {
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers char str[IFNAMSIZ];
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers if (names.pci_path[0])
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.bcma_core) < (int)sizeof(str))
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers if (names.pci_slot[0])
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.bcma_core) < (int)sizeof(str))
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
984c4348ff14d29c526d3d372daa82e278eeb5b4Kay Sievers goto out;
0260944060426d54d9ecb40930baad985cbd02a1Kay Sievers }
0260944060426d54d9ecb40930baad985cbd02a1Kay Sieversout:
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers return EXIT_SUCCESS;
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers}
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers
a660c63c551b88136ac6176855b5907cc533e848Kay Sieversconst struct udev_builtin udev_builtin_net_id = {
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers .name = "net_id",
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers .cmd = builtin_net_id,
5ac0162c3af95efa08a07b84ff62ad32842922c7Lennart Poettering .help = "Network device properties",
a660c63c551b88136ac6176855b5907cc533e848Kay Sievers};