#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 {
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);
if (gateway != NULL)
rtnl->newgateway(index, gateway);
if (type == ARPHRD_ETHER)
read_uevent(interface);
+
+ __connman_technology_add_interface(interface->service_type,
+ interface->index, interface->name, interface->ident);
}
for (list = rtnl_list; list; list = list->next) {
rtnl->newlink(type, index, flags, change);
}
- __connman_technology_add_interface(interface->service_type,
- interface->index, interface->name, interface->ident);
-
for (list = watch_list; list; list = list->next) {
struct watch_data *watch = list->data;
void *src;
char ip_string[INET6_ADDRSTRLEN];
- if (family != AF_INET && family != AF_INET6)
- return;
-
if (family == AF_INET) {
struct in_addr ipv4_addr = { INADDR_ANY };
return;
src = &ipv6_address;
+ } else {
+ return;
}
if (inet_ntop(family, src, ip_string, INET6_ADDRSTRLEN) == NULL)
void *src;
char ip_string[INET6_ADDRSTRLEN];
- if (family != AF_INET && family != AF_INET6)
- return;
-
if (family == AF_INET) {
struct in_addr ipv4_addr = { INADDR_ANY };
return;
src = &ipv6_address;
+ } else {
+ return;
}
if (inet_ntop(family, src, ip_string, INET6_ADDRSTRLEN) == NULL)
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);
- if (dst.s_addr != INADDR_ANY)
+ inet_ntop(family, &dst, dststr, sizeof(dststr));
+ inet_ntop(family, &gateway, gatewaystr, sizeof(gatewaystr));
+
+ __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)
+ 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);
- if (dst.s_addr != INADDR_ANY)
+ 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) {
msg, RTM_PAYLOAD(hdr));
}
-static void rtnl_nd_opt_rdnss(char *interface, struct nd_opt_hdr *opt)
+static void *rtnl_nd_opt_rdnss(struct nd_opt_hdr *opt, guint32 *lifetime,
+ int *nr_servers)
{
guint32 *optint = (void *)opt;
- guint32 lifetime;
- char buf[80];
- int i;
if (opt->nd_opt_len < 3)
- return;
+ return NULL;
- lifetime = ntohl(optint[1]);
- if (!lifetime)
- return;
+ if (*lifetime > ntohl(optint[1]))
+ *lifetime = ntohl(optint[1]);
+
+ /* nd_opt_len is in units of 8 bytes. The header is 1 unit (8 bytes)
+ and each address is another 2 units (16 bytes).
+ So the number of addresses (given rounding) is nd_opt_len/2 */
+ *nr_servers = opt->nd_opt_len / 2;
- optint += 2;
- for (i = 0; i < opt->nd_opt_len / 2; i++, optint += 4) {
- if (inet_ntop(AF_INET6, optint, buf, sizeof(buf)))
- connman_resolver_append_lifetime(interface, NULL,
- buf, lifetime);
+ /* And they start 8 bytes into the packet, or two guint32s in. */
+ return optint + 2;
+}
+
+static const char **rtnl_nd_opt_dnssl(struct nd_opt_hdr *opt, guint32 *lifetime)
+{
+ const char **domains = NULL;
+ guint32 *optint = (void *)opt;
+ unsigned char *optc = (void *)&optint[2];
+ int data_len = (opt->nd_opt_len * 8) - 8;
+ int nr_domains = 0;
+ int i, tmp;
+
+ if (*lifetime > ntohl(optint[1]))
+ *lifetime = ntohl(optint[1]);
+
+ /* Turn it into normal strings by converting the length bytes into '.',
+ and count how many search domains there are while we're at it. */
+ i = 0;
+ while (i < data_len) {
+ if (optc[i] > 0x3f) {
+ DBG("DNSSL contains compressed elements in violation of RFC6106");
+ return NULL;
+ }
+
+ if (optc[i] == 0) {
+ nr_domains++;
+ i++;
+ /* Check for double zero */
+ if (i < data_len && optc[i] == 0)
+ break;
+ continue;
+ }
+
+ tmp = i;
+ i += optc[i] + 1;
+
+ if (i >= data_len) {
+ DBG("DNSSL data overflows option length");
+ return NULL;
+ }
+
+ optc[tmp] = '.';
}
+
+ domains = g_try_new0(const char *, nr_domains + 1);
+ if (!domains)
+ return NULL;
+
+ /* Now point to the normal strings, missing out the leading '.' that
+ each of them will have now. */
+ for (i = 0; i < nr_domains; i++) {
+ domains[i] = (char *)optc + 1;
+ optc += strlen((char *)optc) + 1;
+ }
+
+ return domains;
}
static void rtnl_newnduseropt(struct nlmsghdr *hdr)
{
struct nduseroptmsg *msg = (struct nduseroptmsg *) NLMSG_DATA(hdr);
struct nd_opt_hdr *opt = (void *)&msg[1];
+ guint32 lifetime = -1;
+ const char **domains = NULL;
+ struct in6_addr *servers = NULL;
+ int nr_servers = 0;
int msglen = msg->nduseropt_opts_len;
char *interface;
opt->nd_opt_type, opt->nd_opt_len);
if (opt->nd_opt_type == 25)
- rtnl_nd_opt_rdnss(interface, opt);
+ servers = rtnl_nd_opt_rdnss(opt, &lifetime,
+ &nr_servers);
+ else if (opt->nd_opt_type == 31)
+ domains = rtnl_nd_opt_dnssl(opt, &lifetime);
}
+
+ 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;
+
+ if (domains == NULL || domains[0] == NULL) {
+ connman_resolver_append_lifetime(interface,
+ NULL, buf, lifetime);
+ continue;
+ }
+
+ for (j = 0; domains[j]; j++)
+ connman_resolver_append_lifetime(interface,
+ domains[j],
+ buf, lifetime);
+ }
+ }
+ g_free(domains);
g_free(interface);
}
{
unsigned char buf[4096];
gsize len;
- GIOError err;
+ GIOStatus status;
if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
return FALSE;
memset(buf, 0, sizeof(buf));
- err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
- if (err) {
- if (err == G_IO_ERROR_AGAIN)
- return TRUE;
+ status = g_io_channel_read_chars(chan, (gchar *) buf,
+ sizeof(buf), &len, NULL);
+
+ switch (status) {
+ case G_IO_STATUS_NORMAL:
+ break;
+ case G_IO_STATUS_AGAIN:
+ return TRUE;
+ default:
return FALSE;
}
channel = g_io_channel_unix_new(sk);
g_io_channel_set_close_on_unref(channel, TRUE);
+ 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);