diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2009-08-08 21:07:49 -0700 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2009-08-08 21:07:49 -0700 |
commit | eedda82541e0cc367f784c3551277d40c53b28f5 (patch) | |
tree | a9362e07527e4a60a9453d6113f3e61268e37041 | |
parent | 10b6ada1337f719b1a0a4232c63f098da218bc2b (diff) | |
download | connman-eedda82541e0cc367f784c3551277d40c53b28f5.tar.gz connman-eedda82541e0cc367f784c3551277d40c53b28f5.tar.bz2 connman-eedda82541e0cc367f784c3551277d40c53b28f5.zip |
Add support for tracking route table changes via RTNL
-rw-r--r-- | src/connman.h | 6 | ||||
-rw-r--r-- | src/ipconfig.c | 30 | ||||
-rw-r--r-- | src/rtnl.c | 297 |
3 files changed, 209 insertions, 124 deletions
diff --git a/src/connman.h b/src/connman.h index 28df972d..f8709d7a 100644 --- a/src/connman.h +++ b/src/connman.h @@ -103,6 +103,12 @@ void __connman_ipconfig_add_address(struct connman_ipconfig *ipconfig, void __connman_ipconfig_del_address(struct connman_ipconfig *ipconfig, const char *label, unsigned char prefixlen, const char *address, const char *broadcast); +void __connman_ipconfig_add_route(struct connman_ipconfig *ipconfig, + unsigned char scope, const char *destination, + const char *gateway); +void __connman_ipconfig_del_route(struct connman_ipconfig *ipconfig, + unsigned char scope, const char *destination, + const char *gateway); const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method); enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method); diff --git a/src/ipconfig.c b/src/ipconfig.c index 2d5c5eed..840964a2 100644 --- a/src/ipconfig.c +++ b/src/ipconfig.c @@ -242,6 +242,36 @@ void __connman_ipconfig_del_address(struct connman_ipconfig *ipconfig, address, prefixlen, label); } +static const char *scope2str(unsigned char scope) +{ + switch (scope) { + case 0: + return "UNIVERSE"; + case 253: + return "LINK"; + } + + return ""; +} + +void __connman_ipconfig_add_route(struct connman_ipconfig *ipconfig, + unsigned char scope, const char *destination, + const char *gateway) +{ + connman_info("%s {add} route %s gw %s scope %u <%s>", + ipconfig->interface, destination, + gateway, scope, scope2str(scope)); +} + +void __connman_ipconfig_del_route(struct connman_ipconfig *ipconfig, + unsigned char scope, const char *destination, + const char *gateway) +{ + connman_info("%s {add} route %s gw %s scope %u <%s>", + ipconfig->interface, destination, + gateway, scope, scope2str(scope)); +} + const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method) { switch (method) { @@ -37,6 +37,9 @@ #include "connman.h" +#define print(arg...) do { } while (0) +//#define print(arg...) connman_info(arg) + struct watch_data { unsigned int id; int index; @@ -263,179 +266,235 @@ static void process_dellink(unsigned short type, int index, } } -static char *extract_gateway(struct rtmsg *msg, int bytes, int *index) +static void extract_addr(struct ifaddrmsg *msg, int bytes, + const char **label, + struct in_addr *local, + struct in_addr *address, + struct in_addr *broadcast) { - char *gateway = NULL; - struct in_addr addr; struct rtattr *attr; - for (attr = RTM_RTA(msg); RTA_OK(attr, bytes); + for (attr = IFA_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)); + case IFA_ADDRESS: + if (address != NULL) + *address = *((struct in_addr *) RTA_DATA(attr)); break; - case RTA_OIF: - *index = *((int *) RTA_DATA(attr)); + case IFA_LOCAL: + if (local != NULL) + *local = *((struct in_addr *) RTA_DATA(attr)); + break; + case IFA_BROADCAST: + if (broadcast != NULL) + *broadcast = *((struct in_addr *) RTA_DATA(attr)); + break; + case IFA_LABEL: + if (label != NULL) + *label = RTA_DATA(attr); break; } } - - return gateway; } -static void process_newgateway(struct rtmsg *msg, int bytes) +static void process_newaddr(unsigned char family, unsigned char prefixlen, + int index, struct ifaddrmsg *msg, int bytes) { - int index = -1; - char *gateway; GSList *list; + const char *label; + struct in_addr address = { INADDR_ANY }; - gateway = extract_gateway(msg, bytes, &index); - if (gateway == NULL || index < 0) + if (family != AF_INET) return; - for (list = rtnl_list; list; list = list->next) { - struct connman_rtnl *rtnl = list->data; + extract_addr(msg, bytes, &label, &address, NULL, NULL); - if (rtnl->newgateway) - rtnl->newgateway(index, gateway); - } + for (list = ipconfig_list; list; list = list->next) { + struct connman_ipconfig *ipconfig = list->data; + + if (__connman_ipconfig_get_index(ipconfig) != index) + continue; - g_free(gateway); + __connman_ipconfig_add_address(ipconfig, label, prefixlen, + inet_ntoa(address), NULL); + } } -static void process_delgateway(struct rtmsg *msg, int bytes) +static void process_deladdr(unsigned char family, unsigned char prefixlen, + int index, struct ifaddrmsg *msg, int bytes) { - int index = -1; - char *gateway; GSList *list; + const char *label; + struct in_addr address = { INADDR_ANY }; - gateway = extract_gateway(msg, bytes, &index); - if (gateway == NULL || index < 0) + if (family != AF_INET) return; - for (list = rtnl_list; list; list = list->next) { - struct connman_rtnl *rtnl = list->data; + extract_addr(msg, bytes, &label, &address, NULL, NULL); - if (rtnl->delgateway) - rtnl->delgateway(index, gateway); - } + for (list = ipconfig_list; list; list = list->next) { + struct connman_ipconfig *ipconfig = list->data; - g_free(gateway); + if (__connman_ipconfig_get_index(ipconfig) != index) + continue; + + __connman_ipconfig_del_address(ipconfig, label, prefixlen, + inet_ntoa(address), NULL); + } } -static void extract_addr(struct ifaddrmsg *msg, int bytes, - const char **label, - struct in_addr *local, - struct in_addr *address, - struct in_addr *broadcast) +static void extract_route(struct rtmsg *msg, int bytes, int *index, + struct in_addr *dst, + struct in_addr *gateway) { struct rtattr *attr; - for (attr = IFA_RTA(msg); RTA_OK(attr, bytes); + for (attr = RTM_RTA(msg); RTA_OK(attr, bytes); attr = RTA_NEXT(attr, bytes)) { switch (attr->rta_type) { - case IFA_ADDRESS: - if (address != NULL) - *address = *((struct in_addr *) RTA_DATA(attr)); - break; - case IFA_LOCAL: - if (local != NULL) - *local = *((struct in_addr *) RTA_DATA(attr)); + case RTA_DST: + if (dst != NULL) + *dst = *((struct in_addr *) RTA_DATA(attr)); break; - case IFA_BROADCAST: - if (broadcast != NULL) - *broadcast = *((struct in_addr *) RTA_DATA(attr)); + case RTA_GATEWAY: + if (gateway != NULL) + *gateway = *((struct in_addr *) RTA_DATA(attr)); break; - case IFA_LABEL: - if (label != NULL) - *label = RTA_DATA(attr); + case RTA_OIF: + if (index != NULL) + *index = *((int *) RTA_DATA(attr)); break; } } } -static void process_newaddr(int family, int prefixlen, int index, - struct ifaddrmsg *msg, int bytes) +static void process_newroute(unsigned char family, unsigned char scope, + struct rtmsg *msg, int bytes) { GSList *list; - const char *label; - struct in_addr address; + struct in_addr dst = { INADDR_ANY }, gateway = { INADDR_ANY }; + char dststr[16], gatewaystr[16]; + int index = -1; if (family != AF_INET) return; + extract_route(msg, bytes, &index, &dst, &gateway); + + inet_ntop(family, &dst, dststr, sizeof(dststr)); + inet_ntop(family, &gateway, gatewaystr, sizeof(gatewaystr)); + for (list = ipconfig_list; list; list = list->next) { struct connman_ipconfig *ipconfig = list->data; if (__connman_ipconfig_get_index(ipconfig) != index) continue; - extract_addr(msg, bytes, &label, &address, NULL, NULL); - __connman_ipconfig_add_address(ipconfig, label, prefixlen, - inet_ntoa(address), NULL); + __connman_ipconfig_add_route(ipconfig, scope, + dststr, gatewaystr); } } -static void process_deladdr(int family, int prefixlen, int index, - struct ifaddrmsg *msg, int bytes) +static void process_delroute(unsigned char family, unsigned char scope, + struct rtmsg *msg, int bytes) { GSList *list; - const char *label; - struct in_addr address; + struct in_addr dst = { INADDR_ANY }, gateway = { INADDR_ANY }; + char dststr[16], gatewaystr[16]; + int index = -1; if (family != AF_INET) return; + extract_route(msg, bytes, &index, &dst, &gateway); + + inet_ntop(family, &dst, dststr, sizeof(dststr)); + inet_ntop(family, &gateway, gatewaystr, sizeof(gatewaystr)); + for (list = ipconfig_list; list; list = list->next) { struct connman_ipconfig *ipconfig = list->data; if (__connman_ipconfig_get_index(ipconfig) != index) continue; - extract_addr(msg, bytes, &label, &address, NULL, NULL); - __connman_ipconfig_del_address(ipconfig, label, prefixlen, - inet_ntoa(address), NULL); + __connman_ipconfig_del_route(ipconfig, scope, + dststr, gatewaystr); + } +} + +static void process_newgateway(struct rtmsg *msg, int bytes) +{ + GSList *list; + struct in_addr addr; + int index = -1; + + extract_route(msg, bytes, &index, NULL, &addr); + + for (list = rtnl_list; list; list = list->next) { + struct connman_rtnl *rtnl = list->data; + + if (rtnl->newgateway) + rtnl->newgateway(index, inet_ntoa(addr)); + } +} + +static void process_delgateway(struct rtmsg *msg, int bytes) +{ + GSList *list; + struct in_addr addr; + int index = -1; + + extract_route(msg, bytes, &index, NULL, &addr); + + for (list = rtnl_list; list; list = list->next) { + struct connman_rtnl *rtnl = list->data; + + if (rtnl->delgateway) + rtnl->delgateway(index, inet_ntoa(addr)); } } -static inline void print_inet(struct rtattr *attr, const char *name, int family) +static inline void print_inet(struct rtattr *attr, const char *name, + unsigned char family) { if (family == AF_INET) { struct in_addr addr; addr = *((struct in_addr *) RTA_DATA(attr)); - DBG(" attr %s (len %d) %s\n", name, + print(" attr %s (len %d) %s\n", name, (int) RTA_PAYLOAD(attr), inet_ntoa(addr)); } else - DBG(" attr %s (len %d)\n", name, (int) RTA_PAYLOAD(attr)); + print(" attr %s (len %d)\n", name, (int) RTA_PAYLOAD(attr)); } -static inline void print_char(struct rtattr *attr, const char *name) +static inline void print_string(struct rtattr *attr, const char *name) { - DBG(" attr %s (len %d) %s\n", name, (int) RTA_PAYLOAD(attr), + print(" attr %s (len %d) %s\n", name, (int) RTA_PAYLOAD(attr), (char *) RTA_DATA(attr)); } static inline void print_byte(struct rtattr *attr, const char *name) { - DBG(" attr %s (len %d) 0x%02x\n", name, (int) RTA_PAYLOAD(attr), + print(" attr %s (len %d) 0x%02x\n", name, (int) RTA_PAYLOAD(attr), *((unsigned char *) RTA_DATA(attr))); } +static inline void print_integer(struct rtattr *attr, const char *name) +{ + print(" attr %s (len %d) %d\n", name, (int) RTA_PAYLOAD(attr), + *((int *) RTA_DATA(attr))); +} + static inline void print_attr(struct rtattr *attr, const char *name) { if (name) - DBG(" attr %s (len %d)\n", name, (int) RTA_PAYLOAD(attr)); + print(" attr %s (len %d)\n", name, (int) RTA_PAYLOAD(attr)); else - DBG(" attr %d (len %d)\n", + print(" attr %d (len %d)\n", attr->rta_type, (int) RTA_PAYLOAD(attr)); } static void rtnl_link(struct nlmsghdr *hdr) { -#if 0 struct ifinfomsg *msg; struct rtattr *attr; int bytes; @@ -443,7 +502,7 @@ static void rtnl_link(struct nlmsghdr *hdr) msg = (struct ifinfomsg *) NLMSG_DATA(hdr); bytes = IFLA_PAYLOAD(hdr); - DBG("ifi_index %d ifi_flags 0x%04x", msg->ifi_index, msg->ifi_flags); + print("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)) { @@ -455,10 +514,10 @@ static void rtnl_link(struct nlmsghdr *hdr) print_attr(attr, "broadcast"); break; case IFLA_IFNAME: - print_char(attr, "ifname"); + print_string(attr, "ifname"); break; case IFLA_MTU: - print_attr(attr, "mtu"); + print_integer(attr, "mtu"); break; case IFLA_LINK: print_attr(attr, "link"); @@ -504,40 +563,30 @@ static void rtnl_link(struct nlmsghdr *hdr) break; } } -#endif } static void rtnl_newlink(struct nlmsghdr *hdr) { struct ifinfomsg *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); + rtnl_link(hdr); 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 = (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); + rtnl_link(hdr); process_dellink(msg->ifi_type, msg->ifi_index, msg->ifi_flags, msg->ifi_change); - - rtnl_link(hdr); } static void rtnl_addr(struct nlmsghdr *hdr) { -#if 0 struct ifaddrmsg *msg; struct rtattr *attr; int bytes; @@ -545,7 +594,7 @@ static void rtnl_addr(struct nlmsghdr *hdr) msg = (struct ifaddrmsg *) NLMSG_DATA(hdr); bytes = IFA_PAYLOAD(hdr); - DBG("ifa_family %d ifa_index %d", msg->ifa_family, msg->ifa_index); + print("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)) { @@ -557,7 +606,7 @@ static void rtnl_addr(struct nlmsghdr *hdr) print_inet(attr, "local", msg->ifa_family); break; case IFA_LABEL: - print_char(attr, "label"); + print_string(attr, "label"); break; case IFA_BROADCAST: print_inet(attr, "broadcast", msg->ifa_family); @@ -576,38 +625,30 @@ static void rtnl_addr(struct nlmsghdr *hdr) break; } } -#endif } static void rtnl_newaddr(struct nlmsghdr *hdr) { struct ifaddrmsg *msg = (struct ifaddrmsg *) NLMSG_DATA(hdr); - DBG("ifa_family %d ifa_prefixlen %d ifa_index %d", - msg->ifa_family, msg->ifa_prefixlen, msg->ifa_index); + rtnl_addr(hdr); process_newaddr(msg->ifa_family, msg->ifa_prefixlen, msg->ifa_index, msg, IFA_PAYLOAD(hdr)); - - rtnl_addr(hdr); } static void rtnl_deladdr(struct nlmsghdr *hdr) { struct ifaddrmsg *msg = (struct ifaddrmsg *) NLMSG_DATA(hdr); - DBG("ifa_family %d ifa_prefixlen %d ifa_index %d", - msg->ifa_family, msg->ifa_prefixlen, msg->ifa_index); + rtnl_addr(hdr); process_deladdr(msg->ifa_family, msg->ifa_prefixlen, msg->ifa_index, msg, IFA_PAYLOAD(hdr)); - - rtnl_addr(hdr); } static void rtnl_route(struct nlmsghdr *hdr) { -#if 0 struct rtmsg *msg; struct rtattr *attr; int bytes; @@ -615,7 +656,10 @@ static void rtnl_route(struct nlmsghdr *hdr) msg = (struct rtmsg *) NLMSG_DATA(hdr); bytes = RTM_PAYLOAD(hdr); - DBG("rtm_family %d rtm_flags 0x%04x", msg->rtm_family, msg->rtm_flags); + print("rtm_family %d rtm_table %d rtm_protocol %d", + msg->rtm_family, msg->rtm_table, msg->rtm_protocol); + print("rtm_scope %d rtm_type %d rtm_flags 0x%04x", + msg->rtm_scope, msg->rtm_type, msg->rtm_flags); for (attr = RTM_RTA(msg); RTA_OK(attr, bytes); attr = RTA_NEXT(attr, bytes)) { @@ -627,10 +671,10 @@ static void rtnl_route(struct nlmsghdr *hdr) print_inet(attr, "src", msg->rtm_family); break; case RTA_IIF: - print_char(attr, "iif"); + print_string(attr, "iif"); break; case RTA_OIF: - print_attr(attr, "oif"); + print_integer(attr, "oif"); break; case RTA_GATEWAY: print_inet(attr, "gateway", msg->rtm_family); @@ -645,44 +689,49 @@ static void rtnl_route(struct nlmsghdr *hdr) print_attr(attr, "metrics"); break; case RTA_TABLE: - print_attr(attr, "table"); + print_integer(attr, "table"); break; default: print_attr(attr, NULL); break; } } -#endif } static void rtnl_newroute(struct nlmsghdr *hdr) { struct rtmsg *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); + + if (msg->rtm_table == RT_TABLE_MAIN && + msg->rtm_protocol == RTPROT_BOOT && + msg->rtm_type == RTN_UNICAST) { + + process_newroute(msg->rtm_family, msg->rtm_scope, + msg, RTM_PAYLOAD(hdr)); + + if (msg->rtm_scope == RT_SCOPE_UNIVERSE) + process_newgateway(msg, RTM_PAYLOAD(hdr)); + } } static void rtnl_delroute(struct nlmsghdr *hdr) { struct rtmsg *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); + + if (msg->rtm_table == RT_TABLE_MAIN && + msg->rtm_protocol == RTPROT_BOOT && + msg->rtm_type == RTN_UNICAST) { + + process_delroute(msg->rtm_family, msg->rtm_scope, + msg, RTM_PAYLOAD(hdr)); + + if (msg->rtm_scope == RT_SCOPE_UNIVERSE) + process_delgateway(msg, RTM_PAYLOAD(hdr)); + } } static const char *type2string(uint16_t type) |