r4886 - in developers/werner: . wlan wlan/connman

werner at docs.openmoko.org werner at docs.openmoko.org
Wed Jan 14 01:57:39 CET 2009


Author: werner
Date: 2009-01-14 01:57:38 +0100 (Wed, 14 Jan 2009)
New Revision: 4886

Added:
   developers/werner/wlan/
   developers/werner/wlan/connman/
   developers/werner/wlan/connman/Makefile
   developers/werner/wlan/connman/detect.c
   developers/werner/wlan/connman/rtnl.c
Log:
connman compatibility test.



Added: developers/werner/wlan/connman/Makefile
===================================================================
--- developers/werner/wlan/connman/Makefile	                        (rev 0)
+++ developers/werner/wlan/connman/Makefile	2009-01-14 00:57:38 UTC (rev 4886)
@@ -0,0 +1,15 @@
+CC=arm-angstrom-linux-gnueabi-gcc
+CFLAGS=-Wall -g \
+       -I.. -I../../include \
+       -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include \
+       -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include
+
+OBJS=detect.o rtnl.o
+
+.PHONY:	all
+
+
+all:	try
+
+try:	$(OBJS)
+	$(CC) -o $@ $(OBJS) -lglib-2.0

Added: developers/werner/wlan/connman/detect.c
===================================================================
--- developers/werner/wlan/connman/detect.c	                        (rev 0)
+++ developers/werner/wlan/connman/detect.c	2009-01-14 00:57:38 UTC (rev 4886)
@@ -0,0 +1,324 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 2007-2009  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 <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/ethernet.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+
+#include <glib.h>
+
+#include "connman.h"
+
+#define	connman_debug(FMT, ARGS...)	fprintf(stderr, FMT "\n", ARGS)
+#define	connman_device_get_index(...)	0
+#define	connman_device_create(name, devtype) \
+	(fprintf(stderr, "connman_device_create(%s, %d)\n", name, devtype), \
+	(void *) 1)
+#define	connman_device_set_policy(...)
+#define	connman_device_set_mode(...)
+#define	connman_device_set_index(...)
+#define	connman_device_set_interface(device, devname) \
+	fprintf(stderr, "connman_device_set_interface(%s)\n", devname)
+#define	connman_device_register(...)	0
+#define	connman_device_unref(...)
+#define	connman_device_unregister(...)
+
+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;
+	enum connman_device_mode mode = CONNMAN_DEVICE_MODE_UNKNOWN;
+	struct connman_device *device;
+	gchar *name, *devname;
+
+	DBG("type %d index %d", type, index);
+
+	device = find_device(index);
+	if (device != NULL)
+		return;
+
+	devname = index2name(index);
+	if (devname == NULL)
+		return;
+
+	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_WIFI;
+		else
+			devtype = CONNMAN_DEVICE_TYPE_ETHERNET;
+
+		close(sk);
+	} else if (type == ARPHRD_NONE) {
+		if (g_str_has_prefix(devname, "hso") == TRUE)
+			devtype = CONNMAN_DEVICE_TYPE_HSO;
+	}
+
+	switch (devtype) {
+	case CONNMAN_DEVICE_TYPE_UNKNOWN:
+		g_free(devname);
+		return;
+	case CONNMAN_DEVICE_TYPE_ETHERNET:
+	case CONNMAN_DEVICE_TYPE_WIFI:
+	case CONNMAN_DEVICE_TYPE_WIMAX:
+		name = index2ident(index, "dev_");
+		break;
+	case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+	case CONNMAN_DEVICE_TYPE_HSO:
+	case CONNMAN_DEVICE_TYPE_NOZOMI:
+	case CONNMAN_DEVICE_TYPE_HUAWEI:
+	case CONNMAN_DEVICE_TYPE_NOVATEL:
+	case CONNMAN_DEVICE_TYPE_VENDOR:
+		name = strdup(devname);
+		break;
+	}
+
+	device = connman_device_create(name, devtype);
+	if (device == NULL) {
+		g_free(devname);
+		g_free(name);
+		return;
+	}
+
+	switch (devtype) {
+	case CONNMAN_DEVICE_TYPE_UNKNOWN:
+	case CONNMAN_DEVICE_TYPE_VENDOR:
+	case CONNMAN_DEVICE_TYPE_NOZOMI:
+	case CONNMAN_DEVICE_TYPE_HUAWEI:
+	case CONNMAN_DEVICE_TYPE_NOVATEL:
+		mode = CONNMAN_DEVICE_MODE_UNKNOWN;
+		break;
+	case CONNMAN_DEVICE_TYPE_ETHERNET:
+		mode = CONNMAN_DEVICE_MODE_TRANSPORT_IP;
+		break;
+	case CONNMAN_DEVICE_TYPE_WIFI:
+	case CONNMAN_DEVICE_TYPE_WIMAX:
+		mode = CONNMAN_DEVICE_MODE_NETWORK_SINGLE;
+		break;
+	case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+		mode = CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE;
+		break;
+	case CONNMAN_DEVICE_TYPE_HSO:
+		mode = CONNMAN_DEVICE_MODE_NETWORK_SINGLE;
+		connman_device_set_policy(device, CONNMAN_DEVICE_POLICY_MANUAL);
+		break;
+	}
+
+	connman_device_set_mode(device, mode);
+
+	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("type %d index %d", type, 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;
+}
+
+
+int main(void)
+{
+	GMainLoop *loop;
+
+	loop = g_main_loop_new(NULL, TRUE);
+	__connman_rtnl_init();
+	__connman_detect_init();
+	g_main_loop_run(loop);
+	return 0;
+}

