1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2010-07-07 Bernard fix send mail to mailbox issue.
9 * 2011-07-30 mbbill port lwIP 1.4.0 to RT-Thread
10 * 2012-04-10 Bernard add more compatible with RT-Thread.
11 * 2012-11-12 Bernard The network interface can be initialized
12 * after lwIP initialization.
13 * 2013-02-28 aozima fixed list_tcps bug: ipaddr_ntoa isn't reentrant.
14 * 2016-08-18 Bernard port to lwIP 2.0.0
15 * 2018-11-02 MurphyZhao port to lwIP 2.1.0
16 * 2021-09-07 Grissiom fix eth_tx_msg ack bug
17 * 2022-02-22 xiangxistu integrate v1.4.1 v2.0.3 and v2.1.2 porting layer
18 * 2024-09-12 Evlers add support for independent dns services for multiple network devices
19 */
20
21 /*
22 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
23 * All rights reserved.
24 *
25 * Redistribution and use in source and binary forms, with or without modification,
26 * are permitted provided that the following conditions are met:
27 *
28 * 1. Redistributions of source code must retain the above copyright notice,
29 * this list of conditions and the following disclaimer.
30 * 2. Redistributions in binary form must reproduce the above copyright notice,
31 * this list of conditions and the following disclaimer in the documentation
32 * and/or other materials provided with the distribution.
33 * 3. The name of the author may not be used to endorse or promote products
34 * derived from this software without specific prior written permission.
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
38 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
39 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
40 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
41 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
42 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
43 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
44 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
45 * OF SUCH DAMAGE.
46 *
47 * This file is part of the lwIP TCP/IP stack.
48 *
49 * Author: Adam Dunkels <adam@sics.se>
50 */
51
52 #include <string.h>
53
54 #include <lwip/init.h>
55 #include <lwip/opt.h>
56 #include <lwip/debug.h>
57 #include <lwip/def.h>
58 #include <lwip/mem.h>
59 #include <lwip/pbuf.h>
60 #include <lwip/sys.h>
61 #include <lwip/netif.h>
62 #include <lwip/stats.h>
63 #include <lwip/tcpip.h>
64 #include <lwip/dhcp.h>
65 #include <lwip/netifapi.h>
66 #include <lwip/inet.h>
67 #include <netif/etharp.h>
68 #include <netif/ethernetif.h>
69
70 #include <ipc/completion.h>
71
72 #if LWIP_IPV6
73 #include "lwip/ethip6.h"
74 #endif /* LWIP_IPV6 */
75
76 #if LWIP_NETIF_HOSTNAME
77 #define LWIP_HOSTNAME_LEN 16
78 #endif
79
80 #define netifapi_netif_set_link_up(n) netifapi_netif_common(n, netif_set_link_up, NULL)
81 #define netifapi_netif_set_link_down(n) netifapi_netif_common(n, netif_set_link_down, NULL)
82
83 #ifndef RT_LWIP_ETHTHREAD_PRIORITY
84 #define RT_ETHERNETIF_THREAD_PREORITY 0x90
85 #else
86 #define RT_ETHERNETIF_THREAD_PREORITY RT_LWIP_ETHTHREAD_PRIORITY
87 #endif
88
89 #ifndef LWIP_NO_TX_THREAD
90 /**
91 * Tx message structure for Ethernet interface
92 */
93 struct eth_tx_msg
94 {
95 struct netif *netif;
96 struct pbuf *buf;
97 struct rt_completion ack;
98 };
99
100 static struct rt_mailbox eth_tx_thread_mb;
101 static struct rt_thread eth_tx_thread;
102 #ifndef RT_LWIP_ETHTHREAD_MBOX_SIZE
103 static char eth_tx_thread_mb_pool[32 * sizeof(rt_ubase_t)];
104 static char eth_tx_thread_stack[512];
105 #else
106 static char eth_tx_thread_mb_pool[RT_LWIP_ETHTHREAD_MBOX_SIZE * sizeof(rt_ubase_t)];
107 static char eth_tx_thread_stack[RT_LWIP_ETHTHREAD_STACKSIZE];
108 #endif
109 #endif
110
111 #ifndef LWIP_NO_RX_THREAD
112 static struct rt_mailbox eth_rx_thread_mb;
113 static struct rt_thread eth_rx_thread;
114 #ifndef RT_LWIP_ETHTHREAD_MBOX_SIZE
115 static char eth_rx_thread_mb_pool[48 * sizeof(rt_ubase_t)];
116 static char eth_rx_thread_stack[1024];
117 #else
118 static char eth_rx_thread_mb_pool[RT_LWIP_ETHTHREAD_MBOX_SIZE * sizeof(rt_ubase_t)];
119 static char eth_rx_thread_stack[RT_LWIP_ETHTHREAD_STACKSIZE];
120 #endif
121 #endif
122
123 #ifdef RT_USING_NETDEV
124
125 #include "lwip/ip.h"
126 #include "lwip/init.h"
127 #include "lwip/netdb.h"
128 #include <netdev.h>
129
lwip_netdev_set_up(struct netdev * netif)130 static int lwip_netdev_set_up(struct netdev *netif)
131 {
132 netif_set_up((struct netif *)netif->user_data);
133 return ERR_OK;
134 }
135
lwip_netdev_set_down(struct netdev * netif)136 static int lwip_netdev_set_down(struct netdev *netif)
137 {
138 netif_set_down((struct netif *)netif->user_data);
139 return ERR_OK;
140 }
141
142 #ifndef ip_2_ip4
143 #define ip_2_ip4(ipaddr) (ipaddr)
144 #endif
lwip_netdev_set_addr_info(struct netdev * netif,ip_addr_t * ip_addr,ip_addr_t * netmask,ip_addr_t * gw)145 static int lwip_netdev_set_addr_info(struct netdev *netif, ip_addr_t *ip_addr, ip_addr_t *netmask, ip_addr_t *gw)
146 {
147 if (ip_addr && netmask && gw)
148 {
149 netif_set_addr((struct netif *)netif->user_data, ip_2_ip4(ip_addr), ip_2_ip4(netmask), ip_2_ip4(gw));
150 }
151 else
152 {
153 if (ip_addr)
154 {
155 netif_set_ipaddr((struct netif *)netif->user_data, ip_2_ip4(ip_addr));
156 }
157
158 if (netmask)
159 {
160 netif_set_netmask((struct netif *)netif->user_data, ip_2_ip4(netmask));
161 }
162
163 if (gw)
164 {
165 netif_set_gw((struct netif *)netif->user_data, ip_2_ip4(gw));
166 }
167 }
168
169 return ERR_OK;
170 }
171
172 #ifdef RT_LWIP_DNS
lwip_netdev_set_dns_server(struct netdev * netdev,uint8_t dns_num,ip_addr_t * dns_server)173 static int lwip_netdev_set_dns_server(struct netdev *netdev, uint8_t dns_num, ip_addr_t *dns_server)
174 {
175 #if RT_USING_LWIP_VER_NUM >= 0x20102
176 netdev_low_level_set_dns_server(netdev, dns_num, dns_server);
177 #else
178 #if LWIP_VERSION_MAJOR == 1U /* v1.x */
179 extern void dns_setserver(u8_t numdns, ip_addr_t *dnsserver);
180 #else /* >=2.x */
181 extern void dns_setserver(uint8_t dns_num, const ip_addr_t *dns_server);
182 #endif /* LWIP_VERSION_MAJOR == 1U */
183
184 dns_setserver(dns_num, dns_server);
185 #endif /* RT_USING_LWIP_VER_NUM >= 0x20102 */
186 return ERR_OK;
187 }
188 #endif /* RT_LWIP_DNS */
189
190 #ifdef RT_LWIP_DHCP
lwip_netdev_set_dhcp(struct netdev * netif,rt_bool_t is_enabled)191 static int lwip_netdev_set_dhcp(struct netdev *netif, rt_bool_t is_enabled)
192 {
193 netdev_low_level_set_dhcp_status(netif, is_enabled);
194
195 if(RT_TRUE == is_enabled)
196 {
197 dhcp_start((struct netif *)netif->user_data);
198 }
199 else
200 {
201 dhcp_stop((struct netif *)netif->user_data);
202 }
203
204 return ERR_OK;
205 }
206 #endif /* RT_LWIP_DHCP */
207
208 #ifdef RT_USING_FINSH
209 #ifdef RT_LWIP_USING_PING
210 extern int lwip_ping_recv(int s, int *ttl);
211 extern err_t lwip_ping_send(int s, ip_addr_t *addr, int size);
212
lwip_netdev_ping(struct netdev * netif,const char * host,size_t data_len,uint32_t timeout,struct netdev_ping_resp * ping_resp,rt_bool_t isbind)213 int lwip_netdev_ping(struct netdev *netif, const char *host, size_t data_len,
214 uint32_t timeout, struct netdev_ping_resp *ping_resp, rt_bool_t isbind)
215 {
216 int s, ttl, recv_len, result = 0;
217 int elapsed_time;
218 rt_tick_t recv_start_tick;
219 #if LWIP_VERSION_MAJOR == 1U /* v1.x */
220 int recv_timeout = timeout;
221 #else /* >= v2.x */
222 struct timeval recv_timeout = { timeout / 1000UL, timeout % 1000UL * 1000 };
223 #endif
224 ip_addr_t target_addr;
225 struct addrinfo hint, *res = RT_NULL;
226 struct sockaddr_in *h = RT_NULL;
227 struct in_addr ina;
228 struct sockaddr_in local;
229
230 RT_ASSERT(netif);
231 RT_ASSERT(host);
232 RT_ASSERT(ping_resp);
233
234 rt_memset(&hint, 0x00, sizeof(hint));
235 /* convert URL to IP */
236 if (lwip_getaddrinfo(host, RT_NULL, &hint, &res) != 0)
237 {
238 return -RT_ERROR;
239 }
240 SMEMCPY(&h, &res->ai_addr, sizeof(struct sockaddr_in *));
241 SMEMCPY(&ina, &h->sin_addr, sizeof(ina));
242 lwip_freeaddrinfo(res);
243 if (inet_aton(inet_ntoa(ina), &target_addr) == 0)
244 {
245 return -RT_ERROR;
246 }
247 SMEMCPY(&(ping_resp->ip_addr), &target_addr, sizeof(ip_addr_t));
248
249 /* new a socket */
250 if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0)
251 {
252 return -RT_ERROR;
253 }
254
255 local.sin_len = sizeof(local);
256 local.sin_family = AF_INET;
257 local.sin_port = 0;
258 #ifndef NETDEV_USING_IPV6
259 local.sin_addr.s_addr = (netif->ip_addr.addr);
260 #else
261 local.sin_addr.s_addr = (netif->ip_addr.u_addr.ip4.addr);
262 #endif
263 if (isbind) {
264 lwip_bind(s, (struct sockaddr *)&local, sizeof(struct sockaddr_in));
265 }
266
267 lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &recv_timeout, sizeof(recv_timeout));
268
269 if (lwip_ping_send(s, &target_addr, data_len) == ERR_OK)
270 {
271 recv_start_tick = rt_tick_get();
272 if ((recv_len = lwip_ping_recv(s, &ttl)) >= 0)
273 {
274 elapsed_time = (rt_tick_get() - recv_start_tick) * 1000UL / RT_TICK_PER_SECOND;
275 ping_resp->data_len = recv_len;
276 ping_resp->ttl = ttl;
277 ping_resp->ticks = elapsed_time;
278 }
279 else
280 {
281 result = -RT_ETIMEOUT;
282 goto __exit;
283 }
284 }
285 else
286 {
287 result = -RT_ETIMEOUT;
288 goto __exit;
289 }
290
291 __exit:
292 lwip_close(s);
293
294 return result;
295 }
296 #endif /* RT_LWIP_USING_PING */
297
298 #if defined (RT_LWIP_TCP) || defined (RT_LWIP_UDP)
lwip_netdev_netstat(struct netdev * netif)299 void lwip_netdev_netstat(struct netdev *netif)
300 {
301 extern void list_tcps(void);
302 extern void list_udps(void);
303
304 #ifdef RT_LWIP_TCP
305 list_tcps();
306 #endif
307 #ifdef RT_LWIP_UDP
308 list_udps();
309 #endif
310 }
311 #endif /* RT_LWIP_TCP || RT_LWIP_UDP */
312 #endif /* RT_USING_FINSH */
313
lwip_netdev_set_default(struct netdev * netif)314 static int lwip_netdev_set_default(struct netdev *netif)
315 {
316 netif_set_default((struct netif *)netif->user_data);
317 return ERR_OK;
318 }
319
320 const struct netdev_ops lwip_netdev_ops =
321 {
322 lwip_netdev_set_up,
323 lwip_netdev_set_down,
324
325 lwip_netdev_set_addr_info,
326 #ifdef RT_LWIP_DNS
327 lwip_netdev_set_dns_server,
328 #else
329 NULL,
330 #endif /* RT_LWIP_DNS */
331
332 #ifdef RT_LWIP_DHCP
333 lwip_netdev_set_dhcp,
334 #else
335 NULL,
336 #endif /* RT_LWIP_DHCP */
337
338 #ifdef RT_USING_FINSH
339 #ifdef RT_LWIP_USING_PING
340 lwip_netdev_ping,
341 #else
342 NULL,
343 #endif /* RT_LWIP_USING_PING */
344
345 #if defined (RT_LWIP_TCP) || defined (RT_LWIP_UDP)
346 lwip_netdev_netstat,
347 #endif /* RT_LWIP_TCP || RT_LWIP_UDP */
348 #endif /* RT_USING_FINSH */
349
350 lwip_netdev_set_default,
351 };
352
353 /* synchronize lwIP network interface device and network interface device flags */
netdev_flags_sync(struct netif * lwip_netif)354 static int netdev_flags_sync(struct netif *lwip_netif)
355 {
356 struct netdev *netdev = NULL;
357
358 RT_ASSERT(lwip_netif);
359
360 netdev = netdev_get_by_name(lwip_netif->name);
361 if (netdev == RT_NULL)
362 {
363 return -ERR_IF;
364 }
365
366 netdev->mtu = lwip_netif->mtu;
367
368 /* the macro definition is different from lwip-1.4.1 and lwip-2.x.x about 'flags'. */
369 if(lwip_netif->flags & NETIF_FLAG_BROADCAST)
370 {
371 netdev->flags |= NETDEV_FLAG_BROADCAST;
372 }
373 if(lwip_netif->flags & NETIF_FLAG_ETHARP)
374 {
375 netdev->flags |= NETDEV_FLAG_ETHARP;
376 }
377 if(lwip_netif->flags & NETIF_FLAG_IGMP)
378 {
379 netdev->flags |= NETDEV_FLAG_IGMP;
380 }
381 #if LWIP_VERSION_MAJOR >= 2U /* >= v2.x */
382 if(lwip_netif->flags & NETIF_FLAG_MLD6)
383 {
384 netdev->flags |= NETDEV_FLAG_MLD6;
385 }
386 #endif /* LWIP_VERSION_MAJOR >= 2U */
387
388 #if LWIP_DHCP
389 netdev_low_level_set_dhcp_status(netdev, RT_TRUE);
390 #else
391 netdev_low_level_set_dhcp_status(netdev, RT_FALSE);
392 #endif
393
394 return ERR_OK;
395 }
396
netdev_add(struct netif * lwip_netif)397 static int netdev_add(struct netif *lwip_netif)
398 {
399 int result = 0;
400 struct netdev *netdev = RT_NULL;
401 char name[NETIF_NAMESIZE] = {0};
402
403 RT_ASSERT(lwip_netif);
404
405 netdev = (struct netdev *)rt_calloc(1, sizeof(struct netdev));
406 if (netdev == RT_NULL)
407 {
408 return -ERR_IF;
409 }
410
411 #ifdef SAL_USING_LWIP
412 extern int sal_lwip_netdev_set_pf_info(struct netdev *netdev);
413 /* set the lwIP network interface device protocol family information */
414 sal_lwip_netdev_set_pf_info(netdev);
415 #endif /* SAL_USING_LWIP */
416
417 rt_strncpy(name, lwip_netif->name, NETIF_NAMESIZE);
418 result = netdev_register(netdev, name, (void *)lwip_netif);
419
420 /* Update netdev info after registered */
421 netdev_flags_sync(lwip_netif);
422 netdev->ops = &lwip_netdev_ops;
423 netdev->hwaddr_len = lwip_netif->hwaddr_len;
424 SMEMCPY(netdev->hwaddr, lwip_netif->hwaddr, lwip_netif->hwaddr_len);
425 netdev->ip_addr = lwip_netif->ip_addr;
426 netdev->gw = lwip_netif->gw;
427 netdev->netmask = lwip_netif->netmask;
428
429 #ifdef NETDEV_USING_LINK_STATUS_CALLBACK
430 extern void netdev_status_change(struct netdev *netdev, enum netdev_cb_type type);
431 netdev_set_status_callback(netdev, netdev_status_change);
432 #endif
433
434 return result;
435 }
436
netdev_del(struct netif * lwip_netif)437 static void netdev_del(struct netif *lwip_netif)
438 {
439 char name[NETIF_NAMESIZE];
440 struct netdev *netdev;
441
442 RT_ASSERT(lwip_netif);
443
444 rt_strncpy(name, lwip_netif->name, NETIF_NAMESIZE);
445 netdev = netdev_get_by_name(name);
446 netdev_unregister(netdev);
447 rt_free(netdev);
448 }
449 #endif /* RT_USING_NETDEV */
450
ethernetif_linkoutput(struct netif * netif,struct pbuf * p)451 static err_t ethernetif_linkoutput(struct netif *netif, struct pbuf *p)
452 {
453 #ifndef LWIP_NO_TX_THREAD
454 struct eth_tx_msg msg;
455
456 RT_ASSERT(netif != RT_NULL);
457
458 /* send a message to eth tx thread */
459 msg.netif = netif;
460 msg.buf = p;
461 rt_completion_init(&msg.ack);
462 if (rt_mb_send(ð_tx_thread_mb, (rt_ubase_t) &msg) == RT_EOK)
463 {
464 /* waiting for ack */
465 rt_completion_wait(&msg.ack, RT_WAITING_FOREVER);
466 }
467 #else
468 struct eth_device* enetif;
469
470 RT_ASSERT(netif != RT_NULL);
471 enetif = (struct eth_device*)netif->state;
472
473 if (enetif->eth_tx(&(enetif->parent), p) != RT_EOK)
474 {
475 return ERR_IF;
476 }
477 #endif
478 return ERR_OK;
479 }
480
eth_netif_device_init(struct netif * netif)481 static err_t eth_netif_device_init(struct netif *netif)
482 {
483 struct eth_device *ethif;
484
485 ethif = (struct eth_device*)netif->state;
486 if (ethif != RT_NULL)
487 {
488 rt_device_t device;
489
490 #ifdef RT_USING_NETDEV
491 /* network interface device register */
492 netdev_add(netif);
493 #endif /* RT_USING_NETDEV */
494
495 /* get device object */
496 device = (rt_device_t) ethif;
497 if (rt_device_init(device) != RT_EOK)
498 {
499 return ERR_IF;
500 }
501 if (rt_device_open(device, RT_DEVICE_FLAG_RDWR) != RT_EOK)
502 {
503 return ERR_IF;
504 }
505
506 /* copy device flags to netif flags */
507 netif->flags = (ethif->flags & 0xff);
508 netif->mtu = ETHERNET_MTU;
509
510 /* set output */
511 netif->output = etharp_output;
512
513 #if LWIP_IPV6
514 netif->output_ip6 = ethip6_output;
515 netif->ip6_autoconfig_enabled = 1;
516 netif_create_ip6_linklocal_address(netif, 1);
517
518 #if LWIP_IPV6_MLD
519 netif->flags |= NETIF_FLAG_MLD6;
520
521 /*
522 * For hardware/netifs that implement MAC filtering.
523 * All-nodes link-local is handled by default, so we must let the hardware know
524 * to allow multicast packets in.
525 * Should set mld_mac_filter previously. */
526 if (netif->mld_mac_filter != NULL)
527 {
528 ip6_addr_t ip6_allnodes_ll;
529 ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll);
530 netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER);
531 }
532 #endif /* LWIP_IPV6_MLD */
533
534 #endif /* LWIP_IPV6 */
535
536 /* set default netif */
537 if (netif_default == RT_NULL)
538 netif_set_default(netif);
539
540 /* set interface up */
541 netif_set_up(netif);
542
543 #if LWIP_DHCP
544 /* if this interface uses DHCP, start the DHCP client */
545 dhcp_start(netif);
546 #endif
547
548 if (ethif->flags & ETHIF_LINK_PHYUP)
549 {
550 /* set link_up for this netif */
551 netif_set_link_up(netif);
552 }
553
554 #ifdef RT_USING_NETDEV
555 /* network interface device flags synchronize */
556 netdev_flags_sync(netif);
557 #endif /* RT_USING_NETDEV */
558
559 return ERR_OK;
560 }
561
562 return ERR_IF;
563 }
564
565 /* Keep old drivers compatible in RT-Thread */
eth_device_init_with_flag(struct eth_device * dev,const char * name,rt_uint16_t flags)566 rt_err_t eth_device_init_with_flag(struct eth_device *dev, const char *name, rt_uint16_t flags)
567 {
568 struct netif* netif;
569 #if LWIP_NETIF_HOSTNAME
570 char *hostname = RT_NULL;
571 netif = (struct netif*) rt_calloc (1, sizeof(struct netif) + LWIP_HOSTNAME_LEN);
572 #else
573 netif = (struct netif*) rt_calloc (1, sizeof(struct netif));
574 #endif
575 if (netif == RT_NULL)
576 {
577 rt_kprintf("malloc netif failed\n");
578 return -RT_ERROR;
579 }
580
581 rt_spin_lock_init(&(dev->spinlock));
582 /* set netif */
583 dev->netif = netif;
584 dev->flags = flags;
585 /* link changed status of device */
586 dev->link_changed = 0x00;
587 /* avoid send the same mail to mailbox */
588 dev->rx_notice = 0x00;
589 dev->parent.type = RT_Device_Class_NetIf;
590 /* register to RT-Thread device manager */
591 rt_device_register(&(dev->parent), name, RT_DEVICE_FLAG_RDWR);
592
593 /* set name */
594 rt_strncpy(netif->name, name, NETIF_NAMESIZE);
595
596 /* set hw address to 6 */
597 netif->hwaddr_len = 6;
598 /* maximum transfer unit */
599 netif->mtu = ETHERNET_MTU;
600
601 /* set linkoutput */
602 netif->linkoutput = ethernetif_linkoutput;
603
604 /* get hardware MAC address */
605 rt_device_control(&(dev->parent), NIOCTL_GADDR, netif->hwaddr);
606
607 #if LWIP_NETIF_HOSTNAME
608 /* Initialize interface hostname */
609 hostname = (char *)netif + sizeof(struct netif);
610 rt_sprintf(hostname, "rtthread_%02x%02x", name[0], name[1]);
611 netif->hostname = hostname;
612 #endif /* LWIP_NETIF_HOSTNAME */
613
614 /* if tcp thread has been started up, we add this netif to the system */
615 if (rt_thread_find("tcpip") != RT_NULL)
616 {
617 #if LWIP_VERSION_MAJOR == 1U /* v1.x */
618 struct ip_addr ipaddr, netmask, gw;
619 #else /* >= v2.x */
620 ip4_addr_t ipaddr, netmask, gw;
621 #endif /* LWIP_VERSION_MAJOR == 1U */
622
623 #if !LWIP_DHCP
624 ipaddr.addr = inet_addr(RT_LWIP_IPADDR);
625 gw.addr = inet_addr(RT_LWIP_GWADDR);
626 netmask.addr = inet_addr(RT_LWIP_MSKADDR);
627 #else
628 IP4_ADDR(&ipaddr, 0, 0, 0, 0);
629 IP4_ADDR(&gw, 0, 0, 0, 0);
630 IP4_ADDR(&netmask, 0, 0, 0, 0);
631 #endif
632 netifapi_netif_add(netif, &ipaddr, &netmask, &gw, dev, eth_netif_device_init, tcpip_input);
633 }
634
635 return RT_EOK;
636 }
637
eth_device_init(struct eth_device * dev,const char * name)638 rt_err_t eth_device_init(struct eth_device * dev, const char *name)
639 {
640 rt_uint16_t flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
641
642 #if LWIP_IGMP
643 /* IGMP support */
644 flags |= NETIF_FLAG_IGMP;
645 #endif
646
647 return eth_device_init_with_flag(dev, name, flags);
648 }
649
eth_device_deinit(struct eth_device * dev)650 void eth_device_deinit(struct eth_device *dev)
651 {
652 struct netif* netif = dev->netif;
653
654 #if LWIP_DHCP
655 dhcp_stop(netif);
656 dhcp_cleanup(netif);
657 #endif
658 netif_set_down(netif);
659 netif_remove(netif);
660 #ifdef RT_USING_NETDEV
661 netdev_del(netif);
662 #endif
663 rt_device_close(&(dev->parent));
664 rt_device_unregister(&(dev->parent));
665 rt_free(netif);
666 }
667
668 #ifdef SAL_USING_AF_UNIX /* create loopback netdev */
af_unix_eth_netif_device_init(struct netif * netif)669 static err_t af_unix_eth_netif_device_init(struct netif *netif)
670 {
671 struct eth_device *ethif;
672
673 ethif = (struct eth_device*)netif->state;
674 if (ethif != RT_NULL)
675 {
676 rt_device_t device;
677
678 #ifdef RT_USING_NETDEV
679 /* network interface device register */
680 netdev_add(netif);
681 #endif /* RT_USING_NETDEV */
682
683 /* get device object */
684 device = (rt_device_t) ethif;
685 if (rt_device_init(device) != RT_EOK)
686 {
687 return ERR_IF;
688 }
689 if (rt_device_open(device, RT_DEVICE_FLAG_RDWR) != RT_EOK)
690 {
691 return ERR_IF;
692 }
693
694 /* copy device flags to netif flags */
695 netif->flags = (ethif->flags & 0xff);
696 netif->mtu = ETHERNET_MTU;
697
698 /* set output */
699 netif->output = etharp_output;
700
701 #if LWIP_IPV6
702 netif->output_ip6 = ethip6_output;
703 netif->ip6_autoconfig_enabled = 1;
704 netif_create_ip6_linklocal_address(netif, 1);
705
706 #if LWIP_IPV6_MLD
707 netif->flags |= NETIF_FLAG_MLD6;
708
709 /*
710 * For hardware/netifs that implement MAC filtering.
711 * All-nodes link-local is handled by default, so we must let the hardware know
712 * to allow multicast packets in.
713 * Should set mld_mac_filter previously. */
714 if (netif->mld_mac_filter != NULL)
715 {
716 ip6_addr_t ip6_allnodes_ll;
717 ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll);
718 netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER);
719 }
720 #endif /* LWIP_IPV6_MLD */
721
722 #endif /* LWIP_IPV6 */
723
724 /* set default netif */
725 if (netif_default == RT_NULL)
726 netif_set_default(netif);
727
728 /* set interface up */
729 netif_set_up(netif);
730
731 if (ethif->flags & ETHIF_LINK_PHYUP)
732 {
733 /* set link_up for this netif */
734 netif_set_link_up(netif);
735 }
736
737 #ifdef RT_USING_NETDEV
738 /* network interface device flags synchronize */
739 netdev_flags_sync(netif);
740 #endif /* RT_USING_NETDEV */
741
742 return ERR_OK;
743 }
744
745 return ERR_IF;
746 }
747
748 /* Keep old drivers compatible in RT-Thread */
af_unix_eth_device_init_with_flag(struct eth_device * dev,const char * name,rt_uint16_t flags)749 rt_err_t af_unix_eth_device_init_with_flag(struct eth_device *dev, const char *name, rt_uint16_t flags)
750 {
751 struct netif* netif;
752 #if LWIP_NETIF_HOSTNAME
753 char *hostname = RT_NULL;
754 netif = (struct netif*) rt_calloc (1, sizeof(struct netif) + LWIP_HOSTNAME_LEN);
755 #else
756 netif = (struct netif*) rt_calloc (1, sizeof(struct netif));
757 #endif
758 if (netif == RT_NULL)
759 {
760 rt_kprintf("malloc netif failed\n");
761 return -RT_ERROR;
762 }
763
764 /* set netif */
765 dev->netif = netif;
766 dev->flags = flags;
767 /* link changed status of device */
768 dev->link_changed = 0x00;
769 /* avoid send the same mail to mailbox */
770 dev->rx_notice = 0x00;
771 dev->parent.type = RT_Device_Class_NetIf;
772 /* register to RT-Thread device manager */
773 rt_device_register(&(dev->parent), name, RT_DEVICE_FLAG_RDWR);
774
775 /* set name */
776 netif->name[0] = name[0];
777 netif->name[1] = name[1];
778
779 /* set hw address to 6 */
780 netif->hwaddr_len = 6;
781 /* maximum transfer unit */
782 netif->mtu = ETHERNET_MTU;
783
784 /* set linkoutput */
785 netif->linkoutput = ethernetif_linkoutput;
786
787 /* get hardware MAC address */
788 rt_device_control(&(dev->parent), NIOCTL_GADDR, netif->hwaddr);
789
790 #if LWIP_NETIF_HOSTNAME
791 /* Initialize interface hostname */
792 hostname = (char *)netif + sizeof(struct netif);
793 rt_sprintf(hostname, "rtthread_%02x%02x", name[0], name[1]);
794 netif->hostname = hostname;
795 #endif /* LWIP_NETIF_HOSTNAME */
796
797 /* if tcp thread has been started up, we add this netif to the system */
798 if (rt_thread_find("tcpip") != RT_NULL)
799 {
800 #if LWIP_VERSION_MAJOR == 1U /* v1.x */
801 struct ip_addr ipaddr, netmask, gw;
802 #else /* >= v2.x */
803 ip4_addr_t ipaddr, netmask, gw;
804 #endif /* LWIP_VERSION_MAJOR == 1U */
805
806 ipaddr.addr = inet_addr("127.0.0.1");
807 gw.addr = inet_addr("255.0.0.0");
808 netmask.addr = inet_addr("127.0.0.1");
809
810 netifapi_netif_add(netif, &ipaddr, &netmask, &gw, dev, af_unix_eth_netif_device_init, tcpip_input);
811 }
812
813 return RT_EOK;
814 }
815
af_unix_eth_device_init(struct eth_device * dev,const char * name)816 rt_err_t af_unix_eth_device_init(struct eth_device * dev, const char *name)
817 {
818 rt_uint16_t flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
819
820 #if LWIP_IGMP
821 /* IGMP support */
822 flags |= NETIF_FLAG_IGMP;
823 #endif
824
825 return af_unix_eth_device_init_with_flag(dev, name, flags);
826 }
827 #endif /* SAL_USING_AF_UNIX */
828
829 #ifndef LWIP_NO_RX_THREAD
eth_device_ready(struct eth_device * dev)830 rt_err_t eth_device_ready(struct eth_device* dev)
831 {
832 if (dev->netif)
833 {
834 if(dev->rx_notice == RT_FALSE)
835 {
836 dev->rx_notice = RT_TRUE;
837 return rt_mb_send(ð_rx_thread_mb, (rt_ubase_t)dev);
838 }
839 else
840 return RT_EOK;
841 /* post message to Ethernet thread */
842 }
843 else
844 return -RT_ERROR; /* netif is not initialized yet, just return. */
845 }
846
eth_device_linkchange(struct eth_device * dev,rt_bool_t up)847 rt_err_t eth_device_linkchange(struct eth_device* dev, rt_bool_t up)
848 {
849 rt_base_t level;
850
851 RT_ASSERT(dev != RT_NULL);
852
853 level = rt_spin_lock_irqsave(&(dev->spinlock));
854 dev->link_changed = 0x01;
855 if (up == RT_TRUE)
856 dev->link_status = 0x01;
857 else
858 dev->link_status = 0x00;
859 rt_spin_unlock_irqrestore(&(dev->spinlock), level);
860
861 /* post message to ethernet thread */
862 return rt_mb_send(ð_rx_thread_mb, (rt_ubase_t)dev);
863 }
864 #else
865 /* NOTE: please not use it in interrupt when no RxThread exist */
eth_device_linkchange(struct eth_device * dev,rt_bool_t up)866 rt_err_t eth_device_linkchange(struct eth_device* dev, rt_bool_t up)
867 {
868 if (up == RT_TRUE)
869 netifapi_netif_set_link_up(dev->netif);
870 else
871 netifapi_netif_set_link_down(dev->netif);
872
873 return RT_EOK;
874 }
875 #endif
876
877 #ifndef LWIP_NO_TX_THREAD
878 /* Ethernet Tx Thread */
eth_tx_thread_entry(void * parameter)879 static void eth_tx_thread_entry(void* parameter)
880 {
881 struct eth_tx_msg* msg;
882
883 while (1)
884 {
885 if (rt_mb_recv(ð_tx_thread_mb, (rt_ubase_t *)&msg, RT_WAITING_FOREVER) == RT_EOK)
886 {
887 struct eth_device* enetif;
888
889 RT_ASSERT(msg->netif != RT_NULL);
890 RT_ASSERT(msg->buf != RT_NULL);
891
892 enetif = (struct eth_device*)msg->netif->state;
893 if (enetif != RT_NULL)
894 {
895 /* call driver's interface */
896 if (enetif->eth_tx(&(enetif->parent), msg->buf) != RT_EOK)
897 {
898 /* transmit eth packet failed */
899 }
900 }
901
902 /* send ACK */
903 rt_completion_done(&msg->ack);
904 }
905 }
906 }
907 #endif
908
909 #ifndef LWIP_NO_RX_THREAD
910 /* Ethernet Rx Thread */
eth_rx_thread_entry(void * parameter)911 static void eth_rx_thread_entry(void* parameter)
912 {
913 struct eth_device* device;
914
915 while (1)
916 {
917 if (rt_mb_recv(ð_rx_thread_mb, (rt_ubase_t *)&device, RT_WAITING_FOREVER) == RT_EOK)
918 {
919 rt_base_t level;
920 struct pbuf *p;
921
922 /* check link status */
923 if (device->link_changed)
924 {
925 int status;
926
927 level = rt_spin_lock_irqsave(&(device->spinlock));
928 status = device->link_status;
929 device->link_changed = 0x00;
930 rt_spin_unlock_irqrestore(&(device->spinlock), level);
931
932 if (status)
933 netifapi_netif_set_link_up(device->netif);
934 else
935 netifapi_netif_set_link_down(device->netif);
936 }
937
938 level = rt_spin_lock_irqsave(&(device->spinlock));
939 /* 'rx_notice' will be modify in the interrupt or here */
940 device->rx_notice = RT_FALSE;
941 rt_spin_unlock_irqrestore(&(device->spinlock), level);
942
943 /* receive all of buffer */
944 while (1)
945 {
946 if(device->eth_rx == RT_NULL) break;
947
948 p = device->eth_rx(&(device->parent));
949 if (p != RT_NULL)
950 {
951 /* notify to upper layer */
952 if( device->netif->input(p, device->netif) != ERR_OK )
953 {
954 LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: Input error\n"));
955 pbuf_free(p);
956 p = NULL;
957 }
958 }
959 else break;
960 }
961 }
962 else
963 {
964 LWIP_ASSERT("Should not happen!\n",0);
965 }
966 }
967 }
968 #endif
969
970 /* this function does not need,
971 * use eth_system_device_init_private()
972 * call by lwip_system_init().
973 */
eth_system_device_init(void)974 int eth_system_device_init(void)
975 {
976 return 0;
977 }
978
eth_system_device_init_private(void)979 int eth_system_device_init_private(void)
980 {
981 rt_err_t result = RT_EOK;
982
983 /* initialize Rx thread. */
984 #ifndef LWIP_NO_RX_THREAD
985 /* initialize mailbox and create Ethernet Rx thread */
986 result = rt_mb_init(ð_rx_thread_mb, "erxmb",
987 ð_rx_thread_mb_pool[0], sizeof(eth_rx_thread_mb_pool)/sizeof(rt_ubase_t),
988 RT_IPC_FLAG_FIFO);
989 RT_ASSERT(result == RT_EOK);
990
991 result = rt_thread_init(ð_rx_thread, "erx", eth_rx_thread_entry, RT_NULL,
992 ð_rx_thread_stack[0], sizeof(eth_rx_thread_stack),
993 RT_ETHERNETIF_THREAD_PREORITY, 16);
994 RT_ASSERT(result == RT_EOK);
995 result = rt_thread_startup(ð_rx_thread);
996 RT_ASSERT(result == RT_EOK);
997 #endif
998
999 /* initialize Tx thread */
1000 #ifndef LWIP_NO_TX_THREAD
1001 /* initialize mailbox and create Ethernet Tx thread */
1002 result = rt_mb_init(ð_tx_thread_mb, "etxmb",
1003 ð_tx_thread_mb_pool[0], sizeof(eth_tx_thread_mb_pool)/sizeof(rt_ubase_t),
1004 RT_IPC_FLAG_FIFO);
1005 RT_ASSERT(result == RT_EOK);
1006
1007 result = rt_thread_init(ð_tx_thread, "etx", eth_tx_thread_entry, RT_NULL,
1008 ð_tx_thread_stack[0], sizeof(eth_tx_thread_stack),
1009 RT_ETHERNETIF_THREAD_PREORITY, 16);
1010 RT_ASSERT(result == RT_EOK);
1011
1012 result = rt_thread_startup(ð_tx_thread);
1013 RT_ASSERT(result == RT_EOK);
1014 #endif
1015
1016 return (int)result;
1017 }
1018
set_if(char * netif_name,char * ip_addr,char * gw_addr,char * nm_addr)1019 void set_if(char* netif_name, char* ip_addr, char* gw_addr, char* nm_addr)
1020 {
1021 #if LWIP_VERSION_MAJOR == 1U /* v1.x */
1022 struct ip_addr *ip;
1023 struct ip_addr addr;
1024 #else /* >= v2.x */
1025 ip4_addr_t *ip;
1026 ip4_addr_t addr;
1027 #endif /* LWIP_VERSION_MAJOR == 1U */
1028
1029 struct netif * netif = netif_list;
1030
1031 if(strlen(netif_name) > sizeof(netif->name))
1032 {
1033 rt_kprintf("network interface name too long!\r\n");
1034 return;
1035 }
1036
1037 while(netif != RT_NULL)
1038 {
1039 if(strncmp(netif_name, netif->name, sizeof(netif->name)) == 0)
1040 break;
1041
1042 netif = netif->next;
1043 if( netif == RT_NULL )
1044 {
1045 rt_kprintf("network interface: %s not found!\r\n", netif_name);
1046 return;
1047 }
1048 }
1049
1050 #if LWIP_VERSION_MAJOR == 1U /* v1.x */
1051 ip = (struct ip_addr *)&addr;
1052 #else /* >= v2.x */
1053 ip = (ip4_addr_t *)&addr;
1054 #endif /* LWIP_VERSION_MAJOR == 1U */
1055
1056
1057 /* set ip address */
1058 if ((ip_addr != RT_NULL) && inet_aton(ip_addr, &addr))
1059 {
1060 netif_set_ipaddr(netif, ip);
1061 }
1062
1063 /* set gateway address */
1064 if ((gw_addr != RT_NULL) && inet_aton(gw_addr, &addr))
1065 {
1066 netif_set_gw(netif, ip);
1067 }
1068
1069 /* set netmask address */
1070 if ((nm_addr != RT_NULL) && inet_aton(nm_addr, &addr))
1071 {
1072 netif_set_netmask(netif, ip);
1073 }
1074 }
1075
1076 #ifdef RT_USING_FINSH
1077 #include <finsh.h>
1078 FINSH_FUNCTION_EXPORT(set_if, set network interface address);
1079
1080 #if LWIP_DNS
1081 #include <lwip/dns.h>
set_dns(uint8_t dns_num,char * dns_server)1082 void set_dns(uint8_t dns_num, char* dns_server)
1083 {
1084 ip_addr_t addr;
1085
1086 if ((dns_server != RT_NULL) && ipaddr_aton(dns_server, &addr))
1087 {
1088 dns_setserver(dns_num, &addr);
1089 }
1090 }
1091 FINSH_FUNCTION_EXPORT(set_dns, set DNS server address);
1092 #endif
1093
list_if(void)1094 void list_if(void)
1095 {
1096 rt_uint8_t index;
1097 struct netif * netif;
1098
1099 rt_enter_critical();
1100
1101 netif = netif_list;
1102
1103 while( netif != RT_NULL )
1104 {
1105 rt_kprintf("network interface: %c%c%s\n",
1106 netif->name[0],
1107 netif->name[1],
1108 (netif == netif_default)?" (Default)":"");
1109 rt_kprintf("MTU: %d\n", netif->mtu);
1110 rt_kprintf("MAC: ");
1111 for (index = 0; index < netif->hwaddr_len; index ++)
1112 rt_kprintf("%02x ", netif->hwaddr[index]);
1113 rt_kprintf("\nFLAGS:");
1114 if (netif->flags & NETIF_FLAG_UP) rt_kprintf(" UP");
1115 else rt_kprintf(" DOWN");
1116 if (netif->flags & NETIF_FLAG_LINK_UP) rt_kprintf(" LINK_UP");
1117 else rt_kprintf(" LINK_DOWN");
1118 if (netif->flags & NETIF_FLAG_ETHARP) rt_kprintf(" ETHARP");
1119 if (netif->flags & NETIF_FLAG_BROADCAST) rt_kprintf(" BROADCAST");
1120 if (netif->flags & NETIF_FLAG_IGMP) rt_kprintf(" IGMP");
1121 rt_kprintf("\n");
1122 rt_kprintf("ip address: %s\n", ipaddr_ntoa(&(netif->ip_addr)));
1123 rt_kprintf("gw address: %s\n", ipaddr_ntoa(&(netif->gw)));
1124 rt_kprintf("net mask : %s\n", ipaddr_ntoa(&(netif->netmask)));
1125 #if LWIP_IPV6
1126 {
1127 ip6_addr_t *addr;
1128 int addr_state;
1129 int i;
1130
1131 addr = (ip6_addr_t *)&netif->ip6_addr[0];
1132 addr_state = netif->ip6_addr_state[0];
1133
1134 rt_kprintf("\nipv6 link-local: %s state:%02X %s\n", ip6addr_ntoa(addr),
1135 addr_state, ip6_addr_isvalid(addr_state)?"VALID":"INVALID");
1136
1137 for(i=1; i<LWIP_IPV6_NUM_ADDRESSES; i++)
1138 {
1139 addr = (ip6_addr_t *)&netif->ip6_addr[i];
1140 addr_state = netif->ip6_addr_state[i];
1141
1142 rt_kprintf("ipv6[%d] address: %s state:%02X %s\n", i, ip6addr_ntoa(addr),
1143 addr_state, ip6_addr_isvalid(addr_state)?"VALID":"INVALID");
1144 }
1145
1146 }
1147 rt_kprintf("\r\n");
1148 #endif /* LWIP_IPV6 */
1149 netif = netif->next;
1150 }
1151
1152 #if LWIP_DNS
1153 {
1154 #if LWIP_VERSION_MAJOR == 1U /* v1.x */
1155 struct ip_addr ip_addr;
1156
1157 for(index=0; index<DNS_MAX_SERVERS; index++)
1158 {
1159 ip_addr = dns_getserver(index);
1160 rt_kprintf("dns server #%d: %s\n", index, ipaddr_ntoa(&(ip_addr)));
1161 }
1162 #else /* >= v2.x */
1163 const ip_addr_t *ip_addr;
1164
1165 for(index=0; index<DNS_MAX_SERVERS; index++)
1166 {
1167 ip_addr = dns_getserver(index);
1168 rt_kprintf("dns server #%d: %s\n", index, inet_ntoa(ip_addr));
1169 }
1170 #endif /* LWIP_VERSION_MAJOR == 1U */
1171
1172 }
1173 #endif /**< #if LWIP_DNS */
1174
1175 rt_exit_critical();
1176 }
1177 FINSH_FUNCTION_EXPORT(list_if, list network interface information);
1178
1179 #if LWIP_TCP
1180 #include <lwip/tcp.h>
1181 #if LWIP_VERSION_MAJOR == 1U /* v1.x */
1182 #include <lwip/tcp_impl.h>
1183 #else /* >= v2.x */
1184 #include <lwip/priv/tcp_priv.h>
1185 #endif /* LWIP_VERSION_MAJOR == 1U */
1186
list_tcps(void)1187 void list_tcps(void)
1188 {
1189 rt_uint32_t num = 0;
1190 struct tcp_pcb *pcb;
1191 char local_ip_str[16];
1192 char remote_ip_str[16];
1193
1194 extern struct tcp_pcb *tcp_active_pcbs;
1195 extern union tcp_listen_pcbs_t tcp_listen_pcbs;
1196 extern struct tcp_pcb *tcp_tw_pcbs;
1197
1198 rt_enter_critical();
1199 rt_kprintf("Active PCB states:\n");
1200 for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next)
1201 {
1202 strcpy(local_ip_str, ipaddr_ntoa(&(pcb->local_ip)));
1203 strcpy(remote_ip_str, ipaddr_ntoa(&(pcb->remote_ip)));
1204
1205 rt_kprintf("#%d %s:%d <==> %s:%d snd_nxt 0x%08X rcv_nxt 0x%08X ",
1206 num++,
1207 local_ip_str,
1208 pcb->local_port,
1209 remote_ip_str,
1210 pcb->remote_port,
1211 pcb->snd_nxt,
1212 pcb->rcv_nxt);
1213 rt_kprintf("state: %s\n", tcp_debug_state_str(pcb->state));
1214 }
1215
1216 rt_kprintf("Listen PCB states:\n");
1217 num = 0;
1218 for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next)
1219 {
1220 rt_kprintf("#%d local port %d ", num++, pcb->local_port);
1221 rt_kprintf("state: %s\n", tcp_debug_state_str(pcb->state));
1222 }
1223
1224 rt_kprintf("TIME-WAIT PCB states:\n");
1225 num = 0;
1226 for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next)
1227 {
1228 strcpy(local_ip_str, ipaddr_ntoa(&(pcb->local_ip)));
1229 strcpy(remote_ip_str, ipaddr_ntoa(&(pcb->remote_ip)));
1230
1231 rt_kprintf("#%d %s:%d <==> %s:%d snd_nxt 0x%08X rcv_nxt 0x%08X ",
1232 num++,
1233 local_ip_str,
1234 pcb->local_port,
1235 remote_ip_str,
1236 pcb->remote_port,
1237 pcb->snd_nxt,
1238 pcb->rcv_nxt);
1239 rt_kprintf("state: %s\n", tcp_debug_state_str(pcb->state));
1240 }
1241 rt_exit_critical();
1242 }
1243 FINSH_FUNCTION_EXPORT(list_tcps, list all of tcp connections);
1244 #endif /* LWIP_TCP */
1245
1246 #if LWIP_UDP
1247 #include "lwip/udp.h"
list_udps(void)1248 void list_udps(void)
1249 {
1250 struct udp_pcb *pcb;
1251 rt_uint32_t num = 0;
1252 char local_ip_str[16];
1253 char remote_ip_str[16];
1254
1255 rt_enter_critical();
1256 rt_kprintf("Active UDP PCB states:\n");
1257 for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next)
1258 {
1259 strcpy(local_ip_str, ipaddr_ntoa(&(pcb->local_ip)));
1260 strcpy(remote_ip_str, ipaddr_ntoa(&(pcb->remote_ip)));
1261
1262 rt_kprintf("#%d %d %s:%d <==> %s:%d \n",
1263 num, (int)pcb->flags,
1264 local_ip_str,
1265 pcb->local_port,
1266 remote_ip_str,
1267 pcb->remote_port);
1268
1269 num++;
1270 }
1271 rt_exit_critical();
1272 }
1273 FINSH_FUNCTION_EXPORT(list_udps, list all of udp connections);
1274 #endif /* LWIP_UDP */
1275
1276 #endif
1277