X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Frtnl.c;h=4f5021958c52b19557b59401c212b799d1578e1d;hb=c329f0f22773df936ef31c539d8fd32c3a973659;hp=12939f41e992f7e36a70fbcb35f31607bfe7240c;hpb=1d2fc4e1c652fa4b2385b2893d844fc4648c6762;p=framework%2Fconnectivity%2Fconnman.git diff --git a/src/rtnl.c b/src/rtnl.c index 12939f4..4f50219 100644 --- a/src/rtnl.c +++ b/src/rtnl.c @@ -2,7 +2,7 @@ * * 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 @@ -1189,22 +1189,22 @@ static const char **rtnl_nd_opt_dnssl(struct nd_opt_hdr *opt, guint32 *lifetime) 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); @@ -1212,40 +1212,37 @@ static void rtnl_newnduseropt(struct nlmsghdr *hdr) 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); } @@ -1368,10 +1365,11 @@ 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", + 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: @@ -1417,27 +1415,37 @@ static gboolean netlink_event(GIOChannel *chan, 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; }