1 /*
2 * COPYRIGHT (C) 2006-2018, RT-Thread Development Team
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25 * OF SUCH DAMAGE.
26 *
27 * Change Logs:
28 * Date Author Notes
29 * 2012-12-8 Bernard add file header
30 * export bsd socket symbol for RT-Thread Application Module
31 * 2017-11-15 Bernard add lock for init_done callback.
32 */
33
34 #include <rtthread.h>
35
36 #include "lwip/sys.h"
37 #include "lwip/opt.h"
38 #include "lwip/stats.h"
39 #include "lwip/err.h"
40 #include "arch/sys_arch.h"
41 #include "lwip/debug.h"
42 #include "lwip/netif.h"
43 #include "lwip/netifapi.h"
44 #include "lwip/tcpip.h"
45 #include "netif/ethernetif.h"
46 #include "lwip/sio.h"
47 #include "lwip/init.h"
48 #include "lwip/dhcp.h"
49 #include "lwip/inet.h"
50
51 #include <string.h>
52
53 /*
54 * Initialize the network interface device
55 *
56 * @return the operation status, ERR_OK on OK, ERR_IF on error
57 */
netif_device_init(struct netif * netif)58 static err_t netif_device_init(struct netif *netif)
59 {
60 struct eth_device *ethif;
61
62 ethif = (struct eth_device *)netif->state;
63 if (ethif != RT_NULL)
64 {
65 rt_device_t device;
66
67 /* get device object */
68 device = (rt_device_t) ethif;
69 if (rt_device_init(device) != RT_EOK)
70 {
71 return ERR_IF;
72 }
73
74 /* copy device flags to netif flags */
75 netif->flags = ethif->flags;
76
77 return ERR_OK;
78 }
79
80 return ERR_IF;
81 }
82 /*
83 * Initialize the ethernetif layer and set network interface device up
84 */
tcpip_init_done_callback(void * arg)85 static void tcpip_init_done_callback(void *arg)
86 {
87 rt_device_t device;
88 struct eth_device *ethif;
89 ip4_addr_t ipaddr, netmask, gw;
90 struct rt_list_node* node;
91 struct rt_object* object;
92 struct rt_object_information *information;
93
94 LWIP_ASSERT("invalid arg.\n",arg);
95
96 IP4_ADDR(&gw, 0,0,0,0);
97 IP4_ADDR(&ipaddr, 0,0,0,0);
98 IP4_ADDR(&netmask, 0,0,0,0);
99
100 /* enter critical */
101 rt_enter_critical();
102
103 /* for each network interfaces */
104 information = rt_object_get_information(RT_Object_Class_Device);
105 RT_ASSERT(information != RT_NULL);
106 for (node = information->object_list.next;
107 node != &(information->object_list);
108 node = node->next)
109 {
110 object = rt_list_entry(node, struct rt_object, list);
111 device = (rt_device_t)object;
112 if (device->type == RT_Device_Class_NetIf)
113 {
114 ethif = (struct eth_device *)device;
115
116 /* leave critical */
117 rt_exit_critical();
118 LOCK_TCPIP_CORE();
119
120 netif_add(ethif->netif, &ipaddr, &netmask, &gw,
121 ethif, netif_device_init, tcpip_input);
122
123 if (netif_default == RT_NULL)
124 netif_set_default(ethif->netif);
125
126 #if LWIP_DHCP
127 /* set interface up */
128 netif_set_up(ethif->netif);
129 /* if this interface uses DHCP, start the DHCP client */
130 dhcp_start(ethif->netif);
131 #else
132 /* set interface up */
133 netif_set_up(ethif->netif);
134 #endif
135
136 if (ethif->flags & ETHIF_LINK_PHYUP)
137 {
138 netif_set_link_up(ethif->netif);
139 }
140
141 UNLOCK_TCPIP_CORE();
142 /* enter critical */
143 rt_enter_critical();
144 }
145 }
146
147 /* leave critical */
148 rt_exit_critical();
149 rt_sem_release((rt_sem_t)arg);
150 }
151
152 /**
153 * LwIP system initialization
154 */
155 extern int eth_system_device_init_private(void);
lwip_system_init(void)156 int lwip_system_init(void)
157 {
158 rt_err_t rc;
159 struct rt_semaphore done_sem;
160 static rt_bool_t init_ok = RT_FALSE;
161
162 if (init_ok)
163 {
164 rt_kprintf("lwip system already init.\n");
165 return 0;
166 }
167
168 eth_system_device_init_private();
169
170 /* set default netif to NULL */
171 netif_default = RT_NULL;
172
173 rc = rt_sem_init(&done_sem, "done", 0, RT_IPC_FLAG_FIFO);
174
175 if (rc != RT_EOK)
176 {
177 LWIP_ASSERT("Failed to create semaphore", 0);
178
179 return -1;
180 }
181
182 tcpip_init(tcpip_init_done_callback, (void *)&done_sem);
183
184 /* waiting for initialization done */
185 if (rt_sem_take(&done_sem, RT_WAITING_FOREVER) != RT_EOK)
186 {
187 rt_sem_detach(&done_sem);
188
189 return -1;
190 }
191 rt_sem_detach(&done_sem);
192
193 /* set default ip address */
194 #if !LWIP_DHCP
195 if (netif_default != RT_NULL)
196 {
197 struct ip4_addr ipaddr, netmask, gw;
198
199 ipaddr.addr = inet_addr(RT_LWIP_IPADDR);
200 gw.addr = inet_addr(RT_LWIP_GWADDR);
201 netmask.addr = inet_addr(RT_LWIP_MSKADDR);
202
203 netifapi_netif_set_addr(netif_default, &ipaddr, &netmask, &gw);
204 }
205 #endif
206 rt_kprintf("lwIP-%d.%d.%d initialized!\n", LWIP_VERSION_MAJOR, LWIP_VERSION_MINOR, LWIP_VERSION_REVISION);
207
208 init_ok = RT_TRUE;
209
210 return 0;
211 }
212 INIT_PREV_EXPORT(lwip_system_init);
213
sys_init(void)214 void sys_init(void)
215 {
216 /* nothing on RT-Thread porting */
217 }
218
lwip_sys_init(void)219 void lwip_sys_init(void)
220 {
221 lwip_system_init();
222 }
223
224 /*
225 * Create a new semaphore
226 *
227 * @return the operation status, ERR_OK on OK; others on error
228 */
sys_sem_new(sys_sem_t * sem,u8_t count)229 err_t sys_sem_new(sys_sem_t *sem, u8_t count)
230 {
231 static unsigned short counter = 0;
232 char tname[RT_NAME_MAX];
233 sys_sem_t tmpsem;
234
235 RT_DEBUG_NOT_IN_INTERRUPT;
236
237 rt_snprintf(tname, RT_NAME_MAX, "%s%d", SYS_LWIP_SEM_NAME, counter);
238 counter ++;
239
240 tmpsem = rt_sem_create(tname, count, RT_IPC_FLAG_FIFO);
241 if (tmpsem == RT_NULL)
242 return ERR_MEM;
243 else
244 {
245 *sem = tmpsem;
246
247 return ERR_OK;
248 }
249 }
250
251 /*
252 * Deallocate a semaphore
253 */
sys_sem_free(sys_sem_t * sem)254 void sys_sem_free(sys_sem_t *sem)
255 {
256 RT_DEBUG_NOT_IN_INTERRUPT;
257 rt_sem_delete(*sem);
258 }
259
260 /*
261 * Signal a semaphore
262 */
sys_sem_signal(sys_sem_t * sem)263 void sys_sem_signal(sys_sem_t *sem)
264 {
265 rt_sem_release(*sem);
266 }
267
268 /*
269 * Block the thread while waiting for the semaphore to be signaled
270 *
271 * @return If the timeout argument is non-zero, it will return the number of milliseconds
272 * spent waiting for the semaphore to be signaled; If the semaphore isn't signaled
273 * within the specified time, it will return SYS_ARCH_TIMEOUT; If the thread doesn't
274 * wait for the semaphore, it will return zero
275 */
sys_arch_sem_wait(sys_sem_t * sem,u32_t timeout)276 u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
277 {
278 rt_err_t ret;
279 s32_t t;
280 u32_t tick;
281
282 RT_DEBUG_NOT_IN_INTERRUPT;
283
284 /* get the begin tick */
285 tick = rt_tick_get();
286 if (timeout == 0)
287 t = RT_WAITING_FOREVER;
288 else
289 {
290 /* convert msecond to os tick */
291 if (timeout < (1000/RT_TICK_PER_SECOND))
292 t = 1;
293 else
294 t = timeout / (1000/RT_TICK_PER_SECOND);
295 }
296
297 ret = rt_sem_take(*sem, t);
298
299 if (ret == -RT_ETIMEOUT)
300 return SYS_ARCH_TIMEOUT;
301 else
302 {
303 if (ret == RT_EOK)
304 ret = 1;
305 }
306
307 /* get elapse msecond */
308 tick = rt_tick_get() - tick;
309
310 /* convert tick to msecond */
311 tick = tick * (1000 / RT_TICK_PER_SECOND);
312 if (tick == 0)
313 tick = 1;
314
315 return tick;
316 }
317
318 #ifndef sys_sem_valid
319 /** Check if a semaphore is valid/allocated:
320 * return 1 for valid, 0 for invalid
321 */
sys_sem_valid(sys_sem_t * sem)322 int sys_sem_valid(sys_sem_t *sem)
323 {
324 return (int)(*sem);
325 }
326 #endif
327
328 #ifndef sys_sem_set_invalid
329 /** Set a semaphore invalid so that sys_sem_valid returns 0
330 */
sys_sem_set_invalid(sys_sem_t * sem)331 void sys_sem_set_invalid(sys_sem_t *sem)
332 {
333 *sem = RT_NULL;
334 }
335 #endif
336
337 /* ====================== Mutex ====================== */
338
339 /** Create a new mutex
340 * @param mutex pointer to the mutex to create
341 * @return a new mutex
342 */
sys_mutex_new(sys_mutex_t * mutex)343 err_t sys_mutex_new(sys_mutex_t *mutex)
344 {
345 static unsigned short counter = 0;
346 char tname[RT_NAME_MAX];
347 sys_mutex_t tmpmutex;
348
349 RT_DEBUG_NOT_IN_INTERRUPT;
350
351 rt_snprintf(tname, RT_NAME_MAX, "%s%d", SYS_LWIP_MUTEX_NAME, counter);
352 counter ++;
353
354 tmpmutex = rt_mutex_create(tname, RT_IPC_FLAG_FIFO);
355 if (tmpmutex == RT_NULL)
356 return ERR_MEM;
357 else
358 {
359 *mutex = tmpmutex;
360
361 return ERR_OK;
362 }
363 }
364
365 /** Lock a mutex
366 * @param mutex the mutex to lock
367 */
sys_mutex_lock(sys_mutex_t * mutex)368 void sys_mutex_lock(sys_mutex_t *mutex)
369 {
370 RT_DEBUG_NOT_IN_INTERRUPT;
371 rt_mutex_take(*mutex, RT_WAITING_FOREVER);
372
373 return;
374 }
375
376 /** Unlock a mutex
377 * @param mutex the mutex to unlock
378 */
sys_mutex_unlock(sys_mutex_t * mutex)379 void sys_mutex_unlock(sys_mutex_t *mutex)
380 {
381 rt_mutex_release(*mutex);
382 }
383
384 /** Delete a semaphore
385 * @param mutex the mutex to delete
386 */
sys_mutex_free(sys_mutex_t * mutex)387 void sys_mutex_free(sys_mutex_t *mutex)
388 {
389 RT_DEBUG_NOT_IN_INTERRUPT;
390
391 rt_mutex_delete(*mutex);
392 }
393
394 #ifndef sys_mutex_valid
395 /** Check if a mutex is valid/allocated:
396 * return 1 for valid, 0 for invalid
397 */
sys_mutex_valid(sys_mutex_t * mutex)398 int sys_mutex_valid(sys_mutex_t *mutex)
399 {
400 return (int)(*mutex);
401 }
402 #endif
403
404 #ifndef sys_mutex_set_invalid
405 /** Set a mutex invalid so that sys_mutex_valid returns 0
406 */
sys_mutex_set_invalid(sys_mutex_t * mutex)407 void sys_mutex_set_invalid(sys_mutex_t *mutex)
408 {
409 *mutex = RT_NULL;
410 }
411 #endif
412
413 /* ====================== Mailbox ====================== */
414
415 /*
416 * Create an empty mailbox for maximum "size" elements
417 *
418 * @return the operation status, ERR_OK on OK; others on error
419 */
sys_mbox_new(sys_mbox_t * mbox,int size)420 err_t sys_mbox_new(sys_mbox_t *mbox, int size)
421 {
422 static unsigned short counter = 0;
423 char tname[RT_NAME_MAX];
424 sys_mbox_t tmpmbox;
425
426 RT_DEBUG_NOT_IN_INTERRUPT;
427
428 rt_snprintf(tname, RT_NAME_MAX, "%s%d", SYS_LWIP_MBOX_NAME, counter);
429 counter ++;
430
431 tmpmbox = rt_mb_create(tname, size, RT_IPC_FLAG_FIFO);
432 if (tmpmbox != RT_NULL)
433 {
434 *mbox = tmpmbox;
435
436 return ERR_OK;
437 }
438
439 return ERR_MEM;
440 }
441
442 /*
443 * Deallocate a mailbox
444 */
sys_mbox_free(sys_mbox_t * mbox)445 void sys_mbox_free(sys_mbox_t *mbox)
446 {
447 RT_DEBUG_NOT_IN_INTERRUPT;
448
449 rt_mb_delete(*mbox);
450
451 return;
452 }
453
454 /** Post a message to an mbox - may not fail
455 * -> blocks if full, only used from tasks not from ISR
456 * @param mbox mbox to posts the message
457 * @param msg message to post (ATTENTION: can be NULL)
458 */
sys_mbox_post(sys_mbox_t * mbox,void * msg)459 void sys_mbox_post(sys_mbox_t *mbox, void *msg)
460 {
461 RT_DEBUG_NOT_IN_INTERRUPT;
462
463 rt_mb_send_wait(*mbox, (rt_uint32_t)msg, RT_WAITING_FOREVER);
464
465 return;
466 }
467
468 /*
469 * Try to post the "msg" to the mailbox
470 *
471 * @return return ERR_OK if the "msg" is posted, ERR_MEM if the mailbox is full
472 */
sys_mbox_trypost(sys_mbox_t * mbox,void * msg)473 err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
474 {
475 if (rt_mb_send(*mbox, (rt_uint32_t)msg) == RT_EOK)
476 return ERR_OK;
477
478 return ERR_MEM;
479 }
480
481 /** Wait for a new message to arrive in the mbox
482 * @param mbox mbox to get a message from
483 * @param msg pointer where the message is stored
484 * @param timeout maximum time (in milliseconds) to wait for a message
485 * @return time (in milliseconds) waited for a message, may be 0 if not waited
486 or SYS_ARCH_TIMEOUT on timeout
487 * The returned time has to be accurate to prevent timer jitter!
488 */
sys_arch_mbox_fetch(sys_mbox_t * mbox,void ** msg,u32_t timeout)489 u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
490 {
491 rt_err_t ret;
492 s32_t t;
493 u32_t tick;
494
495 RT_DEBUG_NOT_IN_INTERRUPT;
496
497 /* get the begin tick */
498 tick = rt_tick_get();
499
500 if(timeout == 0)
501 t = RT_WAITING_FOREVER;
502 else
503 {
504 /* convirt msecond to os tick */
505 if (timeout < (1000/RT_TICK_PER_SECOND))
506 t = 1;
507 else
508 t = timeout / (1000/RT_TICK_PER_SECOND);
509 }
510
511 ret = rt_mb_recv(*mbox, (rt_ubase_t *)msg, t);
512
513 if(ret == -RT_ETIMEOUT)
514 return SYS_ARCH_TIMEOUT;
515 else
516 {
517 LWIP_ASSERT("rt_mb_recv returned with error!", ret == RT_EOK);
518 }
519
520 /* get elapse msecond */
521 tick = rt_tick_get() - tick;
522
523 /* convert tick to msecond */
524 tick = tick * (1000 / RT_TICK_PER_SECOND);
525 if (tick == 0)
526 tick = 1;
527
528 return tick;
529 }
530
531 /** Wait for a new message to arrive in the mbox
532 * @param mbox mbox to get a message from
533 * @param msg pointer where the message is stored
534 * @param timeout maximum time (in milliseconds) to wait for a message
535 * @return 0 (milliseconds) if a message has been received
536 * or SYS_MBOX_EMPTY if the mailbox is empty
537 */
sys_arch_mbox_tryfetch(sys_mbox_t * mbox,void ** msg)538 u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
539 {
540 int ret;
541
542 ret = rt_mb_recv(*mbox, (rt_ubase_t *)msg, 0);
543
544 if(ret == -RT_ETIMEOUT)
545 return SYS_ARCH_TIMEOUT;
546 else
547 {
548 if (ret == RT_EOK)
549 ret = 1;
550 }
551
552 return ret;
553 }
554
555 #ifndef sys_mbox_valid
556 /** Check if an mbox is valid/allocated:
557 * return 1 for valid, 0 for invalid
558 */
sys_mbox_valid(sys_mbox_t * mbox)559 int sys_mbox_valid(sys_mbox_t *mbox)
560 {
561 return (int)(*mbox);
562 }
563 #endif
564
565 #ifndef sys_mbox_set_invalid
566 /** Set an mbox invalid so that sys_mbox_valid returns 0
567 */
sys_mbox_set_invalid(sys_mbox_t * mbox)568 void sys_mbox_set_invalid(sys_mbox_t *mbox)
569 {
570 *mbox = RT_NULL;
571 }
572 #endif
573
574 /* ====================== System ====================== */
575
576 /*
577 * Start a new thread named "name" with priority "prio" that will begin
578 * its execution in the function "thread()". The "arg" argument will be
579 * passed as an argument to the thread() function
580 */
sys_thread_new(const char * name,lwip_thread_fn thread,void * arg,int stacksize,int prio)581 sys_thread_t sys_thread_new(const char *name,
582 lwip_thread_fn thread,
583 void *arg,
584 int stacksize,
585 int prio)
586 {
587 rt_thread_t t;
588
589 RT_DEBUG_NOT_IN_INTERRUPT;
590
591 /* create thread */
592 t = rt_thread_create(name, thread, arg, stacksize, prio, 20);
593 RT_ASSERT(t != RT_NULL);
594
595 /* startup thread */
596 rt_thread_startup(t);
597
598 return t;
599 }
600
sys_arch_protect(void)601 sys_prot_t sys_arch_protect(void)
602 {
603 rt_base_t level;
604
605 /* disable interrupt */
606 level = rt_hw_interrupt_disable();
607
608 return level;
609 }
610
sys_arch_unprotect(sys_prot_t pval)611 void sys_arch_unprotect(sys_prot_t pval)
612 {
613 /* enable interrupt */
614 rt_hw_interrupt_enable(pval);
615
616 return;
617 }
618
sys_arch_assert(const char * file,int line)619 void sys_arch_assert(const char *file, int line)
620 {
621 rt_kprintf("\nAssertion: %d in %s, thread %s\n",
622 line, file, rt_thread_self()->name);
623 RT_ASSERT(0);
624 }
625
sys_jiffies(void)626 u32_t sys_jiffies(void)
627 {
628 return rt_tick_get();
629 }
630
sys_now(void)631 u32_t sys_now(void)
632 {
633 return rt_tick_get() * (1000 / RT_TICK_PER_SECOND);
634 }
635
636
637 RT_WEAK
mem_init(void)638 void mem_init(void)
639 {
640 }
641
mem_calloc(mem_size_t count,mem_size_t size)642 void *mem_calloc(mem_size_t count, mem_size_t size)
643 {
644 return rt_calloc(count, size);
645 }
646
mem_trim(void * mem,mem_size_t size)647 void *mem_trim(void *mem, mem_size_t size)
648 {
649 // return rt_realloc(mem, size);
650 /* not support trim yet */
651 return mem;
652 }
653
mem_malloc(mem_size_t size)654 void *mem_malloc(mem_size_t size)
655 {
656 return rt_malloc(size);
657 }
658
mem_free(void * mem)659 void mem_free(void *mem)
660 {
661 rt_free(mem);
662 }
663
664 #ifdef RT_LWIP_PPP
sio_read(sio_fd_t fd,u8_t * buf,u32_t size)665 u32_t sio_read(sio_fd_t fd, u8_t *buf, u32_t size)
666 {
667 u32_t len;
668
669 RT_ASSERT(fd != RT_NULL);
670
671 len = rt_device_read((rt_device_t)fd, 0, buf, size);
672 if (len <= 0)
673 return 0;
674
675 return len;
676 }
677
sio_write(sio_fd_t fd,u8_t * buf,u32_t size)678 u32_t sio_write(sio_fd_t fd, u8_t *buf, u32_t size)
679 {
680 RT_ASSERT(fd != RT_NULL);
681
682 return rt_device_write((rt_device_t)fd, 0, buf, size);
683 }
684
sio_read_abort(sio_fd_t fd)685 void sio_read_abort(sio_fd_t fd)
686 {
687 rt_kprintf("read_abort\n");
688 }
689
ppp_trace(int level,const char * format,...)690 void ppp_trace(int level, const char *format, ...)
691 {
692 va_list args;
693 rt_size_t length;
694 static char rt_log_buf[RT_CONSOLEBUF_SIZE];
695
696 va_start(args, format);
697 length = rt_vsprintf(rt_log_buf, format, args);
698 rt_device_write((rt_device_t)rt_console_get_device(), 0, rt_log_buf, length);
699 va_end(args);
700 }
701 #endif
702
703 /*
704 * export bsd socket symbol for RT-Thread Application Module
705 */
706 #if LWIP_SOCKET
707 #include <lwip/sockets.h>
708 RTM_EXPORT(lwip_accept);
709 RTM_EXPORT(lwip_bind);
710 RTM_EXPORT(lwip_shutdown);
711 RTM_EXPORT(lwip_getpeername);
712 RTM_EXPORT(lwip_getsockname);
713 RTM_EXPORT(lwip_getsockopt);
714 RTM_EXPORT(lwip_setsockopt);
715 RTM_EXPORT(lwip_close);
716 RTM_EXPORT(lwip_connect);
717 RTM_EXPORT(lwip_listen);
718 RTM_EXPORT(lwip_recv);
719 RTM_EXPORT(lwip_read);
720 RTM_EXPORT(lwip_recvfrom);
721 RTM_EXPORT(lwip_send);
722 RTM_EXPORT(lwip_sendto);
723 RTM_EXPORT(lwip_socket);
724 RTM_EXPORT(lwip_write);
725 RTM_EXPORT(lwip_select);
726 RTM_EXPORT(lwip_ioctl);
727 RTM_EXPORT(lwip_fcntl);
728
729 RTM_EXPORT(lwip_htons);
730 RTM_EXPORT(lwip_htonl);
731
732 #if LWIP_DNS
733 #include <lwip/netdb.h>
734 RTM_EXPORT(lwip_gethostbyname);
735 RTM_EXPORT(lwip_gethostbyname_r);
736 RTM_EXPORT(lwip_freeaddrinfo);
737 RTM_EXPORT(lwip_getaddrinfo);
738 #endif
739
740 #endif
741
742 #if LWIP_DHCP
743 #include <lwip/dhcp.h>
744 RTM_EXPORT(dhcp_start);
745 RTM_EXPORT(dhcp_renew);
746 RTM_EXPORT(dhcp_stop);
747 #endif
748
749 #if LWIP_NETIF_API
750 #include <lwip/netifapi.h>
751 RTM_EXPORT(netifapi_netif_set_addr);
752 #endif
753
754 #if LWIP_NETIF_LINK_CALLBACK
755 RTM_EXPORT(netif_set_link_callback);
756 #endif
757
758 #if LWIP_NETIF_STATUS_CALLBACK
759 RTM_EXPORT(netif_set_status_callback);
760 #endif
761
762 RTM_EXPORT(netif_find);
763 RTM_EXPORT(netif_set_addr);
764 RTM_EXPORT(netif_set_ipaddr);
765 RTM_EXPORT(netif_set_gw);
766 RTM_EXPORT(netif_set_netmask);
767