diff --git a/include/netpacket/netlink.h b/include/netpacket/netlink.h index da4e13e165..31daae56a1 100644 --- a/include/netpacket/netlink.h +++ b/include/netpacket/netlink.h @@ -704,6 +704,36 @@ struct rtmsg uint32_t rtm_flags; }; +/* Structures used in prefix information. */ + +struct prefixmsg +{ + uint8_t prefix_family; + uint8_t prefix_pad1; + uint16_t prefix_pad2; + int32_t prefix_ifindex; + uint8_t prefix_type; + uint8_t prefix_len; + uint8_t prefix_flags; + uint8_t prefix_pad3; +}; + +enum +{ + PREFIX_UNSPEC, + PREFIX_ADDRESS, + PREFIX_CACHEINFO, + __PREFIX_MAX +}; + +#define PREFIX_MAX (__PREFIX_MAX - 1) + +struct prefix_cacheinfo +{ + uint32_t preferred_time; + uint32_t valid_time; +}; + /* <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)--> * +---------------------+- - -+- - - - - - - - - -+- - -+ * | Header | Pad | Payload | Pad | diff --git a/net/icmpv6/icmpv6_input.c b/net/icmpv6/icmpv6_input.c index 17d9137b54..e2be6241ac 100644 --- a/net/icmpv6/icmpv6_input.c +++ b/net/icmpv6/icmpv6_input.c @@ -36,6 +36,7 @@ #include #include "devif/devif.h" +#include "netlink/netlink.h" #include "neighbor/neighbor.h" #include "utils/utils.h" #include "icmpv6/icmpv6.h" @@ -450,6 +451,8 @@ void icmpv6_input(FAR struct net_driver_s *dev, unsigned int iplen) { icmpv6_setaddresses(dev, ipv6->srcipaddr, prefixopt->prefix, prefixopt->preflen); + netlink_ipv6_prefix_notify(dev, RTM_NEWPREFIX, + prefixopt); } /* Notify any waiting threads */ diff --git a/net/netlink/Kconfig b/net/netlink/Kconfig index 71d60885fd..dd788e6006 100644 --- a/net/netlink/Kconfig +++ b/net/netlink/Kconfig @@ -116,6 +116,12 @@ config NETLINK_VALIDATE_POLICY VALIDATE_POLICY is used to make sure the parameters you pass in are valid. +config NETLINK_DISABLE_NEWPREFIX + bool "Disable RTM_NEWPREFIX support" + default n + ---help--- + RTM_NEWPREFIX is used to set netdev prefix. + endif # NETLINK_ROUTE config NETLINK_NETFILTER diff --git a/net/netlink/netlink.h b/net/netlink/netlink.h index fd1f81e4b3..9932a9635f 100644 --- a/net/netlink/netlink.h +++ b/net/netlink/netlink.h @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -48,6 +49,7 @@ # define netlink_device_notify_ipaddr(dev, type, domain, addr, preflen) # define netlink_route_notify(route, type, domain) # define netlink_neigh_notify(neigh, type, domain) +# define netlink_ipv6_prefix_notify(dev, type, pinfo) #endif #ifdef CONFIG_NET_NETLINK @@ -552,6 +554,21 @@ void netlink_route_notify(FAR const void *route, int type, int domain); void netlink_neigh_notify(FAR const void *neigh, int type, int domain); #endif +/**************************************************************************** + * Name: netlink_ipv6_prefix_notify() + * + * Description: + * Perform the RA prefix for the NETLINK_ROUTE protocol. + * + ****************************************************************************/ + +#if defined(CONFIG_NETLINK_DISABLE_NEWPREFIX) || !defined(CONFIG_NET_IPV6) +# define netlink_ipv6_prefix_notify(dev, type, pinfo) +#else +void netlink_ipv6_prefix_notify(FAR struct net_driver_s *dev, int type, + FAR const struct icmpv6_prefixinfo_s *pinfo); +#endif + /**************************************************************************** * Name: nla_next * diff --git a/net/netlink/netlink_route.c b/net/netlink/netlink_route.c index 24ee4cddda..b4fecc769d 100644 --- a/net/netlink/netlink_route.c +++ b/net/netlink/netlink_route.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -179,6 +180,32 @@ struct getaddr_recvfrom_rsplist_s struct getaddr_recvfrom_response_s payload; }; +struct getprefix_recvfrom_addr_s +{ + struct rtattr attr; + net_ipv6addr_t addr; +}; + +struct getprefix_recvfrom_cache_s +{ + struct rtattr attr; + struct prefix_cacheinfo pci; +}; + +struct getprefix_recvfrom_response_s +{ + struct nlmsghdr hdr; + struct prefixmsg pmsg; + struct getprefix_recvfrom_addr_s prefix; + struct getprefix_recvfrom_cache_s pci; +}; + +struct getprefix_recvfrom_rsplist_s +{ + sq_entry_t flink; + struct getprefix_recvfrom_response_s payload; +}; + /* netdev_foreach() callback */ struct nlroute_sendto_request_s @@ -1249,6 +1276,58 @@ static int netlink_get_addr(NETLINK_HANDLE handle, } #endif +#if !defined(CONFIG_NETLINK_DISABLE_NEWADDR) && defined(CONFIG_NET_IPV6) +static FAR struct netlink_response_s * +netlink_fill_ipv6prefix(FAR struct net_driver_s *dev, int type, + FAR const struct icmpv6_prefixinfo_s *pinfo) +{ + FAR struct getprefix_recvfrom_rsplist_s *alloc; + FAR struct getprefix_recvfrom_response_s *resp; + + DEBUGASSERT(dev != NULL && pinfo != NULL); + + alloc = kmm_zalloc(sizeof(struct getprefix_recvfrom_rsplist_s)); + if (alloc == NULL) + { + nerr("ERROR: Failed to allocate response buffer.\n"); + return NULL; + } + + /* Initialize the response buffer */ + + resp = &alloc->payload; + + resp->hdr.nlmsg_len = sizeof(struct getprefix_recvfrom_response_s); + resp->hdr.nlmsg_type = type; + resp->hdr.nlmsg_flags = 0; + resp->hdr.nlmsg_seq = 0; + resp->hdr.nlmsg_pid = 0; + + resp->pmsg.prefix_family = AF_INET6; +#ifdef CONFIG_NETDEV_IFINDEX + resp->pmsg.prefix_ifindex = dev->d_ifindex; +#endif + resp->pmsg.prefix_len = pinfo->optlen; + resp->pmsg.prefix_type = pinfo->opttype; + + resp->prefix.attr.rta_len = RTA_LENGTH(sizeof(net_ipv6addr_t)); + resp->prefix.attr.rta_type = PREFIX_ADDRESS; + net_ipv6addr_copy(resp->prefix.addr, pinfo->prefix); + + resp->pci.attr.rta_len = RTA_LENGTH(sizeof(struct prefix_cacheinfo)); + resp->pci.attr.rta_type = PREFIX_CACHEINFO; + + resp->pci.pci.preferred_time = NTOHS(pinfo->plifetime[0]) << 16; + resp->pci.pci.preferred_time |= NTOHS(pinfo->plifetime[1]); + resp->pci.pci.valid_time = NTOHS(pinfo->vlifetime[0]) << 16; + resp->pci.pci.valid_time |= NTOHS(pinfo->vlifetime[1]); + + /* Finally, return the response */ + + return (FAR struct netlink_response_s *)alloc; +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -1582,4 +1661,29 @@ void netlink_neigh_notify(FAR const void *neigh, int type, int domain) } #endif +/**************************************************************************** + * Name: netlink_ipv6_prefix_notify() + * + * Description: + * Perform the RA prefix for the NETLINK_ROUTE protocol. + * + ****************************************************************************/ + +#if !defined(CONFIG_NETLINK_DISABLE_NEWADDR) && defined(CONFIG_NET_IPV6) +void netlink_ipv6_prefix_notify(FAR struct net_driver_s *dev, int type, + FAR const struct icmpv6_prefixinfo_s *pinfo) +{ + FAR struct netlink_response_s *resp; + + resp = netlink_fill_ipv6prefix(dev, type, pinfo); + if (resp == NULL) + { + return; + } + + netlink_add_broadcast(RTNLGRP_IPV6_PREFIX, resp); + netlink_add_terminator(NULL, NULL, RTNLGRP_IPV6_PREFIX); +} +#endif + #endif /* CONFIG_NETLINK_ROUTE */