diff --git a/include/netutils/netlib.h b/include/netutils/netlib.h index bbf561126..79caa7604 100644 --- a/include/netutils/netlib.h +++ b/include/netutils/netlib.h @@ -159,11 +159,11 @@ ****************************************************************************/ #ifdef HAVE_ROUTE_PROCFS +#ifdef CONFIG_NET_IPv4 /* Describes one entry from the IPv4 routing table. All addresses are in * host byte order! */ -#ifdef CONFIG_NET_IPv4 struct netlib_ipv4_route_s { in_addr_t prefix; /* Routing prefix */ @@ -172,11 +172,11 @@ struct netlib_ipv4_route_s }; #endif +#ifdef CONFIG_NET_IPv6 /* Describes one entry from the IPv6 routing table. All addresses are in * host byte order! */ -#ifdef CONFIG_NET_IPv6 struct netlib_ipv6_route_s { uint16_t prefix[8]; /* Routing prefix */ @@ -196,7 +196,7 @@ struct netlib_device_s #endif char ifname[IFNAMSIZ]; /* Interface name */ }; -#endif +#endif /* CONFIG_NETLINK_ROUTE*/ #ifdef CONFIG_NETUTILS_NETLIB_GENERICURLPARSER struct url_s @@ -363,6 +363,12 @@ int netlib_ipv6router(FAR const struct in6_addr *destipaddr, # endif #endif +#if defined(CONFIG_NETLINK_ROUTE) && defined(CONFIG_NET_ROUTE) +struct rtentry; /* Forward reference */ +ssize_t netlib_get_route(FAR struct rtentry *rtelist, + unsigned int nentries, sa_family_t family); +#endif + #ifdef CONFIG_NET_ICMPv6_AUTOCONF /* ICMPv6 Autoconfiguration */ diff --git a/netutils/netlib/Makefile b/netutils/netlib/Makefile index d1ddc1878..396cdf0c8 100644 --- a/netutils/netlib/Makefile +++ b/netutils/netlib/Makefile @@ -88,6 +88,9 @@ endif ifeq ($(CONFIG_NETLINK_ROUTE),y) CSRCS += netlib_getdevs.c +ifeq ($(CONFIG_NET_ROUTE),y) +CSRCS += netlib_getroute.c +endif endif # These require TCP support diff --git a/netutils/netlib/netlib_getarptab.c b/netutils/netlib/netlib_getarptab.c index f2a51c1dd..c80f94e1e 100644 --- a/netutils/netlib/netlib_getarptab.c +++ b/netutils/netlib/netlib_getarptab.c @@ -210,7 +210,7 @@ ssize_t netlib_get_arptable(FAR struct arp_entry_s *arptab, /* Copy the ARP table data to the caller's buffer */ - paysize = resp->attr.rta_len; + paysize = RTA_PAYLOAD(&resp->attr); if (paysize > maxsize) { paysize = maxsize; diff --git a/netutils/netlib/netlib_getdevs.c b/netutils/netlib/netlib_getdevs.c index 15a4e768f..5106bd44b 100644 --- a/netutils/netlib/netlib_getdevs.c +++ b/netutils/netlib/netlib_getdevs.c @@ -40,11 +40,11 @@ #include #include +#include #include #include #include #include -#include #include @@ -168,91 +168,93 @@ ssize_t netlib_get_devices(FAR struct netlib_device_s *devlist, { /* Receive the next device response */ - nrecvd = recv(fd, &resp, sizeof(struct netlib_recvfrom_response_s), 0); - if (nrecvd < 0) - { - int errcode = errno; - fprintf(stderr, "ERROR: recv() failed: %d\n", errcode); - ret = -errcode; - goto errout_with_socket; - } + nrecvd = recv(fd, &resp, sizeof(struct netlib_recvfrom_response_s), 0); + if (nrecvd < 0) + { + int errcode = errno; + fprintf(stderr, "ERROR: recv() failed: %d\n", errcode); + ret = -errcode; + goto errout_with_socket; + } - /* Verify the data and transfer the device list to the caller */ + /* Verify the data and transfer the device list to the caller */ - if (nrecvd != sizeof(struct netlib_recvfrom_response_s) || - resp.hdr.nlmsg_len < sizeof(struct nlmsghdr) || - resp.hdr.nlmsg_len != nrecvd) - { - fprintf(stderr, "ERROR: Bad message\n"); - ret = -EIO; - goto errout_with_socket; - } + if (nrecvd != sizeof(struct netlib_recvfrom_response_s) || + resp.hdr.nlmsg_len < sizeof(struct nlmsghdr) || + resp.hdr.nlmsg_len != nrecvd) + { + fprintf(stderr, "ERROR: Bad message\n"); + ret = -EIO; + goto errout_with_socket; + } - /* The sequence number in the response should match the sequence - * number in the request (since we created the socket, this should - * always be true). - */ + /* The sequence number in the response should match the sequence + * number in the request (since we created the socket, this should + * always be true). + */ - if (resp.hdr.nlmsg_seq != thiseq) - { - fprintf(stderr, "ERROR: Bad sequence number in response\n"); - ret = -EIO; - goto errout_with_socket; - } + if (resp.hdr.nlmsg_seq != thiseq) + { + fprintf(stderr, "ERROR: Bad sequence number in response\n"); + ret = -EIO; + goto errout_with_socket; + } - /* Copy the device list to the caller's buffer */ + /* Copy the device list to the caller's buffer */ - switch (resp.hdr.nlmsg_type) - { - case NLMSG_DONE: - enddump = true; - break; + switch (resp.hdr.nlmsg_type) + { + case NLMSG_DONE: + enddump = true; + break; - case RTM_NEWLINK: - { - FAR struct ifinfomsg *iface; - FAR struct rtattr *attr; - int len; + case RTM_NEWLINK: + { + FAR struct rtattr *attr; + int len; - /* Decode the response */ + /* Decode the response */ - iface = NLMSG_DATA(&resp.hdr); - len = resp.hdr.nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg)); + attr = &resp.attr; + len = RTA_PAYLOAD(attr); - for (attr = IFLA_RTA(iface); - RTA_OK(attr, len); - attr = RTA_NEXT(attr, len)) - { - switch (attr->rta_type) - { - case IFLA_IFNAME: - if (ncopied < nentries) - { + for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) + { + switch (attr->rta_type) + { + case IFLA_IFNAME: + if (ncopied < nentries) + { #ifdef CONFIG_NETDEV_IFINDEX - devlist[ncopied].ifindex = iface->ifi_index; + FAR struct ifinfomsg *iface = &resp.iface; + + devlist[ncopied].ifindex = iface->ifi_index; #endif - strncpy(devlist[ncopied].ifname, - (FAR char *)RTA_DATA(attr), IFNAMSIZ); - ncopied++; - } + strncpy(devlist[ncopied].ifname, + (FAR char *)RTA_DATA(attr), IFNAMSIZ); + ncopied++; + } - break; + break; - default: - break; - } - } - } - break; + default: + break; + } + } + } + break; - default: - fprintf(stderr, "ERROR: Message type %u, length %lu\n", - resp.hdr.nlmsg_type, (unsigned long)resp.hdr.nlmsg_len); - ret = -EIO; - goto errout_with_socket; - } + default: + fprintf(stderr, "ERROR: Message type %u, length %lu\n", + resp.hdr.nlmsg_type, (unsigned long)resp.hdr.nlmsg_len); + ret = -EIO; + goto errout_with_socket; + } } + close(fd); + return ncopied; + errout_with_socket: close(fd); return ret; diff --git a/netutils/netlib/netlib_getnbtab.c b/netutils/netlib/netlib_getnbtab.c index 3d89998c2..39fcc14c5 100644 --- a/netutils/netlib/netlib_getnbtab.c +++ b/netutils/netlib/netlib_getnbtab.c @@ -211,7 +211,7 @@ ssize_t netlib_get_nbtable(FAR struct neighbor_entry_s *nbtab, /* Copy the Neighbor table data to the caller's buffer */ - paysize = resp->attr.rta_len; + paysize = RTA_PAYLOAD(&resp->attr); if (paysize > maxsize) { paysize = maxsize; diff --git a/netutils/netlib/netlib_getroute.c b/netutils/netlib/netlib_getroute.c new file mode 100644 index 000000000..0529c564c --- /dev/null +++ b/netutils/netlib/netlib_getroute.c @@ -0,0 +1,323 @@ +/**************************************************************************** + * netutils/netlib/netlib_getroute.c + * + * Copyright (C) 2019 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "netutils/netlib.h" + +#if defined(CONFIG_NETLINK_ROUTE) && defined(CONFIG_NET_ROUTE) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct netlib_sendto_request_s +{ + struct nlmsghdr hdr; + struct rtgenmsg gen; +}; + +struct netlib_recvfrom_response_s +{ + struct nlmsghdr hdr; + struct rtmsg rte; + struct rtattr attr; + + /* Attribute data and additional attributes follow */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int copy_address(FAR struct sockaddr_storage *dest, FAR void *src, + unsigned int addrlen, unsigned int maxaddr, + sa_family_t family) +{ + DEBUGASSERT(addrlen == maxaddr); + if (addrlen > maxaddr) + { + fprintf(stderr, "ERROR: Bad address length: %u\n", addrlen); + return -EIO; + } + + dest->ss_family = family; + memcpy(dest->ss_data, src, addrlen); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netlib_get_route + * + * Description: + * Return a snapshot of the routing table for the selected address family. + * + * Parameters: + * rtelist - The location to store the list of devices. + * nentries - The size of the provided 'rtelist' in number of entries. + * The size of one entry is given by sizeof(struct rtentry); + * family - Address family. See AF_* definitions in sys/socket.h. + * + * Return: + * The number of routing table entries read is returned on success; a + * negated errno value is returned on failure. + * + ****************************************************************************/ + +ssize_t netlib_get_route(FAR struct rtentry *rtelist, + unsigned int nentries, sa_family_t family) +{ + struct netlib_sendto_request_s req; + struct netlib_recvfrom_response_s resp; + struct sockaddr_nl addr; + static unsigned int seqno = 0; + unsigned int thiseq; + unsigned int maxaddr; + ssize_t nsent; + ssize_t nrecvd; + size_t ncopied = 0; + pid_t pid; + bool enddump; + int fd; + int ret; + + /* Create a NetLink socket with NETLINK_ROUTE protocol */ + + fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + if (fd < 0) + { + int errcode = errno; + fprintf(stderr, "ERROR: socket() failed: %d\n", errcode); + return -errcode; + } + + /* Bind the socket so that we can use send() and receive() */ + + pid = getpid(); + addr.nl_family = AF_NETLINK; + addr.nl_pad = 0; + addr.nl_pid = pid; + addr.nl_groups = RTM_GETROUTE; + + ret = bind(fd, (FAR const struct sockaddr *)&addr, + sizeof( struct sockaddr_nl)); + if (fd < 0) + { + int errcode = errno; + fprintf(stderr, "ERROR: bind() failed: %d\n", errcode); + ret = -errcode; + goto errout_with_socket; + } + + /* Initialize the request */ + + thiseq = ++seqno; + + memset(&req, 0, sizeof(req)); + req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); + req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + req.hdr.nlmsg_seq = thiseq; + req.hdr.nlmsg_type = RTM_GETROUTE; + req.hdr.nlmsg_pid = pid; + req.gen.rtgen_family = family; + + nsent = send(fd, &req, req.hdr.nlmsg_len, 0); + if (nsent < 0) + { + int errcode = errno; + fprintf(stderr, "ERROR: send() failed: %d\n", errcode); + ret = -errcode; + goto errout_with_socket; + } + + /* Read the response(s) */ + + maxaddr = sizeof(struct sockaddr_storage) - sizeof(sa_family_t); + + for (enddump = false; !enddump; ) + { + /* Receive the next device response */ + + nrecvd = recv(fd, &resp, sizeof(struct netlib_recvfrom_response_s), 0); + if (nrecvd < 0) + { + int errcode = errno; + fprintf(stderr, "ERROR: recv() failed: %d\n", errcode); + ret = -errcode; + goto errout_with_socket; + } + + /* Verify the data and transfer the device list to the caller */ + + if (nrecvd != sizeof(struct netlib_recvfrom_response_s) || + resp.hdr.nlmsg_len < sizeof(struct nlmsghdr) || + resp.hdr.nlmsg_len != nrecvd) + { + fprintf(stderr, "ERROR: Bad message\n"); + ret = -EIO; + goto errout_with_socket; + } + + /* The sequence number in the response should match the sequence + * number in the request (since we created the socket, this should + * always be true). + */ + + if (resp.hdr.nlmsg_seq != thiseq) + { + fprintf(stderr, "ERROR: Bad sequence number in response\n"); + ret = -EIO; + goto errout_with_socket; + } + + /* This should be a routing table response */ + + if (resp.rte.rtm_table != RT_TABLE_MAIN) + { + fprintf(stderr, "ERROR: Not a routing table response\n"); + ret = -EIO; + goto errout_with_socket; + } + + /* Copy the routing table entry to the caller's buffer */ + + switch (resp.hdr.nlmsg_type) + { + case NLMSG_DONE: + enddump = true; + break; + + case RTM_NEWLINK: + break; /* Ignore any link information */ + + case RTM_NEWROUTE: + { + FAR struct rtentry *dest; + FAR struct rtattr *attr; + int len; + + DEBUGASSERT(resp.rte.rtm_family == family); + + /* Decode the response */ + + dest = &rtelist[ncopied]; + memset(dest, 0, sizeof(struct rtentry)); + + attr = &resp.attr; + len = RTA_PAYLOAD(attr); + + for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) + { + unsigned int attrlen = RTA_PAYLOAD(attr); + + switch (attr->rta_type) + { + case RTA_DST: /* The destination network */ + ret = copy_address(&dest->rt_dst, RTA_DATA(attr), + attrlen, maxaddr, family); + if (ret < 0) + { + goto errout_with_socket; + } + + break; + + case RTA_SRC: /* The source address mask */ + break; + + case RTA_GENMASK: /* The network address mask */ + ret = copy_address(&dest->rt_genmask, RTA_DATA(attr), + attrlen, maxaddr, family); + if (ret < 0) + { + goto errout_with_socket; + } + + break; + + case RTA_GATEWAY: /* Route packets via this router */ + ret = copy_address(&dest->rt_gateway, RTA_DATA(attr), + attrlen, maxaddr, family); + if (ret < 0) + { + goto errout_with_socket; + } + + break; + + default: + break; + } + } + + ncopied++; + } + break; + + default: + fprintf(stderr, "ERROR: Message type %u, length %lu\n", + resp.hdr.nlmsg_type, (unsigned long)resp.hdr.nlmsg_len); + ret = -EIO; + goto errout_with_socket; + } + } + + close(fd); + return ncopied; + +errout_with_socket: + close(fd); + return ret; +} + +#endif /* CONFIG_NETLINK_ROUTE && CONFIG_NET_ROUTE */ diff --git a/wireless/wapi/src/network.c b/wireless/wapi/src/network.c index c31cf537e..fdc5b43a6 100644 --- a/wireless/wapi/src/network.c +++ b/wireless/wapi/src/network.c @@ -119,19 +119,19 @@ static int wapi_act_route_gw(int sock, int act, /* Set target. */ - sin = (struct sockaddr_in *)&rt.rt_dst; + sin = (FAR struct sockaddr_in *)&rt.rt_dst; sin->sin_family = AF_INET; memcpy(&sin->sin_addr, target, sizeof(struct in_addr)); /* Set netmask. */ - sin = (struct sockaddr_in *)&rt.rt_genmask; + sin = (FAR struct sockaddr_in *)&rt.rt_genmask; sin->sin_family = AF_INET; memcpy(&sin->sin_addr, netmask, sizeof(struct in_addr)); /* Set gateway. */ - sin = (struct sockaddr_in *)&rt.rt_gateway; + sin = (FAR struct sockaddr_in *)&rt.rt_gateway; sin->sin_family = AF_INET; memcpy(&sin->sin_addr, gw, sizeof(struct in_addr));