Added: developers/werner/wlan/connman/rtnl.c
===================================================================
--- developers/werner/wlan/connman/rtnl.c	                        (rev 0)
+++ developers/werner/wlan/connman/rtnl.c	2009-01-14 00:57:38 UTC (rev 4886)
@@ -0,0 +1,802 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 2007-2009  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 <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <linux/if.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <glib.h>
+
+#include "connman.h"
+
+#define connman_debug(FMT, ARGS...)	fprintf(stderr, FMT "\n", ARGS)
+
+struct watch_data {
+	unsigned int id;
+	int index;
+	connman_rtnl_link_cb_t newlink;
+	void *user_data;
+};
+
+static GSList *watch_list = NULL;
+static unsigned int watch_id = 0;
+
+/**
+ * connman_rtnl_add_newlink_watch:
+ * @index: network device index
+ * @callback: callback function
+ * @user_data: callback data;
+ *
+ * Add a new RTNL watch for newlink events
+ *
+ * Returns: %0 on failure and a unique id on success
+ */
+unsigned int connman_rtnl_add_newlink_watch(int index,
+			connman_rtnl_link_cb_t callback, void *user_data)
+{
+	struct watch_data *watch;
+
+	watch = g_try_new0(struct watch_data, 1);
+	if (watch == NULL)
+		return 0;
+
+	watch->id = ++watch_id;
+	watch->index = index;
+
+	watch->newlink = callback;
+	watch->user_data = user_data;
+
+	watch_list = g_slist_prepend(watch_list, watch);
+
+	DBG("id %d", watch->id);
+
+	return watch->id;
+}
+
+/**
+ * connman_rtnl_remove_watch:
+ * @id: watch identifier
+ *
+ * Remove the RTNL watch for the identifier
+ */
+void connman_rtnl_remove_watch(unsigned int id)
+{
+	GSList *list;
+
+	DBG("id %d", id);
+
+	if (id == 0)
+		return;
+
+	for (list = watch_list; list; list = list->next) {
+		struct watch_data *watch = list->data;
+
+		if (watch->id  == id) {
+			watch_list = g_slist_remove(watch_list, watch);
+			g_free(watch);
+			break;
+		}
+	}
+}
+
+static GSList *rtnl_list = NULL;
+
+static gint compare_priority(gconstpointer a, gconstpointer b)
+{
+	const struct connman_rtnl *rtnl1 = a;
+	const struct connman_rtnl *rtnl2 = b;
+
+	return rtnl2->priority - rtnl1->priority;
+}
+
+/**
+ * connman_rtnl_register:
+ * @rtnl: RTNL module
+ *
+ * Register a new RTNL module
+ *
+ * Returns: %0 on success
+ */
+int connman_rtnl_register(struct connman_rtnl *rtnl)
+{
+	DBG("rtnl %p name %s", rtnl, rtnl->name);
+
+	rtnl_list = g_slist_insert_sorted(rtnl_list, rtnl,
+							compare_priority);
+
+	return 0;
+}
+
+/**
+ * connman_rtnl_unregister:
+ * @rtnl: RTNL module
+ *
+ * Remove a previously registered RTNL module
+ */
+void connman_rtnl_unregister(struct connman_rtnl *rtnl)
+{
+	DBG("rtnl %p name %s", rtnl, rtnl->name);
+
+	rtnl_list = g_slist_remove(rtnl_list, rtnl);
+}
+
+static void process_newlink(unsigned short type, int index,
+					unsigned flags, unsigned change)
+{
+	GSList *list;
+
+	for (list = rtnl_list; list; list = list->next) {
+		struct connman_rtnl *rtnl = list->data;
+
+		if (rtnl->newlink)
+			rtnl->newlink(type, index, flags, change);
+	}
+
+	for (list = watch_list; list; list = list->next) {
+		struct watch_data *watch = list->data;
+
+		if (watch->index != index)
+			continue;
+
+		if (watch->newlink)
+			watch->newlink(flags, change, watch->user_data);
+	}
+}
+
+static void process_dellink(unsigned short type, int index,
+					unsigned flags, unsigned change)
+{
+	GSList *list;
+
+	for (list = rtnl_list; list; list = list->next) {
+		struct connman_rtnl *rtnl = list->data;
+
+		if (rtnl->dellink)
+			rtnl->dellink(type, index, flags, change);
+	}
+}
+
+static char *extract_gateway(struct rtmsg *msg, int bytes, int *index)
+{
+	char *gateway = NULL;
+	struct in_addr addr;
+	struct rtattr *attr;
+
+	for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
+					attr = RTA_NEXT(attr, bytes)) {
+		switch (attr->rta_type) {
+		case RTA_GATEWAY:
+			addr = *((struct in_addr *) RTA_DATA(attr));
+			g_free(gateway);
+			gateway = g_strdup(inet_ntoa(addr));
+			break;
+		case RTA_OIF:
+			*index = *((int *) RTA_DATA(attr));
+			break;
+		}
+	}
+
+	return gateway;
+}
+
+static void process_newgateway(struct rtmsg *msg, int bytes)
+{
+	int index = -1;
+	char *gateway;
+	GSList *list;
+
+	gateway = extract_gateway(msg, bytes, &index);
+	if (gateway == NULL || index < 0)
+		return;
+
+	for (list = rtnl_list; list; list = list->next) {
+		struct connman_rtnl *rtnl = list->data;
+
+		if (rtnl->newgateway)
+			rtnl->newgateway(index, gateway);
+	}
+
+	g_free(gateway);
+}
+
+static void process_delgateway(struct rtmsg *msg, int bytes)
+{
+	int index = -1;
+	char *gateway;
+	GSList *list;
+
+	gateway = extract_gateway(msg, bytes, &index);
+	if (gateway == NULL || index < 0)
+		return;
+
+	for (list = rtnl_list; list; list = list->next) {
+		struct connman_rtnl *rtnl = list->data;
+
+		if (rtnl->delgateway)
+			rtnl->delgateway(index, gateway);
+	}
+
+	g_free(gateway);
+}
+
+static inline void print_inet(struct rtattr *attr, const char *name, int family)
+{
+	if (family == AF_INET) {
+		struct in_addr addr;
+		addr = *((struct in_addr *) RTA_DATA(attr));
+		DBG("  attr %s (len %jd) %s\n",
+				name, RTA_PAYLOAD(attr), inet_ntoa(addr));
+	} else
+		DBG("  attr %s (len %jd)\n", name, RTA_PAYLOAD(attr));
+}
+
+static inline void print_char(struct rtattr *attr, const char *name)
+{
+	DBG("  attr %s (len %jd) %s\n", name, RTA_PAYLOAD(attr),
+						(char *) RTA_DATA(attr));
+}
+
+static inline void print_byte(struct rtattr *attr, const char *name)
+{
+	DBG("  attr %s (len %jd) 0x%02x\n", name, RTA_PAYLOAD(attr),
+					*((unsigned char *) RTA_DATA(attr)));
+}
+
+static inline void print_attr(struct rtattr *attr, const char *name)
+{
+	if (name)
+		DBG("  attr %s (len %jd)\n", name, RTA_PAYLOAD(attr));
+	else
+		DBG("  attr %d (len %jd)\n",
+					attr->rta_type, RTA_PAYLOAD(attr));
+}
+
+static void rtnl_link(struct nlmsghdr *hdr)
+{
+#if 0
+	struct ifinfomsg *msg;
+	struct rtattr *attr;
+	int bytes;
+
+	msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
+	bytes = IFLA_PAYLOAD(hdr);
+
+	DBG("ifi_index %d ifi_flags 0x%04x", msg->ifi_index, msg->ifi_flags);
+
+	for (attr = IFLA_RTA(msg); RTA_OK(attr, bytes);
+					attr = RTA_NEXT(attr, bytes)) {
+		switch (attr->rta_type) {
+		case IFLA_ADDRESS:
+			print_attr(attr, "address");
+			break;
+		case IFLA_BROADCAST:
+			print_attr(attr, "broadcast");
+			break;
+		case IFLA_IFNAME:
+			print_char(attr, "ifname");
+			break;
+		case IFLA_MTU:
+			print_attr(attr, "mtu");
+			break;
+		case IFLA_LINK:
+			print_attr(attr, "link");
+			break;
+		case IFLA_QDISC:
+			print_attr(attr, "qdisc");
+			break;
+		case IFLA_STATS:
+			print_attr(attr, "stats");
+			break;
+		case IFLA_COST:
+			print_attr(attr, "cost");
+			break;
+		case IFLA_PRIORITY:
+			print_attr(attr, "priority");
+			break;
+		case IFLA_MASTER:
+			print_attr(attr, "master");
+			break;
+		case IFLA_WIRELESS:
+			print_attr(attr, "wireless");
+			break;
+		case IFLA_PROTINFO:
+			print_attr(attr, "protinfo");
+			break;
+		case IFLA_TXQLEN:
+			print_attr(attr, "txqlen");
+			break;
+		case IFLA_MAP:
+			print_attr(attr, "map");
+			break;
+		case IFLA_WEIGHT:
+			print_attr(attr, "weight");
+			break;
+		case IFLA_OPERSTATE:
+			print_byte(attr, "operstate");
+			break;
+		case IFLA_LINKMODE:
+			print_byte(attr, "linkmode");
+			break;
+		default:
+			print_attr(attr, NULL);
+			break;
+		}
+	}
+#endif
+}
+
+static void rtnl_newlink(struct nlmsghdr *hdr)
+{
+	struct ifinfomsg *msg;
+
+	msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
+
+	DBG("ifi_type %d ifi_index %d ifi_flags 0x%04x ifi_change 0x%04x",
+					msg->ifi_type, msg->ifi_index,
+					msg->ifi_flags, msg->ifi_change);
+
+	process_newlink(msg->ifi_type, msg->ifi_index,
+					msg->ifi_flags, msg->ifi_change);
+
+	rtnl_link(hdr);
+}
+
+static void rtnl_dellink(struct nlmsghdr *hdr)
+{
+	struct ifinfomsg *msg;
+
+	msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
+
+	DBG("ifi_type %d ifi_index %d ifi_flags 0x%04x ifi_change 0x%04x",
+					msg->ifi_type, msg->ifi_index,
+					msg->ifi_flags, msg->ifi_change);
+
+	process_dellink(msg->ifi_type, msg->ifi_index,
+					msg->ifi_flags, msg->ifi_change);
+
+	rtnl_link(hdr);
+}
+
+static void rtnl_addr(struct nlmsghdr *hdr)
+{
+	struct ifaddrmsg *msg;
+	struct rtattr *attr;
+	int bytes;
+
+	msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
+	bytes = IFA_PAYLOAD(hdr);
+
+	DBG("ifa_family %d ifa_index %d", msg->ifa_family, msg->ifa_index);
+
+	for (attr = IFA_RTA(msg); RTA_OK(attr, bytes);
+					attr = RTA_NEXT(attr, bytes)) {
+		switch (attr->rta_type) {
+		case IFA_ADDRESS:
+			print_inet(attr, "address", msg->ifa_family);
+			break;
+		case IFA_LOCAL:
+			print_inet(attr, "local", msg->ifa_family);
+			break;
+		case IFA_LABEL:
+			print_char(attr, "label");
+			break;
+		case IFA_BROADCAST:
+			print_inet(attr, "broadcast", msg->ifa_family);
+			break;
+		case IFA_ANYCAST:
+			print_attr(attr, "anycast");
+			break;
+		case IFA_CACHEINFO:
+			print_attr(attr, "cacheinfo");
+			break;
+		case IFA_MULTICAST:
+			print_attr(attr, "multicast");
+			break;
+		default:
+			print_attr(attr, NULL);
+			break;
+		}
+	}
+}
+
+static void rtnl_route(struct nlmsghdr *hdr)
+{
+#if 0
+	struct rtmsg *msg;
+	struct rtattr *attr;
+	int bytes;
+
+	msg = (struct rtmsg *) NLMSG_DATA(hdr);
+	bytes = RTM_PAYLOAD(hdr);
+
+	DBG("rtm_family %d rtm_flags 0x%04x", msg->rtm_family, msg->rtm_flags);
+
+	for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
+					attr = RTA_NEXT(attr, bytes)) {
+		switch (attr->rta_type) {
+		case RTA_DST:
+			print_inet(attr, "dst", msg->rtm_family);
+			break;
+		case RTA_SRC:
+			print_inet(attr, "src", msg->rtm_family);
+			break;
+		case RTA_IIF:
+			print_char(attr, "iif");
+			break;
+		case RTA_OIF:
+			print_attr(attr, "oif");
+			break;
+		case RTA_GATEWAY:
+			print_inet(attr, "gateway", msg->rtm_family);
+			break;
+		case RTA_PRIORITY:
+			print_attr(attr, "priority");
+			break;
+		case RTA_PREFSRC:
+			print_inet(attr, "prefsrc", msg->rtm_family);
+			break;
+		case RTA_METRICS:
+			print_attr(attr, "metrics");
+			break;
+		case RTA_TABLE:
+			print_attr(attr, "table");
+			break;
+		default:
+			print_attr(attr, NULL);
+			break;
+		}
+	}
+#endif
+}
+
+static void rtnl_newroute(struct nlmsghdr *hdr)
+{
+	struct rtmsg *msg;
+
+	msg = (struct rtmsg *) NLMSG_DATA(hdr);
+
+	if (msg->rtm_type == RTN_UNICAST && msg->rtm_table == RT_TABLE_MAIN &&
+					msg->rtm_scope == RT_SCOPE_UNIVERSE) {
+		DBG("rtm_table %d rtm_scope %d rtm_type %d rtm_flags 0x%04x",
+					msg->rtm_table, msg->rtm_scope,
+					msg->rtm_type, msg->rtm_flags);
+		process_newgateway(msg, RTM_PAYLOAD(hdr));
+	}
+
+	rtnl_route(hdr);
+}
+
+static void rtnl_delroute(struct nlmsghdr *hdr)
+{
+	struct rtmsg *msg;
+
+	msg = (struct rtmsg *) NLMSG_DATA(hdr);
+
+	if (msg->rtm_type == RTN_UNICAST && msg->rtm_table == RT_TABLE_MAIN &&
+					msg->rtm_scope == RT_SCOPE_UNIVERSE) {
+		DBG("rtm_table %d rtm_scope %d rtm_type %d rtm_flags 0x%04x",
+					msg->rtm_table, msg->rtm_scope,
+					msg->rtm_type, msg->rtm_flags);
+		process_delgateway(msg, RTM_PAYLOAD(hdr));
+	}
+
+	rtnl_route(hdr);
+}
+
+static const char *type2string(uint16_t type)
+{
+	switch (type) {
+	case NLMSG_NOOP:
+		return "NOOP";
+	case NLMSG_ERROR:
+		return "ERROR";
+	case NLMSG_DONE:
+		return "DONE";
+	case NLMSG_OVERRUN:
+		return "OVERRUN";
+	case RTM_GETLINK:
+		return "GETLINK";
+	case RTM_NEWLINK:
+		return "NEWLINK";
+	case RTM_DELLINK:
+		return "DELLINK";
+	case RTM_NEWADDR:
+		return "NEWADDR";
+	case RTM_DELADDR:
+		return "DELADDR";
+	case RTM_GETROUTE:
+		return "GETROUTE";
+	case RTM_NEWROUTE:
+		return "NEWROUTE";
+	case RTM_DELROUTE:
+		return "DELROUTE";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static GIOChannel *channel = NULL;
+
+struct rtnl_request {
+	struct nlmsghdr hdr;
+	struct rtgenmsg msg;
+};
+#define RTNL_REQUEST_SIZE  (sizeof(struct nlmsghdr) + sizeof(struct rtgenmsg))
+
+static GSList *request_list = NULL;
+static guint32 request_seq = 0;
+
+static struct rtnl_request *find_request(guint32 seq)
+{
+	GSList *list;
+
+	for (list = request_list; list; list = list->next) {
+		struct rtnl_request *req = list->data;
+
+		if (req->hdr.nlmsg_seq == seq)
+			return req;
+	}
+
+	return NULL;
+}
+
+static int send_request(struct rtnl_request *req)
+{
+	struct sockaddr_nl addr;
+	int sk;
+
+	DBG("%s len %d type %d flags 0x%04x seq %d",
+				type2string(req->hdr.nlmsg_type),
+				req->hdr.nlmsg_len, req->hdr.nlmsg_type,
+				req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
+
+	sk = g_io_channel_unix_get_fd(channel);
+
+	memset(&addr, 0, sizeof(addr));
+	addr.nl_family = AF_NETLINK;
+
+	return sendto(sk, req, req->hdr.nlmsg_len, 0,
+				(struct sockaddr *) &addr, sizeof(addr));
+}
+
+static int queue_request(struct rtnl_request *req)
+{
+	request_list = g_slist_append(request_list, req);
+
+	if (g_slist_length(request_list) > 1)
+		return 0;
+
+	return send_request(req);
+}
+
+static int process_response(guint32 seq)
+{
+	struct rtnl_request *req;
+
+	DBG("seq %d", seq);
+
+	req = find_request(seq);
+	if (req != NULL) {
+		request_list = g_slist_remove(request_list, req);
+		g_free(req);
+	}
+
+	req = g_slist_nth_data(request_list, 0);
+	if (req == NULL)
+		return 0;
+
+	return send_request(req);
+}
+
+static void rtnl_message(void *buf, size_t len)
+{
+	DBG("buf %p len %zd", buf, len);
+
+	while (len > 0) {
+		struct nlmsghdr *hdr = buf;
+		struct nlmsgerr *err;
+
+		if (!NLMSG_OK(hdr, len))
+			break;
+
+		DBG("%s len %d type %d flags 0x%04x seq %d",
+					type2string(hdr->nlmsg_type),
+					hdr->nlmsg_len, hdr->nlmsg_type,
+					hdr->nlmsg_flags, hdr->nlmsg_seq);
+
+		switch (hdr->nlmsg_type) {
+		case NLMSG_NOOP:
+		case NLMSG_OVERRUN:
+			return;
+		case NLMSG_DONE:
+			process_response(hdr->nlmsg_seq);
+			return;
+		case NLMSG_ERROR:
+			err = NLMSG_DATA(hdr);
+			DBG("error %d (%s)", -err->error,
+						strerror(-err->error));
+			return;
+		case RTM_NEWLINK:
+			rtnl_newlink(hdr);
+			break;
+		case RTM_DELLINK:
+			rtnl_dellink(hdr);
+			break;
+		case RTM_NEWADDR:
+		case RTM_DELADDR:
+			rtnl_addr(hdr);
+			break;
+		case RTM_NEWROUTE:
+			rtnl_newroute(hdr);
+			break;
+		case RTM_DELROUTE:
+			rtnl_delroute(hdr);
+			break;
+		}
+
+		len -= hdr->nlmsg_len;
+		buf += hdr->nlmsg_len;
+	}
+}
+
+static gboolean netlink_event(GIOChannel *chan,
+				GIOCondition cond, gpointer data)
+{
+	unsigned char buf[4096];
+	gsize len;
+	GIOError err;
+
+	if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
+		return FALSE;
+
+	memset(buf, 0, sizeof(buf));
+
+	err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
+	if (err) {
+		if (err == G_IO_ERROR_AGAIN)
+			return TRUE;
+		return FALSE;
+	}
+
+	rtnl_message(buf, len);
+
+	return TRUE;
+}
+
+int connman_rtnl_send_getlink(void)
+{
+	struct rtnl_request *req;
+
+	DBG("");
+
+	req = g_try_malloc0(RTNL_REQUEST_SIZE);
+	if (req == NULL)
+		return -ENOMEM;
+
+	req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
+	req->hdr.nlmsg_type = RTM_GETLINK;
+	req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+	req->hdr.nlmsg_pid = 0;
+	req->hdr.nlmsg_seq = request_seq++;
+	req->msg.rtgen_family = AF_INET;
+
+	return queue_request(req);
+}
+
+int connman_rtnl_send_getroute(void)
+{
+	struct rtnl_request *req;
+
+	DBG("");
+
+	req = g_try_malloc0(RTNL_REQUEST_SIZE);
+	if (req == NULL)
+		return -ENOMEM;
+
+	req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
+	req->hdr.nlmsg_type = RTM_GETROUTE;
+	req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+	req->hdr.nlmsg_pid = 0;
+	req->hdr.nlmsg_seq = request_seq++;
+	req->msg.rtgen_family = AF_INET;
+
+	return queue_request(req);
+}
+
+int __connman_rtnl_init(void)
+{
+	struct sockaddr_nl addr;
+	int sk;
+
+	DBG("");
+
+	sk = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+	if (sk < 0)
+		return -1;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.nl_family = AF_NETLINK;
+	addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE;
+	//addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
+	//addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
+
+	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		close(sk);
+		return -1;
+	}
+
+	channel = g_io_channel_unix_new(sk);
+	g_io_channel_set_close_on_unref(channel, TRUE);
+
+	g_io_add_watch(channel, G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+							netlink_event, NULL);
+
+	return 0;
+}
+
+void __connman_rtnl_cleanup(void)
+{
+	GSList *list;
+
+	DBG("");
+
+	for (list = watch_list; list; list = list->next) {
+		struct watch_data *watch = list->data;
+
+		DBG("removing watch %d", watch->id);
+
+		g_free(watch);
+		list->data = NULL;
+	}
+
+	g_slist_free(watch_list);
+	watch_list = NULL;
+
+	for (list = request_list; list; list = list->next) {
+		struct rtnl_request *req = list->data;
+
+		DBG("%s len %d type %d flags 0x%04x seq %d",
+				type2string(req->hdr.nlmsg_type),
+				req->hdr.nlmsg_len, req->hdr.nlmsg_type,
+				req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
+
+		g_free(req);
+		list->data = NULL;
+	}
+
+	g_slist_free(request_list);
+	request_list = NULL;
+
+	g_io_channel_shutdown(channel, TRUE, NULL);
+	g_io_channel_unref(channel);
+
+	channel = NULL;
+}




More information about the commitlog mailing list