diff --git a/net/netdev/netdev_ioctl.c b/net/netdev/netdev_ioctl.c index d1eea0c40e..9a89f96f8f 100644 --- a/net/netdev/netdev_ioctl.c +++ b/net/netdev/netdev_ioctl.c @@ -83,6 +83,7 @@ #include "icmpv6/icmpv6.h" #include "route/route.h" #include "netlink/netlink.h" +#include "utils/utils.h" /**************************************************************************** * Pre-processor Definitions @@ -858,7 +859,8 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, case SIOCSIFADDR: /* Set IP address */ ioctl_set_ipv4addr(&dev->d_ipaddr, &req->ifr_addr); - netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET); + netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET, + &dev->d_ipaddr, net_ipv4_mask2pref(dev->d_netmask)); break; case SIOCGIFDSTADDR: /* Get P-to-P address */ @@ -899,7 +901,8 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, { FAR struct lifreq *lreq = (FAR struct lifreq *)req; ioctl_set_ipv6addr(dev->d_ipv6addr, &lreq->lifr_addr); - netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET6); + netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET6, + dev->d_ipv6addr, net_ipv6_mask2pref(dev->d_ipv6netmask)); } break; @@ -1056,12 +1059,14 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, case SIOCDIFADDR: /* Delete IP address */ #ifdef CONFIG_NET_IPv4 + netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET, + &dev->d_ipaddr, net_ipv4_mask2pref(dev->d_netmask)); dev->d_ipaddr = 0; - netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET); #endif #ifdef CONFIG_NET_IPv6 + netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET6, + dev->d_ipv6addr, net_ipv6_mask2pref(dev->d_ipv6netmask)); memset(&dev->d_ipv6addr, 0, sizeof(net_ipv6addr_t)); - netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET6); #endif break; diff --git a/net/netlink/netlink.h b/net/netlink/netlink.h index c14514f0f2..c86882266f 100644 --- a/net/netlink/netlink.h +++ b/net/netlink/netlink.h @@ -45,7 +45,7 @@ #ifndef CONFIG_NETLINK_ROUTE # define netlink_device_notify(dev) -# define netlink_device_notify_ipaddr(dev, type, domain) +# define netlink_device_notify_ipaddr(dev, type, domain, addr, preflen) #endif #ifdef CONFIG_NET_NETLINK @@ -502,7 +502,8 @@ void netlink_device_notify(FAR struct net_driver_s *dev); ****************************************************************************/ void netlink_device_notify_ipaddr(FAR struct net_driver_s *dev, - int type, int domain); + int type, int domain, + FAR const void *addr, uint8_t preflen); /**************************************************************************** * Name: nla_next diff --git a/net/netlink/netlink_route.c b/net/netlink/netlink_route.c index 8ed9caa4c4..4409016da9 100644 --- a/net/netlink/netlink_route.c +++ b/net/netlink/netlink_route.c @@ -369,16 +369,6 @@ static uint32_t make_mask(int prefixlen) return 0; } - -static uint8_t mask_len(uint32_t nmask) -{ - uint8_t prefixlen = 0; - uint32_t hmask = NTOHL(nmask); - - for (; hmask; ++prefixlen, hmask <<= 1); - - return prefixlen; -} #endif /**************************************************************************** @@ -392,6 +382,7 @@ static uint8_t mask_len(uint32_t nmask) #ifndef CONFIG_NETLINK_DISABLE_GETLINK static FAR struct netlink_response_s * netlink_get_ifaddr(FAR struct net_driver_s *dev, int domain, int type, + FAR const void *local_addr, uint8_t prefixlen, FAR const struct nlroute_sendto_request_s *req) { FAR struct getaddr_recvfrom_rsplist_s *alloc; @@ -429,8 +420,8 @@ netlink_get_ifaddr(FAR struct net_driver_s *dev, int domain, int type, if (domain == AF_INET) { resp->attr.rta_len = RTA_LENGTH(sizeof(struct in_addr)); - memcpy(&resp->local_addr, &dev->d_ipaddr, sizeof(struct in_addr)); - resp->ifaddr.ifa_prefixlen = mask_len(dev->d_netmask); + memcpy(&resp->local_addr, local_addr, sizeof(struct in_addr)); + resp->ifaddr.ifa_prefixlen = prefixlen; } #endif @@ -438,8 +429,8 @@ netlink_get_ifaddr(FAR struct net_driver_s *dev, int domain, int type, if (domain == AF_INET6) { resp->attr.rta_len = RTA_LENGTH(sizeof(struct in6_addr)); - memcpy(&resp->local_addr, dev->d_ipv6addr, sizeof(struct in6_addr)); - resp->ifaddr.ifa_prefixlen = net_ipv6_mask2pref(dev->d_ipv6netmask); + memcpy(&resp->local_addr, local_addr, sizeof(struct in6_addr)); + resp->ifaddr.ifa_prefixlen = prefixlen; } #endif @@ -951,7 +942,8 @@ static int netlink_new_ipv4addr(NETLINK_HANDLE handle, dev->d_ipaddr = nla_get_in_addr(tb[IFA_LOCAL]); dev->d_netmask = make_mask(ifm->ifa_prefixlen); - netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET); + netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET, &dev->d_ipaddr, + ifm->ifa_prefixlen); net_unlock(); return OK; @@ -1000,7 +992,8 @@ static int netlink_new_ipv6addr(NETLINK_HANDLE handle, memcpy(dev->d_ipv6addr, nla_data(tb[IFA_LOCAL]), 16); net_ipv6_pref2mask(ifm->ifa_prefixlen, dev->d_ipv6netmask); - netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET6); + netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET6, dev->d_ipv6addr, + ifm->ifa_prefixlen); net_unlock(); return OK; @@ -1047,9 +1040,10 @@ static int netlink_del_ipv4addr(NETLINK_HANDLE handle, return -EADDRNOTAVAIL; } + netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET, &dev->d_ipaddr, + net_ipv4_mask2pref(dev->d_netmask)); dev->d_ipaddr = 0; - netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET); net_unlock(); return OK; @@ -1090,15 +1084,17 @@ static int netlink_del_ipv6addr(NETLINK_HANDLE handle, return -ENODEV; } - if (tb[IFA_LOCAL] && dev->d_ipaddr != nla_get_in_addr(tb[IFA_LOCAL])) + if (tb[IFA_LOCAL] && !net_ipv6addr_cmp(dev->d_ipv6addr, + nla_data(tb[IFA_LOCAL]))) { net_unlock(); return -EADDRNOTAVAIL; } + netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET6, dev->d_ipv6addr, + net_ipv6_mask2pref(dev->d_ipv6netmask)); memset(&dev->d_ipv6addr, 0, sizeof(net_ipv6addr_t)); - netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET6); net_unlock(); return OK; @@ -1114,14 +1110,36 @@ static int netlink_del_ipv6addr(NETLINK_HANDLE handle, ****************************************************************************/ #ifndef CONFIG_NETLINK_DISABLE_GETADDR -static int netlink_addr_callback(FAR struct net_driver_s *dev, - FAR void *arg) +static int netlink_addr_callback(FAR struct net_driver_s *dev, FAR void *arg) { FAR struct nlroute_info_s *info = arg; FAR struct netlink_response_s *resp; + FAR void *addr = NULL; + uint8_t preflen; + +#ifdef CONFIG_NET_IPv4 + if (info->req->gen.rtgen_family == AF_INET) + { + addr = &dev->d_ipaddr; + preflen = net_ipv4_mask2pref(dev->d_netmask); + } +#endif + +#ifdef CONFIG_NET_IPv6 + if (info->req->gen.rtgen_family == AF_INET6) + { + addr = &dev->d_ipv6addr; + preflen = net_ipv6_mask2pref(dev->d_ipv6netmask); + } +#endif + + if (addr == NULL) + { + return OK; + } resp = netlink_get_ifaddr(dev, info->req->gen.rtgen_family, RTM_NEWADDR, - info->req); + addr, preflen, info->req); if (resp == NULL) { return -ENOMEM; @@ -1378,14 +1396,15 @@ void netlink_device_notify(FAR struct net_driver_s *dev) !defined(CONFIG_NETLINK_DISABLE_DELADDR) || \ !defined(CONFIG_NETLINK_DISABLE_GETADDR) void netlink_device_notify_ipaddr(FAR struct net_driver_s *dev, - int type, int domain) + int type, int domain, + FAR const void *addr, uint8_t preflen) { FAR struct netlink_response_s *resp; int group; DEBUGASSERT(dev != NULL); - resp = netlink_get_ifaddr(dev, domain, type, NULL); + resp = netlink_get_ifaddr(dev, domain, type, addr, preflen, NULL); if (resp != NULL) { #ifdef CONFIG_NET_IPv4 diff --git a/net/utils/CMakeLists.txt b/net/utils/CMakeLists.txt index 8c779bfe0b..27868b2fcd 100644 --- a/net/utils/CMakeLists.txt +++ b/net/utils/CMakeLists.txt @@ -31,12 +31,13 @@ set(SRCS net_snoop.c net_cmsg.c net_iob_concat.c - net_getrandom.c) + net_getrandom.c + net_mask2pref.c) # IPv6 utilities if(CONFIG_NET_IPv6) - list(APPEND SRCS net_ipv6_maskcmp.c net_ipv6_mask2pref.c net_ipv6_pref2mask.c) + list(APPEND SRCS net_ipv6_maskcmp.c net_ipv6_pref2mask.c) endif() # TCP utilities diff --git a/net/utils/Make.defs b/net/utils/Make.defs index 400d0367fb..764dee1481 100644 --- a/net/utils/Make.defs +++ b/net/utils/Make.defs @@ -22,12 +22,12 @@ NET_CSRCS += net_dsec2tick.c net_dsec2timeval.c net_timeval2dsec.c NET_CSRCS += net_chksum.c net_ipchksum.c net_incr32.c net_lock.c net_snoop.c -NET_CSRCS += net_cmsg.c net_iob_concat.c net_getrandom.c +NET_CSRCS += net_cmsg.c net_iob_concat.c net_getrandom.c net_mask2pref.c # IPv6 utilities ifeq ($(CONFIG_NET_IPv6),y) -NET_CSRCS += net_ipv6_maskcmp.c net_ipv6_mask2pref.c net_ipv6_pref2mask.c +NET_CSRCS += net_ipv6_maskcmp.c net_ipv6_pref2mask.c endif # TCP utilities diff --git a/net/utils/net_ipv6_mask2pref.c b/net/utils/net_mask2pref.c similarity index 78% rename from net/utils/net_ipv6_mask2pref.c rename to net/utils/net_mask2pref.c index 4c5de09173..2c06a6607e 100644 --- a/net/utils/net_ipv6_mask2pref.c +++ b/net/utils/net_mask2pref.c @@ -1,5 +1,5 @@ /**************************************************************************** - * net/utils/net_ipv6_mask2pref.c + * net/utils/net_mask2pref.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -26,7 +26,7 @@ #include "utils/utils.h" -#ifdef CONFIG_NET_IPv6 +#if defined(CONFIG_NET_IPv4) || defined(CONFIG_NET_IPv6) /**************************************************************************** * Private Data @@ -112,10 +112,52 @@ static inline uint8_t net_msbits16(uint16_t hword) return ones; } +#endif /* CONFIG_NET_IPv4 || CONFIG_NET_IPv6 */ + /**************************************************************************** * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: net_ipv4_mask2pref + * + * Description: + * Convert a 32-bit netmask to a prefix length. The NuttX IPv4 + * networking uses 32-bit network masks internally. This function + * converts the IPv4 netmask to a prefix length. + * + * The prefix length is the number of MS '1' bits on in the netmask. + * This, of course, assumes that all MS bits are '1' and all LS bits are + * '0' with no intermixed 1's and 0's. This function searches from the MS + * bit until the first '0' is found (this does not necessary mean that + * there might not be additional '1' bits following the firs '0', but that + * will be a malformed netmask. + * + * Input Parameters: + * mask An IPv4 netmask in the form of in_addr_t + * + * Returned Value: + * The prefix length, range 0-32 on success; This function will not + * fail. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv4 + +uint8_t net_ipv4_mask2pref(in_addr_t mask) +{ + uint32_t hmask = NTOHL(mask); + uint8_t ones = net_msbits16((uint16_t)(hmask >> 16)); + if (ones == 16) + { + ones += net_msbits16((uint16_t)(hmask & 0xffff)); + } + + return ones; +} + +#endif /* CONFIG_NET_IPv4 */ + /**************************************************************************** * Name: net_ipv6_mask2pref * @@ -140,6 +182,8 @@ static inline uint8_t net_msbits16(uint16_t hword) * ****************************************************************************/ +#ifdef CONFIG_NET_IPv6 + uint8_t net_ipv6_mask2pref(FAR const uint16_t *mask) { uint8_t preflen; diff --git a/net/utils/utils.h b/net/utils/utils.h index 401f2e1161..9688cac7fd 100644 --- a/net/utils/utils.h +++ b/net/utils/utils.h @@ -159,6 +159,34 @@ unsigned int net_timeval2dsec(FAR struct timeval *tv, void net_getrandom(FAR void *bytes, size_t nbytes); +/**************************************************************************** + * Name: net_ipv4_mask2pref + * + * Description: + * Convert a 32-bit netmask to a prefix length. The NuttX IPv4 + * networking uses 32-bit network masks internally. This function + * converts the IPv4 netmask to a prefix length. + * + * The prefix length is the number of MS '1' bits on in the netmask. + * This, of course, assumes that all MS bits are '1' and all LS bits are + * '0' with no intermixed 1's and 0's. This function searches from the MS + * bit until the first '0' is found (this does not necessary mean that + * there might not be additional '1' bits following the firs '0', but that + * will be a malformed netmask. + * + * Input Parameters: + * mask An IPv4 netmask in the form of in_addr_t + * + * Returned Value: + * The prefix length, range 0-32 on success; This function will not + * fail. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv4 +uint8_t net_ipv4_mask2pref(in_addr_t mask); +#endif + /**************************************************************************** * Name: net_ipv6_mask2pref *