Browse Source

[add] lwIP 2.1.2 transplantation on RT-Thread.

Signed-off-by: liuxianliang <liuxianliang@rt-thread.com>
liuxianliang 5 years ago
parent
commit
de1fd2bfc4

+ 5 - 1
components/net/Kconfig

@@ -120,9 +120,13 @@ config RT_USING_LWIP
 
 
             config RT_USING_LWIP210
             config RT_USING_LWIP210
                 bool "lwIP v2.1.0"
                 bool "lwIP v2.1.0"
+
+	    config RT_USING_LWIP212
+                bool "lwIP v2.1.2"
+
         endchoice
         endchoice
 
 
-        if (RT_USING_LWIP210 || RT_USING_LWIP202)
+        if (RT_USING_LWIP210 || RT_USING_LWIP202 || RT_USING_LWIP212)
             config RT_USING_LWIP_IPV6
             config RT_USING_LWIP_IPV6
                 bool "IPV6 protocol"
                 bool "IPV6 protocol"
                 default n
                 default n

+ 1 - 1
components/net/SConscript

@@ -8,7 +8,7 @@ cwd = GetCurrentDir()
 list = os.listdir(cwd)
 list = os.listdir(cwd)
 
 
 # the default version of LWIP is 2.0.2
 # the default version of LWIP is 2.0.2
-if not GetDepend('RT_USING_LWIP141') and not GetDepend('RT_USING_LWIP202') and not GetDepend('RT_USING_LWIP210'):
+if not GetDepend('RT_USING_LWIP141') and not GetDepend('RT_USING_LWIP202') and not GetDepend('RT_USING_LWIP210') and not GetDepend('RT_USING_LWIP212'):
     AddDepend('RT_USING_LWIP202')
     AddDepend('RT_USING_LWIP202')
 
 
 for d in list:
 for d in list:

+ 89 - 0
components/net/lwip-2.1.2/README_RT-THREAD.md

@@ -0,0 +1,89 @@
+# lwip 移植说明
+
+为了适配 RT-Thread 网卡设备,RT-Thread 团队基于原 [lwip](http://savannah.nongnu.org/projects/lwip/) 进行了一些修改,本文档记录了相关修改内容。
+
+> 本 lwip-2.1.2 版本基于 [lwip STABLE-2_1_2_RELEASE](https://git.savannah.gnu.org/git/lwip.git) 版本移植而来。
+
+
+| Date | Author | Notes |
+| :---- | :---- | :---- |
+| 2019-09-02 | MurphyZhao | 增加 lwip 2.1.2 移植说明 |
+| 2020-06-18 | xiangxistu | 增加部分 lwIP 2.1.2 移植说明 |
+
+## 修改内容
+
+### src/api
+
+- `src/api/sockets.c` 增加 `lwip_tryget_socket` 函数,作为 `tryget_socket` 函数的全局实现
+- `src/api/sockets.c` 在 `alloc_socket` 函数中,增加 SAL 移植函数 `rt_wqueue_init`
+
+```
+#ifdef SAL_USING_POSIX
+      rt_wqueue_init(&sockets[i].wait_head);
+#endif
+```
+
+### src/app
+
+- 增加 `ping/ping.c`,便于在 finsh/msh 中使用 ping 功能
+- 增加 `tftp/tftp_port.c`,便于在 finsh/msh 中使用 tftp_server 功能
+
+### src/arch
+
+增加 `src/arch` 目录,存储对接 RT-Thread 设备框架的移植文件,从 lwip-2.0.2 版本中的移植文件修改而来。
+
+
+
+以及相对于 lwIP2.0.2 的增加修改内容:
+
+
+* 在 `src/arch/sys_arch.c` 中增加 MTU 与 etharp_output 的初始化
+
+* 在 `src/arch/sys_arch.c` 中增加新添加的邮箱函数
+
+  对邮箱机制的新增加的 sys_mbox_trypost_fromisr 函数予以实现
+
+* 在 `src/arch/sys_arch.c` 中增加新添加的内存堆函数
+
+  对内存堆的新增加的 mem_overflow_check_raw 与 mem_overflow_init_raw 函数予以实现
+  
+* 在 `src/arch/cc.h` 中增加对 lwIP 使用的标准错误代码宏的处理,不再使用 lwIP 内置的错误宏
+
+
+### src/core
+
+- 在 `src/core/dns.c` 的 `dns_setserver` 函数中增加 RT-Thread netdev 相关的移植
+- 在 `src/core/netif.c` 中增加 RT-Thread netdev 相关的移植
+
+### src/include
+
+- 在 `src/include/lwip/priv/sockets_priv.h` 中增加 SAL 相关的移植
+
+    在 `lwip_sock` 结构体中增加 `  rt_wqueue_t wait_head;` 成员
+
+- 在 `src/include/lwip/prot/ieee.h` 中增加 EAPOL, EAP over LAN 标识
+
+- 在 `src/include/lwip/init.h` 中的版本号后增加 `U` 标识
+
+- 在 `src/include/lwip/sockets.h` 中增加 `LWIP_SOCKET_SELECT`,解决开启 RT_USING_POSIX 时的冲突
+
+- 在 `src/include/lwip/arch.h` 中修改 `<unistd.h> `为 `"sys/types.h" `,解决编译冲突
+
+    并添加 typedef int ssize_t 定义,补足因 libc 与 dfs 未开启时 ssize_t 的定义不足问题
+
+- 在 `src/include/netif/` 中增加 `ethernetif.h`,用于对接 RT-Thread 网卡设备
+
+### src/netif
+
+- 在 `src/netif/` 中增加 `ethernetif.c`,用于对接 RT-Thread 网卡设备
+- 在 `src/netif/lowpan6.c` 中增加 `LWIP_6LOWPAN` 宏定义,以防止编译错误
+
+### src
+
+- 在 src 目录下,增加 `src/lwipopts.h`,用于 lwip 功能裁剪以及配置设置
+- 在 src 目录下,增加 `src/lwippools.h`,用于定义 `LWIP_MALLOC_MEMPOOL`
+
+### 其它
+
+- 增加 SConscript 文件,用于 scons 构建
+- 增加 README_RT-THREAD.md 文件,用于记录相对原 lwip 源码的改动

+ 265 - 0
components/net/lwip-2.1.2/SConscript

@@ -0,0 +1,265 @@
+from building import *
+
+# get current directory
+cwd = GetCurrentDir()
+
+# 1. The minimum set of files needed for lwIP.
+lwipcore_SRCS = Split("""
+src/core/init.c
+src/core/def.c
+src/core/dns.c
+src/core/inet_chksum.c
+src/core/ip.c
+src/core/memp.c
+src/core/netif.c
+src/core/pbuf.c
+src/core/raw.c
+src/core/stats.c
+src/core/sys.c
+src/core/tcp.c
+src/core/tcp_in.c
+src/core/tcp_out.c
+src/core/timeouts.c
+src/core/udp.c
+""")
+
+# 1.1 
+lwipcore_altcp_SRCS = Split("""
+src/core/altcp.c
+src/core/altcp_alloc.c
+src/core/altcp_tcp.c
+""")
+
+# 1.2 
+lwipcore4_SRCS = Split("""
+src/core/ipv4/autoip.c
+src/core/ipv4/dhcp.c
+src/core/ipv4/etharp.c
+src/core/ipv4/icmp.c
+src/core/ipv4/igmp.c
+src/core/ipv4/ip4_frag.c
+src/core/ipv4/ip4.c
+src/core/ipv4/ip4_addr.c
+""")
+
+# 1.3 
+lwipcore6_SRCS = Split("""
+src/core/ipv6/dhcp6.c
+src/core/ipv6/ethip6.c
+src/core/ipv6/icmp6.c
+src/core/ipv6/inet6.c
+src/core/ipv6/ip6.c
+src/core/ipv6/ip6_addr.c
+src/core/ipv6/ip6_frag.c
+src/core/ipv6/mld6.c
+src/core/ipv6/nd6.c
+""")
+
+# 2. APIFILES: The files which implement the sequential and socket APIs.
+lwipapi_SRCS = Split("""
+src/api/api_lib.c
+src/api/api_msg.c
+src/api/err.c
+src/api/if_api.c
+src/api/netbuf.c
+src/api/netdb.c
+src/api/netifapi.c
+src/api/sockets.c
+src/api/tcpip.c
+""")
+
+# 3. Files implementing various generic network interface functions
+lwipnetif_SRCS = Split("""
+src/netif/ethernet.c
+src/netif/ethernetif.c
+""")
+
+# 3.1 Files implementing an IEEE 802.1D bridge by using a multilayer netif approach
+lwipnetif_bridgeif_SRCS = Split("""
+src/netif/bridgeif.c
+src/netif/bridgeif_fdb.c
+""")
+
+# 3.2 A generic implementation of the SLIP (Serial Line IP) protocol.
+lwipnetif_slipif_SRCS = Split("""
+src/netif/slipif.c
+""")
+
+# 4. 6LoWPAN
+lwipsixlowpan_SRCS = Split("""
+src/netif/lowpan6.c
+""")
+
+# 4.1 A 6LoWPAN over Bluetooth Low Energy (BLE) implementation as netif,
+#           according to RFC-7668.
+lwipsixlowpan_ble_SRCS = Split("""
+src/netif/lowpan6_ble.c
+""")
+
+# 4.2 Common 6LowPAN routines for IPv6.
+lwipsixlowpan_ipv6_SRCS = Split("""
+src/netif/lowpan6_common.c
+""")
+
+# 4.3 A netif implementing the ZigBee Encapsulation Protocol (ZEP).
+lwipsixlowpan_zep_SRCS = Split("""
+src/netif/zepif.c
+""")
+
+# 5. PPP
+lwipppp_SRCS = Split("""
+src/netif/ppp/auth.c
+src/netif/ppp/ccp.c
+src/netif/ppp/chap-md5.c
+src/netif/ppp/chap_ms.c
+src/netif/ppp/chap-new.c
+src/netif/ppp/demand.c
+src/netif/ppp/eap.c
+src/netif/ppp/ecp.c
+src/netif/ppp/eui64.c
+src/netif/ppp/fsm.c
+src/netif/ppp/ipcp.c
+src/netif/ppp/ipv6cp.c
+src/netif/ppp/lcp.c
+src/netif/ppp/magic.c
+src/netif/ppp/mppe.c
+src/netif/ppp/multilink.c
+src/netif/ppp/ppp.c
+src/netif/ppp/pppapi.c
+src/netif/ppp/pppcrypt.c
+src/netif/ppp/pppoe.c
+src/netif/ppp/pppol2tp.c
+src/netif/ppp/pppos.c
+src/netif/ppp/upap.c
+src/netif/ppp/utils.c
+src/netif/ppp/vj.c
+src/netif/ppp/polarssl/arc4.c
+src/netif/ppp/polarssl/des.c
+src/netif/ppp/polarssl/md4.c
+src/netif/ppp/polarssl/md5.c
+src/netif/ppp/polarssl/sha1.c
+""")
+
+# 6. SNMPv3 agent
+lwipsnmp_SRCS = Split("""
+src/apps/snmp/snmp_asn1.c
+src/apps/snmp/snmp_core.c
+src/apps/snmp/snmp_mib2.c
+src/apps/snmp/snmp_mib2_icmp.c
+src/apps/snmp/snmp_mib2_interfaces.c
+src/apps/snmp/snmp_mib2_ip.c
+src/apps/snmp/snmp_mib2_snmp.c
+src/apps/snmp/snmp_mib2_system.c
+src/apps/snmp/snmp_mib2_tcp.c
+src/apps/snmp/snmp_mib2_udp.c
+src/apps/snmp/snmp_snmpv2_framework.c
+src/apps/snmp/snmp_snmpv2_usm.c
+src/apps/snmp/snmp_msg.c
+src/apps/snmp/snmpv3.c
+src/apps/snmp/snmp_netconn.c
+src/apps/snmp/snmp_pbuf_stream.c
+src/apps/snmp/snmp_raw.c
+src/apps/snmp/snmp_scalar.c
+src/apps/snmp/snmp_table.c
+src/apps/snmp/snmp_threadsync.c
+src/apps/snmp/snmp_traps.c
+""")
+
+# 7. HTTP server + client
+lwiphttp_SRCS = Split("""
+src/apps/http/altcp_proxyconnect.c
+src/apps/http/fs.c
+src/apps/http/http_client.c
+src/apps/http/httpd.c
+""")
+
+# 8. MAKEFSDATA HTTP server host utility
+lwipmakefsdata_SRCS = Split("""
+src/apps/http/makefsdata/makefsdata.c
+""")
+
+# 9. IPERF server
+lwipiperf_SRCS = Split("""
+src/apps/lwiperf/lwiperf.c
+""")
+
+# 10. SMTP client
+lwipsmtp_SRCS = Split("""
+src/apps/smtp/smtp.c
+""")
+
+# 11. SNTP client
+lwipsntp_SRCS = Split("""
+src/apps/sntp/sntp.c
+""")
+
+# 12. MDNS responder
+lwipmdns_SRCS = Split("""
+src/apps/mdns/mdns.c
+""")
+
+# 13. NetBIOS name server
+lwipnetbios_SRCS = Split("""
+src/apps/netbiosns/netbiosns.c
+""")
+
+# 14. TFTP server files
+lwiptftp_SRCS = Split("""
+src/apps/tftp/tftp_server.c
+src/apps/tftp/tftp_port.c
+""")
+
+# 15. MQTT client files
+lwipmqtt_SRCS = Split("""
+src/apps/mqtt/mqtt.c
+""")
+
+# 16. ARM MBEDTLS related files of lwIP rep
+lwipmbedtls_SRCS = Split("""
+src/apps/altcp_tls/altcp_tls_mbedtls.c
+src/apps/altcp_tls/altcp_tls_mbedtls_mem.c
+src/apps/snmp/snmpv3_mbedtls.c
+""")
+
+# 17. ping
+lwipping_SRCS = Split("""
+src/apps/ping/ping.c
+""")
+
+src = Split("""
+src/arch/sys_arch.c
+""")
+
+src += lwipcore_SRCS       # rm mem.c
+src += lwipcore_altcp_SRCS
+src += lwipapi_SRCS
+src += lwipnetif_SRCS
+src += lwipsixlowpan_SRCS
+
+src += lwipcore4_SRCS
+
+path = [cwd + '/src',
+    cwd + '/src/include',
+    cwd + '/src/arch/include',
+    cwd + '/src/include/netif']
+
+if not GetDepend('RT_USING_SAL'):
+    path += [cwd + '/src/include/compat/posix']
+
+if GetDepend(['RT_LWIP_SNMP']):
+    src += lwipsnmp_SRCS
+    path += [cwd + '/src/apps/snmp']
+
+if GetDepend(['RT_LWIP_PPP']):
+    src += lwipppp_SRCS
+    path += [cwd + '/src/netif/ppp']
+
+if GetDepend(['RT_USING_LWIP_IPV6']):
+    src += lwipcore6_SRCS
+
+if GetDepend(['RT_LWIP_USING_PING']):
+    src += lwipping_SRCS
+
+group = DefineGroup('lwIP', src, depend = ['RT_USING_LWIP', 'RT_USING_LWIP212'], CPPPATH = path)
+
+Return('group')

+ 245 - 0
components/net/lwip-2.1.2/src/apps/ping/ping.c

@@ -0,0 +1,245 @@
+/*
+ * netutils: ping implementation
+ */
+
+#include <rtthread.h>
+
+#ifdef RT_LWIP_ICMP    /* don't build if not configured for use in rtconfig.h */
+#include <lwip/opt.h>
+#include <lwip/init.h>
+#include <lwip/mem.h>
+#include <lwip/icmp.h>
+#include <lwip/netif.h>
+#include <lwip/sys.h>
+#include <lwip/inet.h>
+#include <lwip/inet_chksum.h>
+#include <lwip/ip.h>
+#include <lwip/netdb.h>
+#include <lwip/sockets.h>
+
+/**
+ * PING_DEBUG: Enable debugging for PING.
+ */
+#ifndef PING_DEBUG
+#define PING_DEBUG     LWIP_DBG_ON
+#endif
+
+/** ping receive timeout - in milliseconds */
+#define PING_RCV_TIMEO (2 * RT_TICK_PER_SECOND)
+/** ping delay - in milliseconds */
+#define PING_DELAY     (1 * RT_TICK_PER_SECOND)
+
+/** ping identifier - must fit on a u16_t */
+#ifndef PING_ID
+#define PING_ID        0xAFAF
+#endif
+
+/** ping additional data size to include in the packet */
+#ifndef PING_DATA_SIZE
+#define PING_DATA_SIZE 32
+#endif
+
+/* ping variables */
+static u16_t ping_seq_num;
+struct _ip_addr
+{
+    rt_uint8_t addr0, addr1, addr2, addr3;
+};
+
+/** Prepare a echo ICMP request */
+static void ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len)
+{
+    size_t i;
+    size_t data_len = len - sizeof(struct icmp_echo_hdr);
+
+    ICMPH_TYPE_SET(iecho, ICMP_ECHO);
+    ICMPH_CODE_SET(iecho, 0);
+    iecho->chksum = 0;
+    iecho->id     = PING_ID;
+    iecho->seqno  = htons(++ping_seq_num);
+
+    /* fill the additional data buffer with some data */
+    for (i = 0; i < data_len; i++)
+    {
+        ((char*) iecho)[sizeof(struct icmp_echo_hdr) + i] = (char) i;
+    }
+
+#ifdef RT_LWIP_USING_HW_CHECKSUM
+      iecho->chksum = 0;
+#else
+      iecho->chksum = inet_chksum(iecho, len);
+#endif
+
+}
+
+/* Ping using the socket ip */
+err_t lwip_ping_send(int s, ip_addr_t *addr, int size)
+{
+    int err;
+    struct icmp_echo_hdr *iecho;
+    struct sockaddr_in to;
+    int ping_size = sizeof(struct icmp_echo_hdr) + size;
+    LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff);
+
+    iecho = rt_malloc(ping_size);
+    if (iecho == RT_NULL)
+    {
+        return ERR_MEM;
+    }
+
+    ping_prepare_echo(iecho, (u16_t) ping_size);
+
+    to.sin_len = sizeof(to);
+    to.sin_family = AF_INET;
+#if LWIP_IPV4 && LWIP_IPV6
+    to.sin_addr.s_addr = addr->u_addr.ip4.addr;
+#elif LWIP_IPV4
+    to.sin_addr.s_addr = addr->addr;
+#elif LWIP_IPV6
+#error Not supported IPv6.
+#endif
+
+    err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*) &to, sizeof(to));
+    rt_free(iecho);
+
+    return (err == ping_size ? ERR_OK : ERR_VAL);
+}
+
+int lwip_ping_recv(int s, int *ttl)
+{
+    char buf[64];
+    int fromlen = sizeof(struct sockaddr_in), len;
+    struct sockaddr_in from;
+    struct ip_hdr *iphdr;
+    struct icmp_echo_hdr *iecho;
+
+    while ((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*) &from, (socklen_t*) &fromlen)) > 0)
+    {
+        if (len >= (int)(sizeof(struct ip_hdr) + sizeof(struct icmp_echo_hdr)))
+        {
+            iphdr = (struct ip_hdr *) buf;
+            iecho = (struct icmp_echo_hdr *) (buf + (IPH_HL(iphdr) * 4));
+            if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)))
+            {
+                *ttl = iphdr->_ttl;
+                return len;
+            }
+        }
+    }
+
+    return len;
+}
+
+#ifndef RT_USING_NETDEV
+
+/* using the lwIP custom ping */
+rt_err_t ping(char* target_name, rt_uint32_t times, rt_size_t size)
+{
+#if LWIP_VERSION_MAJOR >= 2U
+    struct timeval timeout = { PING_RCV_TIMEO / RT_TICK_PER_SECOND, PING_RCV_TIMEO % RT_TICK_PER_SECOND };
+#else
+    int timeout = PING_RCV_TIMEO * 1000UL / RT_TICK_PER_SECOND;
+#endif
+
+    int s, ttl, recv_len;
+    ip_addr_t target_addr;
+    rt_uint32_t send_times;
+    rt_tick_t recv_start_tick;
+    struct addrinfo hint, *res = NULL;
+    struct sockaddr_in *h = NULL;
+    struct in_addr ina;
+
+    send_times = 0;
+    ping_seq_num = 0;
+
+    if (size == 0)
+    {
+        size = PING_DATA_SIZE;
+    }
+
+    memset(&hint, 0, sizeof(hint));
+    /* convert URL to IP */
+    if (lwip_getaddrinfo(target_name, NULL, &hint, &res) != 0)
+    {
+        rt_kprintf("ping: unknown host %s\n", target_name);
+        return -RT_ERROR;
+    }
+    memcpy(&h, &res->ai_addr, sizeof(struct sockaddr_in *));
+    memcpy(&ina, &h->sin_addr, sizeof(ina));
+    lwip_freeaddrinfo(res);
+    if (inet_aton(inet_ntoa(ina), &target_addr) == 0)
+    {
+        rt_kprintf("ping: unknown host %s\n", target_name);
+        return -RT_ERROR;
+    }
+    /* new a socket */
+    if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0)
+    {
+        rt_kprintf("ping: create socket failed\n");
+        return -RT_ERROR;
+    }
+
+    lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+
+    while (1)
+    {
+        int elapsed_time;
+
+        if (lwip_ping_send(s, &target_addr, size) == ERR_OK)
+        {
+            recv_start_tick = rt_tick_get();
+            if ((recv_len = lwip_ping_recv(s, &ttl)) >= 0)
+            {
+                elapsed_time = (rt_tick_get() - recv_start_tick) * 1000UL / RT_TICK_PER_SECOND;
+                rt_kprintf("%d bytes from %s icmp_seq=%d ttl=%d time=%d ms\n", recv_len, inet_ntoa(ina), send_times,
+                        ttl, elapsed_time);
+            }
+            else
+            {
+                rt_kprintf("From %s icmp_seq=%d timeout\n", inet_ntoa(ina), send_times);
+            }
+        }
+        else
+        {
+            rt_kprintf("Send %s - error\n", inet_ntoa(ina));
+        }
+
+        send_times++;
+        if (send_times >= times)
+        {
+            /* send ping times reached, stop */
+            break;
+        }
+
+        rt_thread_delay(PING_DELAY); /* take a delay */
+    }
+
+    lwip_close(s);
+
+    return RT_EOK;
+}
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+
+FINSH_FUNCTION_EXPORT(ping, ping network host);
+
+int cmd_ping(int argc, char **argv)
+{
+    if (argc == 1)
+    {
+        rt_kprintf("Please input: ping <host address>\n");
+    }
+    else
+    {
+        ping(argv[1], 4, 0);
+    }
+
+    return 0;
+}
+FINSH_FUNCTION_EXPORT_ALIAS(cmd_ping, __cmd_ping, ping network host);
+#endif /* RT_USING_FINSH */
+
+#endif /* RT_USING_NETDEV */
+
+#endif /* RT_LWIP_ICMP */
+

