aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios/os/various/lwip_bindings/lwipthread.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chibios/os/various/lwip_bindings/lwipthread.c')
-rw-r--r--lib/chibios/os/various/lwip_bindings/lwipthread.c530
1 files changed, 530 insertions, 0 deletions
diff --git a/lib/chibios/os/various/lwip_bindings/lwipthread.c b/lib/chibios/os/various/lwip_bindings/lwipthread.c
new file mode 100644
index 000000000..0260ae61b
--- /dev/null
+++ b/lib/chibios/os/various/lwip_bindings/lwipthread.c
@@ -0,0 +1,530 @@
1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16/*
17 * **** This file incorporates work covered by the following copyright and ****
18 * **** permission notice: ****
19 *
20 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
21 * All rights reserved.
22 *
23 * Redistribution and use in source and binary forms, with or without modification,
24 * are permitted provided that the following conditions are met:
25 *
26 * 1. Redistributions of source code must retain the above copyright notice,
27 * this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright notice,
29 * this list of conditions and the following disclaimer in the documentation
30 * and/or other materials provided with the distribution.
31 * 3. The name of the author may not be used to endorse or promote products
32 * derived from this software without specific prior written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
35 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
36 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
37 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
38 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
39 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
41 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
42 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
43 * OF SUCH DAMAGE.
44 *
45 * This file is part of the lwIP TCP/IP stack.
46 *
47 * Author: Adam Dunkels <[email protected]>
48 *
49 */
50
51/**
52 * @file lwipthread.c
53 * @brief LWIP wrapper thread code.
54 * @addtogroup LWIP_THREAD
55 * @{
56 */
57
58#include "hal.h"
59#include "evtimer.h"
60
61#include "lwipthread.h"
62
63#include <lwip/opt.h>
64#include <lwip/def.h>
65#include <lwip/mem.h>
66#include <lwip/pbuf.h>
67#include <lwip/sys.h>
68#include <lwip/stats.h>
69#include <lwip/snmp.h>
70#include <lwip/tcpip.h>
71#include <netif/etharp.h>
72#include <lwip/netifapi.h>
73
74#if LWIP_DHCP
75#include <lwip/dhcp.h>
76#endif
77
78#if LWIP_AUTOIP
79#include <lwip/autoip.h>
80#endif
81
82#define PERIODIC_TIMER_ID 1
83#define FRAME_RECEIVED_ID 2
84
85/*
86 * Suspension point for initialization procedure.
87 */
88thread_reference_t lwip_trp = NULL;
89
90/*
91 * Stack area for the LWIP-MAC thread.
92 */
93static THD_WORKING_AREA(wa_lwip_thread, LWIP_THREAD_STACK_SIZE);
94
95/*
96 * Initialization.
97 */
98static void low_level_init(struct netif *netif) {
99 /* set MAC hardware address length */
100 netif->hwaddr_len = ETHARP_HWADDR_LEN;
101
102 /* maximum transfer unit */
103 netif->mtu = LWIP_NETIF_MTU;
104
105 /* device capabilities */
106 /* don't set NETIF_FLAG_ETHARP if this device is not an Ethernet one */
107 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
108
109 /* Do whatever else is needed to initialize interface. */
110}
111
112/*
113 * This function does the actual transmission of the packet. The packet is
114 * contained in the pbuf that is passed to the function. This pbuf
115 * might be chained.
116 *
117 * @param netif the lwip network interface structure for this ethernetif
118 * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
119 * @return ERR_OK if the packet could be sent
120 * an err_t value if the packet couldn't be sent
121 *
122 * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
123 * strange results. You might consider waiting for space in the DMA queue
124 * to become available since the stack doesn't retry to send a packet
125 * dropped because of memory failure (except for the TCP timers).
126 */
127static err_t low_level_output(struct netif *netif, struct pbuf *p) {
128 struct pbuf *q;
129 MACTransmitDescriptor td;
130
131 (void)netif;
132 if (macWaitTransmitDescriptor(&ETHD1, &td, TIME_MS2I(LWIP_SEND_TIMEOUT)) != MSG_OK)
133 return ERR_TIMEOUT;
134
135#if ETH_PAD_SIZE
136 pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
137#endif
138
139 /* Iterates through the pbuf chain. */
140 for(q = p; q != NULL; q = q->next)
141 macWriteTransmitDescriptor(&td, (uint8_t *)q->payload, (size_t)q->len);
142 macReleaseTransmitDescriptor(&td);
143
144 MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
145 if (((u8_t*)p->payload)[0] & 1) {
146 /* broadcast or multicast packet*/
147 MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);
148 }
149 else {
150 /* unicast packet */
151 MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
152 }
153 /* increase ifoutdiscards or ifouterrors on error */
154
155#if ETH_PAD_SIZE
156 pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
157#endif
158
159 LINK_STATS_INC(link.xmit);
160
161 return ERR_OK;
162}
163
164/*
165 * Receives a frame.
166 * Allocates a pbuf and transfers the bytes of the incoming
167 * packet from the interface into the pbuf.
168 *
169 * @param netif the lwip network interface structure for this ethernetif
170 * @return a pbuf filled with the received packet (including MAC header)
171 * NULL on memory error
172 */
173static bool low_level_input(struct netif *netif, struct pbuf **pbuf) {
174 MACReceiveDescriptor rd;
175 struct pbuf *q;
176 u16_t len;
177
178 (void)netif;
179
180 osalDbgAssert(pbuf != NULL, "invalid null pointer");
181
182 if (macWaitReceiveDescriptor(&ETHD1, &rd, TIME_IMMEDIATE) != MSG_OK)
183 return false;
184
185 len = (u16_t)rd.size;
186
187#if ETH_PAD_SIZE
188 len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
189#endif
190
191 /* We allocate a pbuf chain of pbufs from the pool. */
192 *pbuf = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
193
194 if (*pbuf != NULL) {
195#if ETH_PAD_SIZE
196 pbuf_header(*pbuf, -ETH_PAD_SIZE); /* drop the padding word */
197#endif
198
199 /* Iterates through the pbuf chain. */
200 for(q = *pbuf; q != NULL; q = q->next)
201 macReadReceiveDescriptor(&rd, (uint8_t *)q->payload, (size_t)q->len);
202 macReleaseReceiveDescriptor(&rd);
203
204 MIB2_STATS_NETIF_ADD(netif, ifinoctets, (*pbuf)->tot_len);
205
206 if (*(uint8_t *)((*pbuf)->payload) & 1) {
207 /* broadcast or multicast packet*/
208 MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
209 }
210 else {
211 /* unicast packet*/
212 MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
213 }
214
215#if ETH_PAD_SIZE
216 pbuf_header(*pbuf, ETH_PAD_SIZE); /* reclaim the padding word */
217#endif
218
219 LINK_STATS_INC(link.recv);
220 }
221 else {
222 macReleaseReceiveDescriptor(&rd); // Drop packet
223 LINK_STATS_INC(link.memerr);
224 LINK_STATS_INC(link.drop);
225 MIB2_STATS_NETIF_INC(netif, ifindiscards);
226 }
227
228 return true;
229}
230
231/*
232 * Called at the beginning of the program to set up the
233 * network interface. It calls the function low_level_init() to do the
234 * actual setup of the hardware.
235 *
236 * This function should be passed as a parameter to netifapi_netif_add().
237 *
238 * @param netif the lwip network interface structure for this ethernetif
239 * @return ERR_OK if the loopif is initialised
240 * ERR_MEM if private data couldn't be allocated
241 * any other err_t on error
242 */
243static err_t ethernetif_init(struct netif *netif) {
244 osalDbgAssert((netif != NULL), "netif != NULL");
245
246 /*
247 * Initialize the snmp variables and counters inside the struct netif.
248 * The last argument should be replaced with your link speed, in units
249 * of bits per second.
250 */
251 MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LWIP_LINK_SPEED);
252
253 netif->state = NULL;
254 netif->name[0] = LWIP_IFNAME0;
255 netif->name[1] = LWIP_IFNAME1;
256 /* We directly use etharp_output() here to save a function call.
257 * You can instead declare your own function an call etharp_output()
258 * from it if you have to do some checks before sending (e.g. if link
259 * is available...) */
260 netif->output = etharp_output;
261 netif->linkoutput = low_level_output;
262
263 /* initialize the hardware */
264 low_level_init(netif);
265
266 return ERR_OK;
267}
268
269static net_addr_mode_t addressMode;
270static ip4_addr_t ip, gateway, netmask;
271static struct netif thisif;
272
273void lwipDefaultLinkUpCB(void *p)
274{
275 struct netif *ifc = (struct netif*) p;
276 (void) ifc;
277#if LWIP_AUTOIP
278 if (addressMode == NET_ADDRESS_AUTO)
279 autoip_start(ifc);
280#endif
281#if LWIP_DHCP
282 if (addressMode == NET_ADDRESS_DHCP)
283 dhcp_start(ifc);
284#endif
285}
286
287void lwipDefaultLinkDownCB(void *p)
288{
289 struct netif *ifc = (struct netif*) p;
290 (void) ifc;
291#if LWIP_AUTOIP
292 if (addressMode == NET_ADDRESS_AUTO)
293 autoip_stop(ifc);
294#endif
295#if LWIP_DHCP
296 if (addressMode == NET_ADDRESS_DHCP)
297 dhcp_stop(ifc);
298#endif
299}
300
301/**
302 * @brief LWIP handling thread.
303 *
304 * @param[in] p pointer to a @p lwipthread_opts structure or @p NULL
305 * @return The function does not return.
306 */
307static THD_FUNCTION(lwip_thread, p) {
308 event_timer_t evt;
309 event_listener_t el0, el1;
310 static const MACConfig mac_config = {thisif.hwaddr};
311 err_t result;
312 tcpip_callback_fn link_up_cb = NULL;
313 tcpip_callback_fn link_down_cb = NULL;
314
315 chRegSetThreadName(LWIP_THREAD_NAME);
316
317 /* Initializes the thing.*/
318 tcpip_init(NULL, NULL);
319
320 /* TCP/IP parameters, runtime or compile time.*/
321 if (p) {
322 lwipthread_opts_t *opts = p;
323 unsigned i;
324
325 for (i = 0; i < 6; i++)
326 thisif.hwaddr[i] = opts->macaddress[i];
327 ip.addr = opts->address;
328 gateway.addr = opts->gateway;
329 netmask.addr = opts->netmask;
330 addressMode = opts->addrMode;
331#if LWIP_NETIF_HOSTNAME
332 thisif.hostname = opts->ourHostName;
333#endif
334 link_up_cb = opts->link_up_cb;
335 link_down_cb = opts->link_down_cb;
336 }
337 else {
338 thisif.hwaddr[0] = LWIP_ETHADDR_0;
339 thisif.hwaddr[1] = LWIP_ETHADDR_1;
340 thisif.hwaddr[2] = LWIP_ETHADDR_2;
341 thisif.hwaddr[3] = LWIP_ETHADDR_3;
342 thisif.hwaddr[4] = LWIP_ETHADDR_4;
343 thisif.hwaddr[5] = LWIP_ETHADDR_5;
344 LWIP_IPADDR(&ip);
345 LWIP_GATEWAY(&gateway);
346 LWIP_NETMASK(&netmask);
347#if LWIP_DHCP
348 addressMode = NET_ADDRESS_DHCP;
349#elif LWIP_AUTOIP
350 addressMode = NET_ADDRESS_AUTO;
351#else
352 addressMode = NET_ADDRESS_STATIC;
353#endif
354#if LWIP_NETIF_HOSTNAME
355 thisif.hostname = NULL;
356#endif
357 }
358
359 if (!link_up_cb)
360 link_up_cb = lwipDefaultLinkUpCB;
361 if (!link_down_cb)
362 link_down_cb = lwipDefaultLinkDownCB;
363
364#if LWIP_NETIF_HOSTNAME
365 if (thisif.hostname == NULL)
366 thisif.hostname = LWIP_NETIF_HOSTNAME_STRING;
367#endif
368
369 macStart(&ETHD1, &mac_config);
370
371 MIB2_INIT_NETIF(&thisif, snmp_ifType_ethernet_csmacd, 0);
372
373 /* Add interface. */
374 result = netifapi_netif_add(&thisif, &ip, &netmask, &gateway, NULL, ethernetif_init, tcpip_input);
375 if (result != ERR_OK)
376 {
377 chThdSleepMilliseconds(1000); // Give some time to print any other diagnostics.
378 osalSysHalt("netif_add error"); // Not sure what else we can do if an error occurs here.
379 };
380
381 netifapi_netif_set_default(&thisif);
382 netifapi_netif_set_up(&thisif);
383
384 /* Setup event sources.*/
385 evtObjectInit(&evt, LWIP_LINK_POLL_INTERVAL);
386 evtStart(&evt);
387 chEvtRegisterMask(&evt.et_es, &el0, PERIODIC_TIMER_ID);
388 chEvtRegisterMask(macGetReceiveEventSource(&ETHD1), &el1, FRAME_RECEIVED_ID);
389 chEvtAddEvents(PERIODIC_TIMER_ID | FRAME_RECEIVED_ID);
390
391 /* Resumes the caller and goes to the final priority.*/
392 chThdResume(&lwip_trp, MSG_OK);
393 chThdSetPriority(LWIP_THREAD_PRIORITY);
394
395 while (true) {
396 eventmask_t mask = chEvtWaitAny(ALL_EVENTS);
397 if (mask & PERIODIC_TIMER_ID) {
398 bool current_link_status = macPollLinkStatus(&ETHD1);
399 if (current_link_status != netif_is_link_up(&thisif)) {
400 if (current_link_status) {
401 tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_up,
402 &thisif, 0);
403 tcpip_callback_with_block(link_up_cb, &thisif, 0);
404 }
405 else {
406 tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_down,
407 &thisif, 0);
408 tcpip_callback_with_block(link_down_cb, &thisif, 0);
409 }
410 }
411 }
412
413 if (mask & FRAME_RECEIVED_ID) {
414 struct pbuf *p;
415 while (low_level_input(&thisif, &p)) {
416 if (p != NULL) {
417 struct eth_hdr *ethhdr = p->payload;
418 switch (htons(ethhdr->type)) {
419 /* IP or ARP packet? */
420 case ETHTYPE_IP:
421 case ETHTYPE_ARP:
422 /* full packet send to tcpip_thread to process */
423 if (thisif.input(p, &thisif) == ERR_OK)
424 break;
425 LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
426 /* Falls through */
427 default:
428 pbuf_free(p);
429 }
430 }
431 }
432 }
433 }
434}
435
436/**
437 * @brief Initializes the lwIP subsystem.
438 * @note The function exits after the initialization is finished.
439 *
440 * @param[in] opts pointer to the configuration structure, if @p NULL
441 * then the static configuration is used.
442 */
443void lwipInit(const lwipthread_opts_t *opts) {
444
445 /* Creating the lwIP thread (it changes priority internally).*/
446 chThdCreateStatic(wa_lwip_thread, sizeof (wa_lwip_thread),
447 chThdGetPriorityX() - 1, lwip_thread, (void *)opts);
448
449 /* Waiting for the lwIP thread complete initialization. Note,
450 this thread reaches the thread reference object first because
451 the relative priorities.*/
452 chSysLock();
453 chThdSuspendS(&lwip_trp);
454 chSysUnlock();
455}
456
457typedef struct lwip_reconf_params {
458 const lwipreconf_opts_t *opts;
459 semaphore_t completion;
460} lwip_reconf_params_t;
461
462static void do_reconfigure(void *p)
463{
464 lwip_reconf_params_t *reconf = (lwip_reconf_params_t*) p;
465
466 switch (addressMode) {
467#if LWIP_DHCP
468 case NET_ADDRESS_DHCP: {
469 if (netif_is_up(&thisif))
470 dhcp_stop(&thisif);
471 break;
472 }
473#endif
474 case NET_ADDRESS_STATIC: {
475 ip4_addr_t zero = { 0 };
476 netif_set_ipaddr(&thisif, &zero);
477 netif_set_netmask(&thisif, &zero);
478 netif_set_gw(&thisif, &zero);
479 break;
480 }
481#if LWIP_AUTOIP
482 case NET_ADDRESS_AUTO: {
483 if (netif_is_up(&thisif))
484 autoip_stop(&thisif);
485 break;
486 }
487#endif
488 }
489
490 ip.addr = reconf->opts->address;
491 gateway.addr = reconf->opts->gateway;
492 netmask.addr = reconf->opts->netmask;
493 addressMode = reconf->opts->addrMode;
494
495 switch (addressMode) {
496#if LWIP_DHCP
497 case NET_ADDRESS_DHCP: {
498 if (netif_is_up(&thisif))
499 dhcp_start(&thisif);
500 break;
501 }
502#endif
503 case NET_ADDRESS_STATIC: {
504 netif_set_ipaddr(&thisif, &ip);
505 netif_set_netmask(&thisif, &netmask);
506 netif_set_gw(&thisif, &gateway);
507 break;
508 }
509#if LWIP_AUTOIP
510 case NET_ADDRESS_AUTO: {
511 if (netif_is_up(&thisif))
512 autoip_start(&thisif);
513 break;
514 }
515#endif
516 }
517
518 chSemSignal(&reconf->completion);
519}
520
521void lwipReconfigure(const lwipreconf_opts_t *opts)
522{
523 lwip_reconf_params_t params;
524 params.opts = opts;
525 chSemObjectInit(&params.completion, 0);
526 tcpip_callback_with_block(do_reconfigure, &params, 0);
527 chSemWait(&params.completion);
528}
529
530/** @} */