384 строки
12 KiB
Diff
384 строки
12 KiB
Diff
From 6edc865bd02ab591b9121d4a5f6dc3cdbe5af809 Mon Sep 17 00:00:00 2001
|
|
From: Michal Sekletar <msekleta@redhat.com>
|
|
Date: Wed, 9 Apr 2014 09:18:24 +0200
|
|
Subject: [PATCH 19/27] sys-linux: rework get_first_ethernet()
|
|
|
|
We can't assume that host has ethernet NIC named "eth0". Rather than guessing we
|
|
better ask udev. We iterate over symlinks symlinks in /sys/class/net and
|
|
for each device we determine if it is ethernet device and additionally we query
|
|
udev database for sub-type of the device. If we find PCI or USB device which has
|
|
ethernet datalink type and appropriate sub-type we return its name. If we don't
|
|
succeed in determining more information about device we will return "good
|
|
enough" device which in turn is first device with ethernet datalink type.
|
|
|
|
Note that we now have two copies of get_first_ethernet() in the source code. This
|
|
is bad and should be fixed in the future.
|
|
|
|
This commit replaces ppp-2.4.5-eth.patch.
|
|
|
|
Resolves: #682381
|
|
---
|
|
pppd/Makefile.linux | 3 +
|
|
pppd/multilink.c | 4 +-
|
|
pppd/plugins/rp-pppoe/Makefile.linux | 4 +-
|
|
pppd/plugins/rp-pppoe/pppoe-discovery.c | 117 +++++++++++++++++++++++++++++++-
|
|
pppd/pppd.h | 2 +-
|
|
pppd/sys-linux.c | 115 +++++++++++++++++++++++++++++--
|
|
6 files changed, 232 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/pppd/Makefile.linux b/pppd/Makefile.linux
|
|
index 53df4d2..0e8107f 100644
|
|
--- a/pppd/Makefile.linux
|
|
+++ b/pppd/Makefile.linux
|
|
@@ -32,6 +32,9 @@ include .depend
|
|
endif
|
|
|
|
CC = gcc
|
|
+
|
|
+LIBS = -ludev
|
|
+
|
|
#
|
|
COPTS = -Wall $(RPM_OPT_FLAGS) -DLIBDIR=\""$(LIBDIR)"\"
|
|
|
|
diff --git a/pppd/multilink.c b/pppd/multilink.c
|
|
index 135cab0..2f0ed50 100644
|
|
--- a/pppd/multilink.c
|
|
+++ b/pppd/multilink.c
|
|
@@ -436,12 +436,12 @@ static int
|
|
get_default_epdisc(ep)
|
|
struct epdisc *ep;
|
|
{
|
|
- char *p;
|
|
+ char *p = NULL;
|
|
struct hostent *hp;
|
|
u_int32_t addr;
|
|
|
|
/* First try for an ethernet MAC address */
|
|
- p = get_first_ethernet();
|
|
+ get_first_ethernet(&p);
|
|
if (p != 0 && get_if_hwaddr(ep->value, p) >= 0) {
|
|
ep->class = EPD_MAC;
|
|
ep->length = 6;
|
|
diff --git a/pppd/plugins/rp-pppoe/Makefile.linux b/pppd/plugins/rp-pppoe/Makefile.linux
|
|
index 9918091..b949716 100644
|
|
--- a/pppd/plugins/rp-pppoe/Makefile.linux
|
|
+++ b/pppd/plugins/rp-pppoe/Makefile.linux
|
|
@@ -30,8 +30,8 @@ COPTS=$(RPM_OPT_FLAGS)
|
|
CFLAGS=$(COPTS) -I../../../include '-DRP_VERSION="$(RP_VERSION)"'
|
|
all: rp-pppoe.so pppoe-discovery
|
|
|
|
-pppoe-discovery: pppoe-discovery.o debug.o
|
|
- $(CC) -o pppoe-discovery pppoe-discovery.o debug.o
|
|
+pppoe-discovery: pppoe-discovery.o debug.o common.o
|
|
+ $(CC) -o pppoe-discovery pppoe-discovery.o debug.o -ludev
|
|
|
|
pppoe-discovery.o: pppoe-discovery.c
|
|
$(CC) $(CFLAGS) -c -o pppoe-discovery.o pppoe-discovery.c
|
|
diff --git a/pppd/plugins/rp-pppoe/pppoe-discovery.c b/pppd/plugins/rp-pppoe/pppoe-discovery.c
|
|
index c0d927d..2bd910f 100644
|
|
--- a/pppd/plugins/rp-pppoe/pppoe-discovery.c
|
|
+++ b/pppd/plugins/rp-pppoe/pppoe-discovery.c
|
|
@@ -47,8 +47,13 @@
|
|
#include <net/if_arp.h>
|
|
#endif
|
|
|
|
+#include <dirent.h>
|
|
+#include <sys/types.h>
|
|
+#include <libudev.h>
|
|
+
|
|
char *xstrdup(const char *s);
|
|
void usage(void);
|
|
+int get_first_ethernet(char **_r);
|
|
|
|
void die(int status)
|
|
{
|
|
@@ -681,8 +686,15 @@ int main(int argc, char *argv[])
|
|
}
|
|
|
|
/* default interface name */
|
|
- if (!conn->ifName)
|
|
- conn->ifName = strdup("eth0");
|
|
+ if (!conn->ifName) {
|
|
+ char *eth_dev;
|
|
+ if (get_first_ethernet(ð_dev) < 0) {
|
|
+ fprintf(stderr, "No ethernet device on the host.\n");
|
|
+ exit(1);
|
|
+ }
|
|
+ conn->ifName = eth_dev;
|
|
+ }
|
|
+
|
|
|
|
conn->discoverySocket = -1;
|
|
conn->sessionSocket = -1;
|
|
@@ -722,3 +734,104 @@ void usage(void)
|
|
fprintf(stderr, "Usage: pppoe-discovery [options]\n");
|
|
fprintf(stderr, "\nVersion " RP_VERSION "\n");
|
|
}
|
|
+
|
|
+/*
|
|
+ * get_first_ethernet - return the name of the first ethernet-style
|
|
+ * interface on this system.
|
|
+ */
|
|
+int
|
|
+get_first_ethernet(char **_r)
|
|
+{
|
|
+ int r = 0;
|
|
+ DIR *d = NULL;
|
|
+ struct dirent *entry = NULL;
|
|
+ struct udev *udev = NULL;
|
|
+ struct udev_device *dev = NULL;
|
|
+ char *eth_dev = NULL;
|
|
+
|
|
+ d = opendir("/sys/class/net");
|
|
+ if (!d) {
|
|
+ fprintf(stderr, "Failed to open dir /sys/class/net : %m\n");
|
|
+ r = -errno;
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ udev = udev_new();
|
|
+ if (!udev) {
|
|
+ fprintf(stderr, "Failed to talk to systemd-udevd\n");
|
|
+ r = -EIO;
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ while ((entry = readdir(d)) != NULL) {
|
|
+ char syspath[PATH_MAX] = {};
|
|
+ const char *type = NULL;
|
|
+
|
|
+ if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0))
|
|
+ continue;
|
|
+
|
|
+ sprintf(syspath, "/sys/class/net/%s", entry->d_name);
|
|
+
|
|
+ dev = udev_device_new_from_syspath(udev, syspath);
|
|
+ if (!dev)
|
|
+ continue;
|
|
+
|
|
+ type = udev_device_get_sysattr_value(dev, "type");
|
|
+ if (strcmp(type, "1") == 0) {
|
|
+ const char *pci_dev_subclass = NULL, *usb_dev_subclass = NULL;
|
|
+
|
|
+ pci_dev_subclass = udev_device_get_property_value(dev,
|
|
+ "ID_PCI_SUBCLASS_FROM_DATABASE");
|
|
+ usb_dev_subclass = udev_device_get_property_value(dev,
|
|
+ "ID_USB_SUBCLASS_FROM_DATABASE");
|
|
+
|
|
+ if ((pci_dev_subclass && strcmp(pci_dev_subclass, "Ethernet controller") == 0) ||
|
|
+ (usb_dev_subclass && (strcmp(usb_dev_subclass, "Ethernet Networking") == 0 ||
|
|
+ strcmp(usb_dev_subclass, "Ethernet Emulation") == 0))) {
|
|
+ char *d = NULL;
|
|
+
|
|
+ d = strdup(entry->d_name);
|
|
+ if (!d) {
|
|
+ r = -ENOMEM;
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ free(eth_dev);
|
|
+ eth_dev = d;
|
|
+ break;
|
|
+ } else if (!eth_dev) {
|
|
+ eth_dev = strdup(entry->d_name);
|
|
+ if (!eth_dev) {
|
|
+ r = -ENOMEM;
|
|
+ goto fail;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ udev_device_unref(dev);
|
|
+ dev = NULL;
|
|
+ }
|
|
+
|
|
+ if (dev)
|
|
+ udev_device_unref(dev);
|
|
+ udev_unref(udev);
|
|
+ closedir(d);
|
|
+
|
|
+ *_r = eth_dev;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+fail:
|
|
+ if (dev)
|
|
+ udev_device_unref(dev);
|
|
+
|
|
+ if (udev)
|
|
+ udev_unref(udev);
|
|
+
|
|
+ if (d)
|
|
+ closedir(d);
|
|
+
|
|
+ free(eth_dev);
|
|
+
|
|
+ return r;
|
|
+}
|
|
diff --git a/pppd/pppd.h b/pppd/pppd.h
|
|
index de271c1..aaddba1 100644
|
|
--- a/pppd/pppd.h
|
|
+++ b/pppd/pppd.h
|
|
@@ -691,7 +691,7 @@ int sipxfaddr __P((int, unsigned long, unsigned char *));
|
|
int cipxfaddr __P((int));
|
|
#endif
|
|
int get_if_hwaddr __P((u_char *addr, char *name));
|
|
-char *get_first_ethernet __P((void));
|
|
+int get_first_ethernet __P((char **_r));
|
|
|
|
/* Procedures exported from options.c */
|
|
int setipaddr __P((char *, char **, int)); /* Set local/remote ip addresses */
|
|
diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c
|
|
index 0690019..ec09c50 100644
|
|
--- a/pppd/sys-linux.c
|
|
+++ b/pppd/sys-linux.c
|
|
@@ -92,6 +92,9 @@
|
|
#include <ctype.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
+#include <dirent.h>
|
|
+
|
|
+#include <libudev.h>
|
|
|
|
/* This is in netdevice.h. However, this compile will fail miserably if
|
|
you attempt to include netdevice.h because it has so many references
|
|
@@ -1873,10 +1876,101 @@ get_if_hwaddr(u_char *addr, char *name)
|
|
* get_first_ethernet - return the name of the first ethernet-style
|
|
* interface on this system.
|
|
*/
|
|
-char *
|
|
-get_first_ethernet()
|
|
-{
|
|
- return "eth0";
|
|
+int
|
|
+get_first_ethernet(char **_r)
|
|
+{
|
|
+ int r = 0;
|
|
+ DIR *d = NULL;
|
|
+ struct dirent *entry = NULL;
|
|
+ struct udev *udev = NULL;
|
|
+ struct udev_device *dev = NULL;
|
|
+ char *eth_dev = NULL;
|
|
+
|
|
+ d = opendir("/sys/class/net");
|
|
+ if (!d) {
|
|
+ fprintf(stderr, "Failed to open dir /sys/class/net : %m\n");
|
|
+ r = -errno;
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ udev = udev_new();
|
|
+ if (!udev) {
|
|
+ fprintf(stderr, "Failed to talk to systemd-udevd\n");
|
|
+ r = -EIO;
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ while ((entry = readdir(d)) != NULL) {
|
|
+ char syspath[PATH_MAX] = {};
|
|
+ const char *type = NULL;
|
|
+
|
|
+ if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0))
|
|
+ continue;
|
|
+
|
|
+ sprintf(syspath, "/sys/class/net/%s", entry->d_name);
|
|
+
|
|
+ dev = udev_device_new_from_syspath(udev, syspath);
|
|
+ if (!dev)
|
|
+ continue;
|
|
+
|
|
+ type = udev_device_get_sysattr_value(dev, "type");
|
|
+ if (strcmp(type, "1") == 0) {
|
|
+ const char *pci_dev_subclass = NULL, *usb_dev_subclass = NULL;
|
|
+
|
|
+ pci_dev_subclass = udev_device_get_property_value(dev,
|
|
+ "ID_PCI_SUBCLASS_FROM_DATABASE");
|
|
+ usb_dev_subclass = udev_device_get_property_value(dev,
|
|
+ "ID_USB_SUBCLASS_FROM_DATABASE");
|
|
+
|
|
+ if ((pci_dev_subclass && strcmp(pci_dev_subclass, "Ethernet controller") == 0) ||
|
|
+ (usb_dev_subclass && (strcmp(usb_dev_subclass, "Ethernet Networking") == 0 ||
|
|
+ strcmp(usb_dev_subclass, "Ethernet Emulation") == 0))) {
|
|
+ char *d = NULL;
|
|
+
|
|
+ d = strdup(entry->d_name);
|
|
+ if (!d) {
|
|
+ r = -ENOMEM;
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ free(eth_dev);
|
|
+ eth_dev = d;
|
|
+ break;
|
|
+ } else if (!eth_dev) {
|
|
+ eth_dev = strdup(entry->d_name);
|
|
+ if (!eth_dev) {
|
|
+ r = -ENOMEM;
|
|
+ goto fail;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ udev_device_unref(dev);
|
|
+ dev = NULL;
|
|
+ }
|
|
+
|
|
+ if (dev)
|
|
+ udev_device_unref(dev);
|
|
+ udev_unref(udev);
|
|
+ closedir(d);
|
|
+
|
|
+ *_r = eth_dev;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+fail:
|
|
+ if (dev)
|
|
+ udev_device_unref(dev);
|
|
+
|
|
+ if (udev)
|
|
+ udev_unref(udev);
|
|
+
|
|
+ if (d)
|
|
+ closedir(d);
|
|
+
|
|
+ free(eth_dev);
|
|
+
|
|
+ return r;
|
|
}
|
|
|
|
/********************************************************************
|
|
@@ -2859,6 +2953,7 @@ ether_to_eui64(eui64_t *p_eui64)
|
|
struct ifreq ifr;
|
|
int skfd;
|
|
const unsigned char *ptr;
|
|
+ char *eth_dev = NULL;
|
|
|
|
skfd = socket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
|
if(skfd == -1)
|
|
@@ -2867,11 +2962,19 @@ ether_to_eui64(eui64_t *p_eui64)
|
|
return 0;
|
|
}
|
|
|
|
- strcpy(ifr.ifr_name, "eth0");
|
|
+ if (get_first_ethernet(ð_dev) < 0)
|
|
+ {
|
|
+ warn("no ethernet device present on the host");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ strcpy(ifr.ifr_name, eth_dev);
|
|
+ free(eth_dev);
|
|
+
|
|
if(ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
|
|
{
|
|
close(skfd);
|
|
- warn("could not obtain hardware address for eth0");
|
|
+ warn("could not obtain hardware address for %s", ifr.ifr_name);
|
|
return 0;
|
|
}
|
|
close(skfd);
|
|
--
|
|
1.8.3.1
|
|
|