forked from xuos/xiuos
modify nuttx bug of lack of files
This commit is contained in:
@@ -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 fragment’s 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 fragment’s 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 */
|
||||
Reference in New Issue
Block a user