1*97dc5e69SMatthias Ringwald /**
2*97dc5e69SMatthias Ringwald * @file
3*97dc5e69SMatthias Ringwald *
4*97dc5e69SMatthias Ringwald * @defgroup zepif ZEP - ZigBee Encapsulation Protocol
5*97dc5e69SMatthias Ringwald * @ingroup netifs
6*97dc5e69SMatthias Ringwald * A netif implementing the ZigBee Encapsulation Protocol (ZEP).
7*97dc5e69SMatthias Ringwald * This is used to tunnel 6LowPAN over UDP.
8*97dc5e69SMatthias Ringwald *
9*97dc5e69SMatthias Ringwald * Usage (there must be a default netif before!):
10*97dc5e69SMatthias Ringwald * @code{.c}
11*97dc5e69SMatthias Ringwald * netif_add(&zep_netif, NULL, NULL, NULL, NULL, zepif_init, tcpip_6lowpan_input);
12*97dc5e69SMatthias Ringwald * netif_create_ip6_linklocal_address(&zep_netif, 1);
13*97dc5e69SMatthias Ringwald * netif_set_up(&zep_netif);
14*97dc5e69SMatthias Ringwald * netif_set_link_up(&zep_netif);
15*97dc5e69SMatthias Ringwald * @endcode
16*97dc5e69SMatthias Ringwald */
17*97dc5e69SMatthias Ringwald
18*97dc5e69SMatthias Ringwald /*
19*97dc5e69SMatthias Ringwald * Copyright (c) 2018 Simon Goldschmidt
20*97dc5e69SMatthias Ringwald * All rights reserved.
21*97dc5e69SMatthias Ringwald *
22*97dc5e69SMatthias Ringwald * Redistribution and use in source and binary forms, with or without modification,
23*97dc5e69SMatthias Ringwald * are permitted provided that the following conditions are met:
24*97dc5e69SMatthias Ringwald *
25*97dc5e69SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright notice,
26*97dc5e69SMatthias Ringwald * this list of conditions and the following disclaimer.
27*97dc5e69SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright notice,
28*97dc5e69SMatthias Ringwald * this list of conditions and the following disclaimer in the documentation
29*97dc5e69SMatthias Ringwald * and/or other materials provided with the distribution.
30*97dc5e69SMatthias Ringwald * 3. The name of the author may not be used to endorse or promote products
31*97dc5e69SMatthias Ringwald * derived from this software without specific prior written permission.
32*97dc5e69SMatthias Ringwald *
33*97dc5e69SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
34*97dc5e69SMatthias Ringwald * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
35*97dc5e69SMatthias Ringwald * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
36*97dc5e69SMatthias Ringwald * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
37*97dc5e69SMatthias Ringwald * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
38*97dc5e69SMatthias Ringwald * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39*97dc5e69SMatthias Ringwald * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40*97dc5e69SMatthias Ringwald * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41*97dc5e69SMatthias Ringwald * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
42*97dc5e69SMatthias Ringwald * OF SUCH DAMAGE.
43*97dc5e69SMatthias Ringwald *
44*97dc5e69SMatthias Ringwald * This file is part of the lwIP TCP/IP stack.
45*97dc5e69SMatthias Ringwald *
46*97dc5e69SMatthias Ringwald * Author: Simon Goldschmidt <[email protected]>
47*97dc5e69SMatthias Ringwald *
48*97dc5e69SMatthias Ringwald */
49*97dc5e69SMatthias Ringwald
50*97dc5e69SMatthias Ringwald #include "netif/zepif.h"
51*97dc5e69SMatthias Ringwald
52*97dc5e69SMatthias Ringwald #if LWIP_IPV6 && LWIP_UDP
53*97dc5e69SMatthias Ringwald
54*97dc5e69SMatthias Ringwald #include "netif/lowpan6.h"
55*97dc5e69SMatthias Ringwald #include "lwip/udp.h"
56*97dc5e69SMatthias Ringwald #include "lwip/timeouts.h"
57*97dc5e69SMatthias Ringwald #include <string.h>
58*97dc5e69SMatthias Ringwald
59*97dc5e69SMatthias Ringwald /** Define this to 1 to loop back TX packets for testing */
60*97dc5e69SMatthias Ringwald #ifndef ZEPIF_LOOPBACK
61*97dc5e69SMatthias Ringwald #define ZEPIF_LOOPBACK 0
62*97dc5e69SMatthias Ringwald #endif
63*97dc5e69SMatthias Ringwald
64*97dc5e69SMatthias Ringwald #define ZEP_MAX_DATA_LEN 127
65*97dc5e69SMatthias Ringwald
66*97dc5e69SMatthias Ringwald #ifdef PACK_STRUCT_USE_INCLUDES
67*97dc5e69SMatthias Ringwald # include "arch/bpstruct.h"
68*97dc5e69SMatthias Ringwald #endif
69*97dc5e69SMatthias Ringwald PACK_STRUCT_BEGIN
70*97dc5e69SMatthias Ringwald struct zep_hdr {
71*97dc5e69SMatthias Ringwald PACK_STRUCT_FLD_8(u8_t prot_id[2]);
72*97dc5e69SMatthias Ringwald PACK_STRUCT_FLD_8(u8_t prot_version);
73*97dc5e69SMatthias Ringwald PACK_STRUCT_FLD_8(u8_t type);
74*97dc5e69SMatthias Ringwald PACK_STRUCT_FLD_8(u8_t channel_id);
75*97dc5e69SMatthias Ringwald PACK_STRUCT_FIELD(u16_t device_id);
76*97dc5e69SMatthias Ringwald PACK_STRUCT_FLD_8(u8_t crc_mode);
77*97dc5e69SMatthias Ringwald PACK_STRUCT_FLD_8(u8_t unknown_1);
78*97dc5e69SMatthias Ringwald PACK_STRUCT_FIELD(u32_t timestamp[2]);
79*97dc5e69SMatthias Ringwald PACK_STRUCT_FIELD(u32_t seq_num);
80*97dc5e69SMatthias Ringwald PACK_STRUCT_FLD_8(u8_t unknown_2[10]);
81*97dc5e69SMatthias Ringwald PACK_STRUCT_FLD_8(u8_t len);
82*97dc5e69SMatthias Ringwald } PACK_STRUCT_STRUCT;
83*97dc5e69SMatthias Ringwald PACK_STRUCT_END
84*97dc5e69SMatthias Ringwald #ifdef PACK_STRUCT_USE_INCLUDES
85*97dc5e69SMatthias Ringwald # include "arch/epstruct.h"
86*97dc5e69SMatthias Ringwald #endif
87*97dc5e69SMatthias Ringwald
88*97dc5e69SMatthias Ringwald struct zepif_state {
89*97dc5e69SMatthias Ringwald struct zepif_init init;
90*97dc5e69SMatthias Ringwald struct udp_pcb *pcb;
91*97dc5e69SMatthias Ringwald u32_t seqno;
92*97dc5e69SMatthias Ringwald };
93*97dc5e69SMatthias Ringwald
94*97dc5e69SMatthias Ringwald static u8_t zep_lowpan_timer_running;
95*97dc5e69SMatthias Ringwald
96*97dc5e69SMatthias Ringwald /* Helper function that calls the 6LoWPAN timer and reschedules itself */
97*97dc5e69SMatthias Ringwald static void
zep_lowpan_timer(void * arg)98*97dc5e69SMatthias Ringwald zep_lowpan_timer(void *arg)
99*97dc5e69SMatthias Ringwald {
100*97dc5e69SMatthias Ringwald lowpan6_tmr();
101*97dc5e69SMatthias Ringwald if (zep_lowpan_timer_running) {
102*97dc5e69SMatthias Ringwald sys_timeout(LOWPAN6_TMR_INTERVAL, zep_lowpan_timer, arg);
103*97dc5e69SMatthias Ringwald }
104*97dc5e69SMatthias Ringwald }
105*97dc5e69SMatthias Ringwald
106*97dc5e69SMatthias Ringwald /* Pass received pbufs into 6LowPAN netif */
107*97dc5e69SMatthias Ringwald static void
zepif_udp_recv(void * arg,struct udp_pcb * pcb,struct pbuf * p,const ip_addr_t * addr,u16_t port)108*97dc5e69SMatthias Ringwald zepif_udp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p,
109*97dc5e69SMatthias Ringwald const ip_addr_t *addr, u16_t port)
110*97dc5e69SMatthias Ringwald {
111*97dc5e69SMatthias Ringwald err_t err;
112*97dc5e69SMatthias Ringwald struct netif *netif_lowpan6 = (struct netif *)arg;
113*97dc5e69SMatthias Ringwald struct zep_hdr *zep;
114*97dc5e69SMatthias Ringwald
115*97dc5e69SMatthias Ringwald LWIP_ASSERT("arg != NULL", arg != NULL);
116*97dc5e69SMatthias Ringwald LWIP_ASSERT("pcb != NULL", pcb != NULL);
117*97dc5e69SMatthias Ringwald LWIP_UNUSED_ARG(pcb); /* for LWIP_NOASSERT */
118*97dc5e69SMatthias Ringwald LWIP_UNUSED_ARG(addr);
119*97dc5e69SMatthias Ringwald LWIP_UNUSED_ARG(port);
120*97dc5e69SMatthias Ringwald if (p == NULL) {
121*97dc5e69SMatthias Ringwald return;
122*97dc5e69SMatthias Ringwald }
123*97dc5e69SMatthias Ringwald
124*97dc5e69SMatthias Ringwald /* Parse and hide the ZEP header */
125*97dc5e69SMatthias Ringwald if (p->len < sizeof(struct zep_hdr)) {
126*97dc5e69SMatthias Ringwald /* need the zep_hdr in one piece */
127*97dc5e69SMatthias Ringwald goto err_return;
128*97dc5e69SMatthias Ringwald }
129*97dc5e69SMatthias Ringwald zep = (struct zep_hdr *)p->payload;
130*97dc5e69SMatthias Ringwald if (zep->prot_id[0] != 'E') {
131*97dc5e69SMatthias Ringwald goto err_return;
132*97dc5e69SMatthias Ringwald }
133*97dc5e69SMatthias Ringwald if (zep->prot_id[1] != 'X') {
134*97dc5e69SMatthias Ringwald goto err_return;
135*97dc5e69SMatthias Ringwald }
136*97dc5e69SMatthias Ringwald if (zep->prot_version != 2) {
137*97dc5e69SMatthias Ringwald /* we only support this version for now */
138*97dc5e69SMatthias Ringwald goto err_return;
139*97dc5e69SMatthias Ringwald }
140*97dc5e69SMatthias Ringwald if (zep->type != 1) {
141*97dc5e69SMatthias Ringwald goto err_return;
142*97dc5e69SMatthias Ringwald }
143*97dc5e69SMatthias Ringwald if (zep->crc_mode != 1) {
144*97dc5e69SMatthias Ringwald goto err_return;
145*97dc5e69SMatthias Ringwald }
146*97dc5e69SMatthias Ringwald if (zep->len != p->tot_len - sizeof(struct zep_hdr)) {
147*97dc5e69SMatthias Ringwald goto err_return;
148*97dc5e69SMatthias Ringwald }
149*97dc5e69SMatthias Ringwald /* everything seems to be OK, hide the ZEP header */
150*97dc5e69SMatthias Ringwald if (pbuf_remove_header(p, sizeof(struct zep_hdr))) {
151*97dc5e69SMatthias Ringwald goto err_return;
152*97dc5e69SMatthias Ringwald }
153*97dc5e69SMatthias Ringwald /* TODO Check CRC? */
154*97dc5e69SMatthias Ringwald /* remove CRC trailer */
155*97dc5e69SMatthias Ringwald pbuf_realloc(p, p->tot_len - 2);
156*97dc5e69SMatthias Ringwald
157*97dc5e69SMatthias Ringwald /* Call into 6LoWPAN code. */
158*97dc5e69SMatthias Ringwald err = netif_lowpan6->input(p, netif_lowpan6);
159*97dc5e69SMatthias Ringwald if (err == ERR_OK) {
160*97dc5e69SMatthias Ringwald return;
161*97dc5e69SMatthias Ringwald }
162*97dc5e69SMatthias Ringwald err_return:
163*97dc5e69SMatthias Ringwald pbuf_free(p);
164*97dc5e69SMatthias Ringwald }
165*97dc5e69SMatthias Ringwald
166*97dc5e69SMatthias Ringwald /* Send 6LoWPAN TX packets as UDP broadcast */
167*97dc5e69SMatthias Ringwald static err_t
zepif_linkoutput(struct netif * netif,struct pbuf * p)168*97dc5e69SMatthias Ringwald zepif_linkoutput(struct netif *netif, struct pbuf *p)
169*97dc5e69SMatthias Ringwald {
170*97dc5e69SMatthias Ringwald err_t err;
171*97dc5e69SMatthias Ringwald struct pbuf *q;
172*97dc5e69SMatthias Ringwald struct zep_hdr *zep;
173*97dc5e69SMatthias Ringwald struct zepif_state *state;
174*97dc5e69SMatthias Ringwald
175*97dc5e69SMatthias Ringwald LWIP_ASSERT("invalid netif", netif != NULL);
176*97dc5e69SMatthias Ringwald LWIP_ASSERT("invalid pbuf", p != NULL);
177*97dc5e69SMatthias Ringwald
178*97dc5e69SMatthias Ringwald if (p->tot_len > ZEP_MAX_DATA_LEN) {
179*97dc5e69SMatthias Ringwald return ERR_VAL;
180*97dc5e69SMatthias Ringwald }
181*97dc5e69SMatthias Ringwald LWIP_ASSERT("TODO: support chained pbufs", p->next == NULL);
182*97dc5e69SMatthias Ringwald
183*97dc5e69SMatthias Ringwald state = (struct zepif_state *)netif->state;
184*97dc5e69SMatthias Ringwald LWIP_ASSERT("state->pcb != NULL", state->pcb != NULL);
185*97dc5e69SMatthias Ringwald
186*97dc5e69SMatthias Ringwald q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct zep_hdr) + p->tot_len, PBUF_RAM);
187*97dc5e69SMatthias Ringwald if (q == NULL) {
188*97dc5e69SMatthias Ringwald return ERR_MEM;
189*97dc5e69SMatthias Ringwald }
190*97dc5e69SMatthias Ringwald zep = (struct zep_hdr *)q->payload;
191*97dc5e69SMatthias Ringwald memset(zep, 0, sizeof(struct zep_hdr));
192*97dc5e69SMatthias Ringwald zep->prot_id[0] = 'E';
193*97dc5e69SMatthias Ringwald zep->prot_id[1] = 'X';
194*97dc5e69SMatthias Ringwald zep->prot_version = 2;
195*97dc5e69SMatthias Ringwald zep->type = 1; /* Data */
196*97dc5e69SMatthias Ringwald zep->channel_id = 0; /* whatever */
197*97dc5e69SMatthias Ringwald zep->device_id = lwip_htons(1); /* whatever */
198*97dc5e69SMatthias Ringwald zep->crc_mode = 1;
199*97dc5e69SMatthias Ringwald zep->unknown_1 = 0xff;
200*97dc5e69SMatthias Ringwald zep->seq_num = lwip_htonl(state->seqno);
201*97dc5e69SMatthias Ringwald state->seqno++;
202*97dc5e69SMatthias Ringwald zep->len = (u8_t)p->tot_len;
203*97dc5e69SMatthias Ringwald
204*97dc5e69SMatthias Ringwald err = pbuf_take_at(q, p->payload, p->tot_len, sizeof(struct zep_hdr));
205*97dc5e69SMatthias Ringwald if (err == ERR_OK) {
206*97dc5e69SMatthias Ringwald #if ZEPIF_LOOPBACK
207*97dc5e69SMatthias Ringwald zepif_udp_recv(netif, state->pcb, pbuf_clone(PBUF_RAW, PBUF_RAM, q), NULL, 0);
208*97dc5e69SMatthias Ringwald #endif
209*97dc5e69SMatthias Ringwald err = udp_sendto(state->pcb, q, state->init.zep_dst_ip_addr, state->init.zep_dst_udp_port);
210*97dc5e69SMatthias Ringwald }
211*97dc5e69SMatthias Ringwald pbuf_free(q);
212*97dc5e69SMatthias Ringwald
213*97dc5e69SMatthias Ringwald return err;
214*97dc5e69SMatthias Ringwald }
215*97dc5e69SMatthias Ringwald
216*97dc5e69SMatthias Ringwald /**
217*97dc5e69SMatthias Ringwald * @ingroup zepif
218*97dc5e69SMatthias Ringwald * Set up a raw 6LowPAN netif and surround it with input- and output
219*97dc5e69SMatthias Ringwald * functions for ZEP
220*97dc5e69SMatthias Ringwald */
221*97dc5e69SMatthias Ringwald err_t
zepif_init(struct netif * netif)222*97dc5e69SMatthias Ringwald zepif_init(struct netif *netif)
223*97dc5e69SMatthias Ringwald {
224*97dc5e69SMatthias Ringwald err_t err;
225*97dc5e69SMatthias Ringwald struct zepif_init *init_state = (struct zepif_init *)netif->state;
226*97dc5e69SMatthias Ringwald struct zepif_state *state = (struct zepif_state *)mem_malloc(sizeof(struct zepif_state));
227*97dc5e69SMatthias Ringwald
228*97dc5e69SMatthias Ringwald LWIP_ASSERT("zepif needs an input callback", netif->input != NULL);
229*97dc5e69SMatthias Ringwald
230*97dc5e69SMatthias Ringwald if (state == NULL) {
231*97dc5e69SMatthias Ringwald return ERR_MEM;
232*97dc5e69SMatthias Ringwald }
233*97dc5e69SMatthias Ringwald memset(state, 0, sizeof(struct zepif_state));
234*97dc5e69SMatthias Ringwald if (init_state != NULL) {
235*97dc5e69SMatthias Ringwald memcpy(&state->init, init_state, sizeof(struct zepif_init));
236*97dc5e69SMatthias Ringwald }
237*97dc5e69SMatthias Ringwald if (state->init.zep_src_udp_port == 0) {
238*97dc5e69SMatthias Ringwald state->init.zep_src_udp_port = ZEPIF_DEFAULT_UDP_PORT;
239*97dc5e69SMatthias Ringwald }
240*97dc5e69SMatthias Ringwald if (state->init.zep_dst_udp_port == 0) {
241*97dc5e69SMatthias Ringwald state->init.zep_dst_udp_port = ZEPIF_DEFAULT_UDP_PORT;
242*97dc5e69SMatthias Ringwald }
243*97dc5e69SMatthias Ringwald #if LWIP_IPV4
244*97dc5e69SMatthias Ringwald if (state->init.zep_dst_ip_addr == NULL) {
245*97dc5e69SMatthias Ringwald /* With IPv4 enabled, default to broadcasting packets if no address is set */
246*97dc5e69SMatthias Ringwald state->init.zep_dst_ip_addr = IP_ADDR_BROADCAST;
247*97dc5e69SMatthias Ringwald }
248*97dc5e69SMatthias Ringwald #endif /* LWIP_IPV4 */
249*97dc5e69SMatthias Ringwald
250*97dc5e69SMatthias Ringwald netif->state = NULL;
251*97dc5e69SMatthias Ringwald
252*97dc5e69SMatthias Ringwald state->pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
253*97dc5e69SMatthias Ringwald if (state->pcb == NULL) {
254*97dc5e69SMatthias Ringwald err = ERR_MEM;
255*97dc5e69SMatthias Ringwald goto err_ret;
256*97dc5e69SMatthias Ringwald }
257*97dc5e69SMatthias Ringwald err = udp_bind(state->pcb, state->init.zep_src_ip_addr, state->init.zep_src_udp_port);
258*97dc5e69SMatthias Ringwald if (err != ERR_OK) {
259*97dc5e69SMatthias Ringwald goto err_ret;
260*97dc5e69SMatthias Ringwald }
261*97dc5e69SMatthias Ringwald if (state->init.zep_netif != NULL) {
262*97dc5e69SMatthias Ringwald udp_bind_netif(state->pcb, state->init.zep_netif);
263*97dc5e69SMatthias Ringwald }
264*97dc5e69SMatthias Ringwald LWIP_ASSERT("udp_bind(lowpan6_broadcast_pcb) failed", err == ERR_OK);
265*97dc5e69SMatthias Ringwald ip_set_option(state->pcb, SOF_BROADCAST);
266*97dc5e69SMatthias Ringwald udp_recv(state->pcb, zepif_udp_recv, netif);
267*97dc5e69SMatthias Ringwald
268*97dc5e69SMatthias Ringwald err = lowpan6_if_init(netif);
269*97dc5e69SMatthias Ringwald LWIP_ASSERT("lowpan6_if_init set a state", netif->state == NULL);
270*97dc5e69SMatthias Ringwald if (err == ERR_OK) {
271*97dc5e69SMatthias Ringwald netif->state = state;
272*97dc5e69SMatthias Ringwald netif->hwaddr_len = 6;
273*97dc5e69SMatthias Ringwald if (init_state != NULL) {
274*97dc5e69SMatthias Ringwald memcpy(netif->hwaddr, init_state->addr, 6);
275*97dc5e69SMatthias Ringwald } else {
276*97dc5e69SMatthias Ringwald u8_t i;
277*97dc5e69SMatthias Ringwald for (i = 0; i < 6; i++) {
278*97dc5e69SMatthias Ringwald netif->hwaddr[i] = i;
279*97dc5e69SMatthias Ringwald }
280*97dc5e69SMatthias Ringwald netif->hwaddr[0] &= 0xfc;
281*97dc5e69SMatthias Ringwald }
282*97dc5e69SMatthias Ringwald netif->linkoutput = zepif_linkoutput;
283*97dc5e69SMatthias Ringwald
284*97dc5e69SMatthias Ringwald if (!zep_lowpan_timer_running) {
285*97dc5e69SMatthias Ringwald sys_timeout(LOWPAN6_TMR_INTERVAL, zep_lowpan_timer, NULL);
286*97dc5e69SMatthias Ringwald zep_lowpan_timer_running = 1;
287*97dc5e69SMatthias Ringwald }
288*97dc5e69SMatthias Ringwald
289*97dc5e69SMatthias Ringwald return ERR_OK;
290*97dc5e69SMatthias Ringwald }
291*97dc5e69SMatthias Ringwald
292*97dc5e69SMatthias Ringwald err_ret:
293*97dc5e69SMatthias Ringwald if (state->pcb != NULL) {
294*97dc5e69SMatthias Ringwald udp_remove(state->pcb);
295*97dc5e69SMatthias Ringwald }
296*97dc5e69SMatthias Ringwald mem_free(state);
297*97dc5e69SMatthias Ringwald return err;
298*97dc5e69SMatthias Ringwald }
299*97dc5e69SMatthias Ringwald
300*97dc5e69SMatthias Ringwald #endif /* LWIP_IPV6 && LWIP_UDP */
301