modify nuttx bug of lack of files

This commit is contained in:
TangYiwen123
2021-06-11 11:25:07 +08:00
parent 4a7f51a5e9
commit 6d0f2ca39a
6752 changed files with 1528133 additions and 0 deletions
@@ -0,0 +1,317 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
if NET_6LOWPAN
config NET_6LOWPAN_NREASSBUF
int "Number of preallocated reassembly buffers"
default 2
---help---
Large IPv6 packets will be fragmented by 6LoWPAN into multiple
frames and reconstitued into a reassembly buffer on the receiving
side. Each concurrent reassembly requires one buffer. Reassembly
buffers are large: The size of the 6LoWPAN MTU plus some overhead
for the reassembly state.
Some reassembly buffers may be preallocated; some may be allocated
dynamically from the stack. The former require more static memory
usage; the later require additional CPU cycles to perform the
allocation and may effect deterministic behavior. So this is a
trade-off between resources and performance. If the number of pre-
allocated reassembly buffers are exhausted, the reassembly will
continue with dynamically allocated reassembly buffers.
This behavior can be changed with CONFIG_NET_6LOWPAN_REASS_STATIC
config NET_6LOWPAN_REASS_STATIC
bool "Static reassembly buffers"
default n
---help---
By default, reassembly buffers may be allocated dynamically from the
stack when all of the statically allocation reassembly buffers are
in use. This will require additional CPU cycles to perform the
allocation and may effect deterministic behavior. This option may
be selected to suppress all dynamica allocation of reassembly
buffers. In that case, only static reassembly buffers are available;
when those are exhausted, frames that require reassembly will be lost.
choice
prompt "6LoWPAN Compression"
default NET_6LOWPAN_COMPRESSION_HC06
config NET_6LOWPAN_COMPRESSION_IPv6
bool "IPv6 Dispatch"
---help---
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.
config NET_6LOWPAN_COMPRESSION_HC1
bool "6LoWPAN HC1"
---help---
Compress IP/UDP header using HC1 and HC_UDP
config NET_6LOWPAN_COMPRESSION_HC06
bool "6LoWPAN HC06"
---help---
Compress IP/UDP header using HC06 compression
endchoice # 6LoWPAN Compression
config NET_6LOWPAN_COMPRESSION_THRESHOLD
int "Lower compression threshold"
default 63
depends on !NET_6LOWPAN_COMPRESSION_IPv6
---help---
CONFIG_NET_6LOWPAN_COMPRESSION_THRESHOLD sets a lower threshold for
when packets should not be compressed.
config NET_6LOWPAN_MINPORT
hex "Minimum port number"
default 0xf0b0
depends on NET_6LOWPAN_COMPRESSION_HC1
---help---
HC1 compression of UDP headersis feasible only if both src and dest
ports are between CONFIG_NET_6LOWPAN_MINPORT and
CONFIG_NET_6LOWPAN_MINPORT + 15, inclusive.
All nodes must agree on the value of CONFIG_NET_6LOWPAN_MINPORT
if NET_6LOWPAN_COMPRESSION_HC06
config NET_6LOWPAN_MAXADDRCONTEXT
int "Maximum address contexts"
default 1
---help---
If we use IPHC compression, how many address contexts do we support?
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_0
hex "Address context 0 Prefix 0"
default 0xaa
---help---
Prefix 0 for address context zero (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 0)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_1
hex "Address context 0 Prefix 1"
default 0xaa
---help---
Prefix 1 for address context 0 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 0)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_2
hex "Address context 0 Prefix 2"
default 0xaa
---help---
Prefix 2 for address context 0 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 0)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_3
hex "Address context 0 Prefix 3"
default 0xaa
---help---
Prefix 3 for address context 0 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 0)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_4
hex "Address context 0 Prefix 4"
default 0xaa
---help---
Prefix 4 for address context 0 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 0)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_5
hex "Address context 0 Prefix 5"
default 0xaa
---help---
Prefix 5 for address context 0 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 0)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_6
hex "Address context 0 Prefix 6"
default 0xaa
---help---
Prefix 6 for address context 0 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 0)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_0_7
hex "Address context 0 Prefix 7"
default 0xaa
---help---
Prefix 7 for address context 0 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 0)
config NET_6LOWPAN_MAXADDRCONTEXT_PREINIT_1
bool "Pre-initialize address context 1"
default n
---help---
Preinitialize address context 1 for better header compression
(Saves up to 13 bytes per 6lowpan packet). Assumes
CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 1)
if NET_6LOWPAN_MAXADDRCONTEXT_PREINIT_1
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_1_0
hex "Address context 1 Prefix 0"
default 0xaa
---help---
Prefix 0 for address context 1 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 1)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_1_1
hex "Address context 1 Prefix 1"
default 0xaa
---help---
Prefix 1 for address context 1 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 1)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_1_2
hex "Address context 1 Prefix 2"
default 0xaa
---help---
Prefix 2 for address context 1 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 1)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_1_3
hex "Address context 1 Prefix 3"
default 0xaa
---help---
Prefix 3 for address context 1 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 1)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_1_4
hex "Address context 1 Prefix 4"
default 0xaa
---help---
Prefix 4 for address context 1 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 1)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_1_5
hex "Address context 1 Prefix 5"
default 0xaa
---help---
Prefix 5 for address context 1 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 1)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_1_6
hex "Address context 1 Prefix 6"
default 0xaa
---help---
Prefix 6 for address context 1 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 1)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_1_7
hex "Address context 1 Prefix 7"
default 0xaa
---help---
Prefix 7 for address context 1 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 1)
endif # NET_6LOWPAN_MAXADDRCONTEXT_PREINIT_1
config NET_6LOWPAN_MAXADDRCONTEXT_PREINIT_2
bool "Pre-initialize address context 2"
default n
depends on NET_6LOWPAN_MAXADDRCONTEXT_PREINIT_1
---help---
Preinitialize any address contexts for better header compression
(Saves up to 13 bytes per 6lowpan packet). Assumes
CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 2)
if NET_6LOWPAN_MAXADDRCONTEXT_PREINIT_2
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_0
hex "Address context 2 Prefix 0"
default 0xaa
---help---
Prefix 0 for address context 2 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 2)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_1
hex "Address context 2 Prefix 1"
default 0xaa
---help---
Prefix 1 for address context 2 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 2)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_2
hex "Address context 2 Prefix 2"
default 0xaa
---help---
Prefix 2 for address context 2 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 2)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_3
hex "Address context 2 Prefix 3"
default 0xaa
---help---
Prefix 3 for address context 2 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 2)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_4
hex "Address context 2 Prefix 4"
default 0xaa
---help---
Prefix 4 for address context 2 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 2)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_5
hex "Address context 2 Prefix 5"
default 0xaa
---help---
Prefix 5 for address context 2 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 2)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_6
hex "Address context 2 Prefix 6"
default 0xaa
---help---
Prefix 6 for address context 2 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 2)
config NET_6LOWPAN_MAXADDRCONTEXT_PREFIX_2_7
hex "Address context 2 Prefix 7"
default 0xaa
---help---
Prefix 7 for address context 2 (assumes CONFIG_NET_6LOWPAN_MAXADDRCONTEXT >= 2)
endif # NET_6LOWPAN_MAXADDRCONTEXT_PREINIT_2
endif # NET_6LOWPAN_COMPRESSION_HC06
config NET_6LOWPAN_EXTENDEDADDR
bool "Extended IEEE 802.15.4 address"
default n
---help---
By default, a 2-byte short address is used for the IEEE802.15.4 MAC
device's link layer address. If this option is selected, then an
8-byte extended address will be used.
All devices operating on a network have unique, 8-byte addresses,
referred to as extended addresses. A device will use either the
extended address for direct communication within the PAN or the
short 2-byte address that was allocated by the PAN coordinator when
the device associated.
config NET_6LOWPAN_MAXAGE
int "Packet reassembly timeout"
default 20
---help---
Timeout for packet reassembly at the 6lowpan layer in units of
seconds (should be < 60s)
config NET_6LOWPAN_MAX_MACTRANSMITS
int "Max MAC transmissions"
default 4
range 1 255
---help---
CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS specifies how many times the MAC
layer should resend packets if no link-layer ACK was received. This
only makes sense with the csma_driver.
config NET_6LOWPAN_PKTSIZE
int "6LoWPAN packet buffer size"
default 1294
range 590 1518
---help---
Packet buffer size. This size includes the TCP/UDP payload plus the
size of TCP/UDP header, the IP header, and the Ethernet header.
This value is related to the MTU (Maximum Transmission Unit), except
that it includes the size of the link layer header; the payload is
the MSS (Maximum Segment Size). 6LoWPAN has no link layer header (at
least in the packet buffer which is only used for re-assembly). So
for 6LoWPAN the MTU is the same as the PKTSIZE.
NOTE that this option depends on fragmentation support. By
supporting fragmentation, we can handle quite large "logical" packet
sizes. Without fragmentation support, the MTU is equal to the frame
size and that has already been selected.
config NET_6LOWPAN_DUMPBUFFER
bool "Enable dumping of buffer data"
default n
depends on DEBUG_NET_INFO
---help---
Enable dumping of all packet and frame buffers coming into and out
of the 6LoWPAN logic. This will generate a large volume of data if
selected.
endif # NET_6LOWPAN
@@ -0,0 +1,62 @@
############################################################################
# net/sixlowpan/Make.defs
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
# IEEE 802.15.4 support
ifeq ($(CONFIG_NET_6LOWPAN),y)
# Include IEEE 802.15.4 file in the build
NET_CSRCS += sixlowpan_initialize.c sixlowpan_globals.c sixlowpan_utils.c
NET_CSRCS += sixlowpan_input.c sixlowpan_framer.c sixlowpan_framelist.c
NET_CSRCS += sixlowpan_reassbuf.c
ifeq ($(CONFIG_NET_TCP),y)
NET_CSRCS += sixlowpan_tcpsend.c
endif
ifeq ($(CONFIG_NET_UDP),y)
NET_CSRCS += sixlowpan_udpsend.c
endif
ifeq ($(CONFIG_NET_ICMPv6),y)
NET_CSRCS += sixlowpan_icmpv6send.c
endif
ifeq ($(CONFIG_NET_UDP),y)
NET_CSRCS += sixlowpan_send.c
else ifeq ($(CONFIG_NET_ICMPv6),y)
NET_CSRCS += sixlowpan_send.c
endif
ifeq ($(CONFIG_NET_6LOWPAN_COMPRESSION_HC1),y)
NET_CSRCS += sixlowpan_hc1.c
endif
ifeq ($(CONFIG_NET_6LOWPAN_COMPRESSION_HC06),y)
NET_CSRCS += sixlowpan_hc06.c
endif
# Include the sixlowpan directory in the build
DEPPATH += --dep-path sixlowpan
VPATH += :sixlowpan
endif # CONFIG_NET_6LOWPAN
@@ -0,0 +1,177 @@
6LoWPAN Contents
----------------
o 6LoWPAN Addressing
o IPv6 Neighbor Discovery
o Optimal 6LoWPAN Configuration
o Star Configuration
6LoWPAN Addressing
------------------
The current 6LoWPAN implementation uses only link local, MAC-based
addressing addressing (as discussed in more detail below). Thus if you know
the node addressing, then you know the IPv6 address (and vice-versa).
As a configuration option, the 6LoWPAN implementation will use either the
node's 2-byte short address or 8-byte extended address as the MAC address
that the IPv6 address is based on. This is determined by the configuration
setting CONFIG_NET_6LOWPAN_EXTENDEDADDR. By default, the 2-byte short
address is used for the IEEE802.15.4 MAC device's link layer address. If
this option is selected, then an 8-byte extended address will be used,
instead.
All nodes operating on a network have unique, 8-byte extended address,
that was assigned before the network is configured. 6LoWPAN will use
either the extended address for direct communication within the PAN or
the short 2-byte address. The short 2-byte address, however, is allocated
by the PAN coordinator when the device associated. If short addresses are
used, the network cannot be brought up until is is associated.
Node addressing is modified through IOCTL calls from application logic.
The network must be in the DOWN state when ever the node addressing is
modified. The modified node addresses will have no effect on the reported
IPv6 address until the network is brought to the UP state. The new IPv6
MAC-based addresses are only instantiated when the network transitions
from the DOWN to UP state.
IPv6 Neighbor Discovery
-----------------------
IPv6 Neighbor Discovery is not supported. The current ICMPv6 and neighbor-
related logic only works with Ethernet MAC. For 6LoWPAN, a new more
conservative IPv6 neighbor discovery is provided by RFC 6775 which is not
currently supported. With IPv6 neighbor discovery, any IPv6 address may be
associated with any short or extended address. In fact, that is the whole
purpose of the neighbor discover logic: It plays the same role as ARP in
IPv4; it ultimately just manages a neighbor table that, like the arp table,
provides the mapping between IP addresses and node addresses.
The NuttX, Contiki-based 6LoWPAN implementation circumvents the need for
the neighbor discovery logic by using only MAC-based addressing, i.e., the
lower two or eight bytes of the IP address are the node address.
Most of the 6LoWPAN compression algorithms exploit this kind of addressing
to compress the IPv6 address to nothing but a single bit indicating that the
IP address derives from the node address. In this use case, IPv6 neighbor
discover is not useful: If we want to use IPv6 neighbor discovery, we could
dispense with the all MAC based addressing. But if we want to retain the
more compact MAC-based addressing, then we don't need IPv6 neighbor discovery.
However, it would still be nice to have enough in place to support ping6.
Full neighbor support would be necessary if we wanted to route 6LoWPAN frames
outside of the WPAN.
Optimal 6LoWPAN Configuration
-----------------------------
1. Link local IP addresses:
128 112 96 80 64 48 32 16
fe80 0000 0000 0000 xxxx xxxx xxxx xxxx
2. MAC-based IP addresses:
128 112 96 80 64 48 32 16
---- ---- ---- ---- ---- ---- ---- ----
AAAA xxxx xxxx xxxx xxxx 00ff fe00 MMMM 2-byte short address IEEE 48-bit MAC
AAAA 0000 0000 0000 NNNN NNNN NNNN NNNN 8-byte extended address IEEE EUI-64
Where MMM is the 2-byte short address XORed 0x0200. For example, the MAC
address of 0xabcd would be 0xa9cd. And NNNN NNNN NNNN NNNN is the 8-byte
extended address address XOR 02000 0000 0000 0000.
For link-local address, AAAA is 0xfe80
3. MAC based link-local addresses
128 112 96 80 64 48 32 16
---- ---- ---- ---- ---- ---- ---- ----
fe80 0000 0000 0000 0000 00ff fe00 MMMM 2-byte short address IEEE 48-bit MAC
fe80 0000 0000 0000 NNNN NNNN NNNN NNNN 8-byte extended address IEEE EUI-64
4. To be compressible, port numbers must be in the range 0xf0b0-0xf0bf,
hexadecimal. That is 61616-61631 decimal.
5. IOBs: Must be big enough to hold one IEEE802.15.4 frame (typically 127).
There must be enough IOBs to decompose the largest IPv6 packet
(CONFIG_NET_6LOWPAN_PKTSIZE, default 1294, plus per frame overhead).
Fragmentation Headers
---------------------
A fragment header is placed at the beginning of the outgoing packet just
after the MAC header 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 fragments offset within the un-
fragmented payload (in units of 8 bytes).
The length of the fragment header length is four bytes for the first header
(FRAG1) and five bytes for all subsequent headers (FRAGN). For example,
this is a HC1 compressed first frame of a packet
41 88 2a cefa 3412 cdab ### 9-byte MAC header
c50e 000b ### 4-byte FRAG1 header
42 ### SIXLOWPAN_DISPATCH_HC1
fb ### SIXLOWPAN_HC1_HC_UDP_HC1_ENCODING
e0 ### SIXLOWPAN_HC1_HC_UDP_UDP_ENCODING
00 ### SIXLOWPAN_HC1_HC_UDP_TTL
10 ### SIXLOWPAN_HC1_HC_UDP_PORTS
0000 ### SIXLOWPAN_HC1_HC_UDP_CHKSUM
104 byte Payload follows:
4f4e452064617920 48656e6e792d7065 6e6e792077617320 7069636b696e6720
757020636f726e20 696e207468652063 6f726e7961726420 7768656e2d2d7768
61636b212d2d736f 6d657468696e6720 6869742068657220 75706f6e20746865
20686561642e2027
This is the second frame of the same transfer:
41 88 2b cefa 3412 cdab ### 9-byte MAC header
e50e 000b 0d ### 5 byte FRAGN header
42 ### SIXLOWPAN_DISPATCH_HC1
fb ### SIXLOWPAN_HC1_HC_UDP_HC1_ENCODING
e0 ### SIXLOWPAN_HC1_HC_UDP_UDP_ENCODING
00 ### SIXLOWPAN_HC1_HC_UDP_TTL
10 ### SIXLOWPAN_HC1_HC_UDP_PORTS
0000 ### SIXLOWPAN_HC1_HC_UDP_CHKSUM
104 byte Payload follows:
476f6f646e657373 2067726163696f75 73206d6521272073 6169642048656e6e
792d70656e6e793b 202774686520736b 79277320612d676f 696e6720746f2066
616c6c3b2049206d 75737420676f2061 6e642074656c6c20 746865206b696e67
2e270a0a536f2073
The payload length is encoded in the LS 11-bits of the first 16-bit value:
In this example the payload size is 0x050e or 1,294. The tag is 0x000b. In
the second frame, the fifth byte contains the offset 0x0d which is 13 << 3 =
104 bytes, the size of the payload on the first packet.
Star Configuration
------------------
The 6LoWPAN stack can be specially configured as member in a star topology;
either as a endpoint on the star os the star hub. The endpoint is
created with the following settings in the configuration file:
CONFIG_NET_STAR=y
CONFIG_NET_STARPOINT=y
The CONFIG_NET_STARPOINT selection informs the endpoint 6LoWPAN stack that
it must send all frames to the hub of the star, rather than directly to the
recipient. The star hub is assumed to be the coordinator.
The star hub configuration, on the other hand, uses these setting:
CONFIG_NET_STAR=y
CONFIG_NET_STARHUB=y
CONFIG_NET_IPFORWARD=y
The CONFIG_NET_IPFORWARD selection informs the hub that if it receives any
packets that are not destined for the hub, it should forward those packets
appropriately. This affects the behavior of IPv6 packet reception logic but
does not change the behavior of the 6LoWPAN stack.
@@ -0,0 +1,263 @@
/****************************************************************************
* net/sixlowpan/sixlowpan.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef _NET_SIXLOWPAN_SIXLOWPAN_H
#define _NET_SIXLOWPAN_SIXLOWPAN_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#ifdef CONFIG_NET_6LOWPAN
/****************************************************************************
* Public Types
****************************************************************************/
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
struct net_driver_s; /* Forward reference */
struct ipv6_hdr_s; /* Forward reference */
struct socket; /* Forward reference */
struct sockaddr; /* Forward reference */
/****************************************************************************
* Name: sixlowpan_initialize
*
* Description:
* sixlowpan_initialize() is called during OS initialization at power-up
* reset. It is called from the common net_setup() function.
* sixlowpan_initialize() configures 6LoWPAN networking data structures.
* It is called prior to platform-specific driver initialization so that
* the 6LoWPAN networking subsystem is prepared to deal with network
* driver initialization actions.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void sixlowpan_initialize(void);
/****************************************************************************
* Name: psock_6lowpan_tcp_send
*
* Description:
* psock_6lowpan_tcp_send() call may be used only when the TCP socket is in
* a connected state (so that the intended recipient is known).
*
* Input Parameters:
* psock - An instance of the internal socket structure.
* buf - Data to send
* len - Length of data to send
*
* 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().
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
#ifdef CONFIG_NET_TCP
ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
size_t len);
#endif
/****************************************************************************
* Name: sixlowpan_tcp_send
*
* Description:
* TCP output comes through three 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 psock_6lowpan_tcp_send().
* 2. TCP output from the TCP state machine. That will occur
* during TCP packet processing by the TCP state meachine.
* 3. TCP output resulting from TX or timer polling
*
* Cases 2 and 3 will be handled here. Logic in ipv6_tcp_input(),
* devif_poll(), and devif_timer() detect if (1) an attempt to return with
* d_len > 0 and (2) that the device is an IEEE802.15.4 MAC network
* driver. Under those conditions, this function will be called to create
* the IEEE80215.4 frames.
*
* Input Parameters:
* dev - The network device containing the packet to be sent.
* fwddev - The network device used to send the data. This will be the
* same device except for the IP forwarding case where packets
* are sent across devices.
* ipv6 - A pointer to the IPv6 header in dev->d_buf which lies AFTER
* the L1 header. NOTE: dev->d_len must have been decremented
* by the size of any preceding MAC header.
*
* Returned Value:
* None
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
void sixlowpan_tcp_send(FAR struct net_driver_s *dev,
FAR struct net_driver_s *fwddev,
FAR struct ipv6_hdr_s *ipv6);
/****************************************************************************
* Name: sixlowpan_icmpv6_send
*
* Description:
* All outgoing ICMPv6 messages come through one of two mechanisms:
*
* 1. The output from internal ICMPv6 message passing. These outgoing
* messages will use device polling.
* 2. ICMPv6 output resulting from TX or timer polling.
*
* Both cases are handled here.
*
* Input Parameters:
* dev - The network device containing the packet to be sent.
* fwddev - The network device used to send the data. This will be the
* same device except for the IP forwarding case where packets
* are sent across devices.
* ipv6 - A pointer to the IPv6 header in dev->d_buf which lies AFTER
* the L1 header. NOTE: dev->d_len must have been decremented
* by the size of any preceding MAC header.
*
* Returned Value:
* None
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
#ifdef CONFIG_NET_ICMPv6
void sixlowpan_icmpv6_send(FAR struct net_driver_s *dev,
FAR struct net_driver_s *fwddev,
FAR struct ipv6_hdr_s *ipv6);
#endif
/****************************************************************************
* Name: psock_6lowpan_udp_send
*
* Description:
* psock_6lowpan_udp_send() call may be used with connectionlesss UDP
* sockets.
*
* Input Parameters:
* psock - An instance of the internal socket structure.
* buf - Data to send
* len - Length of data to send
*
* 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().
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
#ifdef CONFIG_NET_UDP
ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf,
size_t len);
#endif
/****************************************************************************
* Name: 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.
*
* Input 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);
/****************************************************************************
* Name: sixlowpan_udp_send
*
* Description:
* Handles forwarding a UDP packet via 6LoWPAN. This is currently only
* used by the IPv6 forwarding logic.
*
* Input Parameters:
* dev - An instance of network device state structure
* fwddev - The network device used to send the data. This will be the
* same device except for the IP forwarding case where packets
* are sent across devices.
* ipv6 - A pointer to the IPv6 header in dev->d_buf which lies AFTER
* the L1 header. NOTE: dev->d_len must have been decremented
* by the size of any preceding MAC header.
*
* Returned Value:
* None
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
#ifdef CONFIG_NET_IPFORWARD
void sixlowpan_udp_send(FAR struct net_driver_s *dev,
FAR struct net_driver_s *fwddev,
FAR struct ipv6_hdr_s *ipv6);
#endif
#endif /* CONFIG_NET_6LOWPAN */
#endif /* _NET_SIXLOWPAN_SIXLOWPAN_H */
@@ -0,0 +1,775 @@
/****************************************************************************
* net/sixlowpan/sixlowpan_framelist.c
*
* Copyright (C) 2017-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Parts of this file derive 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/wireless/ieee802154/ieee802154_mac.h>
#include "utils/utils.h"
#include "sixlowpan/sixlowpan_internal.h"
#ifdef CONFIG_NET_6LOWPAN
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
/* A single IOB must be big enough to hold a full frame. This we have to
* check at run time. A IOB must also be big enough to hold the maximum MAC
* header (25 bytes?) plus the FCS and have some amount of space left for
* the payload.
*/
#define MAX_MACHDR 25 /* REVISIT: This is IEEE 802.15.4 specific */
#if CONFIG_IOB_BUFSIZE < (SIXLOWPAN_MAC_FCSSIZE + MAX_MACHDR)
# error CONFIG_IOB_BUFSIZE too small to hold a IEEE802.14.5 frame
#endif
/* There must be at least enough IOBs to hold the full MTU. Probably still
* won't work unless there are a few more.
*/
#if CONFIG_NET_6LOWPAN_PKTSIZE > (CONFIG_IOB_BUFSIZE * CONFIG_IOB_NBUFFERS)
# error Not enough IOBs to hold one full 6LoWPAN packet
#endif
/****************************************************************************
* 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:
* ipv6hdr - Pointer to the IPv6 header to "compress"
* fptr - Pointer to the beginning of the frame under construction
*
* Returned Value:
* None
*
****************************************************************************/
static int sixlowpan_compress_ipv6hdr(FAR const struct ipv6_hdr_s *ipv6hdr,
FAR uint8_t *fptr)
{
/* Indicate the IPv6 dispatch and length */
fptr[g_frame_hdrlen] = SIXLOWPAN_DISPATCH_IPV6;
g_frame_hdrlen += SIXLOWPAN_IPV6_HDR_LEN;
/* Copy the IPv6 header and adjust pointers */
memcpy(&fptr[g_frame_hdrlen], ipv6hdr, IPv6_HDRLEN);
g_frame_hdrlen += IPv6_HDRLEN;
g_uncomp_hdrlen += IPv6_HDRLEN;
return COMPRESS_HDR_INLINE;
}
/****************************************************************************
* Name: sixlowpan_protosize
*
* Description:
* Get the size of any uncompressed protocol header that follows the
* IPv6 header.
*
****************************************************************************/
static uint16_t sixlowpan_protosize(FAR const struct ipv6_hdr_s *ipv6hdr,
FAR uint8_t *fptr)
{
uint16_t protosize;
/* Copy the following protocol header, */
switch (ipv6hdr->proto)
{
#ifdef CONFIG_NET_TCP
case IP_PROTO_TCP:
{
FAR struct tcp_hdr_s *tcp =
&((FAR struct ipv6tcp_hdr_s *)ipv6hdr)->tcp;
/* 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 = UDP_HDRLEN;
break;
#endif
#ifdef CONFIG_NET_ICMPv6
case IP_PROTO_ICMP6:
protosize = ICMPv6_HDRLEN;
break;
#endif
default:
nwarn("WARNING: Unrecognized proto: %u\n", ipv6hdr->proto);
protosize = 0;
break;
}
return protosize;
}
/****************************************************************************
* Name: sixlowpan_ieee802154_metadata
*
* Description:
* Create the meta data that describes the IEEE 802.15.4 MAC header.
*
* Input Parameters:
* radio - The radio network driver instance
* destmac - The IEEE802.15.4 MAC address of the destination
* meta - Location to return the final metadata.
*
* Returned Value:
* OK is returned on success; Otherwise a negated errno value is returned.
*
****************************************************************************/
#ifdef CONFIG_WIRELESS_IEEE802154
static int sixlowpan_ieee802154_metadata(FAR struct radio_driver_s *radio,
FAR const struct netdev_varaddr_s *destmac,
FAR union sixlowpan_metadata_u *meta)
{
struct ieee802_txmetadata_s pktmeta;
int ret;
/* Reset frame meta data */
memset(&pktmeta, 0, sizeof(struct ieee802_txmetadata_s));
pktmeta.xmits = CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS;
/* Set stream mode for all TCP packets, except FIN packets. */
#if 0 /* Currently the frame type is always data */
if (ipv6->proto == IP_PROTO_TCP)
{
FAR const struct tcp_hdr_s *tcp =
&((FAR const struct ipv6tcp_hdr_s *)ipv6)->tcp;
if ((tcp->flags & TCP_FIN) == 0 &&
(tcp->flags & TCP_CTL) != TCP_ACK)
{
pktmeta.type = FRAME_ATTR_TYPE_STREAM;
}
else if ((tcp->flags & TCP_FIN) == TCP_FIN)
{
pktmeta.type = FRAME_ATTR_TYPE_STREAM_END;
}
}
#endif
/* Set the source and destination address. The source MAC address
* is a fixed size, determined by a configuration setting. The
* destination MAC address many be either short or extended.
*/
#ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR
pktmeta.sextended = TRUE;
sixlowpan_eaddrcopy(pktmeta.source.nm_addr,
&radio->r_dev.d_mac.radio.nv_addr);
#else
sixlowpan_saddrcopy(pktmeta.source.nm_addr,
&radio->r_dev.d_mac.radio.nv_addr);
#endif
/* Copy the destination node address into the meta data */
if (destmac->nv_addrlen == NET_6LOWPAN_EADDRSIZE)
{
pktmeta.dextended = TRUE;
sixlowpan_eaddrcopy(pktmeta.dest.nm_addr, destmac->nv_addr);
}
else
{
DEBUGASSERT(destmac->nv_addrlen == NET_6LOWPAN_SADDRSIZE);
sixlowpan_saddrcopy(pktmeta.dest.nm_addr, destmac->nv_addr);
}
/* Get the destination PAN ID.
*
* REVISIT: For now I am assuming that the source and destination
* PAN IDs are the same.
*/
sixlowpan_src_panid(radio, pktmeta.dpanid);
/* Based on the collected attributes and addresses, construct the MAC meta
* data structure that we need to interface with the IEEE802.15.4 MAC (we
* will update the MSDU payload size when the IOB has been setup).
*/
ret = sixlowpan_meta_data(radio, &pktmeta, &meta->ieee802154);
if (ret < 0)
{
nerr("ERROR: sixlowpan_meta_data() failed: %d\n", ret);
}
return ret;
}
#endif
/****************************************************************************
* Name: sixlowpan_pktradio_metadata
*
* Description:
* Create the meta data that describes the MAC header for a generic radio.
*
* Input Parameters:
* radio - The radio network driver instance
* destmac - The radio-specific MAC address of the destination
* meta - Location to return the final metadata.
*
* Returned Value:
* OK is returned on success; Otherwise a negated errno value is returned.
*
****************************************************************************/
#ifdef CONFIG_WIRELESS_PKTRADIO
static int sixlowpan_pktradio_metadata(FAR struct radio_driver_s *radio,
FAR const struct netdev_varaddr_s *destmac,
FAR union sixlowpan_metadata_u *meta)
{
FAR struct pktradio_metadata_s *pktmeta = &meta->pktradio;
/* Reset the meta data */
memset(pktmeta, 0, sizeof(struct pktradio_metadata_s));
/* Set the source address */
pktmeta->pm_src.pa_addrlen = radio->r_dev.d_mac.radio.nv_addrlen;
memcpy(pktmeta->pm_src.pa_addr,
radio->r_dev.d_mac.radio.nv_addr,
radio->r_dev.d_mac.radio.nv_addrlen);
/* Set the destination address.
* REVISIT: Do we need to check for multicast or broadcast addresses
* here?
*/
pktmeta->pm_dest.pa_addrlen = destmac->nv_addrlen;
memcpy(pktmeta->pm_dest.pa_addr, destmac->nv_addr, destmac->nv_addrlen);
return OK;
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_queue_frames
*
* Description:
* Process an outgoing UDP, TCP, or ICMPv6 packet. This function is
* called from send event handler when a TX poll is received. It
* formats 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 'buflen'.
* Compressed headers will be added and if necessary the packet is
* fragmented. The resulting packet/fragments are submitted to the MAC
* where they are queue for transfer.
*
* Input Parameters:
* radio - The radio network driver instance
* ipv6 - IPv6 header followed by TCP, UDP, or ICMPv6 header.
* buf - Beginning of the packet packet to send (with IPv6 + protocol
* headers)
* buflen - Length of data to send (includes IPv6 and protocol headers)
* destmac - The IEEE802.15.4 MAC address of the destination
*
* Returned Value:
* Ok is returned on success; Otherwise 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_queue_frames(FAR struct radio_driver_s *radio,
FAR const struct ipv6_hdr_s *ipv6,
FAR const void *buf, size_t buflen,
FAR const struct netdev_varaddr_s *destmac)
{
union sixlowpan_metadata_u meta;
FAR struct iob_s *iob;
FAR uint8_t *fptr;
int framer_hdrlen;
struct netdev_varaddr_s bcastmac;
uint16_t framelen;
uint16_t pktlen;
uint16_t paysize;
uint16_t outlen = 0;
uint8_t protosize;
int ret;
ninfo("buflen=%lu\n", (unsigned long)buflen);
/* 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 = 0;
protosize = 0;
/* The destination address will be tagged to each outbound packet. If the
* argument destmac is NULL, we are sending a broadcast packet.
*/
if (destmac == NULL)
{
memset(&bcastmac, 0, sizeof(struct netdev_varaddr_s));
destmac = &bcastmac;
}
/* Pre-allocate the IOB to hold frame or the first fragment, waiting if
* necessary.
*/
iob = net_ioballoc(false, IOBUSER_NET_6LOWPAN);
DEBUGASSERT(iob != NULL);
/* Initialize the IOB */
iob->io_flink = NULL;
iob->io_len = 0;
iob->io_offset = 0;
iob->io_pktlen = 0;
fptr = iob->io_data;
ninfo("Sending packet length %zd\n", buflen);
/* Get the metadata that describes the MAC header on the packet */
#ifdef CONFIG_WIRELESS_IEEE802154
#ifdef CONFIG_WIRELESS_PKTRADIO
if (radio->r_dev.d_lltype == NET_LL_IEEE802154)
#endif
{
ret = sixlowpan_ieee802154_metadata(radio, destmac, &meta);
}
#endif
#ifdef CONFIG_WIRELESS_PKTRADIO
#ifdef CONFIG_WIRELESS_IEEE802154
else
#endif
{
ret = sixlowpan_pktradio_metadata(radio, destmac, &meta);
}
#endif
/* Pre-calculate frame header length. */
framer_hdrlen = sixlowpan_frame_hdrlen(radio, &meta);
if (framer_hdrlen < 0)
{
/* Failed to determine the size of the header failed. */
nerr("ERROR: sixlowpan_frame_hdrlen() failed: %d\n", framer_hdrlen);
return framer_hdrlen;
}
/* This sill be the initial offset into io_data. Valid data begins at
* this offset and must be reflected in io_offset.
*/
g_frame_hdrlen = framer_hdrlen;
iob->io_offset = framer_hdrlen;
#ifndef CONFIG_NET_6LOWPAN_COMPRESSION_IPv6
if (buflen >= CONFIG_NET_6LOWPAN_COMPRESSION_THRESHOLD)
{
/* Try to compress the headers */
#if defined(CONFIG_NET_6LOWPAN_COMPRESSION_HC1)
ret = sixlowpan_compresshdr_hc1(radio, ipv6, destmac, fptr);
#elif defined(CONFIG_NET_6LOWPAN_COMPRESSION_HC06)
ret = sixlowpan_compresshdr_hc06(radio, ipv6, destmac, fptr);
#else
# error No compression specified
#endif
}
else
#endif /* !CONFIG_NET_6LOWPAN_COMPRESSION_IPv6 */
{
/* Small.. use IPv6 dispatch (no compression) */
ret = sixlowpan_compress_ipv6hdr(ipv6, fptr);
}
/* Get the size of any uncompressed protocol headers */
if (ret == COMPRESS_HDR_INLINE)
{
protosize = sixlowpan_protosize(ipv6, fptr);
}
ninfo("Header of length=%u protosize=%u\n", g_frame_hdrlen, protosize);
/* Get the maximum packet size supported by this radio. */
ret = sixlowpan_radio_framelen(radio);
if (ret < 0)
{
nerr("ERROR: sixlowpan_radio_framelen() failed: %d\n", ret);
return ret;
}
/* Limit to the maximum size supported by the IOBs */
if (ret > CONFIG_IOB_BUFSIZE)
{
ret = CONFIG_IOB_BUFSIZE;
}
/* Reserve space at the end for any FCS that the hardware may include
* in the payload.
*/
ret -= SIXLOWPAN_MAC_FCSSIZE;
if (ret < MAX_MACHDR || ret > UINT16_MAX)
{
nerr("ERROR: Invalid frame size: %d\n", ret);
return ret;
}
framelen = (uint16_t)ret;
/* Check if we need to fragment the packet into several frames.
* We may need to reserve space at the end of the frame for a 2-byte FCS
*/
if (buflen > (framelen - g_frame_hdrlen - protosize))
{
/* qhead will hold the generated frame list; frames will be
* added at qtail.
*/
FAR struct sixlowpan_reassbuf_s *reass;
FAR struct iob_s *qhead;
FAR struct iob_s *qtail;
FAR uint8_t *frame1;
FAR uint8_t *fragptr;
uint16_t frag1_hdrlen;
/* Recover the reassembly buffer from the driver d_buf. */
reass = (FAR struct sixlowpan_reassbuf_s *)radio->r_dev.d_buf;
DEBUGASSERT(reass != NULL);
/* The outbound IPv6 packet is too large to fit into a single 15.4
* packet, so we fragment it into multiple packets and send them.
* The first fragment contains frag1 dispatch, then
* IPv6/HC1/HC06/HC_UDP dispatchs/headers.
* The following fragments contain only the fragn dispatch.
*/
ninfo("Sending fragmented packet length %zd\n", buflen);
/* Create 1st Fragment */
/* Move HC1/HC06/IPv6 header to make space for the FRAG1 header at the
* beginning of the frame.
*/
fragptr = fptr + framer_hdrlen;
memmove(fragptr + SIXLOWPAN_FRAG1_HDR_LEN, fragptr,
g_frame_hdrlen - framer_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 fragments offset within the
* unfragmented payload.
*
* The fragment header length is 4 bytes for the first header and 5
* bytes for all subsequent headers.
*/
pktlen = buflen + g_uncomp_hdrlen + protosize;
PUTHOST16(fragptr, SIXLOWPAN_FRAG_DISPATCH_SIZE,
((SIXLOWPAN_DISPATCH_FRAG1 << 8) | pktlen));
PUTHOST16(fragptr, SIXLOWPAN_FRAG_TAG, reass->rb_dgramtag);
g_frame_hdrlen += SIXLOWPAN_FRAG1_HDR_LEN;
/* Copy any uncompressed protocol headers that must appear only in th
* first fragment.
*/
if (protosize > 0)
{
FAR uint8_t *src = (FAR uint8_t *)ipv6 + IPv6_HDRLEN;
memcpy(fptr + g_frame_hdrlen, src, protosize);
}
/* Copy payload and enqueue. NOTE that the size is a multiple of eight
* bytes.
*/
paysize = (framelen - g_frame_hdrlen) & ~7;
memcpy(fptr + g_frame_hdrlen + protosize, buf, paysize - protosize);
/* Set outlen to what we already sent from the IP payload */
iob->io_len = paysize + g_frame_hdrlen;
outlen = paysize;
ninfo("First fragment: length %d, tag %d\n",
paysize, reass->rb_dgramtag);
sixlowpan_dumpbuffer("Outgoing frame",
(FAR const uint8_t *)iob->io_data, iob->io_len);
/* Add the first frame to the IOB queue */
ninfo("Queuing frame io_len=%u io_offset=%u\n",
iob->io_len, iob->io_offset);
qhead = iob;
qtail = iob;
/* Keep track of the total amount of data queue */
iob->io_pktlen = iob->io_len;
/* Create following fragments */
frame1 = iob->io_data;
frag1_hdrlen = g_frame_hdrlen;
while (outlen < (buflen + protosize))
{
uint16_t fragn_hdrlen;
/* Allocate an IOB to hold the next fragment, waiting if
* necessary.
*/
iob = net_ioballoc(false, IOBUSER_NET_6LOWPAN);
DEBUGASSERT(iob != NULL);
/* Initialize the IOB */
iob->io_flink = NULL;
iob->io_len = 0;
iob->io_offset = framer_hdrlen;
iob->io_pktlen = 0;
fptr = iob->io_data;
/* Copy the HC1/HC06/IPv6 header the frame header from first
* frame, into the correct location after the FRAGN header
* of subsequent frames.
*/
fragptr = fptr + framer_hdrlen;
memcpy(fragptr + SIXLOWPAN_FRAGN_HDR_LEN,
frame1 + framer_hdrlen + SIXLOWPAN_FRAG1_HDR_LEN,
frag1_hdrlen - framer_hdrlen);
fragn_hdrlen = frag1_hdrlen - SIXLOWPAN_FRAG1_HDR_LEN;
/* Setup up the FRAGN header after the frame header. */
PUTHOST16(fragptr, SIXLOWPAN_FRAG_DISPATCH_SIZE,
((SIXLOWPAN_DISPATCH_FRAGN << 8) | pktlen));
PUTHOST16(fragptr, SIXLOWPAN_FRAG_TAG, reass->rb_dgramtag);
fragptr[SIXLOWPAN_FRAG_OFFSET] = outlen >> 3;
fragn_hdrlen += SIXLOWPAN_FRAGN_HDR_LEN;
/* Copy payload and enqueue.
*
* Check for the last fragment.
*/
paysize = (framelen - fragn_hdrlen) & SIXLOWPAN_DISPATCH_FRAG_MASK;
if (paysize > buflen - outlen + protosize)
{
/* Last fragment, truncate to the correct length */
paysize = buflen - outlen + protosize;
}
memcpy(fptr + fragn_hdrlen, buf + outlen - protosize, paysize);
/* Set outlen to what we already sent from the IP payload */
iob->io_len = paysize + fragn_hdrlen;
outlen += paysize;
ninfo("Fragment offset=%d, paysize=%d, rb_dgramtag=%d\n",
outlen >> 3, paysize, reass->rb_dgramtag);
sixlowpan_dumpbuffer("Outgoing frame",
(FAR const uint8_t *)iob->io_data,
iob->io_len);
/* Add the next frame to the tail of the IOB queue */
ninfo("Queuing frame io_len=%u io_offset=%u\n",
iob->io_len, iob->io_offset);
qtail->io_flink = iob;
qtail = iob;
/* Keep track of the total amount of data queue */
qhead->io_pktlen += iob->io_len;
}
/* Submit all of the fragments to the MAC. We send all frames back-
* to-back like this to minimize any possible condition where some
* frame which is not a fragment from this sequence from intervening.
*/
for (iob = qhead; iob != NULL; iob = qhead)
{
/* Remove the IOB containing the frame from the list */
qhead = iob->io_flink;
iob->io_flink = NULL;
/* And submit the frame to the MAC */
ninfo("Submitting frame\n");
ret = sixlowpan_frame_submit(radio, &meta, iob);
if (ret < 0)
{
nerr("ERROR: sixlowpan_frame_submit() failed: %d\n", ret);
}
}
/* Update the datagram TAG value */
reass->rb_dgramtag++;
}
else
{
/* The packet does not need to be fragmented just copy the "payload"
* and send in one frame.
*/
/* Copy any uncompressed protocol headers that must appear only in th
* first fragment.
*/
if (protosize > 0)
{
FAR uint8_t *src = (FAR uint8_t *)ipv6 + IPv6_HDRLEN;
memcpy(fptr + g_frame_hdrlen, src, protosize);
}
/* Copy the payload into the frame. */
memcpy(fptr + g_frame_hdrlen + protosize, buf, buflen);
iob->io_len = buflen + g_frame_hdrlen + protosize;
iob->io_pktlen = iob->io_len;
ninfo("Non-fragmented: length %d\n", iob->io_len);
sixlowpan_dumpbuffer("Outgoing frame",
(FAR const uint8_t *)iob->io_data, iob->io_len);
/* And submit the frame to the MAC */
ninfo("Submitting frame length=%u io_offset=%u\n",
iob->io_len, iob->io_offset);
ret = sixlowpan_frame_submit(radio, &meta, iob);
if (ret < 0)
{
nerr("ERROR: sixlowpan_frame_submit() failed: %d\n", ret);
}
}
return OK;
}
#endif /* CONFIG_NET_6LOWPAN */
@@ -0,0 +1,284 @@
/****************************************************************************
* net/sixlowpan/sixlowpan_framer.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include "nuttx/net/net.h"
#include "nuttx/net/radiodev.h"
#include "nuttx/wireless/ieee802154/ieee802154_mac.h"
#include "sixlowpan/sixlowpan_internal.h"
#ifdef CONFIG_NET_6LOWPAN
#ifdef CONFIG_WIRELESS_IEEE802154
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_anyaddrnull
*
* Description:
* If the destination address is all zero in the MAC header buf, then it is
* broadcast on the 802.15.4 network.
*
* Input Parameters:
* addr - The address to check
* addrlen - The length of the address in bytes
*
* Returned Value:
* True if the address is all zero.
*
****************************************************************************/
static bool sixlowpan_anyaddrnull(FAR const uint8_t *addr, uint8_t addrlen)
{
while (addrlen-- > 0)
{
if (addr[addrlen] != 0x00)
{
return false;
}
}
return true;
}
/****************************************************************************
* Name: sixlowpan_saddrnull
*
* Description:
* If the destination address is all zero in the MAC header buf, then it is
* broadcast on the 802.15.4 network.
*
* Input Parameters:
* eaddr - The short address to check
*
* Returned Value:
* The address length associated with the address mode.
*
****************************************************************************/
static inline bool sixlowpan_saddrnull(FAR const uint8_t *saddr)
{
return sixlowpan_anyaddrnull(saddr, NET_6LOWPAN_SADDRSIZE);
}
/****************************************************************************
* Name: sixlowpan_eaddrnull
*
* Description:
* If the destination address is all zero in the MAC header buf, then it is
* broadcast on the 802.15.4 network.
*
* Input Parameters:
* eaddr - The extended address to check
*
* Returned Value:
* The address length associated with the address mode.
*
****************************************************************************/
static inline bool sixlowpan_eaddrnull(FAR const uint8_t *eaddr)
{
return sixlowpan_anyaddrnull(eaddr, NET_6LOWPAN_EADDRSIZE);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_meta_data
*
* Description:
* Based on the collected attributes and addresses, construct the MAC meta
* data structure that we need to interface with the IEEE802.15.4 MAC.
*
* Input Parameters:
* radio - Radio network driver state instance.
* pktmeta - Meta-data specific to the current outgoing frame
* meta - Location to return the corresponding meta data.
*
* Returned Value:
* Ok is returned on success; Otherwise a negated errno value is returned.
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
int sixlowpan_meta_data(FAR struct radio_driver_s *radio,
FAR const struct ieee802_txmetadata_s *pktmeta,
FAR struct ieee802154_frame_meta_s *meta)
{
bool rcvrnull;
/* Initialize all settings to all zero */
memset(meta, 0, sizeof(struct ieee802154_frame_meta_s));
/* Source address mode */
meta->srcmode = pktmeta->sextended != 0 ?
IEEE802154_ADDRMODE_EXTENDED :
IEEE802154_ADDRMODE_SHORT;
/* Check for a broadcast destination address (all zero) */
if (pktmeta->dextended != 0)
{
/* Extended destination address mode */
rcvrnull = sixlowpan_eaddrnull(pktmeta->dest.nm_addr);
}
else
{
/* Short destination address mode */
rcvrnull = sixlowpan_saddrnull(pktmeta->dest.nm_addr);
}
if (!rcvrnull)
{
meta->flags.ackreq = TRUE;
}
/* Destination address */
/* If the output address is NULL, then it is broadcast on the 802.15.4
* network.
*/
if (rcvrnull)
{
/* Broadcast requires short address mode. */
meta->destaddr.mode = IEEE802154_ADDRMODE_SHORT;
meta->destaddr.saddr[0] = 0xff;
meta->destaddr.saddr[1] = 0xff;
}
else if (pktmeta->dextended != 0)
{
/* Extended destination address mode */
meta->destaddr.mode = IEEE802154_ADDRMODE_EXTENDED;
sixlowpan_eaddrcopy(&meta->destaddr.eaddr, pktmeta->dest.nm_addr);
}
else
{
/* Short destination address mode */
meta->destaddr.mode = IEEE802154_ADDRMODE_SHORT;
/* 802.15.4 layer expects address in Little-Endian byte order */
meta->destaddr.saddr[0] = pktmeta->dest.nm_addr[1];
meta->destaddr.saddr[1] = pktmeta->dest.nm_addr[0];
}
/* 802.15.4 layer expects address in Little-Endian byte order */
meta->destaddr.panid[0] = pktmeta->dpanid[1];
meta->destaddr.panid[1] = pktmeta->dpanid[0];
/* Handle associated with MSDU. Will increment once per packet, not
* necessarily per frame: The same MSDU handle will be used for each
* fragment of a disassembled packet.
*/
meta->handle = radio->r_msdu_handle++;
#ifdef CONFIG_IEEE802154_SECURITY
# warning CONFIG_IEEE802154_SECURITY not yet supported
#endif
#ifdef CONFIG_IEEE802154_UWB
# warning CONFIG_IEEE802154_UWB not yet supported
#endif
/* Ranging left zero */
return OK;
}
#endif
/****************************************************************************
* Name: sixlowpan_frame_hdrlen
*
* Description:
* This function is before the first frame has been sent in order to
* determine what the size of the IEEE802.15.4 header will be. No frame
* buffer is required to make this determination.
*
* Input Parameters:
* radio - A reference IEEE802.15.4 MAC network device structure.
* meta - Meta data that describes the MAC header
*
* Returned Value:
* The frame header length is returned on success; otherwise, a negated
* errno value is return on failure.
*
****************************************************************************/
int sixlowpan_frame_hdrlen(FAR struct radio_driver_s *radio,
FAR const void *meta)
{
return radio->r_get_mhrlen(radio, meta);
}
/****************************************************************************
* Name: sixlowpan_frame_submit
*
* Description:
* This function is called after eiether (1) the IEEE802.15.4 MAC driver
* polls for TX data or (2) after the IEEE802.15.4 MAC driver provides a
* new incoming frame and the network responds with an outgoing packet. It
* submits any new outgoing frame to the MAC.
*
* Input Parameters:
* radio - A reference to a radio network device instance.
* meta - Meta data that describes the MAC header
* frame - The IOB containing the frame to be submitted.
*
* Returned Value:
* Zero (OK) is returned on success; otherwise, a negated errno value is
* return on any failure.
*
****************************************************************************/
int sixlowpan_frame_submit(FAR struct radio_driver_s *radio,
FAR const void *meta, FAR struct iob_s *frame)
{
return radio->r_req_data(radio, meta, frame);
}
#endif /* CONFIG_NET_6LOWPAN */
@@ -0,0 +1,59 @@
/****************************************************************************
* net/sixlowpan/sixlowpan_globals.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include "sixlowpan/sixlowpan_internal.h"
#ifdef CONFIG_NET_6LOWPAN
/****************************************************************************
* Public Data
****************************************************************************/
/* The following data values are used to hold intermediate settings while
* processing IEEE802.15.4 frames. These globals are shared with incoming
* and outgoing frame processing and possibly with multiple IEEE802.15.4 MAC
* devices. The network lock provides exclusive use of these globals
* during that processing.
*/
/* 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).
*/
uint8_t g_uncomp_hdrlen;
/* g_frame_hdrlen is the total length of (the processed) 6lowpan headers
* (fragment headers, IPV6 or HC1, HC2, and HC1 and HC2 non compressed
* fields).
*/
uint8_t g_frame_hdrlen;
/****************************************************************************
* Public Functions
****************************************************************************/
#endif /* CONFIG_NET_6LOWPAN */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,494 @@
/****************************************************************************
* net/sixlowpan/sixlowpan_hc1.c
*
* Copyright (C) 2017, Gregory Nutt, all rights reserved
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Derives 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 <errno.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/radiodev.h>
#include "sixlowpan/sixlowpan_internal.h"
#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_compresshdr_hc1
*
* Description:
* Compress IP/UDP header using HC1 and HC_UDP
*
* This function is called by the 6lowpan code to create a compressed
* 6lowpan packet in the packetbuf buffer from a full IPv6 packet in the
* uip_buf buffer.
*
* If we can compress everything, we use HC1 dispatch, if not we use
* IPv6 dispatch. We can compress everything if:
*
* - IP version is
* - Flow label and traffic class are 0
* - Both src and dest ip addresses are link local
* - Both src and dest interface ID are recoverable from lower layer
* header
* - Next header is either ICMP, UDP or TCP
*
* Moreover, if next header is UDP, we try to compress it using HC_UDP.
* This is feasible is both ports are between F0B0 and F0B0 + 15
*
* Resulting header structure:
* - For ICMP, TCP, non compressed UDP\n
* HC1 encoding = 11111010 (UDP) 11111110 (TCP) 11111100 (ICMP)
* 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | LoWPAN HC1 Dsp | HC1 encoding | IPv6 Hop limit| L4 hdr + data|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | ...
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* - For compressed UDP
* HC1 encoding = 11111011, HC_UDP encoding = 11100000
* 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | LoWPAN HC1 Dsp| HC1 encoding | HC_UDP encod.| IPv6 Hop limit|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | src p.| dst p.| UDP checksum | L4 data...
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Input Parameters:
* radio - A reference to a radio network device instance
* ipv6 - The IPv6 header followed by TCP, UDP, or ICMPv6 header to be
* compressed
* destmac - L2 destination address, needed to compress the IP
* destination field
* fptr - Pointer to frame to be compressed.
*
* Returned Value:
* On success the indications of the defines COMPRESS_HDR_* are returned.
* A negated errno value is returned on failure.
*
****************************************************************************/
int sixlowpan_compresshdr_hc1(FAR struct radio_driver_s *radio,
FAR const struct ipv6_hdr_s *ipv6,
FAR const struct netdev_varaddr_s *destmac,
FAR uint8_t *fptr)
{
FAR uint8_t *hc1 = fptr + g_frame_hdrlen;
int ret = COMPRESS_HDR_INLINE;
/* Check if all the assumptions for full compression are valid */
if (ipv6->vtc != 0x60 || ipv6->tcf != 0 || ipv6->flow != 0 ||
!sixlowpan_islinklocal(ipv6->srcipaddr) ||
!sixlowpan_ismacbased(ipv6->srcipaddr, &radio->r_dev.d_mac.radio) ||
!sixlowpan_islinklocal(ipv6->destipaddr) ||
!sixlowpan_ismacbased(ipv6->destipaddr, destmac) ||
(1
#ifdef CONFIG_NET_TCP
&& ipv6->proto != IP_PROTO_TCP
#endif
#ifdef CONFIG_NET_UDP
&& ipv6->proto != IP_PROTO_UDP
#endif
#ifdef CONFIG_NET_ICMPv6
&& ipv6->proto != IP_PROTO_ICMP6
#endif
))
{
/* IPV6 DISPATCH
* Something cannot be compressed, use IPV6 DISPATCH, compress
* nothing, copy IPv6 header into the frame buffer
*/
nwarn("WARNING: Fall back to IPv6 dispatch\n");
/* IPv6 dispatch header (1 byte) */
hc1[SIXLOWPAN_HC1_DISPATCH] = SIXLOWPAN_DISPATCH_IPV6;
g_frame_hdrlen += SIXLOWPAN_IPV6_HDR_LEN;
memcpy(fptr + g_frame_hdrlen, ipv6, IPv6_HDRLEN);
g_frame_hdrlen += IPv6_HDRLEN;
g_uncomp_hdrlen += IPv6_HDRLEN;
}
else
{
/* HC1 DISPATCH maximum compression:
* All fields in the IP header but Hop Limit are elided. If next
* header is UDP, we compress UDP header using HC2
*/
hc1[SIXLOWPAN_HC1_DISPATCH] = SIXLOWPAN_DISPATCH_HC1;
g_uncomp_hdrlen += IPv6_HDRLEN;
switch (ipv6->proto)
{
#ifdef CONFIG_NET_ICMPv6
case IP_PROTO_ICMP6:
{
/* HC1 encoding and ttl */
hc1[SIXLOWPAN_HC1_ENCODING] = 0xfc;
hc1[SIXLOWPAN_HC1_TTL] = ipv6->ttl;
g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN;
}
break;
#endif
#ifdef CONFIG_NET_TCP
case IP_PROTO_TCP:
{
/* HC1 encoding and ttl */
hc1[SIXLOWPAN_HC1_ENCODING] = 0xfe;
hc1[SIXLOWPAN_HC1_TTL] = ipv6->ttl;
g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN;
}
break;
#endif
#ifdef CONFIG_NET_UDP
case IP_PROTO_UDP:
{
FAR struct udp_hdr_s *udp =
&(((FAR struct ipv6udp_hdr_s *)ipv6)->udp);
/* Try to compress UDP header (we do only full compression).
* This is feasible if both src and dest ports are between
* CONFIG_NET_6LOWPAN_MINPORT and CONFIG_NET_6LOWPAN_MINPORT +
* 15
*/
ninfo("local/remote port %04x/%04x\n",
udp->srcport, udp->destport);
if (ntohs(udp->srcport) >= CONFIG_NET_6LOWPAN_MINPORT &&
ntohs(udp->srcport) < (CONFIG_NET_6LOWPAN_MINPORT + 16) &&
ntohs(udp->destport) >= CONFIG_NET_6LOWPAN_MINPORT &&
ntohs(udp->destport) < (CONFIG_NET_6LOWPAN_MINPORT + 16))
{
FAR uint8_t *hcudp = fptr + g_frame_hdrlen;
/* HC1 encoding */
hcudp[SIXLOWPAN_HC1_HC_UDP_HC1_ENCODING] = 0xfb;
/* HC_UDP encoding, ttl, src and dest ports, checksum */
hcudp[SIXLOWPAN_HC1_HC_UDP_UDP_ENCODING] = 0xe0;
hcudp[SIXLOWPAN_HC1_HC_UDP_TTL] = ipv6->ttl;
hcudp[SIXLOWPAN_HC1_HC_UDP_PORTS] =
(uint8_t)((ntohs(udp->srcport) -
CONFIG_NET_6LOWPAN_MINPORT) << 4) +
(uint8_t)((ntohs(udp->destport) -
CONFIG_NET_6LOWPAN_MINPORT));
memcpy(&hcudp[SIXLOWPAN_HC1_HC_UDP_CHKSUM],
&udp->udpchksum, 2);
g_frame_hdrlen += SIXLOWPAN_HC1_HC_UDP_HDR_LEN;
g_uncomp_hdrlen += UDP_HDRLEN;
}
else
{
/* HC1 encoding and ttl */
hc1[SIXLOWPAN_HC1_ENCODING] = 0xfa;
hc1[SIXLOWPAN_HC1_TTL] = ipv6->ttl;
g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN;
}
ret = COMPRESS_HDR_ELIDED;
}
break;
#endif /* CONFIG_NET_UDP */
default:
{
/* Test above assures that this will never happen */
nerr("ERROR: Unhandled protocol\n");
DEBUGPANIC();
}
break;
}
}
return ret;
}
/****************************************************************************
* Name: sixlowpan_uncompresshdr_hc1
*
* Description:
* Uncompress HC1 (and HC_UDP) headers and put them in sixlowpan_buf
*
* This function is called by the input function when the dispatch is
* HC1. It processes the frame in the IOB buffer, uncompresses the
* header fields, and copies the result in the packet buffer. At the
* end of the decompression, g_frame_hdrlen and uncompressed_hdr_len
* are set to the appropriate values
*
* Input Parameters:
* metadata - Obfuscated MAC metadata including node addressing
* information.
* iplen - Equal to 0 if the packet is not a fragment (IP length is
* then inferred from the L2 length), non 0 if the packet is
* a 1st fragment.
* iob - Pointer to the IOB containing the received frame.
* fptr - Pointer to frame to be uncompressed.
* bptr - Output goes here. Normally this is a known offset into
* d_buf, may be redirected to a "bitbucket" on the case of
* FRAGN frames.
*
* Returned Value:
* Zero (OK) is returned on success, on failure a negated errno value is
* returned.
*
****************************************************************************/
int sixlowpan_uncompresshdr_hc1(FAR struct radio_driver_s *radio,
FAR const void *metadata, uint16_t iplen,
FAR struct iob_s *iob, FAR uint8_t *fptr,
FAR uint8_t *bptr)
{
FAR struct ipv6_hdr_s *ipv6 = (FAR struct ipv6_hdr_s *)bptr;
FAR uint8_t *hc1 = fptr + g_frame_hdrlen;
struct netdev_varaddr_s addr;
int ret;
ninfo("fptr=%p g_frame_hdrlen=%u\n", fptr, g_frame_hdrlen);
/* Format the IPv6 header in the device d_buf.
*
* Set version, traffic clase, and flow label. This assumes that Bit 4 is
* set in HC1.
*/
ipv6->vtc = 0x60; /* Bits 0-3: version, bits 4-7: traffic class (MS) */
ipv6->tcf = 0; /* Bits 0-3: traffic class (LS), 4-bits: flow label (MS) */
ipv6->flow = 0; /* 16-bit flow label (LS) */
g_uncomp_hdrlen += IPv6_HDRLEN;
/* len[], proto, and ttl depend on the encoding */
switch (hc1[SIXLOWPAN_HC1_ENCODING] & 0x06)
{
#ifdef CONFIG_NET_ICMPv6
case SIXLOWPAN_HC1_NH_ICMPv6:
ipv6->proto = IP_PROTO_ICMP6;
ipv6->ttl = hc1[SIXLOWPAN_HC1_TTL];
g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN;
break;
#endif
#ifdef CONFIG_NET_TCP
case SIXLOWPAN_HC1_NH_TCP:
ipv6->proto = IP_PROTO_TCP;
ipv6->ttl = hc1[SIXLOWPAN_HC1_TTL];
g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN;
break;
#endif
#ifdef CONFIG_NET_UDP
case SIXLOWPAN_HC1_NH_UDP:
{
FAR struct udp_hdr_s *udp =
(FAR struct udp_hdr_s *)(bptr + IPv6_HDRLEN);
FAR uint8_t *hcudp = fptr + g_frame_hdrlen;
ipv6->proto = IP_PROTO_UDP;
/* Check for HC_UDP encoding */
if ((hcudp[SIXLOWPAN_HC1_HC_UDP_HC1_ENCODING] & 0x01) != 0)
{
/* UDP header is compressed with HC_UDP */
if (hcudp[SIXLOWPAN_HC1_HC_UDP_UDP_ENCODING] !=
SIXLOWPAN_HC_UDP_ALL_C)
{
nwarn("WARNING: "
"sixlowpan (uncompress_hdr), packet not supported");
return -EOPNOTSUPP;
}
/* IP TTL */
ipv6->ttl = hcudp[SIXLOWPAN_HC1_HC_UDP_TTL];
/* UDP ports, len, checksum */
udp->srcport =
htons(CONFIG_NET_6LOWPAN_MINPORT +
(hcudp[SIXLOWPAN_HC1_HC_UDP_PORTS] >> 4));
udp->destport =
htons(CONFIG_NET_6LOWPAN_MINPORT +
(hcudp[SIXLOWPAN_HC1_HC_UDP_PORTS] & 0x0f));
ninfo("UDP srcport=%04x destport=%04x\n",
udp->srcport, udp->destport);
memcpy(&udp->udpchksum,
&hcudp[SIXLOWPAN_HC1_HC_UDP_CHKSUM], 2);
g_uncomp_hdrlen += UDP_HDRLEN;
g_frame_hdrlen += SIXLOWPAN_HC1_HC_UDP_HDR_LEN;
}
else
{
g_frame_hdrlen += SIXLOWPAN_HC1_HDR_LEN;
}
}
break;
#endif /* CONFIG_NET_UDP */
default:
return -EPROTONOSUPPORT;
}
/* Re-create the link-local, mac-based IP address from src/dest node
* addresses.
*
* PC: Prefix compressed (link-local prefix assumed)
* IC: Interface identifier elided (derivable from the corresponding
* link-layer address).
*/
if ((hc1[SIXLOWPAN_HC1_ENCODING] & SIXLOWPAN_HC1_SRCADDR_MASK) ==
SIXLOWPAN_HC1_SRCADDR_PCIC)
{
ret = sixlowpan_extract_srcaddr(radio, metadata, &addr);
if (ret < 0)
{
nerr("ERROR: sixlowpan_extract_srcaddr failed: %d\n", ret);
}
else
{
sixlowpan_ipfromaddr(&addr, ipv6->srcipaddr);
}
}
else
{
nwarn("HC1 srcipaddr encoding not supported: %02x\n",
hc1[SIXLOWPAN_HC1_ENCODING]);
}
ninfo("srcipaddr=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
ntohs(ipv6->srcipaddr[0]), ntohs(ipv6->srcipaddr[1]),
ntohs(ipv6->srcipaddr[2]), ntohs(ipv6->srcipaddr[3]),
ntohs(ipv6->srcipaddr[4]), ntohs(ipv6->srcipaddr[5]),
ntohs(ipv6->srcipaddr[6]), ntohs(ipv6->srcipaddr[7]));
if ((hc1[SIXLOWPAN_HC1_ENCODING] & SIXLOWPAN_HC1_DESTADDR_MASK) ==
SIXLOWPAN_HC1_DESTADDR_PCIC)
{
ret = sixlowpan_extract_srcaddr(radio, metadata, &addr);
if (ret < 0)
{
nerr("ERROR: sixlowpan_extract_srcaddr failed: %d\n", ret);
}
else
{
sixlowpan_ipfromaddr(&addr, ipv6->destipaddr);
}
}
else
{
nwarn("HC1 destipaddr encoding not supported: %02x\n",
hc1[SIXLOWPAN_HC1_ENCODING]);
}
ninfo("destipaddr=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
ntohs(ipv6->destipaddr[0]), ntohs(ipv6->destipaddr[1]),
ntohs(ipv6->destipaddr[2]), ntohs(ipv6->destipaddr[3]),
ntohs(ipv6->destipaddr[4]), ntohs(ipv6->destipaddr[5]),
ntohs(ipv6->destipaddr[6]), ntohs(ipv6->destipaddr[7]));
/* IP length field. */
if (iplen == 0)
{
/* This is not a fragmented packet */
ipv6->len[0] = 0;
ipv6->len[1] = iob->io_len - g_frame_hdrlen + g_uncomp_hdrlen -
IPv6_HDRLEN;
}
else
{
/* This is a 1st fragment */
ipv6->len[0] = (iplen - IPv6_HDRLEN) >> 8;
ipv6->len[1] = (iplen - IPv6_HDRLEN) & 0x00ff;
}
ninfo("IPv6 len=%02x:%02x\n", ipv6->len[0], ipv6->len[1]);
#ifdef CONFIG_NET_UDP
/* Length field in UDP header */
if (ipv6->proto == IP_PROTO_UDP)
{
FAR struct udp_hdr_s *udp =
(FAR struct udp_hdr_s *)(bptr + IPv6_HDRLEN);
memcpy(&udp->udplen, &ipv6->len[0], 2);
ninfo("IPv6 len=%04x\n", udp->udplen);
}
#endif
return OK;
}
#endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC1 */
@@ -0,0 +1,144 @@
/****************************************************************************
* net/sixlowpan/sixlowpan_icmpv6send.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/radiodev.h>
#include <nuttx/net/ip.h>
#include "icmpv6/icmpv6.h"
#include "sixlowpan/sixlowpan_internal.h"
#include "sixlowpan/sixlowpan.h"
#if defined(CONFIG_NET_6LOWPAN) && defined(CONFIG_NET_ICMPv6)
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_icmpv6_send
*
* Description:
* Handles forwarding a ICMPv6 packet via 6LoWPAN. This is currently only
* used by the IPv6 forwarding logic.
*
* Input Parameters:
* dev - An instance of network device state structure
* fwddev - The network device used to send the data. This will be the
* same device except for the IP forwarding case where packets
* are sent across devices.
* ipv6 - A pointer to the IPv6 header in dev->d_buf which lies AFTER
* the L1 header. NOTE: dev->d_len must have been decremented
* by the size of any preceding MAC header.
*
* Returned Value:
* None
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
void sixlowpan_icmpv6_send(FAR struct net_driver_s *dev,
FAR struct net_driver_s *fwddev,
FAR struct ipv6_hdr_s *ipv6)
{
FAR struct ipv6icmp_hdr_s *ipv6icmpv6 = (FAR struct ipv6icmp_hdr_s *)ipv6;
/* Double check */
DEBUGASSERT(dev != NULL && dev->d_len > 0 && fwddev != NULL);
ninfo("d_len %u\n", dev->d_len);
if (dev != NULL && dev->d_len > 0)
{
sixlowpan_dumpbuffer("Outgoing ICMPv6 packet",
(FAR const uint8_t *)ipv6icmpv6, dev->d_len);
/* The ICMPv6 data payload should follow the IPv6 header plus the
* protocol header.
*/
if (ipv6icmpv6->ipv6.proto != IP_PROTO_ICMP6)
{
nwarn("WARNING: Expected ICMPv6 prototype: %u vs %u\n",
ipv6icmpv6->ipv6.proto, IP_PROTO_ICMP6);
}
else
{
struct netdev_varaddr_s destmac;
FAR uint8_t *buf;
uint16_t hdrlen;
uint16_t buflen;
int ret;
/* Get the IEEE 802.15.4 MAC address of the next hop. */
ret = sixlowpan_nexthopaddr((FAR struct radio_driver_s *)fwddev,
ipv6icmpv6->ipv6.destipaddr, &destmac);
if (ret < 0)
{
nerr("ERROR: Failed to get dest MAC address: %d\n", ret);
goto drop;
}
/* Get the IPv6 + ICMPv6 combined header length. NOTE: This
* header size includes only the common 32-bit header at the
* beginning of each ICMPv6 message.
*/
hdrlen = IPv6_HDRLEN + ICMPv6_HDRLEN;
/* Drop the packet if the buffer length is less than this. */
if (hdrlen > dev->d_len)
{
nwarn("WARNING: Dropping small ICMPv6 packet: %u < %u\n",
buflen, hdrlen);
}
else
{
/* Convert the outgoing packet into a frame list. */
buf = (FAR uint8_t *)ipv6 + hdrlen;
buflen = dev->d_len - hdrlen;
sixlowpan_queue_frames(
(FAR struct radio_driver_s *)fwddev,
&ipv6icmpv6->ipv6, buf, buflen, &destmac);
}
}
}
drop:
dev->d_len = 0;
}
#endif /* CONFIG_NET_6LOWPAN && CONFIG_NET_ICMPv6 */
@@ -0,0 +1,68 @@
/****************************************************************************
* net/sixlowpan/sixlowpan_initialize.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include "sixlowpan/sixlowpan.h"
#include "sixlowpan/sixlowpan_internal.h"
#ifdef CONFIG_NET_6LOWPAN
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_initialize
*
* Description:
* sixlowpan_initialize() is called during OS initialization at power-up
* reset. It is called from the common net_setup() function.
* sixlowpan_initialize() configures 6LoWPAN networking data structures.
* It is called prior to platform-specific driver initialization so that
* the 6LoWPAN networking subsystem is prepared to deal with network
* driver initialization actions.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void sixlowpan_initialize(void)
{
/* Initialize the reassembly buffer allocator */
sixlowpan_reass_initialize();
#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
/* Initialize HC06 data data structures */
sixlowpan_hc06_initialize();
#endif
}
#endif /* CONFIG_NET_6LOWPAN */
@@ -0,0 +1,888 @@
/****************************************************************************
* 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 */
@@ -0,0 +1,807 @@
/****************************************************************************
* net/sixlowpan/sixlowpan_internal.h
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Parts of this file derive from Contiki:
*
* Copyright (c) 2008, Swedish Institute of Computer Science
* All rights reserved.
*
* Additional fixes for AVR contributed by:
* Colin O'Flynn coflynn@newae.com
* Eric Gnoske egnoske@gmail.com
* Blake Leverett bleverett@gmail.com
* Mike Vidales mavida404@gmail.com
* Kevin Brown kbrown3@uccs.edu
* Nate Bohlmann nate@elfwerks.com
*
* Additional fixes for MSP430 contributed by:
* Joakim Eriksson
* Niclas Finne
* Nicolas Tsiftes
*
* All rights reserved.
*
* 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 copyright holders nor the names of
* 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.
*
****************************************************************************/
#ifndef _NET_SIXLOWPAN_SIXLOWPAN_INTERNAL_H
#define _NET_SIXLOWPAN_SIXLOWPAN_INTERNAL_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdbool.h>
#include <nuttx/net/tcp.h>
#include <nuttx/net/udp.h>
#include <nuttx/net/icmpv6.h>
#include <nuttx/net/sixlowpan.h>
#include <nuttx/wireless/pktradio.h>
#ifdef CONFIG_NET_6LOWPAN
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Copy a generic address */
#define sixlowpan_anyaddrcopy(dest,src,len) \
memcpy(dest, src, len)
#ifdef CONFIG_WIRELESS_IEEE802154
/* IEEE 802.15.4 address macros
*
* Copy a an IEEE 802.15.4 address.
*/
#define sixlowpan_saddrcopy(dest,src) \
sixlowpan_anyaddrcopy(dest,src,NET_6LOWPAN_SADDRSIZE)
#define sixlowpan_eaddrcopy(dest,src) \
sixlowpan_anyaddrcopy(dest,src,NET_6LOWPAN_EADDRSIZE)
#define sixlowpan_addrcopy(dest,src) \
sixlowpan_anyaddrcopy(dest,src,NET_6LOWPAN_ADDRSIZE)
#endif
/* General helper macros ****************************************************/
/* GET 16-bit data: source in network order */
#define GETUINT16(ptr,index) \
((((uint16_t)((ptr)[index])) << 8) | ((uint16_t)(((ptr)[(index) + 1]))))
/* PUT 16-bit data: source in host order, result in network order */
#define PUTHOST16(ptr,index,value) \
do \
{ \
(ptr)[index] = ((uint16_t)(value) >> 8) & 0xff; \
(ptr)[index + 1] = (uint16_t)(value) & 0xff; \
} \
while (0)
/* Return values ************************************************************/
/* Successful return values from header compression logic */
#define COMPRESS_HDR_INLINE 0 /* L2 header not compressed */
#define COMPRESS_HDR_ELIDED 1 /* L2 header compressed */
/* Memory Pools *************************************************************/
#define REASS_POOL_PREALLOCATED 0
#define REASS_POOL_DYNAMIC 1
#define REASS_POOL_RADIO 2
/* Debug ********************************************************************/
#ifdef CONFIG_NET_6LOWPAN_DUMPBUFFER
# define sixlowpan_dumpbuffer(m,b,s) ninfodumpbuffer(m,b,s)
#else
# define sixlowpan_dumpbuffer(m,b,s)
#endif
/****************************************************************************
* Public Types
****************************************************************************/
/* IPv6 TCP/UDP/ICMPv6 Definitions ******************************************/
#ifdef CONFIG_NET_TCP
/* IPv6 + TCP header. Cast compatible based on IPv6 protocol field. */
struct ipv6tcp_hdr_s
{
struct ipv6_hdr_s ipv6;
struct tcp_hdr_s tcp;
};
#endif
#ifdef CONFIG_NET_UDP
/* IPv6 + UDP header */
struct ipv6udp_hdr_s
{
struct ipv6_hdr_s ipv6;
struct udp_hdr_s udp;
};
#endif
#ifdef CONFIG_NET_ICMPv6
/* IPv6 + ICMPv6 header */
struct ipv6icmp_hdr_s
{
struct ipv6_hdr_s ipv6;
struct icmpv6_iphdr_s icmp;
};
#endif
#ifdef CONFIG_WIRELESS_IEEE802154
/* In order to provide a customizable IEEE 802.15.4 MAC header, a structure
* of meta data is passed to the MAC network driver, struct
* ieee802154_frame_meta_s. Many of the settings in this meta data are
* fixed, determined by the 6LoWPAN configuration. Other settings depend
* on the protocol used in the current packet or on chacteristics of the
* destination node.
*
* The following structure is used to summarize those per-packet
* customizations and, along, with the fixed configuration settings,
* determines the full form of that meta data.
*/
struct ieee802_txmetadata_s
{
uint8_t sextended : 1; /* Extended source address */
uint8_t dextended : 1; /* Extended destination address */
uint8_t xmits; /* Max MAC transmisstion */
uint8_t dpanid[IEEE802154_PANIDSIZE]; /* Destination PAN ID */
struct netdev_maxaddr_s source; /* Source IEEE 802.15.4 address */
struct netdev_maxaddr_s dest; /* Destination IEEE 802.15.4 address */
};
#endif
/* This structure holds the packet metadata as a union when multiple
* different radio types are supported.
*/
union sixlowpan_metadata_u
{
#ifdef CONFIG_WIRELESS_IEEE802154
struct ieee802154_frame_meta_s ieee802154;
#endif
#ifdef CONFIG_WIRELESS_PKTRADIO
struct pktradio_metadata_s pktradio;
#endif
};
/****************************************************************************
* Public Data
****************************************************************************/
/* The following data values are used to hold intermediate settings while
* processing IEEE802.15.4 frames. These globals are shared with incoming
* and outgoing frame processing and possibly with multiple IEEE802.15.4 MAC
* devices. The network lock provides exclusive use of these globals
* during that processing.
*/
/* 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).
*/
extern uint8_t g_uncomp_hdrlen;
/* g_frame_hdrlen is the total length of (the processed) 6lowpan headers
* (fragment headers, IPV6 or HC1, HC2, and HC1 and HC2 non compressed
* fields).
*/
extern uint8_t g_frame_hdrlen;
/****************************************************************************
* Public Types
****************************************************************************/
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
struct net_driver_s; /* Forward reference */
struct radio_driver_s; /* Forward reference */
struct devif_callback_s; /* Forward reference */
struct ipv6_hdr_s; /* Forward reference */
struct netdev_varaddr_s; /* Forward reference */
struct iob_s; /* Forward reference */
/****************************************************************************
* Name: sixlowpan_send
*
* Description:
* Process an outgoing UDP or ICMPv6 packet. Takes an IP packet and
* formats it to be sent on an 802.15.4 network using 6lowpan. Called
* from common UDP/ICMPv6 send logic.
*
* The payload data is in the caller 'buf' and is of length 'buflen'.
* Compressed headers will be added and if necessary the packet is
* fragmented. The resulting packet/fragments are submitted to the MAC
* via the network driver r_req_data method.
*
* Input Parameters:
* dev - The IEEE802.15.4 MAC network driver interface.
* list - Head of callback list for send event handler
* ipv6hdr - IPv6 header followed by UDP or ICMPv6 header.
* buf - Data to send
* len - Length of data to send
* destmac - The IEEE802.15.4 MAC address of the destination
* timeout - Send timeout in milliseconds
*
* Returned Value:
* Ok is returned on success; Otherwise 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 logic will fall back to normal
* IPv4/IPv6 formatting.
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
int sixlowpan_send(FAR struct net_driver_s *dev,
FAR struct devif_callback_s **list,
FAR const struct ipv6_hdr_s *ipv6hdr, FAR const void *buf,
size_t len, FAR const struct netdev_varaddr_s *destmac,
unsigned int timeout);
/****************************************************************************
* Name: sixlowpan_meta_data
*
* Description:
* Based on the collected attributes and addresses, construct the MAC meta
* data structure that we need to interface with the IEEE802.15.4 MAC.
*
* Input Parameters:
* radio - Reference to a radio network driver state instance.
* pktmeta - Meta-data specific to the current outgoing frame
* meta - Location to return the corresponding meta data reference
* (obfuscated).
*
* Returned Value:
* Ok is returned on success; Otherwise a negated errno value is returned.
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
#ifdef CONFIG_WIRELESS_IEEE802154
int sixlowpan_meta_data(FAR struct radio_driver_s *radio,
FAR const struct ieee802_txmetadata_s *pktmeta,
FAR struct ieee802154_frame_meta_s *meta);
#endif
/****************************************************************************
* Name: sixlowpan_frame_hdrlen
*
* Description:
* This function is before the first frame has been sent in order to
* determine what the size of the IEEE802.15.4 header will be. No frame
* buffer is required to make this determination.
*
* Input Parameters:
* radio - Reference to a radio network driver state instance.
* meta - obfuscated meta data that describes the MAC header
*
* Returned Value:
* The frame header length is returned on success; otherwise, a negated
* errno value is return on failure.
*
****************************************************************************/
int sixlowpan_frame_hdrlen(FAR struct radio_driver_s *radio,
FAR const void *meta);
/****************************************************************************
* Name: sixlowpan_frame_submit
*
* Description:
* This function is called after eiether (1) the IEEE802.15.4 MAC driver
* polls for TX data or (2) after the IEEE802.15.4 MAC driver provides a
* new incoming frame and the network responds with an outgoing packet. It
* submits any new outgoing frame to the MAC.
*
* Input Parameters:
* radio - Reference to a radio network driver state instance.
* meta - Obfuscated metadata that describes the MAC header
* frame - The IOB containing the frame to be submitted.
*
* Returned Value:
* Zero (OK) is returned on success; otherwise, a negated errno value is
* return on any failure.
*
****************************************************************************/
int sixlowpan_frame_submit(FAR struct radio_driver_s *radio,
FAR const void *meta, FAR struct iob_s *frame);
/****************************************************************************
* Name: sixlowpan_queue_frames
*
* Description:
* Process an outgoing UDP or TCP packet. This function is called from
* the send event handler when a TX poll is received. It formats 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 'buflen'.
* Compressed headers will be added and if necessary the packet is
* fragmented. The resulting packet/fragments are submitted to the MAC
* via the network driver r_req_data method.
*
* Input Parameters:
* radio - Reference to a radio network driver state instance.
* ipv6 - IPv6 header followed by TCP or UDP header.
* buf - Beginning of the packet packet to send (with IPv6 + protocol
* headers)
* buflen - Length of data to send (includes IPv6 and protocol headers)
* destmac - The IEEE802.15.4 MAC address of the destination
*
* Returned Value:
* Ok is returned on success; Otherwise 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_queue_frames(FAR struct radio_driver_s *radio,
FAR const struct ipv6_hdr_s *ipv6,
FAR const void *buf, size_t buflen,
FAR const struct netdev_varaddr_s *destmac);
/****************************************************************************
* Name: sixlowpan_hc06_initialize
*
* Description:
* sixlowpan_hc06_initialize() is called during OS initialization at
* power-up reset. It is called from the common sixlowpan_initialize()
* function. sixlowpan_hc06_initialize() configures HC06 networking data
* structures. It is called prior to platform-specific driver
* initialization so that the 6LoWPAN networking subsystem is prepared to
* deal with network driver initialization actions.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
void sixlowpan_hc06_initialize(void);
#endif
/****************************************************************************
* Name: sixlowpan_compresshdr_hc06
*
* Description:
* Compress IP/UDP header
*
* This function is called by the 6lowpan code to create a compressed
* 6lowpan packet in the packetbuf buffer from a full IPv6 packet in the
* uip_buf buffer.
*
* HC-06:
*
* Originally draft-ietf-6lowpan-hc, version 6:
* http://tools.ietf.org/html/draft-ietf-6lowpan-hc-06,
*
* Updated to:
*
* RFC 6282:
* https://tools.ietf.org/html/rfc6282
*
* NOTE: sixlowpan_compresshdr_hc06() does not support ISA100_UDP header
* compression
*
* Input Parameters:
* radio - Reference to a radio network driver state instance.
* ipv6 - The IPv6 header to be compressed
* destmac - L2 destination address, needed to compress the IP
* destination field
* fptr - Pointer to frame to be compressed.
*
* Returned Value:
* On success the indications of the defines COMPRESS_HDR_* are returned.
* A negated errno value is returned on failure.
*
****************************************************************************/
#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
int sixlowpan_compresshdr_hc06(FAR struct radio_driver_s *radio,
FAR const struct ipv6_hdr_s *ipv6,
FAR const struct netdev_varaddr_s *destmac,
FAR uint8_t *fptr);
#endif
/****************************************************************************
* Name: sixlowpan_uncompresshdr_hc06
*
* Description:
* Uncompress HC06 (i.e., IPHC and LOWPAN_UDP) headers and put them in
* sixlowpan_buf
*
* This function is called by the input function when the dispatch is HC06.
* We process the frame in the IOB buffer, uncompress the header fields,
* and copy the result into the driver packet buffer. At the end of the
* decompression, g_frame_hdrlen and g_uncompressed_hdrlen are set to the
* appropriate values
*
* Input Parameters:
* radio - Reference to a radio network driver state instance.
* metadata - Obfuscated MAC metadata including node addressing
* information.
* iplen - Equal to 0 if the packet is not a fragment (IP length is
* then inferred from the L2 length), non 0 if the packet is
* a first fragment.
* iob - Pointer to the IOB containing the received frame.
* fptr - Pointer to frame to be compressed.
* bptr - Output goes here. Normally this is a known offset into
* d_buf, may be redirected to a "bitbucket" on the case of
* FRAGN frames.
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
FAR const void *metadata,
uint16_t iplen, FAR struct iob_s *iob,
FAR uint8_t *fptr, FAR uint8_t *bptr);
#endif
/****************************************************************************
* Name: sixlowpan_compresshdr_hc1
*
* Description:
* Compress IP/UDP header using HC1 and HC_UDP
*
* This function is called by the 6lowpan code to create a compressed
* 6lowpan packet in the packetbuf buffer from a full IPv6 packet in the
* uip_buf buffer.
*
* Input Parameters:
* radio - Reference to a radio network driver state instance.
* ipv6 - The IPv6 header to be compressed
* destmac - L2 destination address, needed to compress the IP
* destination field
* fptr - Pointer to frame to be compressed.
*
* Returned Value:
* On success the indications of the defines COMPRESS_HDR_* are returned.
* A negated errno value is returned on failure.
*
****************************************************************************/
#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1
int sixlowpan_compresshdr_hc1(FAR struct radio_driver_s *radio,
FAR const struct ipv6_hdr_s *ipv6,
FAR const struct netdev_varaddr_s *destmac,
FAR uint8_t *fptr);
#endif
/****************************************************************************
* Name: sixlowpan_uncompresshdr_hc1
*
* Description:
* Uncompress HC1 (and HC_UDP) headers and put them in sixlowpan_buf
*
* This function is called by the input function when the dispatch is
* HC1. It processes the frame in the IOB buffer, uncompresses the
* header fields, and copies the result in the packet buffer. At the
* end of the decompression, g_frame_hdrlen and uncompressed_hdr_len
* are set to the appropriate values
*
* Input Parameters:
* radio - Reference to a radio network driver state instance.
* metadata - Obfuscated MAC metadata including node addressing
* information.
* iplen - Equal to 0 if the packet is not a fragment (IP length is
* then inferred from the L2 length), non 0 if the packet is
* a 1st fragment.
* iob - Pointer to the IOB containing the received frame.
* fptr - Pointer to frame to be uncompressed.
* bptr - Output goes here. Normally this is a known offset into
* d_buf, may be redirected to a "bitbucket" on the case of
* FRAGN frames.
*
* Returned Value:
* Zero (OK) is returned on success, on failure a negated errno value is
* returned.
*
****************************************************************************/
#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1
int sixlowpan_uncompresshdr_hc1(FAR struct radio_driver_s *radio,
FAR const void *metadata, uint16_t iplen,
FAR struct iob_s *iob, FAR uint8_t *fptr,
FAR uint8_t *bptr);
#endif
/****************************************************************************
* Name: sixlowpan_nexthopaddr
*
* Description:
* sixlowpan_nexthopaddr(): If the destination is on-link, extract the
* IEEE 802.15.14 destination address from the destination IP address. If
* the destination is not reachable directly, use the routing table (if
* available) or fall back to the default router IP address and use the
* router IP address to derive the IEEE 802.15.4 MAC address.
*
****************************************************************************/
int sixlowpan_nexthopaddr(FAR struct radio_driver_s *radio,
FAR const net_ipv6addr_t ipaddr,
FAR struct netdev_varaddr_s *destaddr);
/****************************************************************************
* Name: sixlowpan_islinklocal, sixlowpan_destaddrfromip, and
* sixlowpan_ismacbased
*
* Description:
* sixlowpan_destaddrfromip(): Extract the IEEE 802.15.14 destination
* address from a MAC-based destination IPv6 address. This function
* handles a tagged address union which may either a short or and
* extended destination address.
*
* In the case there the IEEE 802.15.4 node functions as an endpoint in a
* start topology, the destination address will, instead, be the address
* of the star hub (which is assumed to be the address of the coordinator).
*
* sixlowpan_ipfrom[s|e]addr(): Create a link-local, MAC-based IPv6
* address from an IEEE802.15.4 short address (saddr) or extended address
* (eaddr).
*
* sixlowpan_islinklocal() and sixlowpan_ismacbased() will return true for
* address created in this fashion. sixlowpan_destaddrfromip() is
* intended to handle a tagged address or any size. Local addresses are
* of a fixed but configurable size and sixlowpan_isaddrbased() is for use
* with such local addresses.
*
* 128 112 96 80 64 48 32 16
* ---- ---- ---- ---- ---- ---- ---- ----
* fe80 0000 0000 0000 0000 00ff fe00 xxxx 2-byte short address IEEE
* 48-bit MAC
* fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte extended address IEEE
* EUI-64
*
****************************************************************************/
#define sixlowpan_islinklocal(ipaddr) ((ipaddr)[0] == NTOHS(0xfe80))
int sixlowpan_destaddrfromip(FAR struct radio_driver_s *radio,
const net_ipv6addr_t ipaddr,
FAR struct netdev_varaddr_s *addr);
void sixlowpan_ipfromaddr(FAR const struct netdev_varaddr_s *addr,
FAR net_ipv6addr_t ipaddr);
bool sixlowpan_ismacbased(const net_ipv6addr_t ipaddr,
FAR const struct netdev_varaddr_s *addr);
/****************************************************************************
* Name: sixlowpan_radio_framelen
*
* Description:
* Get the maximum frame length supported by radio network driver.
*
* Input Parameters:
* radio - Reference to a radio network driver state instance.
*
* Returned Value:
* A non-negative, maximum frame lengthis returned on success; A negated
* errno valueis returned on any failure.
*
****************************************************************************/
int sixlowpan_radio_framelen(FAR struct radio_driver_s *radio);
/****************************************************************************
* Name: sixlowpan_src_panid
*
* Description:
* Get the source PAN ID from the IEEE802.15.4 radio.
*
* Input Parameters:
* radio - Reference to a radio network driver state instance.
* panid - The location in which to return the PAN ID. 0xfff may be
* returned if the device is not associated.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
#ifdef CONFIG_WIRELESS_IEEE802154
int sixlowpan_src_panid(FAR struct radio_driver_s *radio,
FAR uint8_t *panid);
#endif
/****************************************************************************
* Name: sixlowpan_extract_srcaddr
*
* Description:
* Extract the source MAC address from the radio-specific RX metadata, and
* return the source address in a radio-agnostic form.
*
* Input Parameters:
* radio - Reference to a radio network driver state instance.
* metadata - Opaque reference to the radio-specific RX metadata.
* srcaddr - The location in which to return the source MAC address.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int sixlowpan_extract_srcaddr(FAR struct radio_driver_s *radio,
FAR const void *metadata,
FAR struct netdev_varaddr_s *srcaddr);
/****************************************************************************
* Name: sixlowpan_extract_destaddr
*
* Description:
* Extract the destination MAC address from the radio-specific RX metadata,
* and return the destination address in a radio-agnostic form.
*
* Input Parameters:
* radio - Reference to a radio network driver state instance.
* metadata - Opaque reference to the radio-specific RX metadata.
* destaddr - The location in which to return the destination MAC address.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int sixlowpan_extract_destaddr(FAR struct radio_driver_s *radio,
FAR const void *metadata,
FAR struct netdev_varaddr_s *destaddr);
/****************************************************************************
* Name: sixlowpan_reass_initialize
*
* Description:
* This function initializes the reassembly buffer allocator. This
* function must be called early in the initialization sequence before
* any radios begin operation.
*
* Called only once during network initialization.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void sixlowpan_reass_initialize(void);
/****************************************************************************
* Name: sixlowpan_reass_allocate
*
* Description:
* The sixlowpan_reass_allocate function will get a free reassembly buffer
* structure for use by 6LoWPAN.
*
* This function will first attempt to allocate from the g_free_reass
* list. If that the list is empty, then the reassembly buffer structure
* will be allocated from the dynamic memory pool.
*
* Input Parameters:
* reasstag - The reassembly tag for subsequent lookup.
* fragsrc - The source address of the fragment.
*
* Returned Value:
* A reference to the allocated reass structure. All fields used by the
* reasembly logic have been zeroed. On a failure to allocate, NULL is
* returned.
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
FAR struct sixlowpan_reassbuf_s *
sixlowpan_reass_allocate(uint16_t reasstag,
FAR const struct netdev_varaddr_s *fragsrc);
/****************************************************************************
* Name: sixlowpan_reass_find
*
* Description:
* Find a previously allocated, active reassembly buffer with the specified
* reassembly tag.
*
* Input Parameters:
* reasstag - The reassembly tag to match.
* fragsrc - The source address of the fragment.
*
* Returned Value:
* A reference to the matching reass structure.
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
FAR struct sixlowpan_reassbuf_s *
sixlowpan_reass_find(uint16_t reasstag,
FAR const struct netdev_varaddr_s *fragsrc);
/****************************************************************************
* Name: sixlowpan_reass_free
*
* Description:
* The sixlowpan_reass_free function will return a reass structure
* to the free list of messages if it was a pre-allocated reass
* structure. If the reass structure was allocated dynamically it will
* be deallocated.
*
* Input Parameters:
* reass - reass structure to free
*
* Returned Value:
* None
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
void sixlowpan_reass_free(FAR struct sixlowpan_reassbuf_s *reass);
#endif /* CONFIG_NET_6LOWPAN */
#endif /* _NET_SIXLOWPAN_SIXLOWPAN_INTERNAL_H */
@@ -0,0 +1,442 @@
/****************************************************************************
* net/sixlowpan/sixlowpan_reassbuf.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <nuttx/kmalloc.h>
#include <nuttx/mm/iob.h>
#include "sixlowpan_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Re-assembly timeout in clock ticks */
#define NET_6LOWPAN_TIMEOUT SEC2TICK(CONFIG_NET_6LOWPAN_MAXAGE)
/****************************************************************************
* Private Data
****************************************************************************/
/* The g_free_reass is a list of reassembly buffer structures that are
* available for general use. The number of messages in this list is a
* system configuration item. Protected only by the network lock.
*/
static FAR struct sixlowpan_reassbuf_s *g_free_reass;
/* This is a list of active, allocated reassemby buffers */
static FAR struct sixlowpan_reassbuf_s *g_active_reass;
/* Pool of pre-allocated reassembly buffer structures */
static struct sixlowpan_reassbuf_s
g_metadata_pool[CONFIG_NET_6LOWPAN_NREASSBUF];
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_compare_fragsrc
*
* Description:
* Check if the fragment that we just received is from the same source as
* the previously received fragments.
*
* Input Parameters:
* radio - Radio network device driver state instance
* fragsrc - The source address of the fragment.
*
* Returned Value:
* true if the sources are the same.
*
****************************************************************************/
static bool sixlowpan_compare_fragsrc(FAR struct sixlowpan_reassbuf_s *reass,
FAR const struct netdev_varaddr_s *fragsrc)
{
/* The addresses cannot match if they are not the same size */
if (fragsrc->nv_addrlen == reass->rb_fragsrc.nv_addrlen)
{
/* The are the same size, return the address comparison */
return (memcmp(fragsrc->nv_addr, reass->rb_fragsrc.nv_addr,
fragsrc->nv_addrlen) == 0);
}
return false;
}
/****************************************************************************
* Name: sixlowpan_reass_expire
*
* Description:
* Free all expired or inactive reassembly buffers.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
static void sixlowpan_reass_expire(void)
{
FAR struct sixlowpan_reassbuf_s *reass;
FAR struct sixlowpan_reassbuf_s *next;
clock_t elapsed;
/* If reassembly timed out, cancel it */
for (reass = g_active_reass; reass != NULL; reass = next)
{
/* Needed if 'reass' is freed */
next = reass->rb_flink;
/* Free any inactive reassembly buffers. This is done because the life
* the reassembly buffer is not cerain.
*/
if (!reass->rb_active)
{
sixlowpan_reass_free(reass);
}
else
{
/* Get the elpased time of the reassembly */
elapsed = clock_systime_ticks() - reass->rb_time;
/* If the reassembly has expired, then free the reassembly buffer */
if (elapsed >= NET_6LOWPAN_TIMEOUT)
{
nwarn("WARNING: Reassembly timed out\n");
sixlowpan_reass_free(reass);
}
}
}
}
/****************************************************************************
* Name: sixlowpan_remove_active
*
* Description:
* Remove a reassembly buffer from the active reassembly buffer list.
*
* Input Parameters:
* reass - The reassembly buffer to be removed.
*
* Returned Value:
* None
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
static void sixlowpan_remove_active(FAR struct sixlowpan_reassbuf_s *reass)
{
FAR struct sixlowpan_reassbuf_s *curr;
FAR struct sixlowpan_reassbuf_s *prev;
/* Find the reassembly buffer in the list of active reassembly buffers */
for (prev = NULL, curr = g_active_reass;
curr != NULL && curr != reass;
prev = curr, curr = curr->rb_flink)
{
}
/* Did we find it? */
if (curr != NULL)
{
/* Yes.. remove it from the active reassembly buffer list */
if (prev == NULL)
{
g_active_reass = reass->rb_flink;
}
else
{
prev->rb_flink = reass->rb_flink;
}
}
reass->rb_flink = NULL;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_reass_initialize
*
* Description:
* This function initializes the reassembly buffer allocator. This
* function must be called early in the initialization sequence before
* any radios begin operation.
*
* Called only once during network initialization.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void sixlowpan_reass_initialize(void)
{
FAR struct sixlowpan_reassbuf_s *reass;
int i;
/* Initialize g_free_reass, the list of reassembly buffer structures that
* are available for allocation.
*/
g_free_reass = NULL;
for (i = 0, reass = g_metadata_pool;
i < CONFIG_NET_6LOWPAN_NREASSBUF;
i++, reass++)
{
/* Add the next meta data structure from the pool to the list of
* general structures.
*/
reass->rb_flink = g_free_reass;
g_free_reass = reass;
}
}
/****************************************************************************
* Name: sixlowpan_reass_allocate
*
* Description:
* The sixlowpan_reass_allocate function will get a free reassembly buffer
* structure for use by 6LoWPAN.
*
* This function will first attempt to allocate from the g_free_reass
* list. If that the list is empty, then the reassembly buffer structure
* will be allocated from the dynamic memory pool.
*
* Input Parameters:
* reasstag - The reassembly tag for subsequent lookup.
* fragsrc - The source address of the fragment.
*
* Returned Value:
* A reference to the allocated reass structure. All fields used by the
* reasembly logic have been zeroed. On a failure to allocate, NULL is
* returned.
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
FAR struct sixlowpan_reassbuf_s *
sixlowpan_reass_allocate(uint16_t reasstag,
FAR const struct netdev_varaddr_s *fragsrc)
{
FAR struct sixlowpan_reassbuf_s *reass;
uint8_t pool;
/* First, removed any expired or inactive reassembly buffers. This might
* free up a pre-allocated buffer for this allocation.
*/
sixlowpan_reass_expire();
/* Now, try the free list first */
if (g_free_reass != NULL)
{
reass = g_free_reass;
g_free_reass = reass->rb_flink;
pool = REASS_POOL_PREALLOCATED;
}
else
{
#ifdef CONFIG_NET_6LOWPAN_REASS_STATIC
reass = NULL;
#else
/* If we cannot get a reassembly buffer instance from the free list,
* then we will have to allocate one from the kernel memory pool.
*/
reass = (FAR struct sixlowpan_reassbuf_s *)
kmm_malloc((sizeof (struct sixlowpan_reassbuf_s)));
pool = REASS_POOL_DYNAMIC;
#endif
}
/* We have successfully allocated memory from some source? */
if (reass != NULL)
{
/* Zero and tag the allocated reassembly buffer structure. */
memset(reass, 0, sizeof(struct sixlowpan_reassbuf_s));
memcpy(&reass->rb_fragsrc, fragsrc, sizeof(struct netdev_varaddr_s));
reass->rb_pool = pool;
reass->rb_active = true;
reass->rb_reasstag = reasstag;
reass->rb_time = clock_systime_ticks();
/* Add the reassembly buffer to the list of active reassembly buffers */
reass->rb_flink = g_active_reass;
g_active_reass = reass;
}
return reass;
}
/****************************************************************************
* Name: sixlowpan_reass_find
*
* Description:
* Find a previously allocated, active reassembly buffer with the specified
* reassembly tag.
*
* Input Parameters:
* reasstag - The reassembly tag to match.
* fragsrc - The source address of the fragment.
*
* Returned Value:
* A reference to the matching reass structure.
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
FAR struct sixlowpan_reassbuf_s *
sixlowpan_reass_find(uint16_t reasstag,
FAR const struct netdev_varaddr_s *fragsrc)
{
FAR struct sixlowpan_reassbuf_s *reass;
/* First, removed any expired or inactive reassembly buffers (we don't want
* to return old reassembly buffer with the same tag)
*/
sixlowpan_reass_expire();
/* Now search for the matching reassembly buffer in the remainng, active
* reassembly buffers.
*/
for (reass = g_active_reass; reass != NULL; reass = reass->rb_flink)
{
/* In order to be a match, it must have the same reassembly tag as
* well as source address (different sources might use the same
* reassembly tag).
*/
if (reass->rb_reasstag == reasstag &&
sixlowpan_compare_fragsrc(reass, fragsrc))
{
return reass;
}
}
/* Not found */
return NULL;
}
/****************************************************************************
* Name: sixlowpan_reass_free
*
* Description:
* The sixlowpan_reass_free function will return a reass structure
* to the free list of messages if it was a pre-allocated reass
* structure. If the reass structure was allocated dynamically it will
* be deallocated.
*
* Input Parameters:
* reass - reass structure to free
*
* Returned Value:
* None
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
void sixlowpan_reass_free(FAR struct sixlowpan_reassbuf_s *reass)
{
/* First, remove the reassembly buffer from the list of active reassembly
* buffers.
*/
sixlowpan_remove_active(reass);
/* If this is a pre-allocated reassembly buffer structure, then just put it
* back in the free list.
*/
if (reass->rb_pool == REASS_POOL_PREALLOCATED)
{
reass->rb_flink = g_free_reass;
g_free_reass = reass;
}
else if (reass->rb_pool == REASS_POOL_DYNAMIC)
{
#ifdef CONFIG_NET_6LOWPAN_REASS_STATIC
DEBUGPANIC();
#else
DEBUGASSERT(reass->rb_pool == REASS_POOL_DYNAMIC);
/* Otherwise, deallocate it. */
kmm_free(reass);
#endif
}
/* If the reassembly buffer structure was provided by the driver, nothing
* needs to be freed.
*/
}
@@ -0,0 +1,278 @@
/****************************************************************************
* net/sixlowpan/sixlowpan_send.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/semaphore.h>
#include <nuttx/net/net.h>
#include <nuttx/net/radiodev.h>
#include "netdev/netdev.h"
#include "devif/devif.h"
#include "sixlowpan/sixlowpan_internal.h"
#ifdef CONFIG_NET_6LOWPAN
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* These are temporary stubs. Something like this would be needed to
* monitor the health of a IPv6 neighbor.
*/
#define neighbor_reachable(dev)
#define neighbor_notreachable(dev)
/****************************************************************************
* Private Types
****************************************************************************/
/* This is the state data provided to the send event handler. 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 */
FAR const struct ipv6_hdr_s *s_ipv6hdr; /* IPv6 header, followed by
* UDP or ICMP header. */
FAR const struct netdev_varaddr_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
****************************************************************************/
/****************************************************************************
* Name: send_eventhandler
*
* Description:
* This function is called with the network locked to perform the actual
* send operation when polled by the lower, device interfacing layer.
*
* Input Parameters:
* dev - The structure of the network driver that generated the event.
* 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_eventhandler(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\n", flags);
/* Verify that this is a compatible network driver. */
if (dev->d_lltype != NET_LL_IEEE802154 &&
dev->d_lltype != NET_LL_PKTRADIO)
{
ninfo("Not a compatible network device\n");
return flags;
}
/* REVISIT: Verify that this is the correct IEEE802.15.4 network driver to
* route the outgoing frame(s). Chances are that there is only one
* IEEE802.15.4 network driver
*/
/* Check if the IEEE802.15.4 network driver went down */
if ((flags & NETDEV_DOWN) != 0)
{
nwarn("WARNING: 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 list to the IEEE802.15.4 MAC device */
sinfo->s_result =
sixlowpan_queue_frames((FAR struct radio_driver_s *)dev,
sinfo->s_ipv6hdr, sinfo->s_buf, sinfo->s_len,
sinfo->s_destmac);
flags &= ~WPAN_POLL;
neighbor_reachable(dev);
goto end_wait;
}
/* 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 */
nxsem_post(&sinfo->s_waitsem);
return flags;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_send
*
* Description:
* Process an outgoing UDP or ICMPv6 packet. Takes an IP packet and
* formats it to be sent on an 802.15.4 network using 6lowpan. Called
* from common UDP/ICMPv6 send logic.
*
* The payload data is in the caller 'buf' and is of length 'buflen'.
* Compressed headers will be added and if necessary the packet is
* fragmented. The resulting packet/fragments are submitted to the MAC
* via the network driver r_req_data method.
*
* Input Parameters:
* dev - The IEEE802.15.4 MAC network driver interface.
* list - Head of callback list for send events
* ipv6hdr - IPv6 header followed by UDP or ICMPv6 header.
* buf - Data to send
* len - Length of data to send
* destmac - The IEEE802.15.4 MAC address of the destination
* timeout - Send timeout in milliseconds
*
* Returned Value:
* Ok is returned on success; Otherwise 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 logic will fall back to normal
* IPv4/IPv6 formatting.
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
int sixlowpan_send(FAR struct net_driver_s *dev,
FAR struct devif_callback_s **list,
FAR const struct ipv6_hdr_s *ipv6hdr, FAR const void *buf,
size_t len, FAR const struct netdev_varaddr_s *destmac,
unsigned int timeout)
{
struct sixlowpan_send_s sinfo;
ninfo("len=%lu timeout=%u\n", (unsigned long)len, timeout);
/* Initialize the send state structure */
nxsem_init(&sinfo.s_waitsem, 0, 0);
nxsem_set_protocol(&sinfo.s_waitsem, SEM_PRIO_NONE);
sinfo.s_result = -EBUSY;
sinfo.s_ipv6hdr = ipv6hdr;
sinfo.s_destmac = destmac;
sinfo.s_buf = buf;
sinfo.s_len = len;
net_lock();
if (len > 0)
{
/* Allocate resources to receive a callback.
*
* The second parameter is NULL meaning that we can get only
* device related events, no connect-related events.
*/
sinfo.s_cb = devif_callback_alloc(dev, list);
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_eventhandler;
/* Notify the IEEE802.15.4 MAC that we have data to send. */
netdev_txnotify_dev(dev);
/* Wait for the send to complete or an error to occur.
* net_timedwait will also terminate if a signal is received.
*/
ninfo("Wait for send complete\n");
ret = net_timedwait(&sinfo.s_waitsem, timeout);
if (ret < 0)
{
if (ret == -ETIMEDOUT)
{
neighbor_notreachable(dev);
}
sinfo.s_result = ret;
}
/* Make sure that no further events are processed */
devif_conn_callback_free(dev, sinfo.s_cb, list);
}
}
nxsem_destroy(&sinfo.s_waitsem);
net_unlock();
return (sinfo.s_result < 0 ? sinfo.s_result : len);
}
#endif /* CONFIG_NET_6LOWPAN */
@@ -0,0 +1,930 @@
/****************************************************************************
* net/sixlowpan/sixlowpan_tcpsend.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <inttypes.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/semaphore.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/radiodev.h>
#include <nuttx/net/netstats.h>
#include "netdev/netdev.h"
#include "devif/devif.h"
#include "socket/socket.h"
#include "inet/inet.h"
#include "icmpv6/icmpv6.h"
#include "tcp/tcp.h"
#include "utils/utils.h"
#include "sixlowpan/sixlowpan_internal.h"
#if defined(CONFIG_NET_6LOWPAN) && defined(CONFIG_NET_TCP)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Buffer access helpers */
#define TCPBUF(dev) ((FAR struct tcp_hdr_s *)(&(dev)->d_buf[IPv6_HDRLEN]))
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* These are temporary stubs. Something like this would be needed to
* monitor the health of a IPv6 neighbor.
*/
#define neighbor_reachable(dev)
#define neighbor_notreachable(dev)
/****************************************************************************
* Private Types
****************************************************************************/
/* This is the state data provided to the send event handler. 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 socket *s_sock; /* Internal socket reference */
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 */
FAR const struct netdev_varaddr_s *s_destmac; /* Destination MAC address */
FAR const uint8_t *s_buf; /* Data to send */
size_t s_buflen; /* Length of data in buf */
ssize_t s_sent; /* The number of bytes sent */
uint32_t s_isn; /* Initial sequence number */
uint32_t s_acked; /* The number of bytes acked */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_tcp_chksum
*
* Description:
* Perform the checksum calcaultion over the IPv6, protocol headers, and
* data payload as necessary.
*
* Input Parameters:
* ipv6tcp - A reference to a structure containing the IPv6 and TCP
* headers.
* buf - The beginning of the payload data
* buflen - The length of the payload data.
*
* Returned Value:
* The calculated checksum
*
****************************************************************************/
static uint16_t sixlowpan_tcp_chksum(FAR const struct ipv6tcp_hdr_s *ipv6tcp,
FAR const uint8_t *buf, uint16_t buflen)
{
uint16_t upperlen;
uint16_t tcplen;
uint16_t sum;
/* The length reported in the IPv6 header is the length of the payload
* that follows the header.
*/
upperlen = ((uint16_t)ipv6tcp->ipv6.len[0] << 8) + ipv6tcp->ipv6.len[1];
/* Verify some minimal assumptions */
if (upperlen > CONFIG_NET_6LOWPAN_PKTSIZE)
{
return 0;
}
/* The checksum is calculated starting with a pseudo-header of IPv6 header
* fields according to the IPv6 standard, which consists of the source
* and destination addresses, the packet length and the next header field.
*/
sum = upperlen + ipv6tcp->ipv6.proto;
/* Sum IP source and destination addresses. */
sum = chksum(sum, (FAR uint8_t *)ipv6tcp->ipv6.srcipaddr,
2 * sizeof(net_ipv6addr_t));
/* Sum the TCP header
*
* The TCP header length is encoded in the top 4 bits of the tcpoffset
* field (in units of 32-bit words).
*/
tcplen = ((uint16_t)ipv6tcp->tcp.tcpoffset >> 4) << 2;
sum = chksum(sum, (FAR uint8_t *)&ipv6tcp->tcp, tcplen);
/* Sum payload data. */
sum = chksum(sum, buf, buflen);
return (sum == 0) ? 0xffff : htons(sum);
}
/****************************************************************************
* Name: sixlowpan_tcp_header
*
* Description:
* sixlowpan_tcp_header() will construct the IPv6 and TCP headers
*
* Input Parameters:
* conn - An instance of the TCP connection structure.
* dev - The network device that will route the packet
* buf - Data to send
* bulen - Length of data to send
* ipv6tcp - The location to save the IPv6 + TCP header
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* failure.
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
static int sixlowpan_tcp_header(FAR struct tcp_conn_s *conn,
FAR struct net_driver_s *dev,
FAR const void *buf, size_t buflen,
FAR struct ipv6tcp_hdr_s *ipv6tcp)
{
uint16_t iplen;
/* Initialize the IPv6/TCP headers */
ipv6tcp->ipv6.vtc = 0x60;
ipv6tcp->ipv6.tcf = 0x00;
ipv6tcp->ipv6.flow = 0x00;
ipv6tcp->ipv6.proto = IP_PROTO_TCP;
ipv6tcp->ipv6.ttl = IP_TTL;
/* The IPv6 header length field does not include the size of IPv6 IP
* header.
*/
iplen = buflen + TCP_HDRLEN;
ipv6tcp->ipv6.len[0] = (iplen >> 8);
ipv6tcp->ipv6.len[1] = (iplen & 0xff);
/* Copy the source and destination addresses */
net_ipv6addr_hdrcopy(ipv6tcp->ipv6.destipaddr, conn->u.ipv6.raddr);
if (!net_ipv6addr_cmp(conn->u.ipv6.laddr, g_ipv6_unspecaddr))
{
net_ipv6addr_hdrcopy(ipv6tcp->ipv6.srcipaddr, conn->u.ipv6.laddr);
}
else
{
net_ipv6addr_hdrcopy(ipv6tcp->ipv6.srcipaddr, dev->d_ipv6addr);
}
ninfo("IPv6 length: %d\n",
((int)ipv6tcp->ipv6.len[0] << 8) + ipv6tcp->ipv6.len[1]);
#ifdef CONFIG_NET_STATISTICS
g_netstats.ipv6.sent++;
#endif
/* Initialize the TCP header */
ipv6tcp->tcp.srcport = conn->lport; /* Local port */
ipv6tcp->tcp.destport = conn->rport; /* Connected remote port */
ipv6tcp->tcp.tcpoffset = (TCP_HDRLEN / 4) << 4; /* No optdata */
ipv6tcp->tcp.flags = TCP_ACK | TCP_PSH; /* No urgent data */
ipv6tcp->tcp.urgp[0] = 0; /* No urgent data */
ipv6tcp->tcp.urgp[1] = 0;
/* Set the sequency number information.
*
* REVISIT: There is currently no wait for the data to be ACKed and,
* hence, no mechanism to retransmit the packet.
*/
memcpy(ipv6tcp->tcp.ackno, conn->rcvseq, 4); /* ACK number */
memcpy(ipv6tcp->tcp.seqno, conn->sndseq, 4); /* Sequence number */
/* Set the TCP window */
if (conn->tcpstateflags & TCP_STOPPED)
{
/* If the connection has issued TCP_STOPPED, we advertise a zero
* window so that the remote host will stop sending data.
*/
ipv6tcp->tcp.wnd[0] = 0;
ipv6tcp->tcp.wnd[1] = 0;
}
else
{
/* Update the TCP received window based on I/O buffer availability */
uint16_t recvwndo = tcp_get_recvwindow(dev, conn);
/* Set the TCP Window */
ipv6tcp->tcp.wnd[0] = recvwndo >> 8;
ipv6tcp->tcp.wnd[1] = recvwndo & 0xff;
/* Update the Receiver Window */
conn->rcv_wnd = recvwndo;
}
/* Calculate TCP checksum. */
ipv6tcp->tcp.tcpchksum = 0;
ipv6tcp->tcp.tcpchksum = ~sixlowpan_tcp_chksum(ipv6tcp, buf, buflen);
ninfo("Outgoing TCP packet length: %d bytes\n", iplen + IPv6_HDRLEN);
return OK;
}
/****************************************************************************
* Name: tcp_send_eventhandler
*
* Description:
* This function is called with the network locked to perform the actual
* TCP send operation when polled by the lower, device interfacing layer.
*
* Input Parameters:
* dev - The structure of the network driver that generated the event.
* pvconn - The connection structure associated with the socket
* pvpriv - The event handler's private data argument
* flags - Set of events describing why the callback was invoked
*
* Returned Value:
* None
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
static uint16_t tcp_send_eventhandler(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;
FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn;
struct ipv6tcp_hdr_s ipv6tcp;
int ret;
/* Verify that this is an IEEE802.15.4 network driver. */
if (dev->d_lltype != NET_LL_IEEE802154 &&
dev->d_lltype != NET_LL_PKTRADIO)
{
ninfo("Not a compatible network device\n");
return flags;
}
/* Check if the IEEE802.15.4 network driver went down */
if ((flags & NETDEV_DOWN) != 0)
{
nwarn("WARNING: Device is down\n");
sinfo->s_result = -ENOTCONN;
goto end_wait;
}
/* The TCP socket is connected and, hence, should be bound to a device.
* Make sure that the polling device is the one that we are bound to.
*/
DEBUGASSERT(conn->dev != NULL);
if (dev != conn->dev)
{
ninfo("Not the connected device\n");
return flags;
}
ninfo("flags: %04x acked: %" PRIu32 " sent: %zu\n",
flags, sinfo->s_acked, sinfo->s_sent);
/* If this packet contains an acknowledgement, then update the count of
* acknowledged bytes.
*/
if ((flags & TCP_ACKDATA) != 0)
{
FAR struct tcp_hdr_s *tcp = TCPBUF(dev);
/* The current acknowledgement number number is the (relative) offset
* of the of the next byte needed by the receiver. The s_isn is the
* offset of the first byte to send to the receiver. The difference
* is the number of bytes to be acknowledged.
*/
sinfo->s_acked = tcp_getsequence(tcp->ackno) - sinfo->s_isn;
ninfo("ACK: acked=%" PRId32 " sent=%zd buflen=%zd\n",
sinfo->s_acked, sinfo->s_sent, sinfo->s_buflen);
/* Have all of the bytes in the buffer been sent and acknowledged? */
if (sinfo->s_acked >= sinfo->s_buflen)
{
/* Yes. Then sinfo->s_buflen should hold the number of bytes
* actually sent.
*/
sinfo->s_result = sinfo->s_sent;
goto end_wait;
}
/* No.. fall through to send more data if necessary */
}
/* Check if we are being asked to retransmit data */
else if ((flags & TCP_REXMIT) != 0)
{
/* Yes.. in this case, reset the number of bytes that have been sent
* to the number of bytes that have been ACKed.
*/
sinfo->s_sent = sinfo->s_acked;
/* Fall through to re-send data from the last that was ACKed */
}
/* Check for a loss of connection */
else if ((flags & TCP_DISCONN_EVENTS) != 0)
{
FAR struct socket *psock = sinfo->s_sock;
nwarn("WARNING: Lost connection\n");
/* We could get here recursively through the callback actions of
* tcp_lost_connection(). So don't repeat that action if we have
* already been disconnected.
*/
DEBUGASSERT(psock != NULL);
if (_SS_ISCONNECTED(psock->s_flags))
{
/* Report the disconnection event to all socket clones */
tcp_lost_connection(psock, sinfo->s_cb, flags);
}
/* Report not connected to the sender */
sinfo->s_result = -ENOTCONN;
goto end_wait;
}
/* Check if the outgoing packet is available (it may have been claimed
* by a sendto event handler serving a different thread).
*/
#if 0 /* We can't really support multiple senders on the same TCP socket */
else if (dev->d_sndlen > 0)
{
/* Another thread has beat us sending data, wait for the next poll */
return flags;
}
#endif
/* We get here if (1) not all of the data has been ACKed, (2) we have been
* asked to retransmit data, (3) the connection is still healthy, and (4)
* the outgoing packet is available for our use. In this case, we are
* now free to send more data to receiver -- UNLESS the buffer contains
* unprocessed incoming data. In that event, we will have to wait for the
* next polling cycle.
*/
if ((flags & WPAN_NEWDATA) == 0 && sinfo->s_sent < sinfo->s_buflen)
{
uint32_t seqno;
uint16_t winleft;
uint16_t sndlen;
/* Get the amount of TCP payload data that we can send in the next
* packet.
*/
sndlen = sinfo->s_buflen - sinfo->s_sent;
if (sndlen > conn->mss)
{
sndlen = conn->mss;
}
winleft = conn->snd_wnd - sinfo->s_sent + sinfo->s_acked;
if (sndlen > winleft)
{
sndlen = winleft;
}
ninfo("s_buflen=%zu s_sent=%zu mss=%u snd_wnd=%u sndlen=%d\n",
sinfo->s_buflen, sinfo->s_sent, conn->mss, conn->snd_wnd,
sndlen);
if (sndlen > 0)
{
/* Set the sequence number for this packet. NOTE: The network
* updates sndseq on receipt of ACK *before* this function is
* called. In that case sndseq will point to the next
* unacknowledged byte (which might have already been sent). We
* will overwrite the value of sndseq here before the packet is
* sent.
*/
seqno = sinfo->s_sent + sinfo->s_isn;
ninfo("Sending: sndseq %08" PRIx32 "->%08" PRIx32 "\n",
tcp_getsequence(conn->sndseq), seqno);
tcp_setsequence(conn->sndseq, seqno);
/* Create the IPv6 + TCP header */
ret = sixlowpan_tcp_header(conn, dev, &sinfo->s_buf[sinfo->s_sent],
sndlen, &ipv6tcp);
if (ret < 0)
{
nerr("ERROR: sixlowpan_tcp_header failed: %d\n", ret);
sinfo->s_result = ret;
goto end_wait;
}
/* Transfer the frame list to the IEEE802.15.4 MAC device */
ret = sixlowpan_queue_frames((FAR struct radio_driver_s *)dev,
&ipv6tcp.ipv6,
&sinfo->s_buf[sinfo->s_sent], sndlen,
sinfo->s_destmac);
if (ret < 0)
{
nerr("ERROR: sixlowpan_queue_frames failed: %d\n", ret);
sinfo->s_result = ret;
goto end_wait;
}
/* Increment the count of bytes sent, the number of unacked bytes,
* and the total count of TCP packets sent.
*
* NOTE: tcp_appsend() normally increments conn->tx_unacked based
* on the value of dev->d_sndlen. However, dev->d_len is always
* zero for 6LoWPAN since it does not send via the dev->d_buf
* but, rather, uses a backdoor frame interface with the IEEE
* 802.15.4 MAC.
*/
sinfo->s_sent += sndlen;
conn->tx_unacked += sndlen;
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
/* For compatibility with buffered send logic */
conn->sndseq_max = tcp_addsequence(conn->sndseq, conn->tx_unacked);
#endif
#ifdef CONFIG_NET_STATISTICS
g_netstats.tcp.sent++;
#endif
ninfo("Sent: acked=%" PRId32 " sent=%zd "
"buflen=%zd tx_unacked=%" PRId32 "\n",
sinfo->s_acked, sinfo->s_sent, sinfo->s_buflen,
(uint32_t)conn->tx_unacked);
}
}
/* 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;
/* There are no outstanding, unacknowledged bytes */
conn->tx_unacked = 0;
/* Wake up the waiting thread */
nxsem_post(&sinfo->s_waitsem);
return flags;
}
/****************************************************************************
* Name: sixlowpan_send_packet
*
* Description:
* Process an outgoing TCP packet. Takes an IP packet and formats it to
* be sent on an 802.15.4 network using 6lowpan. Called from common TCP
* send logic.
*
* The payload data is in the caller 'buf' and is of length 'buflen'.
* Compressed headers will be added and if necessary the packet is
* fragmented. The resulting packet/fragments are submitted to the MAC
* via the network driver r_req_data method.
*
* Input Parameters:
* psock - An instance of the internal socket structure.
* dev - The IEEE802.15.4 MAC network driver interface.
* conn - TCP connection structure
* buf - Data to send
* len - Length of data to send
* destmac - The IEEE802.15.4 MAC address of the destination
* timeout - Send timeout in milliseconds
*
* Returned Value:
* Ok is returned on success; Otherwise 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 logic will fall back to normal
* IPv4/IPv6 formatting.
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
static int sixlowpan_send_packet(FAR struct socket *psock,
FAR struct net_driver_s *dev,
FAR struct tcp_conn_s *conn,
FAR const uint8_t *buf, size_t len,
FAR const struct netdev_varaddr_s *destmac,
unsigned int timeout)
{
struct sixlowpan_send_s sinfo;
ninfo("len=%lu timeout=%u\n", (unsigned long)len, timeout);
DEBUGASSERT(psock != NULL && dev != NULL && conn != NULL && buf != NULL &&
destmac != NULL);
memset(&sinfo, 0, sizeof(struct sixlowpan_send_s));
net_lock();
if (len > 0)
{
/* Allocate resources to receive a callback.
*
* The second parameter is NULL meaning that we can get only
* device related events, no connect-related events.
*/
sinfo.s_cb = tcp_callback_alloc(conn);
if (sinfo.s_cb != NULL)
{
int ret;
/* Initialize the send state structure */
nxsem_init(&sinfo.s_waitsem, 0, 0);
nxsem_set_protocol(&sinfo.s_waitsem, SEM_PRIO_NONE);
sinfo.s_sock = psock;
sinfo.s_result = -EBUSY;
sinfo.s_destmac = destmac;
sinfo.s_buf = buf;
sinfo.s_buflen = len;
/* Set up the initial sequence number */
sinfo.s_isn = tcp_getsequence(conn->sndseq);
/* Set up the callback in the connection */
sinfo.s_cb->flags = (NETDEV_DOWN | TCP_ACKDATA | TCP_REXMIT |
TCP_DISCONN_EVENTS | WPAN_POLL);
sinfo.s_cb->priv = (FAR void *)&sinfo;
sinfo.s_cb->event = tcp_send_eventhandler;
/* There is no outstanding, unacknowledged data after this
* initial sequence number.
*/
conn->tx_unacked = 0;
/* Notify the IEEE802.15.4 MAC that we have data to send. */
netdev_txnotify_dev(dev);
/* Wait for the send to complete or an error to occur.
* net_timedwait will also terminate if a signal is received.
*/
ninfo("Wait for send complete\n");
for (; ; )
{
uint32_t acked = sinfo.s_acked;
ret = net_timedwait(&sinfo.s_waitsem, timeout);
if (ret != -ETIMEDOUT || acked == sinfo.s_acked)
{
break; /* Timeout without any progress */
}
}
if (ret < 0)
{
sinfo.s_result = ret;
}
/* Make sure that no further events are processed */
tcp_callback_free(conn, sinfo.s_cb);
}
}
nxsem_destroy(&sinfo.s_waitsem);
net_unlock();
return (sinfo.s_result < 0 ? sinfo.s_result : len);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: psock_6lowpan_tcp_send
*
* Description:
* psock_6lowpan_tcp_send() call may be used only when the TCP socket is
* in a connected state (so that the intended recipient is known).
*
* Input Parameters:
* psock - An instance of the internal socket structure.
* buf - Data to send
* bulen - Length of data to send
*
* 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().
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
size_t buflen)
{
FAR struct tcp_conn_s *conn;
FAR struct net_driver_s *dev;
struct netdev_varaddr_s destmac;
int ret;
ninfo("buflen %lu\n", (unsigned long)buflen);
sixlowpan_dumpbuffer("Outgoing TCP payload", buf, buflen);
DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
DEBUGASSERT(psock->s_type == SOCK_STREAM);
/* Make sure that this is a valid socket */
if (psock == NULL || psock->s_conn == NULL)
{
nerr("ERROR: Invalid socket\n");
return (ssize_t)-EBADF;
}
/* Make sure that this is a connected TCP socket */
if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags))
{
nerr("ERROR: Not connected\n");
return (ssize_t)-ENOTCONN;
}
/* Get the underlying TCP connection structure */
conn = (FAR struct tcp_conn_s *)psock->s_conn;
#ifdef CONFIG_NET_IPv4
/* Ignore if not IPv6 domain */
if (conn->domain != PF_INET6)
{
nwarn("WARNING: Not IPv6\n");
return (ssize_t)-EPROTOTYPE;
}
#endif
/* Route outgoing message to the correct device */
dev = netdev_findby_ripv6addr(conn->u.ipv6.laddr, conn->u.ipv6.raddr);
if (dev == NULL)
{
nwarn("WARNING: Not routable\n");
return (ssize_t)-ENETUNREACH;
}
/* Some network devices support different link layer protocols.
* Check if this device has the hooks to support 6LoWPAN.
*/
if (dev->d_lltype != NET_LL_IEEE802154 &&
dev->d_lltype != NET_LL_PKTRADIO)
{
nwarn("WARNING: Not a compatible network device\n");
return (ssize_t)-ENONET;
}
#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
/* Get the IEEE 802.15.4 MAC address of the next hop. */
ret = sixlowpan_nexthopaddr((FAR struct radio_driver_s *)dev,
conn->u.ipv6.raddr, &destmac);
if (ret < 0)
{
nerr("ERROR: Failed to get dest MAC address: %d\n", ret);
return (ssize_t)ret;
}
/* Send the TCP packets, breaking down the potential large user buffer
* into smaller packets that can be reassembled in the allocated MTU
* packet buffer.
*/
ret = sixlowpan_send_packet(psock, dev, conn, buf, buflen, &destmac,
_SO_TIMEOUT(psock->s_sndtimeo));
if (ret < 0)
{
nerr("ERROR: sixlowpan_send_packet() failed: %d\n", ret);
return (ssize_t)ret;
}
return (ssize_t)buflen;
}
/****************************************************************************
* Name: sixlowpan_tcp_send
*
* Description:
* TCP output comes through three 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 psock_6lowpan_tcp_send().
* 2. TCP output from the TCP state machine. That will occur
* during TCP packet processing by the TCP state meachine.
* 3. TCP output resulting from TX or timer polling
*
* Cases 2 and 3 will be handled here. Logic in ipv6_tcp_input(),
* devif_poll(), and devif_timer() detect if (1) an attempt to return with
* d_len > 0 and (2) that the device is an IEEE802.15.4 MAC network
* driver. Under those conditions, this function will be called to create
* the IEEE80215.4 frames.
*
* Input Parameters:
* dev - The network device containing the packet to be sent.
* fwddev - The network device used to send the data. This will be the
* same device except for the IP forwarding case where packets
* are sent across devices.
* ipv6 - A pointer to the IPv6 header in dev->d_buf which lies AFTER
* the L1 header. NOTE: dev->d_len must have been decremented
* by the size of any preceding MAC header.
*
* Returned Value:
* None
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
void sixlowpan_tcp_send(FAR struct net_driver_s *dev,
FAR struct net_driver_s *fwddev,
FAR struct ipv6_hdr_s *ipv6)
{
DEBUGASSERT(dev != NULL && dev->d_len > 0 && fwddev != NULL);
/* Double check */
ninfo("d_len %u\n", dev->d_len);
sixlowpan_dumpbuffer("Outgoing TCP packet",
(FAR const uint8_t *)ipv6, dev->d_len);
if (dev != NULL && dev->d_len > 0 && fwddev != NULL)
{
FAR struct ipv6tcp_hdr_s *ipv6hdr;
/* The IPv6 header followed by a TCP headers should lie at the
* beginning of d_buf since there is no link layer protocol header
* and the TCP state machine should only response with TCP packets.
*/
ipv6hdr = (FAR struct ipv6tcp_hdr_s *)ipv6;
/* The TCP data payload should follow the IPv6 header plus the
* protocol header.
*/
if (ipv6hdr->ipv6.proto != IP_PROTO_TCP)
{
nwarn("WARNING: Expected TCP prototype: %u vs %u\n",
ipv6hdr->ipv6.proto, IP_PROTO_TCP);
}
else
{
struct netdev_varaddr_s destmac;
FAR uint8_t *buf;
uint16_t hdrlen;
uint16_t buflen;
int ret;
/* Get the IEEE 802.15.4 MAC address of the next hop. */
ret = sixlowpan_nexthopaddr((FAR struct radio_driver_s *)fwddev,
ipv6hdr->ipv6.destipaddr, &destmac);
if (ret < 0)
{
nerr("ERROR: Failed to get dest MAC address: %d\n", ret);
goto drop;
}
/* Get the IPv6 + TCP combined header length. The size of the TCP
* header is encoded in the top 4 bits of the tcpoffset field (in
* units of 32-bit words).
*/
hdrlen = IPv6_HDRLEN +
(((uint16_t)ipv6hdr->tcp.tcpoffset >> 4) << 2);
/* Drop the packet if the buffer length is less than this. */
if (hdrlen > dev->d_len)
{
nwarn("WARNING: Dropping small TCP packet: %u < %u\n",
buflen, hdrlen);
}
else
{
/* Convert the outgoing packet into a frame list. */
buf = (FAR uint8_t *)ipv6 + hdrlen;
buflen = dev->d_len - hdrlen;
sixlowpan_queue_frames(
(FAR struct radio_driver_s *)fwddev,
&ipv6hdr->ipv6, buf, buflen, &destmac);
}
}
}
drop:
dev->d_len = 0;
}
#endif /* CONFIG_NET_6LOWPAN && CONFIG_NET_TCP */
@@ -0,0 +1,481 @@
/****************************************************************************
* net/sixlowpan/sixlowpan_udpsend.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/socket.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include "nuttx/net/netdev.h"
#include "nuttx/net/radiodev.h"
#include "nuttx/net/netstats.h"
#include "netdev/netdev.h"
#include "socket/socket.h"
#include "inet/inet.h"
#include "icmpv6/icmpv6.h"
#include "udp/udp.h"
#include "utils/utils.h"
#include "sixlowpan/sixlowpan_internal.h"
#if defined(CONFIG_NET_6LOWPAN) && defined(CONFIG_NET_UDP)
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_udp_chksum
*
* Description:
* Perform the checksum calculation over the IPv6, protocol headers, and
* data payload as necessary.
*
* Input Parameters:
* ipv6udp - A reference to a structure containing the IPv6 and UDP
* headers.
* buf - The beginning of the payload data
* buflen - The length of the payload data.
*
* Returned Value:
* The calculated checksum
*
****************************************************************************/
#ifdef CONFIG_NET_UDP_CHECKSUMS
static uint16_t sixlowpan_udp_chksum(FAR const struct ipv6udp_hdr_s *ipv6udp,
FAR const uint8_t *buf, uint16_t buflen)
{
uint16_t upperlen;
uint16_t sum;
/* The length reported in the IPv6 header is the length of the payload
* that follows the header.
*/
upperlen = ((uint16_t)ipv6udp->ipv6.len[0] << 8) + ipv6udp->ipv6.len[1];
/* Verify some minimal assumptions */
if (upperlen > CONFIG_NET_6LOWPAN_PKTSIZE)
{
return 0;
}
/* The checksum is calculated starting with a pseudo-header of IPv6 header
* fields according to the IPv6 standard, which consists of the source
* and destination addresses, the packet length and the next header field.
*/
sum = upperlen + ipv6udp->ipv6.proto;
/* Sum IP source and destination addresses. */
sum = chksum(sum, (FAR uint8_t *)ipv6udp->ipv6.srcipaddr,
2 * sizeof(net_ipv6addr_t));
/* Sum the UDP header */
sum = chksum(sum, (FAR uint8_t *)&ipv6udp->udp, UDP_HDRLEN);
/* Sum payload data. */
sum = chksum(sum, buf, buflen);
return (sum == 0) ? 0xffff : htons(sum);
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: 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.
*
* Input Parameters:
* psock A pointer to a NuttX-specific, internal socket structure
* buf Data to send
* buflen 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 buflen, 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 netdev_varaddr_s destmac;
uint16_t iplen;
int ret;
ninfo("buflen %lu\n", (unsigned long)buflen);
DEBUGASSERT(psock != NULL && psock->s_conn != NULL && to != NULL);
DEBUGASSERT(psock->s_type == SOCK_DGRAM);
sixlowpan_dumpbuffer("Outgoing UDP payload", buf, buflen);
if (psock == NULL || to == NULL)
{
return (ssize_t)-EINVAL;
}
/* Make sure that this is a datagram valid socket */
if (psock->s_conn == NULL || 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: sin6_family=%u tolen = %u\n",
to6->sin6_family, tolen);
return (ssize_t)-EPROTOTYPE;
}
/* Get the underlying UDP "connection" structure */
conn = (FAR struct udp_conn_s *)psock->s_conn;
DEBUGASSERT(conn != NULL);
/* Route outgoing message to the correct device */
dev = netdev_findby_ripv6addr(conn->u.ipv6.laddr,
to6->sin6_addr.in6_u.u6_addr16);
if (dev == NULL)
{
nwarn("WARNING: Not routable\n");
return (ssize_t)-ENETUNREACH;
}
/* Some network devices support different link layer protocols.
* Check if this device has the hooks to support 6LoWPAN.
*/
if (dev->d_lltype != NET_LL_IEEE802154 &&
dev->d_lltype != NET_LL_PKTRADIO)
{
nwarn("WARNING: Not a compatible network device\n");
return (ssize_t)-ENONET;
}
#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 */
ipv6udp.ipv6.vtc = 0x60;
ipv6udp.ipv6.tcf = 0x00;
ipv6udp.ipv6.flow = 0x00;
ipv6udp.ipv6.proto = IP_PROTO_UDP;
ipv6udp.ipv6.ttl = conn->ttl;
/* The IPv6 header length field does not include the size of IPv6 IP
* header.
*/
iplen = buflen + UDP_HDRLEN;
ipv6udp.ipv6.len[0] = (iplen >> 8);
ipv6udp.ipv6.len[1] = (iplen & 0xff);
/* Copy the source and destination addresses */
net_ipv6addr_hdrcopy(ipv6udp.ipv6.destipaddr,
to6->sin6_addr.in6_u.u6_addr16);
if (!net_ipv6addr_cmp(conn->u.ipv6.laddr, g_ipv6_unspecaddr))
{
net_ipv6addr_hdrcopy(ipv6udp.ipv6.srcipaddr, conn->u.ipv6.laddr);
}
else
{
net_ipv6addr_hdrcopy(ipv6udp.ipv6.srcipaddr, dev->d_ipv6addr);
}
ninfo("IPv6 length: %d\n",
((int)ipv6udp.ipv6.len[0] << 8) + ipv6udp.ipv6.len[1]);
#ifdef CONFIG_NET_STATISTICS
g_netstats.ipv6.sent++;
#endif
/* Initialize the UDP header */
ipv6udp.udp.srcport = conn->lport;
ipv6udp.udp.destport = to6->sin6_port;
ipv6udp.udp.udplen = htons(iplen);
ipv6udp.udp.udpchksum = 0;
#ifdef CONFIG_NET_UDP_CHECKSUMS
ipv6udp.udp.udpchksum = ~sixlowpan_udp_chksum(&ipv6udp, buf, buflen);
if (ipv6udp.udp.udpchksum == 0)
{
ipv6udp.udp.udpchksum = 0xffff;
}
#endif /* CONFIG_NET_UDP_CHECKSUMS */
ninfo("Outgoing UDP packet length: %d\n", iplen + IPv6_HDRLEN);
#ifdef CONFIG_NET_STATISTICS
g_netstats.udp.sent++;
#endif
/* Get the IEEE 802.15.4 MAC address of the next hop. */
ret = sixlowpan_nexthopaddr((FAR struct radio_driver_s *)dev,
to6->sin6_addr.in6_u.u6_addr16, &destmac);
if (ret < 0)
{
nerr("ERROR: Failed to get dest MAC address: %d\n", ret);
return (ssize_t)ret;
}
/* If routable, then call sixlowpan_send() to format and send the 6LoWPAN
* packet.
*/
ret = sixlowpan_send(dev, &conn->list,
(FAR const struct ipv6_hdr_s *)&ipv6udp,
buf, buflen, &destmac,
_SO_TIMEOUT(psock->s_sndtimeo));
if (ret < 0)
{
nerr("ERROR: sixlowpan_send() failed: %d\n", ret);
}
return (ssize_t)ret;
}
/****************************************************************************
* Name: psock_6lowpan_udp_send
*
* Description:
* psock_6lowpan_udp_send() call may be used with connectionlesss UDP
* sockets.
*
* Input Parameters:
* psock - An instance of the internal socket structure.
* buf - Data to send
* buflen - Length of data to send
*
* 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().
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf,
size_t buflen)
{
FAR struct udp_conn_s *conn;
struct sockaddr_in6 to;
ninfo("buflen %lu\n", (unsigned long)buflen);
DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
DEBUGASSERT(psock->s_type == SOCK_DGRAM);
sixlowpan_dumpbuffer("Outgoing UDP payload", buf, buflen);
/* Make sure that this is a valid socket */
if (psock == NULL || psock->s_conn == NULL)
{
nerr("ERROR: Invalid socket\n");
return (ssize_t)-EBADF;
}
/* Was the UDP socket connected via connect()? */
if (psock->s_type != SOCK_DGRAM || !_SS_ISCONNECTED(psock->s_flags))
{
/* No, then it is not legal to call send() with this socket. */
return -ENOTCONN;
}
/* Get the underlying UDP "connection" structure */
conn = (FAR struct udp_conn_s *)psock->s_conn;
/* Ignore if not IPv6 domain */
if (conn->domain != PF_INET6)
{
nwarn("WARNING: Not IPv6\n");
return (ssize_t)-EPROTOTYPE;
}
/* Create the 'to' address */
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);
return psock_6lowpan_udp_sendto(psock, buf, buflen, 0,
(FAR const struct sockaddr *)&to,
sizeof(struct sockaddr_in6));
}
/****************************************************************************
* Name: sixlowpan_udp_send
*
* Description:
* Handles forwarding a UDP packet via 6LoWPAN. This is currently only
* used by the IPv6 forwarding logic.
*
* Input Parameters:
* dev - An instance of network device state structure
* fwddev - The network device used to send the data. This will be the
* same device except for the IP forwarding case where packets
* are sent across devices.
* ipv6 - A pointer to the IPv6 header in dev->d_buf which lies AFTER
* the L1 header. NOTE: dev->d_len must have been decremented
* by the size of any preceding MAC header.
*
* Returned Value:
* None
*
* Assumptions:
* Called with the network locked.
*
****************************************************************************/
#ifdef CONFIG_NET_IPFORWARD
void sixlowpan_udp_send(FAR struct net_driver_s *dev,
FAR struct net_driver_s *fwddev,
FAR struct ipv6_hdr_s *ipv6)
{
FAR struct ipv6udp_hdr_s *ipv6udp = (FAR struct ipv6udp_hdr_s *)ipv6;
/* Double check */
DEBUGASSERT(dev != NULL && dev->d_len > 0 && fwddev != NULL);
ninfo("d_len %u\n", dev->d_len);
if (dev != NULL && dev->d_len > 0 && fwddev != NULL)
{
sixlowpan_dumpbuffer("Outgoing UDP packet",
(FAR const uint8_t *)ipv6udp, dev->d_len);
/* The UDP data payload should follow the IPv6 header plus the
* protocol header.
*/
if (ipv6udp->ipv6.proto != IP_PROTO_UDP)
{
nwarn("WARNING: Expected UDP prototype: %u vs %u\n",
ipv6udp->ipv6.proto, IP_PROTO_UDP);
}
else
{
struct netdev_varaddr_s destmac;
FAR uint8_t *buf;
uint16_t hdrlen;
uint16_t buflen;
int ret;
/* Get the IEEE 802.15.4 MAC address of the next hop. */
ret = sixlowpan_nexthopaddr((FAR struct radio_driver_s *)fwddev,
ipv6udp->ipv6.destipaddr, &destmac);
if (ret < 0)
{
nerr("ERROR: Failed to get dest MAC address: %d\n", ret);
goto drop;
}
/* Get the IPv6 + UDP combined header length. */
hdrlen = IPv6_HDRLEN + UDP_HDRLEN;
/* Drop the packet if the buffer length is less than this. */
if (hdrlen > dev->d_len)
{
nwarn("WARNING: Dropping small UDP packet: %u < %u\n",
buflen, hdrlen);
}
else
{
/* Convert the outgoing packet into a frame list. */
buf = (FAR uint8_t *)ipv6 + hdrlen;
buflen = dev->d_len - hdrlen;
sixlowpan_queue_frames(
(FAR struct radio_driver_s *)fwddev,
&ipv6udp->ipv6, buf, buflen, &destmac);
}
}
}
drop:
dev->d_len = 0;
}
#endif
#endif /* CONFIG_NET_6LOWPAN && CONFIG_NET_UDP */
@@ -0,0 +1,817 @@
/****************************************************************************
* net/sixlowpan/sixlowpan_utils.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Derives from logic in 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/net/ip.h>
#include <nuttx/net/radiodev.h>
#include <nuttx/net/sixlowpan.h>
#include <nuttx/wireless/pktradio.h>
#include <nuttx/wireless/ieee802154/ieee802154_mac.h>
#include "route/route.h"
#include "inet/inet.h"
#include "sixlowpan/sixlowpan_internal.h"
#ifdef CONFIG_NET_6LOWPAN
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* REVISIT: The setting CONFIG_PKTRADIO_ADDRLEN should be the *maximum*
* address length. If there is only a single packet radio then it should be
* the exact address length of that radio. If there are multiple packet
* radios with different address lengths, then it will be inexact; it will
* be the size of the longest address.
*/
#undef HAVE_BYTEADDR
#undef HAVE_SADDR
#undef HAVE_EADDR
#ifdef CONFIG_WIRELESS_IEEE802154
# define HAVE_SADDR 1
# define HAVE_EADDR 1
#endif
#ifdef CONFIG_WIRELESS_PKTRADIO
# if CONFIG_PKTRADIO_ADDRLEN == 1
# define HAVE_BYTEADDR 1
# elif CONFIG_PKTRADIO_ADDRLEN == 2
# define HAVE_BYTEADDR 1
# define HAVE_SADDR 1
# elif CONFIG_PKTRADIO_ADDRLEN == 8
# define HAVE_BYTEADDR 1
# define HAVE_SADDR 1
# define HAVE_EADDR 1
# else
# error Unsupported value for CONFIG_PKTRADIO_ADDRLEN
# endif
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_[s|e]addrfromip
*
* Description:
* sixlowpan_[s|e]addrfromip(): Extract the IEEE 802.15.14 address from a
* MAC-based IPv6 address. sixlowpan_saddrfromip() and
* sixlowpan_eaddrfromip() handle short and extended addresses,
* respectively.
*
* 128 112 96 80 64 48 32 16
* ---- ---- ---- ---- ---- ---- ---- ----
* fe80 0000 0000 0000 0000 00ff fe00 xx00 1-byte short address 48-bit MAC
* xxxx 0000 0000 0000 0000 00ff fe00 xxxx 2-byte short address 48-bit MAC
* xxxx 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte extended address EUI-64
*
****************************************************************************/
#ifndef CONFIG_NET_STARPOINT
#ifdef HAVE_BYTEADDR
static void sixlowpan_baddrfromip(const net_ipv6addr_t ipaddr,
FAR uint8_t *baddr)
{
/* Big-endian uint16_t to byte order */
baddr[0] = NTOHS(ipaddr[7]) & 0xff;
}
#endif
#ifdef HAVE_SADDR
static void sixlowpan_saddrfromip(const net_ipv6addr_t ipaddr,
FAR uint8_t *saddr)
{
/* Big-endian uint16_t to byte order */
saddr[0] = NTOHS(ipaddr[7]) >> 8;
saddr[1] = NTOHS(ipaddr[7]) & 0xff;
}
#endif
#ifdef HAVE_EADDR
static void sixlowpan_eaddrfromip(const net_ipv6addr_t ipaddr,
FAR uint8_t *eaddr)
{
FAR uint8_t *eptr = eaddr;
int i;
for (i = 4; i < 8; i++)
{
/* Big-endian uint16_t to byte order */
*eptr++ = NTOHS(ipaddr[i]) >> 8;
*eptr++ = NTOHS(ipaddr[i]) & 0xff;
}
eaddr[0] ^= 0x02;
}
#endif
#endif /* !CONFIG_NET_STARPOINT */
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sixlowpan_nexthopaddr
*
* Description:
* sixlowpan_nexthopaddr(): If the destination is on-link, extract the
* IEEE 802.15.14 destination address from the destination IP address.
* If the destination is not reachable directly, use the routing table
* (if available) or fall back to the default router IP address and use
* the router IP address to derive the IEEE 802.15.4 MAC address.
*
****************************************************************************/
int sixlowpan_nexthopaddr(FAR struct radio_driver_s *radio,
FAR const net_ipv6addr_t ipaddr,
FAR struct netdev_varaddr_s *destaddr)
{
FAR net_ipv6addr_t router;
int ret;
/* Try to 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_destaddrfromip(radio, ipaddr, destaddr);
if (ret < 0)
{
/* Destination address is not on the local network */
#ifdef CONFIG_NET_ROUTE
/* We have a routing table.. find the correct router to use in
* this case (or, as a fall-back, use the device's default router
* address). We will use the router IPv6 address instead of the
* destination address when determining the MAC address.
*/
netdev_ipv6_router(&radio->r_dev, ipaddr, router);
#else
/* Use the device's default router IPv6 address instead of the
* destination address when determining the MAC address.
*/
net_ipv6addr_copy(router, radio->r_dev.d_ipv6draddr);
#endif
/* Get the IEEE 802.15.4 MAC address of the router. This
* assumes an encoding of the MAC address in the IPv6 address.
*/
ret = sixlowpan_destaddrfromip(radio, router, destaddr);
if (ret < 0)
{
return ret;
}
}
return OK;
}
/****************************************************************************
* Name: sixlowpan_destaddrfromip
*
* Description:
* sixlowpan_destaddrfromip(): Extract the IEEE 802.15.14 destination
* address from a MAC-based destination IPv6 address. This function
* handles a tagged address union which may either a short or and
* extended destination address.
*
* 128 112 96 80 64 48 32 16
* ---- ---- ---- ---- ---- ---- ---- ----
* ffxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx Multicast address (RFC 3513)
* ff02 0000 0000 0000 0000 0000 0000 0001 All nodes multicast group
* xxxx 0000 0000 0000 0000 00ff fe00 xx00 1-byte short address 48-bit MAC
* xxxx 0000 0000 0000 0000 00ff fe00 xxxx 2-byte short address 48-bit MAC
* xxxx 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte extended address EUI-64
*
* In the case there the IEEE 802.15.4 node functions as an endpoint in a
* start topology, the destination address will, instead, be the address
* of the star hub (which is assumed to be the address of the coordinator).
*
****************************************************************************/
int sixlowpan_destaddrfromip(FAR struct radio_driver_s *radio,
const net_ipv6addr_t ipaddr,
FAR struct netdev_varaddr_s *destaddr)
{
struct radiodev_properties_s properties;
int ret;
#ifdef CONFIG_NET_STARPOINT
/* Only the radio driver knows the correct address of the hub. For IEEE
* 802.15.4 this will be the address of the PAN coordinator. For other
* radios, this may be some configured, "well-known" address.
*/
DEBUGASSERT(radio->r_properties != NULL);
ret = radio->r_properties(radio, &properties);
if (ret < 0)
{
return ret;
}
memcpy(destaddr, &properties.sp_hubnode, sizeof(struct netdev_varaddr_s));
return OK;
#else /* CONFIG_NET_STARPOINT */
/* Check for a multicast address */
if (net_is_addr_mcast(ipaddr))
{
DEBUGASSERT(radio->r_properties != NULL);
ret = radio->r_properties(radio, &properties);
if (ret < 0)
{
return ret;
}
/* Check for the broadcast IP address
*
* IPv6 does not implement the method of broadcast, and therefore
* does not define broadcast addresses. Instead, IPv6 uses multicast
* addressing to the all-nodes multicast group: ff02:0:0:0:0:0:0:1.
*
* However, the use of the all-nodes group is not common, and most
* IPv6 protocols use a dedicated link-local multicast group to avoid
* disturbing every interface in the network.
*/
if (net_ipv6addr_cmp(ipaddr, g_ipv6_allnodes))
{
memcpy(destaddr, &properties.sp_bcast,
sizeof(struct netdev_varaddr_s));
}
/* Some other RFC 3513 multicast address */
else
{
memcpy(destaddr, &properties.sp_mcast,
sizeof(struct netdev_varaddr_s));
}
return OK;
}
/* Otherwise, the destination MAC address is encoded in the IP address */
/* If the address is link-local, or matches the prefix of the local
* address, the interface identifier can be extracted from the lower
* bits of the address.
*/
if (!sixlowpan_islinklocal(ipaddr) &&
!net_ipv6addr_maskcmp(radio->r_dev.d_ipv6addr, ipaddr,
radio->r_dev.d_ipv6netmask))
{
return -EADDRNOTAVAIL;
}
#ifdef CONFIG_WIRELESS_PKTRADIO
/* If this is a packet radio, then we cannot know the correct size of the
* radio's MAC address without asking. The setting CONFIG_PKTRADIO_ADDRLEN
* is inexact if there are multiple packet radios with different address
* lengths; it that case it will be the size of the longest address.
*
* NOTE: This logic assumes that the packet radio's address length is a
* constant.
*/
#ifdef CONFIG_WIRELESS_IEEE802154
if (radio->r_dev.d_lltype == NET_LL_PKTRADIO)
#endif
{
DEBUGASSERT(radio->r_properties != NULL);
ret = radio->r_properties(radio, &properties);
if (ret < 0)
{
return ret;
}
#ifdef HAVE_BYTEADDR
if (properties.sp_addrlen == 1 &&
SIXLOWPAN_IS_IID_8BIT_COMPRESSABLE(ipaddr))
{
memset(destaddr, 0, sizeof(struct netdev_varaddr_s));
sixlowpan_baddrfromip(ipaddr, destaddr->nv_addr);
destaddr->nv_addrlen = 1;
return OK;
}
else
#endif
#ifdef HAVE_SADDR
if (properties.sp_addrlen == 2 &&
SIXLOWPAN_IS_IID_16BIT_COMPRESSABLE(ipaddr))
{
memset(destaddr, 0, sizeof(struct netdev_varaddr_s));
sixlowpan_saddrfromip(ipaddr, destaddr->nv_addr);
destaddr->nv_addrlen = 2;
return OK;
}
else
#endif
#ifdef HAVE_EADDR
if (properties.sp_addrlen == 8)
{
sixlowpan_eaddrfromip(ipaddr, destaddr->nv_addr);
destaddr->nv_addrlen = 8;
return OK;
}
else
#endif
{
/* Just to satisfy the last dangling 'else' */
}
return -EADDRNOTAVAIL;
}
#endif /* CONFIG_WIRELESS_PKTRADIO */
#ifdef CONFIG_WIRELESS_IEEE802154
#ifdef CONFIG_WIRELESS_PKTRADIO
else
#endif
{
if (SIXLOWPAN_IS_IID_16BIT_COMPRESSABLE(ipaddr))
{
memset(destaddr, 0, sizeof(struct netdev_varaddr_s));
sixlowpan_saddrfromip(ipaddr, destaddr->nv_addr);
destaddr->nv_addrlen = NET_6LOWPAN_SADDRSIZE;
}
else
{
sixlowpan_eaddrfromip(ipaddr, destaddr->nv_addr);
destaddr->nv_addrlen = NET_6LOWPAN_EADDRSIZE;
}
return OK;
}
#endif /* CONFIG_WIRELESS_IEEE802154 */
#endif /* CONFIG_NET_STARPOINT */
}
/****************************************************************************
* Name: sixlowpan_ipfromaddr (plus helpers)
*
* Description:
* sixlowpan_ipfrom[s|e]addr(): Create a link-local, MAC-based IPv6
* address from an IEEE802.15.4 short address (saddr), extended address
* (eaddr), or other variable length radio addresses.
*
* 128 112 96 80 64 48 32 16
* ---- ---- ---- ---- ---- ---- ---- ----
* fe80 0000 0000 0000 0000 00ff fe00 xx00 1-byte short address 48-bit MAC
* fe80 0000 0000 0000 0000 00ff fe00 xxxx 2-byte short address 48-bit MAC
* fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte extended address EUI-64
*
****************************************************************************/
#ifdef HAVE_BYTEADDR
static inline void sixlowpan_ipfrombyte(FAR const uint8_t *byte,
FAR net_ipv6addr_t ipaddr)
{
ipaddr[0] = HTONS(0xfe80);
ipaddr[1] = 0;
ipaddr[2] = 0;
ipaddr[3] = 0;
ipaddr[4] = 0;
ipaddr[5] = HTONS(0x00ff);
ipaddr[6] = HTONS(0xfe00);
ipaddr[7] = HTONS((uint16_t)byte[0]);
}
#endif
#ifdef HAVE_SADDR
static inline void sixlowpan_ipfromsaddr(FAR const uint8_t *saddr,
FAR net_ipv6addr_t ipaddr)
{
ipaddr[0] = HTONS(0xfe80);
ipaddr[1] = 0;
ipaddr[2] = 0;
ipaddr[3] = 0;
ipaddr[4] = 0;
ipaddr[5] = HTONS(0x00ff);
ipaddr[6] = HTONS(0xfe00);
/* Preserve big-endian */
memcpy(&ipaddr[7], saddr, 2);
}
#endif
#ifdef HAVE_EADDR
static inline void sixlowpan_ipfromeaddr(FAR const uint8_t *eaddr,
FAR net_ipv6addr_t ipaddr)
{
ipaddr[0] = HTONS(0xfe80);
ipaddr[1] = 0;
ipaddr[2] = 0;
ipaddr[3] = 0;
/* Preserve big-endian */
memcpy(&ipaddr[4], eaddr , 2);
memcpy(&ipaddr[5], eaddr + 2, 2);
memcpy(&ipaddr[6], eaddr + 4, 2);
memcpy(&ipaddr[7], eaddr + 6, 2);
/* Invert the U/L bit */
ipaddr[4] ^= HTONS(0x0200);
}
#endif
void sixlowpan_ipfromaddr(FAR const struct netdev_varaddr_s *addr,
FAR net_ipv6addr_t ipaddr)
{
switch (addr->nv_addrlen)
{
#ifdef HAVE_BYTEADDR
case 1:
sixlowpan_ipfrombyte(addr->nv_addr, ipaddr);
break;
#endif
#ifdef HAVE_SADDR
case NET_6LOWPAN_SADDRSIZE:
sixlowpan_ipfromsaddr(addr->nv_addr, ipaddr);
break;
#endif
#ifdef HAVE_EADDR
case NET_6LOWPAN_EADDRSIZE:
sixlowpan_ipfromeaddr(addr->nv_addr, ipaddr);
break;
#endif
default:
nerr("ERROR: Unsupported address length: %u\n", addr->nv_addrlen);
break;
}
}
/****************************************************************************
* Name: sixlowpan_ismacbased (and helpers)
*
* Description:
* sixlowpan_ismacbased() will return true for IP addresses formed from
* IEEE802.15.4 MAC addresses. sixlowpan_destaddrfromip() is intended to
* handle a tagged address or any size.
*
* 128 112 96 80 64 48 32 16
* ---- ---- ---- ---- ---- ---- ---- ----
* fe80 0000 0000 0000 0000 00ff fe00 xx00 1-byte short address 48-bit MAC
* fe80 0000 0000 0000 0000 00ff fe00 xxxx 2-byte short address 48-bit MAC
* fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte extended address EUI-64
*
****************************************************************************/
#ifdef HAVE_BYTEADDR
static inline bool sixlowpan_isbytebased(const net_ipv6addr_t ipaddr,
uint8_t byte)
{
return (ipaddr[5] == HTONS(0x00ff) &&
ipaddr[6] == HTONS(0xfe00) &&
ipaddr[7] == HTONS((uint16_t)byte));
}
#endif
#ifdef HAVE_SADDR
static inline bool sixlowpan_issaddrbased(const net_ipv6addr_t ipaddr,
FAR const uint8_t *saddr)
{
return (ipaddr[5] == HTONS(0x00ff) &&
ipaddr[6] == HTONS(0xfe00) &&
ipaddr[7] == *(uint16_t *)saddr);
}
#endif
#ifdef HAVE_EADDR
static inline bool sixlowpan_iseaddrbased(const net_ipv6addr_t ipaddr,
FAR const uint8_t *eaddr)
{
/* If the U/L bit is not set, indicating that the address is universal, it
* can not be eaddr-based since EUI-64's are always universal
*/
if ((ipaddr[4] & HTONS(0x0200)) == 0) return false;
return (ipaddr[4] == ((*(uint16_t *)eaddr) ^ HTONS(0x0200)) &&
ipaddr[5] == *(uint16_t *)(eaddr + 2) &&
ipaddr[6] == *(uint16_t *)(eaddr + 4) &&
ipaddr[7] == *(uint16_t *)(eaddr + 6));
}
#endif
bool sixlowpan_ismacbased(const net_ipv6addr_t ipaddr,
FAR const struct netdev_varaddr_s *addr)
{
switch (addr->nv_addrlen)
{
#ifdef HAVE_BYTEADDR
case 1:
return sixlowpan_isbytebased(ipaddr, addr->nv_addr[0]);
#endif
#ifdef HAVE_SADDR
case NET_6LOWPAN_SADDRSIZE:
return sixlowpan_issaddrbased(ipaddr, addr->nv_addr);
#endif
#ifdef HAVE_EADDR
case NET_6LOWPAN_EADDRSIZE:
return sixlowpan_iseaddrbased(ipaddr, addr->nv_addr);
#endif
default:
nerr("ERROR: Unsupported address length: %u\n", addr->nv_addrlen);
return false;
}
}
/****************************************************************************
* Name: sixlowpan_radio_framelen
*
* Description:
* Get the maximum frame length supported by radio network driver.
*
* Input Parameters:
* radio - Reference to a radio network driver state instance.
*
* Returned Value:
* A non-negative, maximum frame lengthis returned on success; A negated
* errno valueis returned on any failure.
*
****************************************************************************/
int sixlowpan_radio_framelen(FAR struct radio_driver_s *radio)
{
struct radiodev_properties_s properties;
int ret;
/* Only the radio driver knows the correct max frame length supported by
* the radio.
*/
DEBUGASSERT(radio->r_properties != NULL);
ret = radio->r_properties(radio, &properties);
if (ret < 0)
{
return ret;
}
return (int)properties.sp_framelen;
}
/****************************************************************************
* Name: sixlowpan_src_panid
*
* Description:
* Get the source PAN ID from the IEEE802.15.4 MAC layer.
*
* Input Parameters:
* radio - Reference to a radio network driver state instance.
* panid - The location in which to return the PAN ID. 0xfff may be
* returned if the device is not associated.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
#ifdef CONFIG_WIRELESS_IEEE802154
int sixlowpan_src_panid(FAR struct radio_driver_s *radio,
FAR uint8_t *panid)
{
FAR struct net_driver_s *dev = &radio->r_dev;
struct ieee802154_netmac_s arg;
int ret;
memcpy(arg.ifr_name, radio->r_dev.d_ifname, IFNAMSIZ);
arg.u.getreq.attr = IEEE802154_ATTR_MAC_PANID;
ret = dev->d_ioctl(dev, MAC802154IOC_MLME_GET_REQUEST,
(unsigned long)((uintptr_t)&arg));
if (ret < 0)
{
nerr("ERROR: MAC802154IOC_MLME_GET_REQUEST failed: %d\n", ret);
return ret;
}
/* MAC802154 gives us PAN ID in Little Endinan Order, but we need
* it in Network Order.
*/
panid[0] = arg.u.getreq.attrval.mac.panid[1];
panid[1] = arg.u.getreq.attrval.mac.panid[0];
return OK;
}
#endif
/****************************************************************************
* Name: sixlowpan_extract_srcaddr
*
* Description:
* Extract the source MAC address from the radio-specific RX metadata, and
* return the source address in a radio-agnostic form.
*
* Input Parameters:
* radio - Reference to a radio network driver state instance.
* metadata - Opaque reference to the radio-specific RX metadata.
* srcaddr - The location in which to return the source MAC address.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int sixlowpan_extract_srcaddr(FAR struct radio_driver_s *radio,
FAR const void *metadata,
FAR struct netdev_varaddr_s *srcaddr)
{
DEBUGASSERT(radio != NULL && metadata != NULL && srcaddr != NULL);
#ifdef CONFIG_WIRELESS_IEEE802154
#ifdef CONFIG_WIRELESS_PKTRADIO
if (radio->r_dev.d_lltype == NET_LL_IEEE802154)
#endif
{
FAR const struct ieee802154_data_ind_s *ind =
(FAR const struct ieee802154_data_ind_s *)metadata;
if (ind->src.mode == IEEE802154_ADDRMODE_SHORT)
{
srcaddr->nv_addrlen = NET_6LOWPAN_SADDRSIZE;
/* MAC802154 gives us Short Address in Little Endinan Order, but we
* need it in Network Order.
*/
srcaddr->nv_addr[0] = ind->src.saddr[1];
srcaddr->nv_addr[1] = ind->src.saddr[0];
}
else
{
srcaddr->nv_addrlen = NET_6LOWPAN_EADDRSIZE;
memcpy(srcaddr->nv_addr, ind->src.eaddr, NET_6LOWPAN_EADDRSIZE);
}
return OK;
}
#endif
#ifdef CONFIG_WIRELESS_PKTRADIO
#ifdef CONFIG_WIRELESS_IEEE802154
else
#endif
{
FAR const struct pktradio_metadata_s *pktmeta =
(FAR const struct pktradio_metadata_s *)metadata;
DEBUGASSERT(pktmeta->pm_src.pa_addrlen <= CONFIG_PKTRADIO_ADDRLEN);
srcaddr->nv_addrlen = pktmeta->pm_src.pa_addrlen;
memcpy(srcaddr->nv_addr, pktmeta->pm_src.pa_addr,
pktmeta->pm_src.pa_addrlen);
return OK;
}
#endif
return -EINVAL; /* Shouldn't get here */
}
/****************************************************************************
* Name: sixlowpan_extract_destaddr
*
* Description:
* Extract the destination MAC address from the radio-specific RX metadata,
* and return the destination address in a radio-agnostic form.
*
* Input Parameters:
* radio - Reference to a radio network driver state instance.
* metadata - Opaque reference to the radio-specific RX metadata.
* destaddr - The location in which to return the destination MAC address.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int sixlowpan_extract_destaddr(FAR struct radio_driver_s *radio,
FAR const void *metadata,
FAR struct netdev_varaddr_s *destaddr)
{
DEBUGASSERT(radio != NULL && metadata != NULL && destaddr != NULL);
#ifdef CONFIG_WIRELESS_IEEE802154
#ifdef CONFIG_WIRELESS_PKTRADIO
if (radio->r_dev.d_lltype == NET_LL_IEEE802154)
#endif
{
FAR const struct ieee802154_data_ind_s *ind =
(FAR const struct ieee802154_data_ind_s *)metadata;
if (ind->dest.mode == IEEE802154_ADDRMODE_SHORT)
{
destaddr->nv_addrlen = NET_6LOWPAN_SADDRSIZE;
/* MAC802154 gives us Short Address in Little Endinan Order, but we
* need it in Network Order.
*/
destaddr->nv_addr[0] = ind->dest.saddr[1];
destaddr->nv_addr[1] = ind->dest.saddr[0];
}
else
{
destaddr->nv_addrlen = NET_6LOWPAN_EADDRSIZE;
memcpy(destaddr->nv_addr, ind->dest.eaddr, NET_6LOWPAN_EADDRSIZE);
}
return OK;
}
#endif
#ifdef CONFIG_WIRELESS_PKTRADIO
#ifdef CONFIG_WIRELESS_IEEE802154
else
#endif
{
FAR const struct pktradio_metadata_s *pktmeta =
(FAR const struct pktradio_metadata_s *)metadata;
DEBUGASSERT(pktmeta->pm_dest.pa_addrlen <= CONFIG_PKTRADIO_ADDRLEN);
destaddr->nv_addrlen = pktmeta->pm_dest.pa_addrlen;
memcpy(destaddr->nv_addr, pktmeta->pm_dest.pa_addr,
pktmeta->pm_dest.pa_addrlen);
return OK;
}
#endif
return -EINVAL; /* Shouldn't get here */
}
#endif /* CONFIG_NET_6LOWPAN */