X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Frtnl.c;h=ece4f16501b65cfdbaf95b687e188088ce5168fa;hb=cd320803ef8b6850e097adcd4c074ef416be190a;hp=3e26dbff020d9188c511656c436a0b2c61ab0f6c;hpb=d3ad57f2adff903961edfdec45b60e5813107eff;p=connman diff --git a/src/rtnl.c b/src/rtnl.c index 3e26dbf..ece4f16 100644 --- a/src/rtnl.c +++ b/src/rtnl.c @@ -2,7 +2,7 @@ * * Connection Manager * - * Copyright (C) 2007 Intel Corporation. All rights reserved. + * 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 @@ -23,7 +23,6 @@ #include #endif -#include #include #include #include @@ -37,19 +36,75 @@ #include "connman.h" -struct rtnl_data { - unsigned ifi_flags; -}; +static GSList *rtnl_list = NULL; -static struct rtnl_data *get_rtnl_data(struct connman_iface *iface) +static gint compare_priority(gconstpointer a, gconstpointer b) { - if ((iface->flags & CONNMAN_IFACE_FLAG_RTNL) == 0) - return NULL; + const struct connman_rtnl *rtnl1 = a; + const struct connman_rtnl *rtnl2 = b; - if (iface->rtnl_data == NULL) - iface->rtnl_data = g_try_new0(struct rtnl_data, 1); + return rtnl2->priority - rtnl1->priority; +} - return iface->rtnl_data; +/** + * 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; + + DBG("index %d", index); + + for (list = rtnl_list; list; list = list->next) { + struct connman_rtnl *rtnl = list->data; + + if (rtnl->newlink) + rtnl->newlink(type, index, flags, change); + } +} + +static void process_dellink(unsigned short type, int index, + unsigned flags, unsigned change) +{ + GSList *list; + + DBG("index %d", index); + + for (list = rtnl_list; list; list = list->next) { + struct connman_rtnl *rtnl = list->data; + + if (rtnl->dellink) + rtnl->dellink(type, index, flags, change); + } } static inline void print_inet(struct rtattr *attr, const char *name, int family) @@ -57,37 +112,36 @@ 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)); - printf(" attr %s (len %d) %s\n", + DBG(" attr %s (len %jd) %s\n", name, RTA_PAYLOAD(attr), inet_ntoa(addr)); } else - printf(" attr %s (len %d)\n", name, RTA_PAYLOAD(attr)); + DBG(" attr %s (len %jd)\n", name, RTA_PAYLOAD(attr)); } static inline void print_char(struct rtattr *attr, const char *name) { - printf(" attr %s (len %d) %s\n", name, RTA_PAYLOAD(attr), + 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) { - printf(" attr %s (len %d) 0x%02x\n", name, RTA_PAYLOAD(attr), + 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) - printf(" attr %s (len %d)\n", name, RTA_PAYLOAD(attr)); + DBG(" attr %s (len %jd)\n", name, RTA_PAYLOAD(attr)); else - printf(" attr %d (len %d)\n", + DBG(" attr %d (len %jd)\n", attr->rta_type, RTA_PAYLOAD(attr)); } static void rtnl_link(struct nlmsghdr *hdr) { - struct connman_iface *iface; - struct rtnl_data *data; +#if 0 struct ifinfomsg *msg; struct rtattr *attr; int bytes; @@ -97,30 +151,6 @@ static void rtnl_link(struct nlmsghdr *hdr) DBG("ifi_index %d ifi_flags 0x%04x", msg->ifi_index, msg->ifi_flags); - iface = __connman_iface_find(msg->ifi_index); - if (iface == NULL) - return; - - data = get_rtnl_data(iface); - if (data == NULL) - return; - - if ((data->ifi_flags & IFF_RUNNING) != (msg->ifi_flags & IFF_RUNNING)) { - if (msg->ifi_flags & IFF_RUNNING) - connman_iface_indicate_carrier_on(iface); - else - connman_iface_indicate_carrier_off(iface); - } - - if ((data->ifi_flags & IFF_UP) != (msg->ifi_flags & IFF_UP)) { - if (msg->ifi_flags & IFF_UP) - connman_iface_indicate_enabled(iface); - else - connman_iface_indicate_disabled(iface); - } - - data->ifi_flags = msg->ifi_flags; - for (attr = IFLA_RTA(msg); RTA_OK(attr, bytes); attr = RTA_NEXT(attr, bytes)) { switch (attr->rta_type) { @@ -155,9 +185,7 @@ static void rtnl_link(struct nlmsghdr *hdr) print_attr(attr, "master"); break; case IFLA_WIRELESS: - if (iface->driver->rtnl_wireless) - iface->driver->rtnl_wireless(iface, - RTA_DATA(attr), RTA_PAYLOAD(attr)); + print_attr(attr, "wireless"); break; case IFLA_PROTINFO: print_attr(attr, "protinfo"); @@ -182,12 +210,39 @@ static void rtnl_link(struct nlmsghdr *hdr) break; } } +#endif +} + +static void rtnl_newlink(struct nlmsghdr *hdr) +{ + struct ifinfomsg *msg; + + msg = (struct ifinfomsg *) NLMSG_DATA(hdr); + + DBG("ifi_index %d ifi_flags 0x%04x", msg->ifi_index, msg->ifi_flags); + + 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_index %d ifi_flags 0x%04x", msg->ifi_index, msg->ifi_flags); + + 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 connman_iface *iface; - struct rtnl_data *data; struct ifaddrmsg *msg; struct rtattr *attr; int bytes; @@ -197,14 +252,6 @@ static void rtnl_addr(struct nlmsghdr *hdr) DBG("ifa_family %d ifa_index %d", msg->ifa_family, msg->ifa_index); - iface = __connman_iface_find(msg->ifa_index); - if (iface == NULL) - return; - - data = get_rtnl_data(iface); - if (data == NULL) - return; - for (attr = IFA_RTA(msg); RTA_OK(attr, bytes); attr = RTA_NEXT(attr, bytes)) { switch (attr->rta_type) { @@ -286,7 +333,7 @@ static void rtnl_route(struct nlmsghdr *hdr) static void rtnl_message(void *buf, size_t len) { - DBG("buf %p len %d", buf, len); + DBG("buf %p len %zd", buf, len); while (len > 0) { struct nlmsghdr *hdr = buf; @@ -316,11 +363,11 @@ static void rtnl_message(void *buf, size_t len) return; case RTM_NEWLINK: DBG("NEWLINK"); - rtnl_link(hdr); + rtnl_newlink(hdr); break; case RTM_DELLINK: DBG("DELLINK"); - rtnl_link(hdr); + rtnl_dellink(hdr); break; case RTM_NEWADDR: DBG("NEWADDR"); @@ -351,7 +398,7 @@ static void rtnl_message(void *buf, size_t len) static gboolean netlink_event(GIOChannel *chan, GIOCondition cond, gpointer data) { - unsigned char buf[256]; + unsigned char buf[4096]; gsize len; GIOError err; @@ -379,7 +426,7 @@ int __connman_rtnl_send(const void *buf, size_t len) struct sockaddr_nl addr; int sk; - DBG("buf %p len %d", buf, len); + DBG("buf %p len %zd", buf, len); sk = g_io_channel_unix_get_fd(channel); @@ -390,6 +437,26 @@ int __connman_rtnl_send(const void *buf, size_t len) (struct sockaddr *) &addr, sizeof(addr)); } +int connman_rtnl_send_getlink(void) +{ + struct { + struct nlmsghdr hdr; + struct rtgenmsg msg; + } req; + + DBG(""); + + memset(&req, 0, sizeof(req)); + req.hdr.nlmsg_len = sizeof(req.hdr) + sizeof(req.msg); + 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 = 42; + req.msg.rtgen_family = AF_INET; + + return __connman_rtnl_send(&req, sizeof(req)); +} + int __connman_rtnl_init(void) { struct sockaddr_nl addr; @@ -403,7 +470,8 @@ int __connman_rtnl_init(void) memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; - addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR; + addr.nl_groups = RTMGRP_LINK; + //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) { @@ -414,9 +482,8 @@ int __connman_rtnl_init(void) 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); + g_io_add_watch(channel, G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR, + netlink_event, NULL); return 0; }