+ 87 - 0
components/net/lwip-2.1.2/src/apps/tftp/tftp_port.c

@@ -0,0 +1,87 @@
+/*
+ * File      : tftp_port.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2017-08-17     armink       first version.
+ */
+
+
+#include <rtthread.h>
+#include <dfs_posix.h>
+#include <lwip/apps/tftp_server.h>
+
+static struct tftp_context ctx;
+
+static void* tftp_open(const char* fname, const char* mode, u8_t write)
+{
+    int fd = -1;
+
+    if (!rt_strcmp(mode, "octet"))
+    {
+        if (write)
+        {
+            fd = open(fname, O_WRONLY | O_CREAT, 0);
+        }
+        else
+        {
+            fd = open(fname, O_RDONLY, 0);
+        }
+    }
+    else
+    {
+        rt_kprintf("tftp: No support this mode(%s).", mode);
+    }
+
+    return (void *) fd;
+}
+
+static int tftp_write(void* handle, struct pbuf* p)
+{
+    int fd = (int) handle;
+
+    return write(fd, p->payload, p->len);
+}
+
+#if defined(RT_USING_FINSH)
+#include <finsh.h>
+
+static void tftp_server(uint8_t argc, char **argv)
+{
+    ctx.open = tftp_open;
+    ctx.close = (void (*)(void *)) close;
+    ctx.read = (int (*)(void *, void *, int)) read;
+    ctx.write = tftp_write;
+
+    if (tftp_init(&ctx) == ERR_OK)
+    {
+        rt_kprintf("TFTP server start successfully.\n");
+    }
+    else
+    {
+        rt_kprintf("TFTP server start failed.\n");
+    }
+}
+FINSH_FUNCTION_EXPORT(tftp_server, start tftp server.);
+
+#if defined(FINSH_USING_MSH)
+MSH_CMD_EXPORT(tftp_server, start tftp server.);
+#endif /* defined(FINSH_USING_MSH) */
+
+#endif /* defined(RT_USING_FINSH) */

+ 35 - 0
components/net/lwip-2.1.2/src/arch/include/arch/bpstruct.h

@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#if defined(__ICCARM__)
+#pragma pack(1)
+#endif

+ 103 - 0
components/net/lwip-2.1.2/src/arch/include/arch/cc.h

@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2001, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: cc.h,v 1.1.1.1 2004/12/16 14:17:13 bear Exp $
+ */
+#ifndef __ARCH_CC_H__
+#define __ARCH_CC_H__
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#define U16_F "hu"
+#define S16_F "hd"
+#define X16_F "hx"
+#define U32_F "lu"
+#define S32_F "ld"
+#define X32_F "lx"
+
+#ifdef RT_USING_LIBC
+#if defined(__CC_ARM) || defined(__CLANG_ARM) || defined(__IAR_SYSTEMS_ICC__)
+#include <sys/errno.h>
+#else
+#include <errno.h>
+/* some errno not defined in newlib */
+#define ENSRNOTFOUND 163  /* Domain name not found */
+/* WARNING: ESHUTDOWN also not defined in newlib. We chose
+			180 here because the number "108" which is used
+			in arch.h has been assigned to another error code. */
+#define ESHUTDOWN 180
+#endif /* __CC_ARM/__IAR_SYSTEMS_ICC__ */
+#endif /* RT_USING_LIBC */
+
+#if defined(RT_USING_LIBC) || defined(RT_USING_MINILIBC) || defined(RT_LIBC_USING_TIME)
+#include <sys/time.h>
+#define LWIP_TIMEVAL_PRIVATE	   0
+#else
+#define LWIP_TIMEVAL_PRIVATE	   1
+#endif
+
+#if defined(__CC_ARM)   /* ARMCC compiler */
+#define PACK_STRUCT_FIELD(x) x
+#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
+#define PACK_STRUCT_BEGIN
+#define PACK_STRUCT_END
+#elif defined(__IAR_SYSTEMS_ICC__)   /* IAR Compiler */
+#define PACK_STRUCT_BEGIN
+#define PACK_STRUCT_STRUCT
+#define PACK_STRUCT_END
+#define PACK_STRUCT_FIELD(x) x
+#define PACK_STRUCT_USE_INCLUDES
+#elif defined(__GNUC__)     /* GNU GCC Compiler */
+#define PACK_STRUCT_FIELD(x) x
+#define PACK_STRUCT_STRUCT __attribute__((packed))
+#define PACK_STRUCT_BEGIN
+#define PACK_STRUCT_END
+#elif defined(_MSC_VER)
+#define PACK_STRUCT_FIELD(x) x
+#define PACK_STRUCT_STRUCT
+#define PACK_STRUCT_BEGIN
+#define PACK_STRUCT_END
+#endif
+
+void sys_arch_assert(const char* file, int line);
+#define LWIP_PLATFORM_DIAG(x)	do {rt_kprintf x;} while(0)
+#define LWIP_PLATFORM_ASSERT(x) do {rt_kprintf(x); sys_arch_assert(__FILE__, __LINE__);}while(0)
+
+#include "string.h"
+
+#define SYS_ARCH_DECL_PROTECT(level)	
+#define SYS_ARCH_PROTECT(level)		rt_enter_critical()
+#define SYS_ARCH_UNPROTECT(level) 	rt_exit_critical()
+
+#endif /* __ARCH_CC_H__ */
+

+ 35 - 0
components/net/lwip-2.1.2/src/arch/include/arch/epstruct.h

@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#if defined(__ICCARM__)
+#pragma pack()
+#endif

+ 52 - 0
components/net/lwip-2.1.2/src/arch/include/arch/perf.h

