1195972f6Sopenharmony_ci/** 2195972f6Sopenharmony_ci * @file 3195972f6Sopenharmony_ci * 4195972f6Sopenharmony_ci * 6LowPAN output for IPv6. Uses ND tables for link-layer addressing. Fragments packets to 6LowPAN units. 5195972f6Sopenharmony_ci * 6195972f6Sopenharmony_ci * This implementation aims to conform to IEEE 802.15.4(-2015), RFC 4944 and RFC 6282. 7195972f6Sopenharmony_ci * @todo: RFC 6775. 8195972f6Sopenharmony_ci */ 9195972f6Sopenharmony_ci 10195972f6Sopenharmony_ci/* 11195972f6Sopenharmony_ci * Copyright (c) 2015 Inico Technologies Ltd. 12195972f6Sopenharmony_ci * All rights reserved. 13195972f6Sopenharmony_ci * 14195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 15195972f6Sopenharmony_ci * are permitted provided that the following conditions are met: 16195972f6Sopenharmony_ci * 17195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, 18195972f6Sopenharmony_ci * this list of conditions and the following disclaimer. 19195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, 20195972f6Sopenharmony_ci * this list of conditions and the following disclaimer in the documentation 21195972f6Sopenharmony_ci * and/or other materials provided with the distribution. 22195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products 23195972f6Sopenharmony_ci * derived from this software without specific prior written permission. 24195972f6Sopenharmony_ci * 25195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 26195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 28195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 30195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34195972f6Sopenharmony_ci * OF SUCH DAMAGE. 35195972f6Sopenharmony_ci * 36195972f6Sopenharmony_ci * This file is part of the lwIP TCP/IP stack. 37195972f6Sopenharmony_ci * 38195972f6Sopenharmony_ci * Author: Ivan Delamer <delamer@inicotech.com> 39195972f6Sopenharmony_ci * 40195972f6Sopenharmony_ci * 41195972f6Sopenharmony_ci * Please coordinate changes and requests with Ivan Delamer 42195972f6Sopenharmony_ci * <delamer@inicotech.com> 43195972f6Sopenharmony_ci */ 44195972f6Sopenharmony_ci 45195972f6Sopenharmony_ci/** 46195972f6Sopenharmony_ci * @defgroup sixlowpan 6LoWPAN (RFC4944) 47195972f6Sopenharmony_ci * @ingroup netifs 48195972f6Sopenharmony_ci * 6LowPAN netif implementation 49195972f6Sopenharmony_ci */ 50195972f6Sopenharmony_ci 51195972f6Sopenharmony_ci#include "netif/lowpan6.h" 52195972f6Sopenharmony_ci 53195972f6Sopenharmony_ci#if LWIP_IPV6 54195972f6Sopenharmony_ci 55195972f6Sopenharmony_ci#include "lwip/ip.h" 56195972f6Sopenharmony_ci#include "lwip/pbuf.h" 57195972f6Sopenharmony_ci#include "lwip/ip_addr.h" 58195972f6Sopenharmony_ci#include "lwip/netif.h" 59195972f6Sopenharmony_ci#include "lwip/nd6.h" 60195972f6Sopenharmony_ci#include "lwip/mem.h" 61195972f6Sopenharmony_ci#include "lwip/udp.h" 62195972f6Sopenharmony_ci#include "lwip/tcpip.h" 63195972f6Sopenharmony_ci#include "lwip/snmp.h" 64195972f6Sopenharmony_ci#include "netif/ieee802154.h" 65195972f6Sopenharmony_ci 66195972f6Sopenharmony_ci#if LWIP_LOWPOWER 67195972f6Sopenharmony_ci#include "lwip/lowpower.h" 68195972f6Sopenharmony_ci#endif 69195972f6Sopenharmony_ci#include <string.h> 70195972f6Sopenharmony_ci 71195972f6Sopenharmony_ci#if LWIP_6LOWPAN_802154_HW_CRC 72195972f6Sopenharmony_ci#define LWIP_6LOWPAN_DO_CALC_CRC(buf, len) 0 73195972f6Sopenharmony_ci#else 74195972f6Sopenharmony_ci#define LWIP_6LOWPAN_DO_CALC_CRC(buf, len) LWIP_6LOWPAN_CALC_CRC(buf, len) 75195972f6Sopenharmony_ci#endif 76195972f6Sopenharmony_ci 77195972f6Sopenharmony_ci/** This is a helper struct for reassembly of fragments 78195972f6Sopenharmony_ci * (IEEE 802.15.4 limits to 127 bytes) 79195972f6Sopenharmony_ci */ 80195972f6Sopenharmony_cistruct lowpan6_reass_helper { 81195972f6Sopenharmony_ci struct lowpan6_reass_helper *next_packet; 82195972f6Sopenharmony_ci struct pbuf *reass; 83195972f6Sopenharmony_ci struct pbuf *frags; 84195972f6Sopenharmony_ci u8_t timer; 85195972f6Sopenharmony_ci struct lowpan6_link_addr sender_addr; 86195972f6Sopenharmony_ci u16_t datagram_size; 87195972f6Sopenharmony_ci u16_t datagram_tag; 88195972f6Sopenharmony_ci}; 89195972f6Sopenharmony_ci 90195972f6Sopenharmony_ci/** This struct keeps track of per-netif state */ 91195972f6Sopenharmony_cistruct lowpan6_ieee802154_data { 92195972f6Sopenharmony_ci /** fragment reassembly list */ 93195972f6Sopenharmony_ci struct lowpan6_reass_helper *reass_list; 94195972f6Sopenharmony_ci#if LWIP_6LOWPAN_NUM_CONTEXTS > 0 95195972f6Sopenharmony_ci /** address context for compression */ 96195972f6Sopenharmony_ci ip6_addr_t lowpan6_context[LWIP_6LOWPAN_NUM_CONTEXTS]; 97195972f6Sopenharmony_ci#endif 98195972f6Sopenharmony_ci /** Datagram Tag for fragmentation */ 99195972f6Sopenharmony_ci u16_t tx_datagram_tag; 100195972f6Sopenharmony_ci /** local PAN ID for IEEE 802.15.4 header */ 101195972f6Sopenharmony_ci u16_t ieee_802154_pan_id; 102195972f6Sopenharmony_ci /** Sequence Number for IEEE 802.15.4 transmission */ 103195972f6Sopenharmony_ci u8_t tx_frame_seq_num; 104195972f6Sopenharmony_ci}; 105195972f6Sopenharmony_ci 106195972f6Sopenharmony_ci/* Maximum frame size is 127 bytes minus CRC size */ 107195972f6Sopenharmony_ci#define LOWPAN6_MAX_PAYLOAD (127 - 2) 108195972f6Sopenharmony_ci 109195972f6Sopenharmony_ci/** Currently, this state is global, since there's only one 6LoWPAN netif */ 110195972f6Sopenharmony_cistatic struct lowpan6_ieee802154_data lowpan6_data; 111195972f6Sopenharmony_ci 112195972f6Sopenharmony_ci#if LWIP_6LOWPAN_NUM_CONTEXTS > 0 113195972f6Sopenharmony_ci#define LWIP_6LOWPAN_CONTEXTS(netif) lowpan6_data.lowpan6_context 114195972f6Sopenharmony_ci#else 115195972f6Sopenharmony_ci#define LWIP_6LOWPAN_CONTEXTS(netif) NULL 116195972f6Sopenharmony_ci#endif 117195972f6Sopenharmony_ci 118195972f6Sopenharmony_cistatic const struct lowpan6_link_addr ieee_802154_broadcast = {2, {0xff, 0xff}}; 119195972f6Sopenharmony_ci 120195972f6Sopenharmony_ci#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS 121195972f6Sopenharmony_cistatic struct lowpan6_link_addr short_mac_addr = {2, {0, 0}}; 122195972f6Sopenharmony_ci#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ 123195972f6Sopenharmony_ci 124195972f6Sopenharmony_ci#if LWIP_LOWPOWER 125195972f6Sopenharmony_ciu32_t 126195972f6Sopenharmony_cilowpan6_tmr_tick() 127195972f6Sopenharmony_ci{ 128195972f6Sopenharmony_ci struct lowpan6_reass_helper *lrh = NULL; 129195972f6Sopenharmony_ci struct lowpan6_reass_helper *lrh_temp = NULL; 130195972f6Sopenharmony_ci u32_t tick = 0; 131195972f6Sopenharmony_ci 132195972f6Sopenharmony_ci lrh = lowpan6_data.reass_list; 133195972f6Sopenharmony_ci while (lrh != NULL) { 134195972f6Sopenharmony_ci lrh_temp = lrh->next_packet; 135195972f6Sopenharmony_ci if (lrh->timer > 0) { 136195972f6Sopenharmony_ci SET_TMR_TICK(tick, lrh->timer); 137195972f6Sopenharmony_ci } 138195972f6Sopenharmony_ci lrh = lrh_temp; 139195972f6Sopenharmony_ci } 140195972f6Sopenharmony_ci 141195972f6Sopenharmony_ci LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "lowpan6_tmr_tick", tick)); 142195972f6Sopenharmony_ci return tick; 143195972f6Sopenharmony_ci} 144195972f6Sopenharmony_ci#endif /* LWIP_LOWPOWER */ 145195972f6Sopenharmony_ci 146195972f6Sopenharmony_ci/* IEEE 802.15.4 specific functions: */ 147195972f6Sopenharmony_ci 148195972f6Sopenharmony_ci/** Write the IEEE 802.15.4 header that encapsulates the 6LoWPAN frame. 149195972f6Sopenharmony_ci * Src and dst PAN IDs are filled with the ID set by @ref lowpan6_set_pan_id. 150195972f6Sopenharmony_ci * 151195972f6Sopenharmony_ci * Since the length is variable: 152195972f6Sopenharmony_ci * @returns the header length 153195972f6Sopenharmony_ci */ 154195972f6Sopenharmony_cistatic u8_t 155195972f6Sopenharmony_cilowpan6_write_iee802154_header(struct ieee_802154_hdr *hdr, const struct lowpan6_link_addr *src, 156195972f6Sopenharmony_ci const struct lowpan6_link_addr *dst) 157195972f6Sopenharmony_ci{ 158195972f6Sopenharmony_ci u8_t ieee_header_len; 159195972f6Sopenharmony_ci u8_t *buffer; 160195972f6Sopenharmony_ci u8_t i; 161195972f6Sopenharmony_ci u16_t fc; 162195972f6Sopenharmony_ci 163195972f6Sopenharmony_ci fc = IEEE_802154_FC_FT_DATA; /* send data packet (2003 frame version) */ 164195972f6Sopenharmony_ci fc |= IEEE_802154_FC_PANID_COMPR; /* set PAN ID compression, for now src and dst PANs are equal */ 165195972f6Sopenharmony_ci if (dst != &ieee_802154_broadcast) { 166195972f6Sopenharmony_ci fc |= IEEE_802154_FC_ACK_REQ; /* data packet, no broadcast: ack required. */ 167195972f6Sopenharmony_ci } 168195972f6Sopenharmony_ci if (dst->addr_len == 2) { 169195972f6Sopenharmony_ci fc |= IEEE_802154_FC_DST_ADDR_MODE_SHORT; 170195972f6Sopenharmony_ci } else { 171195972f6Sopenharmony_ci LWIP_ASSERT("invalid dst address length", dst->addr_len == 8); 172195972f6Sopenharmony_ci fc |= IEEE_802154_FC_DST_ADDR_MODE_EXT; 173195972f6Sopenharmony_ci } 174195972f6Sopenharmony_ci if (src->addr_len == 2) { 175195972f6Sopenharmony_ci fc |= IEEE_802154_FC_SRC_ADDR_MODE_SHORT; 176195972f6Sopenharmony_ci } else { 177195972f6Sopenharmony_ci LWIP_ASSERT("invalid src address length", src->addr_len == 8); 178195972f6Sopenharmony_ci fc |= IEEE_802154_FC_SRC_ADDR_MODE_EXT; 179195972f6Sopenharmony_ci } 180195972f6Sopenharmony_ci hdr->frame_control = fc; 181195972f6Sopenharmony_ci hdr->sequence_number = lowpan6_data.tx_frame_seq_num++; 182195972f6Sopenharmony_ci hdr->destination_pan_id = lowpan6_data.ieee_802154_pan_id; /* pan id */ 183195972f6Sopenharmony_ci 184195972f6Sopenharmony_ci buffer = (u8_t *)hdr; 185195972f6Sopenharmony_ci ieee_header_len = 5; 186195972f6Sopenharmony_ci i = dst->addr_len; 187195972f6Sopenharmony_ci /* reverse memcpy of dst addr */ 188195972f6Sopenharmony_ci while (i-- > 0) { 189195972f6Sopenharmony_ci buffer[ieee_header_len++] = dst->addr[i]; 190195972f6Sopenharmony_ci } 191195972f6Sopenharmony_ci /* Source PAN ID skipped due to PAN ID Compression */ 192195972f6Sopenharmony_ci i = src->addr_len; 193195972f6Sopenharmony_ci /* reverse memcpy of src addr */ 194195972f6Sopenharmony_ci while (i-- > 0) { 195195972f6Sopenharmony_ci buffer[ieee_header_len++] = src->addr[i]; 196195972f6Sopenharmony_ci } 197195972f6Sopenharmony_ci return ieee_header_len; 198195972f6Sopenharmony_ci} 199195972f6Sopenharmony_ci 200195972f6Sopenharmony_ci/** Parse the IEEE 802.15.4 header from a pbuf. 201195972f6Sopenharmony_ci * If successful, the header is hidden from the pbuf. 202195972f6Sopenharmony_ci * 203195972f6Sopenharmony_ci * PAN IDs and seuqence number are not checked 204195972f6Sopenharmony_ci * 205195972f6Sopenharmony_ci * @param p input pbuf, p->payload pointing at the IEEE 802.15.4 header 206195972f6Sopenharmony_ci * @param src pointer to source address filled from the header 207195972f6Sopenharmony_ci * @param dest pointer to destination address filled from the header 208195972f6Sopenharmony_ci * @returns ERR_OK if successful 209195972f6Sopenharmony_ci */ 210195972f6Sopenharmony_cistatic err_t 211195972f6Sopenharmony_cilowpan6_parse_iee802154_header(struct pbuf *p, struct lowpan6_link_addr *src, 212195972f6Sopenharmony_ci struct lowpan6_link_addr *dest) 213195972f6Sopenharmony_ci{ 214195972f6Sopenharmony_ci u8_t *puc; 215195972f6Sopenharmony_ci s8_t i; 216195972f6Sopenharmony_ci u16_t frame_control, addr_mode; 217195972f6Sopenharmony_ci u16_t datagram_offset; 218195972f6Sopenharmony_ci 219195972f6Sopenharmony_ci /* Parse IEEE 802.15.4 header */ 220195972f6Sopenharmony_ci puc = (u8_t *)p->payload; 221195972f6Sopenharmony_ci frame_control = puc[0] | (puc[1] << 8); 222195972f6Sopenharmony_ci datagram_offset = 2; 223195972f6Sopenharmony_ci if (frame_control & IEEE_802154_FC_SEQNO_SUPPR) { 224195972f6Sopenharmony_ci if (IEEE_802154_FC_FRAME_VERSION_GET(frame_control) <= 1) { 225195972f6Sopenharmony_ci /* sequence number suppressed, this is not valid for versions 0/1 */ 226195972f6Sopenharmony_ci return ERR_VAL; 227195972f6Sopenharmony_ci } 228195972f6Sopenharmony_ci } else { 229195972f6Sopenharmony_ci datagram_offset++; 230195972f6Sopenharmony_ci } 231195972f6Sopenharmony_ci datagram_offset += 2; /* Skip destination PAN ID */ 232195972f6Sopenharmony_ci addr_mode = frame_control & IEEE_802154_FC_DST_ADDR_MODE_MASK; 233195972f6Sopenharmony_ci if (addr_mode == IEEE_802154_FC_DST_ADDR_MODE_EXT) { 234195972f6Sopenharmony_ci /* extended address (64 bit) */ 235195972f6Sopenharmony_ci dest->addr_len = 8; 236195972f6Sopenharmony_ci /* reverse memcpy: */ 237195972f6Sopenharmony_ci for (i = 0; i < 8; i++) { 238195972f6Sopenharmony_ci dest->addr[i] = puc[datagram_offset + 7 - i]; 239195972f6Sopenharmony_ci } 240195972f6Sopenharmony_ci datagram_offset += 8; 241195972f6Sopenharmony_ci } else if (addr_mode == IEEE_802154_FC_DST_ADDR_MODE_SHORT) { 242195972f6Sopenharmony_ci /* short address (16 bit) */ 243195972f6Sopenharmony_ci dest->addr_len = 2; 244195972f6Sopenharmony_ci /* reverse memcpy: */ 245195972f6Sopenharmony_ci dest->addr[0] = puc[datagram_offset + 1]; 246195972f6Sopenharmony_ci dest->addr[1] = puc[datagram_offset]; 247195972f6Sopenharmony_ci datagram_offset += 2; 248195972f6Sopenharmony_ci } else { 249195972f6Sopenharmony_ci /* unsupported address mode (do we need "no address"?) */ 250195972f6Sopenharmony_ci return ERR_VAL; 251195972f6Sopenharmony_ci } 252195972f6Sopenharmony_ci 253195972f6Sopenharmony_ci if (!(frame_control & IEEE_802154_FC_PANID_COMPR)) { 254195972f6Sopenharmony_ci /* No PAN ID compression, skip source PAN ID */ 255195972f6Sopenharmony_ci datagram_offset += 2; 256195972f6Sopenharmony_ci } 257195972f6Sopenharmony_ci 258195972f6Sopenharmony_ci addr_mode = frame_control & IEEE_802154_FC_SRC_ADDR_MODE_MASK; 259195972f6Sopenharmony_ci if (addr_mode == IEEE_802154_FC_SRC_ADDR_MODE_EXT) { 260195972f6Sopenharmony_ci /* extended address (64 bit) */ 261195972f6Sopenharmony_ci src->addr_len = 8; 262195972f6Sopenharmony_ci /* reverse memcpy: */ 263195972f6Sopenharmony_ci for (i = 0; i < 8; i++) { 264195972f6Sopenharmony_ci src->addr[i] = puc[datagram_offset + 7 - i]; 265195972f6Sopenharmony_ci } 266195972f6Sopenharmony_ci datagram_offset += 8; 267195972f6Sopenharmony_ci } else if (addr_mode == IEEE_802154_FC_DST_ADDR_MODE_SHORT) { 268195972f6Sopenharmony_ci /* short address (16 bit) */ 269195972f6Sopenharmony_ci src->addr_len = 2; 270195972f6Sopenharmony_ci src->addr[0] = puc[datagram_offset + 1]; 271195972f6Sopenharmony_ci src->addr[1] = puc[datagram_offset]; 272195972f6Sopenharmony_ci datagram_offset += 2; 273195972f6Sopenharmony_ci } else { 274195972f6Sopenharmony_ci /* unsupported address mode (do we need "no address"?) */ 275195972f6Sopenharmony_ci return ERR_VAL; 276195972f6Sopenharmony_ci } 277195972f6Sopenharmony_ci 278195972f6Sopenharmony_ci /* hide IEEE802.15.4 header. */ 279195972f6Sopenharmony_ci if (pbuf_remove_header(p, datagram_offset)) { 280195972f6Sopenharmony_ci return ERR_VAL; 281195972f6Sopenharmony_ci } 282195972f6Sopenharmony_ci return ERR_OK; 283195972f6Sopenharmony_ci} 284195972f6Sopenharmony_ci 285195972f6Sopenharmony_ci/** Calculate the 16-bit CRC as required by IEEE 802.15.4 */ 286195972f6Sopenharmony_ciu16_t 287195972f6Sopenharmony_cilowpan6_calc_crc(const void* buf, u16_t len) 288195972f6Sopenharmony_ci{ 289195972f6Sopenharmony_ci#define CCITT_POLY_16 0x8408U 290195972f6Sopenharmony_ci u16_t i; 291195972f6Sopenharmony_ci u8_t b; 292195972f6Sopenharmony_ci u16_t crc = 0; 293195972f6Sopenharmony_ci const u8_t* p = (const u8_t*)buf; 294195972f6Sopenharmony_ci 295195972f6Sopenharmony_ci for (i = 0; i < len; i++) { 296195972f6Sopenharmony_ci u8_t data = *p; 297195972f6Sopenharmony_ci for (b = 0U; b < 8U; b++) { 298195972f6Sopenharmony_ci if (((data ^ crc) & 1) != 0) { 299195972f6Sopenharmony_ci crc = (u16_t)((crc >> 1) ^ CCITT_POLY_16); 300195972f6Sopenharmony_ci } else { 301195972f6Sopenharmony_ci crc = (u16_t)(crc >> 1); 302195972f6Sopenharmony_ci } 303195972f6Sopenharmony_ci data = (u8_t)(data >> 1); 304195972f6Sopenharmony_ci } 305195972f6Sopenharmony_ci p++; 306195972f6Sopenharmony_ci } 307195972f6Sopenharmony_ci return crc; 308195972f6Sopenharmony_ci} 309195972f6Sopenharmony_ci 310195972f6Sopenharmony_ci/* Fragmentation specific functions: */ 311195972f6Sopenharmony_ci 312195972f6Sopenharmony_cistatic void 313195972f6Sopenharmony_cifree_reass_datagram(struct lowpan6_reass_helper *lrh) 314195972f6Sopenharmony_ci{ 315195972f6Sopenharmony_ci if (lrh->reass) { 316195972f6Sopenharmony_ci pbuf_free(lrh->reass); 317195972f6Sopenharmony_ci } 318195972f6Sopenharmony_ci if (lrh->frags) { 319195972f6Sopenharmony_ci pbuf_free(lrh->frags); 320195972f6Sopenharmony_ci } 321195972f6Sopenharmony_ci mem_free(lrh); 322195972f6Sopenharmony_ci} 323195972f6Sopenharmony_ci 324195972f6Sopenharmony_ci/** 325195972f6Sopenharmony_ci * Removes a datagram from the reassembly queue. 326195972f6Sopenharmony_ci **/ 327195972f6Sopenharmony_cistatic void 328195972f6Sopenharmony_cidequeue_datagram(struct lowpan6_reass_helper *lrh, struct lowpan6_reass_helper *prev) 329195972f6Sopenharmony_ci{ 330195972f6Sopenharmony_ci if (lowpan6_data.reass_list == lrh) { 331195972f6Sopenharmony_ci lowpan6_data.reass_list = lowpan6_data.reass_list->next_packet; 332195972f6Sopenharmony_ci } else { 333195972f6Sopenharmony_ci /* it wasn't the first, so it must have a valid 'prev' */ 334195972f6Sopenharmony_ci LWIP_ASSERT("sanity check linked list", prev != NULL); 335195972f6Sopenharmony_ci prev->next_packet = lrh->next_packet; 336195972f6Sopenharmony_ci } 337195972f6Sopenharmony_ci} 338195972f6Sopenharmony_ci 339195972f6Sopenharmony_ci/** 340195972f6Sopenharmony_ci * Periodic timer for 6LowPAN functions: 341195972f6Sopenharmony_ci * 342195972f6Sopenharmony_ci * - Remove incomplete/old packets 343195972f6Sopenharmony_ci */ 344195972f6Sopenharmony_civoid 345195972f6Sopenharmony_cilowpan6_tmr(void) 346195972f6Sopenharmony_ci{ 347195972f6Sopenharmony_ci struct lowpan6_reass_helper *lrh, *lrh_next, *lrh_prev = NULL; 348195972f6Sopenharmony_ci 349195972f6Sopenharmony_ci lrh = lowpan6_data.reass_list; 350195972f6Sopenharmony_ci while (lrh != NULL) { 351195972f6Sopenharmony_ci lrh_next = lrh->next_packet; 352195972f6Sopenharmony_ci if ((--lrh->timer) == 0) { 353195972f6Sopenharmony_ci dequeue_datagram(lrh, lrh_prev); 354195972f6Sopenharmony_ci free_reass_datagram(lrh); 355195972f6Sopenharmony_ci } else { 356195972f6Sopenharmony_ci lrh_prev = lrh; 357195972f6Sopenharmony_ci } 358195972f6Sopenharmony_ci lrh = lrh_next; 359195972f6Sopenharmony_ci } 360195972f6Sopenharmony_ci} 361195972f6Sopenharmony_ci 362195972f6Sopenharmony_ci/* 363195972f6Sopenharmony_ci * Encapsulates data into IEEE 802.15.4 frames. 364195972f6Sopenharmony_ci * Fragments an IPv6 datagram into 6LowPAN units, which fit into IEEE 802.15.4 frames. 365195972f6Sopenharmony_ci * If configured, will compress IPv6 and or UDP headers. 366195972f6Sopenharmony_ci * */ 367195972f6Sopenharmony_cistatic err_t 368195972f6Sopenharmony_cilowpan6_frag(struct netif *netif, struct pbuf *p, const struct lowpan6_link_addr *src, const struct lowpan6_link_addr *dst) 369195972f6Sopenharmony_ci{ 370195972f6Sopenharmony_ci struct pbuf *p_frag; 371195972f6Sopenharmony_ci u16_t frag_len, remaining_len, max_data_len; 372195972f6Sopenharmony_ci u8_t *buffer; 373195972f6Sopenharmony_ci u8_t ieee_header_len; 374195972f6Sopenharmony_ci u8_t lowpan6_header_len; 375195972f6Sopenharmony_ci u8_t hidden_header_len; 376195972f6Sopenharmony_ci u16_t crc; 377195972f6Sopenharmony_ci u16_t datagram_offset; 378195972f6Sopenharmony_ci err_t err = ERR_IF; 379195972f6Sopenharmony_ci 380195972f6Sopenharmony_ci LWIP_ASSERT("lowpan6_frag: netif->linkoutput not set", netif->linkoutput != NULL); 381195972f6Sopenharmony_ci 382195972f6Sopenharmony_ci /* We'll use a dedicated pbuf for building 6LowPAN fragments. */ 383195972f6Sopenharmony_ci p_frag = pbuf_alloc(PBUF_RAW, 127, PBUF_RAM); 384195972f6Sopenharmony_ci if (p_frag == NULL) { 385195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(netif, ifoutdiscards); 386195972f6Sopenharmony_ci return ERR_MEM; 387195972f6Sopenharmony_ci } 388195972f6Sopenharmony_ci LWIP_ASSERT("this needs a pbuf in one piece", p_frag->len == p_frag->tot_len); 389195972f6Sopenharmony_ci 390195972f6Sopenharmony_ci /* Write IEEE 802.15.4 header. */ 391195972f6Sopenharmony_ci buffer = (u8_t *)p_frag->payload; 392195972f6Sopenharmony_ci ieee_header_len = lowpan6_write_iee802154_header((struct ieee_802154_hdr *)buffer, src, dst); 393195972f6Sopenharmony_ci LWIP_ASSERT("ieee_header_len < p_frag->len", ieee_header_len < p_frag->len); 394195972f6Sopenharmony_ci 395195972f6Sopenharmony_ci#if LWIP_6LOWPAN_IPHC 396195972f6Sopenharmony_ci /* Perform 6LowPAN IPv6 header compression according to RFC 6282 */ 397195972f6Sopenharmony_ci /* do the header compression (this does NOT copy any non-compressed data) */ 398195972f6Sopenharmony_ci err = lowpan6_compress_headers(netif, (u8_t *)p->payload, p->len, 399195972f6Sopenharmony_ci &buffer[ieee_header_len], p_frag->len - ieee_header_len, &lowpan6_header_len, 400195972f6Sopenharmony_ci &hidden_header_len, LWIP_6LOWPAN_CONTEXTS(netif), src, dst); 401195972f6Sopenharmony_ci if (err != ERR_OK) { 402195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(netif, ifoutdiscards); 403195972f6Sopenharmony_ci pbuf_free(p_frag); 404195972f6Sopenharmony_ci return err; 405195972f6Sopenharmony_ci } 406195972f6Sopenharmony_ci pbuf_remove_header(p, hidden_header_len); 407195972f6Sopenharmony_ci 408195972f6Sopenharmony_ci#else /* LWIP_6LOWPAN_IPHC */ 409195972f6Sopenharmony_ci /* Send uncompressed IPv6 header with appropriate dispatch byte. */ 410195972f6Sopenharmony_ci lowpan6_header_len = 1; 411195972f6Sopenharmony_ci buffer[ieee_header_len] = 0x41; /* IPv6 dispatch */ 412195972f6Sopenharmony_ci#endif /* LWIP_6LOWPAN_IPHC */ 413195972f6Sopenharmony_ci 414195972f6Sopenharmony_ci /* Calculate remaining packet length */ 415195972f6Sopenharmony_ci remaining_len = p->tot_len; 416195972f6Sopenharmony_ci 417195972f6Sopenharmony_ci if (remaining_len > 0x7FF) { 418195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(netif, ifoutdiscards); 419195972f6Sopenharmony_ci /* datagram_size must fit into 11 bit */ 420195972f6Sopenharmony_ci pbuf_free(p_frag); 421195972f6Sopenharmony_ci return ERR_VAL; 422195972f6Sopenharmony_ci } 423195972f6Sopenharmony_ci 424195972f6Sopenharmony_ci /* Fragment, or 1 packet? */ 425195972f6Sopenharmony_ci max_data_len = LOWPAN6_MAX_PAYLOAD - ieee_header_len - lowpan6_header_len; 426195972f6Sopenharmony_ci if (remaining_len > max_data_len) { 427195972f6Sopenharmony_ci u16_t data_len; 428195972f6Sopenharmony_ci /* We must move the 6LowPAN header to make room for the FRAG header. */ 429195972f6Sopenharmony_ci memmove(&buffer[ieee_header_len + 4], &buffer[ieee_header_len], lowpan6_header_len); 430195972f6Sopenharmony_ci 431195972f6Sopenharmony_ci /* Now we need to fragment the packet. FRAG1 header first */ 432195972f6Sopenharmony_ci buffer[ieee_header_len] = 0xc0 | (((p->tot_len + hidden_header_len) >> 8) & 0x7); 433195972f6Sopenharmony_ci buffer[ieee_header_len + 1] = (p->tot_len + hidden_header_len) & 0xff; 434195972f6Sopenharmony_ci 435195972f6Sopenharmony_ci lowpan6_data.tx_datagram_tag++; 436195972f6Sopenharmony_ci buffer[ieee_header_len + 2] = (lowpan6_data.tx_datagram_tag >> 8) & 0xff; 437195972f6Sopenharmony_ci buffer[ieee_header_len + 3] = lowpan6_data.tx_datagram_tag & 0xff; 438195972f6Sopenharmony_ci 439195972f6Sopenharmony_ci /* Fragment follows. */ 440195972f6Sopenharmony_ci data_len = (max_data_len - 4) & 0xf8; 441195972f6Sopenharmony_ci frag_len = data_len + lowpan6_header_len; 442195972f6Sopenharmony_ci 443195972f6Sopenharmony_ci pbuf_copy_partial(p, buffer + ieee_header_len + lowpan6_header_len + 4, frag_len - lowpan6_header_len, 0); 444195972f6Sopenharmony_ci remaining_len -= frag_len - lowpan6_header_len; 445195972f6Sopenharmony_ci /* datagram offset holds the offset before compression */ 446195972f6Sopenharmony_ci datagram_offset = frag_len - lowpan6_header_len + hidden_header_len; 447195972f6Sopenharmony_ci LWIP_ASSERT("datagram offset must be a multiple of 8", (datagram_offset & 7) == 0); 448195972f6Sopenharmony_ci 449195972f6Sopenharmony_ci /* Calculate frame length */ 450195972f6Sopenharmony_ci p_frag->len = p_frag->tot_len = ieee_header_len + 4 + frag_len + 2; /* add 2 bytes for crc*/ 451195972f6Sopenharmony_ci 452195972f6Sopenharmony_ci /* 2 bytes CRC */ 453195972f6Sopenharmony_ci crc = LWIP_6LOWPAN_DO_CALC_CRC(p_frag->payload, p_frag->len - 2); 454195972f6Sopenharmony_ci pbuf_take_at(p_frag, &crc, 2, p_frag->len - 2); 455195972f6Sopenharmony_ci 456195972f6Sopenharmony_ci /* send the packet */ 457195972f6Sopenharmony_ci MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p_frag->tot_len); 458195972f6Sopenharmony_ci LWIP_DEBUGF(LWIP_LOWPAN6_DEBUG | LWIP_DBG_TRACE, ("lowpan6_send: sending packet %p\n", (void *)p)); 459195972f6Sopenharmony_ci err = netif->linkoutput(netif, p_frag); 460195972f6Sopenharmony_ci 461195972f6Sopenharmony_ci while ((remaining_len > 0) && (err == ERR_OK)) { 462195972f6Sopenharmony_ci struct ieee_802154_hdr *hdr = (struct ieee_802154_hdr *)buffer; 463195972f6Sopenharmony_ci /* new frame, new seq num for ACK */ 464195972f6Sopenharmony_ci hdr->sequence_number = lowpan6_data.tx_frame_seq_num++; 465195972f6Sopenharmony_ci 466195972f6Sopenharmony_ci buffer[ieee_header_len] |= 0x20; /* Change FRAG1 to FRAGN */ 467195972f6Sopenharmony_ci 468195972f6Sopenharmony_ci LWIP_ASSERT("datagram offset must be a multiple of 8", (datagram_offset & 7) == 0); 469195972f6Sopenharmony_ci buffer[ieee_header_len + 4] = (u8_t)(datagram_offset >> 3); /* datagram offset in FRAGN header (datagram_offset is max. 11 bit) */ 470195972f6Sopenharmony_ci 471195972f6Sopenharmony_ci frag_len = (127 - ieee_header_len - 5 - 2) & 0xf8; 472195972f6Sopenharmony_ci if (frag_len > remaining_len) { 473195972f6Sopenharmony_ci frag_len = remaining_len; 474195972f6Sopenharmony_ci } 475195972f6Sopenharmony_ci 476195972f6Sopenharmony_ci pbuf_copy_partial(p, buffer + ieee_header_len + 5, frag_len, p->tot_len - remaining_len); 477195972f6Sopenharmony_ci remaining_len -= frag_len; 478195972f6Sopenharmony_ci datagram_offset += frag_len; 479195972f6Sopenharmony_ci 480195972f6Sopenharmony_ci /* Calculate frame length */ 481195972f6Sopenharmony_ci p_frag->len = p_frag->tot_len = frag_len + 5 + ieee_header_len + 2; 482195972f6Sopenharmony_ci 483195972f6Sopenharmony_ci /* 2 bytes CRC */ 484195972f6Sopenharmony_ci crc = LWIP_6LOWPAN_DO_CALC_CRC(p_frag->payload, p_frag->len - 2); 485195972f6Sopenharmony_ci pbuf_take_at(p_frag, &crc, 2, p_frag->len - 2); 486195972f6Sopenharmony_ci 487195972f6Sopenharmony_ci /* send the packet */ 488195972f6Sopenharmony_ci MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p_frag->tot_len); 489195972f6Sopenharmony_ci LWIP_DEBUGF(LWIP_LOWPAN6_DEBUG | LWIP_DBG_TRACE, ("lowpan6_send: sending packet %p\n", (void *)p)); 490195972f6Sopenharmony_ci err = netif->linkoutput(netif, p_frag); 491195972f6Sopenharmony_ci } 492195972f6Sopenharmony_ci } else { 493195972f6Sopenharmony_ci /* It fits in one frame. */ 494195972f6Sopenharmony_ci frag_len = remaining_len; 495195972f6Sopenharmony_ci 496195972f6Sopenharmony_ci /* Copy IPv6 packet */ 497195972f6Sopenharmony_ci pbuf_copy_partial(p, buffer + ieee_header_len + lowpan6_header_len, frag_len, 0); 498195972f6Sopenharmony_ci remaining_len = 0; 499195972f6Sopenharmony_ci 500195972f6Sopenharmony_ci /* Calculate frame length */ 501195972f6Sopenharmony_ci p_frag->len = p_frag->tot_len = frag_len + lowpan6_header_len + ieee_header_len + 2; 502195972f6Sopenharmony_ci LWIP_ASSERT("", p_frag->len <= 127); 503195972f6Sopenharmony_ci 504195972f6Sopenharmony_ci /* 2 bytes CRC */ 505195972f6Sopenharmony_ci crc = LWIP_6LOWPAN_DO_CALC_CRC(p_frag->payload, p_frag->len - 2); 506195972f6Sopenharmony_ci pbuf_take_at(p_frag, &crc, 2, p_frag->len - 2); 507195972f6Sopenharmony_ci 508195972f6Sopenharmony_ci /* send the packet */ 509195972f6Sopenharmony_ci MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p_frag->tot_len); 510195972f6Sopenharmony_ci LWIP_DEBUGF(LWIP_LOWPAN6_DEBUG | LWIP_DBG_TRACE, ("lowpan6_send: sending packet %p\n", (void *)p)); 511195972f6Sopenharmony_ci err = netif->linkoutput(netif, p_frag); 512195972f6Sopenharmony_ci } 513195972f6Sopenharmony_ci 514195972f6Sopenharmony_ci pbuf_free(p_frag); 515195972f6Sopenharmony_ci 516195972f6Sopenharmony_ci return err; 517195972f6Sopenharmony_ci} 518195972f6Sopenharmony_ci 519195972f6Sopenharmony_ci/** 520195972f6Sopenharmony_ci * @ingroup sixlowpan 521195972f6Sopenharmony_ci * Set context 522195972f6Sopenharmony_ci */ 523195972f6Sopenharmony_cierr_t 524195972f6Sopenharmony_cilowpan6_set_context(u8_t idx, const ip6_addr_t *context) 525195972f6Sopenharmony_ci{ 526195972f6Sopenharmony_ci#if LWIP_6LOWPAN_NUM_CONTEXTS > 0 527195972f6Sopenharmony_ci if (idx >= LWIP_6LOWPAN_NUM_CONTEXTS) { 528195972f6Sopenharmony_ci return ERR_ARG; 529195972f6Sopenharmony_ci } 530195972f6Sopenharmony_ci 531195972f6Sopenharmony_ci IP6_ADDR_ZONECHECK(context); 532195972f6Sopenharmony_ci 533195972f6Sopenharmony_ci ip6_addr_set(&lowpan6_data.lowpan6_context[idx], context); 534195972f6Sopenharmony_ci 535195972f6Sopenharmony_ci return ERR_OK; 536195972f6Sopenharmony_ci#else 537195972f6Sopenharmony_ci LWIP_UNUSED_ARG(idx); 538195972f6Sopenharmony_ci LWIP_UNUSED_ARG(context); 539195972f6Sopenharmony_ci return ERR_ARG; 540195972f6Sopenharmony_ci#endif 541195972f6Sopenharmony_ci} 542195972f6Sopenharmony_ci 543195972f6Sopenharmony_ci#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS 544195972f6Sopenharmony_ci/** 545195972f6Sopenharmony_ci * @ingroup sixlowpan 546195972f6Sopenharmony_ci * Set short address 547195972f6Sopenharmony_ci */ 548195972f6Sopenharmony_cierr_t 549195972f6Sopenharmony_cilowpan6_set_short_addr(u8_t addr_high, u8_t addr_low) 550195972f6Sopenharmony_ci{ 551195972f6Sopenharmony_ci short_mac_addr.addr[0] = addr_high; 552195972f6Sopenharmony_ci short_mac_addr.addr[1] = addr_low; 553195972f6Sopenharmony_ci 554195972f6Sopenharmony_ci return ERR_OK; 555195972f6Sopenharmony_ci} 556195972f6Sopenharmony_ci#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ 557195972f6Sopenharmony_ci 558195972f6Sopenharmony_ci/* Create IEEE 802.15.4 address from netif address */ 559195972f6Sopenharmony_cistatic err_t 560195972f6Sopenharmony_cilowpan6_hwaddr_to_addr(struct netif *netif, struct lowpan6_link_addr *addr) 561195972f6Sopenharmony_ci{ 562195972f6Sopenharmony_ci addr->addr_len = 8; 563195972f6Sopenharmony_ci if (netif->hwaddr_len == 8) { 564195972f6Sopenharmony_ci LWIP_ERROR("NETIF_MAX_HWADDR_LEN >= 8 required", sizeof(netif->hwaddr) >= 8, return ERR_VAL;); 565195972f6Sopenharmony_ci SMEMCPY(addr->addr, netif->hwaddr, 8); 566195972f6Sopenharmony_ci } else if (netif->hwaddr_len == 6) { 567195972f6Sopenharmony_ci /* Copy from MAC-48 */ 568195972f6Sopenharmony_ci SMEMCPY(addr->addr, netif->hwaddr, 3); 569195972f6Sopenharmony_ci addr->addr[3] = addr->addr[4] = 0xff; 570195972f6Sopenharmony_ci SMEMCPY(&addr->addr[5], &netif->hwaddr[3], 3); 571195972f6Sopenharmony_ci } else { 572195972f6Sopenharmony_ci /* Invalid address length, don't know how to convert this */ 573195972f6Sopenharmony_ci return ERR_VAL; 574195972f6Sopenharmony_ci } 575195972f6Sopenharmony_ci return ERR_OK; 576195972f6Sopenharmony_ci} 577195972f6Sopenharmony_ci 578195972f6Sopenharmony_ci/** 579195972f6Sopenharmony_ci * @ingroup sixlowpan 580195972f6Sopenharmony_ci * Resolve and fill-in IEEE 802.15.4 address header for outgoing IPv6 packet. 581195972f6Sopenharmony_ci * 582195972f6Sopenharmony_ci * Perform Header Compression and fragment if necessary. 583195972f6Sopenharmony_ci * 584195972f6Sopenharmony_ci * @param netif The lwIP network interface which the IP packet will be sent on. 585195972f6Sopenharmony_ci * @param q The pbuf(s) containing the IP packet to be sent. 586195972f6Sopenharmony_ci * @param ip6addr The IP address of the packet destination. 587195972f6Sopenharmony_ci * 588195972f6Sopenharmony_ci * @return err_t 589195972f6Sopenharmony_ci */ 590195972f6Sopenharmony_cierr_t 591195972f6Sopenharmony_cilowpan6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) 592195972f6Sopenharmony_ci{ 593195972f6Sopenharmony_ci err_t result; 594195972f6Sopenharmony_ci const u8_t *hwaddr; 595195972f6Sopenharmony_ci struct lowpan6_link_addr src, dest; 596195972f6Sopenharmony_ci#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS 597195972f6Sopenharmony_ci ip6_addr_t ip6_src; 598195972f6Sopenharmony_ci struct ip6_hdr *ip6_hdr; 599195972f6Sopenharmony_ci#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ 600195972f6Sopenharmony_ci 601195972f6Sopenharmony_ci#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS 602195972f6Sopenharmony_ci /* Check if we can compress source address (use aligned copy) */ 603195972f6Sopenharmony_ci ip6_hdr = (struct ip6_hdr *)q->payload; 604195972f6Sopenharmony_ci ip6_addr_copy_from_packed(ip6_src, ip6_hdr->src); 605195972f6Sopenharmony_ci ip6_addr_assign_zone(&ip6_src, IP6_UNICAST, netif); 606195972f6Sopenharmony_ci if (lowpan6_get_address_mode(&ip6_src, &short_mac_addr) == 3) { 607195972f6Sopenharmony_ci src.addr_len = 2; 608195972f6Sopenharmony_ci src.addr[0] = short_mac_addr.addr[0]; 609195972f6Sopenharmony_ci src.addr[1] = short_mac_addr.addr[1]; 610195972f6Sopenharmony_ci } else 611195972f6Sopenharmony_ci#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ 612195972f6Sopenharmony_ci { 613195972f6Sopenharmony_ci result = lowpan6_hwaddr_to_addr(netif, &src); 614195972f6Sopenharmony_ci if (result != ERR_OK) { 615195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(netif, ifoutdiscards); 616195972f6Sopenharmony_ci return result; 617195972f6Sopenharmony_ci } 618195972f6Sopenharmony_ci } 619195972f6Sopenharmony_ci 620195972f6Sopenharmony_ci /* multicast destination IP address? */ 621195972f6Sopenharmony_ci if (ip6_addr_ismulticast(ip6addr)) { 622195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); 623195972f6Sopenharmony_ci /* We need to send to the broadcast address.*/ 624195972f6Sopenharmony_ci return lowpan6_frag(netif, q, &src, &ieee_802154_broadcast); 625195972f6Sopenharmony_ci } 626195972f6Sopenharmony_ci 627195972f6Sopenharmony_ci /* We have a unicast destination IP address */ 628195972f6Sopenharmony_ci /* @todo anycast? */ 629195972f6Sopenharmony_ci 630195972f6Sopenharmony_ci#if LWIP_6LOWPAN_INFER_SHORT_ADDRESS 631195972f6Sopenharmony_ci if (src.addr_len == 2) { 632195972f6Sopenharmony_ci /* If source address was compressable to short_mac_addr, and dest has same subnet and 633195972f6Sopenharmony_ci * is also compressable to 2-bytes, assume we can infer dest as a short address too. */ 634195972f6Sopenharmony_ci dest.addr_len = 2; 635195972f6Sopenharmony_ci dest.addr[0] = ((u8_t *)q->payload)[38]; 636195972f6Sopenharmony_ci dest.addr[1] = ((u8_t *)q->payload)[39]; 637195972f6Sopenharmony_ci if ((src.addr_len == 2) && (ip6_addr_netcmp_zoneless(&ip6_hdr->src, &ip6_hdr->dest)) && 638195972f6Sopenharmony_ci (lowpan6_get_address_mode(ip6addr, &dest) == 3)) { 639195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); 640195972f6Sopenharmony_ci return lowpan6_frag(netif, q, &src, &dest); 641195972f6Sopenharmony_ci } 642195972f6Sopenharmony_ci } 643195972f6Sopenharmony_ci#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */ 644195972f6Sopenharmony_ci 645195972f6Sopenharmony_ci /* Ask ND6 what to do with the packet. */ 646195972f6Sopenharmony_ci result = nd6_get_next_hop_addr_or_queue(netif, q, ip6addr, &hwaddr); 647195972f6Sopenharmony_ci if (result != ERR_OK) { 648195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(netif, ifoutdiscards); 649195972f6Sopenharmony_ci return result; 650195972f6Sopenharmony_ci } 651195972f6Sopenharmony_ci 652195972f6Sopenharmony_ci /* If no hardware address is returned, nd6 has queued the packet for later. */ 653195972f6Sopenharmony_ci if (hwaddr == NULL) { 654195972f6Sopenharmony_ci return ERR_OK; 655195972f6Sopenharmony_ci } 656195972f6Sopenharmony_ci 657195972f6Sopenharmony_ci /* Send out the packet using the returned hardware address. */ 658195972f6Sopenharmony_ci dest.addr_len = netif->hwaddr_len; 659195972f6Sopenharmony_ci /* XXX: Inferring the length of the source address from the destination address 660195972f6Sopenharmony_ci * is not correct for IEEE 802.15.4, but currently we don't get this information 661195972f6Sopenharmony_ci * from the neighbor cache */ 662195972f6Sopenharmony_ci SMEMCPY(dest.addr, hwaddr, netif->hwaddr_len); 663195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); 664195972f6Sopenharmony_ci return lowpan6_frag(netif, q, &src, &dest); 665195972f6Sopenharmony_ci} 666195972f6Sopenharmony_ci/** 667195972f6Sopenharmony_ci * @ingroup sixlowpan 668195972f6Sopenharmony_ci * NETIF input function: don't free the input pbuf when returning != ERR_OK! 669195972f6Sopenharmony_ci */ 670195972f6Sopenharmony_cierr_t 671195972f6Sopenharmony_cilowpan6_input(struct pbuf *p, struct netif *netif) 672195972f6Sopenharmony_ci{ 673195972f6Sopenharmony_ci u8_t *puc, b; 674195972f6Sopenharmony_ci s8_t i; 675195972f6Sopenharmony_ci struct lowpan6_link_addr src, dest; 676195972f6Sopenharmony_ci u16_t datagram_size = 0; 677195972f6Sopenharmony_ci u16_t datagram_offset, datagram_tag; 678195972f6Sopenharmony_ci struct lowpan6_reass_helper *lrh, *lrh_next, *lrh_prev = NULL; 679195972f6Sopenharmony_ci 680195972f6Sopenharmony_ci if (p == NULL) { 681195972f6Sopenharmony_ci return ERR_OK; 682195972f6Sopenharmony_ci } 683195972f6Sopenharmony_ci 684195972f6Sopenharmony_ci MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len); 685195972f6Sopenharmony_ci 686195972f6Sopenharmony_ci if (p->len != p->tot_len) { 687195972f6Sopenharmony_ci /* for now, this needs a pbuf in one piece */ 688195972f6Sopenharmony_ci goto lowpan6_input_discard; 689195972f6Sopenharmony_ci } 690195972f6Sopenharmony_ci 691195972f6Sopenharmony_ci if (lowpan6_parse_iee802154_header(p, &src, &dest) != ERR_OK) { 692195972f6Sopenharmony_ci goto lowpan6_input_discard; 693195972f6Sopenharmony_ci } 694195972f6Sopenharmony_ci 695195972f6Sopenharmony_ci /* Check dispatch. */ 696195972f6Sopenharmony_ci puc = (u8_t *)p->payload; 697195972f6Sopenharmony_ci 698195972f6Sopenharmony_ci b = *puc; 699195972f6Sopenharmony_ci if ((b & 0xf8) == 0xc0) { 700195972f6Sopenharmony_ci /* FRAG1 dispatch. add this packet to reassembly list. */ 701195972f6Sopenharmony_ci datagram_size = ((u16_t)(puc[0] & 0x07) << 8) | (u16_t)puc[1]; 702195972f6Sopenharmony_ci datagram_tag = ((u16_t)puc[2] << 8) | (u16_t)puc[3]; 703195972f6Sopenharmony_ci 704195972f6Sopenharmony_ci /* check for duplicate */ 705195972f6Sopenharmony_ci lrh = lowpan6_data.reass_list; 706195972f6Sopenharmony_ci while (lrh != NULL) { 707195972f6Sopenharmony_ci uint8_t discard = 0; 708195972f6Sopenharmony_ci lrh_next = lrh->next_packet; 709195972f6Sopenharmony_ci if ((lrh->sender_addr.addr_len == src.addr_len) && 710195972f6Sopenharmony_ci (memcmp(lrh->sender_addr.addr, src.addr, src.addr_len) == 0)) { 711195972f6Sopenharmony_ci /* address match with packet in reassembly. */ 712195972f6Sopenharmony_ci if ((datagram_tag == lrh->datagram_tag) && (datagram_size == lrh->datagram_size)) { 713195972f6Sopenharmony_ci /* duplicate fragment. */ 714195972f6Sopenharmony_ci goto lowpan6_input_discard; 715195972f6Sopenharmony_ci } else { 716195972f6Sopenharmony_ci /* We are receiving the start of a new datagram. Discard old one (incomplete). */ 717195972f6Sopenharmony_ci discard = 1; 718195972f6Sopenharmony_ci } 719195972f6Sopenharmony_ci } 720195972f6Sopenharmony_ci if (discard) { 721195972f6Sopenharmony_ci dequeue_datagram(lrh, lrh_prev); 722195972f6Sopenharmony_ci free_reass_datagram(lrh); 723195972f6Sopenharmony_ci } else { 724195972f6Sopenharmony_ci lrh_prev = lrh; 725195972f6Sopenharmony_ci } 726195972f6Sopenharmony_ci /* Check next datagram in queue. */ 727195972f6Sopenharmony_ci lrh = lrh_next; 728195972f6Sopenharmony_ci } 729195972f6Sopenharmony_ci 730195972f6Sopenharmony_ci pbuf_remove_header(p, 4); /* hide frag1 dispatch */ 731195972f6Sopenharmony_ci 732195972f6Sopenharmony_ci lrh = (struct lowpan6_reass_helper *) mem_malloc(sizeof(struct lowpan6_reass_helper)); 733195972f6Sopenharmony_ci if (lrh == NULL) { 734195972f6Sopenharmony_ci goto lowpan6_input_discard; 735195972f6Sopenharmony_ci } 736195972f6Sopenharmony_ci 737195972f6Sopenharmony_ci lrh->sender_addr.addr_len = src.addr_len; 738195972f6Sopenharmony_ci for (i = 0; i < src.addr_len; i++) { 739195972f6Sopenharmony_ci lrh->sender_addr.addr[i] = src.addr[i]; 740195972f6Sopenharmony_ci } 741195972f6Sopenharmony_ci lrh->datagram_size = datagram_size; 742195972f6Sopenharmony_ci lrh->datagram_tag = datagram_tag; 743195972f6Sopenharmony_ci lrh->frags = NULL; 744195972f6Sopenharmony_ci if (*(u8_t *)p->payload == 0x41) { 745195972f6Sopenharmony_ci /* This is a complete IPv6 packet, just skip dispatch byte. */ 746195972f6Sopenharmony_ci pbuf_remove_header(p, 1); /* hide dispatch byte. */ 747195972f6Sopenharmony_ci lrh->reass = p; 748195972f6Sopenharmony_ci } else if ((*(u8_t *)p->payload & 0xe0 ) == 0x60) { 749195972f6Sopenharmony_ci lrh->reass = lowpan6_decompress(p, datagram_size, LWIP_6LOWPAN_CONTEXTS(netif), &src, &dest); 750195972f6Sopenharmony_ci if (lrh->reass == NULL) { 751195972f6Sopenharmony_ci /* decompression failed */ 752195972f6Sopenharmony_ci mem_free(lrh); 753195972f6Sopenharmony_ci goto lowpan6_input_discard; 754195972f6Sopenharmony_ci } 755195972f6Sopenharmony_ci } 756195972f6Sopenharmony_ci /* TODO: handle the case where we already have FRAGN received */ 757195972f6Sopenharmony_ci lrh->next_packet = lowpan6_data.reass_list; 758195972f6Sopenharmony_ci lrh->timer = 2; 759195972f6Sopenharmony_ci lowpan6_data.reass_list = lrh; 760195972f6Sopenharmony_ci 761195972f6Sopenharmony_ci return ERR_OK; 762195972f6Sopenharmony_ci } else if ((b & 0xf8) == 0xe0) { 763195972f6Sopenharmony_ci /* FRAGN dispatch, find packet being reassembled. */ 764195972f6Sopenharmony_ci datagram_size = ((u16_t)(puc[0] & 0x07) << 8) | (u16_t)puc[1]; 765195972f6Sopenharmony_ci datagram_tag = ((u16_t)puc[2] << 8) | (u16_t)puc[3]; 766195972f6Sopenharmony_ci datagram_offset = (u16_t)puc[4] << 3; 767195972f6Sopenharmony_ci pbuf_remove_header(p, 4); /* hide frag1 dispatch but keep datagram offset for reassembly */ 768195972f6Sopenharmony_ci 769195972f6Sopenharmony_ci for (lrh = lowpan6_data.reass_list; lrh != NULL; lrh_prev = lrh, lrh = lrh->next_packet) { 770195972f6Sopenharmony_ci if ((lrh->sender_addr.addr_len == src.addr_len) && 771195972f6Sopenharmony_ci (memcmp(lrh->sender_addr.addr, src.addr, src.addr_len) == 0) && 772195972f6Sopenharmony_ci (datagram_tag == lrh->datagram_tag) && 773195972f6Sopenharmony_ci (datagram_size == lrh->datagram_size)) { 774195972f6Sopenharmony_ci break; 775195972f6Sopenharmony_ci } 776195972f6Sopenharmony_ci } 777195972f6Sopenharmony_ci if (lrh == NULL) { 778195972f6Sopenharmony_ci /* rogue fragment */ 779195972f6Sopenharmony_ci goto lowpan6_input_discard; 780195972f6Sopenharmony_ci } 781195972f6Sopenharmony_ci /* Insert new pbuf into list of fragments. Each fragment is a pbuf, 782195972f6Sopenharmony_ci this only works for unchained pbufs. */ 783195972f6Sopenharmony_ci LWIP_ASSERT("p->next == NULL", p->next == NULL); 784195972f6Sopenharmony_ci if (lrh->reass != NULL) { 785195972f6Sopenharmony_ci /* FRAG1 already received, check this offset against first len */ 786195972f6Sopenharmony_ci if (datagram_offset < lrh->reass->len) { 787195972f6Sopenharmony_ci /* fragment overlap, discard old fragments */ 788195972f6Sopenharmony_ci dequeue_datagram(lrh, lrh_prev); 789195972f6Sopenharmony_ci free_reass_datagram(lrh); 790195972f6Sopenharmony_ci goto lowpan6_input_discard; 791195972f6Sopenharmony_ci } 792195972f6Sopenharmony_ci } 793195972f6Sopenharmony_ci if (lrh->frags == NULL) { 794195972f6Sopenharmony_ci /* first FRAGN */ 795195972f6Sopenharmony_ci lrh->frags = p; 796195972f6Sopenharmony_ci } else { 797195972f6Sopenharmony_ci /* find the correct place to insert */ 798195972f6Sopenharmony_ci struct pbuf *q, *last; 799195972f6Sopenharmony_ci u16_t new_frag_len = p->len - 1; /* p->len includes datagram_offset byte */ 800195972f6Sopenharmony_ci for (q = lrh->frags, last = NULL; q != NULL; last = q, q = q->next) { 801195972f6Sopenharmony_ci u16_t q_datagram_offset = ((u8_t *)q->payload)[0] << 3; 802195972f6Sopenharmony_ci u16_t q_frag_len = q->len - 1; 803195972f6Sopenharmony_ci if (datagram_offset < q_datagram_offset) { 804195972f6Sopenharmony_ci if (datagram_offset + new_frag_len > q_datagram_offset) { 805195972f6Sopenharmony_ci /* overlap, discard old fragments */ 806195972f6Sopenharmony_ci dequeue_datagram(lrh, lrh_prev); 807195972f6Sopenharmony_ci free_reass_datagram(lrh); 808195972f6Sopenharmony_ci goto lowpan6_input_discard; 809195972f6Sopenharmony_ci } 810195972f6Sopenharmony_ci /* insert here */ 811195972f6Sopenharmony_ci break; 812195972f6Sopenharmony_ci } else if (datagram_offset == q_datagram_offset) { 813195972f6Sopenharmony_ci if (q_frag_len != new_frag_len) { 814195972f6Sopenharmony_ci /* fragment mismatch, discard old fragments */ 815195972f6Sopenharmony_ci dequeue_datagram(lrh, lrh_prev); 816195972f6Sopenharmony_ci free_reass_datagram(lrh); 817195972f6Sopenharmony_ci goto lowpan6_input_discard; 818195972f6Sopenharmony_ci } 819195972f6Sopenharmony_ci /* duplicate, ignore */ 820195972f6Sopenharmony_ci pbuf_free(p); 821195972f6Sopenharmony_ci return ERR_OK; 822195972f6Sopenharmony_ci } 823195972f6Sopenharmony_ci } 824195972f6Sopenharmony_ci /* insert fragment */ 825195972f6Sopenharmony_ci if (last == NULL) { 826195972f6Sopenharmony_ci lrh->frags = p; 827195972f6Sopenharmony_ci } else { 828195972f6Sopenharmony_ci last->next = p; 829195972f6Sopenharmony_ci p->next = q; 830195972f6Sopenharmony_ci } 831195972f6Sopenharmony_ci } 832195972f6Sopenharmony_ci /* check if all fragments were received */ 833195972f6Sopenharmony_ci if (lrh->reass) { 834195972f6Sopenharmony_ci u16_t offset = lrh->reass->len; 835195972f6Sopenharmony_ci struct pbuf *q; 836195972f6Sopenharmony_ci for (q = lrh->frags; q != NULL; q = q->next) { 837195972f6Sopenharmony_ci u16_t q_datagram_offset = ((u8_t *)q->payload)[0] << 3; 838195972f6Sopenharmony_ci if (q_datagram_offset != offset) { 839195972f6Sopenharmony_ci /* not complete, wait for more fragments */ 840195972f6Sopenharmony_ci return ERR_OK; 841195972f6Sopenharmony_ci } 842195972f6Sopenharmony_ci offset += q->len - 1; 843195972f6Sopenharmony_ci } 844195972f6Sopenharmony_ci if (offset == datagram_size) { 845195972f6Sopenharmony_ci /* all fragments received, combine pbufs */ 846195972f6Sopenharmony_ci u16_t datagram_left = datagram_size - lrh->reass->len; 847195972f6Sopenharmony_ci for (q = lrh->frags; q != NULL; q = q->next) { 848195972f6Sopenharmony_ci /* hide datagram_offset byte now */ 849195972f6Sopenharmony_ci pbuf_remove_header(q, 1); 850195972f6Sopenharmony_ci q->tot_len = datagram_left; 851195972f6Sopenharmony_ci datagram_left -= q->len; 852195972f6Sopenharmony_ci } 853195972f6Sopenharmony_ci LWIP_ASSERT("datagram_left == 0", datagram_left == 0); 854195972f6Sopenharmony_ci q = lrh->reass; 855195972f6Sopenharmony_ci q->tot_len = datagram_size; 856195972f6Sopenharmony_ci q->next = lrh->frags; 857195972f6Sopenharmony_ci lrh->frags = NULL; 858195972f6Sopenharmony_ci lrh->reass = NULL; 859195972f6Sopenharmony_ci dequeue_datagram(lrh, lrh_prev); 860195972f6Sopenharmony_ci mem_free(lrh); 861195972f6Sopenharmony_ci 862195972f6Sopenharmony_ci /* @todo: distinguish unicast/multicast */ 863195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(netif, ifinucastpkts); 864195972f6Sopenharmony_ci return ip6_input(q, netif); 865195972f6Sopenharmony_ci } 866195972f6Sopenharmony_ci } 867195972f6Sopenharmony_ci /* pbuf enqueued, waiting for more fragments */ 868195972f6Sopenharmony_ci return ERR_OK; 869195972f6Sopenharmony_ci } else { 870195972f6Sopenharmony_ci if (b == 0x41) { 871195972f6Sopenharmony_ci /* This is a complete IPv6 packet, just skip dispatch byte. */ 872195972f6Sopenharmony_ci pbuf_remove_header(p, 1); /* hide dispatch byte. */ 873195972f6Sopenharmony_ci } else if ((b & 0xe0 ) == 0x60) { 874195972f6Sopenharmony_ci /* IPv6 headers are compressed using IPHC. */ 875195972f6Sopenharmony_ci p = lowpan6_decompress(p, datagram_size, LWIP_6LOWPAN_CONTEXTS(netif), &src, &dest); 876195972f6Sopenharmony_ci if (p == NULL) { 877195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(netif, ifindiscards); 878195972f6Sopenharmony_ci return ERR_OK; 879195972f6Sopenharmony_ci } 880195972f6Sopenharmony_ci } else { 881195972f6Sopenharmony_ci goto lowpan6_input_discard; 882195972f6Sopenharmony_ci } 883195972f6Sopenharmony_ci 884195972f6Sopenharmony_ci /* @todo: distinguish unicast/multicast */ 885195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(netif, ifinucastpkts); 886195972f6Sopenharmony_ci 887195972f6Sopenharmony_ci return ip6_input(p, netif); 888195972f6Sopenharmony_ci } 889195972f6Sopenharmony_cilowpan6_input_discard: 890195972f6Sopenharmony_ci MIB2_STATS_NETIF_INC(netif, ifindiscards); 891195972f6Sopenharmony_ci pbuf_free(p); 892195972f6Sopenharmony_ci /* always return ERR_OK here to prevent the caller freeing the pbuf */ 893195972f6Sopenharmony_ci return ERR_OK; 894195972f6Sopenharmony_ci} 895195972f6Sopenharmony_ci 896195972f6Sopenharmony_ci/** 897195972f6Sopenharmony_ci * @ingroup sixlowpan 898195972f6Sopenharmony_ci */ 899195972f6Sopenharmony_cierr_t 900195972f6Sopenharmony_cilowpan6_if_init(struct netif *netif) 901195972f6Sopenharmony_ci{ 902195972f6Sopenharmony_ci netif->name[0] = 'L'; 903195972f6Sopenharmony_ci netif->name[1] = '6'; 904195972f6Sopenharmony_ci netif->output_ip6 = lowpan6_output; 905195972f6Sopenharmony_ci 906195972f6Sopenharmony_ci MIB2_INIT_NETIF(netif, snmp_ifType_other, 0); 907195972f6Sopenharmony_ci 908195972f6Sopenharmony_ci /* maximum transfer unit */ 909195972f6Sopenharmony_ci netif->mtu = IP6_MIN_MTU_LENGTH; 910195972f6Sopenharmony_ci 911195972f6Sopenharmony_ci /* broadcast capability */ 912195972f6Sopenharmony_ci netif->flags = NETIF_FLAG_BROADCAST /* | NETIF_FLAG_LOWPAN6 */; 913195972f6Sopenharmony_ci 914195972f6Sopenharmony_ci return ERR_OK; 915195972f6Sopenharmony_ci} 916195972f6Sopenharmony_ci 917195972f6Sopenharmony_ci/** 918195972f6Sopenharmony_ci * @ingroup sixlowpan 919195972f6Sopenharmony_ci * Set PAN ID 920195972f6Sopenharmony_ci */ 921195972f6Sopenharmony_cierr_t 922195972f6Sopenharmony_cilowpan6_set_pan_id(u16_t pan_id) 923195972f6Sopenharmony_ci{ 924195972f6Sopenharmony_ci lowpan6_data.ieee_802154_pan_id = pan_id; 925195972f6Sopenharmony_ci 926195972f6Sopenharmony_ci return ERR_OK; 927195972f6Sopenharmony_ci} 928195972f6Sopenharmony_ci 929195972f6Sopenharmony_ci#if !NO_SYS 930195972f6Sopenharmony_ci/** 931195972f6Sopenharmony_ci * @ingroup sixlowpan 932195972f6Sopenharmony_ci * Pass a received packet to tcpip_thread for input processing 933195972f6Sopenharmony_ci * 934195972f6Sopenharmony_ci * @param p the received packet, p->payload pointing to the 935195972f6Sopenharmony_ci * IEEE 802.15.4 header. 936195972f6Sopenharmony_ci * @param inp the network interface on which the packet was received 937195972f6Sopenharmony_ci */ 938195972f6Sopenharmony_cierr_t 939195972f6Sopenharmony_citcpip_6lowpan_input(struct pbuf *p, struct netif *inp) 940195972f6Sopenharmony_ci{ 941195972f6Sopenharmony_ci return tcpip_inpkt(p, inp, lowpan6_input); 942195972f6Sopenharmony_ci} 943195972f6Sopenharmony_ci#endif /* !NO_SYS */ 944195972f6Sopenharmony_ci 945195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */ 946