source: S-port/trunk/Middlewares/Third_Party/LwIP/src/netif/zepif.c

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