@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2001, Swedish Institute of Computer Science.
+ * All rights reserved. 
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions 
+ * are met: 
+ * 1. Redistributions of source code must retain the above copyright 
+ *    notice, this list of conditions and the following disclaimer. 
+ * 2. Redistributions in binary form must reproduce the above copyright 
+ *    notice, this list of conditions and the following disclaimer in the 
+ *    documentation and/or other materials provided with the distribution. 
+ * 3. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
+ * SUCH DAMAGE. 
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: perf.h,v 1.1.1.1 2004/12/16 14:17:13 bear Exp $
+ */
+#ifndef __ARCH_PERF_H__
+#define __ARCH_PERF_H__
+
+//#include <sys/times.h>
+
+#define PERF_START    /* null definition */
+#define PERF_STOP(x)  /* null definition */
+
+/*
+void perf_print(unsigned long c1l, unsigned long c1h,
+		unsigned long c2l, unsigned long c2h,
+		char *key);
+
+void perf_print_times(struct tms *start, struct tms *end, char *key);
+
+void perf_init(char *fname);
+*/
+#endif /* __ARCH_PERF_H__ */

+ 64 - 0
components/net/lwip-2.1.2/src/arch/include/arch/sys_arch.h

@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2001, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: sys_arch.h,v 1.3 2005/03/13 16:03:23 bear Exp $
+ */
+#ifndef __ARCH_SYS_ARCH_H__
+#define __ARCH_SYS_ARCH_H__
+
+#include "arch/cc.h"
+
+#include <rtthread.h>
+
+#ifndef BYTE_ORDER
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+
+#define SYS_MBOX_NULL RT_NULL
+#define SYS_SEM_NULL  RT_NULL
+
+typedef u32_t sys_prot_t;
+
+#define SYS_MBOX_SIZE 10
+#define SYS_LWIP_TIMER_NAME "timer"
+#define SYS_LWIP_MBOX_NAME "mbox"
+#define SYS_LWIP_SEM_NAME "sem"
+#define SYS_LWIP_MUTEX_NAME "mu"
+
+typedef rt_sem_t sys_sem_t;
+typedef rt_mutex_t sys_mutex_t;
+typedef rt_mailbox_t  sys_mbox_t;
+typedef rt_thread_t sys_thread_t;
+
+// err_t sys_mbox_trypost_fromisr(sys_mbox_t *q, void *msg);
+
+#endif /* __ARCH_SYS_ARCH_H__ */

+ 844 - 0
components/net/lwip-2.1.2/src/arch/sys_arch.c

