Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
lwip_lowpan6_ble.c
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 */
Generated on Tue Jul 12 2022 13:54:28 by
1.7.2