123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888 |
- /****************************************************************************
- * net/sixlowpan/sixlowpan_input.c
- * 6LoWPAN implementation (RFC 4944 and RFC 6282)
- *
- * Copyright (C) 2017, Gregory Nutt, all rights reserved
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Derives in large part from Contiki:
- *
- * Copyright (c) 2008, Swedish Institute of Computer Science.
- * All rights reserved.
- * Authors: Adam Dunkels <adam@sics.se>
- * Nicolas Tsiftes <nvt@sics.se>
- * Niclas Finne <nfi@sics.se>
- * Mathilde Durvy <mdurvy@cisco.com>
- * Julien Abeille <jabeille@cisco.com>
- * Joakim Eriksson <joakime@sics.se>
- * Joel Hoglund <joel@sics.se>
- *
- * 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 of the Institute 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 INSTITUTE 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 INSTITUTE 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 <nuttx/config.h>
- #include <string.h>
- #include <assert.h>
- #include <errno.h>
- #include <debug.h>
- #include "nuttx/mm/iob.h"
- #include "nuttx/net/netdev.h"
- #include "nuttx/net/radiodev.h"
- #include "nuttx/net/ip.h"
- #include "nuttx/net/icmpv6.h"
- #include "nuttx/net/sixlowpan.h"
- #include "nuttx/wireless/ieee802154/ieee802154_mac.h"
- #ifdef CONFIG_NET_PKT
- # include "pkt/pkt.h"
- #endif
- #include "sixlowpan/sixlowpan_internal.h"
- #ifdef CONFIG_NET_6LOWPAN
- /****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
- /* Success return values from sixlowpan_frame_process */
- #define INPUT_PARTIAL 0 /* Frame processed successful, packet incomplete */
- #define INPUT_COMPLETE 1 /* Frame processed successful, packet complete */
- /* This is the size of a buffer large enough to hold the largest uncompressed
- * HC06 or HC1 headers.
- */
- #ifdef CONFIG_NET_TCP
- /* The basic TCP header length is TCP_HDRLEN but could include up to 16
- * additional 32-bit words of optional data.
- */
- # define UNCOMP_MAXHDR (IPv6_HDRLEN + TCP_HDRLEN + 16*sizeof(uint32_t))
- #elif defined(CONFIG_NET_UDP)
- /* The UDP header length is always 8 bytes */
- # define UNCOMP_MAXHDR (IPv6_HDRLEN + UDP_HDRLEN)
- #elif defined(CONFIG_NET_ICMPv6)
- /* The ICMPv6 header length is a mere 4 bytes */
- # define UNCOMP_MAXHDR (IPv6_HDRLEN + ICMPv6_HDRLEN)
- #else
- /* No other header type is handled. */
- # define UNCOMP_MAXHDR IPv6_HDRLEN
- #endif
- /* Buffer access helpers */
- #define IPv6BUF(dev) ((FAR struct ipv6_hdr_s *)((dev)->d_buf))
- #define TCPBUF(dev) ((FAR struct tcp_hdr_s *)&(dev)->d_buf[IPv6_HDRLEN])
- /****************************************************************************
- * Private Data
- ****************************************************************************/
- /* This big buffer could be avoided with a little more effort */
- static uint8_t g_bitbucket[UNCOMP_MAXHDR];
- /****************************************************************************
- * Private Functions
- ****************************************************************************/
- /****************************************************************************
- * Name: sixlowpan_compress_ipv6hdr
- *
- * Description:
- * IPv6 dispatch "compression" function. Packets "Compression" when only
- * IPv6 dispatch is used
- *
- * There is no compression in this case, all fields are sent
- * inline. We just add the IPv6 dispatch byte before the packet.
- *
- * 0 1 2 3
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | IPv6 Dsp | IPv6 header and payload ...
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * Input Parameters:
- * fptr - Pointer to the beginning of the frame under construction
- * bptr - Output goes here. Normally this is a known offset into d_buf,
- * may be redirected to g_bitbucket on the case of FRAGN frames.
- * proto - True: Copy the protocol header following the IPv6 header too.
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
- static void sixlowpan_uncompress_ipv6hdr(FAR uint8_t *fptr,
- FAR uint8_t *bptr)
- {
- FAR struct ipv6_hdr_s *ipv6 = (FAR struct ipv6_hdr_s *)bptr;
- /* Put uncompressed IPv6 header in d_buf. */
- g_frame_hdrlen += SIXLOWPAN_IPV6_HDR_LEN;
- memcpy(ipv6, fptr + g_frame_hdrlen, IPv6_HDRLEN);
- /* Update g_uncomp_hdrlen and g_frame_hdrlen. */
- g_frame_hdrlen += IPv6_HDRLEN;
- g_uncomp_hdrlen += IPv6_HDRLEN;
- }
- /****************************************************************************
- * Name: sixlowpan_uncompress_ipv6proto
- *
- * Description:
- * Copy the protocol header following the IPv4 header
- *
- * Input Parameters:
- * fptr - Pointer to the beginning of the frame under construction
- * bptr - Output goes here. Normally this is a known offset into d_buf,
- * may be redirected to g_bitbucket on the case of FRAGN frames.
- * proto - True: Copy the protocol header following the IPv6 header too.
- *
- * Returned Value:
- * The size of the protocol header that was copied.
- *
- ****************************************************************************/
- static uint16_t sixlowpan_uncompress_ipv6proto(FAR uint8_t *fptr,
- FAR uint8_t *bptr)
- {
- FAR struct ipv6_hdr_s *ipv6 = (FAR struct ipv6_hdr_s *)bptr;
- uint16_t protosize = 0;
- /* Copy the following protocol header. */
- switch (ipv6->proto)
- {
- #ifdef CONFIG_NET_TCP
- case IP_PROTO_TCP:
- {
- FAR struct tcp_hdr_s *tcp =
- (FAR struct tcp_hdr_s *)(fptr + g_frame_hdrlen);
- /* The TCP header length is encoded in the top 4 bits of the
- * tcpoffset field (in units of 32-bit words).
- */
- protosize = ((uint16_t)tcp->tcpoffset >> 4) << 2;
- }
- break;
- #endif
- #ifdef CONFIG_NET_UDP
- case IP_PROTO_UDP:
- protosize = sizeof(struct udp_hdr_s);
- break;
- #endif
- #ifdef CONFIG_NET_ICMPv6
- case IP_PROTO_ICMP6:
- protosize = sizeof(struct icmpv6_hdr_s);
- break;
- #endif
- default:
- nwarn("WARNING: Unrecognized proto: %u\n", ipv6->proto);
- return 0;
- }
- /* Copy the protocol header. */
- memcpy((FAR uint8_t *)ipv6 + g_uncomp_hdrlen, fptr + g_frame_hdrlen,
- protosize);
- g_frame_hdrlen += protosize;
- g_uncomp_hdrlen += protosize;
- return protosize;
- }
- /****************************************************************************
- * Public Functions
- ****************************************************************************/
- /****************************************************************************
- * Name: sixlowpan_frame_process
- *
- * Description:
- * Process an incoming 6LoWPAN frame in 'iob'.
- *
- * If its a FRAG1 or a non-fragmented frame we first uncompress the IP
- * header. The 6LoWPAN payload and possibly the uncompressed IP header
- * are then copied into d_buf. An indication is returned if the packet
- * in d_buf is complete (i.e., non-fragmented frame or and the last
- * FRAGN frame).
- *
- * NOTE: We do not check for overlapping sixlowpan fragments (that is a
- * SHALL in the RFC 4944 and should never happen)
- *
- * Input Parameters:
- * radio - The radio network device driver interface.
- * metadata - Metadata characterizing the received frame.
- * iob - The IOB containing the frame.
- *
- * Returned Value:
- * On success, a value greater than equal to zero is returned, either:
- *
- * INPUT_PARTIAL Frame processed successful, packet incomplete
- * INPUT_COMPLETE Frame processed successful, packet complete
- *
- * Otherwise a negated errno value is returned to indicate the nature of
- * the failure.
- *
- * Assumptions:
- * Network is locked
- *
- ****************************************************************************/
- static int sixlowpan_frame_process(FAR struct radio_driver_s *radio,
- FAR const void *metadata,
- FAR struct iob_s *iob)
- {
- FAR struct sixlowpan_reassbuf_s *reass;
- struct netdev_varaddr_s fragsrc;
- FAR uint8_t *fptr; /* Convenience pointer to beginning of the frame */
- FAR uint8_t *bptr; /* Used to redirect uncompressed header to the bitbucket */
- FAR uint8_t *hc1; /* Convenience pointer to HC1 data */
- FAR uint8_t *fragptr; /* Pointer to the fragmentation header */
- uint16_t fragsize = 0; /* Size of the IP packet (read from fragment) */
- uint16_t paysize; /* Size of the data payload */
- uint16_t fragtag = 0; /* Tag of the fragment */
- uint8_t fragoffset = 0; /* Offset of the fragment in the IP packet */
- uint8_t protosize = 0; /* Length of the protocol header (treated like payload) */
- bool isfrag = false; /* true: Frame is a fragment */
- bool isfrag1 = false; /* true: Frame is the first fragment of the series */
- int reqsize; /* Required buffer size */
- int hdrsize; /* Size of the IEEE802.15.4 header */
- int ret;
- /* Get a pointer to the payload following the IEEE802.15.4 frame header(s).
- * This size includes both fragmentation and FCF headers.
- */
- fptr = iob->io_data; /* Frame data is in I/O buffer */
- hdrsize = iob->io_offset; /* Offset past the MAC header */
- DEBUGASSERT((unsigned)hdrsize < iob->io_len);
- /* Initialize global data. Locking the network guarantees that we have
- * exclusive use of the global values for intermediate calculations.
- */
- g_uncomp_hdrlen = 0;
- g_frame_hdrlen = hdrsize;
- /* Since we don't support the mesh and broadcast header, the first header
- * we look for is the fragmentation header. NOTE that g_frame_hdrlen
- * already includes the fragmentation header, if presetn.
- */
- fragptr = fptr + hdrsize;
- switch ((GETUINT16(fragptr, SIXLOWPAN_FRAG_DISPATCH_SIZE) & 0xf800) >> 8)
- {
- /* First fragment of new reassembly */
- case SIXLOWPAN_DISPATCH_FRAG1:
- {
- /* Set up for the reassembly */
- fragsize = GETUINT16(fragptr, SIXLOWPAN_FRAG_DISPATCH_SIZE) & 0x07ff;
- fragtag = GETUINT16(fragptr, SIXLOWPAN_FRAG_TAG);
- g_frame_hdrlen += SIXLOWPAN_FRAG1_HDR_LEN;
- ninfo("FRAG1: fragsize=%d fragtag=%d fragoffset=%d\n",
- fragsize, fragtag, fragoffset);
- /* Drop any zero length fragments */
- if (fragsize == 0)
- {
- nwarn("WARNING: Dropping zero-length 6LoWPAN fragment\n");
- return INPUT_PARTIAL;
- }
- /* Drop the packet if it cannot fit into the d_buf */
- if (fragsize > CONFIG_NET_6LOWPAN_PKTSIZE)
- {
- nwarn("WARNING: Reassembled packet size exceeds "
- "CONFIG_NET_6LOWPAN_PKTSIZE\n");
- return -ENOSPC;
- }
- /* Extract the source address from the 'metadata'. */
- ret = sixlowpan_extract_srcaddr(radio, metadata, &fragsrc);
- if (ret < 0)
- {
- nerr("ERROR: sixlowpan_extract_srcaddr failed: %d\n", ret);
- return ret;
- }
- /* Allocate a new reassembly buffer */
- reass = sixlowpan_reass_allocate(fragtag, &fragsrc);
- if (reass == NULL)
- {
- nerr("ERROR: Failed to allocate a reassembly buffer\n");
- return -ENOMEM;
- }
- radio->r_dev.d_buf = reass->rb_buf;
- radio->r_dev.d_len = 0;
- reass->rb_pktlen = fragsize;
- /* Indicate the first fragment of the reassembly */
- bptr = reass->rb_buf;
- isfrag1 = true;
- isfrag = true;
- }
- break;
- case SIXLOWPAN_DISPATCH_FRAGN:
- {
- /* Get offset, tag, size. Offset is in units of 8 bytes. */
- fragoffset = fragptr[SIXLOWPAN_FRAG_OFFSET];
- fragtag = GETUINT16(fragptr, SIXLOWPAN_FRAG_TAG);
- fragsize = GETUINT16(fragptr, SIXLOWPAN_FRAG_DISPATCH_SIZE) & 0x07ff;
- g_frame_hdrlen += SIXLOWPAN_FRAGN_HDR_LEN;
- /* Extract the source address from the 'metadata'. */
- ret = sixlowpan_extract_srcaddr(radio, metadata, &fragsrc);
- if (ret < 0)
- {
- nerr("ERROR: sixlowpan_extract_srcaddr failed: %d\n", ret);
- return ret;
- }
- /* Find the existing reassembly buffer
- * with the same tag and source address
- */
- reass = sixlowpan_reass_find(fragtag, &fragsrc);
- if (reass == NULL)
- {
- nerr("ERROR: Failed to find a reassembly buffer for tag=%04x\n",
- fragtag);
- return -ENOENT;
- }
- if (fragsize != reass->rb_pktlen)
- {
- /* The packet is a fragment but its size does not match. */
- nwarn("WARNING: Dropping 6LoWPAN packet. Bad fragsize: %u vs %u\n",
- fragsize, reass->rb_pktlen);
- ret = -EPERM;
- goto errout_with_reass;
- }
- radio->r_dev.d_buf = reass->rb_buf;
- radio->r_dev.d_len = 0;
- ninfo("FRAGN: fragsize=%d fragtag=%d fragoffset=%d\n",
- fragsize, fragtag, fragoffset);
- ninfo("FRAGN: rb_accumlen=%d paysize=%u fragsize=%u\n",
- reass->rb_accumlen, iob->io_len - g_frame_hdrlen, fragsize);
- /* Indicate that this frame is a another fragment for reassembly */
- bptr = g_bitbucket;
- isfrag = true;
- }
- break;
- /* Not a fragment */
- default:
- /* We still need a packet buffer. But in this case, the driver should
- * have provided one.
- */
- DEBUGASSERT(radio->r_dev.d_buf != NULL);
- reass = (FAR struct sixlowpan_reassbuf_s *)radio->r_dev.d_buf;
- reass->rb_pool = REASS_POOL_RADIO;
- bptr = reass->rb_buf;
- break;
- }
- /* Process next dispatch and headers */
- hc1 = fptr + g_frame_hdrlen;
- #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
- if ((hc1[SIXLOWPAN_HC1_DISPATCH] & SIXLOWPAN_DISPATCH_IPHC_MASK) ==
- SIXLOWPAN_DISPATCH_IPHC)
- {
- ninfo("IPHC Dispatch\n");
- sixlowpan_uncompresshdr_hc06(radio, metadata,
- fragsize, iob, fptr, bptr);
- }
- else
- #endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC06 */
- #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1
- if (hc1[SIXLOWPAN_HC1_DISPATCH] == SIXLOWPAN_DISPATCH_HC1)
- {
- ninfo("HC1 Dispatch\n");
- sixlowpan_uncompresshdr_hc1(radio, metadata,
- fragsize, iob, fptr, bptr);
- }
- else
- #endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC1 */
- if (hc1[SIXLOWPAN_HC1_DISPATCH] == SIXLOWPAN_DISPATCH_IPV6)
- {
- ninfo("IPv6 Dispatch\n");
- /* Uncompress the IPv6 header */
- sixlowpan_uncompress_ipv6hdr(fptr, bptr);
- /* A protocol header will follow the IPv6 header only on a non-
- * fragmented packet or on the first fragment of a fragmented
- * packet.
- */
- if (!isfrag || isfrag1)
- {
- protosize = sixlowpan_uncompress_ipv6proto(fptr, bptr);
- }
- }
- else
- {
- /* Unknown or unsupported header */
- nwarn("WARNING: Unknown dispatch: %u\n", hc1[SIXLOWPAN_HC1_DISPATCH]);
- ret = -ENOSYS;
- goto errout_with_reass;
- }
- /* Is this the first fragment is a sequence? */
- if (isfrag1)
- {
- /* Yes.. Remember the offset from the beginning of d_buf where we
- * begin placing the data payload.
- */
- reass->rb_boffset = g_uncomp_hdrlen - protosize;
- }
- /* No.. is this a subsequent fragment in the same sequence? */
- else if (isfrag)
- {
- /* Yes, recover the offset from the beginning of the d_buf where
- * we began placing payload data.
- */
- g_uncomp_hdrlen = reass->rb_boffset;
- }
- /* Copy "payload" from the frame buffer to the IEEE802.15.4 MAC driver's
- * packet buffer, d_buf. If this frame is a first fragment or not part of
- * a fragmented packet, we have already copied the compressed headers,
- * g_uncomp_hdrlen and g_frame_hdrlen are non-zerio, fragoffset is.
- */
- paysize = iob->io_len - g_frame_hdrlen;
- if (paysize > CONFIG_NET_6LOWPAN_PKTSIZE)
- {
- nwarn("Packet dropped due to payload (%u) > packet buffer (%u)\n",
- paysize, CONFIG_NET_6LOWPAN_PKTSIZE);
- ret = -ENOSPC;
- goto errout_with_reass;
- }
- /* Sanity-check size of incoming packet to avoid buffer overflow */
- reqsize = g_uncomp_hdrlen + (fragoffset << 3) + paysize;
- if (reqsize > CONFIG_NET_6LOWPAN_PKTSIZE)
- {
- nwarn("WARNING: Required buffer size: %u+%u+%u=%u Available=%u\n",
- g_uncomp_hdrlen, (fragoffset << 3), paysize,
- reqsize, CONFIG_NET_6LOWPAN_PKTSIZE);
- ret = -ENOMEM;
- goto errout_with_reass;
- }
- memcpy(radio->r_dev.d_buf + g_uncomp_hdrlen + (fragoffset << 3),
- fptr + g_frame_hdrlen, paysize);
- /* Update reass->rb_accumlen if the frame is a fragment, reass->rb_pktlen
- * otherwise.
- */
- if (isfrag)
- {
- /* Check if it is the last fragment to be processed.
- *
- * If this is the last fragment, we may shave off any extrenous
- * bytes at the end. We must be liberal in what we accept.
- */
- reass->rb_accumlen = g_uncomp_hdrlen + (fragoffset << 3) + paysize;
- }
- else
- {
- reass->rb_pktlen = paysize + g_uncomp_hdrlen;
- }
- /* If we have a full IP packet in sixlowpan_buf, deliver it to
- * the IP stack
- */
- ninfo("rb_accumlen=%d rb_pktlen=%d paysize=%d\n",
- reass->rb_accumlen, reass->rb_pktlen, paysize);
- if (reass->rb_accumlen == 0 || reass->rb_accumlen >= reass->rb_pktlen)
- {
- ninfo("IP packet ready (length %d)\n", reass->rb_pktlen);
- radio->r_dev.d_buf = reass->rb_buf;
- radio->r_dev.d_len = reass->rb_pktlen;
- reass->rb_active = false;
- reass->rb_pktlen = 0;
- reass->rb_accumlen = 0;
- return INPUT_COMPLETE;
- }
- radio->r_dev.d_buf = NULL;
- radio->r_dev.d_len = 0;
- return INPUT_PARTIAL;
- errout_with_reass:
- sixlowpan_reass_free(reass);
- return ret;
- }
- /****************************************************************************
- * Name: sixlowpan_dispatch
- *
- * Description:
- * Inject the packet in d_buf into the network for normal packet
- * processing.
- *
- * Input Parameters:
- * radio - The IEEE802.15.4 MAC network driver interface.
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
- static int sixlowpan_dispatch(FAR struct radio_driver_s *radio)
- {
- FAR struct sixlowpan_reassbuf_s *reass;
- int ret;
- sixlowpan_dumpbuffer("Incoming packet",
- (FAR const uint8_t *)IPv6BUF(&radio->r_dev),
- radio->r_dev.d_len);
- #ifdef CONFIG_NET_PKT
- /* When packet sockets are enabled, feed the frame into the tap */
- ninfo("Packet tap\n");
- pkt_input(&radio->r_dev);
- #endif
- /* We only accept IPv6 packets. */
- ninfo("IPv6 packet dispatch\n");
- NETDEV_RXIPV6(&radio->r_dev);
- /* Give the IPv6 packet to the network layer. NOTE: If there is a
- * problem with IPv6 header, it will be silently dropped and d_len will
- * be set to zero. Oddly, ipv6_input() will return OK in this case.
- */
- ret = ipv6_input(&radio->r_dev);
- /* Free the reassemby buffer */
- reass = (FAR struct sixlowpan_reassbuf_s *)radio->r_dev.d_buf;
- DEBUGASSERT(reass != NULL);
- sixlowpan_reass_free(reass);
- return ret;
- }
- /****************************************************************************
- * Public Functions
- ****************************************************************************/
- /****************************************************************************
- * Name: sixlowpan_input
- *
- * Description:
- * Process an incoming 6LoWPAN frame.
- *
- * This function is called when the radio device driver has received an
- * frame from the network. The frame from the device driver must be
- * provided in by the IOB frame argument of the function call:
- *
- * - The frame data is in the IOB io_data[] buffer,
- * - The length of the frame is in the IOB io_len field, and
- * - The offset past and radio MAC header is provided in the io_offset
- * field.
- *
- * The frame argument may refer to a single frame (a list of length one)
- * or may it be the head of a list of multiple frames.
- *
- * - The io_flink field points to the next frame in the list (if enable)
- * - The last frame in the list will have io_flink == NULL.
- *
- * An non-NULL d_buf of size CONFIG_NET_6LOWPAN_PKTSIZE +
- * CONFIG_NET_GUARDSIZE must also be provided. The frame will be
- * decompressed and placed in the d_buf. Fragmented packets will also be
- * reassembled in the d_buf as they are received (meaning for the driver,
- * that two packet buffers are required: One for reassembly of RX packets
- * and one used for TX polling).
- *
- * After each frame is processed into d_buf, the IOB is deallocated. If
- * reassembly is incomplete, the partially reassembled packet must be
- * preserved by the radio network driver and provided again when the next
- * frame is received.
- *
- * When the packet in the d_buf is fully reassembled, it will be provided
- * to the network as with any other received packet. d_len will be set
- * the length of the uncompressed, reassembled packet.
- *
- * After the network processes the packet, d_len will be set to zero.
- * Network logic may also decide to send a response to the packet. In
- * that case, the outgoing network packet will be placed in d_buf and
- * d_len will be set to a non-zero value. That case is handled by this
- * function.
- *
- * If that case occurs, the packet will be converted to a list of
- * compressed and possibly fragmented frames and provided to the MAC
- * network driver via the req_data() method as with other TX operations.
- *
- * Input Parameters:
- * radio The radio network driver interface.
- * framelist - The head of an incoming list of frames. Normally this
- * would be a single frame. A list may be provided if
- * appropriate, however.
- * metadata - Meta data characterizing the received packet. The specific
- * type of this metadata is obfuscated and depends on the
- * type of the radio driver. This could be be either
- * (1) struct ieee802154_data_ind_s for an IEEE 802.15.4
- * radio, or (2) struct pktradio_metadata_s for a non-standard
- * packet radio.
- *
- * If there are multilple frames in the list, this metadata
- * must apply to all of the frames in the list.
- *
- * Returned Value:
- * Zero (OK) is returned if the the frame was consumed; Otherwise a negated
- * errno value is returned.
- *
- ****************************************************************************/
- int sixlowpan_input(FAR struct radio_driver_s *radio,
- FAR struct iob_s *framelist, FAR const void *metadata)
- {
- int ret = -EINVAL;
- uint8_t *d_buf_backup;
- DEBUGASSERT(radio != NULL && framelist != NULL);
- /* Sixlowpan modifies the d_buf to process fragments using reassembly
- * buffers. Save the value of d_buf on entry and set it back before
- * returning
- */
- d_buf_backup = radio->r_dev.d_buf;
- /* Verify that an frame has been provided. */
- while (framelist != NULL)
- {
- FAR struct iob_s *iob;
- /* Remove the IOB containing the frame from the device structure */
- iob = framelist;
- framelist = iob->io_flink;
- sixlowpan_dumpbuffer("Incoming frame", iob->io_data, iob->io_len);
- /* Process the frame, decompressing it into the packet buffer */
- ret = sixlowpan_frame_process(radio, metadata, iob);
- /* If the frame was a valid 6LoWPAN frame, free the IOB the held the
- * consumed frame. Otherwise, the frame must stay allocated since the
- * MAC layer will try and pass it to another receiver to see if that
- * receiver wants it.
- */
- if (ret >= 0)
- {
- iob_free(iob, IOBUSER_NET_6LOWPAN);
- }
- /* Was the frame successfully processed? Is the packet in d_buf fully
- * reassembled?
- */
- if (ret == INPUT_COMPLETE)
- {
- /* Inject the uncompressed, reassembled packet into the network */
- ret = sixlowpan_dispatch(radio);
- if (ret >= 0)
- {
- /* Check if this resulted in a request to send an outgoing
- * packet.
- */
- if (radio->r_dev.d_len > 0)
- {
- FAR struct ipv6_hdr_s *ipv6hdr;
- FAR uint8_t *buffer;
- struct netdev_varaddr_s destmac;
- size_t hdrlen;
- size_t buflen;
- /* The IPv6 header followed by TCP or UDP headers should
- * lie at the beginning of d_buf since there is no link
- * layer protocol header.
- */
- ipv6hdr = IPv6BUF(&radio->r_dev);
- /* Get the IEEE 802.15.4 MAC address of the destination.
- * This assumes an encoding of the MAC address in the IPv6
- * address.
- */
- ret = sixlowpan_nexthopaddr(radio, ipv6hdr->destipaddr,
- &destmac);
- if (ret < 0)
- {
- nerr("ERROR: Failed to get dest MAC address: %d\n",
- ret);
- goto drop;
- }
- /* The data payload should follow the IPv6 header plus
- * the protocol header.
- */
- switch (ipv6hdr->proto)
- {
- #ifdef CONFIG_NET_TCP
- case IP_PROTO_TCP:
- {
- FAR struct tcp_hdr_s *tcp = TCPBUF(&radio->r_dev);
- uint16_t tcplen;
- /* The TCP header length is encoded in the top 4
- * bits of the tcpoffset field (in units of 32-bit
- * words).
- */
- tcplen = ((uint16_t)tcp->tcpoffset >> 4) << 2;
- hdrlen = IPv6_HDRLEN + tcplen;
- }
- break;
- #endif
- #ifdef CONFIG_NET_UDP
- case IP_PROTO_UDP:
- {
- hdrlen = IPv6_HDRLEN + UDP_HDRLEN;
- }
- break;
- #endif
- #ifdef CONFIG_NET_ICMPv6
- case IP_PROTO_ICMP6:
- {
- hdrlen = IPv6_HDRLEN + ICMPv6_HDRLEN;
- }
- break;
- #endif
- default:
- {
- nwarn("WARNING: Unsupported prototype: %u\n",
- ipv6hdr->proto);
- goto drop;
- }
- }
- if (hdrlen > radio->r_dev.d_len)
- {
- nwarn("WARNING: Packet too small: Have %u need >%zu\n",
- radio->r_dev.d_len, hdrlen);
- goto drop;
- }
- /* Convert the outgoing packet into a frame list. */
- buffer = radio->r_dev.d_buf + hdrlen;
- buflen = radio->r_dev.d_len - hdrlen;
- ret = sixlowpan_queue_frames(radio, ipv6hdr, buffer,
- buflen, &destmac);
- drop:
- radio->r_dev.d_len = 0;
- /* We consumed the frame, so we must return 0. */
- ret = 0;
- }
- }
- }
- }
- /* Restore the d_buf back to it's original state */
- radio->r_dev.d_buf = d_buf_backup;
- return ret;
- }
- #endif /* CONFIG_NET_6LOWPAN */
|