From 76406af71b0c9b63b924c5c0725a29f522eead6f Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 2 Apr 2017 11:15:46 -0600 Subject: [PATCH] 6loWPAN: Add support for sendto() --- net/devif/ipv6_input.c | 37 ++++- net/sixlowpan/sixlowpan.h | 37 ++++- net/sixlowpan/sixlowpan_udpsend.c | 242 ++++++++++++++++++++---------- net/socket/send.c | 42 ++---- net/socket/sendto.c | 18 ++- net/tcp/tcp_input.c | 2 +- 6 files changed, 264 insertions(+), 114 deletions(-) diff --git a/net/devif/ipv6_input.c b/net/devif/ipv6_input.c index 149f06d33d..e1940bf4f0 100644 --- a/net/devif/ipv6_input.c +++ b/net/devif/ipv6_input.c @@ -255,12 +255,45 @@ int ipv6_input(FAR struct net_driver_s *dev) { #ifdef NET_TCP_HAVE_STACK case IP_PROTO_TCP: /* TCP input */ + /* Forward the IPv6 TCP packet */ + tcp_ipv6_input(dev); - break; + +#ifdef CONFIG_NET_6LOWPAN + /* TCP output comes through two different mechansims. Either from: + * + * 1. TCP socket output. For the case of TCP output to an + * IEEE802.15.4, the TCP output is caught in the socket + * send()/sendto() logic and and redirected to 6loWPAN logic. + * 2. TCP output from the TCP state machine. That will pass + * here and can be detected if d_len > 0. It will be redirected + * to 6loWPAN logic here. + */ + +#ifdef CONFIG_NET_MULTILINK + /* Handle the case where multiple link layer protocols are supported */ + + if (dev->d_len > 0 && dev->d_lltype == CONFIG_NET_6LOWPAN) +#else + if (dev->d_len > 0) #endif + { + /* Let 6loWPAN handle the TCP output */ + + sixlowpan_tcp_send(dev); + + /* Drop the packet in the d_buf */ + + goto drop; + } +#endif /* CONFIG_NET_6LOWPAN */ + break; +#endif /* NET_TCP_HAVE_STACK */ #ifdef NET_UDP_HAVE_STACK case IP_PROTO_UDP: /* UDP input */ + /* Forward the IPv6 UDP packet */ + udp_ipv6_input(dev); break; #endif @@ -269,6 +302,8 @@ int ipv6_input(FAR struct net_driver_s *dev) #ifdef CONFIG_NET_ICMPv6 case IP_PROTO_ICMP6: /* ICMP6 input */ + /* Forward the ICMPv6 packet */ + icmpv6_input(dev); break; #endif diff --git a/net/sixlowpan/sixlowpan.h b/net/sixlowpan/sixlowpan.h index d3660cb2ce..62a9074acf 100644 --- a/net/sixlowpan/sixlowpan.h +++ b/net/sixlowpan/sixlowpan.h @@ -53,7 +53,8 @@ * Public Function Prototypes ****************************************************************************/ -struct socket; /* Forward reference */ +struct socket; /* Forward reference */ +struct sockaddr; /* Forward reference */ /**************************************************************************** * Name: sixlowpan_initialize @@ -132,5 +133,39 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, size_t len); #endif +/**************************************************************************** + * Function: psock_6lowpan_udp_sendto + * + * Description: + * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) + * socket, the parameters to and 'tolen' are ignored (and the error EISCONN + * may be returned when they are not NULL and 0), and the error ENOTCONN is + * returned when the socket was not actually connected. + * + * Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Data to send + * len Length of data to send + * flags Send flags + * to Address of recipient + * tolen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately. Returned error + * number must be consistent with definition of errors reported by + * sendto(). + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock, + FAR const void *buf, + size_t len, int flags, + FAR const struct sockaddr *to, + socklen_t tolen); + #endif /* CONFIG_NET_6LOWPAN */ #endif /* _NET_SIXLOWPAN_SIXLOWPAN_H */ diff --git a/net/sixlowpan/sixlowpan_udpsend.c b/net/sixlowpan/sixlowpan_udpsend.c index c0c3148b90..ae16a23355 100644 --- a/net/sixlowpan/sixlowpan_udpsend.c +++ b/net/sixlowpan/sixlowpan_udpsend.c @@ -39,6 +39,8 @@ #include +#include +#include #include #include #include @@ -56,6 +58,159 @@ * Public Functions ****************************************************************************/ +/**************************************************************************** + * Function: psock_6lowpan_udp_sendto + * + * Description: + * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) + * socket, the parameters to and 'tolen' are ignored (and the error EISCONN + * may be returned when they are not NULL and 0), and the error ENOTCONN is + * returned when the socket was not actually connected. + * + * Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Data to send + * len Length of data to send + * flags Send flags + * to Address of recipient + * tolen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately. Returned error + * number must be consistent with definition of errors reported by + * sendto(). + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock, + FAR const void *buf, + size_t len, int flags, + FAR const struct sockaddr *to, + socklen_t tolen) +{ + FAR struct sockaddr_in6 *to6 = (FAR struct sockaddr_in6 *)to; + FAR struct udp_conn_s *conn; + FAR struct net_driver_s *dev; + struct ipv6udp_hdr_s ipv6udp; + struct rimeaddr_s destmac; + uint16_t timeout; + int ret; + + DEBUGASSERT(psock != NULL && psock->s_crefs > 0 && to != NULL); + DEBUGASSERT(psock->s_type == SOCK_DGRAM); + + if (psock == NULL || to == NULL) + { + return (ssize_t)-EINVAL; + } + + /* Make sure that this is a datagram valid socket */ + + if (psock->s_crefs <= 0 || psock->s_type != SOCK_DGRAM) + { + nerr("ERROR: Invalid socket\n"); + return (ssize_t)-EBADF; + } + + /* Make sure that the destination address is valid */ + + if (to6->sin6_family != AF_INET6 || tolen < sizeof(struct sockaddr_in6)) + { + nerr("ERROR: Invalid destination address\n"); + return (ssize_t)-EAFNOSUPPORT; + } + + /* Get the underlying UDP "connection" structure */ + + conn = (FAR struct udp_conn_s *)psock->s_conn; + DEBUGASSERT(conn != NULL); + + /* Ignore if not IPv6 domain */ + + if (conn->domain != PF_INET6) + { + nwarn("WARNING: Not IPv6\n"); + return (ssize_t)-EPROTOTYPE; + } + + /* Route outgoing message to the correct device */ + +#ifdef CONFIG_NETDEV_MULTINIC + dev = netdev_findby_ipv6addr(conn->u.ipv6.laddr, + to6->sin6_addr.in6_u.u6_addr16); +#ifdef CONFIG_NETDEV_MULTILINK + if (dev == NULL || dev->d_lltype != NET_LL_IEEE802154) +#else + if (dev == NULL) +#endif + { + nwarn("WARNING: Not routable or not IEEE802.15.4 MAC\n"); + return (ssize_t)-ENETUNREACH; + } +#else + dev = netdev_findby_ipv6addr(to6->sin6_addr.in6_u.u6_addr16); +#ifdef CONFIG_NETDEV_MULTILINK + if (dev == NULL || dev->d_lltype != NET_LL_IEEE802154) +#else + if (dev == NULL) +#endif + { + nwarn("WARNING: Not routable\n"); + return (ssize_t)-ENETUNREACH; + } +#endif + +#ifdef CONFIG_NET_ICMPv6_NEIGHBOR + /* Make sure that the IP address mapping is in the Neighbor Table */ + + ret = icmpv6_neighbor(to6->sin6_addr.in6_u.u6_addr16); + if (ret < 0) + { + nerr("ERROR: Not reachable\n"); + return (ssize_t)-ENETUNREACH; + } +#endif + + /* Initialize the IPv6/UDP headers */ +#warning Missing logic + + /* Set the socket state to sending */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); + + /* Get the Rime MAC address of the destination This assumes an encoding + * of the MAC address in the IPv6 address. + */ + + sixlowpan_rimefromip(to6->sin6_addr.in6_u.u6_addr16, &destmac); + + /* If routable, then call sixlowpan_send() to format and send the 6loWPAN + * packet. + */ + +#ifdef CONFIG_NET_SOCKOPTS + timeout = psock->s_sndtimeo; +#else + timeout = 0; +#endif + + ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6udp, + buf, len, &destmac, timeout); + if (ret < 0) + { + nerr("ERROR: sixlowpan_send() failed: %d\n", ret); + } + + /* Set the socket state to idle */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); + return ret; +} + /**************************************************************************** * Function: psock_6lowpan_udp_send * @@ -71,8 +226,7 @@ * Returned Value: * On success, returns the number of characters sent. On error, * -1 is returned, and errno is set appropriately. Returned error numbers - * must be consistent with definition of errors reported by send() or - * sendto(). + * must be consistent with definition of errors reported by send(). * * Assumptions: * Called with the network locked. @@ -83,11 +237,7 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, size_t len) { FAR struct udp_conn_s *conn; - FAR struct net_driver_s *dev; - struct ipv6udp_hdr_s ipv6udp; - struct rimeaddr_s destmac; - uint16_t timeout; - int ret; + struct sockaddr_in6 to; DEBUGASSERT(psock != NULL && psock->s_crefs > 0); DEBUGASSERT(psock->s_type == SOCK_DGRAM); @@ -114,7 +264,6 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, conn = (FAR struct udp_conn_s *)psock->s_conn; DEBUGASSERT(conn != NULL); -#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) /* Ignore if not IPv6 domain */ if (conn->domain != PF_INET6) @@ -122,79 +271,16 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, nwarn("WARNING: Not IPv6\n"); return (ssize_t)-EPROTOTYPE; } -#endif - /* Route outgoing message to the correct device */ + /* Create the 'to' address */ -#ifdef CONFIG_NETDEV_MULTINIC - dev = netdev_findby_ipv6addr(conn->u.ipv6.laddr, conn->u.ipv6.raddr); -#ifdef CONFIG_NETDEV_MULTILINK - if (dev == NULL || dev->d_lltype != NET_LL_IEEE802154) -#else - if (dev == NULL) -#endif - { - nwarn("WARNING: Not routable or not IEEE802.15.4 MAC\n"); - return (ssize_t)-ENETUNREACH; - } -#else - dev = netdev_findby_ipv6addr(conn->u.ipv6.raddr); -#ifdef CONFIG_NETDEV_MULTILINK - if (dev == NULL || dev->d_lltype != NET_LL_IEEE802154) -#else - if (dev == NULL) -#endif - { - nwarn("WARNING: Not routable\n"); - return (ssize_t)-ENETUNREACH; - } -#endif + to.sin6_family = AF_INET6; + to.sin6_port = conn->rport; /* Already network order */ + memcpy(to.sin6_addr.in6_u.u6_addr16, conn->u.ipv6.raddr, 16); -#ifdef CONFIG_NET_ICMPv6_NEIGHBOR - /* Make sure that the IP address mapping is in the Neighbor Table */ - - ret = icmpv6_neighbor(conn->u.ipv6.raddr); - if (ret < 0) - { - nerr("ERROR: Not reachable\n"); - return (ssize_t)-ENETUNREACH; - } -#endif - - /* Initialize the IPv6/UDP headers */ -#warning Missing logic - - /* Set the socket state to sending */ - - psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); - - /* Get the Rime MAC address of the destination This assumes an encoding - * of the MAC address in the IPv6 address. - */ - - sixlowpan_rimefromip(conn->u.ipv6.raddr, &destmac); - - /* If routable, then call sixlowpan_send() to format and send the 6loWPAN - * packet. - */ - -#ifdef CONFIG_NET_SOCKOPTS - timeout = psock->s_sndtimeo; -#else - timeout = 0; -#endif - - ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6udp, - buf, len, &destmac, timeout); - if (ret < 0) - { - nerr("ERROR: sixlowpan_send() failed: %d\n", ret); - } - - /* Set the socket state to idle */ - - psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); - return ret; + return psock_6lowpan_udp_sendto(psock, buf, len, 0, + (FAR const struct sockaddr *)&to, + sizeof(struct sockaddr_in6)); } #endif /* CONFIG_NET_6LOWPAN && CONFIG_NET_UDP */ diff --git a/net/socket/send.c b/net/socket/send.c index fb50549e86..2e805b4eaf 100644 --- a/net/socket/send.c +++ b/net/socket/send.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/send.c * - * Copyright (C) 2007-2014, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2014, 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -166,29 +166,18 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, ret = psock_6lowpan_tcp_send(psock, buf, len); -#ifdef CONFIG_NETDEV_MULTINIC +#if defined(CONFIG_NETDEV_MULTINIC) && defined(NET_TCP_HAVE_STACK) if (ret < 0) { /* TCP/IP packet send */ ret = psock_tcp_send(psock, buf, len); -#ifdef NET_TCP_HAVE_STACK - ret = psock_tcp_send(psock, buf, len); -#else - ret = -ENOSYS; -#endif } - -#endif /* CONFIG_NETDEV_MULTINIC */ -#else /* CONFIG_NET_6LOWPAN */ - - /* Only TCP/IP packet send */ - -#ifdef NET_TCP_HAVE_STACK - ret = psock_tcp_send(psock, buf, len); +#endif /* CONFIG_NETDEV_MULTINIC && NET_TCP_HAVE_STACK */ +#elif defined(NET_TCP_HAVE_STACK) + nsent = psock_tcp_send(psock, buf, len, flags, to, tolen); #else - ret = -ENOSYS; -#endif + nsent = -ENOSYS; #endif /* CONFIG_NET_6LOWPAN */ } #endif /* CONFIG_NET_TCP */ @@ -215,34 +204,25 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, else #endif { -#ifdef CONFIG_NET_6LOWPAN +#if defined(CONFIG_NET_6LOWPAN) /* Try 6loWPAN UDP packet send */ ret = psock_6lowpan_udp_send(psock, buf, len); -#ifdef CONFIG_NETDEV_MULTINIC +#if defined(CONFIG_NETDEV_MULTINIC) && defined(NET_UDP_HAVE_STACK) if (ret < 0) { /* UDP/IP packet send */ ret = psock_udp_send(psock, buf, len); -#ifdef NET_UDP_HAVE_STACK - ret = psock_udp_send(psock, buf, len); -#else - ret = -ENOSYS; -#endif } - -#endif /* CONFIG_NETDEV_MULTINIC */ -#else /* CONFIG_NET_6LOWPAN */ - +#endif /* CONFIG_NETDEV_MULTINIC && NET_UDP_HAVE_STACK */ +#elif defined(NET_UDP_HAVE_STACK) /* Only UDP/IP packet send */ - -#ifdef NET_UDP_HAVE_STACK + ret = psock_udp_send(psock, buf, len); #else ret = -ENOSYS; -#endif #endif /* CONFIG_NET_6LOWPAN */ } #endif /* CONFIG_NET_UDP */ diff --git a/net/socket/sendto.c b/net/socket/sendto.c index eba84f5cea..4c2798cd6c 100644 --- a/net/socket/sendto.c +++ b/net/socket/sendto.c @@ -49,6 +49,7 @@ #include #include "udp/udp.h" +#include "sixlowpan/sixlowpan.h" #include "local/local.h" #include "socket/socket.h" #include "usrsock/usrsock.h" @@ -237,11 +238,24 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, else #endif { -#ifdef NET_UDP_HAVE_STACK +#if defined(CONFIG_NET_6LOWPAN) + /* Try 6loWPAN UDP packet sendto() */ + + nsent = psock_6lowpan_udp_sendto(psock, buf, len, flags, to, tolen); + +#if defined(CONFIG_NETDEV_MULTINIC) && defined(NET_UDP_HAVE_STACK) + if (nsent < 0) + { + /* UDP/IP packet sendto */ + + nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen); + } +#endif /* CONFIG_NETDEV_MULTINIC && NET_UDP_HAVE_STACK */ +#elif defined(NET_UDP_HAVE_STACK) nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen); #else nsent = -ENOSYS; -#endif +#endif /* CONFIG_NET_6LOWPAN */ } #endif /* CONFIG_NET_UDP */ diff --git a/net/tcp/tcp_input.c b/net/tcp/tcp_input.c index 184dfebb01..1918bd3492 100644 --- a/net/tcp/tcp_input.c +++ b/net/tcp/tcp_input.c @@ -2,7 +2,7 @@ * net/tcp/tcp_input.c * Handling incoming TCP input * - * Copyright (C) 2007-2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2014, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Adapted for NuttX from logic in uIP which also has a BSD-like license: