Explorar o código

add: 添加napt支持, 跑通Air780E+Air601的NAPT

Wendal Chen hai 1 ano
pai
achega
227144dc84

+ 173 - 0
components/network/ulwip/binding/luat_lib_napt.c

@@ -0,0 +1,173 @@
+/*
+@module  natp
+@summary 网络地址端口转换(开发中)
+@version 1.0
+@date    2024.4.22
+@auther  wendal
+@tag     LUAT_USE_NAPT
+@usage
+-- 开发中, 请关注 https://github.com/wendal/xt804-spinet
+*/
+
+#include "luat_base.h"
+#include "luat_ulwip.h"
+#include "luat_napt.h"
+#include "luat_crypto.h"
+#include "luat_zbuff.h"
+#include "luat_network_adapter.h"
+
+#define LUAT_LOG_TAG "napt"
+#include "luat_log.h"
+
+extern uint8_t napt_target_adapter;
+
+/*
+初始化NAPT
+@api napt.init(adapter)
+@int adapter 目标网卡索引, 默认是socket.LWIP_AP, 这里指内网
+@return nil 无返回值
+*/
+static int l_napt_init(lua_State *L) {
+    if (lua_isinteger(L, 1)) {
+        napt_target_adapter = lua_tointeger(L, 1);
+    }
+    else {
+        napt_target_adapter = NW_ADAPTER_INDEX_LWIP_WIFI_AP;
+    }
+    return 0;
+}
+
+// EC618/EC7XX的特殊逻辑
+#if ENABLE_PSIF
+
+#ifndef UINT8
+#define UINT8  uint8_t
+#endif
+#ifndef UINT16
+#define UINT16 uint16_t
+#endif
+#ifndef UINT32
+#define UINT32 uint32_t
+#endif
+#ifndef BOOL
+#define BOOL   uint8_t
+#endif
+static void toPs(void *ctx)
+{
+    extern BOOL PsifRawUlOutput(UINT8, UINT8 *, UINT16);
+
+    uint8_t *pkt = (uint8_t *)((void **)ctx)[0];
+    uint32_t len = (uint32_t)((void **)ctx)[1];
+
+    uint8_t ipv = pkt[0];
+    ipv = ((ipv >> 4) & 0x0F);
+    UINT8 cid = ipv == 4 ? 1 : 2;
+
+    int rc = PsifRawUlOutput(cid, pkt, len);
+    if (rc) {
+        LLOGE("PsifRawUlOutput rc %d", rc);
+    }
+
+    luat_heap_free(ctx);
+    luat_heap_free(pkt);
+}
+
+static void sendIp2Ps(uint8_t *pkt, uint32_t len, struct netif* netif)
+{
+    void **param = (void **)luat_heap_malloc(sizeof(void *) * 2);
+    if (param == NULL) {
+        LLOGE("no mem for sendIp2Ps");
+        return;
+    }
+    param[0] = (void *)pkt;
+    param[1] = (void *)len;
+    int rc = tcpip_callback(toPs, param);
+    if (rc) {
+        luat_heap_free(param);
+        luat_heap_free(pkt);
+    }
+}
+#endif
+
+/*
+重建MAC包
+@api napt.rebuild(buff, is_inet, adapter)
+@userdata 待处理的MAC包,必须是zbuff对象
+@bool 来源是不是内网
+@int 目标网络适配器的索引, 例如socket.LWIP_GP
+@return bool 成功返回true,失败返回false
+*/
+static int l_napt_rebuild(lua_State *L) {
+    luat_zbuff_t* zbuff = tozbuff(L);
+    u8 is_inet = lua_toboolean(L, 2);
+    ip_addr_t gw_ip = {0};
+    struct netif* netif = NULL;
+    int ip = -1;
+    ip = luaL_checkinteger(L, 3);
+    if (ip < 0) {
+        return 0;
+    }
+    if (ip >= NW_ADAPTER_INDEX_LWIP_NETIF_QTY) {
+        return 0;
+    }
+    netif = ulwip_find_netif(ip);
+    if (netif == NULL) {
+        return 0;
+    }
+    ip_addr_set_ip4_u32(&gw_ip, ip_addr_get_ip4_u32(&netif->ip_addr));
+    int dlen = zbuff->len - zbuff->used;
+    uint8_t* data = (uint8_t*)zbuff->addr + zbuff->used;
+    int rc = luat_napt_input(is_inet, (u8*)data, dlen, &gw_ip);
+    if (!rc) {
+        if (is_inet)
+            memcpy(data, netif->hwaddr, 6);
+        else {
+            // LLOGD("赋值mac %02x:%02x:%02x:%02x:%02x:%02x", netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2],
+            // netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5]);
+            memcpy(data + 6, netif->hwaddr, 6);
+        }
+        #if ENABLE_PSIF
+        if (ip == NW_ADAPTER_INDEX_LWIP_GPRS) {
+            char* tmp = luat_heap_malloc(dlen - 14);
+            if (!tmp) {
+                LLOGE("no mem for sendIp2Ps");
+                return 0;
+            }
+            memcpy(tmp, data + 14, dlen - 14);
+            sendIp2Ps((uint8_t*)tmp, dlen - 14, netif);
+            lua_pushboolean(L, 1);
+            return 1;
+        }
+        #endif
+        lua_pushboolean(L, 1);
+        return 1;
+    }
+    return 0;
+}
+
+/*
+检查和清理NAT表
+@api napt.check()
+@return nil
+@usage
+-- 需要周期性调用, 30秒一次
+*/
+static int l_napt_check(lua_State *L) {
+    luat_napt_table_check(NULL);
+    return 0;
+}
+
+#include "rotable2.h"
+static const rotable_Reg_t reg_napt[] =
+{
+    { "init" ,              ROREG_FUNC(l_napt_init)},
+    { "rebuild",            ROREG_FUNC(l_napt_rebuild)},
+    { "check",              ROREG_FUNC(l_napt_check)},
+	{ NULL,                 ROREG_INT(0)}
+};
+
+LUAMOD_API int luaopen_napt( lua_State *L ) {
+    luat_napt_init();
+    luat_newlib2(L, reg_napt);
+    return 1;
+}

+ 35 - 76
components/network/ulwip/binding/luat_lib_ulwip.c

@@ -20,6 +20,8 @@ lua代码 <- ulwip回调函数 <- lwip(netif->low_level_output) <- lwip处理逻
 1. Air601的wifi模块作为被控端, 通过UART/SPI收发MAC包, 实现Air780E/Air780EP集成wifi模块的功能
 2. 使用W5500/CH395/ENC28J60等以太网模块, 在用户lua代码中控制其mac包收发, 并集成到luatos socket框架中
 3. 通过蓝牙模块,集成lowpan6
+
+-- 开发中, 请关注 https://github.com/wendal/xt804-spinet
 ]]
 */
 
@@ -34,7 +36,7 @@ static ulwip_ctx_t nets[USERLWIP_NET_COUNT];
 extern struct netif *netif_default;
 
 // 搜索adpater_index对应的netif
