From e77f2d1c63c96990529f4e4294337263b8738ff8 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 7 Aug 2009 21:33:07 -0700 Subject: Add initial steps for IPv4 monitoring via RTNL --- include/ipconfig.h | 2 +- src/connman.h | 12 ++++ src/device.c | 19 ++++--- src/ipconfig.c | 38 ++++++++++++- src/network.c | 14 ++--- src/rtnl.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++++---- src/service.c | 27 ++++----- 7 files changed, 237 insertions(+), 39 deletions(-) diff --git a/include/ipconfig.h b/include/ipconfig.h index 66a260ba..08fe5588 100644 --- a/include/ipconfig.h +++ b/include/ipconfig.h @@ -47,7 +47,7 @@ enum connman_ipconfig_method { struct connman_ipconfig; -struct connman_ipconfig *connman_ipconfig_create(void); +struct connman_ipconfig *connman_ipconfig_create(const char *interface); struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig); void connman_ipconfig_unref(struct connman_ipconfig *ipconfig); diff --git a/src/connman.h b/src/connman.h index bbe9e226..a5fb7091 100644 --- a/src/connman.h +++ b/src/connman.h @@ -91,6 +91,15 @@ int __connman_security_check_privilege(DBusMessage *message, #include +int __connman_ipconfig_get_index(struct connman_ipconfig *ipconfig); + +void __connman_ipconfig_add_address(struct connman_ipconfig *ipconfig, + const char *label, unsigned int prefixlen, + const char *address, const char *broadcast); +void __connman_ipconfig_del_address(struct connman_ipconfig *ipconfig, + const char *label, unsigned int prefixlen, + const char *address, const char *broadcast); + const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method); enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method); @@ -347,3 +356,6 @@ void __connman_rtnl_start(void); void __connman_rtnl_cleanup(void); int __connman_rtnl_send(const void *buf, size_t len); + +int __connman_rtnl_register_ipconfig(struct connman_ipconfig *ipconfig); +void __connman_rtnl_unregister_ipconfig(struct connman_ipconfig *ipconfig); diff --git a/src/device.c b/src/device.c index 984f55f5..7ac2ab85 100644 --- a/src/device.c +++ b/src/device.c @@ -544,6 +544,9 @@ static DBusMessage *set_property(DBusConnection *conn, } else if (g_str_has_prefix(name, "IPv4.") == TRUE) { int err; + if (device->ipconfig == NULL) + return __connman_error_invalid_property(msg); + switch (device->mode) { case CONNMAN_DEVICE_MODE_UNKNOWN: case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: @@ -862,7 +865,10 @@ static void device_destruct(struct connman_element *element) g_free(device->control); g_free(device->interface); - connman_ipconfig_unref(device->ipconfig); + if (device->ipconfig != NULL) { + connman_ipconfig_unref(device->ipconfig); + device->ipconfig = NULL; + } g_free(device->last_network); @@ -944,12 +950,6 @@ struct connman_device *connman_device_create(const char *node, break; } - device->ipconfig = connman_ipconfig_create(); - if (device->ipconfig == NULL) { - connman_device_unref(device); - return NULL; - } - device->networks = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, unregister_network); @@ -1079,6 +1079,11 @@ void connman_device_set_interface(struct connman_device *device, device->name = g_strdup_printf("%s (%s)", str, device->interface); } + + if (device->ipconfig != NULL) + connman_ipconfig_unref(device->ipconfig); + + device->ipconfig = connman_ipconfig_create(interface); } const char *connman_device_get_control(struct connman_device *device) diff --git a/src/ipconfig.c b/src/ipconfig.c index 6e4927d4..2e3d22bc 100644 --- a/src/ipconfig.c +++ b/src/ipconfig.c @@ -29,6 +29,8 @@ struct connman_ipconfig { gint refcount; + int index; + char *interface; enum connman_ipconfig_method method; }; @@ -39,18 +41,28 @@ struct connman_ipconfig { * * Returns: a newly-allocated #connman_ipconfig structure */ -struct connman_ipconfig *connman_ipconfig_create(void) +struct connman_ipconfig *connman_ipconfig_create(const char *interface) { struct connman_ipconfig *ipconfig; + int index; DBG(""); + index = connman_inet_ifindex(interface); + if (index < 0) + return NULL; + ipconfig = g_try_new0(struct connman_ipconfig, 1); if (ipconfig == NULL) return NULL; + ipconfig->index = index; + ipconfig->interface = g_strdup(interface); + DBG("ipconfig %p", ipconfig); + __connman_rtnl_register_ipconfig(ipconfig); + return ipconfig; } @@ -76,6 +88,9 @@ struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig) void connman_ipconfig_unref(struct connman_ipconfig *ipconfig) { if (g_atomic_int_dec_and_test(&ipconfig->refcount) == TRUE) { + __connman_rtnl_unregister_ipconfig(ipconfig); + + g_free(ipconfig->interface); g_free(ipconfig); } } @@ -95,6 +110,27 @@ int connman_ipconfig_set_method(struct connman_ipconfig *ipconfig, return 0; } +int __connman_ipconfig_get_index(struct connman_ipconfig *ipconfig) +{ + return ipconfig->index; +} + +void __connman_ipconfig_add_address(struct connman_ipconfig *ipconfig, + const char *label, unsigned int prefixlen, + const char *address, const char *broadcast) +{ + connman_info("%s {add} address %s/%d label %s", ipconfig->interface, + address, prefixlen, label); +} + +void __connman_ipconfig_del_address(struct connman_ipconfig *ipconfig, + const char *label, unsigned int prefixlen, + const char *address, const char *broadcast) +{ + connman_info("%s {del} address %s/%d label %s", ipconfig->interface, + address, prefixlen, label); +} + const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method) { switch (method) { diff --git a/src/network.c b/src/network.c index c9f61886..932e1f26 100644 --- a/src/network.c +++ b/src/network.c @@ -205,6 +205,9 @@ static DBusMessage *set_property(DBusConnection *conn, } else if (g_str_has_prefix(name, "IPv4.") == TRUE) { int err; + if (network->ipconfig == NULL) + return __connman_error_invalid_property(msg); + err = __connman_ipconfig_set_ipv4(network->ipconfig, name + 5, &value); if (err < 0) @@ -368,7 +371,10 @@ static void network_destruct(struct connman_element *element) g_free(network->address); g_free(network->identifier); - connman_ipconfig_unref(network->ipconfig); + if (network->ipconfig) { + connman_ipconfig_unref(network->ipconfig); + network->ipconfig = NULL; + } } /** @@ -425,12 +431,6 @@ struct connman_network *connman_network_create(const char *identifier, network->secondary = FALSE; network->identifier = g_strdup(temp); - network->ipconfig = connman_ipconfig_create(); - if (network->ipconfig == NULL) { - connman_network_unref(network); - return NULL; - } - return network; } diff --git a/src/rtnl.c b/src/rtnl.c index 5b07865e..40b3ea93 100644 --- a/src/rtnl.c +++ b/src/rtnl.c @@ -244,6 +244,99 @@ static void process_delgateway(struct rtmsg *msg, int bytes) g_free(gateway); } +static void extract_addr(struct ifaddrmsg *msg, int bytes, + const char **label, + struct in_addr *local, + struct in_addr *address, + struct in_addr *broadcast) +{ + struct rtattr *attr; + + for (attr = IFA_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)); + 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; + } + } +} + +static GSList *ipconfig_list = NULL; + +static void process_newaddr(int family, int prefixlen, int index, + struct ifaddrmsg *msg, int bytes) +{ + GSList *list; + const char *label; + struct in_addr address; + + if (family != AF_INET) + return; + + 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); + } +} + +static void process_deladdr(int family, int prefixlen, int index, + struct ifaddrmsg *msg, int bytes) +{ + GSList *list; + const char *label; + struct in_addr address; + + if (family != AF_INET) + return; + + 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); + } +} + +int __connman_rtnl_register_ipconfig(struct connman_ipconfig *ipconfig) +{ + DBG("ipconfig %p", ipconfig); + + ipconfig_list = g_slist_append(ipconfig_list, ipconfig); + + return 0; +} + +void __connman_rtnl_unregister_ipconfig(struct connman_ipconfig *ipconfig) +{ + DBG("ipconfig %p", ipconfig); + + ipconfig_list = g_slist_remove(ipconfig_list, ipconfig); +} + static inline void print_inet(struct rtattr *attr, const char *name, int family) { if (family == AF_INET) { @@ -384,6 +477,7 @@ static void rtnl_dellink(struct nlmsghdr *hdr) static void rtnl_addr(struct nlmsghdr *hdr) { +#if 0 struct ifaddrmsg *msg; struct rtattr *attr; int bytes; @@ -422,6 +516,35 @@ 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); + + 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; + + 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); + + 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) @@ -476,9 +599,7 @@ static void rtnl_route(struct nlmsghdr *hdr) static void rtnl_newroute(struct nlmsghdr *hdr) { - struct rtmsg *msg; - - msg = (struct rtmsg *) NLMSG_DATA(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) { @@ -493,9 +614,7 @@ static void rtnl_newroute(struct nlmsghdr *hdr) static void rtnl_delroute(struct nlmsghdr *hdr) { - struct rtmsg *msg; - - msg = (struct rtmsg *) NLMSG_DATA(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) { @@ -648,8 +767,10 @@ static void rtnl_message(void *buf, size_t len) rtnl_dellink(hdr); break; case RTM_NEWADDR: + rtnl_newaddr(hdr); + break; case RTM_DELADDR: - rtnl_addr(hdr); + rtnl_deladdr(hdr); break; case RTM_NEWROUTE: rtnl_newroute(hdr); @@ -708,6 +829,26 @@ int connman_rtnl_send_getlink(void) return queue_request(req); } +static int send_getaddr(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_GETADDR; + 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; @@ -741,9 +882,7 @@ int __connman_rtnl_init(void) 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; + addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE; if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { close(sk); @@ -762,6 +901,8 @@ int __connman_rtnl_init(void) void __connman_rtnl_start(void) { DBG(""); + + send_getaddr(); } void __connman_rtnl_cleanup(void) @@ -770,6 +911,9 @@ void __connman_rtnl_cleanup(void) DBG(""); + g_slist_free(ipconfig_list); + ipconfig_list = NULL; + for (list = watch_list; list; list = list->next) { struct watch_data *watch = list->data; diff --git a/src/service.c b/src/service.c index dfb2149f..09d2534e 100644 --- a/src/service.c +++ b/src/service.c @@ -467,7 +467,9 @@ static DBusMessage *get_properties(DBusConnection *conn, break; } - __connman_ipconfig_append_ipv4(service->ipconfig, &dict, "IPv4."); + if (service->ipconfig != NULL) + __connman_ipconfig_append_ipv4(service->ipconfig, + &dict, "IPv4."); dbus_message_iter_close_container(&array, &dict); @@ -541,6 +543,9 @@ static DBusMessage *set_property(DBusConnection *conn, } else if (g_str_has_prefix(name, "IPv4.") == TRUE) { int err; + if (service->ipconfig == NULL) + return __connman_error_invalid_property(msg); + err = __connman_ipconfig_set_ipv4(service->ipconfig, name + 5, &value); if (err < 0) @@ -942,7 +947,10 @@ static void service_free(gpointer user_data) if (service->network != NULL) connman_network_unref(service->network); - connman_ipconfig_unref(service->ipconfig); + if (service->ipconfig != NULL) { + connman_ipconfig_unref(service->ipconfig); + service->ipconfig = NULL; + } g_free(service->profile); g_free(service->name); @@ -1011,15 +1019,6 @@ struct connman_service *connman_service_create(void) __connman_service_initialize(service); - service->ipconfig = connman_ipconfig_create(); - if (service->ipconfig == NULL) { - g_free(service); - return NULL; - } - - connman_ipconfig_set_method(service->ipconfig, - CONNMAN_IPCONFIG_METHOD_DHCP); - return service; } @@ -2087,7 +2086,8 @@ static int service_load(struct connman_service *service) service->passphrase = str; } - __connman_ipconfig_load(service->ipconfig, keyfile, + if (service->ipconfig != NULL) + __connman_ipconfig_load(service->ipconfig, keyfile, service->identifier, "IPv4."); done: @@ -2204,7 +2204,8 @@ update: g_key_file_remove_key(keyfile, service->identifier, "Passphrase", NULL); - __connman_ipconfig_save(service->ipconfig, keyfile, + if (service->ipconfig != NULL) + __connman_ipconfig_save(service->ipconfig, keyfile, service->identifier, "IPv4."); data = g_key_file_to_data(keyfile, &length, NULL); -- cgit v1.2.3