mirror of
https://github.com/oliverschmidt/contiki.git
synced 2024-12-26 19:29:24 +00:00
1100 lines
32 KiB
C
1100 lines
32 KiB
C
/**
|
|
* \file sicslow_ethernet.c
|
|
* Routines to interface between Ethernet and 6LowPan
|
|
*
|
|
* \author
|
|
* Colin O'Flynn <coflynn@newae.com>
|
|
*
|
|
* \addtogroup usbstick
|
|
*/
|
|
|
|
/* Copyright (c) 2008 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
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * 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.
|
|
* * 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.
|
|
*/
|
|
|
|
/**
|
|
\ingroup usbstick
|
|
\defgroup sicslowinterop 6LowPan Ethernet Interop
|
|
@{
|
|
*/
|
|
|
|
//TODO: Should be able to always use this SIMPLE mode, hence can remove the 'complex' mode permanently
|
|
//TODO: RF230BB !SIMPLE works on XP, Ubuntu. SIMPLE works on Vista, W7. Find out why!
|
|
|
|
#ifndef UIP_CONF_SIMPLE_JACKDAW_ADDR_TRANS
|
|
#define UIP_CONF_SIMPLE_JACKDAW_ADDR_TRANS 0
|
|
#endif // ifndef UIP_CONF_SIMPLE_JACKDAW_ADDR_TRANS
|
|
|
|
#ifndef UIP_CONF_AUTO_SUBSTITUTE_LOCAL_MAC_ADDR
|
|
#define UIP_CONF_AUTO_SUBSTITUTE_LOCAL_MAC_ADDR 1
|
|
#endif // ifndef UIP_CONF_AUTO_SUBSTITUTE_LOCAL_MAC_ADDR
|
|
|
|
#if UIP_CONF_SIMPLE_JACKDAW_ADDR_TRANS
|
|
/**
|
|
\par Ethernet to 6LowPan Address Translation
|
|
|
|
It should be obvious that since 802.15.4 addresses are 8
|
|
bytes, and 802.3 addresses are 6 bytes, some form of
|
|
address translation is needed. These routines provide this
|
|
|
|
\par Address Translation on Packets coming FROM Ethernet
|
|
|
|
Packets coming from Ethernet, have any addresses inside
|
|
IPv6 packets (such as 'source link-layer address') expanded
|
|
by inserting a 0xFF 0xFE sequence as such:
|
|
|
|
\verbatim
|
|
AA:BB:CC:DD:EE:FF
|
|
|
|
becomes
|
|
|
|
AA:BB:CC:FF:FE:DD:EE:FF
|
|
\endverbatim
|
|
|
|
The 802.15.4 destination address is always derived from the IPv6
|
|
destination address.
|
|
|
|
\par Address Translation on Packets coming FROM 802.15.4
|
|
|
|
Packets coming from 802.15.4, have any addresses inside IPv6
|
|
packets (such as a 'source link-layer address') replaced
|
|
with the local_ethernet_addr, defined to 3A:3B:3C:3D:3E:3F here.
|
|
|
|
The destination ethernet address is performed by performing
|
|
the reverse process used to make the 802.15.4 addresses before.
|
|
|
|
\par Comments on Using This
|
|
|
|
Thus you always send IPv6 messages to the local_ethernet_addr,
|
|
which is 3A:3B:3C:3D:3E:3F. The actual 802.15.4 destination
|
|
address is based on the lower 64-bits of your IPv6 destination
|
|
address. IPv6 addresses must always be based on link-layer
|
|
addresses in the 802.15.4 network for this to work.
|
|
|
|
\par Notes on how addresses are stored
|
|
|
|
An 802.15.4 address will be reported for example as:
|
|
|
|
0x8877665544332211
|
|
|
|
Stored in the array as passed to these functions, it will be:
|
|
\verbatim
|
|
array[0] = 0x88;
|
|
array[1] = 0x77;
|
|
array[2] = 0x66;
|
|
etc.
|
|
\endverbatim
|
|
|
|
An 802.3 address will be reported for example as:
|
|
02:43:53:35:45:45
|
|
|
|
Stored in the array as passed to these functions, it will be:
|
|
\verbatim
|
|
array[0] = 0x02;
|
|
array[1] = 0x43;
|
|
array[2] = 0x53;
|
|
array[3] = 0x35
|
|
etc.
|
|
\endverbatim
|
|
*/
|
|
#else
|
|
/**
|
|
\par Ethernet to 6LowPan Address Translation
|
|
|
|
It should be obvious that since 802.15.4 addresses are 8
|
|
bytes, and 802.3 addresses are 6 bytes, some form of
|
|
address translation is needed. These routines provide this
|
|
|
|
\par 802.3 Address Formats
|
|
|
|
802.3 MAC addresses used here have this form:
|
|
|
|
\verbatim
|
|
+----+----+----+----+----+----+----+----+
|
|
+ + + + + + TR + GL + MU +
|
|
+----+----+----+----+----+----+----+----+
|
|
\endverbatim
|
|
|
|
|
|
It can be seen this is like a normal ethernet MAC address,
|
|
with GL being the Global/Local bit, and MU being the
|
|
Multicast/Unicast bit.
|
|
|
|
The addition is the 'TR' bit, which if set indicates that
|
|
the address must be translated when going between 802.15.4
|
|
and 802.3.
|
|
|
|
\par Address Translation
|
|
|
|
If the TRANSLATE (TR) bit is CLEAR, this means the 5th and
|
|
4th LSBytes of the 802.15.4 address are fffe, aka the address
|
|
has the hexidecial form:
|
|
|
|
xxxxxxfffexxxxxx
|
|
|
|
\note
|
|
You should always aim to set the 802.15.4 addresses
|
|
of the devices on your network to ones that will
|
|
satisfy this requirement. Some examples are:
|
|
\note
|
|
0x02 23 42 ff fe 73 92 28
|
|
\note
|
|
0x82 00 82 ff fe cd ee 22
|
|
|
|
\note
|
|
So the most significant octets MUST
|
|
have bit 0 CLEAR, bit 1 SET, and bit 2 CLEAR. The remaining
|
|
bits in this octet can be anything.
|
|
|
|
If the TRANSLATE bit is SET, this means the address on the
|
|
802.3 side does not directly convert to an 802.15.4 address.
|
|
To translate it, the remainder of the octet is used as an
|
|
index in a look-up table. This look-up table simply stores
|
|
the 4th, 5th, and 8th octet of the 802.15.4 address, and attaches
|
|
them to the remaining 5 bytes of the 802.3 address.
|
|
|
|
In this way there can be 32 different 802.15.4 'prefixes',
|
|
requiring only 96 bytes of RAM in a storage table on the
|
|
802.3 to 802.15.4 bridge.
|
|
|
|
Mulitcast addresses on 802.3 are mapped to broadcast addresses on
|
|
802.15.4 and vis-versa. Since IPv6 does not use 802.3 broadcast,
|
|
this code will drop all 802.3 broadcast packets. They are most
|
|
likely something unwanted, such as IPv4 packets that snuck in.
|
|
|
|
\par Notes on how addresses are stored
|
|
|
|
An 802.15.4 address will be reported for example as:
|
|
|
|
0x8877665544332211
|
|
|
|
Stored in the array as passed to these functions, it will be:
|
|
\verbatim
|
|
array[0] = 0x88;
|
|
array[1] = 0x77;
|
|
array[2] = 0x66;
|
|
etc.
|
|
\endverbatim
|
|
|
|
An 802.3 address will be reported for example as:
|
|
02:43:53:35:45:45
|
|
|
|
Stored in the array as passed to these functions, it will be:
|
|
\verbatim
|
|
array[0] = 0x02;
|
|
array[1] = 0x43;
|
|
array[2] = 0x53;
|
|
array[3] = 0x35
|
|
etc.
|
|
\endverbatim
|
|
*/
|
|
#endif
|
|
|
|
#include "uip.h"
|
|
#include "uip_arp.h" //For ethernet header structure
|
|
|
|
#include "net/rime.h"
|
|
#include "sicslowpan.h"
|
|
#include "sicslow_ethernet.h"
|
|
#if !RF230BB
|
|
#include "zmac.h"
|
|
#include "frame.h"
|
|
#include "radio.h"
|
|
#endif
|
|
#include "rndis/rndis_protocol.h"
|
|
#include "rndis/rndis_task.h"
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#define DEBUG 0
|
|
#if DEBUG
|
|
#define PRINTF(FORMAT,args...) printf_P(PSTR(FORMAT),##args)
|
|
#else
|
|
#define PRINTF(...)
|
|
#endif
|
|
|
|
#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
|
|
#define ETHBUF(x) ((struct uip_eth_hdr *)x)
|
|
|
|
//For little endian, such as our friend mr. AVR
|
|
#ifndef LSB
|
|
#define LSB(u16) (((uint8_t *)&(u16))[0]) //!< Least significant byte of \a u16.
|
|
#define MSB(u16) (((uint8_t *)&(u16))[1]) //!< Most significant byte of \a u16.
|
|
#endif
|
|
|
|
static const uint64_t simple_trans_ethernet_addr = 0x3E3D3C3B3AF2ULL;
|
|
|
|
#if UIP_CONF_IPV6_RPL
|
|
static uip_ipaddr_t last_sender;
|
|
#endif
|
|
|
|
extern uint64_t usb_ethernet_addr;
|
|
|
|
extern uint64_t macLongAddr;
|
|
|
|
#if !RF230BB
|
|
extern void (*pinput)(const struct mac_driver *r);
|
|
void (*sicslowinput)(const struct mac_driver *r);
|
|
parsed_frame_t * parsed_frame;
|
|
#endif
|
|
usbstick_mode_t usbstick_mode;
|
|
|
|
uint8_t mac_createSicslowpanLongAddr(uint8_t * ethernet, uip_lladdr_t * lowpan);
|
|
uint8_t mac_createEthernetAddr(uint8_t * ethernet, uip_lladdr_t * lowpan);
|
|
uint8_t mac_createDefaultEthernetAddr(uint8_t * ethernet);
|
|
void mac_ethhijack_nondata(const struct mac_driver *r);
|
|
void mac_ethhijack(const struct mac_driver *r);
|
|
|
|
extern void (*sicslowmac_snifferhook)(const struct mac_driver *r);
|
|
|
|
|
|
//! Location of TRANSLATE (TR) bit in Ethernet address
|
|
#define TRANSLATE_BIT_MASK (1<<2)
|
|
//! Location of LOCAL (GL) bit in Ethernet address
|
|
#define LOCAL_BIT_MASK (1<<1)
|
|
//! Location of MULTICAST (MU) bit in Ethernet address
|
|
#define MULTICAST_BIT_MASK (1<<0)
|
|
|
|
#define PREFIX_BUFFER_SIZE 32
|
|
|
|
uint8_t prefixCounter;
|
|
uint8_t prefixBuffer[PREFIX_BUFFER_SIZE][3];
|
|
|
|
/* 6lowpan max size + ethernet header size + 1 */
|
|
uint8_t raw_buf[127+ UIP_LLH_LEN +1];
|
|
|
|
/**
|
|
* \brief Perform any setup needed
|
|
*/
|
|
#if !RF230BB
|
|
struct mac_driver * pmac;
|
|
#endif
|
|
void mac_ethernetSetup(void)
|
|
{
|
|
usbstick_mode.sicslowpan = 1;
|
|
usbstick_mode.sendToRf = 1;
|
|
usbstick_mode.translate = 1;
|
|
usbstick_mode.debugOn= 1;
|
|
//usbstick_mode.raw = 1;
|
|
usbstick_mode.raw = 0; //default: don't report raw frames until they are entirely correct
|
|
|
|
#if !RF230BB
|
|
sicslowinput = pinput;
|
|
|
|
pmac = sicslowmac_get_driver();
|
|
pmac->set_receive_function(mac_ethhijack);
|
|
sicslowmac_snifferhook = mac_ethhijack_nondata;
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
* \brief Take a packet received over the ethernet link, and send it
|
|
* out over 802.15.4
|
|
*/
|
|
void mac_ethernetToLowpan(uint8_t * ethHeader)
|
|
{
|
|
//Dest address
|
|
uip_lladdr_t destAddr;
|
|
uip_lladdr_t *destAddrPtr = NULL;
|
|
|
|
PRINTF("Packet type: 0x%04x\n\r", uip_ntohs(((struct uip_eth_hdr *) ethHeader)->type));
|
|
|
|
//RUM doesn't support sending data
|
|
#if UIP_CONF_USE_RUM
|
|
return;
|
|
#endif
|
|
|
|
// In sniffer mode we don't ever send anything
|
|
if (usbstick_mode.sendToRf == 0) {
|
|
uip_len = 0;
|
|
return;
|
|
}
|
|
|
|
|
|
//If not IPv6 we don't do anything
|
|
if (((struct uip_eth_hdr *) ethHeader)->type != UIP_HTONS(UIP_ETHTYPE_IPV6)) {
|
|
PRINTF("eth2low: Dropping packet w/type=0x%04x\n",uip_ntohs(((struct uip_eth_hdr *) ethHeader)->type));
|
|
// printf("!ipv6");
|
|
#if !RF230BB
|
|
usb_eth_stat.txbad++;
|
|
#endif
|
|
uip_len = 0;
|
|
return;
|
|
}
|
|
|
|
/* IPv6 uses 33-33-xx-xx-xx-xx prefix for multicast ND stuff */
|
|
if ( (((struct uip_eth_hdr *) ethHeader)->dest.addr[0] == 0x33) &&
|
|
(((struct uip_eth_hdr *) ethHeader)->dest.addr[1] == 0x33) )
|
|
{
|
|
PRINTF("eth2low: Ethernet multicast packet received\n\r");
|
|
;//Do Nothing
|
|
} else if ( (((struct uip_eth_hdr *) ethHeader)->dest.addr[0] == 0xFF) &&
|
|
(((struct uip_eth_hdr *) ethHeader)->dest.addr[1] == 0xFF) &&
|
|
(((struct uip_eth_hdr *) ethHeader)->dest.addr[2] == 0xFF) &&
|
|
(((struct uip_eth_hdr *) ethHeader)->dest.addr[3] == 0xFF) &&
|
|
(((struct uip_eth_hdr *) ethHeader)->dest.addr[4] == 0xFF) &&
|
|
(((struct uip_eth_hdr *) ethHeader)->dest.addr[5] == 0xFF) ) {
|
|
/* IPv6 does not use broadcast addresses, hence this should not happen */
|
|
PRINTF("eth2low: Dropping broadcast packet\n\r");
|
|
#if !RF230BB
|
|
usb_eth_stat.txbad++;
|
|
#endif
|
|
uip_len = 0;
|
|
return;
|
|
} else {
|
|
|
|
/* Simple Address Translation */
|
|
if(memcmp((uint8_t *)&simple_trans_ethernet_addr, &(((struct uip_eth_hdr *) ethHeader)->dest.addr[0]), 6) == 0) {
|
|
//Addressed to us: make 802.15.4 address from IPv6 Address
|
|
destAddr.addr[0] = UIP_IP_BUF->destipaddr.u8[8] ^ 0x02;
|
|
destAddr.addr[1] = UIP_IP_BUF->destipaddr.u8[9];
|
|
destAddr.addr[2] = UIP_IP_BUF->destipaddr.u8[10];
|
|
destAddr.addr[3] = UIP_IP_BUF->destipaddr.u8[11];
|
|
destAddr.addr[4] = UIP_IP_BUF->destipaddr.u8[12];
|
|
destAddr.addr[5] = UIP_IP_BUF->destipaddr.u8[13];
|
|
destAddr.addr[6] = UIP_IP_BUF->destipaddr.u8[14];
|
|
destAddr.addr[7] = UIP_IP_BUF->destipaddr.u8[15];
|
|
|
|
destAddrPtr = &destAddr;
|
|
}
|
|
#if UIP_CONF_SIMPLE_JACKDAW_ADDR_TRANS
|
|
else {
|
|
//Not addressed to us
|
|
uip_len = 0;
|
|
return;
|
|
}
|
|
#else
|
|
|
|
/* Complex Address Translation */
|
|
PRINTF("eth2low: Addressed packet received... ");
|
|
//Check this returns OK
|
|
if (mac_createSicslowpanLongAddr( &(((struct uip_eth_hdr *) ethHeader)->dest.addr[0]), &destAddr) == 0) {
|
|
PRINTF(" translation failed\n\r");
|
|
#if !RF230BB
|
|
usb_eth_stat.txbad++;
|
|
#endif
|
|
uip_len = 0;
|
|
return;
|
|
}
|
|
PRINTF(" translated OK\n\r");
|
|
destAddrPtr = &destAddr;
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
//Remove header from length before passing onward
|
|
uip_len -= UIP_LLH_LEN;
|
|
|
|
//Some IP packets have link layer in them, need to change them around!
|
|
if (usbstick_mode.translate) {
|
|
#if DEBUG
|
|
uint8_t transReturn = mac_translateIPLinkLayer(ll_802154_type);
|
|
PRINTF("IPTranslation: returns %d\n\r", transReturn);
|
|
#else
|
|
mac_translateIPLinkLayer(ll_802154_type);
|
|
#endif
|
|
}
|
|
|
|
#if UIP_CONF_IPV6
|
|
/* Send the packet to the uip6 stack if it exists, else send to 6lowpan */
|
|
#if UIP_CONF_IPV6_RPL
|
|
/* Save the destination address, to trap ponging it back to the interface */
|
|
uip_ipaddr_copy(&last_sender, &UIP_IP_BUF->srcipaddr);
|
|
tcpip_input();
|
|
#else
|
|
tcpip_output(destAddrPtr);
|
|
#endif
|
|
#else /* UIP_CONF_IPV6 */
|
|
tcpip_output(); //Allow non-ipv6 builds (Hello World)
|
|
#endif /* UIP_CONF_IPV6 */
|
|
|
|
#if !RF230BB
|
|
usb_eth_stat.txok++;
|
|
#endif
|
|
uip_len = 0;
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* \brief Take a packet received over the 802.15.4 link, and send it
|
|
* out over ethernet, performing any translations needed.
|
|
*/
|
|
void mac_LowpanToEthernet(void)
|
|
{
|
|
#if !RF230BB
|
|
parsed_frame = sicslowmac_get_frame();
|
|
#endif
|
|
|
|
//Setup generic ethernet stuff
|
|
ETHBUF(uip_buf)->type = uip_htons(UIP_ETHTYPE_IPV6);
|
|
|
|
//Check for broadcast message
|
|
|
|
#if RF230BB
|
|
if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) {
|
|
// if(rimeaddr_cmp((const rimeaddr_t *)destAddr, &rimeaddr_null)) {
|
|
#else
|
|
if( ( parsed_frame->fcf->destAddrMode == SHORTADDRMODE) &&
|
|
( parsed_frame->dest_addr->addr16 == 0xffff) ) {
|
|
#endif
|
|
ETHBUF(uip_buf)->dest.addr[0] = 0x33;
|
|
ETHBUF(uip_buf)->dest.addr[1] = 0x33;
|
|
ETHBUF(uip_buf)->dest.addr[2] = UIP_IP_BUF->destipaddr.u8[12];
|
|
ETHBUF(uip_buf)->dest.addr[3] = UIP_IP_BUF->destipaddr.u8[13];
|
|
ETHBUF(uip_buf)->dest.addr[4] = UIP_IP_BUF->destipaddr.u8[14];
|
|
ETHBUF(uip_buf)->dest.addr[5] = UIP_IP_BUF->destipaddr.u8[15];
|
|
} else {
|
|
//Otherwise we have a real address
|
|
mac_createEthernetAddr((uint8_t *) &(ETHBUF(uip_buf)->dest.addr[0]),
|
|
(uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
|
|
}
|
|
|
|
#if !UIP_CONF_SIMPLE_JACKDAW_ADDR_TRANS
|
|
//Source ethernet depends on node
|
|
if(!mac_createEthernetAddr(
|
|
(uint8_t *) &(ETHBUF(uip_buf)->src.addr[0]),
|
|
(uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER)
|
|
))
|
|
#endif
|
|
|
|
{
|
|
mac_createDefaultEthernetAddr((uint8_t *) &(ETHBUF(uip_buf)->src.addr[0]));
|
|
}
|
|
|
|
//We only do address translation in network mode!
|
|
if (usbstick_mode.translate) {
|
|
//Some IP packets have link layer in them, need to change them around!
|
|
mac_translateIPLinkLayer(ll_8023_type);
|
|
}
|
|
|
|
#if UIP_CONF_IPV6_RPL
|
|
/* We won't play ping-pong with the host! */
|
|
if(uip_ipaddr_cmp(&last_sender, &UIP_IP_BUF->srcipaddr)) {
|
|
PRINTF("siclow_ethernet: Destination off-link but no route\n");
|
|
uip_len=0;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
PRINTF("Low2Eth: Sending packet to ethernet\n\r");
|
|
|
|
uip_len += UIP_LLH_LEN;
|
|
|
|
usb_eth_send(uip_buf, uip_len, 1);
|
|
#if !RF230BB
|
|
usb_eth_stat.rxok++;
|
|
#endif
|
|
uip_len = 0;
|
|
}
|
|
|
|
/**
|
|
* \brief Translate IP packet's possible link-layer addresses, passing
|
|
* the message to the appropriate higher level function for this
|
|
* packet (aka: ICMP)
|
|
* \param target The target we want to end up with - either ll_8023_type
|
|
* for ethernet, or ll_802154_type for 802.15.4
|
|
* \return Returns how successful the translation was
|
|
* \retval 0 Addresses, if present, were translated.
|
|
* \retval <0 Negative return values indicate various errors, as defined
|
|
* by the higher level function.
|
|
*/
|
|
int8_t mac_translateIPLinkLayer(lltype_t target)
|
|
{
|
|
|
|
#if UIP_LLADDR_LEN == 8
|
|
if (UIP_IP_BUF->proto == UIP_PROTO_ICMP6) {
|
|
PRINTF("eth2low: ICMP Message detected\n\r");
|
|
return mac_translateIcmpLinkLayer(target);
|
|
}
|
|
return 0;
|
|
#else
|
|
return 1;
|
|
#endif
|
|
|
|
}
|
|
|
|
#include "net/uip-icmp6.h"
|
|
#include "net/uip-nd6.h"
|
|
|
|
typedef struct {
|
|
uint8_t type;
|
|
uint8_t length;
|
|
uint8_t data[16];
|
|
} icmp_opts_t;
|
|
|
|
#define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[UIP_LLH_LEN + UIP_IPH_LEN])
|
|
#define UIP_ICMP_OPTS(x) ((icmp_opts_t *)&uip_buf[UIP_LLH_LEN + UIP_IPH_LEN + x])
|
|
|
|
void slide(uint8_t * data, uint8_t length, int16_t slide);
|
|
|
|
/**
|
|
* \brief Translate the link-layer (L2) addresses in an ICMP packet.
|
|
* This will just be NA/NS/RA/RS packets currently.
|
|
* \param target The target we want to end up with - either ll_8023_type
|
|
* for ethernet, or ll_802154_type for 802.15.4
|
|
* \return Returns how successful the translation was
|
|
* \retval 0 Addresses, if present, were translated.
|
|
* \retval -1 ICMP message was unknown type, nothing done.
|
|
* \retval -2 ICMP Length does not make sense?
|
|
* \retval -3 Unknown 'target' type
|
|
*/
|
|
int8_t mac_translateIcmpLinkLayer(lltype_t target)
|
|
{
|
|
uint16_t icmp_opt_offset = 0;
|
|
int16_t len = UIP_IP_BUF->len[1] | (UIP_IP_BUF->len[0] << 8);
|
|
|
|
uint16_t iplen;
|
|
|
|
uint8_t i;
|
|
|
|
int16_t sizechange;
|
|
|
|
uint8_t llbuf[16];
|
|
|
|
//Figure out offset to start of options
|
|
switch(UIP_ICMP_BUF->type) {
|
|
case ICMP6_NS:
|
|
case ICMP6_NA:
|
|
icmp_opt_offset = 24;
|
|
break;
|
|
|
|
case ICMP6_RS:
|
|
icmp_opt_offset = 8;
|
|
break;
|
|
|
|
case ICMP6_RA:
|
|
icmp_opt_offset = 16;
|
|
break;
|
|
|
|
case ICMP6_REDIRECT:
|
|
icmp_opt_offset = 40;
|
|
break;
|
|
|
|
/** Things without link-layer */
|
|
case ICMP6_DST_UNREACH:
|
|
case ICMP6_PACKET_TOO_BIG:
|
|
case ICMP6_TIME_EXCEEDED:
|
|
case ICMP6_PARAM_PROB:
|
|
case ICMP6_ECHO_REQUEST:
|
|
case ICMP6_ECHO_REPLY:
|
|
return 0;
|
|
break;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
//Figure out length of options
|
|
len -= icmp_opt_offset;
|
|
|
|
//Sanity check
|
|
if (len < 8) return -2;
|
|
|
|
//While we have options to do...
|
|
while (len >= 8){
|
|
|
|
//If we have one of these, we have something useful!
|
|
if (((UIP_ICMP_OPTS(icmp_opt_offset)->type) == UIP_ND6_OPT_SLLAO) ||
|
|
((UIP_ICMP_OPTS(icmp_opt_offset)->type) == UIP_ND6_OPT_TLLAO) ) {
|
|
|
|
/* Shrinking the buffer may thrash things, so we store the old
|
|
link-layer address */
|
|
for(i = 0; i < (UIP_ICMP_OPTS(icmp_opt_offset)->length*8 - 2); i++) {
|
|
llbuf[i] = UIP_ICMP_OPTS(icmp_opt_offset)->data[i];
|
|
}
|
|
|
|
//Shrink/grow buffer as needed
|
|
if (target == ll_802154_type) {
|
|
//Current is 802.3, Hence current link-layer option is 6 extra bytes
|
|
sizechange = 8;
|
|
slide(UIP_ICMP_OPTS(icmp_opt_offset)->data + 6, len - 6, sizechange);
|
|
} else if (target == ll_8023_type) {
|
|
/* Current is 802.15.4, Hence current link-layer option is 14 extra
|
|
* bytes.
|
|
* (Actual LL is 8 bytes, but total option length is in multiples of
|
|
* 8 Bytes, hence 8 + 2 = 10. Closest is 16 bytes, then 16 bytes for
|
|
* total optional length - 2 bytes for type + length leaves 14 )
|
|
*/
|
|
sizechange = -8;
|
|
slide(UIP_ICMP_OPTS(icmp_opt_offset)->data + 14, len - 14, sizechange);
|
|
} else {
|
|
return -3; //Uh-oh!
|
|
}
|
|
|
|
//Translate addresses
|
|
if (target == ll_802154_type) {
|
|
mac_createSicslowpanLongAddr(llbuf, (uip_lladdr_t *)UIP_ICMP_OPTS(icmp_opt_offset)->data);
|
|
} else {
|
|
#if !UIP_CONF_SIMPLE_JACKDAW_ADDR_TRANS
|
|
if(!mac_createEthernetAddr(UIP_ICMP_OPTS(icmp_opt_offset)->data, (uip_lladdr_t *)llbuf))
|
|
#endif
|
|
mac_createDefaultEthernetAddr(UIP_ICMP_OPTS(icmp_opt_offset)->data);
|
|
}
|
|
|
|
//Adjust the length
|
|
if (target == ll_802154_type) {
|
|
UIP_ICMP_OPTS(icmp_opt_offset)->length = 2;
|
|
} else {
|
|
UIP_ICMP_OPTS(icmp_opt_offset)->length = 1;
|
|
}
|
|
|
|
//Adjust the IP header length, as well as uIP length
|
|
iplen = UIP_IP_BUF->len[1] | (UIP_IP_BUF->len[0]<<8);
|
|
iplen += sizechange;
|
|
len += sizechange;
|
|
|
|
UIP_IP_BUF->len[1] = (uint8_t)iplen;
|
|
UIP_IP_BUF->len[0] = (uint8_t)(iplen >> 8);
|
|
|
|
uip_len += sizechange;
|
|
|
|
//We broke ICMP checksum, be sure to fix that
|
|
UIP_ICMP_BUF->icmpchksum = 0;
|
|
#if UIP_CONF_IPV6 //allow non ipv6 builds
|
|
UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
|
|
#endif
|
|
|
|
//Finally set up next run in while loop
|
|
len -= 8 * UIP_ICMP_OPTS(icmp_opt_offset)->length;
|
|
icmp_opt_offset += 8 * UIP_ICMP_OPTS(icmp_opt_offset)->length;
|
|
} else {
|
|
|
|
//Not an option we care about, ignore it
|
|
len -= 8 * UIP_ICMP_OPTS(icmp_opt_offset)->length;
|
|
|
|
//This shouldn't happen!
|
|
if (UIP_ICMP_OPTS(icmp_opt_offset)->length == 0) {
|
|
PRINTF("Option in ND packet has length zero, error?\n\r");
|
|
len = 0;
|
|
}
|
|
|
|
icmp_opt_offset += 8 * UIP_ICMP_OPTS(icmp_opt_offset)->length;
|
|
|
|
} //If ICMP_OPT is one we care about
|
|
|
|
} //while(len >= 8)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* \brief Create a 802.15.4 long address from a 802.3 address
|
|
* \param ethernet Pointer to ethernet address
|
|
* \param lowpan Pointer to 802.15.4 address
|
|
*/
|
|
uint8_t mac_createSicslowpanLongAddr(uint8_t * ethernet, uip_lladdr_t * lowpan)
|
|
{
|
|
#if UIP_CONF_AUTO_SUBSTITUTE_LOCAL_MAC_ADDR
|
|
//Special case - if the address is our address, we just copy over what we know to be
|
|
//our 802.15.4 address
|
|
if (memcmp((uint8_t *)&usb_ethernet_addr, ethernet, 6) == 0)
|
|
{
|
|
memcpy((uint8_t *)lowpan, &macLongAddr, UIP_LLADDR_LEN);
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
#if UIP_CONF_SIMPLE_JACKDAW_ADDR_TRANS
|
|
|
|
//Easy does it!
|
|
lowpan->addr[0] = ethernet[0];
|
|
lowpan->addr[1] = ethernet[1];
|
|
lowpan->addr[2] = ethernet[2];
|
|
lowpan->addr[3] = 0xff;
|
|
lowpan->addr[4] = 0xfe;
|
|
lowpan->addr[5] = ethernet[3];
|
|
lowpan->addr[6] = ethernet[4];
|
|
lowpan->addr[7] = ethernet[5];
|
|
|
|
#else //!UIP_CONF_SIMPLE_JACKDAW_ADDR_TRANS
|
|
|
|
uint8_t index;
|
|
|
|
#if UIP_LLADDR_LEN == 8
|
|
//Check if translate bit is set, hence we have to look up the prefix
|
|
if((ethernet[0]&(TRANSLATE_BIT_MASK|MULTICAST_BIT_MASK|LOCAL_BIT_MASK)) == (TRANSLATE_BIT_MASK|LOCAL_BIT_MASK)) {
|
|
//Get top bits
|
|
index = ethernet[0] >> 3;
|
|
|
|
//Copy over prefix
|
|
lowpan->addr[0] = prefixBuffer[index][0];
|
|
lowpan->addr[1] = prefixBuffer[index][1];
|
|
lowpan->addr[2] = prefixBuffer[index][2];
|
|
lowpan->addr[3] = ethernet[1];
|
|
lowpan->addr[4] = ethernet[2];
|
|
|
|
//Check this is plausible...
|
|
if (index >= prefixCounter)
|
|
return 0;
|
|
} else {
|
|
lowpan->addr[0] = ethernet[0];
|
|
lowpan->addr[1] = ethernet[1];
|
|
lowpan->addr[2] = ethernet[2];
|
|
lowpan->addr[3] = 0xff;
|
|
lowpan->addr[4] = 0xfe;
|
|
}
|
|
|
|
lowpan->addr[5] = ethernet[3];
|
|
lowpan->addr[6] = ethernet[4];
|
|
lowpan->addr[7] = ethernet[5];
|
|
|
|
#else //UIP_LLADDR != 8
|
|
// Not sure when we would ever hit this case...
|
|
uint8_t i;
|
|
for(i = 0; i < UIP_LLADDR_LEN; i++) {
|
|
lowpan->addr[i] = ethernet[i];
|
|
}
|
|
#endif //UIP_LLADDR == 8
|
|
|
|
#endif //UIP_CONF_SIMPLE_JACKDAW_ADDR_TRANS
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/**
|
|
* \brief Create a 802.3 address from a 802.15.4 long address
|
|
* \param ethernet Pointer to ethernet address
|
|
* \param lowpan Pointer to 802.15.4 address
|
|
*/
|
|
uint8_t mac_createEthernetAddr(uint8_t * ethernet, uip_lladdr_t * lowpan)
|
|
{
|
|
#if UIP_CONF_AUTO_SUBSTITUTE_LOCAL_MAC_ADDR
|
|
//Special case - if the address is our address, we just copy over what we know to be
|
|
//our 802.3 address
|
|
if (memcmp((uint8_t *)&macLongAddr, (uint8_t *)lowpan, UIP_LLADDR_LEN) == 0) {
|
|
usb_eth_get_mac_address(ethernet);
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
#if UIP_CONF_SIMPLE_JACKDAW_ADDR_TRANS
|
|
|
|
/** Just copy over 6 bytes **/
|
|
ethernet[0] = lowpan->addr[0];
|
|
ethernet[1] = lowpan->addr[1];
|
|
ethernet[2] = lowpan->addr[2];
|
|
ethernet[3] = lowpan->addr[5];
|
|
ethernet[4] = lowpan->addr[6];
|
|
ethernet[5] = lowpan->addr[7];
|
|
|
|
#else //!UIP_CONF_SIMPLE_JACKDAW_ADDR_TRANS
|
|
|
|
uint8_t index = 0;
|
|
uint8_t i;
|
|
|
|
#if UIP_LLADDR_LEN == 8
|
|
|
|
//Check if we need to do anything:
|
|
if ((lowpan->addr[3] == 0xff) && (lowpan->addr[4] == 0xfe) &&
|
|
((lowpan->addr[0] & TRANSLATE_BIT_MASK) == 0) &&
|
|
((lowpan->addr[0] & MULTICAST_BIT_MASK) == 0) &&
|
|
(lowpan->addr[0] & LOCAL_BIT_MASK)) {
|
|
|
|
/** Nope: just copy over 6 bytes **/
|
|
ethernet[0] = lowpan->addr[0];
|
|
ethernet[1] = lowpan->addr[1];
|
|
ethernet[2] = lowpan->addr[2];
|
|
ethernet[3] = lowpan->addr[5];
|
|
ethernet[4] = lowpan->addr[6];
|
|
ethernet[5] = lowpan->addr[7];
|
|
|
|
|
|
} else {
|
|
|
|
/** Yes: need to store prefix **/
|
|
for (i = 0; i < prefixCounter; i++) {
|
|
//Check the current prefix - if it fails, check next one
|
|
if ((lowpan->addr[0] == prefixBuffer[i][0]) &&
|
|
(lowpan->addr[1] == prefixBuffer[i][1]) &&
|
|
(lowpan->addr[2] == prefixBuffer[i][2])) {
|
|
break;
|
|
}
|
|
}
|
|
index = i;
|
|
|
|
if (index >= PREFIX_BUFFER_SIZE) {
|
|
// Overflow. Fall back to simple translation.
|
|
// TODO: Implement me!
|
|
ethernet[0] = lowpan->addr[0];
|
|
ethernet[1] = lowpan->addr[1];
|
|
ethernet[2] = lowpan->addr[2];
|
|
ethernet[3] = lowpan->addr[5];
|
|
ethernet[4] = lowpan->addr[6];
|
|
ethernet[5] = lowpan->addr[7];
|
|
return 0;
|
|
} else {
|
|
//Are we making a new one?
|
|
if (index == prefixCounter) {
|
|
prefixCounter++;
|
|
prefixBuffer[index][0] = lowpan->addr[0];
|
|
prefixBuffer[index][1] = lowpan->addr[1];
|
|
prefixBuffer[index][2] = lowpan->addr[2];
|
|
}
|
|
|
|
//Create ethernet MAC address now
|
|
ethernet[0] = TRANSLATE_BIT_MASK | LOCAL_BIT_MASK | (index << 3);
|
|
ethernet[1] = lowpan->addr[3];
|
|
ethernet[2] = lowpan->addr[4];
|
|
ethernet[3] = lowpan->addr[5];
|
|
ethernet[4] = lowpan->addr[6];
|
|
ethernet[5] = lowpan->addr[7];
|
|
}
|
|
}
|
|
|
|
#else //UIP_LLADDR_LEN != 8
|
|
// Not sure when we would ever hit this case...
|
|
//Create ethernet MAC address now
|
|
for(i = 0; i < UIP_LLADDR_LEN; i++) {
|
|
ethernet[i] = lowpan->addr[i];
|
|
}
|
|
#endif //UIP_LLADDR_LEN == 8
|
|
|
|
#endif //UIP_CONF_SIMPLE_JACKDAW_ADDR_TRANS
|
|
|
|
return 1;
|
|
}
|
|
/**
|
|
* \brief Create a 802.3 address (default)
|
|
* \param ethernet Pointer to ethernet address
|
|
*/
|
|
uint8_t mac_createDefaultEthernetAddr(uint8_t * ethernet)
|
|
{
|
|
memcpy(ethernet, &simple_trans_ethernet_addr, 6);
|
|
return 1;
|
|
}
|
|
/**
|
|
* \brief Slide the pointed to memory up a certain amount,
|
|
* growing/shrinking a buffer
|
|
* \param data Pointer to start of data buffer
|
|
* \param length Length of the data buffer
|
|
* \param slide How many bytes to slide the buffer up in memory (if +) or
|
|
* down in memory (if -)
|
|
*/
|
|
void slide(uint8_t * data, uint8_t length, int16_t slide)
|
|
{
|
|
//Sanity checks
|
|
if (!length) return;
|
|
if (!slide) return;
|
|
|
|
uint8_t i = 0;
|
|
|
|
while(length) {
|
|
length--;
|
|
|
|
//If we are sliding up, we do from the top of the buffer down
|
|
if (slide > 0) {
|
|
*(data + length + slide) = *(data + length);
|
|
|
|
//If we are sliding down, we do from the bottom of the buffer up
|
|
} else {
|
|
*(data + slide + i) = *(data + i);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
//#define ETHBUF(x) ((struct uip_eth_hdr *)x)
|
|
//#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
|
|
|
|
void
|
|
mac_log_802_15_4_tx(const uint8_t* buffer, size_t total_len) {
|
|
if (usbstick_mode.raw != 0) {
|
|
uint8_t sendlen;
|
|
|
|
static uint8_t raw_buf[127+ UIP_LLH_LEN +1];
|
|
|
|
/* Get the raw frame */
|
|
memcpy(&raw_buf[UIP_LLH_LEN], buffer, total_len);
|
|
sendlen = total_len;
|
|
|
|
/* Setup generic ethernet stuff */
|
|
ETHBUF(raw_buf)->type = uip_htons(0x809A); //UIP_ETHTYPE_802154 0x809A
|
|
|
|
/* Check for broadcast message */
|
|
if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) {
|
|
ETHBUF(raw_buf)->dest.addr[0] = 0x33;
|
|
ETHBUF(raw_buf)->dest.addr[1] = 0x33;
|
|
ETHBUF(raw_buf)->dest.addr[2] = 0x00;
|
|
ETHBUF(raw_buf)->dest.addr[3] = 0x00;
|
|
ETHBUF(raw_buf)->dest.addr[4] = 0x80;
|
|
ETHBUF(raw_buf)->dest.addr[5] = 0x9A;
|
|
|
|
/*
|
|
ETHBUF(raw_buf)->dest.addr[2] = UIP_IP_BUF->destipaddr.u8[12];
|
|
ETHBUF(raw_buf)->dest.addr[3] = UIP_IP_BUF->destipaddr.u8[13];
|
|
ETHBUF(raw_buf)->dest.addr[4] = UIP_IP_BUF->destipaddr.u8[14];
|
|
ETHBUF(raw_buf)->dest.addr[5] = UIP_IP_BUF->destipaddr.u8[15];
|
|
*/
|
|
} else {
|
|
/* Otherwise we have a real address */
|
|
mac_createEthernetAddr((uint8_t *) &(ETHBUF(raw_buf)->dest.addr[0]),
|
|
(uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
|
|
}
|
|
|
|
// mac_createEthernetAddr((uint8_t *) &(ETHBUF(raw_buf)->src.addr[0]),(uip_lladdr_t *)&uip_lladdr.addr);
|
|
mac_createDefaultEthernetAddr((uint8_t *) &(ETHBUF(raw_buf)->src.addr[0]));
|
|
|
|
sendlen += UIP_LLH_LEN;
|
|
usb_eth_send(raw_buf, sendlen, 0);
|
|
}
|
|
}
|
|
|
|
void
|
|
mac_log_802_15_4_rx(const uint8_t* buf, size_t len) {
|
|
if (usbstick_mode.raw != 0) {
|
|
uint8_t sendlen;
|
|
|
|
/* Get the raw frame */
|
|
memcpy(&raw_buf[UIP_LLH_LEN], buf, len);
|
|
sendlen = len;
|
|
|
|
/* Setup generic ethernet stuff */
|
|
ETHBUF(raw_buf)->type = uip_htons(0x809A); //UIP_ETHTYPE_802154 0x809A
|
|
|
|
/* Check for broadcast message */
|
|
if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) {
|
|
ETHBUF(raw_buf)->dest.addr[0] = 0x33;
|
|
ETHBUF(raw_buf)->dest.addr[1] = 0x33;
|
|
ETHBUF(raw_buf)->dest.addr[2] = 0x00;
|
|
ETHBUF(raw_buf)->dest.addr[3] = 0x00;
|
|
ETHBUF(raw_buf)->dest.addr[4] = 0x80;
|
|
ETHBUF(raw_buf)->dest.addr[5] = 0x9A;
|
|
/*
|
|
ETHBUF(raw_buf)->dest.addr[2] = UIP_IP_BUF->destipaddr.u8[12];
|
|
ETHBUF(raw_buf)->dest.addr[3] = UIP_IP_BUF->destipaddr.u8[13];
|
|
ETHBUF(raw_buf)->dest.addr[4] = UIP_IP_BUF->destipaddr.u8[14];
|
|
ETHBUF(raw_buf)->dest.addr[5] = UIP_IP_BUF->destipaddr.u8[15];
|
|
*/
|
|
} else {
|
|
/* Otherwise we have a real address */
|
|
mac_createEthernetAddr((uint8_t *) &(ETHBUF(raw_buf)->dest.addr[0]),
|
|
(uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
|
|
}
|
|
|
|
// mac_createEthernetAddr((uint8_t *) &(ETHBUF(raw_buf)->src.addr[0]),(uip_lladdr_t *)&uip_lladdr.addr);
|
|
mac_createDefaultEthernetAddr((uint8_t *) &(ETHBUF(raw_buf)->src.addr[0]));
|
|
|
|
sendlen += UIP_LLH_LEN;
|
|
usb_eth_send(raw_buf, sendlen, 0);
|
|
}
|
|
}
|
|
|
|
bool
|
|
mac_is_send_enabled(void) {
|
|
return usbstick_mode.sendToRf;
|
|
}
|
|
|
|
/** @} */
|
|
|
|
|
|
|
|
/** @} */
|
|
|
|
|
|
#if !RF230BB
|
|
/*--------------------------------------------------------------------*/
|
|
/** \brief Process a received 6lowpan packet. Hijack function.
|
|
* \param r The MAC layer
|
|
*
|
|
* The 6lowpan packet is put in packetbuf by the MAC. This routine calls
|
|
* any other needed layers (either 6lowpan, or just raw ethernet dump)
|
|
*/
|
|
void mac_ethhijack(const struct mac_driver *r)
|
|
{
|
|
if (usbstick_mode.raw) {
|
|
mac_802154raw(r);
|
|
}
|
|
|
|
if (usbstick_mode.sicslowpan) {
|
|
|
|
#if UIP_CONF_USE_RUM
|
|
if (parsed_frame->payload[4]) { /* RUM 6lowpan frame type */
|
|
#endif
|
|
sicslowinput(r);
|
|
#if UIP_CONF_USE_RUM
|
|
}
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void mac_ethhijack_nondata(const struct mac_driver *r)
|
|
{
|
|
if (usbstick_mode.raw)
|
|
mac_802154raw(r);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
/*--------------------------------------------------------------------*/
|
|
/** \brief Logs a sent 6lowpan frame
|
|
*
|
|
* This routine passes a frame
|
|
* directly to the ethernet layer without decompressing.
|
|
*/
|
|
void mac_logTXtoEthernet(frame_create_params_t *p,frame_result_t *frame_result)
|
|
{
|
|
mac_log_802_15_4_tx(frame_result->frame, frame_result->length);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
/** \brief Process a received 6lowpan packet.
|
|
* \param r The MAC layer
|
|
*
|
|
* The 6lowpan packet is put in packetbuf by the MAC. This routine passes
|
|
* it directly to the ethernet layer without decompressing.
|
|
*/
|
|
void mac_802154raw(const struct mac_driver *r) {
|
|
mac_log_802_15_4_tx(radio_frame_data(), radio_frame_length());
|
|
}
|
|
|
|
#endif /* !RF230BB */
|
|
|
|
|
|
|