Browse Source

add: netdrv,ping函数,支持ipv6地址的ping, 如果对应网卡支持的话

https://gitee.com/openLuat/LuatOS/issues/ID6HJX
Wendal Chen 2 months ago
parent
commit
c6ea9fba74

+ 7 - 6
components/network/icmp/binding/luat_lib_icmp.c

@@ -39,12 +39,12 @@ typedef struct ping_result
 
 static int l_icmp_handler(lua_State *L, void* ptr) {
     rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
+    luat_icmp_ctx_t* ctx = (luat_icmp_ctx_t*)msg->ptr;
     lua_getglobal(L, "sys_pub");
-    uint32_t addr = msg->arg2;
-    char buff[32] = {0};
-    ip_addr_t ip = {0};
-    ip_addr_set_ip4_u32(&ip, addr);
-    ipaddr_ntoa_r(&ip, buff, 32);
+    char buff[64] = {0};
+    if (ctx) {
+        ipaddr_ntoa_r(&ctx->dst, buff, sizeof(buff));
+    }
     if (lua_isfunction(L, -1)) {
         lua_pushstring(L, "PING_RESULT");
         lua_pushinteger(L, (msg->arg1 >> 16) & 0xFFFF);
@@ -62,8 +62,9 @@ static void l_icmp_cb(void* _ctx, uint32_t tused) {
     luat_icmp_ctx_t* ctx = (luat_icmp_ctx_t*)_ctx;
     rtos_msg_t msg = {
         .handler = l_icmp_handler,
+        .ptr = ctx,
         .arg1 = ctx->adapter_id << 16 | (tused & 0xFFFF),
-        .arg2 = ip_addr_get_ip4_u32(&ctx->dst)
+        .arg2 = 0
     };
     luat_msgbus_put(&msg, 0);
 }

+ 4 - 1
components/network/icmp/include/luat_icmp.h

@@ -16,7 +16,10 @@ typedef struct luat_icmp_ctx
 {
     uint8_t adapter_id;
     struct netif *netif;
-    struct raw_pcb *pcb;
+    struct raw_pcb *pcb_v4;
+#if LWIP_IPV6
+    struct raw_pcb *pcb_v6;
+#endif
     ip_addr_t dst;
     ip_addr_t tmpdst;
     size_t len;

+ 168 - 53
components/network/icmp/src/luat_icmp.c

@@ -8,8 +8,14 @@
 #include "lwip/init.h"
 #include "lwip/prot/icmp.h"
 #include "lwip/prot/ip.h"
+#if LWIP_IPV6
+#include "lwip/prot/ip6.h"
+#include "lwip/prot/icmp6.h"
+#include "lwip/ip6_addr.h"
+#endif
 #include "lwip/pbuf.h"
 #include "lwip/inet_chksum.h"
+#include <stddef.h>
 
 #define LUAT_LOG_TAG "icmp"
 #include "luat_log.h"
@@ -20,68 +26,124 @@ uint8_t g_icmp_debug;
 
 static u8_t luat_icmp_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr)
 {
-    char buff[32] = {0};
-    ipaddr_ntoa_r(addr, buff, 32);
+    if (p == NULL || addr == NULL) {
+        return 0;
+    }
+    char buff[64] = {0};
+    ipaddr_ntoa_r(addr, buff, sizeof(buff));
     if (g_icmp_debug) {
-        LLOGD("ICMP recv %p %p %d", arg, pcb, p->tot_len);
+        LLOGD("ICMP recv %p %p %d %s", arg, pcb, p->tot_len, buff);
     }
     uint32_t adapter_id = (uint32_t)arg;
     if (adapter_id >= NW_ADAPTER_INDEX_LWIP_NETIF_QTY) {
         return 0;
     }
-    if (ctxs[adapter_id] == NULL) {
-        return 0;
-    }
     luat_icmp_ctx_t* ctx = ctxs[adapter_id];
-    if (ctx->send_time == 0) {
+    if (ctx == NULL || ctx->send_time == 0) {
         return 0; // 并没有待接收的ICMP数据
     }
-    struct icmp_echo_hdr *iecho;
-    
-    LWIP_UNUSED_ARG(arg);
+
     LWIP_UNUSED_ARG(pcb);
-    LWIP_UNUSED_ARG(addr);
 
-    if (p->tot_len >= sizeof(struct icmp_echo_hdr) + sizeof(struct ip_hdr)) {
-        iecho = (struct icmp_echo_hdr *)(p->payload + sizeof(struct ip_hdr));
-        if (g_icmp_debug) {
-            LLOGD("ICMP recv %d %d %d", iecho->type, htons(iecho->id), htons(iecho->seqno));
+    if (IP_IS_V4(addr)) {
+        if (p->tot_len >= (sizeof(struct icmp_echo_hdr) + sizeof(struct ip_hdr)) && p->len >= sizeof(struct ip_hdr)) {
+            struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
+            u16_t ip_header_len = (u16_t)(IPH_HL(iphdr) * 4);
+            if (p->tot_len >= ip_header_len + sizeof(struct icmp_echo_hdr) && p->len >= ip_header_len + sizeof(struct icmp_echo_hdr)) {
+                const struct icmp_echo_hdr *iecho = (const struct icmp_echo_hdr *)((uint8_t *)p->payload + ip_header_len);
+                if (g_icmp_debug) {
+                    LLOGD("ICMPv4 recv type=%d id=%d seq=%d", iecho->type, htons(iecho->id), htons(iecho->seqno));
+                }
+                if (iecho->type == ICMP_ER && htons(iecho->id) == ctx->id && htons(iecho->seqno) == ctx->seqno) {
+                    uint32_t elapsed = (uint32_t)(luat_mcu_tick64_ms() - ctx->send_time);
+                    if (elapsed < 16 * 1000 && ctx->cb) {
+                        ctx->cb(ctx, elapsed);
+                    }
+                    pbuf_free(p);
+                    return 1;
+                }
+            }
         }
-        /* 验证是否为ICMP Echo回复 */
-        if (iecho->type == ICMP_ER && htons(iecho->id) == ctx->id && htons(iecho->seqno) == ctx->seqno) {
-            
-            /* 计算往返时间(示例中需要计时器支持)*/
-            uint32_t elapsed = (uint32_t)(luat_mcu_tick64_ms() - ctx->send_time);
-            if (elapsed < 16 *1000 && ctx->cb) {
-                ctx->cb(ctx, elapsed);
+    }
+#if LWIP_IPV6
+    else if (IP_IS_V6(addr)) {
+        if (p->tot_len >= (sizeof(struct icmp6_echo_hdr) + sizeof(struct ip6_hdr)) && p->len >= sizeof(struct ip6_hdr)) {
+            const struct icmp6_echo_hdr *iecho6 = (const struct icmp6_echo_hdr *)((uint8_t *)p->payload + sizeof(struct ip6_hdr));
+            if (g_icmp_debug) {
+                LLOGD("ICMPv6 recv type=%d id=%d seq=%d", iecho6->type, htons(iecho6->id), htons(iecho6->seqno));
+            }
+            if (iecho6->type == ICMP6_TYPE_EREP && htons(iecho6->id) == ctx->id && htons(iecho6->seqno) == ctx->seqno) {
+                uint32_t elapsed = (uint32_t)(luat_mcu_tick64_ms() - ctx->send_time);
+                if (elapsed < 16 * 1000 && ctx->cb) {
+                    ctx->cb(ctx, elapsed);
+                }
+                pbuf_free(p);
+                return 1;
             }
-            pbuf_free(p);   // 释放pbuf
-            return 1;       // 已处理该包
         }
     }
+#endif
     return 0;               // 继续传递数据包
 }
 
-/** Prepare a echo ICMP request */
-static void ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len, u16_t id, uint32_t seq_num)
+static void ping_fill_payload(void *hdr, u16_t header_len, u16_t total_len)
 {
-    size_t i;
-    size_t data_len = len - sizeof(struct icmp_echo_hdr);
+    size_t data_len = total_len > header_len ? (size_t)(total_len - header_len) : 0;
+    char *payload = (char *)hdr + header_len;
+    for (size_t i = 0; i < data_len; i++) {
+        payload[i] = (char)i;
+    }
+}
 
+/** Prepare an IPv4 ICMP echo request */
+static void ping_prepare_echo4(struct icmp_echo_hdr *iecho, u16_t len, u16_t id, u16_t seq_num)
+{
     ICMPH_TYPE_SET(iecho, ICMP_ECHO);
     ICMPH_CODE_SET(iecho, 0);
     iecho->chksum = 0;
     iecho->id     = htons(id);
     iecho->seqno  = htons(seq_num);
+    ping_fill_payload(iecho, sizeof(struct icmp_echo_hdr), len);
+    iecho->chksum = inet_chksum(iecho, len);
+}
 
-    /* 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;
-    }
+#if LWIP_IPV6
+/** Prepare an IPv6 ICMP echo request */
+static void ping_prepare_echo6(struct icmp6_echo_hdr *iecho6, u16_t len, u16_t id, u16_t seq_num)
+{
+    iecho6->type = ICMP6_TYPE_EREQ;
+    iecho6->code = 0;
+    iecho6->chksum = 0;
+    iecho6->id    = htons(id);
+    iecho6->seqno = htons(seq_num);
+    ping_fill_payload(iecho6, sizeof(struct icmp6_echo_hdr), len);
+}
 
-    iecho->chksum = inet_chksum(iecho, len);
+static int luat_icmp_select_ipv6_src(luat_icmp_ctx_t *ctx, ip_addr_t *src)
+{
+    if (ctx == NULL || ctx->netif == NULL || src == NULL) {
+        return -1;
+    }
+    const ip6_addr_t *candidate = NULL;
+    for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+        if (ip6_addr_isvalid(netif_ip6_addr_state(ctx->netif, i))) {
+            const ip6_addr_t *addr = netif_ip6_addr(ctx->netif, i);
+            if (ip6_addr_isglobal(addr)) {
+                ip_addr_copy_from_ip6(*src, *addr);
+                return 0;
+            }
+            if (candidate == NULL) {
+                candidate = addr;
+            }
+        }
+    }
+    if (candidate) {
+        ip_addr_copy_from_ip6(*src, *candidate);
+        return 0;
+    }
+    return -1;
 }
+#endif
 
 luat_icmp_ctx_t* luat_icmp_get(uint8_t adapter_id) {
     luat_netdrv_t* netdrv = luat_netdrv_get(adapter_id);
@@ -106,51 +168,104 @@ luat_icmp_ctx_t* luat_icmp_init(uint8_t adapter_id) {
     luat_icmp_ctx_t* ctx = ctxs[adapter_id];
     memset(ctx, 0, sizeof(luat_icmp_ctx_t));
     ctx->netif = netdrv->netif;
-    ctx->pcb = raw_new(IP_PROTO_ICMP);
-    if (ctx->pcb == NULL) {
+    ctx->pcb_v4 = raw_new(IP_PROTO_ICMP);
+    if (ctx->pcb_v4 == NULL) {
         LLOGE("分配ICMP RAW PCB失败!!");
         luat_heap_free(ctxs[adapter_id]);
         ctxs[adapter_id] = NULL;
         return NULL;
     }
+#if LWIP_IPV6
+    ctx->pcb_v6 = NULL;
+#endif
     ctx->id = 0x02;
     ctx->seqno = 0x01;
     ctx->adapter_id = adapter_id;
     #if LWIP_VERSION_MAJOR == 2 && LWIP_VERSION_MINOR >= 1
-    raw_bind_netif(ctx->pcb, ctx->netif);
+    raw_bind_netif(ctx->pcb_v4, ctx->netif);
     #endif
-    raw_bind(ctx->pcb, &ctx->netif->ip_addr);
-    raw_recv(ctx->pcb, luat_icmp_recv, (void*)(uint32_t)adapter_id);
+    raw_bind(ctx->pcb_v4, &ctx->netif->ip_addr);
+    raw_recv(ctx->pcb_v4, luat_icmp_recv, (void*)(uint32_t)adapter_id);
     return ctx;
 }
 
 void luat_icmp_ping(luat_icmp_ctx_t* ctx) {
+    if (ctx == NULL || ctx->netif == NULL) {
+        return;
+    }
     int ret = 0;
-    struct icmp_echo_hdr *iecho;
+    char src_buff[64] = {0};
+    char dst_buff[64] = {0};
     memcpy(&ctx->dst, &ctx->tmpdst, sizeof(ip_addr_t));
     ctx->send_time = 0;
     ctx->recv_time = 0;
-    int ping_size = sizeof(struct icmp_echo_hdr) + ctx->len;
+    uint16_t header_len = IP_IS_V6(&ctx->dst) ?
+#if LWIP_IPV6
+        sizeof(struct icmp6_echo_hdr)
+#else
+        sizeof(struct icmp_echo_hdr)
+#endif
+        : sizeof(struct icmp_echo_hdr);
+    uint16_t ping_size = header_len + (uint16_t)ctx->len;
     struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, ping_size, PBUF_RAM);
     if (p == NULL) {
         return;
     }
-    raw_bind(ctx->pcb, &ctx->netif->ip_addr);
-    iecho = (struct icmp_echo_hdr *)(p->payload);
+
     ctx->id ++;
     ctx->seqno ++;
-    ping_prepare_echo(iecho, ping_size, ctx->id, ctx->seqno);
-
-    // ret = raw_sendto_if_src(ctx->pcb, p, dst, ctx->netif, &ctx->netif->ip_addr);
-    char buff[32] = {0};
-    char buff2[32] = {0};
-    ipaddr_ntoa_r(&ctx->netif->ip_addr, buff, 32);
-    ipaddr_ntoa_r(&ctx->dst, buff2, 32);
-    // LLOGD("ICMP sendto %s --> %s", buff, buff2);
+    struct raw_pcb *pcb = NULL;
+
+    if (IP_IS_V6(&ctx->dst)) {
+#if LWIP_IPV6
+        if (ctx->pcb_v6 == NULL) {
+            ctx->pcb_v6 = raw_new_ip_type(IPADDR_TYPE_V6, IP6_NEXTH_ICMP6);
+            if (ctx->pcb_v6 == NULL) {
+                pbuf_free(p);
+                LLOGE("ICMPv6 RAW PCB alloc failed");
+                return;
+            }
+            ctx->pcb_v6->chksum_offset = offsetof(struct icmp6_echo_hdr, chksum);
+            ctx->pcb_v6->chksum_reqd = 1;
+            #if LWIP_VERSION_MAJOR == 2 && LWIP_VERSION_MINOR >= 1
+            raw_bind_netif(ctx->pcb_v6, ctx->netif);
+            #endif
+            raw_recv(ctx->pcb_v6, luat_icmp_recv, (void*)(uint32_t)ctx->adapter_id);
+        }
+        ip_addr_t src = {0};
+        if (luat_icmp_select_ipv6_src(ctx, &src) != 0) {
+            pbuf_free(p);
+            LLOGW("ICMPv6 no valid local address");
+            return;
+        }
+        ping_prepare_echo6((struct icmp6_echo_hdr *)p->payload, ping_size, ctx->id, ctx->seqno);
+        raw_bind(ctx->pcb_v6, &src);
+        pcb = ctx->pcb_v6;
+        ipaddr_ntoa_r(&src, src_buff, sizeof(src_buff));
+#else
+        pbuf_free(p);
+        LLOGW("ICMPv6 unsupported in this build");
+        return;
+#endif
+    } else {
+        if (ctx->pcb_v4 == NULL) {
+            pbuf_free(p);
+            LLOGE("ICMPv4 PCB invalid");
+            return;
+        }
+        ping_prepare_echo4((struct icmp_echo_hdr *)p->payload, ping_size, ctx->id, ctx->seqno);
+        raw_bind(ctx->pcb_v4, &ctx->netif->ip_addr);
+        pcb = ctx->pcb_v4;
+        ipaddr_ntoa_r(&ctx->netif->ip_addr, src_buff, sizeof(src_buff));
+    }
+
+    ipaddr_ntoa_r(&ctx->dst, dst_buff, sizeof(dst_buff));
     ctx->send_time = luat_mcu_tick64_ms();
-    ret = raw_sendto(ctx->pcb, p, &ctx->dst);
+    ret = raw_sendto(pcb, p, &ctx->dst);
     pbuf_free(p);
     if (ret) {
-        LLOGW("ICMP sendto error %d %s --> %s", ret, buff, buff2);
+        LLOGW("ICMP sendto error %d %s --> %s", ret, src_buff, dst_buff);
+    } else if (g_icmp_debug) {
+        LLOGD("ICMP sendto %s --> %s len=%u", src_buff, dst_buff, ping_size);
     }
 }

+ 19 - 7
olddemo/icmp/ping/main.lua

@@ -5,6 +5,10 @@ VERSION = "1.0.2"
 -- sys库是标配
 sys = require("sys")
 
+if mobile and mobile.ipv6 then
+    mobile.ipv6(true)
+end
+
 sys.subscribe("PING_RESULT", function(id, time, dst)
     log.info("ping", id, time, dst);
 end)
@@ -13,13 +17,13 @@ sys.taskInit(function()
     local adapter = socket.LWIP_GP
     local ip = "121.14.77.221"
     -- icmp.debug(true)
-    if wlan and wlan.connect then
-        sys.wait(500)
-        wlan.init()
-        wlan.connect("luatos1234", "12341234")
-        adapter = socket.LWIP_STA
-        -- ip = "192.168.1.10"
-    end
+    -- if wlan and wlan.connect then
+    --     sys.wait(500)
+    --     wlan.init()
+    --     wlan.connect("luatos1234", "12341234")
+    --     adapter = socket.LWIP_STA
+    --     -- ip = "192.168.1.10"
+    -- end
     sys.waitUntil("IP_READY")
     sys.wait(1000)
     icmp.setup(adapter)
@@ -28,6 +32,14 @@ sys.taskInit(function()
         icmp.ping(adapter, ip)
         sys.waitUntil("PING_RESULT", 3000)
         sys.wait(1000)
+        -- 测试ipv6的ping
+        if mobile and mobile.ipv6 then
+            local ipv6_addr = "2408:400a:13d:d000:9e36:89b7:3230:25ab"
+            log.info("执行PING操作", ipv6_addr, socket.localIP(adapter))
+            icmp.ping(adapter, ipv6_addr)
+            sys.waitUntil("PING_RESULT", 3000)
+            sys.wait(1000)
+        end
     end
 end)