From 3d52695c2fa60c2e8cb6b7bc4af5aeb504981974 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 27 Dec 2008 08:41:14 +0100 Subject: [PATCH] Add generic device detection support --- src/Makefile.am | 5 +- src/connman.h | 3 + src/detect.c | 256 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/element.c | 4 + 4 files changed, 266 insertions(+), 2 deletions(-) create mode 100644 src/detect.c diff --git a/src/Makefile.am b/src/Makefile.am index 018fb15..42a8a48 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,8 +6,9 @@ dbus_DATA = connman.conf sbin_PROGRAMS = connmand connmand_SOURCES = main.c connman.h log.c selftest.c error.c plugin.c \ - profile.c element.c device.c network.c security.c \ - resolver.c storage.c manager.c agent.c rtnl.c dbus.c + profile.c element.c device.c network.c \ + security.c resolver.c storage.c manager.c \ + agent.c detect.c rtnl.c dbus.c if UDEV connmand_SOURCES += udev.c diff --git a/src/connman.h b/src/connman.h index 918cc7c..55f78c0 100644 --- a/src/connman.h +++ b/src/connman.h @@ -111,6 +111,9 @@ static inline void __connman_element_unlock(struct connman_element *element) { } +int __connman_detect_init(void); +void __connman_detect_cleanup(void); + #include int __connman_device_init(void); diff --git a/src/detect.c b/src/detect.c new file mode 100644 index 0000000..85fb077 --- /dev/null +++ b/src/detect.c @@ -0,0 +1,256 @@ +/* + * + * Connection Manager + * + * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "connman.h" + +static GSList *device_list = NULL; + +static struct connman_device *find_device(int index) +{ + GSList *list; + + for (list = device_list; list; list = list->next) { + struct connman_device *device = list->data; + + if (connman_device_get_index(device) == index) + return device; + } + + return NULL; +} + +static char *index2name(int index) +{ + struct ifreq ifr; + int sk, err; + + if (index < 0) + return NULL; + + sk = socket(PF_INET, SOCK_DGRAM, 0); + if (sk < 0) + return NULL; + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_ifindex = index; + + err = ioctl(sk, SIOCGIFNAME, &ifr); + + close(sk); + + if (err < 0) + return NULL; + + return strdup(ifr.ifr_name); +} + +static char *index2ident(int index, const char *prefix) +{ + struct ifreq ifr; + struct ether_addr *eth; + char *str; + int sk, err, len; + + if (index < 0) + return NULL; + + sk = socket(PF_INET, SOCK_DGRAM, 0); + if (sk < 0) + return NULL; + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_ifindex = index; + + err = ioctl(sk, SIOCGIFNAME, &ifr); + + if (err == 0) + err = ioctl(sk, SIOCGIFHWADDR, &ifr); + + close(sk); + + if (err < 0) + return NULL; + + len = prefix ? strlen(prefix) + 18 : 18; + + str = malloc(len); + if (!str) + return NULL; + + eth = (void *) &ifr.ifr_hwaddr.sa_data; + snprintf(str, len, "%s%02X_%02X_%02X_%02X_%02X_%02X", + prefix ? prefix : "", + eth->ether_addr_octet[0], + eth->ether_addr_octet[1], + eth->ether_addr_octet[2], + eth->ether_addr_octet[3], + eth->ether_addr_octet[4], + eth->ether_addr_octet[5]); + + return str; +} + +static void detect_newlink(unsigned short type, int index, + unsigned flags, unsigned change) +{ + enum connman_device_type devtype = CONNMAN_DEVICE_TYPE_UNKNOWN; + struct connman_device *device; + gchar *name, *devname; + + DBG("index %d", index); + + device = find_device(index); + if (device != NULL) + return; + + devname = index2name(index); + + if (type == ARPHRD_ETHER) { + char bridge_path[PATH_MAX], wimax_path[PATH_MAX]; + struct stat st; + struct iwreq iwr; + int sk; + + snprintf(bridge_path, PATH_MAX, + "/sys/class/net/%s/bridge", devname); + snprintf(wimax_path, PATH_MAX, + "/sys/class/net/%s/wimax", devname); + + memset(&iwr, 0, sizeof(iwr)); + strncpy(iwr.ifr_ifrn.ifrn_name, devname, IFNAMSIZ); + + sk = socket(PF_INET, SOCK_DGRAM, 0); + + if (g_str_has_prefix(devname, "bnep") == TRUE) + devtype = CONNMAN_DEVICE_TYPE_UNKNOWN; + else if (stat(bridge_path, &st) == 0 && (st.st_mode & S_IFDIR)) + devtype = CONNMAN_DEVICE_TYPE_UNKNOWN; + else if (stat(wimax_path, &st) == 0 && (st.st_mode & S_IFDIR)) + devtype = CONNMAN_DEVICE_TYPE_WIMAX; + else if (ioctl(sk, SIOCGIWNAME, &iwr) == 0) + devtype = CONNMAN_DEVICE_TYPE_UNKNOWN; + else + devtype = CONNMAN_DEVICE_TYPE_ETHERNET; + + close(sk); + } + + if (devtype == CONNMAN_DEVICE_TYPE_UNKNOWN) { + g_free(devname); + return; + } + + name = index2ident(index, "dev_"); + + device = connman_device_create(name, devtype); + if (device == NULL) { + g_free(devname); + g_free(name); + return; + } + + connman_device_set_index(device, index); + connman_device_set_interface(device, devname); + + g_free(devname); + g_free(name); + + if (connman_device_register(device) < 0) { + connman_device_unref(device); + return; + } + + device_list = g_slist_append(device_list, device); +} + +static void detect_dellink(unsigned short type, int index, + unsigned flags, unsigned change) +{ + struct connman_device *device; + + DBG("index %d", index); + + device = find_device(index); + if (device == NULL) + return; + + device_list = g_slist_remove(device_list, device); + + connman_device_unregister(device); + connman_device_unref(device); +} + +static struct connman_rtnl detect_rtnl = { + .name = "detect", + .priority = CONNMAN_RTNL_PRIORITY_LOW, + .newlink = detect_newlink, + .dellink = detect_dellink, +}; + +int __connman_detect_init(void) +{ + int err; + + err = connman_rtnl_register(&detect_rtnl); + if (err < 0) + return err; + + connman_rtnl_send_getlink(); + + return 0; +} + +void __connman_detect_cleanup(void) +{ + GSList *list; + + connman_rtnl_unregister(&detect_rtnl); + + for (list = device_list; list; list = list->next) { + struct connman_device *device = list->data; + + connman_device_unregister(device); + connman_device_unref(device); + } + + g_slist_free(device_list); + device_list = NULL; +} diff --git a/src/element.c b/src/element.c index fbed4f6..9045c9b 100644 --- a/src/element.c +++ b/src/element.c @@ -1961,11 +1961,15 @@ void __connman_element_start(void) probe_node, NULL); started = TRUE; + + __connman_detect_init(); } void __connman_element_stop(void) { DBG(""); + + __connman_detect_cleanup(); } static gboolean free_driver(GNode *node, gpointer data) -- 1.7.9.5