Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_lowpan6_ble.c Source File

lwip_lowpan6_ble.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * 6LowPAN over BLE output for IPv6 (RFC7668).
00004 */
00005 
00006 /*
00007  * Copyright (c) 2017 Benjamin Aigner
00008  * Copyright (c) 2015 Inico Technologies Ltd. , Author: Ivan Delamer <delamer@inicotech.com>
00009  * 
00010  * All rights reserved.
00011  *
00012  * Redistribution and use in source and binary forms, with or without modification,
00013  * are permitted provided that the following conditions are met:
00014  *
00015  * 1. Redistributions of source code must retain the above copyright notice,
00016  *    this list of conditions and the following disclaimer.
00017  * 2. Redistributions in binary form must reproduce the above copyright notice,
00018  *    this list of conditions and the following disclaimer in the documentation
00019  *    and/or other materials provided with the distribution.
00020  * 3. The name of the author may not be used to endorse or promote products
00021  *    derived from this software without specific prior written permission.
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00024  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00025  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00026  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00027  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00028  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00029  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00030  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00031  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00032  * OF SUCH DAMAGE.
00033  *
00034  * Author: Benjamin Aigner <aignerb@technikum-wien.at>
00035  * 
00036  * Based on the original 6lowpan implementation of lwIP ( @see 6lowpan.c)
00037  */
00038 
00039 
00040 /**
00041  * @defgroup rfc7668if 6LoWPAN over BLE (RFC7668)
00042  * @ingroup netifs
00043  * This file implements a RFC7668 implementation for 6LoWPAN over
00044  * Bluetooth Low Energy. The specification is very similar to 6LoWPAN,
00045  * so most of the code is re-used.
00046  * Compared to 6LoWPAN, much functionality is already implemented in
00047  * lower BLE layers (fragmenting, session management,...).
00048  *
00049  * Usage:
00050  * - add this netif
00051  *   - don't add IPv4 addresses (no IPv4 support in RFC7668), pass 'NULL','NULL','NULL'
00052  *   - use the BLE to EUI64 conversation util to create an IPv6 link-local address from the BLE MAC (@ref ble_addr_to_eui64)
00053  *   - input function: @ref rfc7668_input
00054  * - set the link output function, which transmits output data to an established L2CAP channel
00055  * - If data arrives (HCI event "L2CAP_DATA_PACKET"):
00056  *   - allocate a @ref PBUF_RAW buffer
00057  *   - let the pbuf struct point to the incoming data or copy it to the buffer
00058  *   - call netif->input
00059  *
00060  * @todo:
00061  * - further testing
00062  * - support compression contexts
00063  * - support multiple addresses
00064  * - support multicast
00065  * - support neighbor discovery
00066  */
00067 
00068 
00069 #include "netif/lowpan6_ble.h"
00070 
00071 #if LWIP_IPV6
00072 
00073 #include "lwip/ip.h"
00074 #include "lwip/pbuf.h"
00075 #include "lwip/ip_addr.h"
00076 #include "lwip/netif.h"
00077 #include "lwip/nd6.h"
00078 #include "lwip/mem.h"
00079 #include "lwip/udp.h"
00080 #include "lwip/tcpip.h"
00081 #include "lwip/snmp.h"
00082 
00083 #include <string.h>
00084 
00085 #if LWIP_6LOWPAN_NUM_CONTEXTS > 0
00086 /** context memory, containing IPv6 addresses */
00087 static ip6_addr_t rfc7668_context[LWIP_6LOWPAN_NUM_CONTEXTS];
00088 #else
00089 #define rfc7668_context NULL
00090 #endif
00091 
00092 static struct lowpan6_link_addr rfc7668_local_addr;
00093 static struct lowpan6_link_addr rfc7668_peer_addr;
00094 
00095 /**
00096  * @ingroup rfc7668if
00097  *  convert BT address to EUI64 addr
00098  * 
00099  * This method converts a Bluetooth MAC address to an EUI64 address,
00100  * which is used within IPv6 communication
00101  * 
00102  * @param dst IPv6 destination space
00103  * @param src BLE MAC address source
00104  * @param public_addr If the LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS
00105  * option is set, bit 0x02 will be set if param=0 (no public addr); cleared otherwise
00106  * 
00107  * @see LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS
00108  */
00109 void
00110 ble_addr_to_eui64(uint8_t *dst, const uint8_t *src, int public_addr)
00111 {
00112   /* according to RFC7668 ch 3.2.2. */
00113   memcpy(dst, src, 3);
00114   dst[3] = 0xFF;
00115   dst[4] = 0xFE;
00116   memcpy(&dst[5], &src[3], 3);
00117 #if LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS
00118   if(public_addr) {
00119     dst[0] &= ~0x02;
00120   } else {
00121     dst[0] |= 0x02;
00122   }
00123 #else
00124   LWIP_UNUSED_ARG(public_addr);
00125 #endif
00126 }
00127 
00128 /**
00129  * @ingroup rfc7668if
00130  *  convert EUI64 address to Bluetooth MAC addr
00131  * 
00132  * This method converts an EUI64 address to a Bluetooth MAC address,
00133  * 
00134  * @param dst BLE MAC address destination
00135  * @param src IPv6 source
00136  * 
00137  */
00138 void
00139 eui64_to_ble_addr(uint8_t *dst, const uint8_t *src)
00140 {
00141   /* according to RFC7668 ch 3.2.2. */
00142   memcpy(dst,src,3);
00143   memcpy(&dst[3],&src[5],3);
00144 }
00145 
00146 /** Set an address used for stateful compression.
00147  * This expects an address of 6 or 8 bytes.
00148  */
00149 static err_t
00150 rfc7668_set_addr(struct lowpan6_link_addr *addr, const u8_t *in_addr, size_t in_addr_len, int is_mac_48, int is_public_addr)
00151 {
00152   if ((in_addr == NULL) || (addr == NULL)) {
00153     return ERR_VAL;
00154   }
00155   if (is_mac_48) {
00156     if (in_addr_len != 6) {
00157       return ERR_VAL;
00158     }
00159     addr->addr_len = 8;
00160     ble_addr_to_eui64(addr->addr, in_addr, is_public_addr);
00161   } else {
00162     if (in_addr_len != 8) {
00163       return ERR_VAL;
00164     }
00165     addr->addr_len = 8;
00166     memcpy(addr->addr, in_addr, 8);
00167   }
00168   return ERR_OK;
00169 }
00170 
00171 
00172 /** Set the local address used for stateful compression.
00173  * This expects an address of 8 bytes.
00174  */
00175 err_t
00176 rfc7668_set_local_addr_eui64(struct netif *netif, const u8_t *local_addr, size_t local_addr_len)
00177 {
00178   /* netif not used for now, the address is stored globally... */
00179   LWIP_UNUSED_ARG(netif);
00180   return rfc7668_set_addr(&rfc7668_local_addr, local_addr, local_addr_len, 0, 0);
00181 }
00182 
00183 /** Set the local address used for stateful compression.
00184  * This expects an address of 6 bytes.
00185  */
00186 err_t
00187 rfc7668_set_local_addr_mac48(struct netif *netif, const u8_t *local_addr, size_t local_addr_len, int is_public_addr)
00188 {
00189   /* netif not used for now, the address is stored globally... */
00190   LWIP_UNUSED_ARG(netif);
00191   return rfc7668_set_addr(&rfc7668_local_addr, local_addr, local_addr_len, 1, is_public_addr);
00192 }
00193 
00194 /** Set the peer address used for stateful compression.
00195  * This expects an address of 8 bytes.
00196  */
00197 err_t
00198 rfc7668_set_peer_addr_eui64(struct netif *netif, const u8_t *peer_addr, size_t peer_addr_len)
00199 {
00200   /* netif not used for now, the address is stored globally... */
00201   LWIP_UNUSED_ARG(netif);
00202   return rfc7668_set_addr(&rfc7668_peer_addr, peer_addr, peer_addr_len, 0, 0);
00203 }
00204 
00205 /** Set the peer address used for stateful compression.
00206  * This expects an address of 6 bytes.
00207  */
00208 err_t
00209 rfc7668_set_peer_addr_mac48(struct netif *netif, const u8_t *peer_addr, size_t peer_addr_len, int is_public_addr)
00210 {
00211   /* netif not used for now, the address is stored globally... */
00212   LWIP_UNUSED_ARG(netif);
00213   return rfc7668_set_addr(&rfc7668_peer_addr, peer_addr, peer_addr_len, 1, is_public_addr);
00214 }
00215 
00216 /** Encapsulate IPv6 frames for BLE transmission
00217  * 
00218  * This method implements the IPv6 header compression:
00219  *  *) According to RFC6282
00220  *  *) See Figure 2, contains base format of bit positions
00221  *  *) Fragmentation not necessary (done at L2CAP layer of BLE)
00222  * @note Currently the pbuf allocation uses 256 bytes. If longer packets are used (possible due to MTU=1480Bytes), increase it here!
00223  * 
00224  * @param p Pbuf struct, containing the payload data
00225  * @param netif Output network interface. Should be of RFC7668 type
00226  * 
00227  * @return Same as netif->output.
00228  */
00229 static err_t
00230 rfc7668_compress(struct netif *netif, struct pbuf *p)
00231 {
00232   struct pbuf *p_frag;
00233   u16_t remaining_len;
00234   u8_t *buffer;
00235   u8_t lowpan6_header_len;
00236   u8_t hidden_header_len;
00237   err_t err;
00238 
00239   LWIP_ASSERT("lowpan6_frag: netif->linkoutput not set", netif->linkoutput != NULL);
00240 
00241 #if LWIP_6LOWPAN_IPHC
00242 
00243   /* We'll use a dedicated pbuf for building BLE fragments.
00244    * We'll over-allocate it by the bytes saved for header compression.
00245    */
00246   p_frag = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
00247   if (p_frag == NULL) {
00248     MIB2_STATS_NETIF_INC(netif, ifoutdiscards);
00249     return ERR_MEM;
00250   }
00251   LWIP_ASSERT("this needs a pbuf in one piece", p_frag->len == p_frag->tot_len);
00252 
00253   /* Write IP6 header (with IPHC). */
00254   buffer = (u8_t*)p_frag->payload;
00255 
00256   err = lowpan6_compress_headers(netif, (u8_t *)p->payload, p->len, buffer, p_frag->len,
00257     &lowpan6_header_len, &hidden_header_len, rfc7668_context, &rfc7668_local_addr, &rfc7668_peer_addr);
00258   if (err != ERR_OK) {
00259     MIB2_STATS_NETIF_INC(netif, ifoutdiscards);
00260     pbuf_free(p_frag);
00261     return err;
00262   }
00263   pbuf_remove_header(p, hidden_header_len);
00264 
00265   /* Calculate remaining packet length */
00266   remaining_len = p->tot_len;
00267 
00268   /* Copy IPv6 packet */
00269   pbuf_copy_partial(p, buffer + lowpan6_header_len, remaining_len, 0);
00270 
00271   /* Calculate frame length */
00272   p_frag->len = p_frag->tot_len = remaining_len + lowpan6_header_len;
00273 
00274   /* send the packet */
00275   MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p_frag->tot_len);
00276   LWIP_DEBUGF(LWIP_LOWPAN6_DEBUG|LWIP_DBG_TRACE, ("rfc7668_output: sending packet %p\n", (void *)p));
00277   err = netif->linkoutput(netif, p_frag);
00278 
00279   pbuf_free(p_frag);
00280 
00281   return err;
00282 #else /* LWIP_6LOWPAN_IPHC */
00283   /* 6LoWPAN over BLE requires IPHC! */
00284   return ERR_IF;
00285 #endif/* LWIP_6LOWPAN_IPHC */
00286 }
00287 
00288 /**
00289  * @ingroup rfc7668if
00290  * Set context id IPv6 address
00291  *
00292  * Store one IPv6 address to a given context id.
00293  *
00294  * @param idx Context id
00295  * @param context IPv6 addr for this context
00296  *
00297  * @return ERR_OK (if everything is fine), ERR_ARG (if the context id is out of range), ERR_VAL (if contexts disabled)
00298  */
00299 err_t
00300 rfc7668_set_context(u8_t idx, const ip6_addr_t *context)
00301 {
00302 #if LWIP_6LOWPAN_NUM_CONTEXTS > 0
00303   /* check if the ID is possible */
00304   if (idx >= LWIP_6LOWPAN_NUM_CONTEXTS) {
00305     return ERR_ARG;
00306   }
00307   /* copy IPv6 address to context storage */
00308   ip6_addr_set(&rfc7668_context[idx], context);
00309   return ERR_OK;
00310 #else
00311   LWIP_UNUSED_ARG(idx);
00312   LWIP_UNUSED_ARG(context);
00313   return ERR_VAL;
00314 #endif
00315 }
00316 
00317 /**
00318  * @ingroup rfc7668if
00319  * Compress outgoing IPv6 packet and pass it on to netif->linkoutput
00320  *
00321  * @param netif The lwIP network interface which the IP packet will be sent on.
00322  * @param q The pbuf(s) containing the IP packet to be sent.
00323  * @param ip6addr The IP address of the packet destination.
00324  *
00325  * @return See rfc7668_compress
00326  */
00327 err_t
00328 rfc7668_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr)
00329 {
00330   /* dst ip6addr is not used here, we only have one peer */
00331   LWIP_UNUSED_ARG(ip6addr);
00332 
00333   return rfc7668_compress(netif, q);
00334 }
00335 
00336 /**
00337  * @ingroup rfc7668if
00338  * Process a received raw payload from an L2CAP channel
00339  *
00340  * @param p the received packet, p->payload pointing to the
00341  *        IPv6 header (maybe compressed)
00342  * @param netif the network interface on which the packet was received
00343  * 
00344  * @return ERR_OK if everything was fine
00345  */
00346 err_t
00347 rfc7668_input(struct pbuf * p, struct netif *netif)
00348 {
00349   u8_t * puc;
00350 
00351   MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
00352 
00353   /* Load first header byte */
00354   puc = (u8_t*)p->payload;
00355   
00356   /* no IP header compression */
00357   if (*puc == 0x41) {
00358     LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Completed packet, removing dispatch: 0x%2x \n", *puc));
00359     /* This is a complete IPv6 packet, just skip header byte. */
00360     pbuf_remove_header(p, 1);
00361   /* IPHC header compression */
00362   } else if ((*puc & 0xe0 )== 0x60) {
00363     LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Completed packet, decompress dispatch: 0x%2x \n", *puc));
00364     /* IPv6 headers are compressed using IPHC. */
00365     p = lowpan6_decompress(p, 0, rfc7668_context, &rfc7668_peer_addr, &rfc7668_local_addr);
00366     /* if no pbuf is returned, handle as discarded packet */
00367     if (p == NULL) {
00368       MIB2_STATS_NETIF_INC(netif, ifindiscards);
00369       return ERR_OK;
00370     }
00371   /* invalid header byte, discard */
00372   } else {
00373     LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Completed packet, discarding: 0x%2x \n", *puc));
00374     MIB2_STATS_NETIF_INC(netif, ifindiscards);
00375     pbuf_free(p);
00376     return ERR_OK;
00377   }
00378   /* @todo: distinguish unicast/multicast */
00379   MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
00380 
00381 #if LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG
00382   {
00383     u16_t i;
00384     LWIP_DEBUGF(LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG, ("IPv6 payload:\n"));
00385     for (i = 0; i < p->len; i++) {
00386       if ((i%4)==0) {
00387         LWIP_DEBUGF(LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG, ("\n"));
00388       }
00389       LWIP_DEBUGF(LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG, ("%2X ", *((uint8_t *)p->payload+i)));
00390     }
00391     LWIP_DEBUGF(LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG, ("\np->len: %d\n", p->len));
00392   }
00393 #endif
00394   /* pass data to ip6_input */
00395   return ip6_input(p, netif);
00396 }
00397 
00398 /**
00399  * @ingroup rfc7668if
00400  * Initialize the netif
00401  * 
00402  * No flags are used (broadcast not possible, not ethernet, ...)
00403  * The shortname for this netif is "BT"
00404  *
00405  * @param netif the network interface to be initialized as RFC7668 netif
00406  * 
00407  * @return ERR_OK if everything went fine
00408  */
00409 err_t
00410 rfc7668_if_init(struct netif *netif)
00411 {
00412   netif->name[0] = 'b';
00413   netif->name[1] = 't';
00414   /* local function as IPv6 output */
00415   netif->output_ip6 = rfc7668_output;
00416 
00417   MIB2_INIT_NETIF(netif, snmp_ifType_other, 0);
00418 
00419   /* maximum transfer unit, set according to RFC7668 ch2.4 */
00420   netif->mtu = 1280;
00421 
00422   /* no flags set (no broadcast, ethernet,...)*/
00423   netif->flags = 0;
00424 
00425   /* everything fine */
00426   return ERR_OK;
00427 }
00428 
00429 #if !NO_SYS
00430 /**
00431  * Pass a received packet to tcpip_thread for input processing
00432  *
00433  * @param p the received packet, p->payload pointing to the
00434  *          IEEE 802.15.4 header.
00435  * @param inp the network interface on which the packet was received
00436  * 
00437  * @return see @ref tcpip_inpkt, same return values
00438  */
00439 err_t
00440 tcpip_rfc7668_input(struct pbuf *p, struct netif *inp)
00441 {
00442   /* send data to upper layer, return the result */
00443   return tcpip_inpkt(p, inp, rfc7668_input);
00444 }
00445 #endif /* !NO_SYS */
00446 
00447 #endif /* LWIP_IPV6 */