@@ -0,0 +1,844 @@
+/*
+ * COPYRIGHT (C) 2006-2018, RT-Thread Development Team
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2012-12-8      Bernard      add file header
+ *                             export bsd socket symbol for RT-Thread Application Module
+ * 2017-11-15     Bernard      add lock for init_done callback.
+ * 2018-11-02     MurphyZhao   port to lwip2.1.0
+ */
+
+#include <rtthread.h>
+
+#include "lwip/sys.h"
+#include "lwip/opt.h"
+#include "lwip/stats.h"
+#include "lwip/err.h"
+#include "arch/sys_arch.h"
+#include "lwip/debug.h"
+#include "lwip/netif.h"
+#include "lwip/netifapi.h"
+#include "lwip/tcpip.h"
+#include "netif/ethernetif.h"
+#include "lwip/sio.h"
+#include "lwip/init.h"
+#include "lwip/dhcp.h"
+#include "lwip/inet.h"
+
+#include "netif/etharp.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * Initialize the network interface device
+ *
+ * @return the operation status, ERR_OK on OK, ERR_IF on error
+ */
+static err_t netif_device_init(struct netif *netif)
+{
+    struct eth_device *ethif;
+
+    ethif = (struct eth_device *)netif->state;
+    if (ethif != RT_NULL)
+    {
+        rt_device_t device;
+
+        /* get device object */
+        device = (rt_device_t) ethif;
+        if (rt_device_init(device) != RT_EOK)
+        {
+            return ERR_IF;
+        }
+
+        /* copy device flags to netif flags */
+        netif->flags = ethif->flags;
+        netif->mtu = ETHERNET_MTU;
+
+        /* set output */
+        netif->output = etharp_output;
+
+        return ERR_OK;
+    }
+
+    return ERR_IF;
+}
+/*
+ * Initialize the ethernetif layer and set network interface device up
+ */
+static void tcpip_init_done_callback(void *arg)
+{
+    rt_device_t device;
+    struct eth_device *ethif;
+    ip4_addr_t ipaddr, netmask, gw;
+    struct rt_list_node* node;
+    struct rt_object* object;
+    struct rt_object_information *information;
+
+    LWIP_ASSERT("invalid arg.\n",arg);
+
+    IP4_ADDR(&gw, 0,0,0,0);
+    IP4_ADDR(&ipaddr, 0,0,0,0);
+    IP4_ADDR(&netmask, 0,0,0,0);
+
+    /* enter critical */
+    rt_enter_critical();
+
+    /* for each network interfaces */
+    information = rt_object_get_information(RT_Object_Class_Device);
+    RT_ASSERT(information != RT_NULL);
+    for (node = information->object_list.next;
+         node != &(information->object_list);
+         node = node->next)
+    {
+        object = rt_list_entry(node, struct rt_object, list);
+        device = (rt_device_t)object;
+        if (device->type == RT_Device_Class_NetIf)
+        {
+            ethif = (struct eth_device *)device;
+
+            /* leave critical */
+            rt_exit_critical();
+            LOCK_TCPIP_CORE();
+
+            netif_add(ethif->netif, &ipaddr, &netmask, &gw,
+                      ethif, netif_device_init, tcpip_input);
+
+            if (netif_default == RT_NULL)
+                netif_set_default(ethif->netif);
+
+#if LWIP_DHCP
+            /* set interface up */
+            netif_set_up(ethif->netif);
+            /* if this interface uses DHCP, start the DHCP client */
+            dhcp_start(ethif->netif);
+#else
+            /* set interface up */
+            netif_set_up(ethif->netif);
+#endif
+
+            if (ethif->flags & ETHIF_LINK_PHYUP)
+            {
+                netif_set_link_up(ethif->netif);
+            }
+
+            UNLOCK_TCPIP_CORE();
+            /* enter critical */
+            rt_enter_critical();
+        }
+    }
+
+    /* leave critical */
+    rt_exit_critical();
+    rt_sem_release((rt_sem_t)arg);
+}
+
+/**
+ * LwIP system initialization
+ */
+extern int eth_system_device_init_private(void);
+int lwip_system_init(void)
+{
+    rt_err_t rc;
+    struct rt_semaphore done_sem;
+    static rt_bool_t init_ok = RT_FALSE;
+
+    if (init_ok)
+    {
+        rt_kprintf("lwip system already init.\n");
+        return 0;
+    }
+
+    eth_system_device_init_private();
+
+    /* set default netif to NULL */
+    netif_default = RT_NULL;
+
+    rc = rt_sem_init(&done_sem, "done", 0, RT_IPC_FLAG_FIFO);
+
+    if (rc != RT_EOK)
+    {
+        LWIP_ASSERT("Failed to create semaphore", 0);
+
+        return -1;
+    }
+
+    tcpip_init(tcpip_init_done_callback, (void *)&done_sem);
+
+    /* waiting for initialization done */
+    if (rt_sem_take(&done_sem, RT_WAITING_FOREVER) != RT_EOK)
+    {
+        rt_sem_detach(&done_sem);
+
+        return -1;
+    }
+    rt_sem_detach(&done_sem);
+
+    /* set default ip address */
+#if !LWIP_DHCP
+    if (netif_default != RT_NULL)
+    {
+        struct ip4_addr ipaddr, netmask, gw;
+
+        ipaddr.addr = inet_addr(RT_LWIP_IPADDR);
+        gw.addr = inet_addr(RT_LWIP_GWADDR);
+        netmask.addr = inet_addr(RT_LWIP_MSKADDR);
+
+        netifapi_netif_set_addr(netif_default, &ipaddr, &netmask, &gw);
+    }
+#endif
+    rt_kprintf("lwIP-%d.%d.%d initialized!\n", LWIP_VERSION_MAJOR, LWIP_VERSION_MINOR, LWIP_VERSION_REVISION);
+
+    init_ok = RT_TRUE;
+
+    return 0;
+}
+INIT_PREV_EXPORT(lwip_system_init);
+
+void sys_init(void)
+{
+    /* nothing on RT-Thread porting */
+}
+
+void lwip_sys_init(void)
+{
+    lwip_system_init();
+}
+
+/*
+ * Create a new semaphore
+ *
+ * @return the operation status, ERR_OK on OK; others on error
+ */
+err_t sys_sem_new(sys_sem_t *sem, u8_t count)
+{
+    static unsigned short counter = 0;
+    char tname[RT_NAME_MAX];
+    sys_sem_t tmpsem;
+
+    RT_DEBUG_NOT_IN_INTERRUPT;
+
+    rt_snprintf(tname, RT_NAME_MAX, "%s%d", SYS_LWIP_SEM_NAME, counter);
+    counter ++;
+
+    tmpsem = rt_sem_create(tname, count, RT_IPC_FLAG_FIFO);
+    if (tmpsem == RT_NULL)
+        return ERR_MEM;
+    else
+    {
+        *sem = tmpsem;
+
+        return ERR_OK;
+    }
+}
+
+/*
+ * Deallocate a semaphore
+ */
+void sys_sem_free(sys_sem_t *sem)
+{
+    RT_DEBUG_NOT_IN_INTERRUPT;
+    rt_sem_delete(*sem);
+}
+
+/*
+ * Signal a semaphore
+ */
+void sys_sem_signal(sys_sem_t *sem)
+{
+    rt_sem_release(*sem);
+}
+
+/*
+ * Block the thread while waiting for the semaphore to be signaled
+ *
+ * @return If the timeout argument is non-zero, it will return the number of milliseconds
+ *         spent waiting for the semaphore to be signaled; If the semaphore isn't signaled
+ *         within the specified time, it will return SYS_ARCH_TIMEOUT; If the thread doesn't
+ *         wait for the semaphore, it will return zero
+ */
+u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
+{
+    rt_err_t ret;
+    s32_t t;
+    u32_t tick;
+
+    RT_DEBUG_NOT_IN_INTERRUPT;
+
+    /* get the begin tick */
+    tick = rt_tick_get();
+    if (timeout == 0)
+        t = RT_WAITING_FOREVER;
+    else
+    {
+        /* convert msecond to os tick */
+        if (timeout < (1000/RT_TICK_PER_SECOND))
+            t = 1;
+        else
+            t = timeout / (1000/RT_TICK_PER_SECOND);
+    }
+
+    ret = rt_sem_take(*sem, t);
+
+    if (ret == -RT_ETIMEOUT)
+        return SYS_ARCH_TIMEOUT;
+    else
+    {
+        if (ret == RT_EOK)
+            ret = 1;
+    }
+
+    /* get elapse msecond */
+    tick = rt_tick_get() - tick;
+
+    /* convert tick to msecond */
+    tick = tick * (1000 / RT_TICK_PER_SECOND);
+    if (tick == 0)
+        tick = 1;
+
+    return tick;
+}
+
+#ifndef sys_sem_valid
+/** Check if a semaphore is valid/allocated:
+ *  return 1 for valid, 0 for invalid
+ */
+int sys_sem_valid(sys_sem_t *sem)
+{
+    return (int)(*sem);
+}
+#endif
+
+#ifndef sys_sem_set_invalid
+/** Set a semaphore invalid so that sys_sem_valid returns 0
+ */
+void sys_sem_set_invalid(sys_sem_t *sem)
+{
+    *sem = RT_NULL;
+}
+#endif
+
+/* ====================== Mutex ====================== */
+
+/** Create a new mutex
+ * @param mutex pointer to the mutex to create
+ * @return a new mutex
+ */
+err_t sys_mutex_new(sys_mutex_t *mutex)
+{
+    static unsigned short counter = 0;
+    char tname[RT_NAME_MAX];
+    sys_mutex_t tmpmutex;
+
+    RT_DEBUG_NOT_IN_INTERRUPT;
+
+    rt_snprintf(tname, RT_NAME_MAX, "%s%d", SYS_LWIP_MUTEX_NAME, counter);
+    counter ++;
+
+    tmpmutex = rt_mutex_create(tname, RT_IPC_FLAG_FIFO);
+    if (tmpmutex == RT_NULL)
+        return ERR_MEM;
+    else
+    {
+        *mutex = tmpmutex;
+
+        return ERR_OK;
+    }
+}
+
+/** Lock a mutex
+ * @param mutex the mutex to lock
+ */
+void sys_mutex_lock(sys_mutex_t *mutex)
+{
+    RT_DEBUG_NOT_IN_INTERRUPT;
+    rt_mutex_take(*mutex, RT_WAITING_FOREVER);
+
+    return;
+}
+
+/** Unlock a mutex
+ * @param mutex the mutex to unlock
+ */
+void sys_mutex_unlock(sys_mutex_t *mutex)
+{
+    rt_mutex_release(*mutex);
+}
+
+/** Delete a semaphore
+ * @param mutex the mutex to delete
+ */
+void sys_mutex_free(sys_mutex_t *mutex)
+{
+    RT_DEBUG_NOT_IN_INTERRUPT;
+
+    rt_mutex_delete(*mutex);
+}
+
+#ifndef sys_mutex_valid
+/** Check if a mutex is valid/allocated:
+ *  return 1 for valid, 0 for invalid
+ */
+int sys_mutex_valid(sys_mutex_t *mutex)
+{
+    return (int)(*mutex);
+}
+#endif
+
+#ifndef sys_mutex_set_invalid
+/** Set a mutex invalid so that sys_mutex_valid returns 0
+ */
+void sys_mutex_set_invalid(sys_mutex_t *mutex)
+{
+    *mutex = RT_NULL;
+}
+#endif
+
+/* ====================== Mailbox ====================== */
+
+/*
+ * Create an empty mailbox for maximum "size" elements
+ *
+ * @return the operation status, ERR_OK on OK; others on error
+ */
+err_t sys_mbox_new(sys_mbox_t *mbox, int size)
+{
+    static unsigned short counter = 0;
+    char tname[RT_NAME_MAX];
+    sys_mbox_t tmpmbox;
+
+    RT_DEBUG_NOT_IN_INTERRUPT;
+
+    rt_snprintf(tname, RT_NAME_MAX, "%s%d", SYS_LWIP_MBOX_NAME, counter);
+    counter ++;
+
+    tmpmbox = rt_mb_create(tname, size, RT_IPC_FLAG_FIFO);
+    if (tmpmbox != RT_NULL)
+    {
+        *mbox = tmpmbox;
+
+        return ERR_OK;
+    }
+
+    return ERR_MEM;
+}
+
+/*
+ * Deallocate a mailbox
+ */
+void sys_mbox_free(sys_mbox_t *mbox)
+{
+    RT_DEBUG_NOT_IN_INTERRUPT;
+
+    rt_mb_delete(*mbox);
+
+    return;
+}
+
+/** Post a message to an mbox - may not fail
+ * -> blocks if full, only used from tasks not from ISR
+ * @param mbox mbox to posts the message
+ * @param msg message to post (ATTENTION: can be NULL)
+ */
+void sys_mbox_post(sys_mbox_t *mbox, void *msg)
+{
+    RT_DEBUG_NOT_IN_INTERRUPT;
+
+    rt_mb_send_wait(*mbox, (rt_uint32_t)msg, RT_WAITING_FOREVER);
+
+    return;
+}
+
+/*
+ * Try to post the "msg" to the mailbox
+ *
+ * @return return ERR_OK if the "msg" is posted, ERR_MEM if the mailbox is full
+ */
+err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
+{
+    if (rt_mb_send(*mbox, (rt_uint32_t)msg) == RT_EOK)
+        return ERR_OK;
+
+    return ERR_MEM;
+}
+
+err_t
+sys_mbox_trypost_fromisr(sys_mbox_t *q, void *msg)
+{
+  return sys_mbox_trypost(q, msg);
+}
+
+/** Wait for a new message to arrive in the mbox
+ * @param mbox mbox to get a message from
+ * @param msg pointer where the message is stored
+ * @param timeout maximum time (in milliseconds) to wait for a message
+ * @return time (in milliseconds) waited for a message, may be 0 if not waited
+           or SYS_ARCH_TIMEOUT on timeout
+ *         The returned time has to be accurate to prevent timer jitter!
+ */
+u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
+{
+    rt_err_t ret;
+    s32_t t;
+    u32_t tick;
+
+    RT_DEBUG_NOT_IN_INTERRUPT;
+
+    /* get the begin tick */
+    tick = rt_tick_get();
+
+    if(timeout == 0)
+        t = RT_WAITING_FOREVER;
+    else
+    {
+        /* convirt msecond to os tick */
+        if (timeout < (1000/RT_TICK_PER_SECOND))
+            t = 1;
+        else
+            t = timeout / (1000/RT_TICK_PER_SECOND);
+    }
+
+    ret = rt_mb_recv(*mbox, (rt_ubase_t *)msg, t);
+    if(ret != RT_EOK)
+    {
+        return SYS_ARCH_TIMEOUT;
+    }
+
+    /* get elapse msecond */
+    tick = rt_tick_get() - tick;
+
+    /* convert tick to msecond */
+    tick = tick * (1000 / RT_TICK_PER_SECOND);
+    if (tick == 0)
+        tick = 1;
+
+    return tick;
+}
+
+/** Wait for a new message to arrive in the mbox
+ * @param mbox mbox to get a message from
+ * @param msg pointer where the message is stored
+ * @param timeout maximum time (in milliseconds) to wait for a message
+ * @return 0 (milliseconds) if a message has been received
+ *         or SYS_MBOX_EMPTY if the mailbox is empty
+ */
+u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
+{
+    int ret;
+
+    ret = rt_mb_recv(*mbox, (rt_ubase_t *)msg, 0);
+
+    if(ret == -RT_ETIMEOUT)
+        return SYS_ARCH_TIMEOUT;
+    else
+    {
+        if (ret == RT_EOK)
+            ret = 1;
+    }
+
+    return ret;
+}
+
+#ifndef sys_mbox_valid
+/** Check if an mbox is valid/allocated:
+ *  return 1 for valid, 0 for invalid
+ */
+int sys_mbox_valid(sys_mbox_t *mbox)
+{
+    return (int)(*mbox);
+}
+#endif
+
+#ifndef sys_mbox_set_invalid
+/** Set an mbox invalid so that sys_mbox_valid returns 0
+ */
+void sys_mbox_set_invalid(sys_mbox_t *mbox)
+{
+    *mbox = RT_NULL;
+}
+#endif
+
+/* ====================== System ====================== */
+
+/*
+ * Start a new thread named "name" with priority "prio" that will begin
+ * its execution in the function "thread()". The "arg" argument will be
+ * passed as an argument to the thread() function
+ */
+sys_thread_t sys_thread_new(const char    *name,
+                            lwip_thread_fn thread,
+                            void          *arg,
+                            int            stacksize,
+                            int            prio)
+{
+    rt_thread_t t;
+
+    RT_DEBUG_NOT_IN_INTERRUPT;
+
+    /* create thread */
+    t = rt_thread_create(name, thread, arg, stacksize, prio, 20);
+    RT_ASSERT(t != RT_NULL);
+
+    /* startup thread */
+    rt_thread_startup(t);
+
+    return t;
+}
+
+sys_prot_t sys_arch_protect(void)
+{
+    rt_base_t level;
+
+    /* disable interrupt */
+    level = rt_hw_interrupt_disable();
+
+    return level;
+}
+
+void sys_arch_unprotect(sys_prot_t pval)
+{
+    /* enable interrupt */
+    rt_hw_interrupt_enable(pval);
+
+    return;
+}
+
+void sys_arch_assert(const char *file, int line)
+{
+    rt_kprintf("\nAssertion: %d in %s, thread %s\n",
+               line, file, rt_thread_self()->name);
+    RT_ASSERT(0);
+}
+
+u32_t sys_jiffies(void)
+{
+    return rt_tick_get();
+}
+
+u32_t sys_now(void)
+{
+    return rt_tick_get() * (1000 / RT_TICK_PER_SECOND);
+}
+
+#if MEM_OVERFLOW_CHECK || MEMP_OVERFLOW_CHECK
+/**
+ * Check if a mep element was victim of an overflow or underflow
+ * (e.g. the restricted area after/before it has been altered)
+ *
+ * @param p the mem element to check
+ * @param size allocated size of the element
+ * @param descr1 description of the element source shown on error
+ * @param descr2 description of the element source shown on error
+ */
+void
+mem_overflow_check_raw(void *p, size_t size, const char *descr1, const char *descr2)
+{
+#if MEM_SANITY_REGION_AFTER_ALIGNED || MEM_SANITY_REGION_BEFORE_ALIGNED
+  u16_t k;
+  u8_t *m;
+
+#if MEM_SANITY_REGION_AFTER_ALIGNED > 0
+  m = (u8_t *)p + size;
+  for (k = 0; k < MEM_SANITY_REGION_AFTER_ALIGNED; k++) {
+    if (m[k] != 0xcd) {
+      char errstr[128];
+      snprintf(errstr, sizeof(errstr), "detected mem overflow in %s%s", descr1, descr2);
+      LWIP_ASSERT(errstr, 0);
+    }
+  }
+#endif /* MEM_SANITY_REGION_AFTER_ALIGNED > 0 */
+
+#if MEM_SANITY_REGION_BEFORE_ALIGNED > 0
+  m = (u8_t *)p - MEM_SANITY_REGION_BEFORE_ALIGNED;
+  for (k = 0; k < MEM_SANITY_REGION_BEFORE_ALIGNED; k++) {
+    if (m[k] != 0xcd) {
+      char errstr[128];
+      snprintf(errstr, sizeof(errstr), "detected mem underflow in %s%s", descr1, descr2);
+      LWIP_ASSERT(errstr, 0);
+    }
+  }
+#endif /* MEM_SANITY_REGION_BEFORE_ALIGNED > 0 */
+#else
+  LWIP_UNUSED_ARG(p);
+  LWIP_UNUSED_ARG(desc);
+  LWIP_UNUSED_ARG(descr);
+#endif
+}
+
+/**
+ * Initialize the restricted area of a mem element.
+ */
+void
+mem_overflow_init_raw(void *p, size_t size)
+{
+#if MEM_SANITY_REGION_BEFORE_ALIGNED > 0 || MEM_SANITY_REGION_AFTER_ALIGNED > 0
+  u8_t *m;
+#if MEM_SANITY_REGION_BEFORE_ALIGNED > 0
+  m = (u8_t *)p - MEM_SANITY_REGION_BEFORE_ALIGNED;
+  memset(m, 0xcd, MEM_SANITY_REGION_BEFORE_ALIGNED);
+#endif
+#if MEM_SANITY_REGION_AFTER_ALIGNED > 0
+  m = (u8_t *)p + size;
+  memset(m, 0xcd, MEM_SANITY_REGION_AFTER_ALIGNED);
+#endif
+#else /* MEM_SANITY_REGION_BEFORE_ALIGNED > 0 || MEM_SANITY_REGION_AFTER_ALIGNED > 0 */
+  LWIP_UNUSED_ARG(p);
+  LWIP_UNUSED_ARG(desc);
+#endif /* MEM_SANITY_REGION_BEFORE_ALIGNED > 0 || MEM_SANITY_REGION_AFTER_ALIGNED > 0 */
+}
+#endif /* MEM_OVERFLOW_CHECK || MEMP_OVERFLOW_CHECK */
+
+RT_WEAK
+void mem_init(void)
+{
+}
+
+void *mem_calloc(mem_size_t count, mem_size_t size)
+{
+    return rt_calloc(count, size);
+}
+
+void *mem_trim(void *mem, mem_size_t size)
+{
+    // return rt_realloc(mem, size);
+    /* not support trim yet */
+    return mem;
+}
+
+void *mem_malloc(mem_size_t size)
+{
+    return rt_malloc(size);
+}
+
+void  mem_free(void *mem)
+{
+    rt_free(mem);
+}
+
+#ifdef RT_LWIP_PPP
+u32_t sio_read(sio_fd_t fd, u8_t *buf, u32_t size)
+{
+    u32_t len;
+
+    RT_ASSERT(fd != RT_NULL);
+
+    len = rt_device_read((rt_device_t)fd, 0, buf, size);
+    if (len <= 0)
+        return 0;
+
+    return len;
+}
+
+u32_t sio_write(sio_fd_t fd, u8_t *buf, u32_t size)
+{
+    RT_ASSERT(fd != RT_NULL);
+
+    return rt_device_write((rt_device_t)fd, 0, buf, size);
+}
+
+void sio_read_abort(sio_fd_t fd)
+{
+    rt_kprintf("read_abort\n");
+}
+
+void ppp_trace(int level, const char *format, ...)
+{
+    va_list args;
+    rt_size_t length;
+    static char rt_log_buf[RT_CONSOLEBUF_SIZE];
+
+    va_start(args, format);
+    length = rt_vsprintf(rt_log_buf, format, args);
+    rt_device_write((rt_device_t)rt_console_get_device(), 0, rt_log_buf, length);
+    va_end(args);
+}
+#endif
+
+/*
+ * export bsd socket symbol for RT-Thread Application Module
+ */
+#if LWIP_SOCKET
+#include <lwip/sockets.h>
+RTM_EXPORT(lwip_accept);
+RTM_EXPORT(lwip_bind);
+RTM_EXPORT(lwip_shutdown);
+RTM_EXPORT(lwip_getpeername);
+RTM_EXPORT(lwip_getsockname);
+RTM_EXPORT(lwip_getsockopt);
+RTM_EXPORT(lwip_setsockopt);
+RTM_EXPORT(lwip_close);
+RTM_EXPORT(lwip_connect);
+RTM_EXPORT(lwip_listen);
+RTM_EXPORT(lwip_recv);
+RTM_EXPORT(lwip_read);
+RTM_EXPORT(lwip_recvfrom);
+RTM_EXPORT(lwip_send);
+RTM_EXPORT(lwip_sendto);
+RTM_EXPORT(lwip_socket);
+RTM_EXPORT(lwip_write);
+RTM_EXPORT(lwip_select);
+RTM_EXPORT(lwip_ioctl);
+RTM_EXPORT(lwip_fcntl);
+
+RTM_EXPORT(lwip_htons);
+RTM_EXPORT(lwip_htonl);
+
+#if LWIP_DNS
+#include <lwip/netdb.h>
+RTM_EXPORT(lwip_gethostbyname);
+RTM_EXPORT(lwip_gethostbyname_r);
+RTM_EXPORT(lwip_freeaddrinfo);
+RTM_EXPORT(lwip_getaddrinfo);
+#endif
+
+#endif
+
+#if LWIP_DHCP
+#include <lwip/dhcp.h>
+RTM_EXPORT(dhcp_start);
+RTM_EXPORT(dhcp_renew);
+RTM_EXPORT(dhcp_stop);
+#endif
+
+#if LWIP_NETIF_API
+#include <lwip/netifapi.h>
+RTM_EXPORT(netifapi_netif_set_addr);
+#endif
+
+#if LWIP_NETIF_LINK_CALLBACK
+RTM_EXPORT(netif_set_link_callback);
+#endif
+
+#if LWIP_NETIF_STATUS_CALLBACK
+RTM_EXPORT(netif_set_status_callback);
+#endif
+
+RTM_EXPORT(netif_find);
+RTM_EXPORT(netif_set_addr);
+RTM_EXPORT(netif_set_ipaddr);
+RTM_EXPORT(netif_set_gw);
+RTM_EXPORT(netif_set_netmask);

+ 52 - 0
components/net/lwip-2.1.2/src/include/netif/ethernetif.h

