From e7e5884a772201354487824b652d1c8ec04f3e45 Mon Sep 17 00:00:00 2001 From: xueyunfei Date: Mon, 6 Jul 2020 19:20:48 +0800 Subject: [PATCH] lwip:add feature for ipv6 ping --- components/lwip/apps/ping/esp_ping.c | 18 ++++-- components/lwip/apps/ping/ping.c | 11 ++-- components/lwip/apps/ping/ping_sock.c | 58 +++++++++++++------ components/lwip/include/apps/esp_ping.h | 3 +- components/lwip/include/apps/ping/ping_sock.h | 2 + .../icmp_echo/main/echo_example_main.c | 39 ++++++++----- 6 files changed, 84 insertions(+), 47 deletions(-) diff --git a/components/lwip/apps/ping/esp_ping.c b/components/lwip/apps/ping/esp_ping.c index 75b669412d..65c0540e42 100644 --- a/components/lwip/apps/ping/esp_ping.c +++ b/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; diff --git a/components/lwip/apps/ping/ping.c b/components/lwip/apps/ping/ping.c index 1082f62fb4..8f954d5a7a 100644 --- a/components/lwip/apps/ping/ping.c +++ b/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, diff --git a/components/lwip/apps/ping/ping_sock.c b/components/lwip/apps/ping/ping_sock.c index ced6e2bf3e..243375ac9c 100644 --- a/components/lwip/apps/ping/ping_sock.c +++ b/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; diff --git a/components/lwip/include/apps/esp_ping.h b/components/lwip/include/apps/esp_ping.h index 181921d325..86dcc6ac01 100644 --- a/components/lwip/include/apps/esp_ping.h +++ b/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 { diff --git a/components/lwip/include/apps/ping/ping_sock.h b/components/lwip/include/apps/ping/ping_sock.h index f2581fdbe8..2a37e583e8 100644 --- a/components/lwip/include/apps/ping/ping_sock.h +++ b/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 */ diff --git a/examples/protocols/icmp_echo/main/echo_example_main.c b/examples/protocols/icmp_echo/main/echo_example_main.c index 5750749acb..eb400bdde2 100644 --- a/examples/protocols/icmp_echo/main/echo_example_main.c +++ b/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 */