*
* Connection Manager
*
- * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
+ * Copyright (C) 2007-2012 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
#include <config.h>
#endif
+#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define ARPHDR_PHONET_PIPE (821)
#endif
-#define print(arg...) do { } while (0)
+#define print(arg...) do { if (0) connman_info(arg); } while (0)
//#define print(arg...) connman_info(arg)
struct watch_data {
if (name == NULL)
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;
-
- /* virtual interface from Virtual Machine Manager */
- if (g_str_has_prefix(name, "virbr") == TRUE)
+ if (__connman_device_isfiltered(name) == TRUE)
return TRUE;
return FALSE;
struct iwreq wrq;
int fd, err;
- fd = socket(PF_INET, SOCK_DGRAM, 0);
+ fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (fd < 0)
return FALSE;
DBG("id %d", watch->id);
if (callback) {
- unsigned int flags = __connman_ipconfig_get_flags(index);
+ unsigned int flags = __connman_ipconfig_get_flags_from_index(index);
if (flags > 0)
callback(flags, 0, user_data);
struct connman_rtnl *rtnl = user_data;
if (rtnl->newlink) {
- unsigned short type = __connman_ipconfig_get_type(index);
- unsigned int flags = __connman_ipconfig_get_flags(index);
+ unsigned short type = __connman_ipconfig_get_type_from_index(index);
+ unsigned int flags = __connman_ipconfig_get_flags_from_index(index);
rtnl->newlink(type, index, flags, 0);
}
if (rtnl->newgateway) {
- const char *gateway = __connman_ipconfig_get_gateway(index);
+ const char *gateway =
+ __connman_ipconfig_get_gateway_from_index(index,
+ CONNMAN_IPCONFIG_TYPE_ALL);
if (gateway != NULL)
rtnl->newgateway(index, gateway);
__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);
+ }
}
static void process_deladdr(unsigned char family, unsigned char prefixlen,
prefixlen, ip_string);
}
-static void extract_route(struct rtmsg *msg, int bytes, int *index,
+static void extract_ipv4_route(struct rtmsg *msg, int bytes, int *index,
struct in_addr *dst,
struct in_addr *gateway)
{
}
}
+static void extract_ipv6_route(struct rtmsg *msg, int bytes, int *index,
+ struct in6_addr *dst,
+ struct in6_addr *gateway)
+{
+ struct rtattr *attr;
+
+ for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
+ attr = RTA_NEXT(attr, bytes)) {
+ switch (attr->rta_type) {
+ case RTA_DST:
+ if (dst != NULL)
+ *dst = *((struct in6_addr *) RTA_DATA(attr));
+ break;
+ case RTA_GATEWAY:
+ if (gateway != NULL)
+ *gateway =
+ *((struct in6_addr *) RTA_DATA(attr));
+ break;
+ case RTA_OIF:
+ if (index != NULL)
+ *index = *((int *) RTA_DATA(attr));
+ break;
+ }
+ }
+}
+
static void process_newroute(unsigned char family, unsigned char scope,
struct rtmsg *msg, int bytes)
{
GSList *list;
- struct in_addr dst = { INADDR_ANY }, gateway = { INADDR_ANY };
- char dststr[16], gatewaystr[16];
+ char dststr[INET6_ADDRSTRLEN], gatewaystr[INET6_ADDRSTRLEN];
int index = -1;
- if (family != AF_INET)
- return;
+ if (family == AF_INET) {
+ struct in_addr dst = { INADDR_ANY }, gateway = { INADDR_ANY };
- extract_route(msg, bytes, &index, &dst, &gateway);
+ extract_ipv4_route(msg, bytes, &index, &dst, &gateway);
- inet_ntop(family, &dst, dststr, sizeof(dststr));
- inet_ntop(family, &gateway, gatewaystr, sizeof(gatewaystr));
+ inet_ntop(family, &dst, dststr, sizeof(dststr));
+ inet_ntop(family, &gateway, gatewaystr, sizeof(gatewaystr));
- __connman_ipconfig_newroute(index, family, scope, dststr, gatewaystr);
+ __connman_ipconfig_newroute(index, family, scope, dststr,
+ gatewaystr);
- /* skip host specific routes */
- if (scope != RT_SCOPE_UNIVERSE &&
+ /* skip host specific routes */
+ if (scope != RT_SCOPE_UNIVERSE &&
!(scope == RT_SCOPE_LINK && dst.s_addr == INADDR_ANY))
- return;
+ return;
+
+ if (dst.s_addr != INADDR_ANY)
+ return;
+
+ } else if (family == AF_INET6) {
+ struct in6_addr dst = IN6ADDR_ANY_INIT,
+ gateway = IN6ADDR_ANY_INIT;
+
+ extract_ipv6_route(msg, bytes, &index, &dst, &gateway);
+
+ inet_ntop(family, &dst, dststr, sizeof(dststr));
+ inet_ntop(family, &gateway, gatewaystr, sizeof(gatewaystr));
- if (dst.s_addr != INADDR_ANY)
+ __connman_ipconfig_newroute(index, family, scope, dststr,
+ gatewaystr);
+
+ /* skip host specific routes */
+ if (scope != RT_SCOPE_UNIVERSE &&
+ !(scope == RT_SCOPE_LINK &&
+ IN6_IS_ADDR_UNSPECIFIED(&dst)))
+ return;
+
+ if (!IN6_IS_ADDR_UNSPECIFIED(&dst))
+ return;
+ } else
return;
for (list = rtnl_list; list; list = list->next) {
struct rtmsg *msg, int bytes)
{
GSList *list;
- struct in_addr dst = { INADDR_ANY }, gateway = { INADDR_ANY };
- char dststr[16], gatewaystr[16];
+ char dststr[INET6_ADDRSTRLEN], gatewaystr[INET6_ADDRSTRLEN];
int index = -1;
- if (family != AF_INET)
- return;
+ if (family == AF_INET) {
+ struct in_addr dst = { INADDR_ANY }, gateway = { INADDR_ANY };
- extract_route(msg, bytes, &index, &dst, &gateway);
+ extract_ipv4_route(msg, bytes, &index, &dst, &gateway);
- inet_ntop(family, &dst, dststr, sizeof(dststr));
- inet_ntop(family, &gateway, gatewaystr, sizeof(gatewaystr));
+ inet_ntop(family, &dst, dststr, sizeof(dststr));
+ inet_ntop(family, &gateway, gatewaystr, sizeof(gatewaystr));
- __connman_ipconfig_delroute(index, family, scope, dststr, gatewaystr);
+ __connman_ipconfig_delroute(index, family, scope, dststr,
+ gatewaystr);
- /* skip host specific routes */
- if (scope != RT_SCOPE_UNIVERSE &&
+ /* skip host specific routes */
+ if (scope != RT_SCOPE_UNIVERSE &&
!(scope == RT_SCOPE_LINK && dst.s_addr == INADDR_ANY))
- return;
+ return;
- if (dst.s_addr != INADDR_ANY)
+ if (dst.s_addr != INADDR_ANY)
+ return;
+
+ } else if (family == AF_INET6) {
+ struct in6_addr dst = IN6ADDR_ANY_INIT,
+ gateway = IN6ADDR_ANY_INIT;
+
+ extract_ipv6_route(msg, bytes, &index, &dst, &gateway);
+
+ inet_ntop(family, &dst, dststr, sizeof(dststr));
+ inet_ntop(family, &gateway, gatewaystr, sizeof(gatewaystr));
+
+ __connman_ipconfig_delroute(index, family, scope, dststr,
+ gatewaystr);
+
+ /* skip host specific routes */
+ if (scope != RT_SCOPE_UNIVERSE &&
+ !(scope == RT_SCOPE_LINK &&
+ IN6_IS_ADDR_UNSPECIFIED(&dst)))
+ return;
+
+ if (!IN6_IS_ADDR_UNSPECIFIED(&dst))
+ return;
+ } else
return;
for (list = rtnl_list; list; list = list->next) {
static void rtnl_newnduseropt(struct nlmsghdr *hdr)
{
struct nduseroptmsg *msg = (struct nduseroptmsg *) NLMSG_DATA(hdr);
- struct nd_opt_hdr *opt = (void *)&msg[1];
+ struct nd_opt_hdr *opt;
guint32 lifetime = -1;
const char **domains = NULL;
struct in6_addr *servers = NULL;
- int nr_servers = 0;
+ int i, nr_servers = 0;
int msglen = msg->nduseropt_opts_len;
char *interface;
- DBG("family %02x index %x len %04x type %02x code %02x",
- msg->nduseropt_family, msg->nduseropt_ifindex,
- msg->nduseropt_opts_len, msg->nduseropt_icmp_type,
- msg->nduseropt_icmp_code);
+ DBG("family %d index %d len %d type %d code %d",
+ msg->nduseropt_family, msg->nduseropt_ifindex,
+ msg->nduseropt_opts_len, msg->nduseropt_icmp_type,
+ msg->nduseropt_icmp_code);
if (msg->nduseropt_family != AF_INET6 ||
- msg->nduseropt_icmp_type != ND_ROUTER_ADVERT ||
- msg->nduseropt_icmp_code != 0)
+ msg->nduseropt_icmp_type != ND_ROUTER_ADVERT ||
+ msg->nduseropt_icmp_code != 0)
return;
interface = connman_inet_ifname(msg->nduseropt_ifindex);
return;
for (opt = (void *)&msg[1];
- msglen >= 2 && msglen >= opt->nd_opt_len && opt->nd_opt_len;
- msglen -= opt->nd_opt_len,
- opt = ((void *)opt) + opt->nd_opt_len*8) {
+ msglen > 0;
+ msglen -= opt->nd_opt_len * 8,
+ opt = ((void *)opt) + opt->nd_opt_len*8) {
- DBG("nd opt type %d len %d\n",
- opt->nd_opt_type, opt->nd_opt_len);
+ DBG("remaining %d nd opt type %d len %d\n",
+ msglen, opt->nd_opt_type, opt->nd_opt_len);
- if (opt->nd_opt_type == 25)
- servers = rtnl_nd_opt_rdnss(opt, &lifetime,
- &nr_servers);
- else if (opt->nd_opt_type == 31)
- domains = rtnl_nd_opt_dnssl(opt, &lifetime);
- }
+ if (opt->nd_opt_type == 25) { /* ND_OPT_RDNSS */
+ char buf[40];
- if (nr_servers) {
- int i, j;
- char buf[40];
-
- for (i = 0; i < nr_servers; i++) {
- if (!inet_ntop(AF_INET6, servers + i, buf, sizeof(buf)))
- continue;
+ servers = rtnl_nd_opt_rdnss(opt, &lifetime,
+ &nr_servers);
+ for (i = 0; i < nr_servers; i++) {
+ if (!inet_ntop(AF_INET6, servers + i, buf,
+ sizeof(buf)))
+ continue;
- if (domains == NULL || domains[0] == NULL) {
connman_resolver_append_lifetime(interface,
NULL, buf, lifetime);
- continue;
}
- for (j = 0; domains[j]; j++)
+ } else if (opt->nd_opt_type == 31) { /* ND_OPT_DNSSL */
+ g_free(domains);
+
+ domains = rtnl_nd_opt_dnssl(opt, &lifetime);
+ for (i = 0; domains != NULL && domains[i] != NULL; i++)
connman_resolver_append_lifetime(interface,
- domains[j],
- buf, lifetime);
+ domains[i], NULL, lifetime);
}
}
+
g_free(domains);
g_free(interface);
}
return "NEWLINK";
case RTM_DELLINK:
return "DELLINK";
+ case RTM_GETADDR:
+ return "GETADDR";
case RTM_NEWADDR:
return "NEWADDR";
case RTM_DELADDR:
if (!NLMSG_OK(hdr, len))
break;
- DBG("%s len %d type %d flags 0x%04x seq %d",
+ DBG("%s len %d type %d flags 0x%04x seq %d pid %d",
type2string(hdr->nlmsg_type),
hdr->nlmsg_len, hdr->nlmsg_type,
- hdr->nlmsg_flags, hdr->nlmsg_seq);
+ hdr->nlmsg_flags, hdr->nlmsg_seq,
+ hdr->nlmsg_pid);
switch (hdr->nlmsg_type) {
case NLMSG_NOOP:
GIOCondition cond, gpointer data)
{
unsigned char buf[4096];
- gsize len;
- GIOStatus status;
+ struct sockaddr_nl nladdr;
+ socklen_t addr_len = sizeof(nladdr);
+ ssize_t status;
+ int fd;
if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
return FALSE;
memset(buf, 0, sizeof(buf));
+ memset(&nladdr, 0, sizeof(nladdr));
- status = g_io_channel_read_chars(chan, (gchar *) buf,
- sizeof(buf), &len, NULL);
+ fd = g_io_channel_unix_get_fd(chan);
+
+ status = recvfrom(fd, buf, sizeof(buf), 0,
+ (struct sockaddr *) &nladdr, &addr_len);
+ if (status < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ return TRUE;
- switch (status) {
- case G_IO_STATUS_NORMAL:
- break;
- case G_IO_STATUS_AGAIN:
- return TRUE;
- default:
return FALSE;
}
- rtnl_message(buf, len);
+ if (status == 0)
+ return FALSE;
+
+ if (nladdr.nl_pid != 0) { /* not sent by kernel, ignore */
+ DBG("Received msg from %u, ignoring it", nladdr.nl_pid);
+ return TRUE;
+ }
+
+ rtnl_message(buf, status);
return TRUE;
}
interface_list = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, free_interface);
- sk = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ sk = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE);
if (sk < 0)
return -1;