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