@@ -0,0 +1,52 @@
+#ifndef __NETIF_ETHERNETIF_H__
+#define __NETIF_ETHERNETIF_H__
+
+#include "lwip/netif.h"
+#include <rtthread.h>
+
+#define NIOCTL_GADDR		0x01
+#ifndef RT_LWIP_ETH_MTU
+#define ETHERNET_MTU		1500
+#else
+#define ETHERNET_MTU		RT_LWIP_ETH_MTU
+#endif
+
+/* eth flag with auto_linkup or phy_linkup */
+#define ETHIF_LINK_AUTOUP	0x0000
+#define ETHIF_LINK_PHYUP	0x0100
+
+struct eth_device
+{
+    /* inherit from rt_device */
+    struct rt_device parent;
+
+    /* network interface for lwip */
+    struct netif *netif;
+    struct rt_semaphore tx_ack;
+
+    rt_uint16_t flags;
+    rt_uint8_t  link_changed;
+    rt_uint8_t  link_status;
+
+    /* eth device interface */
+    struct pbuf* (*eth_rx)(rt_device_t dev);
+    rt_err_t (*eth_tx)(rt_device_t dev, struct pbuf* p);
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    rt_err_t eth_device_ready(struct eth_device* dev);
+    rt_err_t eth_device_init(struct eth_device * dev, const char *name);
+    rt_err_t eth_device_init_with_flag(struct eth_device *dev, const char *name, rt_uint16_t flag);
+    rt_err_t eth_device_linkchange(struct eth_device* dev, rt_bool_t up);
+    void eth_device_deinit(struct eth_device *dev);
+
+    int eth_system_device_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __NETIF_ETHERNETIF_H__ */

+ 644 - 0
components/net/lwip-2.1.2/src/lwipopts.h

@@ -0,0 +1,644 @@
+#ifndef __LWIPOPTS_H__
+#define __LWIPOPTS_H__
+
+#include <rtconfig.h>
+
+#define ERRNO                       1
+
+#define LWIP_SOCKET_SELECT 1
+#define LWIP_SOCKET_POLL 1
+
+#define LWIP_IPV4                   1
+
+#ifdef RT_USING_LWIP_IPV6
+#define LWIP_IPV6                   1
+#else
+#define LWIP_IPV6                   0
+#endif /* RT_USING_LWIP_IPV6 */
+
+#define NO_SYS                      0
+#define LWIP_SOCKET                 1
+#define LWIP_NETCONN                1
+
+#ifdef RT_LWIP_IGMP
+#define LWIP_IGMP                   1
+#else
+#define LWIP_IGMP                   0
+#endif
+
+#ifdef RT_LWIP_ICMP
+#define LWIP_ICMP                   1
+#else
+#define LWIP_ICMP                   0
+#endif
+
+#ifdef RT_LWIP_SNMP
+#define LWIP_SNMP                   1
+#else
+#define LWIP_SNMP                   0
+#endif
+
+#ifdef RT_LWIP_DNS
+#define LWIP_DNS                    1
+#else
+#define LWIP_DNS                    0
+#endif
+
+#define LWIP_HAVE_LOOPIF            0
+
+#define LWIP_PLATFORM_BYTESWAP      0
+
+#ifndef BYTE_ORDER
+#define BYTE_ORDER                  LITTLE_ENDIAN
+#endif
+
+/* #define RT_LWIP_DEBUG */
+
+#ifdef RT_LWIP_DEBUG
+#define LWIP_DEBUG
+#endif
+
+/* ---------- Debug options ---------- */
+#ifdef LWIP_DEBUG
+#ifdef RT_LWIP_SYS_DEBUG
+#define SYS_DEBUG                   LWIP_DBG_ON
+#else
+#define SYS_DEBUG                   LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_ETHARP_DEBUG
+#define ETHARP_DEBUG                LWIP_DBG_ON
+#else
+#define ETHARP_DEBUG                LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_PPP_DEBUG
+#define PPP_DEBUG                   LWIP_DBG_ON
+#else
+#define PPP_DEBUG                   LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_MEM_DEBUG
+#define MEM_DEBUG                   LWIP_DBG_ON
+#else
+#define MEM_DEBUG                   LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_MEMP_DEBUG
+#define MEMP_DEBUG                  LWIP_DBG_ON
+#else
+#define MEMP_DEBUG                  LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_PBUF_DEBUG
+#define PBUF_DEBUG                  LWIP_DBG_ON
+#else
+#define PBUF_DEBUG                  LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_API_LIB_DEBUG
+#define API_LIB_DEBUG               LWIP_DBG_ON
+#else
+#define API_LIB_DEBUG               LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_API_MSG_DEBUG
+#define API_MSG_DEBUG               LWIP_DBG_ON
+#else
+#define API_MSG_DEBUG               LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_TCPIP_DEBUG
+#define TCPIP_DEBUG                 LWIP_DBG_ON
+#else
+#define TCPIP_DEBUG                 LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_NETIF_DEBUG
+#define NETIF_DEBUG                 LWIP_DBG_ON
+#else
+#define NETIF_DEBUG                 LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_SOCKETS_DEBUG
+#define SOCKETS_DEBUG               LWIP_DBG_ON
+#else
+#define SOCKETS_DEBUG               LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_DNS_DEBUG
+#define DNS_DEBUG                   LWIP_DBG_ON
+#else
+#define DNS_DEBUG                   LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_AUTOIP_DEBUG
+#define AUTOIP_DEBUG                LWIP_DBG_ON
+#else
+#define AUTOIP_DEBUG                LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_DHCP_DEBUG
+#define DHCP_DEBUG                  LWIP_DBG_ON
+#else
+#define DHCP_DEBUG                  LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_IP_DEBUG
+#define IP_DEBUG                    LWIP_DBG_ON
+#else
+#define IP_DEBUG                    LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_IP_REASS_DEBUG
+#define IP_REASS_DEBUG              LWIP_DBG_ON
+#else
+#define IP_REASS_DEBUG              LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_ICMP_DEBUG
+#define ICMP_DEBUG                  LWIP_DBG_ON
+#else
+#define ICMP_DEBUG                  LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_IGMP_DEBUG
+#define IGMP_DEBUG                  LWIP_DBG_ON
+#else
+#define IGMP_DEBUG                  LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_UDP_DEBUG
+#define UDP_DEBUG                   LWIP_DBG_ON
+#else
+#define UDP_DEBUG                   LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_TCP_DEBUG
+#define TCP_DEBUG                   LWIP_DBG_ON
+#else
+#define TCP_DEBUG                   LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_TCP_INPUT_DEBUG
+#define TCP_INPUT_DEBUG             LWIP_DBG_ON
+#else
+#define TCP_INPUT_DEBUG             LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_TCP_OUTPUT_DEBUG
+#define TCP_OUTPUT_DEBUG            LWIP_DBG_ON
+#else
+#define TCP_OUTPUT_DEBUG            LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_TCP_RTO_DEBUG
+#define TCP_RTO_DEBUG               LWIP_DBG_ON
+#else
+#define TCP_RTO_DEBUG               LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_TCP_CWND_DEBUG
+#define TCP_CWND_DEBUG              LWIP_DBG_ON
+#else
+#define TCP_CWND_DEBUG              LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_TCP_WND_DEBUG
+#define TCP_WND_DEBUG               LWIP_DBG_ON
+#else
+#define TCP_WND_DEBUG               LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_TCP_FR_DEBUG
+#define TCP_FR_DEBUG                LWIP_DBG_ON
+#else
+#define TCP_FR_DEBUG                LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_TCP_QLEN_DEBUG
+#define TCP_QLEN_DEBUG              LWIP_DBG_ON
+#else
+#define TCP_QLEN_DEBUG              LWIP_DBG_OFF
+#endif
+
+#ifdef RT_LWIP_TCP_RST_DEBUG
+#define TCP_RST_DEBUG               LWIP_DBG_ON
+#else
+#define TCP_RST_DEBUG               LWIP_DBG_OFF
+#endif
+
+#endif /* LWIP_DEBUG */
+
+#define LWIP_DBG_TYPES_ON           (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH|LWIP_DBG_HALT)
+
+# ifndef __STRICT_ANSI__
+#  define SSIZE_MAX LONG_MAX
+# endif
+
+#ifdef RT_USING_LIBC
+#define LWIP_NO_UNISTD_H 0
+#else
+#define LWIP_NO_UNISTD_H 1
+#endif
+
+/* ---------- Memory options ---------- */
+#define MEM_ALIGNMENT               4
+#define MEMP_OVERFLOW_CHECK         1 ////
+#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 1 ////
+//#define MEM_LIBC_MALLOC             1
+//#define MEM_USE_POOLS               1
+//#define MEMP_USE_CUSTOM_POOLS       1
+//#define MEM_SIZE                    (1024*64)
+
+#define MEMP_MEM_MALLOC             0
+
+/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
+   sends a lot of data out of ROM (or other static memory), this
+   should be set high. */
+#define MEMP_NUM_PBUF               32 //16
+
+/* the number of struct netconns */
+#ifdef RT_MEMP_NUM_NETCONN
+#define MEMP_NUM_NETCONN            RT_MEMP_NUM_NETCONN
+#endif
+
+/* the number of UDP protocol control blocks. One per active RAW "connection". */
+#ifdef RT_LWIP_RAW_PCB_NUM
+#define MEMP_NUM_RAW_PCB            RT_LWIP_RAW_PCB_NUM
+#endif
+
+/* the number of UDP protocol control blocks. One per active UDP "connection". */
+#ifdef RT_LWIP_UDP_PCB_NUM
+#define MEMP_NUM_UDP_PCB            RT_LWIP_UDP_PCB_NUM
+#endif
+
+/* the number of simulatenously active TCP connections. */
+#ifdef RT_LWIP_TCP_PCB_NUM
+#define MEMP_NUM_TCP_PCB            RT_LWIP_TCP_PCB_NUM
+#endif
+
+/* the number of simultaneously queued TCP */
+#ifdef RT_LWIP_TCP_SEG_NUM
+#define MEMP_NUM_TCP_SEG            RT_LWIP_TCP_SEG_NUM
+#else
+#define MEMP_NUM_TCP_SEG            TCP_SND_QUEUELEN
+#endif
+
+/*
+ * You can re-define following setting in rtcofnig.h to overwrite the default
+ * setting in the lwip opts.h
+ */
+/* MEMP_NUM_NETBUF: the number of struct netbufs. */
+// #define MEMP_NUM_NETBUF             2
+/* MEMP_NUM_NETCONN: the number of struct netconns. */
+// #define MEMP_NUM_NETCONN            4
+
+/* MEMP_NUM_TCPIP_MSG_*: the number of struct tcpip_msg, which is used
+   for sequential API communication and incoming packets. Used in
+   src/api/tcpip.c. */
+// #define MEMP_NUM_TCPIP_MSG_API      16
+// #define MEMP_NUM_TCPIP_MSG_INPKT    16
+
+/* ---------- Pbuf options ---------- */
+/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
+#ifdef RT_LWIP_PBUF_NUM
+#define PBUF_POOL_SIZE               RT_LWIP_PBUF_NUM
+#endif
+
+/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
+#ifdef RT_LWIP_PBUF_POOL_BUFSIZE
+#define PBUF_POOL_BUFSIZE            RT_LWIP_PBUF_POOL_BUFSIZE
+#endif
+
+/* PBUF_LINK_HLEN: the number of bytes that should be allocated for a
+   link level header. */
+#define PBUF_LINK_HLEN              16
+
+#ifdef RT_LWIP_ETH_PAD_SIZE
+#define ETH_PAD_SIZE                RT_LWIP_ETH_PAD_SIZE
+#endif
+
+/** SYS_LIGHTWEIGHT_PROT
+ * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection
+ * for certain critical regions during buffer allocation, deallocation and memory
+ * allocation and deallocation.
+ */
+#define SYS_LIGHTWEIGHT_PROT        (NO_SYS==0)
+
+#ifdef LWIP_USING_NAT
+#define IP_NAT                      1
+#else
+#define IP_NAT                      0
+#endif
+
+/* ---------- TCP options ---------- */
+#ifdef RT_LWIP_TCP
+#define LWIP_TCP                    1
+#else
+#define LWIP_TCP                    0
+#endif
+
+#define TCP_TTL                     255
+
+/* Controls if TCP should queue segments that arrive out of
+   order. Define to 0 if your device is low on memory. */
+#define TCP_QUEUE_OOSEQ             1
+
+/* TCP Maximum segment size. */
+#define TCP_MSS                     1460
+
+/* TCP sender buffer space (bytes). */
+#ifdef RT_LWIP_TCP_SND_BUF
+#define TCP_SND_BUF                 RT_LWIP_TCP_SND_BUF
+#else
+#define TCP_SND_BUF                 (TCP_MSS * 2)
+#endif
+
+/* TCP sender buffer space (pbufs). This must be at least = 2 *
+   TCP_SND_BUF/TCP_MSS for things to work. */
+#define TCP_SND_QUEUELEN            (4 * TCP_SND_BUF/TCP_MSS)
+
+/* TCP writable space (bytes). This must be less than or equal
+   to TCP_SND_BUF. It is the amount of space which must be
+   available in the tcp snd_buf for select to return writable */
+#define TCP_SNDLOWAT                (TCP_SND_BUF/2)
+#define TCP_SNDQUEUELOWAT           TCP_SND_QUEUELEN/2
+
+/* TCP receive window. */
+#ifdef RT_LWIP_TCP_WND
+#define TCP_WND                     RT_LWIP_TCP_WND
+#else
+#define TCP_WND                     (TCP_MSS * 2)
+#endif
+
+/* Maximum number of retransmissions of data segments. */
+#define TCP_MAXRTX                  12
+
+/* Maximum number of retransmissions of SYN segments. */
+#define TCP_SYNMAXRTX               4
+
+/* tcpip thread options */
+#ifdef RT_LWIP_TCPTHREAD_PRIORITY
+#define TCPIP_MBOX_SIZE             RT_LWIP_TCPTHREAD_MBOX_SIZE
+#define TCPIP_THREAD_PRIO           RT_LWIP_TCPTHREAD_PRIORITY
+#define TCPIP_THREAD_STACKSIZE      RT_LWIP_TCPTHREAD_STACKSIZE
+#else
+#define TCPIP_MBOX_SIZE             8
+#define TCPIP_THREAD_PRIO           128
+#define TCPIP_THREAD_STACKSIZE      4096
+#endif
+#define TCPIP_THREAD_NAME           "tcpip"
+#define DEFAULT_TCP_RECVMBOX_SIZE   10
+
+/* ---------- ARP options ---------- */
+#define LWIP_ARP                    1
+#define ARP_TABLE_SIZE              10
+#define ARP_QUEUEING                1
+
+/* ---------- Checksum options ---------- */
+#ifdef RT_LWIP_USING_HW_CHECKSUM
+#define CHECKSUM_GEN_IP                 0
+#define CHECKSUM_GEN_UDP                0
+#define CHECKSUM_GEN_TCP                0
+#define CHECKSUM_GEN_ICMP               0
+#define CHECKSUM_CHECK_IP               0
+#define CHECKSUM_CHECK_UDP              0
+#define CHECKSUM_CHECK_TCP              0
+#define CHECKSUM_CHECK_ICMP             0
+#endif
+
+/* ---------- IP options ---------- */
+/* Define IP_FORWARD to 1 if you wish to have the ability to forward
+   IP packets across network interfaces. If you are going to run lwIP
+   on a device with only one network interface, define this to 0. */
+#define IP_FORWARD                  0
+
+/* IP reassembly and segmentation.These are orthogonal even
+ * if they both deal with IP fragments */
+#ifdef RT_LWIP_REASSEMBLY_FRAG
+#define IP_REASSEMBLY               1
+#define IP_FRAG                     1
+#define IP_REASS_MAX_PBUFS          10
+#define MEMP_NUM_REASSDATA          10
+#else
+#define IP_REASSEMBLY               0
+#define IP_FRAG                     0
+#endif
+
+/* ---------- ICMP options ---------- */
+#define ICMP_TTL                    255
+
+/* ---------- DHCP options ---------- */
+/* Define LWIP_DHCP to 1 if you want DHCP configuration of
+   interfaces. */
+#ifdef RT_LWIP_DHCP
+#define LWIP_DHCP                   1
+#else
+#define LWIP_DHCP                   0
+#endif
+
+/* 1 if you want to do an ARP check on the offered address
+   (recommended). */
+#define DHCP_DOES_ARP_CHECK         (LWIP_DHCP)
+
+/* ---------- AUTOIP options ------- */
+#define LWIP_AUTOIP                 0
+#define LWIP_DHCP_AUTOIP_COOP       (LWIP_DHCP && LWIP_AUTOIP)
+
+/* ---------- UDP options ---------- */
+#ifdef RT_LWIP_UDP
+#define LWIP_UDP                    1
+#else
+#define LWIP_UDP                    0
+#endif
+
+#define LWIP_UDPLITE                0
+#define UDP_TTL                     255
+#define DEFAULT_UDP_RECVMBOX_SIZE   1
+
+/* ---------- RAW options ---------- */
+#ifdef RT_LWIP_RAW
+#define LWIP_RAW                    1
+#else
+#define LWIP_RAW                    0
+#endif
+
+#define DEFAULT_RAW_RECVMBOX_SIZE   1
+#define DEFAULT_ACCEPTMBOX_SIZE     10
+
+/* ---------- Statistics options ---------- */
+#ifdef RT_LWIP_STATS
+#define LWIP_STATS                  1
+#define LWIP_STATS_DISPLAY          1
+#else
+#define LWIP_STATS                  0
+#endif
+
+#if LWIP_STATS
+#define LINK_STATS                  1
+#define IP_STATS                    1
+#define ICMP_STATS                  1
+#define IGMP_STATS                  1
+#define IPFRAG_STATS                1
+#define UDP_STATS                   1
+#define TCP_STATS                   1
+#define MEM_STATS                   1
+#define MEMP_STATS                  1
+#define PBUF_STATS                  1
+#define SYS_STATS                   1
+#define MIB2_STATS                  1
+#endif /* LWIP_STATS */
+
+/* ---------- PPP options ---------- */
+#ifdef RT_LWIP_PPP
+#define PPP_SUPPORT                 1      /* Set > 0 for PPP */
+#else
+#define PPP_SUPPORT                 0      /* Set > 0 for PPP */
+#endif
+
+#if PPP_SUPPORT
+#define NUM_PPP                     1      /* Max PPP sessions. */
+
+/* Select modules to enable.  Ideally these would be set in the makefile but
+ * we're limited by the command line length so you need to modify the settings
+ * in this file.
+ */
+#ifdef RT_LWIP_PPPOE
+#define PPPOE_SUPPORT               1
+#else
+#define PPPOE_SUPPORT               0
+#endif
+
+#ifdef RT_LWIP_PPPOS
+#define PPPOS_SUPPORT               1
+#else
+#define PPPOS_SUPPORT               0
+#endif
+
+#define PAP_SUPPORT                 1      /* Set > 0 for PAP. */
+#define CHAP_SUPPORT                1      /* Set > 0 for CHAP. */
+#define MSCHAP_SUPPORT              0      /* Set > 0 for MSCHAP (NOT FUNCTIONAL!) */
+#define CBCP_SUPPORT                0      /* Set > 0 for CBCP (NOT FUNCTIONAL!) */
+#define CCP_SUPPORT                 0      /* Set > 0 for CCP (NOT FUNCTIONAL!) */
+#define VJ_SUPPORT                  1      /* Set > 0 for VJ header compression. */
+#define MD5_SUPPORT                 1      /* Set > 0 for MD5 (see also CHAP) */
+
+#endif /* PPP_SUPPORT */
+
+/**
+ * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names.
+ * Disable this option if you use a POSIX operating system that uses the same
+ * names (read, write & close). (only used if you use sockets.c)
+ */
+#ifndef LWIP_POSIX_SOCKETS_IO_NAMES
+#define LWIP_POSIX_SOCKETS_IO_NAMES     0
+#endif
+
+/**
+ * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT
+ * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set
+ * in seconds. (does not require sockets.c, and will affect tcp.c)
+ */
+#ifndef LWIP_TCP_KEEPALIVE
+#define LWIP_TCP_KEEPALIVE              1
+#endif
+
+/**
+ * LWIP_NETIF_HOSTNAME==1: Support netif hostname
+ */
+#ifndef LWIP_NETIF_HOSTNAME
+#define LWIP_NETIF_HOSTNAME             1
+#endif
+
+/**
+ * LWIP_NETIF_API==1: Support netif api (in netifapi.c)
+ */
+#ifndef LWIP_NETIF_API
+#define LWIP_NETIF_API                  1
+#endif
+
+#ifdef LWIP_IGMP
+#include <stdlib.h>
+#define LWIP_RAND                  rand
+#endif
+/*
+   ------------------------------------
+   ---------- Socket options ----------
+   ------------------------------------
+*/
+/*
+ * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)
+ */
+#ifndef LWIP_SOCKET
+#define LWIP_SOCKET                     1
+#endif
+
+/*
+ * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names.
+ * (only used if you use sockets.c)
+ */
+#ifdef SAL_USING_POSIX
+#define LWIP_COMPAT_SOCKETS             0
+#else
+#ifndef LWIP_COMPAT_SOCKETS
+#define LWIP_COMPAT_SOCKETS             1
+#endif
+#endif
+
+/**
+ * LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and
+ * SO_SNDTIMEO processing.
+ */
+#ifndef LWIP_SO_SNDTIMEO
+#define LWIP_SO_SNDTIMEO                1
+#endif
+
+/**
+ * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and
+ * SO_RCVTIMEO processing.
+ */
+#ifndef LWIP_SO_RCVTIMEO
+#define LWIP_SO_RCVTIMEO                1
+#endif
+
+/**
+ * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing.
+ */
+#ifndef LWIP_SO_RCVBUF
+#define LWIP_SO_RCVBUF                  1
+#endif
+
+/**
+ * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize.
+ */
+#ifndef RECV_BUFSIZE_DEFAULT
+#define RECV_BUFSIZE_DEFAULT            8192
+#endif
+
+/**
+ * SO_REUSE==1: Enable SO_REUSEADDR option.
+ */
+#ifndef SO_REUSE
+#define SO_REUSE                        0
+#endif
+
+/*
+   ------------------------------------
+   ------- Applications options -------
+   ------------------------------------
+*/
+
+/**
+ * Max. length of TFTP filename
+ */
+#ifdef RT_LWIP_TFTP_MAX_FILENAME_LEN
+#define TFTP_MAX_FILENAME_LEN           RT_LWIP_TFTP_MAX_FILENAME_LEN
+#elif defined(RT_DFS_ELM_MAX_LFN)
+#define TFTP_MAX_FILENAME_LEN           RT_DFS_ELM_MAX_LFN
+#else
+#define TFTP_MAX_FILENAME_LEN           64
+#endif
+
+
+#endif /* __LWIPOPTS_H__ */

+ 10 - 0
components/net/lwip-2.1.2/src/lwippools.h

@@ -0,0 +1,10 @@
+#if 1
+ LWIP_MALLOC_MEMPOOL_START
+ LWIP_MALLOC_MEMPOOL((unsigned char)128, 256)
+ LWIP_MALLOC_MEMPOOL((unsigned char)128, 512)
+ LWIP_MALLOC_MEMPOOL((unsigned char)128, 1024)
+ LWIP_MALLOC_MEMPOOL((unsigned char)128, 1514)
+ LWIP_MALLOC_MEMPOOL((unsigned char)128, 1536)
+ LWIP_MALLOC_MEMPOOL((unsigned char)128, 4096)
+ LWIP_MALLOC_MEMPOOL_END
+#endif

+ 1000 - 0
components/net/lwip-2.1.2/src/netif/ethernetif.c

@@ -0,0 +1,1000 @@
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * COPYRIGHT (C) 2006-2018, RT-Thread Development Team
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2010-07-07     Bernard      fix send mail to mailbox issue.
+ * 2011-07-30     mbbill       port lwIP 1.4.0 to RT-Thread
+ * 2012-04-10     Bernard      add more compatible with RT-Thread.
+ * 2012-11-12     Bernard      The network interface can be initialized
+ *                             after lwIP initialization.
+ * 2013-02-28     aozima       fixed list_tcps bug: ipaddr_ntoa isn't reentrant.
+ * 2016-08-18     Bernard      port to lwIP 2.0.0
+ * 2018-11-02     MurphyZhao   port to lwIP 2.1.0
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/opt.h"
+#include "lwip/debug.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/pbuf.h"
+#include "lwip/sys.h"
+#include "lwip/netif.h"
+#include "lwip/stats.h"
+#include "lwip/tcpip.h"
+#include "lwip/dhcp.h"
+#include "lwip/netifapi.h"
+
+#include "netif/etharp.h"
+#include "netif/ethernetif.h"
+
+#include "lwip/inet.h"
+
+#if LWIP_IPV6
+#include "lwip/ethip6.h"
+#endif /* LWIP_IPV6 */
+
+#define netifapi_netif_set_link_up(n)      netifapi_netif_common(n, netif_set_link_up, NULL)
+#define netifapi_netif_set_link_down(n)    netifapi_netif_common(n, netif_set_link_down, NULL)
+
+#ifndef RT_LWIP_ETHTHREAD_PRIORITY
+#define RT_ETHERNETIF_THREAD_PREORITY   0x90
+#else
+#define RT_ETHERNETIF_THREAD_PREORITY   RT_LWIP_ETHTHREAD_PRIORITY
+#endif
+
+#ifndef LWIP_NO_TX_THREAD
+/**
+ * Tx message structure for Ethernet interface
+ */
+struct eth_tx_msg
+{
+    struct netif    *netif;
+    struct pbuf     *buf;
+};
+
+static struct rt_mailbox eth_tx_thread_mb;
+static struct rt_thread eth_tx_thread;
+#ifndef RT_LWIP_ETHTHREAD_MBOX_SIZE
+static char eth_tx_thread_mb_pool[32 * 4];
+static char eth_tx_thread_stack[512];
+#else
+static char eth_tx_thread_mb_pool[RT_LWIP_ETHTHREAD_MBOX_SIZE * 4];
+static char eth_tx_thread_stack[RT_LWIP_ETHTHREAD_STACKSIZE];
+#endif
+#endif
+
+#ifndef LWIP_NO_RX_THREAD
+static struct rt_mailbox eth_rx_thread_mb;
+static struct rt_thread eth_rx_thread;
+#ifndef RT_LWIP_ETHTHREAD_MBOX_SIZE
+static char eth_rx_thread_mb_pool[48 * 4];
+static char eth_rx_thread_stack[1024];
+#else
+static char eth_rx_thread_mb_pool[RT_LWIP_ETHTHREAD_MBOX_SIZE * 4];
+static char eth_rx_thread_stack[RT_LWIP_ETHTHREAD_STACKSIZE];
+#endif
+#endif
+
+#ifdef RT_USING_NETDEV
+
+#include "lwip/ip.h"
+#include "lwip/init.h"
+#include "lwip/netdb.h"
+#include <netdev.h>
+
+static int lwip_netdev_set_up(struct netdev *netif)
+{
+    netif_set_up((struct netif *)netif->user_data);
+    return ERR_OK;
+}
+
+static int lwip_netdev_set_down(struct netdev *netif)
+{
+    netif_set_down((struct netif *)netif->user_data);
+    return ERR_OK;
+}
+
+static int lwip_netdev_set_addr_info(struct netdev *netif, ip_addr_t *ip_addr, ip_addr_t *netmask, ip_addr_t *gw)
+{
+    if (ip_addr && netmask && gw)
+    {
+        netif_set_addr((struct netif *)netif->user_data, ip_2_ip4(ip_addr), ip_2_ip4(netmask), ip_2_ip4(gw));
+    }
+    else
+    {
+        if (ip_addr)
+        {
+            netif_set_ipaddr((struct netif *)netif->user_data, ip_2_ip4(ip_addr));
+        }
+
+        if (netmask)
+        {
+            netif_set_netmask((struct netif *)netif->user_data, ip_2_ip4(netmask));
+        }
+
+        if (gw)
+        {
+            netif_set_gw((struct netif *)netif->user_data, ip_2_ip4(gw));
+        }
+    }
+
+    return ERR_OK;
+}
+
+#ifdef RT_LWIP_DNS
+static int lwip_netdev_set_dns_server(struct netdev *netif, uint8_t dns_num, ip_addr_t *dns_server)
+{
+    extern void dns_setserver(uint8_t dns_num, const ip_addr_t *dns_server);
+    dns_setserver(dns_num, dns_server);
+    return ERR_OK;
+}
+#endif /* RT_LWIP_DNS */
+
+#ifdef RT_LWIP_DHCP
+static int lwip_netdev_set_dhcp(struct netdev *netif, rt_bool_t is_enabled)
+{
+    netdev_low_level_set_dhcp_status(netif, is_enabled);
+    return ERR_OK;
+}
+#endif /* RT_LWIP_DHCP */
+
+#ifdef RT_USING_FINSH
+#ifdef RT_LWIP_USING_PING
+extern int lwip_ping_recv(int s, int *ttl);
+extern err_t lwip_ping_send(int s, ip_addr_t *addr, int size);
+
+int lwip_netdev_ping(struct netdev *netif, const char *host, size_t data_len, 
+                        uint32_t timeout, struct netdev_ping_resp *ping_resp)
+{
+    int s, ttl, recv_len, result = 0;
+    int elapsed_time;
+    rt_tick_t recv_start_tick;
+#if LWIP_VERSION_MAJOR >= 2U
+    struct timeval recv_timeout = { timeout / RT_TICK_PER_SECOND, timeout % RT_TICK_PER_SECOND };
+#else
+    int recv_timeout = timeout * 1000UL / RT_TICK_PER_SECOND;
+#endif
+    ip_addr_t target_addr;
+    struct addrinfo hint, *res = RT_NULL;
+    struct sockaddr_in *h = RT_NULL;
+    struct in_addr ina;
+    
+    RT_ASSERT(netif);
+    RT_ASSERT(host);
+    RT_ASSERT(ping_resp);
+
+    rt_memset(&hint, 0x00, sizeof(hint));
+    /* convert URL to IP */
+    if (lwip_getaddrinfo(host, RT_NULL, &hint, &res) != 0)
+    {
+        return -RT_ERROR;
+    }
+    rt_memcpy(&h, &res->ai_addr, sizeof(struct sockaddr_in *));
+    rt_memcpy(&ina, &h->sin_addr, sizeof(ina));
+    lwip_freeaddrinfo(res);
+    if (inet_aton(inet_ntoa(ina), &target_addr) == 0)
+    {
+        return -RT_ERROR;
+    }
+    rt_memcpy(&(ping_resp->ip_addr), &target_addr, sizeof(ip_addr_t));
+    
+    /* new a socket */
+    if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0)
+    {
+        return -RT_ERROR;
+    }
+
+    lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &recv_timeout, sizeof(recv_timeout));
+
+    if (lwip_ping_send(s, &target_addr, data_len) == ERR_OK)
+    {
+        recv_start_tick = rt_tick_get();
+        if ((recv_len = lwip_ping_recv(s, &ttl)) >= 0)
+        {
+            elapsed_time = (rt_tick_get() - recv_start_tick) * 1000UL / RT_TICK_PER_SECOND;
+            ping_resp->data_len = recv_len;
+            ping_resp->ttl = ttl;
+            ping_resp->ticks = elapsed_time;
+        }
+        else
+        {
+            result = -RT_ETIMEOUT;
+            goto __exit;
+        }
+    }
+    else
+    {
+        result = -RT_ETIMEOUT;
+        goto __exit;
+    }
+
+__exit:
+    lwip_close(s);
+
+    return result;
+}
+#endif /* RT_LWIP_USING_PING */
+
+#if defined (RT_LWIP_TCP) || defined (RT_LWIP_UDP)
+void lwip_netdev_netstat(struct netdev *netif)
+{
+    extern void list_tcps(void);
+    extern void list_udps(void);
+
+#ifdef RT_LWIP_TCP
+    list_tcps();
+#endif
+#ifdef RT_LWIP_UDP
+    list_udps();
+#endif
+}
+#endif /* RT_LWIP_TCP || RT_LWIP_UDP */
+#endif /* RT_USING_FINSH */
+
+static int lwip_netdev_set_default(struct netdev *netif)
+{
+    netif_set_default((struct netif *)netif->user_data);
+    return ERR_OK;
+}
+
+const struct netdev_ops lwip_netdev_ops =
+{
+    lwip_netdev_set_up,
+    lwip_netdev_set_down,
+
+    lwip_netdev_set_addr_info,
+#ifdef RT_LWIP_DNS
+    lwip_netdev_set_dns_server,
+#else 
+    NULL,
+#endif /* RT_LWIP_DNS */
+
+#ifdef RT_LWIP_DHCP
+    lwip_netdev_set_dhcp,
+#else
+    NULL,
+#endif /* RT_LWIP_DHCP */
+
+#ifdef RT_USING_FINSH
+#ifdef RT_LWIP_USING_PING
+    lwip_netdev_ping,
+#else
+    NULL,
+#endif /* RT_LWIP_USING_PING */
+
+#if defined (RT_LWIP_TCP) || defined (RT_LWIP_UDP)
+    lwip_netdev_netstat,
+#endif /* RT_LWIP_TCP || RT_LWIP_UDP */
+#endif /* RT_USING_FINSH */
+
+    lwip_netdev_set_default,
+};
+
+static int netdev_add(struct netif *lwip_netif)
+{
+#define LWIP_NETIF_NAME_LEN 2
+    int result = 0;
+    struct netdev *netdev = RT_NULL;
+    char name[LWIP_NETIF_NAME_LEN + 1] = {0};
+
+    RT_ASSERT(lwip_netif);
+
+    netdev = (struct netdev *)rt_calloc(1, sizeof(struct netdev));
+    if (netdev == RT_NULL)
+    {
+        return -ERR_IF;
+    }
+    
+#ifdef SAL_USING_LWIP
+    extern int sal_lwip_netdev_set_pf_info(struct netdev *netdev);
+    /* set the lwIP network interface device protocol family information */
+    sal_lwip_netdev_set_pf_info(netdev);
+#endif /* SAL_USING_LWIP */
+
+    rt_strncpy(name, lwip_netif->name, LWIP_NETIF_NAME_LEN);
+    result = netdev_register(netdev, name, (void *)lwip_netif);
+	
+    /* Update netdev info after registered */
+    netdev->flags = lwip_netif->flags;
+    netdev->mtu = lwip_netif->mtu;
+    netdev->ops = &lwip_netdev_ops;
+    netdev->hwaddr_len =  lwip_netif->hwaddr_len;
+    rt_memcpy(netdev->hwaddr, lwip_netif->hwaddr, lwip_netif->hwaddr_len);
+    netdev->ip_addr = lwip_netif->ip_addr;
+    netdev->gw = lwip_netif->gw;
+    netdev->netmask = lwip_netif->netmask;
+
+#ifdef RT_LWIP_DHCP
+    netdev_low_level_set_dhcp_status(netdev, RT_TRUE);
+#endif
+
+    return result;
+}
+
+static void netdev_del(struct netif *lwip_netif)
+{
+    char name[LWIP_NETIF_NAME_LEN + 1];
+    struct netdev *netdev;
+
+    RT_ASSERT(lwip_netif);
+
+    rt_strncpy(name, lwip_netif->name, LWIP_NETIF_NAME_LEN);
+    netdev = netdev_get_by_name(name);
+    netdev_unregister(netdev);
+    rt_free(netdev);
+}
+
+/* synchronize lwIP network interface device and network interface device flags */
+static int netdev_flags_sync(struct netif *lwip_netif)
+{
+    struct netdev *netdev = NULL;
+
+    RT_ASSERT(lwip_netif);
+
+    netdev = netdev_get_by_name(lwip_netif->name);
+    if (netdev == RT_NULL)
+    {
+        return -ERR_IF;
+    }
+    
+    netdev->mtu = lwip_netif->mtu;
+    netdev->flags |= lwip_netif->flags;
+
+    return ERR_OK;
+}
+#endif /* RT_USING_NETDEV */
+
+static err_t ethernetif_linkoutput(struct netif *netif, struct pbuf *p)
+{
+#ifndef LWIP_NO_TX_THREAD
+    struct eth_tx_msg msg;
+    struct eth_device* enetif;
+
+    RT_ASSERT(netif != RT_NULL);
+    enetif = (struct eth_device*)netif->state;
+
+    /* send a message to eth tx thread */
+    msg.netif = netif;
+    msg.buf   = p;
+    if (rt_mb_send(&eth_tx_thread_mb, (rt_uint32_t) &msg) == RT_EOK)
+    {
+        /* waiting for ack */
+        rt_sem_take(&(enetif->tx_ack), RT_WAITING_FOREVER);
+    }
+#else
+    struct eth_device* enetif;
+
+    RT_ASSERT(netif != RT_NULL);
+    enetif = (struct eth_device*)netif->state;
+
+    if (enetif->eth_tx(&(enetif->parent), p) != RT_EOK)
+    {
+        return ERR_IF;
+    }
+#endif
+    return ERR_OK;
+}
+
+static err_t eth_netif_device_init(struct netif *netif)
+{
+    struct eth_device *ethif;
+
+    ethif = (struct eth_device*)netif->state;
+    if (ethif != RT_NULL)
+    {
+        rt_device_t device;
+
+#ifdef RT_USING_NETDEV
+    /* network interface device register */
+    netdev_add(netif);
+#endif /* RT_USING_NETDEV */
+
+        /* get device object */
+        device = (rt_device_t) ethif;
+        if (rt_device_init(device) != RT_EOK)
+        {
+            return ERR_IF;
+        }
+
+        /* copy device flags to netif flags */
+        netif->flags = (ethif->flags & 0xff);
+        netif->mtu = ETHERNET_MTU;
+        
+        /* set output */
+        netif->output       = etharp_output;
+
+#if LWIP_IPV6
+        netif->output_ip6 = ethip6_output;
+        netif->ip6_autoconfig_enabled = 1;
+        netif_create_ip6_linklocal_address(netif, 1);
+
+#if LWIP_IPV6_MLD
+        netif->flags |= NETIF_FLAG_MLD6;
+
+        /*
+        * For hardware/netifs that implement MAC filtering.
+        * All-nodes link-local is handled by default, so we must let the hardware know
+        * to allow multicast packets in.
+        * Should set mld_mac_filter previously. */
+        if (netif->mld_mac_filter != NULL)
+        {
+            ip6_addr_t ip6_allnodes_ll;
+            ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll);
+            netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER);
+        }
+#endif /* LWIP_IPV6_MLD */
+
+#endif /* LWIP_IPV6 */
+
+        /* set default netif */
+        if (netif_default == RT_NULL)
+            netif_set_default(ethif->netif);
+
+#if LWIP_DHCP
+        /* set interface up */
+        netif_set_up(ethif->netif);
+        /* if this interface uses DHCP, start the DHCP client */
+        dhcp_start(ethif->netif);
+#else
+        /* set interface up */
+        netif_set_up(ethif->netif);
+#endif
+
+        if (ethif->flags & ETHIF_LINK_PHYUP)
+        {
+            /* set link_up for this netif */
+            netif_set_link_up(ethif->netif);
+        }
+
+        return ERR_OK;
+    }
+
+    return ERR_IF;
+}
+
+/* Keep old drivers compatible in RT-Thread */
+rt_err_t eth_device_init_with_flag(struct eth_device *dev, const char *name, rt_uint16_t flags)
+{
+    struct netif* netif;
+#if LWIP_NETIF_HOSTNAME
+#define LWIP_HOSTNAME_LEN 16
+    char *hostname = RT_NULL;
+    netif = (struct netif*) rt_calloc (1, sizeof(struct netif) + LWIP_HOSTNAME_LEN);
+#else
+    netif = (struct netif*) rt_calloc (1, sizeof(struct netif));
+#endif
+    if (netif == RT_NULL)
+    {
+        rt_kprintf("malloc netif failed\n");
+        return -RT_ERROR;
+    }
+
+    /* set netif */
+    dev->netif = netif;
+    /* device flags, which will be set to netif flags when initializing */
+    dev->flags = flags;
+    /* link changed status of device */
+    dev->link_changed = 0x00;
+    dev->parent.type = RT_Device_Class_NetIf;
+    /* register to RT-Thread device manager */
+    rt_device_register(&(dev->parent), name, RT_DEVICE_FLAG_RDWR);
+    rt_sem_init(&(dev->tx_ack), name, 0, RT_IPC_FLAG_FIFO);
+
+    /* set name */
+    netif->name[0] = name[0];
+    netif->name[1] = name[1];
+
+    /* set hw address to 6 */
+    netif->hwaddr_len   = 6;
+    /* maximum transfer unit */
+    netif->mtu          = ETHERNET_MTU;
+
+    /* set linkoutput */
+    netif->linkoutput   = ethernetif_linkoutput;
+        
+    /* get hardware MAC address */
+    rt_device_control(&(dev->parent), NIOCTL_GADDR, netif->hwaddr);
+
+#if LWIP_NETIF_HOSTNAME
+    /* Initialize interface hostname */
+    hostname = (char *)netif + sizeof(struct netif);
+    rt_sprintf(hostname, "rtthread_%02x%02x", name[0], name[1]);
+    netif->hostname = hostname;
+#endif /* LWIP_NETIF_HOSTNAME */
+
+    /* if tcp thread has been started up, we add this netif to the system */
+    if (rt_thread_find("tcpip") != RT_NULL)
+    {
+        ip4_addr_t ipaddr, netmask, gw;
+
+#if !LWIP_DHCP
+        ipaddr.addr = inet_addr(RT_LWIP_IPADDR);
+        gw.addr = inet_addr(RT_LWIP_GWADDR);
+        netmask.addr = inet_addr(RT_LWIP_MSKADDR);
+#else        
+        IP4_ADDR(&ipaddr, 0, 0, 0, 0);
+        IP4_ADDR(&gw, 0, 0, 0, 0);
+        IP4_ADDR(&netmask, 0, 0, 0, 0);
+#endif
+        netifapi_netif_add(netif, &ipaddr, &netmask, &gw, dev, eth_netif_device_init, tcpip_input);
+    }
+
+#ifdef RT_USING_NETDEV
+    /* network interface device flags synchronize */
+    netdev_flags_sync(netif);
+#endif /* RT_USING_NETDEV */
+
+    return RT_EOK;
+}
+
+rt_err_t eth_device_init(struct eth_device * dev, const char *name)
+{
+    rt_uint16_t flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
+
+#if LWIP_IGMP
+    /* IGMP support */
+    flags |= NETIF_FLAG_IGMP;
+#endif
+
+    return eth_device_init_with_flag(dev, name, flags);
+}
+
+void eth_device_deinit(struct eth_device *dev)
+{
+    struct netif* netif = dev->netif;
+
+#if LWIP_DHCP
+    dhcp_stop(netif);
+    dhcp_cleanup(netif);
+#endif
+    netif_set_down(netif);
+    netif_remove(netif);
+#ifdef RT_USING_NETDEV
+    netdev_del(netif);
+#endif
+    rt_device_close(&(dev->parent));
+    rt_device_unregister(&(dev->parent));
+    rt_sem_detach(&(dev->tx_ack));
+    rt_free(netif);
+}
+
+#ifndef LWIP_NO_RX_THREAD
+rt_err_t eth_device_ready(struct eth_device* dev)
+{
+    if (dev->netif)
+        /* post message to Ethernet thread */
+        return rt_mb_send(&eth_rx_thread_mb, (rt_uint32_t)dev);
+    else
+        return ERR_OK; /* netif is not initialized yet, just return. */
+}
+
+rt_err_t eth_device_linkchange(struct eth_device* dev, rt_bool_t up)
+{
+    rt_uint32_t level;
+
+    RT_ASSERT(dev != RT_NULL);
+
+    level = rt_hw_interrupt_disable();
+    dev->link_changed = 0x01;
+    if (up == RT_TRUE)
+        dev->link_status = 0x01;
+    else
+        dev->link_status = 0x00;
+    rt_hw_interrupt_enable(level);
+
+    /* post message to ethernet thread */
+    return rt_mb_send(&eth_rx_thread_mb, (rt_uint32_t)dev);
+}
+#else
+/* NOTE: please not use it in interrupt when no RxThread exist */
+rt_err_t eth_device_linkchange(struct eth_device* dev, rt_bool_t up)
+{
+    if (up == RT_TRUE)
+        netifapi_netif_set_link_up(dev->netif);
+    else
+        netifapi_netif_set_link_down(dev->netif);
+
+    return RT_EOK;
+}
+#endif
+
+#ifndef LWIP_NO_TX_THREAD
+/* Ethernet Tx Thread */
+static void eth_tx_thread_entry(void* parameter)
+{
+    struct eth_tx_msg* msg;
+
+    while (1)
+    {
+        if (rt_mb_recv(&eth_tx_thread_mb, (rt_ubase_t *)&msg, RT_WAITING_FOREVER) == RT_EOK)
+        {
+            struct eth_device* enetif;
+
+            RT_ASSERT(msg->netif != RT_NULL);
+            RT_ASSERT(msg->buf   != RT_NULL);
+
+            enetif = (struct eth_device*)msg->netif->state;
+            if (enetif != RT_NULL)
+            {
+                /* call driver's interface */
+                if (enetif->eth_tx(&(enetif->parent), msg->buf) != RT_EOK)
+                {
+                    /* transmit eth packet failed */
+                }
+            }
+
+            /* send ACK */
+            rt_sem_release(&(enetif->tx_ack));
+        }
+    }
+}
+#endif
+
+#ifndef LWIP_NO_RX_THREAD
+/* Ethernet Rx Thread */
+static void eth_rx_thread_entry(void* parameter)
+{
+    struct eth_device* device;
+
+    while (1)
+    {
+        if (rt_mb_recv(&eth_rx_thread_mb, (rt_ubase_t *)&device, RT_WAITING_FOREVER) == RT_EOK)
+        {
+            struct pbuf *p;
+
+            /* check link status */
+            if (device->link_changed)
+            {
+                int status;
+                rt_uint32_t level;
+
+                level = rt_hw_interrupt_disable();
+                status = device->link_status;
+                device->link_changed = 0x00;
+                rt_hw_interrupt_enable(level);
+
+                if (status)
+                    netifapi_netif_set_link_up(device->netif);
+                else
+                    netifapi_netif_set_link_down(device->netif);
+            }
+
+            /* receive all of buffer */
+            while (1)
+            {
+                if(device->eth_rx == RT_NULL) break;
+                
+                p = device->eth_rx(&(device->parent));
+                if (p != RT_NULL)
+                {
+                    /* notify to upper layer */
+                    if( device->netif->input(p, device->netif) != ERR_OK )
+                    {
+                        LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: Input error\n"));
+                        pbuf_free(p);
+                        p = NULL;
+                    }
+                }
+                else break;
+            }
+        }
+        else
+        {
+            LWIP_ASSERT("Should not happen!\n",0);
+        }
+    }
+}
+#endif
+
+/* this function does not need, 
+ * use eth_system_device_init_private() 
+ * call by lwip_system_init(). 
+ */
+int eth_system_device_init(void)
+{
+    return 0;
+}
+
+int eth_system_device_init_private(void)
+{
+    rt_err_t result = RT_EOK;
+
+    /* initialize Rx thread. */
+#ifndef LWIP_NO_RX_THREAD
+    /* initialize mailbox and create Ethernet Rx thread */
+    result = rt_mb_init(&eth_rx_thread_mb, "erxmb",
+                        &eth_rx_thread_mb_pool[0], sizeof(eth_rx_thread_mb_pool)/4,
+                        RT_IPC_FLAG_FIFO);
+    RT_ASSERT(result == RT_EOK);
+
+    result = rt_thread_init(&eth_rx_thread, "erx", eth_rx_thread_entry, RT_NULL,
+                            &eth_rx_thread_stack[0], sizeof(eth_rx_thread_stack),
+                            RT_ETHERNETIF_THREAD_PREORITY, 16);
+    RT_ASSERT(result == RT_EOK);
+    result = rt_thread_startup(&eth_rx_thread);
+    RT_ASSERT(result == RT_EOK);
+#endif
+
+    /* initialize Tx thread */
+#ifndef LWIP_NO_TX_THREAD
+    /* initialize mailbox and create Ethernet Tx thread */
+    result = rt_mb_init(&eth_tx_thread_mb, "etxmb",
+                        &eth_tx_thread_mb_pool[0], sizeof(eth_tx_thread_mb_pool)/4,
+                        RT_IPC_FLAG_FIFO);
+    RT_ASSERT(result == RT_EOK);
+
+    result = rt_thread_init(&eth_tx_thread, "etx", eth_tx_thread_entry, RT_NULL,
+                            &eth_tx_thread_stack[0], sizeof(eth_tx_thread_stack),
+                            RT_ETHERNETIF_THREAD_PREORITY, 16);
+    RT_ASSERT(result == RT_EOK);
+
+    result = rt_thread_startup(&eth_tx_thread);
+    RT_ASSERT(result == RT_EOK);
+#endif
+
+    return (int)result;
+}
+
+void set_if(char* netif_name, char* ip_addr, char* gw_addr, char* nm_addr)
+{
+    ip4_addr_t *ip;
+    ip4_addr_t addr;
+    struct netif * netif = netif_list;
+
+    if(strlen(netif_name) > sizeof(netif->name))
+    {
+        rt_kprintf("network interface name too long!\r\n");
+        return;
+    }
+
+    while(netif != RT_NULL)
+    {
+        if(strncmp(netif_name, netif->name, sizeof(netif->name)) == 0)
+            break;
+
+        netif = netif->next;
+        if( netif == RT_NULL )
+        {
+            rt_kprintf("network interface: %s not found!\r\n", netif_name);
+            return;
+        }
+    }
+
+    ip = (ip4_addr_t *)&addr;
+
+    /* set ip address */
+    if ((ip_addr != RT_NULL) && ip4addr_aton(ip_addr, &addr))
+    {
+        netif_set_ipaddr(netif, ip);
+    }
+
+    /* set gateway address */
+    if ((gw_addr != RT_NULL) && ip4addr_aton(gw_addr, &addr))
+    {
+        netif_set_gw(netif, ip);
+    }
+
+    /* set netmask address */
+    if ((nm_addr != RT_NULL) && ip4addr_aton(nm_addr, &addr))
+    {
+        netif_set_netmask(netif, ip);
+    }
+}
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(set_if, set network interface address);
+
+#if LWIP_DNS
+#include <lwip/dns.h>
+void set_dns(uint8_t dns_num, char* dns_server)
+{
+    ip_addr_t addr;
+
+    if ((dns_server != RT_NULL) && ipaddr_aton(dns_server, &addr))
+    {
+        dns_setserver(dns_num, &addr);
+    }
+}
+FINSH_FUNCTION_EXPORT(set_dns, set DNS server address);
+#endif
+
+void list_if(void)
+{
+    rt_ubase_t index;
+    struct netif * netif;
+
+    rt_enter_critical();
+
+    netif = netif_list;
+
+    while( netif != RT_NULL )
+    {
+        rt_kprintf("network interface: %c%c%s\n",
+                   netif->name[0],
+                   netif->name[1],
+                   (netif == netif_default)?" (Default)":"");
+        rt_kprintf("MTU: %d\n", netif->mtu);
+        rt_kprintf("MAC: ");
+        for (index = 0; index < netif->hwaddr_len; index ++)
+            rt_kprintf("%02x ", netif->hwaddr[index]);
+        rt_kprintf("\nFLAGS:");
+        if (netif->flags & NETIF_FLAG_UP) rt_kprintf(" UP");
+        else rt_kprintf(" DOWN");
+        if (netif->flags & NETIF_FLAG_LINK_UP) rt_kprintf(" LINK_UP");
+        else rt_kprintf(" LINK_DOWN");
+        if (netif->flags & NETIF_FLAG_ETHARP) rt_kprintf(" ETHARP");
+        if (netif->flags & NETIF_FLAG_BROADCAST) rt_kprintf(" BROADCAST");
+        if (netif->flags & NETIF_FLAG_IGMP) rt_kprintf(" IGMP");
+        rt_kprintf("\n");
+        rt_kprintf("ip address: %s\n", ipaddr_ntoa(&(netif->ip_addr)));
+        rt_kprintf("gw address: %s\n", ipaddr_ntoa(&(netif->gw)));
+        rt_kprintf("net mask  : %s\n", ipaddr_ntoa(&(netif->netmask)));
+#if LWIP_IPV6
+		{
+			ip6_addr_t *addr;
+			int addr_state;
+			int i;
+			
+			addr = (ip6_addr_t *)&netif->ip6_addr[0];
+			addr_state = netif->ip6_addr_state[0];
+			
+			rt_kprintf("\nipv6 link-local: %s state:%02X %s\n", ip6addr_ntoa(addr), 
+			addr_state, ip6_addr_isvalid(addr_state)?"VALID":"INVALID");
+			
+			for(i=1; i<LWIP_IPV6_NUM_ADDRESSES; i++)
+			{
+				addr = (ip6_addr_t *)&netif->ip6_addr[i];
+				addr_state = netif->ip6_addr_state[i];
+			
+				rt_kprintf("ipv6[%d] address: %s state:%02X %s\n", i, ip6addr_ntoa(addr), 
+				addr_state, ip6_addr_isvalid(addr_state)?"VALID":"INVALID");
+			}
+			
+		}
+        rt_kprintf("\r\n");
+#endif /* LWIP_IPV6 */
+        netif = netif->next;
+    }
+
+#if LWIP_DNS
+    {
+        const ip_addr_t *ip_addr;
+
+        for(index=0; index<DNS_MAX_SERVERS; index++)
+        {
+            ip_addr = dns_getserver(index);
+            rt_kprintf("dns server #%d: %s\n", index, ipaddr_ntoa(ip_addr));
+        }
+    }
+#endif /**< #if LWIP_DNS */
+
+    rt_exit_critical();
+}
+FINSH_FUNCTION_EXPORT(list_if, list network interface information);
+
+#if LWIP_TCP
+#include <lwip/tcp.h>
+#include <lwip/priv/tcp_priv.h>
+
+void list_tcps(void)
+{
+    rt_uint32_t num = 0;
+    struct tcp_pcb *pcb;
+    char local_ip_str[16];
+    char remote_ip_str[16];
+
+    extern struct tcp_pcb *tcp_active_pcbs;
+    extern union tcp_listen_pcbs_t tcp_listen_pcbs;
+    extern struct tcp_pcb *tcp_tw_pcbs;
+
+    rt_enter_critical();
+    rt_kprintf("Active PCB states:\n");
+    for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next)
+    {
+        strcpy(local_ip_str, ipaddr_ntoa(&(pcb->local_ip)));
+        strcpy(remote_ip_str, ipaddr_ntoa(&(pcb->remote_ip)));
+
+        rt_kprintf("#%d %s:%d <==> %s:%d snd_nxt 0x%08X rcv_nxt 0x%08X ",
+                   num++,
+                   local_ip_str,
+                   pcb->local_port,
+                   remote_ip_str,
+                   pcb->remote_port,
+                   pcb->snd_nxt,
+                   pcb->rcv_nxt);
+        rt_kprintf("state: %s\n", tcp_debug_state_str(pcb->state));
+    }
+
+    rt_kprintf("Listen PCB states:\n");
+    num = 0;
+    for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next)
+    {
+        rt_kprintf("#%d local port %d ", num++, pcb->local_port);
+        rt_kprintf("state: %s\n", tcp_debug_state_str(pcb->state));
+    }
+
+    rt_kprintf("TIME-WAIT PCB states:\n");
+    num = 0;
+    for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next)
+    {
+        strcpy(local_ip_str, ipaddr_ntoa(&(pcb->local_ip)));
+        strcpy(remote_ip_str, ipaddr_ntoa(&(pcb->remote_ip)));
+
+        rt_kprintf("#%d %s:%d <==> %s:%d snd_nxt 0x%08X rcv_nxt 0x%08X ",
+                   num++,
+                   local_ip_str,
+                   pcb->local_port,
+                   remote_ip_str,
+                   pcb->remote_port,
+                   pcb->snd_nxt,
+                   pcb->rcv_nxt);
+        rt_kprintf("state: %s\n", tcp_debug_state_str(pcb->state));
+    }
+    rt_exit_critical();
+}
+FINSH_FUNCTION_EXPORT(list_tcps, list all of tcp connections);
+#endif /* LWIP_TCP */
+
+#if LWIP_UDP
+#include "lwip/udp.h"
+void list_udps(void)
+{
+    struct udp_pcb *pcb;
+    rt_uint32_t num = 0;
+    char local_ip_str[16];
+    char remote_ip_str[16];
+
+    rt_enter_critical();
+    rt_kprintf("Active UDP PCB states:\n");
+    for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next)
+    {
+        strcpy(local_ip_str, ipaddr_ntoa(&(pcb->local_ip)));
+        strcpy(remote_ip_str, ipaddr_ntoa(&(pcb->remote_ip)));
+
+        rt_kprintf("#%d %d %s:%d <==> %s:%d \n",
+                   num, (int)pcb->flags,
+                   local_ip_str,
+                   pcb->local_port,
+                   remote_ip_str,
+                   pcb->remote_port);
+
+        num++;
+    }
+    rt_exit_critical();
+}
+FINSH_FUNCTION_EXPORT(list_udps, list all of udp connections);
+#endif /* LWIP_UDP */
+
+#endif