static NMIP6Device * process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg) { NMIP6Device *device; struct nduseroptmsg *ndmsg; struct nd_opt_hdr *opt; guint opts_len; gboolean changed = FALSE; nm_log_dbg (LOGD_IP6, "processing netlink nduseropt message"); ndmsg = (struct nduseroptmsg *) NLMSG_DATA (nlmsg_hdr (msg)); if (!nlmsg_valid_hdr (nlmsg_hdr (msg), sizeof (*ndmsg)) || nlmsg_datalen (nlmsg_hdr (msg)) < (ndmsg->nduseropt_opts_len + sizeof (*ndmsg))) { nm_log_dbg (LOGD_IP6, "ignoring invalid nduseropt message"); return NULL; } if (ndmsg->nduseropt_family != AF_INET6 || ndmsg->nduseropt_icmp_type != ND_ROUTER_ADVERT || ndmsg->nduseropt_icmp_code != 0) { nm_log_dbg (LOGD_IP6, "ignoring non-Router Advertisement message"); return NULL; } device = nm_ip6_manager_get_device (manager, ndmsg->nduseropt_ifindex); if (!device) { nm_log_dbg (LOGD_IP6, "ignoring message for unknown device"); return NULL; } opt = (struct nd_opt_hdr *) (ndmsg + 1); opts_len = ndmsg->nduseropt_opts_len; while (opts_len >= sizeof (struct nd_opt_hdr)) { size_t nd_opt_len = opt->nd_opt_len; if (nd_opt_len == 0 || opts_len < (nd_opt_len << 3)) break; switch (opt->nd_opt_type) { case ND_OPT_RDNSS: changed = process_nduseropt_rdnss (device, opt); break; case ND_OPT_DNSSL: changed = process_nduseropt_dnssl (device, opt); break; } opts_len -= opt->nd_opt_len << 3; opt = (struct nd_opt_hdr *) ((uint8_t *) opt + (opt->nd_opt_len << 3)); } if (changed) return device; else return NULL; }
static NMIP6Device * process_prefix (NMIP6Manager *manager, struct nl_msg *msg) { struct prefixmsg *pmsg; NMIP6Device *device; /* We don't care about the prefix itself, but if we receive a * router advertisement telling us to use DHCP, we might not * get any RTM_NEWADDRs or RTM_NEWROUTEs, so this is our only * way to notice immediately that an RA was received. */ nm_log_dbg (LOGD_IP6, "processing netlink new prefix message"); if (!nlmsg_valid_hdr (nlmsg_hdr (msg), sizeof(*pmsg))) { nm_log_dbg (LOGD_IP6, "ignoring invalid prefix message"); return NULL; } pmsg = (struct prefixmsg *) NLMSG_DATA (nlmsg_hdr (msg)); device = nm_ip6_manager_get_device (manager, pmsg->prefix_ifindex); if (!device || device->addrconf_complete) { nm_log_dbg (LOGD_IP6, "(%s): ignoring unknown or completed device", device ? device->iface : "(none)"); return NULL; } return device; }
static NMIP6Device * process_address_change (NMIP6Manager *manager, struct nl_msg *msg) { NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); NMIP6Device *device; struct nlmsghdr *hdr; struct rtnl_addr *rtnladdr; int old_size; hdr = nlmsg_hdr (msg); rtnladdr = NULL; nl_msg_parse (msg, ref_object, &rtnladdr); if (!rtnladdr) { nm_log_dbg (LOGD_IP6, "error processing netlink new/del address message"); return NULL; } device = nm_ip6_manager_get_device (manager, rtnl_addr_get_ifindex (rtnladdr)); old_size = nl_cache_nitems (priv->addr_cache); nl_cache_include (priv->addr_cache, (struct nl_object *)rtnladdr, NULL, NULL); /* The kernel will re-notify us of automatically-added addresses * every time it gets another router advertisement. We only want * to notify higher levels if we actually changed something. */ nm_log_dbg (LOGD_IP6, "(%s): address cache size: %d -> %d:", device_get_iface (device), old_size, nl_cache_nitems (priv->addr_cache)); dump_address_change (device, hdr, rtnladdr); rtnl_addr_put (rtnladdr); if (nl_cache_nitems (priv->addr_cache) == old_size) return NULL; return device; }
static NMIP6Device * process_newlink (NMIP6Manager *manager, struct nl_msg *msg) { struct nlmsghdr *hdr = nlmsg_hdr (msg); struct ifinfomsg *ifi; NMIP6Device *device; struct nlattr *tb[IFLA_MAX + 1]; struct nlattr *pi[IFLA_INET6_MAX + 1]; int err; /* FIXME: we have to do this manually for now since libnl doesn't yet * support the IFLA_PROTINFO attribute of NEWLINK messages. When it does, * we can get rid of this function and just grab IFLA_PROTINFO from * nm_ip6_device_sync_from_netlink(), then get the IFLA_INET6_FLAGS out of * the PROTINFO. */ err = nlmsg_parse (hdr, sizeof (*ifi), tb, IFLA_MAX, link_policy); if (err < 0) { nm_log_dbg (LOGD_IP6, "ignoring invalid newlink netlink message " "while parsing PROTINFO attribute"); return NULL; } ifi = nlmsg_data (hdr); if (ifi->ifi_family != AF_INET6) { nm_log_dbg (LOGD_IP6, "ignoring netlink message family %d", ifi->ifi_family); return NULL; } device = nm_ip6_manager_get_device (manager, ifi->ifi_index); if (!device || device->addrconf_complete) { nm_log_dbg (LOGD_IP6, "(%s): ignoring unknown or completed device", device ? device->iface : "(none)"); return NULL; } if (!tb[IFLA_PROTINFO]) { nm_log_dbg (LOGD_IP6, "(%s): message had no PROTINFO attribute", device->iface); return NULL; } err = nla_parse_nested (pi, IFLA_INET6_MAX, tb[IFLA_PROTINFO], link_prot_policy); if (err < 0) { nm_log_dbg (LOGD_IP6, "(%s): error parsing PROTINFO flags", device->iface); return NULL; } if (!pi[IFLA_INET6_FLAGS]) { nm_log_dbg (LOGD_IP6, "(%s): message had no PROTINFO flags", device->iface); return NULL; } device->ra_flags = nla_get_u32 (pi[IFLA_INET6_FLAGS]); nm_log_dbg (LOGD_IP6, "(%s): got IPv6 flags 0x%X", device->iface, device->ra_flags); return device; }
static NMIP6Device * process_route_change (NMIP6Manager *manager, struct nl_msg *msg) { NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); NMIP6Device *device; struct nlmsghdr *hdr; struct rtnl_route *rtnlroute; int old_size; hdr = nlmsg_hdr (msg); rtnlroute = NULL; nl_msg_parse (msg, ref_object, &rtnlroute); if (!rtnlroute) { nm_log_dbg (LOGD_IP6, "error processing netlink new/del route message"); return NULL; } /* Cached/cloned routes are created by the kernel for specific operations * and aren't part of the interface's permanent routing configuration. */ if (rtnl_route_get_flags (rtnlroute) & RTM_F_CLONED) { rtnl_route_put (rtnlroute); return NULL; } device = nm_ip6_manager_get_device (manager, rtnl_route_get_oif (rtnlroute)); old_size = nl_cache_nitems (priv->route_cache); nl_cache_include (priv->route_cache, (struct nl_object *)rtnlroute, NULL, NULL); /* As above in process_address_change */ nm_log_dbg (LOGD_IP6, "(%s): route cache size: %d -> %d:", device_get_iface (device), old_size, nl_cache_nitems (priv->route_cache)); dump_route_change (device, hdr, rtnlroute); rtnl_route_put (rtnlroute); if (nl_cache_nitems (priv->route_cache) == old_size) return NULL; return device; }
static NMIP6Device * process_route (NMIP6Manager *manager, struct nl_msg *msg) { NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); NMIP6Device *device; struct rtnl_route *rtnlroute; int old_size; nm_log_dbg (LOGD_IP6, "processing netlink new/del route message"); rtnlroute = NULL; nl_msg_parse (msg, ref_object, &rtnlroute); if (!rtnlroute) { nm_log_dbg (LOGD_IP6, "error processing netlink new/del route message"); return NULL; } device = nm_ip6_manager_get_device (manager, rtnl_route_get_oif (rtnlroute)); if (!device) { nm_log_dbg (LOGD_IP6, "ignoring message for unknown device"); rtnl_route_put (rtnlroute); return NULL; } old_size = nl_cache_nitems (priv->route_cache); nl_cache_include (priv->route_cache, (struct nl_object *)rtnlroute, NULL, NULL); rtnl_route_put (rtnlroute); /* As above in process_addr */ if (nl_cache_nitems (priv->route_cache) == old_size) { nm_log_dbg (LOGD_IP6, "(%s): route cache unchanged, ignoring message", device->iface); return NULL; } return device; }