From 732f0855c607da4d9551bb33e75647fbcac380ad Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 31 Mar 2017 15:09:07 -0600 Subject: [PATCH] 6loWPAN: Fleshes out framwork for IEEE802.15.4 send. But still has some gaping holes. --- include/nuttx/net/sixlowpan.h | 8 +- net/devif/devif.h | 4 +- net/sixlowpan/sixlowpan_globals.c | 9 + net/sixlowpan/sixlowpan_internal.h | 103 +++++-- net/sixlowpan/sixlowpan_send.c | 455 ++++++++++++++++++++++++----- net/sixlowpan/sixlowpan_tcpsend.c | 9 +- net/sixlowpan/sixlowpan_udpsend.c | 9 +- net/tcp/tcp_send_unbuffered.c | 12 +- 8 files changed, 510 insertions(+), 99 deletions(-) diff --git a/include/nuttx/net/sixlowpan.h b/include/nuttx/net/sixlowpan.h index b9b995cdae..1fbfee79b4 100644 --- a/include/nuttx/net/sixlowpan.h +++ b/include/nuttx/net/sixlowpan.h @@ -99,7 +99,6 @@ #define SIXLOWPAN_IPHC_TTL_255 0x03 #define SIXLOWPAN_IPHC_TTL_I 0x00 - /* Values of fields within the IPHC encoding second byte */ #define SIXLOWPAN_IPHC_CID 0x80 @@ -422,6 +421,13 @@ struct ieee802154_driver_s */ uint8_t i_dsn; + + /* i_dgramtag. Datagram tag to be put in the header of the set of + * fragments. It is used by the recipient to match fragments of the + * same payload. + */ + + uint16_t i_dgramtag; }; /* The structure of a next header compressor. This compressor is provided diff --git a/net/devif/devif.h b/net/devif/devif.h index e15f6317b8..28135f4d30 100644 --- a/net/devif/devif.h +++ b/net/devif/devif.h @@ -1,7 +1,7 @@ /**************************************************************************** * net/devif/devif.h * - * Copyright (C) 2007-2009, 2013-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2013-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * This logic was leveraged from uIP which also has a BSD-style license: @@ -170,11 +170,13 @@ #define TCP_NEWDATA (1 << 1) #define UDP_NEWDATA TCP_NEWDATA #define PKT_NEWDATA TCP_NEWDATA +#define WPAN_NEWDATA TCP_NEWDATA #define TCP_SNDACK (1 << 2) #define TCP_REXMIT (1 << 3) #define TCP_POLL (1 << 4) #define UDP_POLL TCP_POLL #define PKT_POLL TCP_POLL +#define WPAN_POLL TCP_POLL #define TCP_BACKLOG (1 << 5) #define TCP_CLOSE (1 << 6) #define TCP_ABORT (1 << 7) diff --git a/net/sixlowpan/sixlowpan_globals.c b/net/sixlowpan/sixlowpan_globals.c index 1c7c378df0..b62c3e110f 100644 --- a/net/sixlowpan/sixlowpan_globals.c +++ b/net/sixlowpan/sixlowpan_globals.c @@ -72,6 +72,15 @@ FAR struct sixlowpan_rime_sniffer_s *g_sixlowpan_sniffer; FAR uint8_t *g_rimeptr; +/* The length of the payload in the Rime buffer. + * + * The payload is what comes after the compressed or uncompressed headers + * (can be the IP payload if the IP header only is compressed or the UDP + * payload if the UDP header is also compressed) + */ + +uint8_t g_rime_payloadlen; + /* g_uncomp_hdrlen is the length of the headers before compression (if HC2 * is used this includes the UDP header in addition to the IP header). */ diff --git a/net/sixlowpan/sixlowpan_internal.h b/net/sixlowpan/sixlowpan_internal.h index 05240dafdf..3bf65fc09c 100644 --- a/net/sixlowpan/sixlowpan_internal.h +++ b/net/sixlowpan/sixlowpan_internal.h @@ -82,24 +82,45 @@ #define rimeaddr_cmp(addr1,addr2) \ (memcmp(addr1, addr2, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE) == 0) -/* Frame buffer helpers */ +/* Pointers in the Rime buffer */ -#define FRAME_RESET() \ - do \ - { \ - g_dataoffset = 0; \ - } \ - while (0) +/* Fragment header. + * + * The fragment header is used when the payload is too large to fit in a + * single IEEE 802.15.4 frame. The fragment header contains three fields: + * Datagram size, datagram tag and datagram offset. + * + * 1. Datagram size describes the total (un-fragmented) payload. + * 2. Datagram tag identifies the set of fragments and is used to match + * fragments of the same payload. + * 3. Datagram offset identifies the fragment’s offset within the un- + * fragmented payload. + * + * The fragment header length is 4 bytes for the first header and 5 + * bytes for all subsequent headers. + */ -#define FRAME_HDR_START(iob) ((iob)->io_data) -#define FRAME_HDR_SIZE(iob) g_dataoffset +#define RIME_FRAG_PTR g_rimeptr +#define RIME_FRAG_DISPATCH_SIZE 0 /* 16 bit */ +#define RIME_FRAG_TAG 2 /* 16 bit */ +#define RIME_FRAG_OFFSET 4 /* 8 bit */ -#define FRAME_DATA_START(iob) ((FAR uint8_t *)((iob)->io_data) + g_dataoffset) -#define FRAME_DATA_SIZE(iob) ((iob)->io_len - g_dataoffset) +/* Define the Rime buffer as a byte array */ -#define FRAME_REMAINING(iob) (CONFIG_NET_6LOWPAN_FRAMELEN - (iob)->io_len) -#define FRAME_SIZE(ieee,iob) \ - ((iob)->io_len) +#define RIME_IPHC_BUF (g_rimeptr + g_rime_hdrlen) + +#define RIME_HC1_PTR (g_rimeptr + g_rime_hdrlen) +#define RIME_HC1_DISPATCH 0 /* 8 bit */ +#define RIME_HC1_ENCODING 1 /* 8 bit */ +#define RIME_HC1_TTL 2 /* 8 bit */ + +#define RIME_HC1_HC_UDP_PTR (g_rimeptr + g_rime_hdrlen) +#define RIME_HC1_HC_UDP_DISPATCH 0 /* 8 bit */ +#define RIME_HC1_HC_UDP_HC1_ENCODING 1 /* 8 bit */ +#define RIME_HC1_HC_UDP_UDP_ENCODING 2 /* 8 bit */ +#define RIME_HC1_HC_UDP_TTL 3 /* 8 bit */ +#define RIME_HC1_HC_UDP_PORTS 4 /* 8 bit */ +#define RIME_HC1_HC_UDP_CHKSUM 5 /* 16 bit */ /* These are some definitions of element values used in the FCF. See the * IEEE802.15.4 spec for details. @@ -185,6 +206,37 @@ #define PACKETBUF_NUM_ADDRS 4 +/* Frame buffer helpers *****************************************************/ + +#define FRAME_RESET() \ + do \ + { \ + g_dataoffset = 0; \ + } \ + while (0) + +#define FRAME_HDR_START(iob) ((iob)->io_data) +#define FRAME_HDR_SIZE(iob) g_dataoffset + +#define FRAME_DATA_START(iob) ((FAR uint8_t *)((iob)->io_data) + g_dataoffset) +#define FRAME_DATA_SIZE(iob) ((iob)->io_len - g_dataoffset) + +#define FRAME_REMAINING(iob) (CONFIG_NET_6LOWPAN_FRAMELEN - (iob)->io_len) +#define FRAME_SIZE(ieee,iob) \ + ((iob)->io_len) + +/* General helper macros ****************************************************/ + +#define GETINT16(ptr,index) \ + ((((uint16_t)((ptr)[index]) << 8)) | ((uint16_t)(((ptr)[(index) + 1])))) +#define PUTINT16(ptr,index,value) \ + do \ + { \ + (ptr)[index] = ((uint16_t)(value) >> 8) & 0xff; \ + (ptr)[index + 1] = (uint16_t)(value) & 0xff; \ + } \ + while(0) + /**************************************************************************** * Public Types ****************************************************************************/ @@ -310,6 +362,15 @@ extern FAR struct sixlowpan_rime_sniffer_s *g_sixlowpan_sniffer; extern FAR uint8_t *g_rimeptr; +/* The length of the payload in the Rime buffer. + * + * The payload is what comes after the compressed or uncompressed headers + * (can be the IP payload if the IP header only is compressed or the UDP + * payload if the UDP header is also compressed) + */ + +extern uint8_t g_rime_payloadlen; + /* g_uncomp_hdrlen is the length of the headers before compression (if HC2 * is used this includes the UDP header in addition to the IP header). */ @@ -360,11 +421,12 @@ struct iob_s; /* Forward reference */ * ieee->i_framelist. * * Input Parameters: - * dev - The IEEE802.15.4 MAC network driver interface. - * ipv6 - IPv6 plus TCP or UDP headers. - * buf - Data to send - * len - Length of data to send - * raddr - The MAC address of the destination + * dev - The IEEE802.15.4 MAC network driver interface. + * ipv6 - IPv6 plus TCP or UDP headers. + * buf - Data to send + * len - Length of data to send + * raddr - The MAC address of the destination + * timeout - Send timeout in deciseconds * * Returned Value: * Ok is returned on success; Othewise a negated errno value is returned. @@ -379,7 +441,8 @@ struct iob_s; /* Forward reference */ int sixlowpan_send(FAR struct net_driver_s *dev, FAR const struct ipv6_hdr_s *ipv6, FAR const void *buf, - size_t len, FAR const struct rimeaddr_s *raddr); + size_t len, FAR const struct rimeaddr_s *raddr, + uint16_t timeout); /**************************************************************************** * Function: sixlowpan_hdrlen diff --git a/net/sixlowpan/sixlowpan_send.c b/net/sixlowpan/sixlowpan_send.c index cf9c8d751b..69bf3b8392 100644 --- a/net/sixlowpan/sixlowpan_send.c +++ b/net/sixlowpan/sixlowpan_send.c @@ -54,13 +54,15 @@ #include #include -#include "nuttx/net/iob.h" +#include "nuttx/semaphore.h" +#include "nuttx/net/net.h" #include "nuttx/net/netdev.h" +#include "nuttx/net/iob.h" #include "nuttx/net/ip.h" #include "iob/iob.h" #include "netdev/netdev.h" -#include "socket/socket.h" +#include "devif/devif.h" #include "tcp/tcp.h" #include "udp/udp.h" #include "sixlowpan/sixlowpan_internal.h" @@ -87,6 +89,30 @@ # error Not enough IOBs to hold one full IEEE802.14.5 packet #endif +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This is the state data provided to the send interrupt logic. No actions + * can be taken until the until we receive the TX poll, then we can call + * sixlowpan_queue_frames() with this data strurcture. + */ + +struct sixlowpan_send_s +{ + FAR struct devif_callback_s *s_cb; /* Reference to callback instance */ + sem_t s_waitsem; /* Supports waiting for driver events */ + int s_result; /* The result of the transfer */ +#ifdef CONFIG_NET_SOCKOPTS + uint16_t s_timeout; /* Send timeout in deciseconds */ + systime_t s_time; /* Last send time for determining timeout */ +#endif + FAR const struct ipv6_hdr_s *s_destip; /* Destination IP address */ + FAR const struct rimeaddr_s *s_destmac; /* Destination MAC address */ + FAR const void *s_buf; /* Data to send */ + size_t s_len; /* Length of data in buf */ +}; + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -106,6 +132,7 @@ * ****************************************************************************/ +/* REVISIT: This is use in input function, but only for sniffer on output */ static void sixlowpan_set_pktattrs(FAR struct ieee802154_driver_s *ieee, FAR const struct ipv6_hdr_s *ipv6) { @@ -206,16 +233,6 @@ static int sixlowpan_send_frame(FAR struct ieee802154_driver_s *ieee, FAR struct iob_s *iobq) { /* Prepare the frame */ -#warning Missing logic - /* Set up for the TX poll */ - /* When polled, then we need to call sixlowpan_framecreate() to create the - * frame and copy the payload data into the frame. - */ -#if 0 /* Just some notes of what needs to be done in interrupt handler */ - framer_hdrlen = sixlowpan_createframe(ieee, ieee->i_panid); - memcpy(g_rimeptr + g_rime_hdrlen, (uint8_t *)ipv6 + g_uncomp_hdrlen, len - g_uncomp_hdrlen); - iob->io_len = len - g_uncomp_hdrlen + g_rime_hdrlen; -#endif #warning Missing logic /* Notify the IEEE802.14.5 MAC driver that we have data to be sent */ #warning Missing logic @@ -225,29 +242,22 @@ static int sixlowpan_send_frame(FAR struct ieee802154_driver_s *ieee, } /**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: sixlowpan_send + * Name: sixlowpan_queue_frames * * Description: - * Process an outgoing UDP or TCP packet. Takes an IP packet and formats - * it to be sent on an 802.15.4 network using 6lowpan. Called from common - * UDP/TCP send logic. + * Process an outgoing UDP or TCP packet. This function is called from + * send interrupt logic when a TX poll is received. It formates the + * list of frames to be sent by the IEEE802.15.4 MAC driver. * - * The payload data is in the caller 'buf' and is of length 'len'. + * The payload data is in the caller 's_buf' and is of length 's_len'. * Compressed headers will be added and if necessary the packet is * fragmented. The resulting packet/fragments are put in ieee->i_framelist * and the entire list of frames will be delivered to the 802.15.4 MAC via * ieee->i_framelist. * * Input Parameters: - * dev - The IEEE802.15.4 MAC network driver interface. - * ipv6 - IPv6 plus TCP or UDP headers. - * buf - Data to send - * len - Length of data to send - * raddr - The IEEE802.15.4 MAC address of the destination + * dev - The structure of the network driver that caused the interrupt + * sinfo - Send state information * * Returned Value: * Ok is returned on success; Othewise a negated errno value is returned. @@ -260,9 +270,8 @@ static int sixlowpan_send_frame(FAR struct ieee802154_driver_s *ieee, * ****************************************************************************/ -int sixlowpan_send(FAR struct net_driver_s *dev, - FAR const struct ipv6_hdr_s *ipv6, FAR const void *buf, - size_t len, FAR const struct rimeaddr_s *raddr) +int sixlowpan_queue_frames(FAR struct net_driver_s *dev, + FAR struct sixlowpan_send_s *sinfo) { FAR struct ieee802154_driver_s *ieee = (FAR struct ieee802154_driver_s *)dev; FAR struct iob_s *iob; @@ -301,7 +310,7 @@ int sixlowpan_send(FAR struct net_driver_s *dev, /* Call the attribution when the callback comes, but set attributes here */ - sixlowpan_set_pktattrs(ieee, ipv6); + sixlowpan_set_pktattrs(ieee, sinfo->s_destip); } #endif @@ -315,9 +324,9 @@ int sixlowpan_send(FAR struct net_driver_s *dev, /* Set stream mode for all TCP packets, except FIN packets. */ - if (ipv6->proto == IP_PROTO_TCP) + if (sinfo->s_destip->proto == IP_PROTO_TCP) { - FAR const struct tcp_hdr_s *tcp = &((FAR const struct ipv6tcp_hdr_s *)ipv6)->tcp; + FAR const struct tcp_hdr_s *tcp = &((FAR const struct ipv6tcp_hdr_s *)sinfo->s_destip)->tcp; if ((tcp->flags & TCP_FIN) == 0 && (tcp->flags & TCP_CTL) != TCP_ACK) @@ -331,22 +340,22 @@ int sixlowpan_send(FAR struct net_driver_s *dev, } /* The destination address will be tagged to each outbound packet. If the - * argument raddr is NULL, we are sending a broadcast packet. + * argument destmac is NULL, we are sending a broadcast packet. */ - if (raddr == NULL) + if (sinfo->s_destmac == NULL) { memset(&dest, 0, sizeof(struct rimeaddr_s)); } else { - rimeaddr_copy(&dest, (FAR const struct rimeaddr_s *)raddr); + rimeaddr_copy(&dest, (FAR const struct rimeaddr_s *)sinfo->s_destmac); } - ninfo("Sending packet len %d\n", len); + ninfo("Sending packet len %d\n", sinfo->s_len); #ifndef CONFIG_NET_6LOWPAN_COMPRESSION_IPv6 - if (len >= CONFIG_NET_6LOWPAN_COMPRESSION_THRESHOLD) + if (sinfo->s_len >= CONFIG_NET_6LOWPAN_COMPRESSION_THRESHOLD) { /* Try to compress the headers */ @@ -363,7 +372,7 @@ int sixlowpan_send(FAR struct net_driver_s *dev, { /* Small.. use IPv6 dispatch (no compression) */ - sixlowpan_compress_ipv6hdr(ieee, ipv6); + sixlowpan_compress_ipv6hdr(ieee, sinfo->s_destip); } ninfo("Header of len %d\n", g_rime_hdrlen); @@ -383,7 +392,7 @@ int sixlowpan_send(FAR struct net_driver_s *dev, /* Check if we need to fragment the packet into several frames */ - if ((int)len - (int)g_uncomp_hdrlen > + if ((int)sinfo->s_len - (int)g_uncomp_hdrlen > (int)CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen - (int)g_rime_hdrlen) { @@ -402,7 +411,7 @@ int sixlowpan_send(FAR struct net_driver_s *dev, * The following fragments contain only the fragn dispatch. */ - ninfo("Fragmentation sending packet len %d\n", len); + ninfo("Fragmentation sending packet len %d\n", sinfo->s_len); /* Allocate an IOB to hold the first fragment, waiting if necessary. */ @@ -417,28 +426,52 @@ int sixlowpan_send(FAR struct net_driver_s *dev, iob->io_pktlen = 0; /* Create 1st Fragment */ - /* Add the frame header. */ + /* Add the frame header */ - verify = sixlowpan_hdrlen(ieee, ieee->i_panid); + verify = sixlowpan_framecreate(ieee, iob, ieee->i_panid); DEBUGASSERT(vreify == framer_hdrlen); UNUSED(verify); /* Move HC1/HC06/IPv6 header */ -# warning Missing logic - /* FRAG1 dispatch + header - * Note that the length is in units of 8 bytes + memmove(g_rimeptr + SIXLOWPAN_FRAG1_HDR_LEN, g_rimeptr, g_rime_hdrlen); + + /* Setup up the fragment header. + * + * The fragment header contains three fields: Datagram size, datagram + * tag and datagram offset: + * + * 1. Datagram size describes the total (un-fragmented) payload. + * 2. Datagram tag identifies the set of fragments and is used to + * match fragments of the same payload. + * 3. Datagram offset identifies the fragment’s offset within the un- + * fragmented payload. + * + * The fragment header length is 4 bytes for the first header and 5 + * bytes for all subsequent headers. */ -# warning Missing logic - /* Copy payload and send */ -# warning Missing logic + PUTINT16(RIME_FRAG_PTR, RIME_FRAG_DISPATCH_SIZE, + ((SIXLOWPAN_DISPATCH_FRAG1 << 8) | sinfo->s_len)); + PUTINT16(RIME_FRAG_PTR, RIME_FRAG_TAG, ieee->i_dgramtag); + ieee->i_dgramtag++; - /* Check TX result. */ -# warning Missing logic + /* Copy payload and enqueue */ + + g_rime_hdrlen += SIXLOWPAN_FRAG1_HDR_LEN; + g_rime_payloadlen = + (CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen - g_rime_hdrlen) & 0xf8; + + memcpy(g_rimeptr + g_rime_hdrlen, + (uint8_t *) sinfo->s_destip + g_uncomp_hdrlen, g_rime_payloadlen); + iob->io_len += g_rime_payloadlen + g_rime_hdrlen; /* Set outlen to what we already sent from the IP payload */ -# warning Missing logic + + outlen = g_rime_payloadlen + g_uncomp_hdrlen; + + ninfo("First fragment: len %d, tag %d\n", + g_rime_payloadlen, ieee->i_dgramtag); /* Add the first frame to the IOB queue */ @@ -449,13 +482,11 @@ int sixlowpan_send(FAR struct net_driver_s *dev, iob->io_pktlen = iob->io_len; - /* Create following fragments - * Datagram tag is already in the buffer, we need to set the - * FRAGN dispatch and for each fragment, the offset - */ -# warning Missing logic + /* Create following fragments */ - while (outlen < len) + g_rime_hdrlen = SIXLOWPAN_FRAGN_HDR_LEN; + + while (outlen < sinfo->s_len) { /* Allocate an IOB to hold the next fragment, waiting if * necessary. @@ -471,11 +502,47 @@ int sixlowpan_send(FAR struct net_driver_s *dev, iob->io_offset = 0; iob->io_pktlen = 0; - /* Copy payload */ -# warning Missing logic + /* Add the frame header */ + + verify = sixlowpan_framecreate(ieee, iob, ieee->i_panid); + DEBUGASSERT(vreify == framer_hdrlen); + UNUSED(verify); + + /* Move HC1/HC06/IPv6 header */ + + memmove(g_rimeptr + SIXLOWPAN_FRAGN_HDR_LEN, g_rimeptr, g_rime_hdrlen); + + /* Setup up the fragment header */ + + PUTINT16(RIME_FRAG_PTR, RIME_FRAG_DISPATCH_SIZE, + ((SIXLOWPAN_DISPATCH_FRAGN << 8) | sinfo->s_len)); + PUTINT16(RIME_FRAG_PTR, RIME_FRAG_TAG, ieee->i_dgramtag); + RIME_FRAG_PTR[RIME_FRAG_OFFSET] = outlen >> 3; + + /* Copy payload and enqueue */ + + if (sinfo->s_len - outlen < g_rime_payloadlen) + { + /* Last fragment */ + + g_rime_payloadlen = sinfo->s_len - outlen; + } + else + { + g_rime_payloadlen = + (CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen - g_rime_hdrlen) & 0xf8; + } + + memcpy(g_rimeptr + g_rime_hdrlen, (FAR uint8_t *) sinfo->s_destip + outlen, + g_rime_payloadlen); + iob->io_len = g_rime_payloadlen + g_rime_hdrlen; + + /* Set outlen to what we already sent from the IP payload */ + + outlen += (g_rime_payloadlen + g_uncomp_hdrlen); ninfo("sixlowpan output: fragment offset %d, len %d, tag %d\n", - outlen >> 3, g_rime_payloadlen, g_mytag); + outlen >> 3, g_rime_payloadlen, ieee->i_dgramtag); /* Add the next frame to the tail of the IOB queue */ @@ -484,16 +551,13 @@ int sixlowpan_send(FAR struct net_driver_s *dev, /* Keep track of the total amount of data queue */ ieee->i_framelist->io_pktlen += iob->io_len; - - /* Check tx result. */ -# warning Missing logic } /* Send the list of frames */ return sixlowpan_send_frame(ieee, ieee->i_framelist); #else - nerr("ERROR: Packet too large: %d\n", len); + nerr("ERROR: Packet too large: %d\n", sinfo->s_len); nerr(" Cannot to be sent without fragmentation support\n"); nerr(" dropping packet\n"); @@ -502,6 +566,8 @@ int sixlowpan_send(FAR struct net_driver_s *dev, } else { + int verify; + /* The packet does not need to be fragmented just copy the "payload" * and send in one frame. */ @@ -518,11 +584,17 @@ int sixlowpan_send(FAR struct net_driver_s *dev, iob->io_offset = 0; iob->io_pktlen = 0; - /* Format the single frame */ -# warning Missing logic + /* Add the frame header */ - /* Send the single frame */ -# warning Missing logic + verify = sixlowpan_framecreate(ieee, iob, ieee->i_panid); + DEBUGASSERT(vreify == framer_hdrlen); + UNUSED(verify); + + /* Copy the payload and queue */ + + memcpy(g_rimeptr + g_rime_hdrlen, (uint8_t *)sinfo->s_destip + g_uncomp_hdrlen, + sinfo->s_len - g_uncomp_hdrlen); + iob->io_len = sinfo->s_len - g_uncomp_hdrlen + g_rime_hdrlen; /* Add the first frame to the IOB queue */ @@ -535,5 +607,252 @@ int sixlowpan_send(FAR struct net_driver_s *dev, return sixlowpan_send_frame(ieee, iob); } } +/**************************************************************************** + * Function: send_timeout + * + * Description: + * Check for send timeout. + * + * Input Parameters: + * sinfo - Send state structure reference + * + * Returned Value: + * TRUE:timeout FALSE:no timeout + * + * Assumptions: + * The network is locked + * + ****************************************************************************/ + +#ifdef CONFIG_NET_SOCKOPTS +static inline int send_timeout(FAR struct sixlowpan_send_s *sinfo) +{ + /* Check for a timeout. Zero means none and, in that case, we will let + * the send wait forever. + */ + + if (sinfo->s_timeout != 0) + { + /* Check if the configured timeout has elapsed */ + /* REVISIT: I would need a psock to do this */ + + //return net_timeo(sinfo->s_time, psock->s_sndtimeo); +#warning Missing logic + } + + /* No timeout */ + + return FALSE; +} +#endif /* CONFIG_NET_SOCKOPTS */ + +/**************************************************************************** + * Function: tcpsend_interrupt + * + * Description: + * This function is called from the interrupt level to perform the actual + * send operation when polled by the lower, device interfacing layer. + * + * Parameters: + * dev - The structure of the network driver that caused the interrupt + * conn - The connection structure associated with the socket + * flags - Set of events describing why the callback was invoked + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +static uint16_t send_interrupt(FAR struct net_driver_s *dev, + FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct sixlowpan_send_s *sinfo = (FAR struct sixlowpan_send_s *)pvpriv; + + ninfo("flags: %04x: %d\n", flags); + + /* Check if the IEEE802.15.4 went down */ + + if ((flags & NETDEV_DOWN) != 0) + { + ninfo("Device is down\n"); + sinfo->s_result = -ENOTCONN; + goto end_wait; + } + + /* Check for a poll for TX data. */ + + if ((flags & WPAN_NEWDATA) == 0) + { + DEBUGASSERT((flags & WPAN_POLL) != 0); + + /* Transfer the frame listto the IEEE802.15.4 MAC device */ + + sinfo->s_result = sixlowpan_queue_frames(dev, sinfo); + flags &= ~WPAN_POLL; + goto end_wait; + } + +#ifdef CONFIG_NET_SOCKOPTS + /* All data has been sent and we are just waiting for ACK or re-transmit + * indications to complete the send. Check for a timeout. + */ + + if (send_timeout(sinfo)) + { + /* Yes.. report the timeout */ + + nwarn("WARNING: SEND timeout\n"); + sinfo->s_result = -ETIMEDOUT; + goto end_wait; + } +#endif /* CONFIG_NET_SOCKOPTS */ + + /* Continue waiting */ + + return flags; + +end_wait: + /* Do not allow any further callbacks */ + + sinfo->s_cb->flags = 0; + sinfo->s_cb->priv = NULL; + sinfo->s_cb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&sinfo->s_waitsem); + return flags; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sixlowpan_send + * + * Description: + * Process an outgoing UDP or TCP packet. Takes an IP packet and formats + * it to be sent on an 802.15.4 network using 6lowpan. Called from common + * UDP/TCP send logic. + * + * The payload data is in the caller 'buf' and is of length 'len'. + * Compressed headers will be added and if necessary the packet is + * fragmented. The resulting packet/fragments are put in ieee->i_framelist + * and the entire list of frames will be delivered to the 802.15.4 MAC via + * ieee->i_framelist. + * + * Input Parameters: + * dev - The IEEE802.15.4 MAC network driver interface. + * ipv6 - IPv6 plus TCP or UDP headers. + * buf - Data to send + * len - Length of data to send + * raddr - The IEEE802.15.4 MAC address of the destination + * timeout - Send timeout in deciseconds + * + * Returned Value: + * Ok is returned on success; Othewise a negated errno value is returned. + * This function is expected to fail if the driver is not an IEEE802.15.4 + * MAC network driver. In that case, the UDP/TCP will fall back to normal + * IPv4/IPv6 formatting. + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +int sixlowpan_send(FAR struct net_driver_s *dev, + FAR const struct ipv6_hdr_s *ipv6, FAR const void *buf, + size_t len, FAR const struct rimeaddr_s *raddr, + uint16_t timeout) +{ + struct sixlowpan_send_s sinfo; + + /* Initialize the send state structure */ + + sem_init(&sinfo.s_waitsem, 0, 0); + (void)sem_setprotocol(&sinfo.s_waitsem, SEM_PRIO_NONE); + + sinfo.s_result = -EBUSY; + sinfo.s_destip = ipv6; + sinfo.s_destmac = raddr; + sinfo.s_buf = buf; + sinfo.s_len = len; + +#ifdef CONFIG_NET_SOCKOPTS + sinfo.s_timeout = timeout; + sinfo.s_time = clock_systimer(); +#endif + + /* Set the socket state to sending */ + /* REVISIT: We would need a psock to do this. Already done by caller. */ + + //psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); +#warning Missing logic + + net_lock(); + if (len > 0) + { + /* Allocate resources to receive a callback */ + /* REVISIT: Need a psock instance to get the second argument + * to devif_conn_callback_alloc(). + */ + + sinfo.s_cb = devif_callback_alloc(dev, NULL); + if (sinfo.s_cb != NULL) + { + int ret; + + /* Set up the callback in the connection */ + + sinfo.s_cb->flags = (NETDEV_DOWN | WPAN_POLL); + sinfo.s_cb->priv = (FAR void *)&sinfo; + sinfo.s_cb->event = send_interrupt; + + /* Notify the the IEEE802.15.4 MAC that we have data to send. */ + /* REVISIT: Need a psock instance for the arguments to + * send_txnotify(). + */ + + // send_txnotify(psock, conn); +#warning Missing logic + + /* Wait for the send to complete or an error to occur: NOTES: (1) + * net_lockedwait will also terminate if a signal is received, (2) interrupts + * may be disabled! They will be re-enabled while the task sleeps and + * automatically re-enabled when the task restarts. + */ + + ret = net_lockedwait(&sinfo.s_waitsem); + if (ret < 0) + { + sinfo.s_result = -get_errno(); + } + + /* Make sure that no further interrupts are processed */ + /* REVISIT: Need a psock instance to get the arguments + * to devif_conn_callback_free(). + */ + + //devif_conn_callback_free(conn, sinfo.s_cb, NULL); +#warning Missing logic + } + } + + sem_destroy(&sinfo.s_waitsem); + net_unlock(); + + /* Set the socket state to idle */ + /* REVISIT: Again, need a psock instance */ + + // psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); +#warning Missing logic + + return (sinfo.s_result < 0 ? sinfo.s_result : len); +} #endif /* CONFIG_NET_6LOWPAN */ diff --git a/net/sixlowpan/sixlowpan_tcpsend.c b/net/sixlowpan/sixlowpan_tcpsend.c index 4e9f01d237..c84e04e388 100644 --- a/net/sixlowpan/sixlowpan_tcpsend.c +++ b/net/sixlowpan/sixlowpan_tcpsend.c @@ -86,6 +86,7 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, FAR struct net_driver_s *dev; struct ipv6tcp_hdr_s ipv6tcp; struct rimeaddr_s dest; + uint16_t timeout; int ret; DEBUGASSERT(psock != NULL && psock->s_crefs > 0); @@ -173,8 +174,14 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, * packet. */ +#ifdef CONFIG_NET_SOCKOPTS + timeout = psock->s_sndtimeo; +#else + timeout = 0; +#endif + ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6tcp, - buf, len, &dest); + buf, len, &dest, timeout); if (ret < 0) { nerr("ERROR: sixlowpan_send() failed: %d\n", ret); diff --git a/net/sixlowpan/sixlowpan_udpsend.c b/net/sixlowpan/sixlowpan_udpsend.c index 7f55810180..5f76245f76 100644 --- a/net/sixlowpan/sixlowpan_udpsend.c +++ b/net/sixlowpan/sixlowpan_udpsend.c @@ -86,6 +86,7 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, FAR struct net_driver_s *dev; struct ipv6udp_hdr_s ipv6udp; struct rimeaddr_s dest; + uint16_t timeout; int ret; DEBUGASSERT(psock != NULL && psock->s_crefs > 0); @@ -174,8 +175,14 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, * 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, &dest); + buf, len, &dest, timeout); if (ret < 0) { nerr("ERROR: sixlowpan_send() failed: %d\n", ret); diff --git a/net/tcp/tcp_send_unbuffered.c b/net/tcp/tcp_send_unbuffered.c index 6c3688d85a..5a2ccc98c4 100644 --- a/net/tcp/tcp_send_unbuffered.c +++ b/net/tcp/tcp_send_unbuffered.c @@ -129,7 +129,7 @@ struct send_s * TRUE:timeout FALSE:no timeout * * Assumptions: - * Running at the interrupt level + * The network is locked. * ****************************************************************************/ @@ -139,7 +139,7 @@ static inline int send_timeout(FAR struct send_s *pstate) FAR struct socket *psock; /* Check for a timeout configured via setsockopts(SO_SNDTIMEO). - * If none... we well let the send wait forever. + * If none... we will let the send wait forever. */ psock = pstate->snd_sock; @@ -173,7 +173,7 @@ static inline int send_timeout(FAR struct send_s *pstate) * None * * Assumptions: - * Running at the interrupt level + * The network is locked. * ****************************************************************************/ @@ -224,7 +224,7 @@ static inline void tcpsend_ipselect(FAR struct net_driver_s *dev, * None * * Assumptions: - * Running at the interrupt level + * The network is locked. * ****************************************************************************/ @@ -278,7 +278,7 @@ static inline bool psock_send_addrchck(FAR struct tcp_conn_s *conn) * None * * Assumptions: - * Running at the interrupt level + * The network is locked. * ****************************************************************************/ @@ -708,8 +708,6 @@ static inline void send_txnotify(FAR struct socket *psock, * In this case the process will also receive a SIGPIPE unless * MSG_NOSIGNAL is set. * - * Assumptions: - * ****************************************************************************/ ssize_t psock_tcp_send(FAR struct socket *psock,