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