Parcourir la source

lwip:add feature for ipv6 ping

xueyunfei il y a 5 ans
Parent
commit
e7e5884a77

+ 12 - 6
components/lwip/apps/ping/esp_ping.c

@@ -16,12 +16,12 @@
 #include "esp_ping.h"
 
 #include "lwip/ip_addr.h"
-
 typedef struct _ping_option {
-    ip4_addr_t ping_target;
+    ip_addr_t ping_target;
     uint32_t ping_count;
     uint32_t ping_rcv_timeout;
     uint32_t ping_delay;
+    uint32_t interface;
     size_t ping_data_len;
     uint16_t ping_id;
     u8_t ping_tos;
@@ -42,13 +42,16 @@ esp_err_t esp_ping_set_target(ping_target_id_t opt_id, void *opt_val, uint32_t o
 
     switch (opt_id) {
     case PING_TARGET_IP_ADDRESS:
-        ESP_PING_CHECK_OPTLEN(opt_len, uint32_t);
-        ping_option_info->ping_target.addr = *(uint32_t *)opt_val;
+        ipaddr_aton(opt_val, &(ping_option_info->ping_target));
         break;
     case PING_TARGET_IP_ADDRESS_COUNT:
         ESP_PING_CHECK_OPTLEN(opt_len, uint32_t);
         ping_option_info->ping_count = *(uint32_t *)opt_val;
         break;
+    case PING_TARGET_IF_INDEX:
+        ESP_PING_CHECK_OPTLEN(opt_len, uint32_t);
+        ping_option_info->interface = *(uint32_t *)opt_val;
+        break;
     case PING_TARGET_RCV_TIMEO:
         ESP_PING_CHECK_OPTLEN(opt_len, uint32_t);
         ping_option_info->ping_rcv_timeout = (*(uint32_t *)opt_val);
@@ -93,13 +96,16 @@ esp_err_t esp_ping_get_target(ping_target_id_t opt_id, void *opt_val, uint32_t o
 
     switch (opt_id) {
     case PING_TARGET_IP_ADDRESS:
-        ESP_PING_CHECK_OPTLEN(opt_len, uint32_t);
-        *(uint32_t *)opt_val = ping_option_info->ping_target.addr;
+        ip_addr_copy(*(ip_addr_t*)opt_val, ping_option_info->ping_target);
         break;
     case PING_TARGET_IP_ADDRESS_COUNT:
         ESP_PING_CHECK_OPTLEN(opt_len, uint32_t);
         *(uint32_t *)opt_val = ping_option_info->ping_count;
         break;
+    case PING_TARGET_IF_INDEX:
+        ESP_PING_CHECK_OPTLEN(opt_len, uint32_t);
+        *(uint32_t *)opt_val = ping_option_info->interface;
+        break;
     case PING_TARGET_RCV_TIMEO:
         ESP_PING_CHECK_OPTLEN(opt_len, uint32_t);
         *(uint32_t *)opt_val = ping_option_info->ping_rcv_timeout;

+ 6 - 5
components/lwip/apps/ping/ping.c

@@ -268,22 +268,23 @@ ping_init(void)
   uint32_t ping_timeout = PING_RCV_TIMEO;
   uint32_t ping_delay = PING_DELAY;
   uint32_t ping_count_max = 3;
-  ip_addr_t ping_target;
-  ip4_addr_t ipaddr;
+  uint32_t interface = 0;
+  ip_addr_t ipaddr;
 
   esp_ping_get_target(PING_TARGET_IP_ADDRESS_COUNT, &ping_count_max, sizeof(ping_count_max));
   esp_ping_get_target(PING_TARGET_RCV_TIMEO, &ping_timeout, sizeof(ping_timeout));
   esp_ping_get_target(PING_TARGET_DELAY_TIME, &ping_delay, sizeof(ping_delay));
-  esp_ping_get_target(PING_TARGET_IP_ADDRESS, &ipaddr.addr, sizeof(uint32_t));
+  esp_ping_get_target(PING_TARGET_IP_ADDRESS, &ipaddr, sizeof(ip_addr_t));
   esp_ping_get_target(PING_TARGET_IP_TOS, &tos, sizeof(tos));
-  ip_addr_copy_from_ip4(ping_target, ipaddr);
+  esp_ping_get_target(PING_TARGET_IF_INDEX, &interface, sizeof(interface));
 
   esp_ping_config_t config = ESP_PING_DEFAULT_CONFIG();
   config.count = ping_count_max;
   config.timeout_ms = ping_timeout;
   config.interval_ms = ping_delay;
-  config.target_addr = ping_target;
+  config.target_addr = ipaddr;
   config.tos = tos;
+  config.interface = interface;
 
   esp_ping_callbacks_t cbs = {
     .on_ping_end = on_ping_end,

+ 39 - 19
components/lwip/apps/ping/ping_sock.c

@@ -80,8 +80,10 @@ static esp_err_t esp_ping_send(esp_ping_t *ep)
     ep->packet_hdr->seqno++;
     /* generate checksum since "seqno" has changed */
     ep->packet_hdr->chksum = 0;
-    ep->packet_hdr->chksum = inet_chksum(ep->packet_hdr, ep->icmp_pkt_size);
-
+    if (ep->packet_hdr->type == ICMP_ECHO) {
+        ep->packet_hdr->chksum = inet_chksum(ep->packet_hdr, ep->icmp_pkt_size);
+    }
+    
     int sent = sendto(ep->sock, ep->packet_hdr, ep->icmp_pkt_size, 0,
                       (struct sockaddr *)&ep->target_addr, sizeof(ep->target_addr));
 
@@ -103,24 +105,24 @@ static int esp_ping_receive(esp_ping_t *ep)
     int len = 0;
     struct sockaddr_storage from;
     int fromlen = sizeof(from);
-    uint16_t data_head = (uint16_t)(sizeof(struct ip_hdr) + sizeof(struct icmp_echo_hdr));
+    uint16_t data_head = 0;
 
     while ((len = recvfrom(ep->sock, buf, sizeof(buf), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen)) > 0) {
+        if (from.ss_family == AF_INET) {
+            // IPv4
+            struct sockaddr_in *from4 = (struct sockaddr_in *)&from;
+            inet_addr_to_ip4addr(ip_2_ip4(&ep->recv_addr), &from4->sin_addr);
+            IP_SET_TYPE_VAL(ep->recv_addr, IPADDR_TYPE_V4);
+            data_head = (uint16_t)(sizeof(struct ip_hdr) + sizeof(struct icmp_echo_hdr));
+        } else {
+            // IPv6
+            struct sockaddr_in6 *from6 = (struct sockaddr_in6 *)&from;
+            inet6_addr_to_ip6addr(ip_2_ip6(&ep->recv_addr), &from6->sin6_addr);
+            IP_SET_TYPE_VAL(ep->recv_addr, IPADDR_TYPE_V6);
+            data_head = (uint16_t)(sizeof(struct ip6_hdr) + sizeof(struct icmp6_echo_hdr));
+        }
         if (len >= data_head) {
-            if (from.ss_family == AF_INET) {
-                // IPv4
-                struct sockaddr_in *from4 = (struct sockaddr_in *)&from;
-                inet_addr_to_ip4addr(ip_2_ip4(&ep->recv_addr), &from4->sin_addr);
-                IP_SET_TYPE_VAL(ep->recv_addr, IPADDR_TYPE_V4);
-            } else {
-                // IPv6
-                struct sockaddr_in6 *from6 = (struct sockaddr_in6 *)&from;
-                inet6_addr_to_ip6addr(ip_2_ip6(&ep->recv_addr), &from6->sin6_addr);
-                IP_SET_TYPE_VAL(ep->recv_addr, IPADDR_TYPE_V6);
-            }
-
-            // Currently we only process IPv4
-            if (IP_IS_V4_VAL(ep->recv_addr)) {
+            if (IP_IS_V4_VAL(ep->recv_addr)) {              // Currently we process IPv4
                 struct ip_hdr *iphdr = (struct ip_hdr *)buf;
                 struct icmp_echo_hdr *iecho = (struct icmp_echo_hdr *)(buf + (IPH_HL(iphdr) * 4));
                 if ((iecho->id == ep->packet_hdr->id) && (iecho->seqno == ep->packet_hdr->seqno)) {
@@ -129,6 +131,14 @@ static int esp_ping_receive(esp_ping_t *ep)
                     ep->recv_len = lwip_ntohs(IPH_LEN(iphdr)) - data_head;  // The data portion of ICMP
                     return len;
                 }
+            } else if (IP_IS_V6_VAL(ep->recv_addr)) {      // Currently we process IPv6
+                struct ip6_hdr *iphdr = (struct ip6_hdr *)buf;
+                struct icmp6_echo_hdr *iecho6 = (struct icmp6_echo_hdr *)(buf + sizeof(struct ip6_hdr)); // IPv6 head length is 40
+                if ((iecho6->id == ep->packet_hdr->id) && (iecho6->seqno == ep->packet_hdr->seqno)) {
+                    ep->received++;
+                    ep->recv_len = IP6H_PLEN(iphdr) - sizeof(struct icmp6_echo_hdr); //The data portion of ICMPv6
+                    return len;
+                }
             }
         }
         fromlen = sizeof(from);
@@ -227,7 +237,6 @@ esp_err_t esp_ping_new_session(const esp_ping_config_t *config, const esp_ping_c
     ep->packet_hdr = mem_calloc(1, ep->icmp_pkt_size);
     PING_CHECK(ep->packet_hdr, "no memory for echo packet", err, ESP_ERR_NO_MEM);
     /* set ICMP type and code field */
-    ep->packet_hdr->type = ICMP_ECHO;
     ep->packet_hdr->code = 0;
     /* ping id should be unique, treat task handle as ping ID */
     ep->packet_hdr->id = ((uint32_t)ep->ping_task_hdl) & 0xFFFF;
@@ -244,7 +253,16 @@ esp_err_t esp_ping_new_session(const esp_ping_config_t *config, const esp_ping_c
         ep->sock = socket(AF_INET6, SOCK_RAW, IP6_NEXTH_ICMP6);
     }
     PING_CHECK(ep->sock > 0, "create socket failed: %d", err, ESP_FAIL, ep->sock);
-
+    /* set if index */
+    if(config->interface) {
+        struct ifreq iface;
+        if(netif_index_to_name(config->interface, iface.ifr_name) == NULL) {
+          goto err;
+        }
+        if(setsockopt(ep->sock, SOL_SOCKET, SO_BINDTODEVICE, &iface, sizeof(iface) !=0)) {
+          goto err;
+        }
+    }
     struct timeval timeout;
     timeout.tv_sec = config->timeout_ms / 1000;
     timeout.tv_usec = (config->timeout_ms % 1000) * 1000;
@@ -259,11 +277,13 @@ esp_err_t esp_ping_new_session(const esp_ping_config_t *config, const esp_ping_c
         struct sockaddr_in *to4 = (struct sockaddr_in *)&ep->target_addr;
         to4->sin_family = AF_INET;
         inet_addr_from_ip4addr(&to4->sin_addr, ip_2_ip4(&config->target_addr));
+        ep->packet_hdr->type = ICMP_ECHO;
     }
     if (IP_IS_V6(&config->target_addr)) {
         struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)&ep->target_addr;
         to6->sin6_family = AF_INET6;
         inet6_addr_from_ip6addr(&to6->sin6_addr, ip_2_ip6(&config->target_addr));
+        ep->packet_hdr->type = ICMP6_TYPE_EREQ;
     }
     /* return ping handle to user */
     *hdl_out = (esp_ping_handle_t)ep;

+ 2 - 1
components/lwip/include/apps/esp_ping.h

@@ -54,7 +54,8 @@ typedef enum {
     PING_TARGET_RES_FN              = 55,   /**< ping result callback function */
     PING_TARGET_RES_RESET           = 56,   /**< ping result statistic reset */
     PING_TARGET_DATA_LEN            = 57,   /**< ping data length*/
-    PING_TARGET_IP_TOS              = 58    /**< ping QOS*/
+    PING_TARGET_IP_TOS              = 58,    /**< ping QOS*/
+    PING_TARGET_IF_INDEX            = 59    /**< ping if index*/
 } ping_target_id_t;
 
 typedef enum {

+ 2 - 0
components/lwip/include/apps/ping/ping_sock.h

@@ -71,6 +71,7 @@ typedef struct {
     ip_addr_t target_addr;    /*!< Target IP address, either IPv4 or IPv6 */
     uint32_t task_stack_size; /*!< Stack size of internal ping task */
     uint32_t task_prio;       /*!< Priority of internal ping task */
+    uint32_t interface;       /*!< Netif index, interface=0 means NETIF_NO_INDEX*/
 } esp_ping_config_t;
 
 /**
@@ -87,6 +88,7 @@ typedef struct {
         .target_addr = ip_addr_any_type, \
         .task_stack_size = 2048,         \
         .task_prio = 2,                  \
+        .interface = 0,\
     }
 
 #define ESP_PING_COUNT_INFINITE (0) /*!< Set ping count to zero will ping target infinitely */

+ 23 - 16
examples/protocols/icmp_echo/main/echo_example_main.c

@@ -32,7 +32,7 @@ static void cmd_ping_on_ping_success(esp_ping_handle_t hdl, void *args)
     esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len));
     esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time));
     printf("%d bytes from %s icmp_seq=%d ttl=%d time=%d ms\n",
-           recv_len, inet_ntoa(target_addr.u_addr.ip4), seqno, ttl, elapsed_time);
+           recv_len, ipaddr_ntoa((ip_addr_t*)&target_addr), seqno, ttl, elapsed_time);
 }
 
 static void cmd_ping_on_ping_timeout(esp_ping_handle_t hdl, void *args)
@@ -41,7 +41,7 @@ static void cmd_ping_on_ping_timeout(esp_ping_handle_t hdl, void *args)
     ip_addr_t target_addr;
     esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
     esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
-    printf("From %s icmp_seq=%d timeout\n", inet_ntoa(target_addr.u_addr.ip4), seqno);
+    printf("From %s icmp_seq=%d timeout\n",ipaddr_ntoa((ip_addr_t*)&target_addr), seqno);
 }
 
 static void cmd_ping_on_ping_end(esp_ping_handle_t hdl, void *args)
@@ -108,24 +108,31 @@ static int do_ping_cmd(int argc, char **argv)
     }
 
     // parse IP address
+    struct sockaddr_in6 sock_addr6;
     ip_addr_t target_addr;
-    struct addrinfo hint;
-    struct addrinfo *res = NULL;
-    memset(&hint, 0, sizeof(hint));
     memset(&target_addr, 0, sizeof(target_addr));
-    /* convert domain name to IP address */
-    if (getaddrinfo(ping_args.host->sval[0], NULL, &hint, &res) != 0) {
-        printf("ping: unknown host %s\n", ping_args.host->sval[0]);
-        return 1;
-    }
-    if (res->ai_family == AF_INET) {
-        struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr;
-        inet_addr_to_ip4addr(ip_2_ip4(&target_addr), &addr4);
+    
+    if (inet_pton(AF_INET6, ping_args.host->sval[0], &sock_addr6.sin6_addr) == 1) {
+        /* convert ip6 string to ip6 address */
+        ipaddr_aton(ping_args.host->sval[0], &target_addr);
     } else {
-        struct in6_addr addr6 = ((struct sockaddr_in6 *) (res->ai_addr))->sin6_addr;
-        inet6_addr_to_ip6addr(ip_2_ip6(&target_addr), &addr6);
+        struct addrinfo hint;
+        struct addrinfo *res = NULL;
+        memset(&hint, 0, sizeof(hint));
+        /* convert ip4 string or hostname to ip4 or ip6 address */
+        if (getaddrinfo(ping_args.host->sval[0], NULL, &hint, &res) != 0) {
+            printf("ping: unknown host %s\n", ping_args.host->sval[0]);
+            return 1;
+        }
+        if (res->ai_family == AF_INET) {
+            struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr;
+            inet_addr_to_ip4addr(ip_2_ip4(&target_addr), &addr4);
+        } else {
+            struct in6_addr addr6 = ((struct sockaddr_in6 *) (res->ai_addr))->sin6_addr;
+            inet6_addr_to_ip6addr(ip_2_ip6(&target_addr), &addr6);
+        }
+        freeaddrinfo(res);
     }
-    freeaddrinfo(res);
     config.target_addr = target_addr;
 
     /* set callback functions */