diff --git a/drivers/net/rpmsgdrv.c b/drivers/net/rpmsgdrv.c index 67cf6286f8..12a829be0b 100644 --- a/drivers/net/rpmsgdrv.c +++ b/drivers/net/rpmsgdrv.c @@ -1057,7 +1057,7 @@ static int net_rpmsg_drv_ioctl(FAR struct net_driver_s *dev, int cmd, ssize_t len; int ret; - len = net_ioctl_arglen(cmd); + len = net_ioctl_arglen(PF_RPMSG, cmd); if (len >= 0) { FAR struct net_rpmsg_ioctl_s *msg; diff --git a/include/netinet/in.h b/include/netinet/in.h index a6038a474d..6901e44e2d 100644 --- a/include/netinet/in.h +++ b/include/netinet/in.h @@ -335,6 +335,13 @@ struct in6_pktinfo int ipi6_ifindex; /* send/recv interface index */ }; +struct in6_ifreq +{ + struct in6_addr ifr6_addr; /* The IPv6 address of the request */ + uint32_t ifr6_prefixlen; /* The IPv6 prefix length */ + int ifr6_ifindex; /* The interface index of the request */ +}; + /**************************************************************************** * Public Data ****************************************************************************/ diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h index f92ea91ca8..4c2452f0c0 100644 --- a/include/nuttx/net/net.h +++ b/include/nuttx/net/net.h @@ -301,7 +301,7 @@ void net_initialize(void); * Calculate the ioctl argument buffer length. * * Input Parameters: - * + * domain The socket domain * cmd The ioctl command * * Returned Value: @@ -309,7 +309,7 @@ void net_initialize(void); * ****************************************************************************/ -ssize_t net_ioctl_arglen(int cmd); +ssize_t net_ioctl_arglen(uint8_t domain, int cmd); /**************************************************************************** * Critical section management. diff --git a/net/netdev/netdev_ifconf.c b/net/netdev/netdev_ifconf.c index 1e30f3c208..362c926b07 100644 --- a/net/netdev/netdev_ifconf.c +++ b/net/netdev/netdev_ifconf.c @@ -26,7 +26,9 @@ #include #include +#include #include +#include #include #include @@ -139,6 +141,77 @@ static int ifconf_ipv4_callback(FAR struct net_driver_s *dev, FAR void *arg) } #endif +/**************************************************************************** + * Name: ifconf_ipv6_addr_callback + * + * Description: + * Callback from netdev_ipv6_foreach() that does the real implementation of + * netdev_ipv6_ifconf(). + * + * Input Parameters: + * dev - The network device for this callback. + * addr - The IPv6 address. + * arg - User callback argument + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +static int ifconf_ipv6_addr_callback(FAR struct net_driver_s *dev, + FAR struct netdev_ifaddr6_s *addr, + FAR void *arg) +{ + FAR struct ifconf_ipv6_info_s *info = (FAR struct ifconf_ipv6_info_s *)arg; + FAR struct lifconf *lifc = info->lifc; + + if (lifc->lifc_len + sizeof(struct lifreq) <= info->bufsize) + { + FAR struct lifreq *req = + (FAR struct lifreq *)&lifc->lifc_buf[lifc->lifc_len]; + FAR struct sockaddr_in6 *inaddr = + (FAR struct sockaddr_in6 *)&req->lifr_addr; +#ifdef CONFIG_NETDEV_MULTIPLE_IPv6 + int addr_idx = addr - dev->d_ipv6; + + /* There is space for information about another adapter. Within + * each ifreq structure, lifr_name will receive the interface + * name and lifr_addr the address. The actual number of bytes + * transferred is returned in lifc_len. + */ + + if (addr_idx > 0) + { + /* eth0:0 represents the second addr on eth0 */ + + if (snprintf(req->lifr_name, IFNAMSIZ, + "%s:%d", dev->d_ifname, addr_idx - 1) >= IFNAMSIZ) + { + nwarn("WARNING: ifname too long to print %s:%d\n", + dev->d_ifname, addr_idx - 1); + } + } + else +#endif + { + strlcpy(req->lifr_name, dev->d_ifname, IFNAMSIZ); + } + + inaddr->sin6_family = AF_INET6; + inaddr->sin6_port = 0; + net_ipv6addr_copy(inaddr->sin6_addr.s6_addr16, addr->addr); + } + + /* Increment the size of the buffer in any event */ + + lifc->lifc_len += sizeof(struct lifreq); + + return OK; +} +#endif + /**************************************************************************** * Name: ifconf_ipv6_callback * @@ -160,10 +233,8 @@ static int ifconf_ipv4_callback(FAR struct net_driver_s *dev, FAR void *arg) static int ifconf_ipv6_callback(FAR struct net_driver_s *dev, FAR void *arg) { FAR struct ifconf_ipv6_info_s *info = (FAR struct ifconf_ipv6_info_s *)arg; - FAR struct lifconf *lifc; DEBUGASSERT(dev != NULL && info != NULL && info->lifc != NULL); - lifc = info->lifc; /* Check if this adapter has an IPv6 address assigned and is in the UP * state. @@ -186,29 +257,7 @@ static int ifconf_ipv6_callback(FAR struct net_driver_s *dev, FAR void *arg) * cases. */ - if (lifc->lifc_len + sizeof(struct lifreq) <= info->bufsize) - { - FAR struct lifreq *req = - (FAR struct lifreq *)&lifc->lifc_buf[lifc->lifc_len]; - FAR struct sockaddr_in6 *inaddr = - (FAR struct sockaddr_in6 *)&req->lifr_addr; - - /* There is space for information about another adapter. Within - * each ifreq structure, lifr_name will receive the interface - * name and lifr_addr the address. The actual number of bytes - * transferred is returned in lifc_len. - */ - - strlcpy(req->lifr_name, dev->d_ifname, IFNAMSIZ); - - inaddr->sin6_family = AF_INET6; - inaddr->sin6_port = 0; - net_ipv6addr_copy(inaddr->sin6_addr.s6_addr16, dev->d_ipv6addr); - } - - /* Increment the size of the buffer in any event */ - - lifc->lifc_len += sizeof(struct lifreq); + return netdev_ipv6_foreach(dev, ifconf_ipv6_addr_callback, arg); } return 0; diff --git a/net/netdev/netdev_ioctl.c b/net/netdev/netdev_ioctl.c index 9a89f96f8f..1b8e0cebe2 100644 --- a/net/netdev/netdev_ioctl.c +++ b/net/netdev/netdev_ioctl.c @@ -652,31 +652,32 @@ static int netdev_wifr_ioctl(FAR struct socket *psock, int cmd, #endif /**************************************************************************** - * Name: netdev_ifr_dev + * Name: netdev_ifr_split_idx * * Description: - * Verify the struct ifreq and get the Ethernet device. + * Split the address index from device name like 'eth0:0'. * * Input Parameters: * req - The argument of the ioctl cmd * * Returned Value: - * A pointer to the driver structure on success; NULL on failure. + * The address index from device name. * ****************************************************************************/ -static FAR struct net_driver_s *netdev_ifr_dev(FAR struct ifreq *req) +static unsigned int netdev_ifr_split_idx(FAR struct ifreq *req) { - if (req != NULL) - { - /* Find the network device associated with the device name - * in the request data. - */ + FAR char *colon = strchr(req->ifr_name, ':'); + int idx; - return netdev_findbyname(req->ifr_name); + if (colon) + { + *colon++ = '\0'; /* Remove suffix from device name */ + idx = atoi(colon); + return idx >= 0 ? idx + 1 : 0; /* eth0:0 represents the second addr */ } - return NULL; + return 0; } /**************************************************************************** @@ -686,7 +687,7 @@ static FAR struct net_driver_s *netdev_ifr_dev(FAR struct ifreq *req) * Calculate the ioctl argument buffer length of ifreq. * * Input Parameters: - * + * domain The socket domain * cmd The ioctl command * * Returned Value: @@ -694,12 +695,11 @@ static FAR struct net_driver_s *netdev_ifr_dev(FAR struct ifreq *req) * ****************************************************************************/ -static ssize_t net_ioctl_ifreq_arglen(int cmd) +static ssize_t net_ioctl_ifreq_arglen(uint8_t domain, int cmd) { switch (cmd) { case SIOCGIFADDR: - case SIOCSIFADDR: case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCGIFBRDADDR: @@ -710,7 +710,6 @@ static ssize_t net_ioctl_ifreq_arglen(int cmd) case SIOCGIFMTU: case SIOCGIFHWADDR: case SIOCSIFHWADDR: - case SIOCDIFADDR: case SIOCGIFCOUNT: case SIOCSIFFLAGS: case SIOCGIFFLAGS: @@ -730,6 +729,11 @@ static ssize_t net_ioctl_ifreq_arglen(int cmd) case SIOCGIFINDEX: return sizeof(struct ifreq); + case SIOCSIFADDR: + case SIOCDIFADDR: + return domain == PF_INET6 ? + sizeof(struct in6_ifreq) : sizeof(struct ifreq); + case SIOCGLIFADDR: case SIOCSLIFADDR: case SIOCGLIFDSTADDR: @@ -769,6 +773,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, FAR struct ifreq *req) { FAR struct net_driver_s *dev = NULL; + unsigned int idx = 0; int ret = OK; ninfo("cmd: %d\n", cmd); @@ -827,15 +832,27 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, break; #endif default: - if (net_ioctl_ifreq_arglen(cmd) > 0) + if (req == NULL) { - dev = netdev_ifr_dev(req); - if (dev == NULL) - { - ret = -ENODEV; - } + net_unlock(); + return -ENOTTY; } - else + + if (net_ioctl_ifreq_arglen(psock->s_domain, cmd) + >= (ssize_t)sizeof(struct ifreq)) + { + idx = netdev_ifr_split_idx(req); + UNUSED(idx); + dev = netdev_findbyname(req->ifr_name); + } + else if (net_ioctl_ifreq_arglen(psock->s_domain, cmd) + == (ssize_t)sizeof(struct in6_ifreq)) + { + FAR struct in6_ifreq *ifr6 = (FAR struct in6_ifreq *)req; + dev = netdev_findbyindex(ifr6->ifr6_ifindex); + } + + if (dev == NULL) { ret = -ENOTTY; } @@ -857,12 +874,6 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, ioctl_get_ipv4addr(&req->ifr_addr, dev->d_ipaddr); break; - case SIOCSIFADDR: /* Set IP address */ - ioctl_set_ipv4addr(&dev->d_ipaddr, &req->ifr_addr); - 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 */ ioctl_get_ipv4addr(&req->ifr_dstaddr, dev->d_draddr); break; @@ -893,16 +904,18 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, case SIOCGLIFADDR: /* Get IP address */ { FAR struct lifreq *lreq = (FAR struct lifreq *)req; - ioctl_get_ipv6addr(&lreq->lifr_addr, dev->d_ipv6addr); + idx = MIN(idx, CONFIG_NETDEV_MAX_IPv6_ADDR - 1); + ioctl_get_ipv6addr(&lreq->lifr_addr, dev->d_ipv6[idx].addr); } break; case SIOCSLIFADDR: /* Set IP address */ { FAR struct lifreq *lreq = (FAR struct lifreq *)req; - ioctl_set_ipv6addr(dev->d_ipv6addr, &lreq->lifr_addr); + idx = MIN(idx, CONFIG_NETDEV_MAX_IPv6_ADDR - 1); + ioctl_set_ipv6addr(dev->d_ipv6[idx].addr, &lreq->lifr_addr); netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET6, - dev->d_ipv6addr, net_ipv6_mask2pref(dev->d_ipv6netmask)); + dev->d_ipv6[idx].addr, net_ipv6_mask2pref(dev->d_ipv6[idx].mask)); } break; @@ -928,14 +941,16 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, case SIOCGLIFNETMASK: /* Get network mask */ { FAR struct lifreq *lreq = (FAR struct lifreq *)req; - ioctl_get_ipv6addr(&lreq->lifr_addr, dev->d_ipv6netmask); + idx = MIN(idx, CONFIG_NETDEV_MAX_IPv6_ADDR - 1); + ioctl_get_ipv6addr(&lreq->lifr_addr, dev->d_ipv6[idx].mask); } break; case SIOCSLIFNETMASK: /* Set network mask */ { FAR struct lifreq *lreq = (FAR struct lifreq *)req; - ioctl_set_ipv6addr(dev->d_ipv6netmask, &lreq->lifr_addr); + idx = MIN(idx, CONFIG_NETDEV_MAX_IPv6_ADDR - 1); + ioctl_set_ipv6addr(dev->d_ipv6[idx].mask, &lreq->lifr_addr); } break; #endif @@ -1057,16 +1072,53 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, break; #endif + case SIOCSIFADDR: /* Set IP address */ +#ifdef CONFIG_NET_IPv4 + if (psock->s_domain != PF_INET6) + { + ioctl_set_ipv4addr(&dev->d_ipaddr, &req->ifr_addr); + netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET, + &dev->d_ipaddr, net_ipv4_mask2pref(dev->d_netmask)); + } +#endif + +#ifdef CONFIG_NET_IPv6 + if (psock->s_domain == PF_INET6) + { + FAR struct in6_ifreq *ifr6 = (FAR struct in6_ifreq *)req; + ret = netdev_ipv6_add(dev, ifr6->ifr6_addr.in6_u.u6_addr16, + ifr6->ifr6_prefixlen); + if (ret == OK) + { + netlink_device_notify_ipaddr(dev, RTM_NEWADDR, AF_INET6, + ifr6->ifr6_addr.in6_u.u6_addr16, ifr6->ifr6_prefixlen); + } + } +#endif + break; + case SIOCDIFADDR: /* Delete IP address */ #ifdef CONFIG_NET_IPv4 - netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET, + if (psock->s_domain != PF_INET6) + { + netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET, &dev->d_ipaddr, net_ipv4_mask2pref(dev->d_netmask)); - dev->d_ipaddr = 0; + dev->d_ipaddr = 0; + } #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)); + if (psock->s_domain == PF_INET6) + { + FAR struct in6_ifreq *ifr6 = (FAR struct in6_ifreq *)req; + ret = netdev_ipv6_del(dev, ifr6->ifr6_addr.in6_u.u6_addr16, + ifr6->ifr6_prefixlen); + if (ret == OK) + { + netlink_device_notify_ipaddr(dev, RTM_DELADDR, AF_INET6, + ifr6->ifr6_addr.in6_u.u6_addr16, ifr6->ifr6_prefixlen); + } + } #endif break; @@ -1589,7 +1641,7 @@ static int netdev_ioctl(FAR struct socket *psock, int cmd, * Calculate the ioctl argument buffer length. * * Input Parameters: - * + * domain The socket domain * cmd The ioctl command * * Returned Value: @@ -1597,11 +1649,11 @@ static int netdev_ioctl(FAR struct socket *psock, int cmd, * ****************************************************************************/ -ssize_t net_ioctl_arglen(int cmd) +ssize_t net_ioctl_arglen(uint8_t domain, int cmd) { ssize_t arglen; - arglen = net_ioctl_ifreq_arglen(cmd); + arglen = net_ioctl_ifreq_arglen(domain, cmd); if (arglen > 0) { return arglen; diff --git a/net/usrsock/usrsock_ioctl.c b/net/usrsock/usrsock_ioctl.c index 4d9e264562..d102f17d20 100644 --- a/net/usrsock/usrsock_ioctl.c +++ b/net/usrsock/usrsock_ioctl.c @@ -183,7 +183,7 @@ int usrsock_ioctl(FAR struct socket *psock, int cmd, unsigned long arg_) return -ENOTTY; } - arglen = net_ioctl_arglen(cmd); + arglen = net_ioctl_arglen(psock->s_domain, cmd); if (arglen < 0) { return arglen;