578 lines
17 KiB
C
578 lines
17 KiB
C
/****************************************************************************
|
|
* net/sixlowpan/sixlowpan_framer.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 <stdbool.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <debug.h>
|
|
|
|
#include "nuttx/net/net.h"
|
|
#include "nuttx/net/sixlowpan.h"
|
|
|
|
#include "sixlowpan/sixlowpan_internal.h"
|
|
|
|
#ifdef CONFIG_NET_6LOWPAN
|
|
|
|
/****************************************************************************
|
|
* Private Types
|
|
****************************************************************************/
|
|
|
|
/* Structure that contains the lengths of the various addressing and
|
|
* security fields in the 802.15.4 header.
|
|
*/
|
|
|
|
struct field_length_s
|
|
{
|
|
uint8_t dest_pid_len; /**< Length (in bytes) of destination PAN ID field */
|
|
uint8_t dest_addr_len; /**< Length (in bytes) of destination address field */
|
|
uint8_t src_pid_len; /**< Length (in bytes) of source PAN ID field */
|
|
uint8_t src_addr_len; /**< Length (in bytes) of source address field */
|
|
uint8_t aux_sec_len; /**< Length (in bytes) of aux security header field */
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Function: sixlowpan_addrlen
|
|
*
|
|
* Description:
|
|
* Return the address length associated with a 2-bit address mode
|
|
*
|
|
* Input parameters:
|
|
* addrmode - The address mode
|
|
*
|
|
* Returned Value:
|
|
* The address length associated with the address mode.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline uint8_t sixlowpan_addrlen(uint8_t addrmode)
|
|
{
|
|
switch (addrmode)
|
|
{
|
|
case FRAME802154_SHORTADDRMODE: /* 16-bit address */
|
|
return 2;
|
|
case FRAME802154_LONGADDRMODE: /* 64-bit address */
|
|
return 8;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Function: sixlowpan_addrnull
|
|
*
|
|
* Description:
|
|
* If the output address is NULL in the Rime buf, then it is broadcast
|
|
* on the 802.15.4 network.
|
|
*
|
|
* Input parameters:
|
|
* addrmode - The address mode
|
|
*
|
|
* Returned Value:
|
|
* The address length associated with the address mode.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static bool sixlowpan_addrnull(FAR uint8_t *addr)
|
|
{
|
|
#if CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 2
|
|
int i = 2;
|
|
#else
|
|
int i = 8;
|
|
#endif
|
|
|
|
while (i-- > 0)
|
|
{
|
|
if (addr[i] != 0x00)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* Function: sixlowpan_fieldlengths
|
|
*
|
|
* Description:
|
|
* Return the lengths associated fields of the IEEE802.15.4 header.
|
|
*
|
|
* Input parameters:
|
|
* finfo - IEEE802.15.4 header info (input)
|
|
* flen - Field length info (output)
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void sixlowpan_fieldlengths(FAR struct frame802154_s *finfo,
|
|
FAR struct field_length_s *flen)
|
|
{
|
|
/* Initialize to all zero */
|
|
|
|
memset(flen, 0, sizeof(struct field_length_s));
|
|
|
|
/* Determine lengths of each field based on fcf and other args */
|
|
|
|
if ((finfo->fcf.dest_addr_mode & 3) != 0)
|
|
{
|
|
flen->dest_pid_len = 2;
|
|
}
|
|
|
|
if ((finfo->fcf.src_addr_mode & 3) != 0)
|
|
{
|
|
flen->src_pid_len = 2;
|
|
}
|
|
|
|
/* Set PAN ID compression bit if src pan id matches dest pan id. */
|
|
|
|
if ((finfo->fcf.dest_addr_mode & 3) != 0 &&
|
|
(finfo->fcf.src_addr_mode & 3) != 0 &&
|
|
finfo->src_pid == finfo->dest_pid)
|
|
{
|
|
finfo->fcf.panid_compression = 1;
|
|
|
|
/* Compressed header, only do dest pid */
|
|
/* flen->src_pid_len = 0; */
|
|
}
|
|
|
|
/* Determine address lengths */
|
|
|
|
flen->dest_addr_len = sixlowpan_addrlen(finfo->fcf.dest_addr_mode & 3);
|
|
flen->src_addr_len = sixlowpan_addrlen(finfo->fcf.src_addr_mode & 3);
|
|
|
|
/* Aux security header */
|
|
|
|
#if 0 /* TODO Aux security header not yet implemented */
|
|
if ((finfo->fcf.security_enabled & 1) != 0)
|
|
{
|
|
switch(finfo->aux_hdr.security_control.key_id_mode)
|
|
{
|
|
case 0:
|
|
flen->aux_sec_len = 5; /* Minimum value */
|
|
break;
|
|
|
|
case 1:
|
|
flen->aux_sec_len = 6;
|
|
break;
|
|
|
|
case 2:
|
|
flen->aux_sec_len = 10;
|
|
break;
|
|
|
|
case 3:
|
|
flen->aux_sec_len = 14;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Function: sixlowpan_fieldlengths
|
|
*
|
|
* Description:
|
|
* Return the lengths associated fields of the IEEE802.15.4 header.
|
|
*
|
|
* Input parameters:
|
|
* finfo - IEEE802.15.4 header info (input)
|
|
* flen - Field length info (output)
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int sixlowpan_flen_hdrlen(FAR const struct field_length_s *flen)
|
|
{
|
|
return 3 + flen->dest_pid_len + flen->dest_addr_len +
|
|
flen->src_pid_len + flen->src_addr_len + flen->aux_sec_len;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Function: sixlowpan_802154_hdrlen
|
|
*
|
|
* Description:
|
|
* Calculates the length of the frame header. This function is meant to
|
|
* be called by a higher level function, that interfaces to a MAC.
|
|
*
|
|
* Input parameters:
|
|
* finfo - IEEE802.15.4 header info that specifies the frame to send.
|
|
*
|
|
* Returned Value:
|
|
* The length of the frame header.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int sixlowpan_802154_hdrlen(FAR struct frame802154_s *finfo)
|
|
{
|
|
struct field_length_s flen;
|
|
|
|
sixlowpan_fieldlengths(finfo, &flen);
|
|
return sixlowpan_flen_hdrlen(&flen);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Function: sixlowpan_setup_params
|
|
*
|
|
* Description:
|
|
* Configure frame parmeters structure.
|
|
*
|
|
* Input parameters:
|
|
* ieee - A reference IEEE802.15.4 MAC network device structure.
|
|
* params - Where to put the parmeters
|
|
* dest_panid - PAN ID of the destination. May be 0xffff if the destination
|
|
* is not associated.
|
|
*
|
|
* Returned Value:
|
|
* None.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee,
|
|
FAR struct frame802154_s *params,
|
|
uint16_t dest_panid)
|
|
{
|
|
bool rcvrnull;
|
|
|
|
/* Initialize all prameters to all zero */
|
|
|
|
memset(¶ms, 0, sizeof(params));
|
|
|
|
/* Reset to an empty frame */
|
|
|
|
ieee->i_framelen = 0;
|
|
ieee->i_dataoffset = 0;
|
|
|
|
/* Build the FCF (Only non-zero elements need to be initialized). */
|
|
|
|
params->fcf.frame_type = FRAME802154_DATAFRAME;
|
|
params->fcf.frame_pending = ieee->i_pktattrs[PACKETBUF_ATTR_PENDING];
|
|
|
|
/* If the output address is NULL in the Rime buf, then it is broadcast
|
|
* on the 802.15.4 network.
|
|
*/
|
|
|
|
rcvrnull = sixlowpan_addrnull(ieee->i_pktaddrs[PACKETBUF_ADDR_RECEIVER].u8);
|
|
if (rcvrnull)
|
|
{
|
|
params->fcf.ack_required = ieee->i_pktattrs[PACKETBUF_ATTR_MAC_ACK];
|
|
}
|
|
|
|
/* Insert IEEE 802.15.4 (2003) version bit. */
|
|
|
|
params->fcf.frame_version = FRAME802154_IEEE802154_2003;
|
|
|
|
/* Increment and set the data sequence number. */
|
|
|
|
if (ieee->i_pktattrs[PACKETBUF_ATTR_MAC_SEQNO] != 0)
|
|
{
|
|
params->seq = ieee->i_pktattrs[PACKETBUF_ATTR_MAC_SEQNO];
|
|
}
|
|
else
|
|
{
|
|
params->seq = ieee->i_dsn++;
|
|
ieee->i_pktattrs[PACKETBUF_ATTR_MAC_SEQNO] = params->seq;
|
|
}
|
|
|
|
/* Complete the addressing fields. */
|
|
/* Set the source and destination PAN ID. */
|
|
|
|
params->src_pid = ieee->i_panid;
|
|
params->dest_pid = dest_panid;
|
|
|
|
/* If the output address is NULL in the Rime buf, then it is broadcast
|
|
* on the 802.15.4 network.
|
|
*/
|
|
|
|
if (rcvrnull)
|
|
{
|
|
/* Broadcast requires short address mode. */
|
|
|
|
params->fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE;
|
|
params->dest_addr[0] = 0xff;
|
|
params->dest_addr[1] = 0xff;
|
|
}
|
|
else
|
|
{
|
|
/* Copy the destination address */
|
|
|
|
rimeaddr_copy((struct rimeaddr_s *)¶ms->dest_addr,
|
|
ieee->i_pktaddrs[PACKETBUF_ADDR_RECEIVER].u8);
|
|
|
|
/* Use short address mode if so configured */
|
|
|
|
#if CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 2
|
|
params->fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE;
|
|
#else
|
|
params->fcf.dest_addr_mode = FRAME802154_LONGADDRMODE;
|
|
#endif
|
|
}
|
|
|
|
/* Set the source address to the node address assigned to the device */
|
|
|
|
rimeaddr_copy((struct rimeaddr_s *)¶ms->src_addr, &ieee->i_nodeaddr.u8);
|
|
|
|
/* Configure the payload address and length */
|
|
|
|
params->payload = FRAME_DATA_START(ieee);
|
|
params->payload_len = FRAME_DATA_SIZE(ieee);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Function: sixlowpan_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:
|
|
* ieee - A reference IEEE802.15.4 MAC network device structure.
|
|
* dest_panid - PAN ID of the destination. May be 0xffff if the destination
|
|
* is not associated.
|
|
*
|
|
* Returned Value:
|
|
* The frame header length is returnd on success; otherwise, a negated
|
|
* errno value is return on failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int sixlowpan_hdrlen(FAR struct ieee802154_driver_s *ieee,
|
|
uint16_t dest_panid)
|
|
{
|
|
struct frame802154_s params;
|
|
|
|
/* Set up the frame parameters */
|
|
|
|
sixlowpan_setup_params(ieee, ¶ms, dest_panid);
|
|
|
|
/* Return the length of the header */
|
|
|
|
return sixlowpan_802154_hdrlen(¶ms);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Function: sixlowpan_802154_framecreate
|
|
*
|
|
* Description:
|
|
* Creates a frame for transmission over the air. This function is meant
|
|
* to be called by a higher level function, that interfaces to a MAC.
|
|
*
|
|
* Input parameters:
|
|
* finfo - Pointer to struct EEE802.15.4 header structure that specifies
|
|
* the frame to send.
|
|
* buf - Pointer to the buffer to use for the frame.
|
|
* buflen - The length of the buffer to use for the frame.
|
|
* finfo - I that specifies the frame to send.
|
|
*
|
|
* Returned Value:
|
|
* The length of the frame header or 0 if there was insufficient space in
|
|
* the buffer for the frame headers.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int sixlowpan_802154_framecreate(FAR struct frame802154_s *finfo,
|
|
FAR uint8_t *buf, int buflen)
|
|
{
|
|
struct field_length_s flen;
|
|
uint8_t pos;
|
|
int hdrlen;
|
|
int i;
|
|
|
|
sixlowpan_fieldlengths(finfo, &flen);
|
|
|
|
hdrlen = sixlowpan_flen_hdrlen(&flen);
|
|
if (hdrlen > buflen)
|
|
{
|
|
/* Too little space for headers. */
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* OK, now we have field lengths. Time to actually construct
|
|
* the outgoing frame, and store it in the provided buffer
|
|
*/
|
|
|
|
buf[0] = (finfo->fcf.frame_type & 7) |
|
|
((finfo->fcf.security_enabled & 1) << 3) |
|
|
((finfo->fcf.frame_pending & 1) << 4) |
|
|
((finfo->fcf.ack_required & 1) << 5) |
|
|
((finfo->fcf.panid_compression & 1) << 6);
|
|
buf[1] = ((finfo->fcf.dest_addr_mode & 3) << 2) |
|
|
((finfo->fcf.frame_version & 3) << 4) |
|
|
((finfo->fcf.src_addr_mode & 3) << 6);
|
|
|
|
/* Sequence number */
|
|
|
|
buf[2] = finfo->seq;
|
|
pos = 3;
|
|
|
|
/* Destination PAN ID */
|
|
|
|
if (flen.dest_pid_len == 2)
|
|
{
|
|
buf[pos++] = finfo->dest_pid & 0xff;
|
|
buf[pos++] = (finfo->dest_pid >> 8) & 0xff;
|
|
}
|
|
|
|
/* Destination address */
|
|
|
|
for (i = flen.dest_addr_len; i > 0; i--)
|
|
{
|
|
buf[pos++] = finfo->dest_addr[i - 1];
|
|
}
|
|
|
|
/* Source PAN ID */
|
|
|
|
if (flen.src_pid_len == 2)
|
|
{
|
|
buf[pos++] = finfo->src_pid & 0xff;
|
|
buf[pos++] = (finfo->src_pid >> 8) & 0xff;
|
|
}
|
|
|
|
/* Source address */
|
|
|
|
for (i = flen.src_addr_len; i > 0; i--)
|
|
{
|
|
buf[pos++] = finfo->src_addr[i - 1];
|
|
}
|
|
|
|
/* Aux header */
|
|
|
|
#if 0 /* TODO Aux security header not yet implemented */
|
|
if (flen.aux_sec_len)
|
|
{
|
|
pos += flen.aux_sec_len;
|
|
}
|
|
#endif
|
|
|
|
DEBUGASSERT(pos == hdrlen);
|
|
return (int)pos;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Function: sixlowpan_framecreate
|
|
*
|
|
* Description:
|
|
* This function is called after the IEEE802.15.4 MAC driver polls for
|
|
* TX data. It creates the IEEE802.15.4 header in the frame buffer.
|
|
*
|
|
* Input parameters:
|
|
* ieee - A reference IEEE802.15.4 MAC network device structure.
|
|
* dest_panid - PAN ID of the destination. May be 0xffff if the destination
|
|
* is not associated.
|
|
*
|
|
* Returned Value:
|
|
* The frame header length is returnd on success; otherwise, a negated
|
|
* errno value is return on failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee,
|
|
uint16_t dest_panid)
|
|
{
|
|
struct frame802154_s params;
|
|
int len;
|
|
int ret;
|
|
|
|
/* Set up the frame parameters */
|
|
|
|
sixlowpan_setup_params(ieee, ¶ms, dest_panid);
|
|
|
|
/* Get the length of the header */
|
|
|
|
len = sixlowpan_802154_hdrlen(¶ms);
|
|
|
|
/* Allocate space for the header in the frame buffer */
|
|
|
|
ret = sixlowpan_frame_hdralloc(ieee, len);
|
|
if (ret < 0)
|
|
{
|
|
wlerr("ERROR: Header too large: %u\n", len);
|
|
return ret;
|
|
}
|
|
|
|
/* Then create the frame */
|
|
|
|
sixlowpan_802154_framecreate(¶ms, FRAME_HDR_START(ieee), len);
|
|
|
|
wlinfo("Frame type: %02x Data len: %d %u (%u)\n",
|
|
params.fcf.frame_type, len, FRAME_DATA_SIZE(ieee),
|
|
FRAME_SIZE(ieee));
|
|
#if CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 2
|
|
wlinfo("Dest address: %02x:%02x\n",
|
|
params.dest_addr[0], params.dest_addr[1]);
|
|
#else
|
|
wlinfo("Dest address: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
params.dest_addr[0], params.dest_addr[1], params.dest_addr[2],
|
|
params.dest_addr[3], params.dest_addr[4], params.dest_addr[5],
|
|
params.dest_addr[6], params.dest_addr[7]);
|
|
#endif
|
|
|
|
return len;
|
|
}
|
|
|
|
#endif /* CONFIG_NET_6LOWPAN */
|