X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Frtnl.c;h=7c8c68b858d6f273c000cb246a77224beab5e3c8;hb=cce6ed197cf6503e5ff068c2a25ad8f435b12068;hp=4f5021958c52b19557b59401c212b799d1578e1d;hpb=941e94a18d9e8c0af1124b36f8c0682b608604c4;p=platform%2Fupstream%2Fconnman.git diff --git a/src/rtnl.c b/src/rtnl.c index 4f50219..7c8c68b 100644 --- a/src/rtnl.c +++ b/src/rtnl.c @@ -2,7 +2,7 @@ * * Connection Manager * - * Copyright (C) 2007-2012 Intel Corporation. All rights reserved. + * Copyright (C) 2007-2013 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 @@ -46,6 +46,12 @@ #define ARPHDR_PHONET_PIPE (821) #endif +#if defined TIZEN_EXT +#ifndef ARPHDR_RMNET +#define ARPHDR_RMNET (530) +#endif +#endif + #define print(arg...) do { if (0) connman_info(arg); } while (0) //#define print(arg...) connman_info(arg) @@ -65,7 +71,6 @@ static guint update_timeout = 0; struct interface_data { int index; - char *name; char *ident; enum connman_service_type service_type; enum connman_device_type device_type; @@ -78,92 +83,121 @@ static void free_interface(gpointer data) struct interface_data *interface = data; __connman_technology_remove_interface(interface->service_type, - interface->index, interface->name, interface->ident); + interface->index, interface->ident); g_free(interface->ident); - g_free(interface->name); g_free(interface); } -static connman_bool_t ether_blacklisted(const char *name) +static bool ether_blacklisted(const char *name) { - if (name == NULL) - return TRUE; + if (!name) + return true; - /* virtual interface from VMware */ - if (g_str_has_prefix(name, "vmnet") == TRUE) - return TRUE; - - /* virtual interface from VirtualBox */ - if (g_str_has_prefix(name, "vboxnet") == TRUE) - return TRUE; + if (__connman_device_isfiltered(name)) + return true; - /* virtual interface from Virtual Machine Manager */ - if (g_str_has_prefix(name, "virbr") == TRUE) - return TRUE; - - return FALSE; + return false; } -static connman_bool_t wext_interface(char *ifname) +#if !defined TIZEN_EXT +static bool wext_interface(char *ifname) { struct iwreq wrq; int fd, err; fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (fd < 0) - return FALSE; + return false; memset(&wrq, 0, sizeof(wrq)); - strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + strncpy(wrq.ifr_name, ifname, sizeof(wrq.ifr_name) - 1); err = ioctl(fd, SIOCGIWNAME, &wrq); close(fd); if (err < 0) - return FALSE; + return false; - return TRUE; + return true; +} +#endif + +#if defined TIZEN_EXT +static bool __connman_rtnl_is_cellular_device(const char *name) +{ + char **pattern; + char **cellular_interfaces; + + cellular_interfaces = + connman_setting_get_string_list( + "NetworkCellularInterfaceList"); + if (!cellular_interfaces) + return false; + + for (pattern = cellular_interfaces; *pattern; pattern++) { + if (g_str_has_prefix(name, *pattern)) { + DBG("Cellular interface: %s", name); + return true; + } + } + + return false; } +#endif static void read_uevent(struct interface_data *interface) { - char *filename, line[128]; - connman_bool_t found_devtype; + char *filename, *name, line[128]; + bool found_devtype; FILE *f; - if (ether_blacklisted(interface->name) == TRUE) { + name = connman_inet_ifname(interface->index); + +#if defined TIZEN_EXT + if (__connman_rtnl_is_cellular_device(name)) { + interface->service_type = CONNMAN_SERVICE_TYPE_CELLULAR; + interface->device_type = CONNMAN_DEVICE_TYPE_CELLULAR; + g_free(name); + return; + } +#endif + + if (ether_blacklisted(name)) { interface->service_type = CONNMAN_SERVICE_TYPE_UNKNOWN; interface->device_type = CONNMAN_DEVICE_TYPE_UNKNOWN; + goto out; } else { interface->service_type = CONNMAN_SERVICE_TYPE_ETHERNET; interface->device_type = CONNMAN_DEVICE_TYPE_ETHERNET; } - filename = g_strdup_printf("/sys/class/net/%s/uevent", - interface->name); + filename = g_strdup_printf("/sys/class/net/%s/uevent", name); f = fopen(filename, "re"); g_free(filename); - if (f == NULL) - return; + if (!f) { + interface->service_type = CONNMAN_SERVICE_TYPE_UNKNOWN; + interface->device_type = CONNMAN_DEVICE_TYPE_UNKNOWN; + goto out; + } - found_devtype = FALSE; + found_devtype = false; while (fgets(line, sizeof(line), f)) { char *pos; pos = strchr(line, '\n'); - if (pos == NULL) + if (!pos) continue; pos[0] = '\0'; if (strncmp(line, "DEVTYPE=", 8) != 0) continue; - found_devtype = TRUE; + found_devtype = true; if (strcmp(line + 8, "wlan") == 0) { interface->service_type = CONNMAN_SERVICE_TYPE_WIFI; @@ -174,13 +208,15 @@ static void read_uevent(struct interface_data *interface) } else if (strcmp(line + 8, "bluetooth") == 0) { interface->service_type = CONNMAN_SERVICE_TYPE_BLUETOOTH; interface->device_type = CONNMAN_DEVICE_TYPE_BLUETOOTH; - } else if (strcmp(line + 8, "wimax") == 0) { - interface->service_type = CONNMAN_SERVICE_TYPE_WIMAX; - interface->device_type = CONNMAN_DEVICE_TYPE_WIMAX; } else if (strcmp(line + 8, "gadget") == 0) { interface->service_type = CONNMAN_SERVICE_TYPE_GADGET; interface->device_type = CONNMAN_DEVICE_TYPE_GADGET; - + } else if (strcmp(line + 8, "vlan") == 0) { + interface->service_type = CONNMAN_SERVICE_TYPE_ETHERNET; + interface->device_type = CONNMAN_DEVICE_TYPE_ETHERNET; + } else if (strcmp(line + 8, "bond") == 0) { + interface->service_type = CONNMAN_SERVICE_TYPE_ETHERNET; + interface->device_type = CONNMAN_DEVICE_TYPE_ETHERNET; } else { interface->service_type = CONNMAN_SERVICE_TYPE_UNKNOWN; interface->device_type = CONNMAN_DEVICE_TYPE_UNKNOWN; @@ -190,16 +226,21 @@ static void read_uevent(struct interface_data *interface) fclose(f); if (found_devtype) - return; + goto out; +#if !defined TIZEN_EXT + /* TIZEN does not use old wext interface */ /* We haven't got a DEVTYPE, let's check if it's a wireless device */ - if (wext_interface(interface->name)) { + if (wext_interface(name)) { interface->service_type = CONNMAN_SERVICE_TYPE_WIFI; interface->device_type = CONNMAN_DEVICE_TYPE_WIFI; - connman_error("%s runs an unsupported 802.11 driver", - interface->name); + connman_error("%s runs an unsupported 802.11 driver", name); } +#endif + +out: + g_free(name); } enum connman_device_type __connman_rtnl_get_device_type(int index) @@ -208,7 +249,7 @@ enum connman_device_type __connman_rtnl_get_device_type(int index) interface = g_hash_table_lookup(interface_list, GINT_TO_POINTER(index)); - if (interface == NULL) + if (!interface) return CONNMAN_DEVICE_TYPE_UNKNOWN; return interface->device_type; @@ -230,7 +271,7 @@ unsigned int connman_rtnl_add_newlink_watch(int index, struct watch_data *watch; watch = g_try_new0(struct watch_data, 1); - if (watch == NULL) + if (!watch) return 0; watch->id = ++watch_id; @@ -295,7 +336,7 @@ static void trigger_rtnl(int index, void *user_data) __connman_ipconfig_get_gateway_from_index(index, CONNMAN_IPCONFIG_TYPE_ALL); - if (gateway != NULL) + if (gateway) rtnl->newgateway(index, gateway); } } @@ -365,10 +406,10 @@ static const char *operstate2str(unsigned char operstate) return ""; } -static void extract_link(struct ifinfomsg *msg, int bytes, +static bool extract_link(struct ifinfomsg *msg, int bytes, struct ether_addr *address, const char **ifname, unsigned int *mtu, unsigned char *operstate, - struct rtnl_link_stats *stats) + struct rtnl_link_stats *stats) { struct rtattr *attr; @@ -376,37 +417,40 @@ static void extract_link(struct ifinfomsg *msg, int bytes, attr = RTA_NEXT(attr, bytes)) { switch (attr->rta_type) { case IFLA_ADDRESS: - if (address != NULL) + if (address) memcpy(address, RTA_DATA(attr), ETH_ALEN); break; case IFLA_IFNAME: - if (ifname != NULL) + if (ifname) *ifname = RTA_DATA(attr); break; case IFLA_MTU: - if (mtu != NULL) + if (mtu) *mtu = *((unsigned int *) RTA_DATA(attr)); break; case IFLA_STATS: - if (stats != NULL) + if (stats) memcpy(stats, RTA_DATA(attr), sizeof(struct rtnl_link_stats)); break; case IFLA_OPERSTATE: - if (operstate != NULL) + if (operstate) *operstate = *((unsigned char *) RTA_DATA(attr)); break; case IFLA_LINKMODE: break; + case IFLA_WIRELESS: + return false; } } + + return true; } static void process_newlink(unsigned short type, int index, unsigned flags, unsigned change, struct ifinfomsg *msg, int bytes) { struct ether_addr address = {{ 0, 0, 0, 0, 0, 0 }}; - struct ether_addr compare = {{ 0, 0, 0, 0, 0, 0 }}; struct rtnl_link_stats stats; unsigned char operstate = 0xff; struct interface_data *interface; @@ -416,7 +460,30 @@ static void process_newlink(unsigned short type, int index, unsigned flags, GSList *list; memset(&stats, 0, sizeof(stats)); - extract_link(msg, bytes, &address, &ifname, &mtu, &operstate, &stats); + if (!extract_link(msg, bytes, &address, &ifname, &mtu, &operstate, &stats)) + return; + +#if defined TIZEN_EXT_WIFI_MESH + /* Do not accept Wi-Fi Mesh interface */ + if (g_strrstr(ifname, "mesh") != NULL) { + DBG("Newlink event for Wi-Fi Mesh interface ignored"); + return; + } + + /* Do not accept Wi-Fi WLAN1 interface "dedicated for softAP */ + if (!g_strcmp0(ifname, "wlan1")) { + DBG("Newlink event for Wi-Fi WLAN1 interface ignored"); + return; + } +#endif + +#if defined TIZEN_EXT + /* Do not accept Wi-Fi P2P interface */ + if (g_strrstr(ifname, "p2p") != NULL) { + DBG("Newlink event for Wi-Fi P2P interface ignored"); + return; + } +#endif snprintf(ident, 13, "%02x%02x%02x%02x%02x%02x", address.ether_addr_octet[0], @@ -434,19 +501,38 @@ static void process_newlink(unsigned short type, int index, unsigned flags, address.ether_addr_octet[4], address.ether_addr_octet[5]); + if (flags & IFF_SLAVE) { + connman_info("%s {newlink} ignoring slave, index %d address %s", + ifname, index, str); + return; + } + +#ifdef TIZEN_EXT + if (TIZEN_TV_EXT && g_strcmp0(ident, "eeeeeeeeeeee") == 0) { + DBG("Newlink event with Dummy MAC. Ignored!"); + return; + } +#endif + switch (type) { case ARPHRD_ETHER: case ARPHRD_LOOPBACK: case ARPHDR_PHONET_PIPE: + case ARPHRD_PPP: case ARPHRD_NONE: +#if defined TIZEN_EXT +/* + * Description: ARPHDR_RMNET for QC modem using QMI + */ + case ARPHDR_RMNET: +#endif __connman_ipconfig_newlink(index, type, flags, str, mtu, &stats); break; } - if (memcmp(&address, &compare, ETH_ALEN) != 0) - connman_info("%s {newlink} index %d address %s mtu %u", - ifname, index, str, mtu); + connman_info("%s {newlink} index %d address %s mtu %u", + ifname, index, str, mtu); if (operstate != 0xff) connman_info("%s {newlink} index %d operstate %u <%s>", @@ -454,10 +540,9 @@ static void process_newlink(unsigned short type, int index, unsigned flags, operstate2str(operstate)); interface = g_hash_table_lookup(interface_list, GINT_TO_POINTER(index)); - if (interface == NULL) { + if (!interface) { interface = g_new0(struct interface_data, 1); interface->index = index; - interface->name = g_strdup(ifname); interface->ident = g_strdup(ident); g_hash_table_insert(interface_list, @@ -465,10 +550,29 @@ static void process_newlink(unsigned short type, int index, unsigned flags, if (type == ARPHRD_ETHER) read_uevent(interface); +#if defined TIZEN_EXT + if (type == ARPHRD_PPP || type == ARPHDR_RMNET) + read_uevent(interface); + + } else if (g_strcmp0(interface->ident, ident) != 0) { + /* If an original address is built-in physical device, + * it's hardly get an address at a initial creation + */ + __connman_technology_remove_interface(interface->service_type, + interface->index, interface->ident); + + g_free(interface->ident); + interface->ident = g_strdup(ident); __connman_technology_add_interface(interface->service_type, - interface->index, interface->name, interface->ident); - } + interface->index, interface->ident); + + interface = NULL; +#endif + } else if (type == ARPHRD_ETHER && interface->device_type == CONNMAN_DEVICE_TYPE_UNKNOWN) + read_uevent(interface); + else + interface = NULL; for (list = rtnl_list; list; list = list->next) { struct connman_rtnl *rtnl = list->data; @@ -477,14 +581,25 @@ static void process_newlink(unsigned short type, int index, unsigned flags, rtnl->newlink(type, index, flags, change); } - for (list = watch_list; list; list = list->next) { - struct watch_data *watch = list->data; + /* + * The interface needs to be added after the newlink call. + * The newlink will create the technology when needed and + * __connman_technology_add_interface() expects the + * technology to be there already. + */ + if (interface) + __connman_technology_add_interface(interface->service_type, + interface->index, interface->ident); - if (watch->index != index) - continue; + list = watch_list; + while (list) { + GSList *next = list->next; + struct watch_data *watch = list->data; - if (watch->newlink) + if (watch->index == index && watch->newlink) watch->newlink(flags, change, watch->user_data); + + list = next; } } @@ -497,7 +612,8 @@ static void process_dellink(unsigned short type, int index, unsigned flags, GSList *list; memset(&stats, 0, sizeof(stats)); - extract_link(msg, bytes, NULL, &ifname, NULL, &operstate, &stats); + if (!extract_link(msg, bytes, NULL, &ifname, NULL, &operstate, &stats)) + return; if (operstate != 0xff) connman_info("%s {dellink} index %d operstate %u <%s>", @@ -514,7 +630,16 @@ static void process_dellink(unsigned short type, int index, unsigned flags, switch (type) { case ARPHRD_ETHER: case ARPHRD_LOOPBACK: + case ARPHDR_PHONET_PIPE: + case ARPHRD_PPP: case ARPHRD_NONE: +#if defined TIZEN_EXT + /* + * Description: SLP requires ARPHRD_PPP for PPP type device + * ARPHDR_RMNET for QC modem using QMI + */ + case ARPHDR_RMNET: +#endif __connman_ipconfig_dellink(index, &stats); break; } @@ -534,19 +659,19 @@ static void extract_ipv4_addr(struct ifaddrmsg *msg, int bytes, attr = RTA_NEXT(attr, bytes)) { switch (attr->rta_type) { case IFA_ADDRESS: - if (address != NULL) + if (address) *address = *((struct in_addr *) RTA_DATA(attr)); break; case IFA_LOCAL: - if (local != NULL) + if (local) *local = *((struct in_addr *) RTA_DATA(attr)); break; case IFA_BROADCAST: - if (broadcast != NULL) + if (broadcast) *broadcast = *((struct in_addr *) RTA_DATA(attr)); break; case IFA_LABEL: - if (label != NULL) + if (label) *label = RTA_DATA(attr); break; } @@ -563,11 +688,11 @@ static void extract_ipv6_addr(struct ifaddrmsg *msg, int bytes, attr = RTA_NEXT(attr, bytes)) { switch (attr->rta_type) { case IFA_ADDRESS: - if (addr != NULL) + if (addr) *addr = *((struct in6_addr *) RTA_DATA(attr)); break; case IFA_LOCAL: - if (local != NULL) + if (local) *local = *((struct in6_addr *) RTA_DATA(attr)); break; } @@ -577,18 +702,17 @@ static void extract_ipv6_addr(struct ifaddrmsg *msg, int bytes, static void process_newaddr(unsigned char family, unsigned char prefixlen, int index, struct ifaddrmsg *msg, int bytes) { + struct in_addr ipv4_addr = { INADDR_ANY }; + struct in6_addr ipv6_address, ipv6_local; const char *label = NULL; void *src; char ip_string[INET6_ADDRSTRLEN]; if (family == AF_INET) { - struct in_addr ipv4_addr = { INADDR_ANY }; extract_ipv4_addr(msg, bytes, &label, &ipv4_addr, NULL, NULL); src = &ipv4_addr; } else if (family == AF_INET6) { - struct in6_addr ipv6_address, ipv6_local; - extract_ipv6_addr(msg, bytes, &ipv6_address, &ipv6_local); if (IN6_IS_ADDR_LINKLOCAL(&ipv6_address)) return; @@ -598,42 +722,37 @@ static void process_newaddr(unsigned char family, unsigned char prefixlen, return; } - if (inet_ntop(family, src, ip_string, INET6_ADDRSTRLEN) == NULL) + if (!inet_ntop(family, src, ip_string, INET6_ADDRSTRLEN)) return; - __connman_ipconfig_newaddr(index, family, label, - prefixlen, ip_string); - - if (family == AF_INET6) { - /* - * Re-create RDNSS configured servers if there are any - * for this interface. This is done because we might - * have now properly configured interface with proper - * autoconfigured address. - */ - char *interface = connman_inet_ifname(index); - - __connman_resolver_redo_servers(interface); - - g_free(interface); + if (__connman_ipconfig_newaddr(index, family, label, + prefixlen, ip_string) >= 0) { + if (family == AF_INET6) { + /* + * Re-create RDNSS configured servers if there + * are any for this interface. This is done + * because we might have now properly + * configured interface with proper + * autoconfigured address. + */ + __connman_resolver_redo_servers(index); + } } } static void process_deladdr(unsigned char family, unsigned char prefixlen, int index, struct ifaddrmsg *msg, int bytes) { + struct in_addr ipv4_addr = { INADDR_ANY }; + struct in6_addr ipv6_address, ipv6_local; const char *label = NULL; void *src; char ip_string[INET6_ADDRSTRLEN]; if (family == AF_INET) { - struct in_addr ipv4_addr = { INADDR_ANY }; - extract_ipv4_addr(msg, bytes, &label, &ipv4_addr, NULL, NULL); src = &ipv4_addr; } else if (family == AF_INET6) { - struct in6_addr ipv6_address, ipv6_local; - extract_ipv6_addr(msg, bytes, &ipv6_address, &ipv6_local); if (IN6_IS_ADDR_LINKLOCAL(&ipv6_address)) return; @@ -643,7 +762,7 @@ static void process_deladdr(unsigned char family, unsigned char prefixlen, return; } - if (inet_ntop(family, src, ip_string, INET6_ADDRSTRLEN) == NULL) + if (!inet_ntop(family, src, ip_string, INET6_ADDRSTRLEN)) return; __connman_ipconfig_deladdr(index, family, label, @@ -660,15 +779,15 @@ static void extract_ipv4_route(struct rtmsg *msg, int bytes, int *index, attr = RTA_NEXT(attr, bytes)) { switch (attr->rta_type) { case RTA_DST: - if (dst != NULL) + if (dst) *dst = *((struct in_addr *) RTA_DATA(attr)); break; case RTA_GATEWAY: - if (gateway != NULL) + if (gateway) *gateway = *((struct in_addr *) RTA_DATA(attr)); break; case RTA_OIF: - if (index != NULL) + if (index) *index = *((int *) RTA_DATA(attr)); break; } @@ -685,16 +804,16 @@ static void extract_ipv6_route(struct rtmsg *msg, int bytes, int *index, attr = RTA_NEXT(attr, bytes)) { switch (attr->rta_type) { case RTA_DST: - if (dst != NULL) + if (dst) *dst = *((struct in6_addr *) RTA_DATA(attr)); break; case RTA_GATEWAY: - if (gateway != NULL) + if (gateway) *gateway = *((struct in6_addr *) RTA_DATA(attr)); break; case RTA_OIF: - if (index != NULL) + if (index) *index = *((int *) RTA_DATA(attr)); break; } @@ -946,6 +1065,9 @@ static void rtnl_newlink(struct nlmsghdr *hdr) rtnl_link(hdr); + if (hdr->nlmsg_type == IFLA_WIRELESS) + connman_warn_once("Obsolete WEXT WiFi driver detected"); + process_newlink(msg->ifi_type, msg->ifi_index, msg->ifi_flags, msg->ifi_change, msg, IFA_PAYLOAD(hdr)); } @@ -1073,20 +1195,22 @@ static void rtnl_route(struct nlmsghdr *hdr) } } -static connman_bool_t is_route_rtmsg(struct rtmsg *msg) +static bool is_route_rtmsg(struct rtmsg *msg) { + if (msg->rtm_flags & RTM_F_CLONED) + return false; if (msg->rtm_table != RT_TABLE_MAIN) - return FALSE; + return false; if (msg->rtm_protocol != RTPROT_BOOT && msg->rtm_protocol != RTPROT_KERNEL) - return FALSE; + return false; if (msg->rtm_type != RTN_UNICAST) - return FALSE; + return false; - return TRUE; + return true; } static void rtnl_newroute(struct nlmsghdr *hdr) @@ -1195,7 +1319,7 @@ static void rtnl_newnduseropt(struct nlmsghdr *hdr) struct in6_addr *servers = NULL; int i, nr_servers = 0; int msglen = msg->nduseropt_opts_len; - char *interface; + int index; DBG("family %d index %d len %d type %d code %d", msg->nduseropt_family, msg->nduseropt_ifindex, @@ -1207,10 +1331,41 @@ static void rtnl_newnduseropt(struct nlmsghdr *hdr) msg->nduseropt_icmp_code != 0) return; - interface = connman_inet_ifname(msg->nduseropt_ifindex); - if (!interface) + index = msg->nduseropt_ifindex; + if (index < 0) return; +#if defined TIZEN_EXT + struct connman_service *service; + enum connman_service_state state; + enum connman_dnsconfig_method ipv6_dns_method; + + service = __connman_service_lookup_from_index(index); + if (!service) { + DBG("Invalid service"); + return; + } + + DBG("service: %p index: %d\n", service, index); + + if (connman_setting_get_bool("SingleConnectedTechnology") == TRUE) { + state = __connman_service_ipconfig_get_state(service, CONNMAN_IPCONFIG_TYPE_IPV6); + if (state != CONNMAN_SERVICE_STATE_ASSOCIATION && + state != CONNMAN_SERVICE_STATE_CONFIGURATION && + state != CONNMAN_SERVICE_STATE_READY && + state != CONNMAN_SERVICE_STATE_ONLINE) { + DBG("Service state[%d] is not connecting/connected", state); + return; + } + } + + ipv6_dns_method = connman_service_get_ipv6_dns_method(service); + if (ipv6_dns_method != CONNMAN_DNSCONFIG_METHOD_DHCP) { + DBG("IPv6 DNS method is not Auto ignore RA!!! [DNS method: %d]", ipv6_dns_method); + return; + } +#endif + for (opt = (void *)&msg[1]; msglen > 0; msglen -= opt->nd_opt_len * 8, @@ -1221,7 +1376,12 @@ static void rtnl_newnduseropt(struct nlmsghdr *hdr) if (opt->nd_opt_type == 25) { /* ND_OPT_RDNSS */ char buf[40]; +#if defined TIZEN_EXT + struct connman_service *service; + service = __connman_service_lookup_from_index(index); + DBG("service: %p\n",service); +#endif servers = rtnl_nd_opt_rdnss(opt, &lifetime, &nr_servers); for (i = 0; i < nr_servers; i++) { @@ -1229,7 +1389,15 @@ static void rtnl_newnduseropt(struct nlmsghdr *hdr) sizeof(buf))) continue; - connman_resolver_append_lifetime(interface, +#if defined TIZEN_EXT + __connman_service_nameserver_remove(service, + buf, false, + CONNMAN_IPCONFIG_TYPE_IPV6); + __connman_service_nameserver_append(service, + buf, false, + CONNMAN_IPCONFIG_TYPE_IPV6); +#endif + connman_resolver_append_lifetime(index, NULL, buf, lifetime); } @@ -1237,14 +1405,13 @@ static void rtnl_newnduseropt(struct nlmsghdr *hdr) g_free(domains); domains = rtnl_nd_opt_dnssl(opt, &lifetime); - for (i = 0; domains != NULL && domains[i] != NULL; i++) - connman_resolver_append_lifetime(interface, + for (i = 0; domains && domains[i]; i++) + connman_resolver_append_lifetime(index, domains[i], NULL, lifetime); } } g_free(domains); - g_free(interface); } static const char *type2string(uint16_t type) @@ -1264,6 +1431,8 @@ static const char *type2string(uint16_t type) return "NEWLINK"; case RTM_DELLINK: return "DELLINK"; + case RTM_GETADDR: + return "GETADDR"; case RTM_NEWADDR: return "NEWADDR"; case RTM_DELADDR: @@ -1282,6 +1451,7 @@ static const char *type2string(uint16_t type) } static GIOChannel *channel = NULL; +static guint channel_watch = 0; struct rtnl_request { struct nlmsghdr hdr; @@ -1342,13 +1512,13 @@ static int process_response(guint32 seq) DBG("seq %d", seq); req = find_request(seq); - if (req != NULL) { + if (req) { request_list = g_slist_remove(request_list, req); g_free(req); } req = g_slist_nth_data(request_list, 0); - if (req == NULL) + if (!req) return 0; return send_request(req); @@ -1356,8 +1526,6 @@ static int process_response(guint32 seq) 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; @@ -1365,7 +1533,7 @@ static void rtnl_message(void *buf, size_t len) if (!NLMSG_OK(hdr, len)) break; - DBG("%s len %d type %d flags 0x%04x seq %d pid %d", + DBG("%s len %u type %u flags 0x%04x seq %u pid %u", type2string(hdr->nlmsg_type), hdr->nlmsg_len, hdr->nlmsg_type, hdr->nlmsg_flags, hdr->nlmsg_seq, @@ -1411,8 +1579,7 @@ static void rtnl_message(void *buf, size_t len) } } -static gboolean netlink_event(GIOChannel *chan, - GIOCondition cond, gpointer data) +static gboolean netlink_event(GIOChannel *chan, GIOCondition cond, gpointer data) { unsigned char buf[4096]; struct sockaddr_nl nladdr; @@ -1420,8 +1587,15 @@ static gboolean netlink_event(GIOChannel *chan, ssize_t status; int fd; +#if defined TIZEN_EXT + if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) { + __connman_rtnl_init(GIO_SOCKET_RETRY_COUNT); + return FALSE; + } +#else /* TIZEN_EXT */ if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) return FALSE; +#endif /* TIZEN_EXT */ memset(buf, 0, sizeof(buf)); memset(&nladdr, 0, sizeof(nladdr)); @@ -1434,11 +1608,21 @@ static gboolean netlink_event(GIOChannel *chan, if (errno == EINTR || errno == EAGAIN) return TRUE; +#if defined TIZEN_EXT + __connman_rtnl_init(GIO_SOCKET_RETRY_COUNT); +#endif /* TIZEN_EXT */ return FALSE; } +#if defined TIZEN_EXT + if (status == 0) { + __connman_rtnl_init(GIO_SOCKET_RETRY_COUNT); + return FALSE; + } +#else /* TIZEN_EXT */ if (status == 0) return FALSE; +#endif /* TIZEN_EXT */ if (nladdr.nl_pid != 0) { /* not sent by kernel, ignore */ DBG("Received msg from %u, ignoring it", nladdr.nl_pid); @@ -1457,7 +1641,7 @@ static int send_getlink(void) DBG(""); req = g_try_malloc0(RTNL_REQUEST_SIZE); - if (req == NULL) + if (!req) return -ENOMEM; req->hdr.nlmsg_len = RTNL_REQUEST_SIZE; @@ -1477,7 +1661,7 @@ static int send_getaddr(void) DBG(""); req = g_try_malloc0(RTNL_REQUEST_SIZE); - if (req == NULL) + if (!req) return -ENOMEM; req->hdr.nlmsg_len = RTNL_REQUEST_SIZE; @@ -1497,7 +1681,7 @@ static int send_getroute(void) DBG(""); req = g_try_malloc0(RTNL_REQUEST_SIZE); - if (req == NULL) + if (!req) return -ENOMEM; req->hdr.nlmsg_len = RTNL_REQUEST_SIZE; @@ -1568,7 +1752,7 @@ unsigned int __connman_rtnl_update_interval_remove(unsigned int interval) update_list = g_slist_remove(update_list, GINT_TO_POINTER(interval)); - if (update_list != NULL) + if (update_list) min = GPOINTER_TO_UINT(g_slist_nth_data(update_list, 0)); if (min > update_interval) @@ -1582,19 +1766,34 @@ int __connman_rtnl_request_update(void) return send_getlink(); } +#if defined TIZEN_EXT +int __connman_rtnl_init(int retry_count) +#else /* TIZEN_EXT */ int __connman_rtnl_init(void) +#endif /* TIZEN_EXT */ { struct sockaddr_nl addr; int sk; +#if defined TIZEN_EXT + if (retry_count < 0) + return -1; + + DBG("retry_count %d", retry_count); +#else /* TIZEN_EXT */ DBG(""); +#endif /* TIZEN_EXT */ interface_list = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free_interface); sk = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE); if (sk < 0) +#if defined TIZEN_EXT + return __connman_rtnl_init(retry_count - 1); +#else /* TIZEN_EXT */ return -1; +#endif /* TIZEN_EXT */ memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; @@ -1604,7 +1803,11 @@ int __connman_rtnl_init(void) if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { close(sk); +#if defined TIZEN_EXT + return __connman_rtnl_init(retry_count - 1); +#else /* TIZEN_EXT */ return -1; +#endif /* TIZEN_EXT */ } channel = g_io_channel_unix_new(sk); @@ -1613,8 +1816,9 @@ int __connman_rtnl_init(void) g_io_channel_set_encoding(channel, NULL, NULL); g_io_channel_set_buffered(channel, FALSE); - g_io_add_watch(channel, G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR, - netlink_event, NULL); + channel_watch = g_io_add_watch(channel, + G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR, + netlink_event, NULL); return 0; } @@ -1664,6 +1868,11 @@ void __connman_rtnl_cleanup(void) g_slist_free(request_list); request_list = NULL; + if (channel_watch) { + g_source_remove(channel_watch); + channel_watch = 0; + } + g_io_channel_shutdown(channel, TRUE, NULL); g_io_channel_unref(channel);