netlink: Explicitly set ip address for netlink notify

Prepare for multiple IPv6 addresses per net device, then we can notify
add/remove of a single address later.

Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
Zhe Weng 2023-10-19 15:04:23 +08:00 committed by Xiang Xiao
parent 85a375cd7d
commit c7845f5b25
7 changed files with 134 additions and 36 deletions

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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
*