-static struct netif* find_netif(uint8_t adapter_index) {
+struct netif* ulwip_find_netif(uint8_t adapter_index) {
     struct netif *netif = NULL;
     for (size_t i = 0; i < USERLWIP_NET_COUNT; i++)
     {
@@ -47,7 +49,7 @@ static struct netif* find_netif(uint8_t adapter_index) {
     return netif;
 }
 
-static int find_index(uint8_t adapter_index) {
+int ulwip_find_index(uint8_t adapter_index) {
     for (size_t i = 0; i < USERLWIP_NET_COUNT; i++)
     {
         if (nets[i].adapter_index == adapter_index)
@@ -103,10 +105,10 @@ int ulwip_netif_ip_event(ulwip_ctx_t* ctx) {
 }
 
 // 回调函数, 用于lwip的netif输出数据
-static int netif_output_cb(lua_State *L, void* ptr) {
-    // LLOGD("netif_output_cb");
+int l_ulwip_netif_output_cb(lua_State *L, void* ptr) {
+    // LLOGD("l_ulwip_netif_output_cb");
     rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
-    int idx = find_index(msg->arg2);
+    int idx = ulwip_find_index(msg->arg2);
     if (idx < 0 || nets[idx].netif == NULL) {
         LLOGE("非法的适配器索引号 %d", msg->arg2);
         return 0;
@@ -118,7 +120,7 @@ static int netif_output_cb(lua_State *L, void* ptr) {
             luat_zbuff_t* buff = lua_newuserdata(L, sizeof(luat_zbuff_t));
             if (buff == NULL)
             {
-                LLOGE("malloc failed for netif_output_cb");
+                LLOGE("malloc failed for l_ulwip_netif_output_cb");
                 return 0;
             }
             memset(buff, 0, sizeof(luat_zbuff_t));
@@ -143,7 +145,7 @@ static int netif_output_cb(lua_State *L, void* ptr) {
 static err_t netif_output(struct netif *netif, struct pbuf *p) {
     // LLOGD("lwip待发送数据 %p %d", p, p->tot_len);
     rtos_msg_t msg = {0};
-    msg.handler = netif_output_cb;
+    msg.handler = l_ulwip_netif_output_cb;
     msg.arg1 = p->tot_len;
     msg.arg2 = -1;
     for (size_t i = 0; i < USERLWIP_NET_COUNT; i++)
@@ -262,6 +264,9 @@ static int l_ulwip_setup(lua_State *L) {
         if (lua_isinteger(L, -1)) {
             reverse = (uint8_t)luaL_checkinteger(L, -1);
         }
+        if (lua_isboolean(L, -1)) {
+            reverse = (uint8_t)lua_toboolean(L, -1);
+        }
         lua_pop(L, 1);
     }
 
@@ -271,6 +276,7 @@ static int l_ulwip_setup(lua_State *L) {
     {
         if (nets[i].netif == NULL)
         {
+            
             if (reverse) {
                 #if defined(CHIP_EC718) || defined(CHIP_EC618) || defined(CHIP_EC716)
                 extern struct netif * net_lwip_get_netif(uint8_t adapter_index);
@@ -292,6 +298,7 @@ static int l_ulwip_setup(lua_State *L) {
                 memcpy(nets[i].hwaddr, netif->hwaddr, ETH_HWADDR_LEN);
                 nets[i].output_lua_ref = luaL_ref(L, LUA_REGISTRYINDEX);
                 lua_pushboolean(L, 1);
+                LLOGD("挂载netif(reverse模式) %p %d %d", netif, i, adapter_index);
                 return 1;
             }
 
@@ -307,6 +314,7 @@ static int l_ulwip_setup(lua_State *L) {
                 lua_pushvalue(L, 3);
                 memcpy(nets[i].hwaddr, mac, ETH_HWADDR_LEN);
                 nets[i].output_lua_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+                LLOGD("挂载netif(普通模式) %p %d %d", netif, i, adapter_index);
                 break;
             }
         }
@@ -347,7 +355,7 @@ static int l_ulwip_setup(lua_State *L) {
 static int l_ulwip_updown(lua_State *L) {
     // 必须有适配器编号
     uint8_t adapter_index = (uint8_t)luaL_checkinteger(L, 1);
-    int idx = find_index(adapter_index);
+    int idx = ulwip_find_index(adapter_index);
     if (idx < 0) {
         LLOGE("没有找到netif");
         return 0;
@@ -377,7 +385,7 @@ static int l_ulwip_updown(lua_State *L) {
 static int l_ulwip_link(lua_State *L) {
     // 必须有适配器编号
     uint8_t adapter_index = (uint8_t)luaL_checkinteger(L, 1);
-    int idx = find_index(adapter_index);
+    int idx = ulwip_find_index(adapter_index);
     if (idx < 0) {
         LLOGE("没有找到netif");
         return 0;
@@ -399,27 +407,20 @@ static int l_ulwip_link(lua_State *L) {
 
 static void netif_input_cb(void *ptr) {
     netif_cb_ctx_t* cb_ctx = (netif_cb_ctx_t*)ptr;
-    if (cb_ctx->ctx->reverse) {
-        if (ERR_OK != cb_ctx->ctx->netif->output(cb_ctx->ctx->netif, cb_ctx->p, NULL)) {
-            LLOGW("ctx->netif->input 失败 %d", cb_ctx->p->tot_len);
-            pbuf_free(cb_ctx->p);
-        }
-    }
-    else {
-        if (ERR_OK != cb_ctx->ctx->netif->input(cb_ctx->p, cb_ctx->ctx->netif)) {
-            LLOGW("ctx->netif->input 失败 %d", cb_ctx->p->tot_len);
-            pbuf_free(cb_ctx->p);
-        }
-
+    if (ERR_OK != cb_ctx->ctx->netif->input(cb_ctx->p, cb_ctx->ctx->netif)) {
+        LLOGW("ctx->netif->input 失败 %d", cb_ctx->p->tot_len);
+        pbuf_free(cb_ctx->p);
     }
     luat_heap_free(cb_ctx);
 }
 
 /*
 往netif输入数据
-@api ulwip.input(adapter_index, data)
+@api ulwip.input(adapter_index, data, len, offset)
 @int adapter_index 适配器编号
-@string data 输入的数据
+@string/userdata data 输入的数据
+@int 如果data是zbuff, len默认是zbuff的used, 对string无效
+@int 如果data是zbuff, offset为数据起始位置, 默认是0, 对string无效
 @return boolean 成功与否
 @usage
 -- 参考ulwip.setup
@@ -432,11 +433,15 @@ static int l_ulwip_input(lua_State *L) {
     const char* data = NULL;
     size_t len = 0;
     size_t offset = 0;
-    int idx = find_index(adapter_index);
+    int idx = ulwip_find_index(adapter_index);
     if (idx < 0) {
         LLOGE("没有找到netif %d", adapter_index);
         return 0;
     }
+    if (nets[idx].netif == NULL || nets[idx].netif->input == NULL) {
+        LLOGE("该netif 不支持input操作 %d", adapter_index);
+        return 0;
+    }
     if (lua_type(L, 2) == LUA_TSTRING)
     {
         data = luaL_checklstring(L, 2, &len);
@@ -468,12 +473,7 @@ static int l_ulwip_input(lua_State *L) {
         data += q->len;
     }
     #if NO_SYS
-    if (nets[idx].reverse) {
-        ret = nets[idx].netif->output(p, nets[idx].netif, NULL);
-    }
-    else {
-        ret = nets[idx].netif->input(p, nets[idx].netif);
-    }
+    ret = nets[idx].netif->input(p, nets[idx].netif);
     #else
     netif_cb_ctx_t* cb_ctx = (netif_cb_ctx_t*)luat_heap_malloc(sizeof(netif_cb_ctx_t));
     if (cb_ctx == NULL) {
@@ -514,13 +514,13 @@ static int l_ulwip_input(lua_State *L) {
 static int l_ulwip_dhcp(lua_State *L) {
     // 必须有适配器编号
     uint8_t adapter_index = (uint8_t)luaL_checkinteger(L, 1);
-    struct netif* netif = find_netif(adapter_index);
+    struct netif* netif = ulwip_find_netif(adapter_index);
     if (netif == NULL) {
         LLOGE("没有找到netif");
         return 0;
     }
     int dhcp_enable = lua_toboolean(L, 2);
-    int i = find_index(adapter_index);
+    int i = ulwip_find_index(adapter_index);
     if (i < 0)
     {
         LLOGE("没有找到adapter_index %d", adapter_index);
@@ -556,7 +556,7 @@ static int l_ulwip_ip(lua_State *L) {
     const char* tmp = NULL;
     // 必须有适配器编号
     uint8_t adapter_index = (uint8_t)luaL_checkinteger(L, 1);
-    struct netif* netif = find_netif(adapter_index);
+    struct netif* netif = ulwip_find_netif(adapter_index);
     if (netif == NULL) {
         LLOGE("没有找到netif %d", adapter_index);
         return 0;
@@ -570,7 +570,7 @@ static int l_ulwip_ip(lua_State *L) {
         tmp = luaL_checkstring(L, 4);
         ipaddr_aton(tmp, &netif->gw);
         
-        int idx = find_index(adapter_index);
+        int idx = ulwip_find_index(adapter_index);
         nets[idx].ip_static = !ip_addr_isany(&netif->ip_addr);
     }
     // 反馈IP信息
@@ -594,7 +594,7 @@ static int l_ulwip_ip(lua_State *L) {
 static int l_ulwip_reg(lua_State *L) {
     // 必须有适配器编号
     uint8_t adapter_index = (uint8_t)luaL_checkinteger(L, 1);
-    struct netif* netif = find_netif(adapter_index);
+    struct netif* netif = ulwip_find_netif(adapter_index);
     if (netif == NULL) {
         LLOGE("没有找到netif %d", adapter_index);
         return 0;
@@ -637,44 +637,3 @@ LUAMOD_API int luaopen_ulwip( lua_State *L ) {
     luat_newlib2(L, reg_ulwip);
     return 1;
 }
-
-// 针对EC618/EC7xx平台的IP包输入回调
-err_t ulwip_ip_input_cb(struct pbuf *p, struct netif *inp) {
-    for (size_t i = 0; i < NW_ADAPTER_INDEX_LWIP_NETIF_QTY; i++)
-    {
-        if (nets[i].netif == inp)
-        {
-            // TODO 过滤一下当前能处理的包
-            // 回调到lua中
-            netif_output(inp, p);
-            break;
-        }
-    }
-    
-    // LLOGD("收到IP数据包(len=%d)", p->tot_len);
-    // u8_t ipVersion;
-    // ipVersion = IP_HDR_GET_VERSION(p->payload);
-    // if (ipVersion == 4) {
-    //     // 解析出里面的协议内容
-    //     struct ip_hdr *ip = (struct ip_hdr *)p->payload;
-    //     u16_t udpPort = 0;
-    //     if (ip->_proto == IP_PROTO_UDP) {
-    //         // UDP协议
-    //         struct udp_hdr *udp = (struct udp_hdr *)((char*)p->payload + sizeof(struct ip_hdr));
-    //         udpPort = lwip_ntohs(udp->dest);
-    //     }
-    //     else if (ip->_proto == IP_PROTO_TCP) {
-    //         // TCP协议
-    //         struct tcp_hdr *tcp = (struct tcp_hdr *)((char*)p->payload + sizeof(struct ip_hdr));
-    //         udpPort = lwip_ntohs(tcp->dest);
-    //     }
-    //     // else {
-    //     //     // 其他协议
-    //     //     LLOGD("IP协议版本 %d, 协议 %d, 源端口 %d, 目的端口 %d", ipVersion, IP_HDR_GET_PROTO(ip), lwip_ntohs(ip->src.addr), udpPort);
-    //     // }
-    //     char buff[32] = {0};
-    //     ip4addr_ntoa_r(&ip->src, buff, 32);
-    //     LLOGD("IP协议版本 %d, 协议 %d, 源IP %s, 目的端口 %d", ipVersion, ip->_proto, buff, udpPort);
-    // }
-    return ERR_OK;
-}

+ 61 - 0
components/network/ulwip/include/luat_napt.h

@@ -0,0 +1,61 @@
+#ifndef LUAT_NAPT_H
+#define LUAT_NAPT_H
+
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C"{
+#endif
+#endif /* __cplusplus */
+
+/* ============================== configure ===================== */
+/* napt age time (second) */
+#define NAPT_TABLE_TIMEOUT           60
+
+/* napt port range: 15000~25000 */
+#define NAPT_LOCAL_PORT_RANGE_START  0x3A98
+#define NAPT_LOCAL_PORT_RANGE_END    0x61A8
+
+/* napt icmp id range: 3000-65535 */
+#define NAPT_ICMP_ID_RANGE_START     0xBB8
+#define NAPT_ICMP_ID_RANGE_END       0xFFFF
+
+
+/* napt table size */
+// #define NAPT_TABLE_LIMIT
+#ifdef  NAPT_TABLE_LIMIT
+#define NAPT_TABLE_SIZE_MAX          3000
+#endif
+/* ============================================================ */
+
+
+#define NAPT_TMR_INTERVAL            ((NAPT_TABLE_TIMEOUT / 2) * 1000UL)
+
+#ifndef u16
+#define u16  unsigned short
+#endif
+
+#ifndef u8
+#define u8   unsigned char
+#endif
+
+#ifndef u32
+#define u32  unsigned int
+#endif
+
+extern u8 luat_napt_port_is_used(u16 port);
+
+extern int luat_napt_init(void);
+
+extern int luat_napt_input(u8 is_inet, u8 *pkt_body, u32 pkt_len, ip_addr_t* gw_ip);
+
+void luat_napt_table_check(void *arg);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif
+#endif /* __cplusplus */
+
+#endif /* __ALG_H__ */
+

+ 3 - 0
components/network/ulwip/include/luat_ulwip.h

@@ -61,5 +61,8 @@ err_t ulwip_etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t
 int ulwip_netif_ip_event(ulwip_ctx_t* ctx);
 
 int l_dhcp_client_cb(lua_State *L, void* ptr);
+int l_ulwip_netif_output_cb(lua_State *L, void* ptr);
+
+struct netif* ulwip_find_netif(uint8_t adapter_index);
 
 #endif

+ 1403 - 0
components/network/ulwip/src/napt_ipv4.c

@@ -0,0 +1,1403 @@
+/*
+NAPT(Network Address Port Translation)
+IPv4版本的NAPT,支持TCP/UDP/ICMP协议
+原版代码来源:
+https://gitee.com/openLuat/luatos-soc-air101
+https://www.winnermicro.com/html/1/156/158/558.html
+
+为适应luatos环境做了大量修改, 脱离了平台依赖性
+*/
+#include "luat_base.h"
+#include <stdio.h>
+#include <string.h>
+#include "lwip/ip.h"
+#include "lwip/udp.h"
+#include "lwip/icmp.h"
+#include "lwip/dns.h"
+#include "lwip/priv/tcp_priv.h"
+#include "lwip/timeouts.h"
+
+#include "luat_napt.h"
+#include "luat_mem.h"
+
+#define LUAT_LOG_TAG "napt"
+#include "luat_log.h"
+
+//#define NAPT_ALLOC_DEBUG
+#ifdef  NAPT_ALLOC_DEBUG
+static u16 napt4ic_cnt;
+static u16 napt4tcp_cnt;
+static u16 napt4udp_cnt;
+#endif
+
+//#define NAPT_DEBUG
+#ifdef  NAPT_DEBUG
+#define NAPT_PRINT printf
+#else
+#define NAPT_PRINT(...)
+#endif
+
+#define IP_PROTO_GRE                 47
+
+#define NAPT_ETH_HDR_LEN             sizeof(struct ethhdr)
+
+#define NAPT_CHKSUM_16BIT_LEN        sizeof(u16)
+
+#define NAPT_TABLE_FOREACH(pos, head)\
+         for (pos = head.next; NULL != pos; pos = pos->next)
+
+/* napt tcp/udp */
+struct napt_addr_4tu{
+    struct napt_addr_4tu *next;
+    u16 src_port;
+    u16 new_port;
+    u8 src_ip;
+    u8 time_stamp;
+    u8 mac[6];
+};
+
+/* napt icmp */
+struct napt_addr_4ic{
+    struct napt_addr_4ic *next;
+    u16 src_id;/* icmp id */
+    u16 new_id;
+    u8 src_ip;
+    u8 time_stamp;
+    u8 mac[6];
+};
+
+struct napt_addr_gre{
+    u8 src_ip;
+    u8 time_stamp;
+    u8 is_used;
+    u8 mac[6];
+};
+
+struct napt_table_head_4tu{
+    struct napt_addr_4tu *next;
+#ifdef NAPT_TABLE_LIMIT
+    u16 cnt;
+#endif
+};
+
+struct napt_table_head_4ic{
+    struct napt_addr_4ic *next;
+#ifdef NAPT_TABLE_LIMIT
+    u16 cnt;
+#endif
+};
+
+/* napt head */
+static struct napt_table_head_4tu napt_table_4tcp;
+static struct napt_table_head_4tu napt_table_4udp;
+static struct napt_table_head_4ic napt_table_4ic;
+
+//#define NAPT_USE_HW_TIMER
+
+//#define NAPT_TABLE_MUTEX_LOCK
+#ifdef  NAPT_TABLE_MUTEX_LOCK
+static tls_os_sem_t *napt_table_lock_4tcp;
+static tls_os_sem_t *napt_table_lock_4udp;
+static tls_os_sem_t *napt_table_lock_4ic;
+#ifdef  NAPT_USE_HW_TIMER
+static bool napt_check_tcp = FALSE;
+static bool napt_check_udp = FALSE;
+static bool napt_check_ic  = FALSE;
+#endif /* NAPT_USE_HW_TIMER */
+#endif /* NAPT_TABLE_MUTEX_LOCK */
+
+/* tcp&udp */
+static u16 napt_curr_port;
+
+/* icmp id */
+static u16 napt_curr_id;
+
+/* gre for vpn */
+static struct napt_addr_gre gre_info;
+
+static inline void *luat_napt_mem_alloc(u32 size)
+{
+    return luat_heap_malloc(size);
+}
+
+static inline void luat_napt_mem_free(void *p)
+{
+    luat_heap_free(p);
+}
+
+/*****************************************************************************
+ Prototype    : luat_napt_try_lock
+ Description  : try hold lock
+ Input        : tls_os_sem_t *lock  point lock
+ Output       : None
+ Return Value : int  0  success
+                    -1  failed
+ ------------------------------------------------------------------------------
+ 
+  History        :
+  1.Date         : 2019/2/1
+    Author       : Li Limin, lilm@winnermicro.com
+    Modification : Created function
+
+*****************************************************************************/
+// static inline int luat_napt_try_lock(tls_os_sem_t *lock)
+// {
+//     return (tls_os_sem_acquire(lock, HZ / 10) == TLS_OS_SUCCESS) ? 0 : -1;
+//     return 0;
+// }
+
+/*****************************************************************************
+ Prototype    : luat_napt_lock
+ Description  : hold lock
+ Input        : tls_os_sem_t *lock  point lock
+ Output       : None
+ Return Value : void
+ ------------------------------------------------------------------------------
+ 
+  History        :
+  1.Date         : 2019/2/1
+    Author       : Li Limin, lilm@winnermicro.com
+    Modification : Created function
+
+*****************************************************************************/
+// static inline void luat_napt_lock(tls_os_sem_t *lock)
+// {
+//     tls_os_sem_acquire(lock, 0);
+//     return;
+// }
+
+/*****************************************************************************
+ Prototype    : luat_napt_unlock
+ Description  : release lock
+ Input        : tls_os_sem_t *lock  point lock
+ Output       : None
+ Return Value : void
+ ------------------------------------------------------------------------------
+ 
+  History        :
+  1.Date         : 2019/2/1
+    Author       : Li Limin, lilm@winnermicro.com
+    Modification : Created function
+
+*****************************************************************************/
+// static inline void luat_napt_unlock(tls_os_sem_t *lock)
+// {
+//     tls_os_sem_release(lock);
+// }
+
+#ifdef NAPT_TABLE_LIMIT
+/*****************************************************************************
+ Prototype    : luat_napt_table_is_full
+ Description  : the napt table is full
+ Input        : void
+ Output       : None
+ Return Value : bool    true   the napt table is full
+                        false  the napt table not is full
+ ------------------------------------------------------------------------------
+ 
+  History        :
+  1.Date         : 2015/3/10
+    Author       : Li Limin, lilm@winnermicro.com
+    Modification : Created function
+
+*****************************************************************************/
+static inline bool luat_napt_table_is_full(void)
+{
+    bool is_full = false;
+
+    if ((napt_table_4tcp.cnt + napt_table_4udp.cnt + napt_table_4ic.cnt) >= NAPT_TABLE_SIZE_MAX)
+    {
+#ifdef NAPT_ALLOC_DEBUG
+        printf("@@@ napt batle: limit is reached for tcp/udp.\r\n");
+#endif
+        NAPT_PRINT("napt batle: limit is reached for tcp/udp.\n");
+        is_full = true;
+    }
+
+    return is_full;
+}
+#endif
+
+static inline u16 luat_napt_port_alloc(void)
+{
+    u8_t i;
+    u16 cnt = 0;
+    struct udp_pcb *udp_pcb;
+    struct tcp_pcb *tcp_pcb;
+    struct napt_addr_4tu *napt_tcp;
+    struct napt_addr_4tu *napt_udp;
+
+again:
+    if (napt_curr_port++ == NAPT_LOCAL_PORT_RANGE_END)
+    {
+        napt_curr_port = NAPT_LOCAL_PORT_RANGE_START;
+    }
+
+    /* udp */
+    for(udp_pcb = udp_pcbs; udp_pcb != NULL; udp_pcb = udp_pcb->next)
+    {
+        if (udp_pcb->local_port == napt_curr_port)
+        {
+            if (++cnt > (NAPT_LOCAL_PORT_RANGE_END - NAPT_LOCAL_PORT_RANGE_START))
+            {
+                return 0;
+            }
+            goto again;
+        }
+    }
+
+    /* tcp */
+    for (i = 0; i < NUM_TCP_PCB_LISTS; i++)
+    {
+        for(tcp_pcb = *tcp_pcb_lists[i]; tcp_pcb != NULL; tcp_pcb = tcp_pcb->next)
+        {
+            if (tcp_pcb->local_port == napt_curr_port)
+            {
+                if (++cnt > (NAPT_LOCAL_PORT_RANGE_END - NAPT_LOCAL_PORT_RANGE_START))
+                {
+                    return 0;
+                }
+                goto again;
+            }
+        }
+    }
+
+    /* tcp napt */
+    NAPT_TABLE_FOREACH(napt_tcp, napt_table_4tcp)
+    {
+        if (napt_tcp->new_port == napt_curr_port)
+        {
+            if (++cnt > (NAPT_LOCAL_PORT_RANGE_END - NAPT_LOCAL_PORT_RANGE_START))
+            {
+                return 0;
+            }
+            goto again;
+        }
+    }
+
+    /* udp napt */
+    NAPT_TABLE_FOREACH(napt_udp, napt_table_4udp)
+    {
+        if (napt_udp->new_port == napt_curr_port)
+        {
+            if (++cnt > (NAPT_LOCAL_PORT_RANGE_END - NAPT_LOCAL_PORT_RANGE_START))
+            {
+                return 0;
+            }
+            goto again;
+        }
+    }
+
+    return napt_curr_port;
+}
+
+static inline struct napt_addr_4ic *luat_napt_get_by_src_id(u16 id, u8 ip)
+{
+    struct napt_addr_4ic *ret = NULL;
+    struct napt_addr_4ic *napt;
+
+    NAPT_TABLE_FOREACH(napt, napt_table_4ic)
+    {
+        if ((id == napt->src_id) && (ip == napt->src_ip))
+        {
+	       ret = napt;
+	       break;
+        }
+    }
+
+    return ret;
+}
+
+static inline struct napt_addr_4ic *luat_napt_get_by_dst_id(u16 id)
+{
+    struct napt_addr_4ic *ret = NULL;
+    struct napt_addr_4ic *napt;
+
+    NAPT_TABLE_FOREACH(napt, napt_table_4ic)
+    {
+        if (id == napt->new_id)
+        {
+	       ret = napt;
+	       break;
+        }
+    }
+
+    return ret;
+}
+
+static u16 luat_napt_icmp_id_alloc(void)
+{
+    u16 cnt = 0;
+    struct napt_addr_4ic *napt;
+
+again:
+    if (napt_curr_id++ == NAPT_ICMP_ID_RANGE_END)
+    {
+        napt_curr_id = NAPT_ICMP_ID_RANGE_START;
+    }
+
+    NAPT_TABLE_FOREACH(napt, napt_table_4ic)
+    {
+        if (napt_curr_id == napt->new_id)
+        {
+            if (++cnt > (NAPT_ICMP_ID_RANGE_END - NAPT_ICMP_ID_RANGE_START))
+            {
+                return 0;
+            }
+
+	       goto again;
+        }
+    }
+
+    return napt_curr_id;
+}
+
+static inline struct napt_addr_4ic *luat_napt_table_insert_4ic(u16 id, u8 ip)
+{
+    struct napt_addr_4ic *napt;
+
+#ifdef NAPT_TABLE_LIMIT
+    if (true == luat_napt_table_is_full())
+    {
+        return NULL;
+    }
+#endif
+
+    napt = luat_napt_mem_alloc(sizeof(struct napt_addr_4ic));
+    if (NULL == napt)
+    {
+        return NULL;
+    }
+
+    memset(napt, 0, sizeof(struct napt_addr_4ic));
+    napt->src_id = id;
+
+    napt->new_id = luat_napt_icmp_id_alloc();
+    if (0 == napt->new_id)
+    {
+        luat_napt_mem_free(napt);
+        return NULL;
+    }
+
+    napt->src_ip = ip;
+    napt->time_stamp++;
+
+#ifdef NAPT_TABLE_LIMIT
+    napt_table_4ic.cnt++;
+#endif
+    napt->next = napt_table_4ic.next;
+    napt_table_4ic.next = napt;
+    
+#ifdef NAPT_ALLOC_DEBUG
+    printf("@@ napt id alloc %hu\r\n", ++napt4ic_cnt);
+#endif
+
+    return napt;
+}
+
+static inline void luat_napt_table_update_4ic(struct napt_addr_4ic *napt)
+{
+    if (!++napt->time_stamp)
+        napt->time_stamp++;
+
+    return;
+}
+
+static inline struct napt_addr_4tu *luat_napt_get_tcp_port_by_dest(u16 port)
+{
+    struct napt_addr_4tu *ret = NULL;
+    struct napt_addr_4tu *napt;
+
+    NAPT_TABLE_FOREACH(napt, napt_table_4tcp)
+    {
+        if (napt->new_port == port)
+        {
+            ret = napt;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+static inline struct napt_addr_4tu *luat_napt_get_tcp_port_by_src(u16 port, u8 ip)
+{
+    struct napt_addr_4tu *ret = NULL;
+    struct napt_addr_4tu *napt;
+
+    NAPT_TABLE_FOREACH(napt, napt_table_4tcp)
+    {
+        if (port == napt->src_port)
+        {
+            if (ip == napt->src_ip)
+            {
+                ret = napt;
+                break;
+            }
+        }
+    }
+
+    return ret;
+}
+
+static inline struct napt_addr_4tu *luat_napt_table_insert_4tcp(u16 src_port, u8 ip)
+{
+    u16 new_port;
+    struct napt_addr_4tu *napt;
+
+#ifdef NAPT_TABLE_LIMIT
+    if (true == luat_napt_table_is_full())
+    {
+        return NULL;
+    }
+#endif
+
+    napt = luat_napt_mem_alloc(sizeof(struct napt_addr_4tu));
+    if (NULL == napt)
+    {
+        return NULL;
+    }
+
+    memset(napt, 0, sizeof(struct napt_addr_4tu));
+    napt->src_port = src_port;
+
+    new_port = luat_napt_port_alloc();
+    if (0 == new_port)
+    {
+        luat_napt_mem_free(napt);
+        return NULL;
+    }
+
+    napt->new_port = htons(new_port);
+    napt->src_ip = ip;
+    napt->time_stamp++;
+
+#ifdef NAPT_TABLE_LIMIT
+    napt_table_4tcp.cnt++;
+#endif
+    napt->next = napt_table_4tcp.next;
+    napt_table_4tcp.next = napt;
+
+#ifdef NAPT_ALLOC_DEBUG
+    printf("@@ napt tcp port alloc %hu\r\n", ++napt4tcp_cnt);
+#endif
+
+    return napt;
+}
+
+static inline void luat_napt_table_update_4tcp(struct napt_addr_4tu *napt)
+{
+    if (!++napt->time_stamp)
+        napt->time_stamp++;
+
+    return;
+}
+
+static inline struct napt_addr_4tu *luat_napt_get_udp_port_by_dest(u16 port)
+{
+    struct napt_addr_4tu *ret = NULL;
+    struct napt_addr_4tu *napt;
+
+    NAPT_TABLE_FOREACH(napt, napt_table_4udp)
+    {
+        if (napt->new_port == port)
+        {
+            ret = napt;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+static inline struct napt_addr_4tu *luat_napt_get_udp_port_by_src(u16 port, u8 ip)
+{
+    struct napt_addr_4tu *ret = NULL;
+    struct napt_addr_4tu *napt;
+
+    NAPT_TABLE_FOREACH(napt, napt_table_4udp)
+    {
+        if (port == napt->src_port)
+        {
+            if (ip == napt->src_ip)
+            {
+                ret = napt;
+                break;
+            }
+        }
+    }
+
+    return ret;
+}
+static inline struct napt_addr_4tu *luat_napt_table_insert_4udp(u16 src_port, u8 ip)
+{
+    u16 new_port;
+    struct napt_addr_4tu *napt;
+
+#ifdef NAPT_TABLE_LIMIT
+    if (true == luat_napt_table_is_full())
+    {
+        return NULL;
+    }
+#endif
+
+    napt = luat_napt_mem_alloc(sizeof(struct napt_addr_4tu));
+    if (NULL == napt)
+    {
+        return NULL;
+    }
+
+    memset(napt, 0, sizeof(struct napt_addr_4tu));
+    napt->src_port = src_port;
+
+    new_port = luat_napt_port_alloc();
+    if (0 == new_port)
+    {
+        luat_napt_mem_free(napt);
+        return NULL;
+    }
+
+    napt->new_port = htons(new_port);
+    napt->src_ip = ip;
+    napt->time_stamp++;
+
+#ifdef NAPT_TABLE_LIMIT
+    napt_table_4udp.cnt++;
+#endif
+    napt->next = napt_table_4udp.next;
+    napt_table_4udp.next = napt;
+
+#ifdef NAPT_ALLOC_DEBUG
+    printf("@@ napt udp port alloc %hu\r\n", ++napt4udp_cnt);
+#endif
+
+    return napt;
+}
+
+static inline void luat_napt_table_update_4udp(struct napt_addr_4tu *napt)
+{
+    if (!++napt->time_stamp)
+        napt->time_stamp++;
+
+    return;
+}
+
+static void luat_napt_table_check_4tcp(void)
+{
+    struct napt_addr_4tu *napt4tcp;
+    struct napt_addr_4tu *napt4tcp_prev;
+
+    /* tcp */
+#ifdef NAPT_TABLE_MUTEX_LOCK
+#ifdef NAPT_USE_HW_TIMER
+    if (luat_napt_try_lock(napt_table_lock_4tcp))
+    {
+        //printf("## try tcp\r\n");
+        napt_check_tcp = TRUE;
+        return;
+    }
+    napt_check_tcp = FALSE;
+#else
+    luat_napt_lock(napt_table_lock_4tcp);
+#endif
+#endif
+    for (napt4tcp_prev = napt_table_4tcp.next;\
+         NULL != napt4tcp_prev;\
+         napt4tcp_prev = napt4tcp_prev->next)
+    {
+        napt4tcp = napt4tcp_prev->next;
+        if (NULL != napt4tcp)
+        {
+            if (0 == napt4tcp->time_stamp)
+            {
+#ifdef NAPT_TABLE_LIMIT
+                napt_table_4tcp.cnt--;
+#endif
+                napt4tcp_prev->next = napt4tcp->next;
+                napt4tcp->next = NULL;
+                luat_napt_mem_free(napt4tcp);
+#ifdef NAPT_ALLOC_DEBUG
+                printf("@@ napt tcp port free %hu\r\n", --napt4tcp_cnt);
+#endif
+            }
+            else
+            {
+                napt4tcp->time_stamp = 0;
+            }
+        }
+        
+    }
+    napt4tcp = napt_table_4tcp.next;
+    if (NULL != napt4tcp)
+    {
+        if (0 == napt4tcp->time_stamp)
+        {
+#ifdef NAPT_TABLE_LIMIT
+            napt_table_4tcp.cnt--;
+#endif
+            napt_table_4tcp.next = napt4tcp->next;
+            napt4tcp->next = NULL;
+            luat_napt_mem_free(napt4tcp);
+#ifdef NAPT_ALLOC_DEBUG
+            printf("@@ napt tcp port free %hu\r\n", --napt4tcp_cnt);
+#endif
+        }
+        else
+        {
+            napt4tcp->time_stamp = 0;
+        }
+    }
+#ifdef NAPT_TABLE_MUTEX_LOCK
+    luat_napt_unlock(napt_table_lock_4tcp);
+#endif
+    return;
+}
+
+static void luat_napt_table_check_4udp(void)
+{
+    struct napt_addr_4tu *napt4udp;
+    struct napt_addr_4tu *napt4udp_prev;
+
+    /* udp */
+#ifdef NAPT_TABLE_MUTEX_LOCK
+#ifdef NAPT_USE_HW_TIMER
+    if (luat_napt_try_lock(napt_table_lock_4udp))
+    {
+        //printf("## try udp\r\n");
+        napt_check_udp = TRUE;
+        return;
+    }
+    napt_check_udp = FALSE;
+#else
+    luat_napt_lock(napt_table_lock_4udp);
+#endif
+#endif
+    for (napt4udp_prev = napt_table_4udp.next;\
+         NULL != napt4udp_prev;\
+         napt4udp_prev = napt4udp_prev->next)
+    {
+        napt4udp = napt4udp_prev->next;
+        if (NULL != napt4udp)
+        {
+            if (0 == napt4udp->time_stamp)
+            {
+#ifdef NAPT_TABLE_LIMIT
+                napt_table_4udp.cnt--;
+#endif
+                napt4udp_prev->next = napt4udp->next;
+                napt4udp->next = NULL;
+                luat_napt_mem_free(napt4udp);
+#ifdef NAPT_ALLOC_DEBUG
+                printf("@@ napt udp port free %hu\r\n", --napt4udp_cnt);
+#endif
+            }
+            else
+            {
+                napt4udp->time_stamp = 0;
+            }
+        }
+        
+    }
+    napt4udp = napt_table_4udp.next;
+    if (NULL != napt4udp)
+    {
+        if (0 == napt4udp->time_stamp)
+        {
+#ifdef NAPT_TABLE_LIMIT
+            napt_table_4udp.cnt--;
+#endif
+            napt_table_4udp.next = napt4udp->next;
+            napt4udp->next = NULL;
+            luat_napt_mem_free(napt4udp);
+#ifdef NAPT_ALLOC_DEBUG
+            printf("@@ napt udp port free %hu\r\n", --napt4udp_cnt);
+#endif
+        }
+        else
+        {
+            napt4udp->time_stamp = 0;
+        }
+    }
+#ifdef NAPT_TABLE_MUTEX_LOCK
+    luat_napt_unlock(napt_table_lock_4udp);
+#endif
+    return;
+}
+
+static void luat_napt_table_check_4ic(void)
+{
+    struct napt_addr_4ic *napt4ic;
+    struct napt_addr_4ic *napt4ic_prev;
+
+    /* icmp */
+#ifdef NAPT_TABLE_MUTEX_LOCK
+#ifdef NAPT_USE_HW_TIMER
+    if (luat_napt_try_lock(napt_table_lock_4ic))
+    {
+        //printf("## try ic\r\n");
+        napt_check_ic = TRUE;
+        return;
+    }
+    napt_check_ic = FALSE;
+#else
+    luat_napt_lock(napt_table_lock_4ic);
+#endif
+#endif
+    /* skip the first item */
+    for (napt4ic_prev = napt_table_4ic.next;\
+         NULL != napt4ic_prev;\
+         napt4ic_prev = napt4ic_prev->next)
+    {
+        napt4ic = napt4ic_prev->next;
+        if (NULL != napt4ic)
+        {
+            if (0 == napt4ic->time_stamp)
+            {
+#ifdef NAPT_TABLE_LIMIT
+                napt_table_4ic.cnt--;
+#endif
+                napt4ic_prev->next = napt4ic->next;
+                napt4ic->next = NULL;
+                luat_napt_mem_free(napt4ic);
+#ifdef NAPT_ALLOC_DEBUG
+                printf("@@ napt id free %hu\r\n", --napt4ic_cnt);
+#endif
+            }
+            else
+            {
+                napt4ic->time_stamp = 0;
+            }
+        }
+        
+    }
+    /* check the first item */
+    napt4ic = napt_table_4ic.next;
+    if (NULL != napt4ic)
+    {
+        if (0 == napt4ic->time_stamp)
+        {
+#ifdef NAPT_TABLE_LIMIT
+            napt_table_4ic.cnt--;
+#endif
+            napt_table_4ic.next = napt4ic->next;
+            napt4ic->next = NULL;
+            luat_napt_mem_free(napt4ic);
+#ifdef NAPT_ALLOC_DEBUG
+            printf("@@ napt id free %hu\r\n", --napt4ic_cnt);
+#endif
+        }
+        else
+        {
+            napt4ic->time_stamp = 0;
+        }
+    }
+#ifdef NAPT_TABLE_MUTEX_LOCK
+    luat_napt_unlock(napt_table_lock_4ic);
+#endif
+    return;
+}
+
+static void luat_napt_table_check_4gre(void)
+{
+    if (0 == gre_info.time_stamp)
+    {
+        gre_info.is_used = 0;
+        //gre_info.src_ip = 0;
+    }
+    else
+    {
+        gre_info.time_stamp = 0;
+    }
+
+    return;
+}
+
+void luat_napt_table_check(void *arg)
+{
+    luat_napt_table_check_4tcp();
+    luat_napt_table_check_4udp();
+    luat_napt_table_check_4ic();
+    luat_napt_table_check_4gre();
+
+    return;
+}
+
+#ifdef NAPT_USE_HW_TIMER
+static void luat_napt_table_check_try(void)
+{
+    if (napt_check_tcp)
+        luat_napt_table_check_4tcp();
+
+    if (napt_check_udp)
+        luat_napt_table_check_4udp();
+
+    if (napt_check_ic)
+        luat_napt_table_check_4ic();
+
+    return;
+}
+#endif
+
+static inline u32 alg_hdr_16bitsum(const u16 *buff, u16 len)
+{
+    u32 sum = 0;
+
+    u16 *pos = (u16 *)buff;
+    u16 remainder_size = len;
+
+    while (remainder_size > 1)
+    {
+        sum += *pos ++;
+        remainder_size -= NAPT_CHKSUM_16BIT_LEN;
+    }
+
+    if (remainder_size > 0)
+    {
+        sum += *(u8*)pos;
+    }
+
+    return sum;
+}
+
+static inline u16 alg_iphdr_chksum(const u16 *buff, u16 len)
+{
+    u32 sum = alg_hdr_16bitsum(buff, len);
+
+    sum = (sum >> 16) + (sum & 0xFFFF);
+    sum += (sum >> 16);
+
+    return (u16)(~sum);
+}
+
+static inline u16 alg_tcpudphdr_chksum(u32 src_addr, u32 dst_addr, u8 proto,
+                                       const u16 *buff, u16 len)
+{
+    u32 sum = 0;
+
+    sum += (src_addr & 0xffffUL);
+    sum += ((src_addr >> 16) & 0xffffUL);
+    sum += (dst_addr & 0xffffUL);
+    sum += ((dst_addr >> 16) & 0xffffUL);
+    sum += (u32)htons((u16)proto);
+    sum += (u32)htons(len);
+
+    sum += alg_hdr_16bitsum(buff, len);
+
+    sum = (sum >> 16) + (sum & 0xFFFF);
+    sum += (sum >> 16);
+
+    return (u16)(~sum);
+}
+
+static int alg_icmp_proc(u8 is_inet,
+                         struct ip_hdr *ip_hdr,
+                         ip_addr_t* gw_ip)
+{
+    int err = -1;
+    struct napt_addr_4ic *napt;
+    struct icmp_echo_hdr *icmp_hdr;
+    u8* ptr = ((u8*)ip_hdr) - 14;
+    u8 iphdr_len;
+
+    iphdr_len = (ip_hdr->_v_hl & 0x0F) * 4;
+    icmp_hdr = (struct icmp_echo_hdr *)((u8 *)ip_hdr + iphdr_len);
+
+    if (is_inet)
+    {
+
+#ifdef NAPT_TABLE_MUTEX_LOCK
+        luat_napt_lock(napt_table_lock_4ic);
+#endif
+        napt = luat_napt_get_by_src_id(icmp_hdr->id, ip_hdr->src.addr >> 24);
+        if (NULL == napt)
+        {
+            napt = luat_napt_table_insert_4ic(icmp_hdr->id, ip_hdr->src.addr >> 24);
+            if (NULL == napt)
+            {
+#ifdef NAPT_TABLE_MUTEX_LOCK
+                luat_napt_unlock(napt_table_lock_4ic);
+#endif
+                return -1;
+            }
+        }
+        else
+        {
+            luat_napt_table_update_4ic(napt);
+        }
+
+        icmp_hdr->id = napt->new_id;
+        memcpy(napt->mac, ptr + 6, 6);
+#ifdef NAPT_TABLE_MUTEX_LOCK
+        luat_napt_unlock(napt_table_lock_4ic);
+#endif
+
+        icmp_hdr->chksum = 0;
+        icmp_hdr->chksum = alg_iphdr_chksum((u16 *)icmp_hdr, ntohs(ip_hdr->_len) - iphdr_len);
+
+        ip_hdr->src.addr = ip_addr_get_ip4_u32(gw_ip);
+        ip_hdr->_chksum = 0;
+        ip_hdr->_chksum = alg_iphdr_chksum((u16 *)ip_hdr, iphdr_len);
+
+        return 0; // 已经改造完成, 可以返回了
+    }
+    else
+    {
+#ifdef NAPT_TABLE_MUTEX_LOCK
+        luat_napt_lock(napt_table_lock_4ic);
+#endif
+        napt = luat_napt_get_by_dst_id(icmp_hdr->id);
+        if (NULL != napt)
+        {
+            //luat_napt_table_update_4ic(napt);
+
+            icmp_hdr->id = napt->src_id;
+            icmp_hdr->chksum = 0;
+            icmp_hdr->chksum = alg_iphdr_chksum((u16 *)icmp_hdr, ntohs(ip_hdr->_len) - iphdr_len);
+
+            ip_hdr->dest.addr = ((napt->src_ip) << 24) | (ip_addr_get_ip4_u32(gw_ip) & 0x00ffffff);
+
+#ifdef NAPT_TABLE_MUTEX_LOCK
+            luat_napt_unlock(napt_table_lock_4ic);
+#endif
+
+            ip_hdr->_chksum = 0;
+            ip_hdr->_chksum = alg_iphdr_chksum((u16 *)ip_hdr, iphdr_len);
+
+            memcpy(ptr, napt->mac, 6);
+            return 0; // 已经改造完成, 可以返回了
+        }
+        else
+        {
+#ifdef NAPT_TABLE_MUTEX_LOCK
+            luat_napt_unlock(napt_table_lock_4ic);
+#endif
+
+        }
+    }
+
+    return -1;
+}
+
+static int alg_tcp_proc(u8 is_inet,
+                        struct ip_hdr *ip_hdr,
+                        ip_addr_t* gw_ip)
+{
+    int err;
+    u8 src_ip;
+    struct napt_addr_4tu *napt;
+    struct tcp_hdr *tcp_hdr;
+    u8* ptr = ((u8*)ip_hdr) - 14;
+    u8 iphdr_len;
+
+    iphdr_len = (ip_hdr->_v_hl & 0x0F) * 4;
+    tcp_hdr = (struct tcp_hdr *)((u8 *)ip_hdr + iphdr_len);
+
+    if (is_inet)
+    {
+
+#ifdef NAPT_TABLE_MUTEX_LOCK
+        luat_napt_lock(napt_table_lock_4tcp);
+#endif
+        src_ip = ip_hdr->src.addr >> 24;
+        napt = luat_napt_get_tcp_port_by_src(tcp_hdr->src, src_ip);
+        if (NULL == napt)
+        {
+            napt = luat_napt_table_insert_4tcp(tcp_hdr->src, src_ip);
+            if (NULL == napt)
+            {
+#ifdef NAPT_TABLE_MUTEX_LOCK
+                luat_napt_unlock(napt_table_lock_4tcp);
+#endif
+                return -1;
+            }
+            LLOGD("分配新的TCP映射 ip %d port %d -> %d", src_ip, tcp_hdr->src, napt->new_port);
+        }
+        else
+        {
+            luat_napt_table_update_4tcp(napt);
+            LLOGD("复用老的TCP映射 ip %d port %d -> %d", src_ip, tcp_hdr->src, napt->new_port);
+        }
+        memcpy(napt->mac, ptr + 6, 6); //保存源mac地址
+        // LLOGD("记录内网-->外网的源MAC %02X%02X%02X%02X%02X%02X", napt->mac[0], napt->mac[1], napt->mac[2], napt->mac[3], napt->mac[4], napt->mac[5]);
+        tcp_hdr->src = napt->new_port;
+#ifdef NAPT_TABLE_MUTEX_LOCK
+        luat_napt_unlock(napt_table_lock_4tcp);
+#endif
+
+        ip_hdr->src.addr = ip_addr_get_ip4_u32(gw_ip);
+        ip_hdr->_chksum = 0;
+        ip_hdr->_chksum = alg_iphdr_chksum((u16 *)ip_hdr, iphdr_len);
+
+        tcp_hdr->chksum = 0;
+        tcp_hdr->chksum = alg_tcpudphdr_chksum(ip_hdr->src.addr,
+                                               ip_hdr->dest.addr,
+                                               IP_PROTO_TCP,
+                                               (u16 *)tcp_hdr,
+                                               ntohs(ip_hdr->_len) - iphdr_len);
+
+        return 0; 
+    }
+    /* from ap... */
+    else
+    {
+#ifdef NAPT_TABLE_MUTEX_LOCK
+        luat_napt_lock(napt_table_lock_4tcp);
+#endif
+        napt = luat_napt_get_tcp_port_by_dest(tcp_hdr->dest);
+        /* forward to sta... */
+        if (NULL != napt)
+        {
+            //luat_napt_table_update_4tcp(napt);
+
+            ip_hdr->dest.addr = (napt->src_ip << 24) | (ip_addr_get_ip4_u32(gw_ip) & 0x00ffffff);
+            ip_hdr->_chksum = 0;
+            ip_hdr->_chksum = alg_iphdr_chksum((u16 *)ip_hdr, iphdr_len);
+
+            tcp_hdr->dest = napt->src_port;
+
+#ifdef NAPT_TABLE_MUTEX_LOCK
+            luat_napt_unlock(napt_table_lock_4tcp);
+#endif
+
+            tcp_hdr->chksum = 0;
+            tcp_hdr->chksum = alg_tcpudphdr_chksum(ip_hdr->src.addr,
+                                                   ip_hdr->dest.addr,
+                                                   IP_PROTO_TCP,
+                                                   (u16 *)tcp_hdr,
+                                                   ntohs(ip_hdr->_len) - iphdr_len);
+
+            memcpy(ptr, napt->mac, 6); // 还原MAC地址
+            return 0;
+        }
+        /* deliver to default gateway */
+        else
+        {
+#ifdef NAPT_TABLE_MUTEX_LOCK
+            luat_napt_unlock(napt_table_lock_4tcp);
+#endif
+
+        }
+    }
+
+    return -1;
+}
+
+static int alg_udp_proc(u8 is_inet,
+                        struct ip_hdr *ip_hdr,
+                        ip_addr_t* gw_ip)
+{
+    int err = 0;
+    u8 src_ip;
+    struct napt_addr_4tu *napt;
+    struct udp_hdr *udp_hdr;
+    u8* ptr = ((u8*)ip_hdr) - 14;
+    u8 iphdr_len;
+
+    iphdr_len = (ip_hdr->_v_hl & 0x0F) * 4;
+    udp_hdr = (struct udp_hdr *)((u8 *)ip_hdr + iphdr_len);
+
+    /* from sta... */
+    if (is_inet)
+    {
+        /* create/update napt item */
+#ifdef NAPT_TABLE_MUTEX_LOCK
+        luat_napt_lock(napt_table_lock_4udp);
+#endif
+        src_ip = ip_hdr->src.addr >> 24;
+        napt = luat_napt_get_udp_port_by_src(udp_hdr->src, src_ip);
+        if (NULL == napt)
+        {
+            napt = luat_napt_table_insert_4udp(udp_hdr->src, src_ip);
+            if (NULL == napt)
+            {
+#ifdef NAPT_TABLE_MUTEX_LOCK
+                luat_napt_unlock(napt_table_lock_4udp);
+#endif
+                return -1;
+            }
+        }
+        else
+        {
+            luat_napt_table_update_4udp(napt);
+        }
+
+        udp_hdr->src = napt->new_port;
+        memcpy(napt->mac, ptr + 6, 6); // 拷贝源MAC地址
+
+#ifdef NAPT_TABLE_MUTEX_LOCK
+        luat_napt_unlock(napt_table_lock_4udp);
+#endif
+
+redo:
+
+        ip_hdr->src.addr = ip_addr_get_ip4_u32(gw_ip);
+        ip_hdr->_chksum = 0;
+        ip_hdr->_chksum = alg_iphdr_chksum((u16 *)ip_hdr, iphdr_len);
+
+        if (0 != udp_hdr->chksum)
+        {
+            udp_hdr->chksum = 0;
+            udp_hdr->chksum = alg_tcpudphdr_chksum(ip_hdr->src.addr,
+                                                   ip_hdr->dest.addr,
+                                                   IP_PROTO_UDP,
+                                                   (u16 *)udp_hdr,
+                                                   ntohs(ip_hdr->_len) - iphdr_len);
+        }
+
+        return 0;
+    }
+    /* form ap... */
+    else
+    {
+#ifdef NAPT_TABLE_MUTEX_LOCK
+        luat_napt_lock(napt_table_lock_4udp);
+#endif
+        napt = luat_napt_get_udp_port_by_dest(udp_hdr->dest);
+        /* forward to sta... */
+        if (NULL != napt)
+        {
+            luat_napt_table_update_4udp(napt);
+
+            ip_hdr->dest.addr = (napt->src_ip << 24) | (ip_addr_get_ip4_u32(gw_ip) & 0x00ffffff);
+
+            udp_hdr->dest = napt->src_port;
+
+#ifdef NAPT_TABLE_MUTEX_LOCK
+            luat_napt_unlock(napt_table_lock_4udp);
+#endif
+
+            ip_hdr->_chksum = 0;
+            ip_hdr->_chksum = alg_iphdr_chksum((u16 *)ip_hdr, iphdr_len);
+
+            if (0 != udp_hdr->chksum)
+            {
+                udp_hdr->chksum = 0;
+                udp_hdr->chksum = alg_tcpudphdr_chksum(ip_hdr->src.addr,
+                                                       ip_hdr->dest.addr,
+                                                       IP_PROTO_UDP,
+                                                       (u16 *)udp_hdr,
+                                                       ntohs(ip_hdr->_len) - iphdr_len);
+            }
+
+            memcpy(ptr, napt->mac, 6);
+            return 0;
+        }
+        /* deliver to default gateway */
+        else
+        {
+#ifdef NAPT_TABLE_MUTEX_LOCK
+            luat_napt_unlock(napt_table_lock_4udp);
+#endif
+
+        }
+    }
+
+end:
+    return -1;
+}
+
+static int alg_gre_proc(u8 is_inet, struct ip_hdr *ip_hdr, ip_addr_t* gw_ip)
+{
+    int err;
+    u8 src_ip;
+    u8 iphdr_len;
+
+    iphdr_len = (ip_hdr->_v_hl & 0x0F) * 4;
+
+    /* from sta... */
+    if (is_inet)
+    {
+        src_ip = ip_hdr->src.addr >> 24;
+
+        if (src_ip == gre_info.src_ip)    /* current vpn */
+        {
+            gre_info.time_stamp++;
+        }
+        else if (1 == gre_info.is_used)/* vpn used */
+        {
+            return -1;
+        }
+        else                              /* new vpn */
+        {
+            gre_info.is_used = 1;
+            gre_info.src_ip = src_ip;
+            if (!++gre_info.time_stamp)
+                gre_info.time_stamp++;
+        }
+
+        ip_hdr->src.addr = ip_addr_get_ip4_u32(gw_ip);
+        ip_hdr->_chksum = 0;
+        ip_hdr->_chksum = alg_iphdr_chksum((u16 *)ip_hdr, iphdr_len);
+
+        return 0;
+    }
+    /* from ap... */
+    else
+    {
+        ip_hdr->dest.addr = (gre_info.src_ip << 24) | (ip_addr_get_ip4_u32(gw_ip) & 0x00ffffff);
+        ip_hdr->_chksum = 0;
+        ip_hdr->_chksum = alg_iphdr_chksum((u16 *)ip_hdr, iphdr_len);
+
+        return 0;
+    }
+
+}
+
+int luat_napt_input(u8 is_inet, u8 *pkt_body, u32 pkt_len, ip_addr_t* gw_ip)
+{
+    int err = -1;
+    struct ip_hdr *ip_hdr = NULL;
+
+#ifdef NAPT_USE_HW_TIMER
+    luat_napt_table_check_try();
+#endif
+
+    ip_hdr = (struct ip_hdr *)(pkt_body + 14);
+    switch(ip_hdr->_proto)
+    {
+        case IP_PROTO_ICMP:
+        {
+            err = alg_icmp_proc(is_inet, ip_hdr, gw_ip);
+            if (err)
+                LLOGD("ICMP包 rc %d", err);
+            break;
+        }
+        case IP_PROTO_TCP:
+        {
+            err = alg_tcp_proc(is_inet, ip_hdr, gw_ip);
+            if (err)
+                LLOGD("TCP包 rc %d", err);
+            break;
+        }
+        case IP_PROTO_UDP:
+        {
+            err = alg_udp_proc(is_inet, ip_hdr, gw_ip);
+            if (err)
+                LLOGD("UDP包 rc %d", err);
+            break;
+        }
+        case IP_PROTO_GRE:/* vpn */
+        {
+            err = alg_gre_proc(is_inet, ip_hdr, gw_ip);
+            if (err)
+                LLOGD("GRE包 rc %d", err);
+            break;
+        }
+        default:
+        {
+            LLOGW("不认识的协议包 0x%02X", ip_hdr->_proto);
+            err = -1;
+            break;
+        }
+    }
+
+    return err;
+}
+
+u8 luat_napt_port_is_used(u16 port)
+{
+    u8 is_used = 0;
+    struct napt_addr_4tu *napt_tcp;
+    struct napt_addr_4tu *napt_udp;
+
+#ifdef NAPT_TABLE_MUTEX_LOCK
+    luat_napt_lock(napt_table_lock_4tcp);
+#endif
+    NAPT_TABLE_FOREACH(napt_tcp, napt_table_4tcp)
+    {
+        if (port == napt_tcp->new_port)
+        {
+            is_used = 1;
+            break;
+        }
+    }
+#ifdef NAPT_TABLE_MUTEX_LOCK
+    luat_napt_unlock(napt_table_lock_4tcp);
+#endif
+
+    if (1 != is_used)
+    {
+#ifdef NAPT_TABLE_MUTEX_LOCK
+        luat_napt_lock(napt_table_lock_4udp);
+#endif
+        NAPT_TABLE_FOREACH(napt_udp, napt_table_4udp)
+        {
+            if (port == napt_udp->new_port)
+            {
+                is_used = 1;
+                break;
+            }
+        }
+#ifdef NAPT_TABLE_MUTEX_LOCK
+        luat_napt_unlock(napt_table_lock_4udp);
+#endif
+    }
+
+    return is_used;
+}
+
+int luat_napt_init(void)
+{
+    int err = 0;
+#ifdef NAPT_USE_HW_TIMER
+    struct tls_timer_cfg timer_cfg;
+#endif
+
+    memset(&napt_table_4tcp, 0, sizeof(struct napt_table_head_4tu));
+    memset(&napt_table_4udp, 0, sizeof(struct napt_table_head_4tu));
+    memset(&napt_table_4ic, 0, sizeof(struct napt_table_head_4ic));
+
+    napt_curr_port = NAPT_LOCAL_PORT_RANGE_START;
+    napt_curr_id   = NAPT_ICMP_ID_RANGE_START;
+
+#ifdef NAPT_TABLE_MUTEX_LOCK
+    err = tls_os_sem_create(&napt_table_lock_4tcp, 1);
+    if (TLS_OS_SUCCESS != err)
+    {
+        NAPT_PRINT("failed to init alg.\n");
+        return err;
+    }
+
+    err = tls_os_sem_create(&napt_table_lock_4udp, 1);
+    if (TLS_OS_SUCCESS != err)
+    {
+        NAPT_PRINT("failed to init alg.\n");
+        return err;
+    }
+
+    err = tls_os_sem_create(&napt_table_lock_4ic, 1);
+    if (TLS_OS_SUCCESS != err)
+    {
+        NAPT_PRINT("failed to init alg.\n");
+    }
+#endif
+
+#ifdef NAPT_ALLOC_DEBUG
+    napt4ic_cnt = 0;
+    napt4tcp_cnt = 0;
+    napt4udp_cnt = 0;
+#endif
+
+#ifdef NAPT_USE_HW_TIMER
+    memset(&timer_cfg, 0, sizeof(timer_cfg));
+    timer_cfg.unit = TLS_TIMER_UNIT_MS;
+    timer_cfg.timeout = NAPT_TMR_INTERVAL;
+    timer_cfg.is_repeat = TRUE;
+    timer_cfg.callback = luat_napt_table_check;
+    err = tls_timer_create(&timer_cfg);
+    if (WM_TIMER_ID_INVALID != err)
+    {
+        tls_timer_start(err);
+        err = 0;
+    }
+    else
+    {
+        NAPT_PRINT("failed to init alg timer.\n");
+    }
+#else
+
+#endif
+
+    return err;
+}
+

+ 92 - 0
components/network/ulwip/src/ulwip_gprs_ip.c

@@ -0,0 +1,92 @@
+
+#include "luat_base.h"
+#include "luat_ulwip.h"
+#include "luat_crypto.h"
+
+#define LUAT_LOG_TAG "ulwip"
+#include "luat_log.h"
+
+#include "lwip/ip.h"
+#include "lwip/udp.h"
+#include "lwip/tcp.h"
+#include "luat_napt.h"
+
+// 针对EC618/EC7xx平台的IP包输入回调
+static uint8_t napt_tmpbuff[1600];
+
+uint8_t napt_target_adapter;
+
+err_t ulwip_ip_input_cb(struct pbuf *p, struct netif *inp) {
+    //LLOGD("收到IP数据包(len=%d)", p->tot_len);
+    u8_t ipVersion;
+    if (napt_target_adapter == 0) {
+        // 没有注册NAPT目标适配器(内网的), 不需要转发
+        return 1;
+    }
+    ipVersion = IP_HDR_GET_VERSION(p->payload);
+    if (ipVersion != 4) {
+        // LLOGD("仅转发IPv4的包, 忽略%p %d", p, p->tot_len);
+        return 1; // 当前仅考虑IPv4的转发
+    }
+    // 包太大的话也不处理
+    if (p->tot_len > sizeof(napt_tmpbuff) - 14) {
+        LLOGD("IP包太大了, 忽略%p %d", p, p->tot_len);
+        return 1;
+    }
+    int offset = 14; // MAC头长度, 传入luat_napt_input需要是MAC包
+    struct pbuf *q;
+    for (q = p; q != NULL; q = q->next) {
+        memcpy(napt_tmpbuff + offset, q->payload, q->len);
+        offset += q->len;
+    }
+    struct ip_hdr *ip = (struct ip_hdr *)(napt_tmpbuff + 14);
+    if (ip->_proto == IP_PROTO_TCP) {
+        // TCP协议
+        struct tcp_hdr *tcp = (struct tcp_hdr *)((char*)ip + sizeof(struct ip_hdr));
+        u16_t tcpPort = tcp->dest;
+        if(!luat_napt_port_is_used(tcpPort)) {
+            // 目标端口没有被占用, 不需要转发
+            // LLOGD("IP包的目标端口未使用, 忽略%p %d", p, p->tot_len);
+            return 1;
+        }
+    }
+    else if (ip->_proto == IP_PROTO_UDP) {
+        // UDP协议
+        struct udp_hdr *udp = (struct udp_hdr *)((char*)ip + sizeof(struct ip_hdr));
+        u16_t udpPort = udp->dest;
+        if(!luat_napt_port_is_used(udpPort)) {
+            // 目标端口没有被占用, 不需要转发
+            // LLOGD("IP包的目标端口未使用, 忽略%p %d", p, p->tot_len);
+            return 1;
+        }
+    }
+    // 如果已经注册了netif, 就转发了
+    struct netif* tmp = ulwip_find_netif(NW_ADAPTER_INDEX_LWIP_GPRS);
+    struct netif* gw = ulwip_find_netif(napt_target_adapter);
+    if (gw && tmp == inp) {
+        int rc = luat_napt_input(0, napt_tmpbuff, q->tot_len + 14, &gw->ip_addr);
+        // LLOGD("luat_napt_input %d", rc);
+        if (rc == 0) {
+            char* ptr = luat_heap_malloc(p->tot_len + 14);
+            if (ptr == NULL) {
+                LLOGE("IP包改造完成,但系统内存不足,导致无法转发到lua层");
+                return 4;
+            }
+            memcpy(napt_tmpbuff + 6, gw->hwaddr, 6);
+            napt_tmpbuff[12] = 0x08;
+            napt_tmpbuff[13] = 0x00;
+            memcpy(ptr, napt_tmpbuff, p->tot_len + 14);
+            rtos_msg_t msg = {0};
+            msg.handler = l_ulwip_netif_output_cb;
+            msg.arg1 = p->tot_len + 14;
+            msg.arg2 = NW_ADAPTER_INDEX_LWIP_WIFI_AP;
+            msg.ptr = ptr;
+            luat_msgbus_put(&msg, 0);
+            return ERR_OK;
+        }
+    }
+    else {
+        // LLOGD("转发目标不存在, 跳过NAPT流程 %p %d", p, p->tot_len);
+    }
+    return 2;
+}

+ 3 - 0
luat/include/luat_libs.h

@@ -188,4 +188,7 @@ LUAMOD_API int luaopen_wlan_raw(lua_State *L);
 // 液晶屏驱动
 LUAMOD_API int luaopen_ht1621(lua_State *L);
 
+// NAPT
+LUAMOD_API int luaopen_napt(lua_State *L);
+
 #endif