1195972f6Sopenharmony_ci/**
2195972f6Sopenharmony_ci * @file
3195972f6Sopenharmony_ci * 6LowPAN over BLE output for IPv6 (RFC7668).
4195972f6Sopenharmony_ci*/
5195972f6Sopenharmony_ci
6195972f6Sopenharmony_ci/*
7195972f6Sopenharmony_ci * Copyright (c) 2017 Benjamin Aigner
8195972f6Sopenharmony_ci * Copyright (c) 2015 Inico Technologies Ltd. , Author: Ivan Delamer <delamer@inicotech.com>
9195972f6Sopenharmony_ci *
10195972f6Sopenharmony_ci * All rights reserved.
11195972f6Sopenharmony_ci *
12195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification,
13195972f6Sopenharmony_ci * are permitted provided that the following conditions are met:
14195972f6Sopenharmony_ci *
15195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice,
16195972f6Sopenharmony_ci *    this list of conditions and the following disclaimer.
17195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice,
18195972f6Sopenharmony_ci *    this list of conditions and the following disclaimer in the documentation
19195972f6Sopenharmony_ci *    and/or other materials provided with the distribution.
20195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products
21195972f6Sopenharmony_ci *    derived from this software without specific prior written permission.
22195972f6Sopenharmony_ci *
23195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
24195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
26195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
28195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
31195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32195972f6Sopenharmony_ci * OF SUCH DAMAGE.
33195972f6Sopenharmony_ci *
34195972f6Sopenharmony_ci * Author: Benjamin Aigner <aignerb@technikum-wien.at>
35195972f6Sopenharmony_ci *
36195972f6Sopenharmony_ci * Based on the original 6lowpan implementation of lwIP ( @see 6lowpan.c)
37195972f6Sopenharmony_ci */
38195972f6Sopenharmony_ci
39195972f6Sopenharmony_ci
40195972f6Sopenharmony_ci/**
41195972f6Sopenharmony_ci * @defgroup rfc7668if 6LoWPAN over BLE (RFC7668)
42195972f6Sopenharmony_ci * @ingroup netifs
43195972f6Sopenharmony_ci * This file implements a RFC7668 implementation for 6LoWPAN over
44195972f6Sopenharmony_ci * Bluetooth Low Energy. The specification is very similar to 6LoWPAN,
45195972f6Sopenharmony_ci * so most of the code is re-used.
46195972f6Sopenharmony_ci * Compared to 6LoWPAN, much functionality is already implemented in
47195972f6Sopenharmony_ci * lower BLE layers (fragmenting, session management,...).
48195972f6Sopenharmony_ci *
49195972f6Sopenharmony_ci * Usage:
50195972f6Sopenharmony_ci * - add this netif
51195972f6Sopenharmony_ci *   - don't add IPv4 addresses (no IPv4 support in RFC7668), pass 'NULL','NULL','NULL'
52195972f6Sopenharmony_ci *   - use the BLE to EUI64 conversation util to create an IPv6 link-local address from the BLE MAC (@ref ble_addr_to_eui64)
53195972f6Sopenharmony_ci *   - input function: @ref rfc7668_input
54195972f6Sopenharmony_ci * - set the link output function, which transmits output data to an established L2CAP channel
55195972f6Sopenharmony_ci * - If data arrives (HCI event "L2CAP_DATA_PACKET"):
56195972f6Sopenharmony_ci *   - allocate a @ref PBUF_RAW buffer
57195972f6Sopenharmony_ci *   - let the pbuf struct point to the incoming data or copy it to the buffer
58195972f6Sopenharmony_ci *   - call netif->input
59195972f6Sopenharmony_ci *
60195972f6Sopenharmony_ci * @todo:
61195972f6Sopenharmony_ci * - further testing
62195972f6Sopenharmony_ci * - support compression contexts
63195972f6Sopenharmony_ci * - support multiple addresses
64195972f6Sopenharmony_ci * - support multicast
65195972f6Sopenharmony_ci * - support neighbor discovery
66195972f6Sopenharmony_ci */
67195972f6Sopenharmony_ci
68195972f6Sopenharmony_ci
69195972f6Sopenharmony_ci#include "netif/lowpan6_ble.h"
70195972f6Sopenharmony_ci
71195972f6Sopenharmony_ci#if LWIP_IPV6
72195972f6Sopenharmony_ci
73195972f6Sopenharmony_ci#include "lwip/ip.h"
74195972f6Sopenharmony_ci#include "lwip/pbuf.h"
75195972f6Sopenharmony_ci#include "lwip/ip_addr.h"
76195972f6Sopenharmony_ci#include "lwip/netif.h"
77195972f6Sopenharmony_ci#include "lwip/nd6.h"
78195972f6Sopenharmony_ci#include "lwip/mem.h"
79195972f6Sopenharmony_ci#include "lwip/udp.h"
80195972f6Sopenharmony_ci#include "lwip/tcpip.h"
81195972f6Sopenharmony_ci#include "lwip/snmp.h"
82195972f6Sopenharmony_ci
83195972f6Sopenharmony_ci#include <string.h>
84195972f6Sopenharmony_ci
85195972f6Sopenharmony_ci#if LWIP_6LOWPAN_NUM_CONTEXTS > 0
86195972f6Sopenharmony_ci/** context memory, containing IPv6 addresses */
87195972f6Sopenharmony_cistatic ip6_addr_t rfc7668_context[LWIP_6LOWPAN_NUM_CONTEXTS];
88195972f6Sopenharmony_ci#else
89195972f6Sopenharmony_ci#define rfc7668_context NULL
90195972f6Sopenharmony_ci#endif
91195972f6Sopenharmony_ci
92195972f6Sopenharmony_cistatic struct lowpan6_link_addr rfc7668_local_addr;
93195972f6Sopenharmony_cistatic struct lowpan6_link_addr rfc7668_peer_addr;
94195972f6Sopenharmony_ci
95195972f6Sopenharmony_ci/**
96195972f6Sopenharmony_ci * @ingroup rfc7668if
97195972f6Sopenharmony_ci *  convert BT address to EUI64 addr
98195972f6Sopenharmony_ci *
99195972f6Sopenharmony_ci * This method converts a Bluetooth MAC address to an EUI64 address,
100195972f6Sopenharmony_ci * which is used within IPv6 communication
101195972f6Sopenharmony_ci *
102195972f6Sopenharmony_ci * @param dst IPv6 destination space
103195972f6Sopenharmony_ci * @param src BLE MAC address source
104195972f6Sopenharmony_ci * @param public_addr If the LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS
105195972f6Sopenharmony_ci * option is set, bit 0x02 will be set if param=0 (no public addr); cleared otherwise
106195972f6Sopenharmony_ci *
107195972f6Sopenharmony_ci * @see LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS
108195972f6Sopenharmony_ci */
109195972f6Sopenharmony_civoid
110195972f6Sopenharmony_cible_addr_to_eui64(uint8_t *dst, const uint8_t *src, int public_addr)
111195972f6Sopenharmony_ci{
112195972f6Sopenharmony_ci  /* according to RFC7668 ch 3.2.2. */
113195972f6Sopenharmony_ci  memcpy(dst, src, 3);
114195972f6Sopenharmony_ci  dst[3] = 0xFF;
115195972f6Sopenharmony_ci  dst[4] = 0xFE;
116195972f6Sopenharmony_ci  memcpy(&dst[5], &src[3], 3);
117195972f6Sopenharmony_ci#if LWIP_RFC7668_LINUX_WORKAROUND_PUBLIC_ADDRESS
118195972f6Sopenharmony_ci  if(public_addr) {
119195972f6Sopenharmony_ci    dst[0] &= ~0x02;
120195972f6Sopenharmony_ci  } else {
121195972f6Sopenharmony_ci    dst[0] |= 0x02;
122195972f6Sopenharmony_ci  }
123195972f6Sopenharmony_ci#else
124195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(public_addr);
125195972f6Sopenharmony_ci#endif
126195972f6Sopenharmony_ci}
127195972f6Sopenharmony_ci
128195972f6Sopenharmony_ci/**
129195972f6Sopenharmony_ci * @ingroup rfc7668if
130195972f6Sopenharmony_ci *  convert EUI64 address to Bluetooth MAC addr
131195972f6Sopenharmony_ci *
132195972f6Sopenharmony_ci * This method converts an EUI64 address to a Bluetooth MAC address,
133195972f6Sopenharmony_ci *
134195972f6Sopenharmony_ci * @param dst BLE MAC address destination
135195972f6Sopenharmony_ci * @param src IPv6 source
136195972f6Sopenharmony_ci *
137195972f6Sopenharmony_ci */
138195972f6Sopenharmony_civoid
139195972f6Sopenharmony_cieui64_to_ble_addr(uint8_t *dst, const uint8_t *src)
140195972f6Sopenharmony_ci{
141195972f6Sopenharmony_ci  /* according to RFC7668 ch 3.2.2. */
142195972f6Sopenharmony_ci  memcpy(dst,src,3);
143195972f6Sopenharmony_ci  memcpy(&dst[3],&src[5],3);
144195972f6Sopenharmony_ci}
145195972f6Sopenharmony_ci
146195972f6Sopenharmony_ci/** Set an address used for stateful compression.
147195972f6Sopenharmony_ci * This expects an address of 6 or 8 bytes.
148195972f6Sopenharmony_ci */
149195972f6Sopenharmony_cistatic err_t
150195972f6Sopenharmony_cirfc7668_set_addr(struct lowpan6_link_addr *addr, const u8_t *in_addr, size_t in_addr_len, int is_mac_48, int is_public_addr)
151195972f6Sopenharmony_ci{
152195972f6Sopenharmony_ci  if ((in_addr == NULL) || (addr == NULL)) {
153195972f6Sopenharmony_ci    return ERR_VAL;
154195972f6Sopenharmony_ci  }
155195972f6Sopenharmony_ci  if (is_mac_48) {
156195972f6Sopenharmony_ci    if (in_addr_len != 6) {
157195972f6Sopenharmony_ci      return ERR_VAL;
158195972f6Sopenharmony_ci    }
159195972f6Sopenharmony_ci    addr->addr_len = 8;
160195972f6Sopenharmony_ci    ble_addr_to_eui64(addr->addr, in_addr, is_public_addr);
161195972f6Sopenharmony_ci  } else {
162195972f6Sopenharmony_ci    if (in_addr_len != 8) {
163195972f6Sopenharmony_ci      return ERR_VAL;
164195972f6Sopenharmony_ci    }
165195972f6Sopenharmony_ci    addr->addr_len = 8;
166195972f6Sopenharmony_ci    memcpy(addr->addr, in_addr, 8);
167195972f6Sopenharmony_ci  }
168195972f6Sopenharmony_ci  return ERR_OK;
169195972f6Sopenharmony_ci}
170195972f6Sopenharmony_ci
171195972f6Sopenharmony_ci
172195972f6Sopenharmony_ci/** Set the local address used for stateful compression.
173195972f6Sopenharmony_ci * This expects an address of 8 bytes.
174195972f6Sopenharmony_ci */
175195972f6Sopenharmony_cierr_t
176195972f6Sopenharmony_cirfc7668_set_local_addr_eui64(struct netif *netif, const u8_t *local_addr, size_t local_addr_len)
177195972f6Sopenharmony_ci{
178195972f6Sopenharmony_ci  /* netif not used for now, the address is stored globally... */
179195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(netif);
180195972f6Sopenharmony_ci  return rfc7668_set_addr(&rfc7668_local_addr, local_addr, local_addr_len, 0, 0);
181195972f6Sopenharmony_ci}
182195972f6Sopenharmony_ci
183195972f6Sopenharmony_ci/** Set the local address used for stateful compression.
184195972f6Sopenharmony_ci * This expects an address of 6 bytes.
185195972f6Sopenharmony_ci */
186195972f6Sopenharmony_cierr_t
187195972f6Sopenharmony_cirfc7668_set_local_addr_mac48(struct netif *netif, const u8_t *local_addr, size_t local_addr_len, int is_public_addr)
188195972f6Sopenharmony_ci{
189195972f6Sopenharmony_ci  /* netif not used for now, the address is stored globally... */
190195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(netif);
191195972f6Sopenharmony_ci  return rfc7668_set_addr(&rfc7668_local_addr, local_addr, local_addr_len, 1, is_public_addr);
192195972f6Sopenharmony_ci}
193195972f6Sopenharmony_ci
194195972f6Sopenharmony_ci/** Set the peer address used for stateful compression.
195195972f6Sopenharmony_ci * This expects an address of 8 bytes.
196195972f6Sopenharmony_ci */
197195972f6Sopenharmony_cierr_t
198195972f6Sopenharmony_cirfc7668_set_peer_addr_eui64(struct netif *netif, const u8_t *peer_addr, size_t peer_addr_len)
199195972f6Sopenharmony_ci{
200195972f6Sopenharmony_ci  /* netif not used for now, the address is stored globally... */
201195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(netif);
202195972f6Sopenharmony_ci  return rfc7668_set_addr(&rfc7668_peer_addr, peer_addr, peer_addr_len, 0, 0);
203195972f6Sopenharmony_ci}
204195972f6Sopenharmony_ci
205195972f6Sopenharmony_ci/** Set the peer address used for stateful compression.
206195972f6Sopenharmony_ci * This expects an address of 6 bytes.
207195972f6Sopenharmony_ci */
208195972f6Sopenharmony_cierr_t
209195972f6Sopenharmony_cirfc7668_set_peer_addr_mac48(struct netif *netif, const u8_t *peer_addr, size_t peer_addr_len, int is_public_addr)
210195972f6Sopenharmony_ci{
211195972f6Sopenharmony_ci  /* netif not used for now, the address is stored globally... */
212195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(netif);
213195972f6Sopenharmony_ci  return rfc7668_set_addr(&rfc7668_peer_addr, peer_addr, peer_addr_len, 1, is_public_addr);
214195972f6Sopenharmony_ci}
215195972f6Sopenharmony_ci
216195972f6Sopenharmony_ci/** Encapsulate IPv6 frames for BLE transmission
217195972f6Sopenharmony_ci *
218195972f6Sopenharmony_ci * This method implements the IPv6 header compression:
219195972f6Sopenharmony_ci *  *) According to RFC6282
220195972f6Sopenharmony_ci *  *) See Figure 2, contains base format of bit positions
221195972f6Sopenharmony_ci *  *) Fragmentation not necessary (done at L2CAP layer of BLE)
222195972f6Sopenharmony_ci * @note Currently the pbuf allocation uses 256 bytes. If longer packets are used (possible due to MTU=1480Bytes), increase it here!
223195972f6Sopenharmony_ci *
224195972f6Sopenharmony_ci * @param p Pbuf struct, containing the payload data
225195972f6Sopenharmony_ci * @param netif Output network interface. Should be of RFC7668 type
226195972f6Sopenharmony_ci *
227195972f6Sopenharmony_ci * @return Same as netif->output.
228195972f6Sopenharmony_ci */
229195972f6Sopenharmony_cistatic err_t
230195972f6Sopenharmony_cirfc7668_compress(struct netif *netif, struct pbuf *p)
231195972f6Sopenharmony_ci{
232195972f6Sopenharmony_ci  struct pbuf *p_frag;
233195972f6Sopenharmony_ci  u16_t remaining_len;
234195972f6Sopenharmony_ci  u8_t *buffer;
235195972f6Sopenharmony_ci  u8_t lowpan6_header_len;
236195972f6Sopenharmony_ci  u8_t hidden_header_len;
237195972f6Sopenharmony_ci  err_t err;
238195972f6Sopenharmony_ci
239195972f6Sopenharmony_ci  LWIP_ASSERT("lowpan6_frag: netif->linkoutput not set", netif->linkoutput != NULL);
240195972f6Sopenharmony_ci
241195972f6Sopenharmony_ci#if LWIP_6LOWPAN_IPHC
242195972f6Sopenharmony_ci
243195972f6Sopenharmony_ci  /* We'll use a dedicated pbuf for building BLE fragments.
244195972f6Sopenharmony_ci   * We'll over-allocate it by the bytes saved for header compression.
245195972f6Sopenharmony_ci   */
246195972f6Sopenharmony_ci  p_frag = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
247195972f6Sopenharmony_ci  if (p_frag == NULL) {
248195972f6Sopenharmony_ci    MIB2_STATS_NETIF_INC(netif, ifoutdiscards);
249195972f6Sopenharmony_ci    return ERR_MEM;
250195972f6Sopenharmony_ci  }
251195972f6Sopenharmony_ci  LWIP_ASSERT("this needs a pbuf in one piece", p_frag->len == p_frag->tot_len);
252195972f6Sopenharmony_ci
253195972f6Sopenharmony_ci  /* Write IP6 header (with IPHC). */
254195972f6Sopenharmony_ci  buffer = (u8_t*)p_frag->payload;
255195972f6Sopenharmony_ci
256195972f6Sopenharmony_ci  err = lowpan6_compress_headers(netif, (u8_t *)p->payload, p->len, buffer, p_frag->len,
257195972f6Sopenharmony_ci    &lowpan6_header_len, &hidden_header_len, rfc7668_context, &rfc7668_local_addr, &rfc7668_peer_addr);
258195972f6Sopenharmony_ci  if (err != ERR_OK) {
259195972f6Sopenharmony_ci    MIB2_STATS_NETIF_INC(netif, ifoutdiscards);
260195972f6Sopenharmony_ci    pbuf_free(p_frag);
261195972f6Sopenharmony_ci    return err;
262195972f6Sopenharmony_ci  }
263195972f6Sopenharmony_ci  pbuf_remove_header(p, hidden_header_len);
264195972f6Sopenharmony_ci
265195972f6Sopenharmony_ci  /* Calculate remaining packet length */
266195972f6Sopenharmony_ci  remaining_len = p->tot_len;
267195972f6Sopenharmony_ci
268195972f6Sopenharmony_ci  /* Copy IPv6 packet */
269195972f6Sopenharmony_ci  pbuf_copy_partial(p, buffer + lowpan6_header_len, remaining_len, 0);
270195972f6Sopenharmony_ci
271195972f6Sopenharmony_ci  /* Calculate frame length */
272195972f6Sopenharmony_ci  p_frag->len = p_frag->tot_len = remaining_len + lowpan6_header_len;
273195972f6Sopenharmony_ci
274195972f6Sopenharmony_ci  /* send the packet */
275195972f6Sopenharmony_ci  MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p_frag->tot_len);
276195972f6Sopenharmony_ci  LWIP_DEBUGF(LWIP_LOWPAN6_DEBUG|LWIP_DBG_TRACE, ("rfc7668_output: sending packet %p\n", (void *)p));
277195972f6Sopenharmony_ci  err = netif->linkoutput(netif, p_frag);
278195972f6Sopenharmony_ci
279195972f6Sopenharmony_ci  pbuf_free(p_frag);
280195972f6Sopenharmony_ci
281195972f6Sopenharmony_ci  return err;
282195972f6Sopenharmony_ci#else /* LWIP_6LOWPAN_IPHC */
283195972f6Sopenharmony_ci  /* 6LoWPAN over BLE requires IPHC! */
284195972f6Sopenharmony_ci  return ERR_IF;
285195972f6Sopenharmony_ci#endif/* LWIP_6LOWPAN_IPHC */
286195972f6Sopenharmony_ci}
287195972f6Sopenharmony_ci
288195972f6Sopenharmony_ci/**
289195972f6Sopenharmony_ci * @ingroup rfc7668if
290195972f6Sopenharmony_ci * Set context id IPv6 address
291195972f6Sopenharmony_ci *
292195972f6Sopenharmony_ci * Store one IPv6 address to a given context id.
293195972f6Sopenharmony_ci *
294195972f6Sopenharmony_ci * @param idx Context id
295195972f6Sopenharmony_ci * @param context IPv6 addr for this context
296195972f6Sopenharmony_ci *
297195972f6Sopenharmony_ci * @return ERR_OK (if everything is fine), ERR_ARG (if the context id is out of range), ERR_VAL (if contexts disabled)
298195972f6Sopenharmony_ci */
299195972f6Sopenharmony_cierr_t
300195972f6Sopenharmony_cirfc7668_set_context(u8_t idx, const ip6_addr_t *context)
301195972f6Sopenharmony_ci{
302195972f6Sopenharmony_ci#if LWIP_6LOWPAN_NUM_CONTEXTS > 0
303195972f6Sopenharmony_ci  /* check if the ID is possible */
304195972f6Sopenharmony_ci  if (idx >= LWIP_6LOWPAN_NUM_CONTEXTS) {
305195972f6Sopenharmony_ci    return ERR_ARG;
306195972f6Sopenharmony_ci  }
307195972f6Sopenharmony_ci  /* copy IPv6 address to context storage */
308195972f6Sopenharmony_ci  ip6_addr_set(&rfc7668_context[idx], context);
309195972f6Sopenharmony_ci  return ERR_OK;
310195972f6Sopenharmony_ci#else
311195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(idx);
312195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(context);
313195972f6Sopenharmony_ci  return ERR_VAL;
314195972f6Sopenharmony_ci#endif
315195972f6Sopenharmony_ci}
316195972f6Sopenharmony_ci
317195972f6Sopenharmony_ci/**
318195972f6Sopenharmony_ci * @ingroup rfc7668if
319195972f6Sopenharmony_ci * Compress outgoing IPv6 packet and pass it on to netif->linkoutput
320195972f6Sopenharmony_ci *
321195972f6Sopenharmony_ci * @param netif The lwIP network interface which the IP packet will be sent on.
322195972f6Sopenharmony_ci * @param q The pbuf(s) containing the IP packet to be sent.
323195972f6Sopenharmony_ci * @param ip6addr The IP address of the packet destination.
324195972f6Sopenharmony_ci *
325195972f6Sopenharmony_ci * @return See rfc7668_compress
326195972f6Sopenharmony_ci */
327195972f6Sopenharmony_cierr_t
328195972f6Sopenharmony_cirfc7668_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr)
329195972f6Sopenharmony_ci{
330195972f6Sopenharmony_ci  /* dst ip6addr is not used here, we only have one peer */
331195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(ip6addr);
332195972f6Sopenharmony_ci
333195972f6Sopenharmony_ci  return rfc7668_compress(netif, q);
334195972f6Sopenharmony_ci}
335195972f6Sopenharmony_ci
336195972f6Sopenharmony_ci/**
337195972f6Sopenharmony_ci * @ingroup rfc7668if
338195972f6Sopenharmony_ci * Process a received raw payload from an L2CAP channel
339195972f6Sopenharmony_ci *
340195972f6Sopenharmony_ci * @param p the received packet, p->payload pointing to the
341195972f6Sopenharmony_ci *        IPv6 header (maybe compressed)
342195972f6Sopenharmony_ci * @param netif the network interface on which the packet was received
343195972f6Sopenharmony_ci *
344195972f6Sopenharmony_ci * @return ERR_OK if everything was fine
345195972f6Sopenharmony_ci */
346195972f6Sopenharmony_cierr_t
347195972f6Sopenharmony_cirfc7668_input(struct pbuf * p, struct netif *netif)
348195972f6Sopenharmony_ci{
349195972f6Sopenharmony_ci  u8_t * puc;
350195972f6Sopenharmony_ci
351195972f6Sopenharmony_ci  MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
352195972f6Sopenharmony_ci
353195972f6Sopenharmony_ci  /* Load first header byte */
354195972f6Sopenharmony_ci  puc = (u8_t*)p->payload;
355195972f6Sopenharmony_ci
356195972f6Sopenharmony_ci  /* no IP header compression */
357195972f6Sopenharmony_ci  if (*puc == 0x41) {
358195972f6Sopenharmony_ci    LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Completed packet, removing dispatch: 0x%2x \n", *puc));
359195972f6Sopenharmony_ci    /* This is a complete IPv6 packet, just skip header byte. */
360195972f6Sopenharmony_ci    pbuf_remove_header(p, 1);
361195972f6Sopenharmony_ci  /* IPHC header compression */
362195972f6Sopenharmony_ci  } else if ((*puc & 0xe0 )== 0x60) {
363195972f6Sopenharmony_ci    LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Completed packet, decompress dispatch: 0x%2x \n", *puc));
364195972f6Sopenharmony_ci    /* IPv6 headers are compressed using IPHC. */
365195972f6Sopenharmony_ci    p = lowpan6_decompress(p, 0, rfc7668_context, &rfc7668_peer_addr, &rfc7668_local_addr);
366195972f6Sopenharmony_ci    /* if no pbuf is returned, handle as discarded packet */
367195972f6Sopenharmony_ci    if (p == NULL) {
368195972f6Sopenharmony_ci      MIB2_STATS_NETIF_INC(netif, ifindiscards);
369195972f6Sopenharmony_ci      return ERR_OK;
370195972f6Sopenharmony_ci    }
371195972f6Sopenharmony_ci  /* invalid header byte, discard */
372195972f6Sopenharmony_ci  } else {
373195972f6Sopenharmony_ci    LWIP_DEBUGF(LWIP_LOWPAN6_DECOMPRESSION_DEBUG, ("Completed packet, discarding: 0x%2x \n", *puc));
374195972f6Sopenharmony_ci    MIB2_STATS_NETIF_INC(netif, ifindiscards);
375195972f6Sopenharmony_ci    pbuf_free(p);
376195972f6Sopenharmony_ci    return ERR_OK;
377195972f6Sopenharmony_ci  }
378195972f6Sopenharmony_ci  /* @todo: distinguish unicast/multicast */
379195972f6Sopenharmony_ci  MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
380195972f6Sopenharmony_ci
381195972f6Sopenharmony_ci#if LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG
382195972f6Sopenharmony_ci  {
383195972f6Sopenharmony_ci    u16_t i;
384195972f6Sopenharmony_ci    LWIP_DEBUGF(LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG, ("IPv6 payload:\n"));
385195972f6Sopenharmony_ci    for (i = 0; i < p->len; i++) {
386195972f6Sopenharmony_ci      if ((i%4)==0) {
387195972f6Sopenharmony_ci        LWIP_DEBUGF(LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG, ("\n"));
388195972f6Sopenharmony_ci      }
389195972f6Sopenharmony_ci      LWIP_DEBUGF(LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG, ("%2X ", *((uint8_t *)p->payload+i)));
390195972f6Sopenharmony_ci    }
391195972f6Sopenharmony_ci    LWIP_DEBUGF(LWIP_RFC7668_IP_UNCOMPRESSED_DEBUG, ("\np->len: %d\n", p->len));
392195972f6Sopenharmony_ci  }
393195972f6Sopenharmony_ci#endif
394195972f6Sopenharmony_ci  /* pass data to ip6_input */
395195972f6Sopenharmony_ci  return ip6_input(p, netif);
396195972f6Sopenharmony_ci}
397195972f6Sopenharmony_ci
398195972f6Sopenharmony_ci/**
399195972f6Sopenharmony_ci * @ingroup rfc7668if
400195972f6Sopenharmony_ci * Initialize the netif
401195972f6Sopenharmony_ci *
402195972f6Sopenharmony_ci * No flags are used (broadcast not possible, not ethernet, ...)
403195972f6Sopenharmony_ci * The shortname for this netif is "BT"
404195972f6Sopenharmony_ci *
405195972f6Sopenharmony_ci * @param netif the network interface to be initialized as RFC7668 netif
406195972f6Sopenharmony_ci *
407195972f6Sopenharmony_ci * @return ERR_OK if everything went fine
408195972f6Sopenharmony_ci */
409195972f6Sopenharmony_cierr_t
410195972f6Sopenharmony_cirfc7668_if_init(struct netif *netif)
411195972f6Sopenharmony_ci{
412195972f6Sopenharmony_ci  netif->name[0] = 'b';
413195972f6Sopenharmony_ci  netif->name[1] = 't';
414195972f6Sopenharmony_ci  /* local function as IPv6 output */
415195972f6Sopenharmony_ci  netif->output_ip6 = rfc7668_output;
416195972f6Sopenharmony_ci
417195972f6Sopenharmony_ci  MIB2_INIT_NETIF(netif, snmp_ifType_other, 0);
418195972f6Sopenharmony_ci
419195972f6Sopenharmony_ci  /* maximum transfer unit, set according to RFC7668 ch2.4 */
420195972f6Sopenharmony_ci  netif->mtu = IP6_MIN_MTU_LENGTH;
421195972f6Sopenharmony_ci
422195972f6Sopenharmony_ci  /* no flags set (no broadcast, ethernet,...)*/
423195972f6Sopenharmony_ci  netif->flags = 0;
424195972f6Sopenharmony_ci
425195972f6Sopenharmony_ci  /* everything fine */
426195972f6Sopenharmony_ci  return ERR_OK;
427195972f6Sopenharmony_ci}
428195972f6Sopenharmony_ci
429195972f6Sopenharmony_ci#if !NO_SYS
430195972f6Sopenharmony_ci/**
431195972f6Sopenharmony_ci * Pass a received packet to tcpip_thread for input processing
432195972f6Sopenharmony_ci *
433195972f6Sopenharmony_ci * @param p the received packet, p->payload pointing to the
434195972f6Sopenharmony_ci *          IEEE 802.15.4 header.
435195972f6Sopenharmony_ci * @param inp the network interface on which the packet was received
436195972f6Sopenharmony_ci *
437195972f6Sopenharmony_ci * @return see @ref tcpip_inpkt, same return values
438195972f6Sopenharmony_ci */
439195972f6Sopenharmony_cierr_t
440195972f6Sopenharmony_citcpip_rfc7668_input(struct pbuf *p, struct netif *inp)
441195972f6Sopenharmony_ci{
442195972f6Sopenharmony_ci  /* send data to upper layer, return the result */
443195972f6Sopenharmony_ci  return tcpip_inpkt(p, inp, rfc7668_input);
444195972f6Sopenharmony_ci}
445195972f6Sopenharmony_ci#endif /* !NO_SYS */
446195972f6Sopenharmony_ci
447195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */
448