summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2009-08-08 21:07:49 -0700
committerMarcel Holtmann <marcel@holtmann.org>2009-08-08 21:07:49 -0700
commiteedda82541e0cc367f784c3551277d40c53b28f5 (patch)
treea9362e07527e4a60a9453d6113f3e61268e37041
parent10b6ada1337f719b1a0a4232c63f098da218bc2b (diff)
downloadconnman-eedda82541e0cc367f784c3551277d40c53b28f5.tar.gz
connman-eedda82541e0cc367f784c3551277d40c53b28f5.tar.bz2
connman-eedda82541e0cc367f784c3551277d40c53b28f5.zip
Add support for tracking route table changes via RTNL
-rw-r--r--src/connman.h6
-rw-r--r--src/ipconfig.c30
-rw-r--r--src/rtnl.c297
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) {
diff --git a/src/rtnl.c b/src/rtnl.c
index 679a9dfe..c6fd27e7 100644
--- a/src/rtnl.c
+++ b/src/rtnl.c
@@ -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)