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