Sfoglia il codice sorgente

openthread: add iperf example for ot-network test

zhangwenxu 4 anni fa
parent
commit
2be77287b3

+ 6 - 0
components/openthread/Kconfig

@@ -91,4 +91,10 @@ menu "OpenThread"
         help
             Override the shipped libopenthread_br.a and libopenthread_port.a, for internal builds.
 
+    config OPENTHREAD_NUM_MESSAGE_BUFFERS
+        int "The number of openthread message buffers"
+        depends on OPENTHREAD_ENABLED
+        default 65
+        range 50 100
+
 endmenu

+ 1 - 1
components/openthread/private_include/openthread-core-esp32x-ftd-config.h

@@ -95,7 +95,7 @@
  *
  * The number of message buffers in buffer pool
  */
-#define OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS 50
+#define OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS CONFIG_OPENTHREAD_NUM_MESSAGE_BUFFERS
 
 /**
  * @def OPENTHREAD_CONFIG_COAP_API_ENABLE

+ 27 - 12
examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/main/cmd_wifi.c

@@ -23,7 +23,9 @@ typedef struct {
     struct arg_str *ip;
     struct arg_lit *server;
     struct arg_lit *udp;
+    struct arg_lit *version;
     struct arg_int *port;
+    struct arg_int *length;
     struct arg_int *interval;
     struct arg_int *time;
     struct arg_lit *abort;
@@ -51,8 +53,8 @@ static const char *TAG = "iperf";
 static EventGroupHandle_t wifi_event_group;
 const int CONNECTED_BIT = BIT0;
 const int DISCONNECTED_BIT = BIT1;
-static esp_netif_t * sta_netif = NULL;
-static esp_netif_t * ap_netif = NULL;
+static esp_netif_t *sta_netif = NULL;
+static esp_netif_t *ap_netif = NULL;
 
 static void scan_done_handler(void)
 {
@@ -75,8 +77,8 @@ static void scan_done_handler(void)
     free(ap_list_buffer);
 }
 
-static void wifi_event_handler(void* arg, esp_event_base_t event_base,
-                                int32_t event_id, void* event_data)
+static void wifi_event_handler(void *arg, esp_event_base_t event_base,
+                               int32_t event_id, void *event_data)
 {
     switch (event_id) {
     case WIFI_EVENT_SCAN_DONE:
@@ -102,8 +104,8 @@ static void wifi_event_handler(void* arg, esp_event_base_t event_base,
     return;
 }
 
-static void ip_event_handler(void* arg, esp_event_base_t event_base,
-                                int32_t event_id, void* event_data)
+static void ip_event_handler(void *arg, esp_event_base_t event_base,
+                             int32_t event_id, void *event_data)
 {
     switch (event_id) {
     case IP_EVENT_STA_GOT_IP:
@@ -292,7 +294,7 @@ static int wifi_cmd_query(int argc, char **argv)
 static uint32_t wifi_get_local_ip(void)
 {
     int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 0);
-    esp_netif_t * ifx = ap_netif;
+    esp_netif_t *ifx = ap_netif;
     esp_netif_ip_info_t ip_info;
     wifi_mode_t mode;
 
@@ -323,6 +325,9 @@ static int wifi_cmd_iperf(int argc, char **argv)
 
     memset(&cfg, 0, sizeof(cfg));
 
+    // wifi iperf only support IPV4 address
+    cfg.type = IPERF_IP_TYPE_IPV4;
+
     if ( iperf_args.abort->count != 0) {
         iperf_stop();
         return 0;
@@ -337,15 +342,21 @@ static int wifi_cmd_iperf(int argc, char **argv)
     if (iperf_args.ip->count == 0) {
         cfg.flag |= IPERF_FLAG_SERVER;
     } else {
-        cfg.dip = esp_ip4addr_aton(iperf_args.ip->sval[0]);
+        cfg.destination_ip4 = esp_ip4addr_aton(iperf_args.ip->sval[0]);
         cfg.flag |= IPERF_FLAG_CLIENT;
     }
 
-    cfg.sip = wifi_get_local_ip();
-    if (cfg.sip == 0) {
+    cfg.source_ip4 = wifi_get_local_ip();
+    if (cfg.source_ip4 == 0) {
         return 0;
     }
 
+    if (iperf_args.length->count == 0) {
+        cfg.len_send_buf = 0;
+    } else {
+        cfg.len_send_buf = iperf_args.length->ival[0];
+    }
+
     if (iperf_args.udp->count == 0) {
         cfg.flag |= IPERF_FLAG_TCP;
     } else {
@@ -386,8 +397,10 @@ static int wifi_cmd_iperf(int argc, char **argv)
     ESP_LOGI(TAG, "mode=%s-%s sip=%d.%d.%d.%d:%d, dip=%d.%d.%d.%d:%d, interval=%d, time=%d",
              cfg.flag & IPERF_FLAG_TCP ? "tcp" : "udp",
              cfg.flag & IPERF_FLAG_SERVER ? "server" : "client",
-             cfg.sip & 0xFF, (cfg.sip >> 8) & 0xFF, (cfg.sip >> 16) & 0xFF, (cfg.sip >> 24) & 0xFF, cfg.sport,
-             cfg.dip & 0xFF, (cfg.dip >> 8) & 0xFF, (cfg.dip >> 16) & 0xFF, (cfg.dip >> 24) & 0xFF, cfg.dport,
+             cfg.source_ip4 & 0xFF, (cfg.source_ip4 >> 8) & 0xFF, (cfg.source_ip4 >> 16) & 0xFF,
+             (cfg.source_ip4 >> 24) & 0xFF, cfg.sport,
+             cfg.destination_ip4 & 0xFF, (cfg.destination_ip4 >> 8) & 0xFF, (cfg.destination_ip4 >> 16) & 0xFF,
+             (cfg.destination_ip4 >> 24) & 0xFF, cfg.dport,
              cfg.interval, cfg.time);
 
     iperf_start(&cfg);
@@ -471,7 +484,9 @@ void register_wifi(void)
     iperf_args.ip = arg_str0("c", "client", "<ip>", "run in client mode, connecting to <host>");
     iperf_args.server = arg_lit0("s", "server", "run in server mode");
     iperf_args.udp = arg_lit0("u", "udp", "use UDP rather than TCP");
+    iperf_args.version = arg_lit0("V", "ipv6_domain", "use IPV6 address rather than IPV4");
     iperf_args.port = arg_int0("p", "port", "<port>", "server port to listen on/connect to");
+    iperf_args.length = arg_int0("l", "len", "<length>", "set read/write buffer size");
     iperf_args.interval = arg_int0("i", "interval", "<interval>", "seconds between periodic bandwidth reports");
     iperf_args.time = arg_int0("t", "time", "<time>", "time in seconds to transmit for (default 10 secs)");
     iperf_args.abort = arg_lit0("a", "abort", "abort running iperf");

+ 22 - 7
examples/common_components/iperf/include/iperf.h

@@ -10,12 +10,20 @@
 #ifndef __IPERF_H_
 #define __IPERF_H_
 
+#include "esp_err.h"
+#include "esp_types.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#include "esp_types.h"
-#include "esp_err.h"
+#define IPERF_IP_TYPE_IPV4 0
+#define IPERF_IP_TYPE_IPV6 1
+#define IPERF_TRANS_TYPE_TCP 0
+#define IPERF_TRANS_TYPE_UDP 1
+
+#define IPERF_FLAG_SET(cfg, flag) ((cfg) |= (flag))
+#define IPERF_FLAG_CLR(cfg, flag) ((cfg) &= (~(flag)))
 
 #define IPERF_FLAG_CLIENT (1)
 #define IPERF_FLAG_SERVER (1 << 1)
@@ -27,12 +35,11 @@ extern "C" {
 #define IPERF_DEFAULT_TIME 30
 
 #define IPERF_TRAFFIC_TASK_NAME "iperf_traffic"
-#define IPERF_TRAFFIC_TASK_PRIORITY 10
+#define IPERF_TRAFFIC_TASK_PRIORITY 4
 #define IPERF_TRAFFIC_TASK_STACK 4096
 #define IPERF_REPORT_TASK_NAME "iperf_report"
-#define IPERF_REPORT_TASK_PRIORITY 20
+#define IPERF_REPORT_TASK_PRIORITY 6
 #define IPERF_REPORT_TASK_STACK 4096
-#define IPERF_REPORT_TASK_NAME "iperf_report"
 
 #define IPERF_UDP_TX_LEN (1472)
 #define IPERF_UDP_RX_LEN (16 << 10)
@@ -46,12 +53,20 @@ extern "C" {
 
 typedef struct {
     uint32_t flag;
-    uint32_t dip;
-    uint32_t sip;
+    union {
+        uint32_t destination_ip4;
+        char    *destination_ip6;
+    };
+    union {
+        uint32_t source_ip4;
+        char    *source_ip6;
+    };
+    uint8_t type;
     uint16_t dport;
     uint16_t sport;
     uint32_t interval;
     uint32_t time;
+    uint16_t len_send_buf;
 } iperf_cfg_t;
 
 esp_err_t iperf_start(iperf_cfg_t *cfg);

+ 273 - 198
examples/common_components/iperf/iperf.c

@@ -12,6 +12,7 @@
 #include <sys/socket.h>
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
+#include "esp_check.h"
 #include "esp_log.h"
 #include "iperf.h"
 
@@ -24,12 +25,6 @@ typedef struct {
     uint32_t sockfd;
 } iperf_ctrl_t;
 
-typedef struct {
-    int32_t id;
-    uint32_t sec;
-    uint32_t usec;
-} iperf_udp_pkt_t;
-
 static bool s_iperf_is_running = false;
 static iperf_ctrl_t s_iperf_ctrl;
 static const char *TAG = "iperf";
@@ -56,7 +51,6 @@ inline static bool iperf_is_tcp_server(void)
 
 static int iperf_get_socket_error_code(int sockfd)
 {
-
     return errno;
 }
 
@@ -113,241 +107,325 @@ static esp_err_t iperf_start_report(void)
     return ESP_OK;
 }
 
-static esp_err_t IRAM_ATTR iperf_run_tcp_server(void)
+static void socket_recv(int recv_socket, struct sockaddr_storage listen_addr, uint8_t type)
 {
-    socklen_t addr_len = sizeof(struct sockaddr);
-    struct sockaddr_in remote_addr;
-    struct sockaddr_in addr;
-    int actual_recv = 0;
-    int want_recv = 0;
+    bool udp_recv_start = true;
     uint8_t *buffer;
-    int listen_socket;
-    struct timeval t;
-    int sockfd;
-    int opt = 1;
-
-    listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-    if (listen_socket < 0) {
-        iperf_show_socket_error_reason("tcp server create", listen_socket);
-        return ESP_FAIL;
-    }
-
-    setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
-
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(s_iperf_ctrl.cfg.sport);
-    addr.sin_addr.s_addr = s_iperf_ctrl.cfg.sip;
-    if (bind(listen_socket, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
-        iperf_show_socket_error_reason("tcp server bind", listen_socket);
-        close(listen_socket);
-        return ESP_FAIL;
-    }
-
-    if (listen(listen_socket, 5) < 0) {
-        iperf_show_socket_error_reason("tcp server listen", listen_socket);
-        close(listen_socket);
-        return ESP_FAIL;
-    }
-
-    printf("iperf tcp server create successfully\n");
-    buffer = s_iperf_ctrl.buffer;
-    want_recv = s_iperf_ctrl.buffer_len;
-    while (!s_iperf_ctrl.finish) {
-
-        /*TODO need to change to non-block mode */
-        sockfd = accept(listen_socket, (struct sockaddr *)&remote_addr, &addr_len);
-        if (sockfd < 0) {
-            iperf_show_socket_error_reason("tcp server listen", listen_socket);
-            close(listen_socket);
-            return ESP_FAIL;
-        } else {
-            printf("accept: %s,%d\n", inet_ntoa(remote_addr.sin_addr), htons(remote_addr.sin_port));
-            iperf_start_report();
-
-            t.tv_sec = IPERF_SOCKET_RX_TIMEOUT;
-            setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
-        }
-
-        while (!s_iperf_ctrl.finish) {
-            actual_recv = recv(sockfd, buffer, want_recv, 0);
-            if (actual_recv < 0) {
-                iperf_show_socket_error_reason("tcp server recv", listen_socket);
-                s_iperf_ctrl.finish = true;
-                break;
-            } else {
-                s_iperf_ctrl.total_len += actual_recv;
-            }
-        }
-
-        close(sockfd);
-    }
-
-    s_iperf_ctrl.finish = true;
-    close(listen_socket);
-    return ESP_OK;
-}
-
-static esp_err_t IRAM_ATTR iperf_run_udp_server(void)
-{
-    socklen_t addr_len = sizeof(struct sockaddr_in);
-    struct sockaddr_in addr;
-    int actual_recv = 0;
-    struct timeval t;
     int want_recv = 0;
-    uint8_t *buffer;
-    int sockfd;
-    int opt = 1;
-    bool udp_recv_start = true ;
-
-    sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-    if (sockfd < 0) {
-        iperf_show_socket_error_reason("udp server create", sockfd);
-        return ESP_FAIL;
-    }
-
-    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
-
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(s_iperf_ctrl.cfg.sport);
-    addr.sin_addr.s_addr = s_iperf_ctrl.cfg.sip;
-    if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
-        iperf_show_socket_error_reason("udp server bind", sockfd);
-        return ESP_FAIL;
-    }
-
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(s_iperf_ctrl.cfg.sport);
-    addr.sin_addr.s_addr = s_iperf_ctrl.cfg.sip;
+    int actual_recv = 0;
+    socklen_t addr_len = sizeof(struct sockaddr);
 
     buffer = s_iperf_ctrl.buffer;
     want_recv = s_iperf_ctrl.buffer_len;
-    ESP_LOGI(TAG, "want recv=%d", want_recv);
-
-    t.tv_sec = IPERF_SOCKET_RX_TIMEOUT;
-    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
 
     while (!s_iperf_ctrl.finish) {
-        actual_recv = recvfrom(sockfd, buffer, want_recv, 0, (struct sockaddr *)&addr, &addr_len);
+        if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) {
+            addr_len = sizeof(struct sockaddr_in6);
+            actual_recv = recvfrom(recv_socket, buffer, want_recv, 0, (struct sockaddr *)&listen_addr, &addr_len);
+        } else if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
+            addr_len = sizeof(struct sockaddr_in);
+            actual_recv = recvfrom(recv_socket, buffer, want_recv, 0, (struct sockaddr *)&listen_addr, &addr_len);
+        }
         if (actual_recv < 0) {
-            iperf_show_socket_error_reason("udp server recv", sockfd);
+            if (type == IPERF_TRANS_TYPE_TCP) {
+                iperf_show_socket_error_reason("tcp server recv", recv_socket);
+            }
+            if (type == IPERF_TRANS_TYPE_UDP) {
+                iperf_show_socket_error_reason("udp server recv", recv_socket);
+            }
+            s_iperf_ctrl.finish = true;
+            break;
         } else {
-            if(udp_recv_start){
+            if (udp_recv_start) {
                 iperf_start_report();
                 udp_recv_start = false;
             }
             s_iperf_ctrl.total_len += actual_recv;
         }
     }
-
-    s_iperf_ctrl.finish = true;
-    close(sockfd);
-    return ESP_OK;
 }
 
-static esp_err_t iperf_run_udp_client(void)
+static void socket_send(int send_socket, struct sockaddr_storage dest_addr, uint8_t type)
 {
-    struct sockaddr_in addr;
-    iperf_udp_pkt_t *udp;
-    int actual_send = 0;
     bool retry = false;
-    uint32_t delay = 1;
-    int want_send = 0;
     uint8_t *buffer;
-    int sockfd;
-    int opt = 1;
-    int err;
-    int id;
-
-    sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-    if (sockfd < 0) {
-        iperf_show_socket_error_reason("udp client create", sockfd);
-        return ESP_FAIL;
-    }
-
-    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
-
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(s_iperf_ctrl.cfg.dport);
-    addr.sin_addr.s_addr = s_iperf_ctrl.cfg.dip;
+    uint8_t delay = 0;
+    int actual_send = 0;
+    int want_send = 0;
+    int err = 0;
 
-    iperf_start_report();
     buffer = s_iperf_ctrl.buffer;
-    udp = (iperf_udp_pkt_t *)buffer;
     want_send = s_iperf_ctrl.buffer_len;
-    id = 0;
+    iperf_start_report();
 
     while (!s_iperf_ctrl.finish) {
-        if (false == retry) {
-            id++;
-            udp->id = htonl(id);
-            delay = 1;
+        if (type == IPERF_TRANS_TYPE_UDP) {
+            if (false == retry) {
+                delay = 1;
+            }
+            retry = false;
+        }
+        if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) {
+            actual_send = sendto(send_socket, buffer, want_send, 0, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
+        } else if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
+            actual_send = sendto(send_socket, buffer, want_send, 0, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in));
         }
-
-        retry = false;
-        actual_send = sendto(sockfd, buffer, want_send, 0, (struct sockaddr *)&addr, sizeof(addr));
-
         if (actual_send != want_send) {
-            err = iperf_get_socket_error_code(sockfd);
-            if (err == ENOMEM) {
-                vTaskDelay(delay);
-                if (delay < IPERF_MAX_DELAY) {
-                    delay <<= 1;
+            if (type == IPERF_TRANS_TYPE_UDP) {
+                err = iperf_get_socket_error_code(send_socket);
+                if (err == ENOMEM) {
+                    vTaskDelay(delay);
+                    if (delay < IPERF_MAX_DELAY) {
+                        delay <<= 1;
+                    }
+                    retry = true;
+                    continue;
+                } else {
+                    if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
+                        ESP_LOGE(TAG, "udp client send abort: err=%d", err);
+                    }
                 }
-                retry = true;
-                continue;
-            } else {
-                ESP_LOGE(TAG, "udp client send abort: err=%d", err);
+            }
+            if (type == IPERF_TRANS_TYPE_TCP) {
+                iperf_show_socket_error_reason("tcp client send", send_socket);
+                ESP_LOGI(TAG, "tcp client send error\n");
                 break;
             }
         } else {
             s_iperf_ctrl.total_len += actual_send;
         }
     }
+}
+
+static esp_err_t IRAM_ATTR iperf_run_tcp_server(void)
+{
+    int listen_socket = -1;
+    int client_socket = -1;
+    int opt = 1;
+    int err = 0;
+    esp_err_t ret = ESP_OK;
+    struct sockaddr_in remote_addr;
+    struct timeval timeout = { 0 };
+    socklen_t addr_len = sizeof(struct sockaddr);
+    struct sockaddr_storage listen_addr = { 0 };
+    struct sockaddr_in6 listen_addr6 = { 0 };
+    struct sockaddr_in listen_addr4 = { 0 };
+
+    ESP_GOTO_ON_FALSE((s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6 || s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4), ESP_FAIL, exit, TAG, "Ivalid AF types");
 
+    if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) {
+        // The TCP server listen at the address "::", which means all addresses can be listened to.
+        inet6_aton("::", &listen_addr6.sin6_addr);
+        listen_addr6.sin6_family = AF_INET6;
+        listen_addr6.sin6_port = htons(s_iperf_ctrl.cfg.sport);
+
+        listen_socket = socket(AF_INET6, SOCK_STREAM, IPPROTO_IPV6);
+        ESP_GOTO_ON_FALSE((listen_socket >= 0), ESP_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
+
+        setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+        setsockopt(listen_socket, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
+
+        ESP_LOGI(TAG, "Socket created");
+
+        err = bind(listen_socket, (struct sockaddr *)&listen_addr6, sizeof(listen_addr6));
+        ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to bind: errno %d, IPPROTO: %d", errno, AF_INET6);
+        err = listen(listen_socket, 1);
+        ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Error occurred during listen: errno %d", errno);
+
+        timeout.tv_sec = IPERF_SOCKET_RX_TIMEOUT;
+        setsockopt(listen_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+
+        memcpy(&listen_addr, &listen_addr6, sizeof(listen_addr6));
+    } else if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
+        listen_addr4.sin_family = AF_INET;
+        listen_addr4.sin_port = htons(s_iperf_ctrl.cfg.sport);
+        listen_addr4.sin_addr.s_addr = s_iperf_ctrl.cfg.source_ip4;
+
+        listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+        ESP_GOTO_ON_FALSE((listen_socket >= 0), ESP_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
+
+        setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+
+        ESP_LOGI(TAG, "Socket created");
+
+        err = bind(listen_socket, (struct sockaddr *)&listen_addr4, sizeof(listen_addr4));
+        ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to bind: errno %d, IPPROTO: %d", errno, AF_INET);
+
+        err = listen(listen_socket, 5);
+        ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Error occurred during listen: errno %d", errno);
+        memcpy(&listen_addr, &listen_addr4, sizeof(listen_addr4));
+    }
+
+    client_socket = accept(listen_socket, (struct sockaddr *)&remote_addr, &addr_len);
+    ESP_GOTO_ON_FALSE((client_socket >= 0), ESP_FAIL, exit, TAG, "Unable to accept connection: errno %d", errno);
+    ESP_LOGI(TAG, "accept: %s,%d\n", inet_ntoa(remote_addr.sin_addr), htons(remote_addr.sin_port));
+
+    timeout.tv_sec = IPERF_SOCKET_RX_TIMEOUT;
+    setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+
+    socket_recv(client_socket, listen_addr, IPERF_TRANS_TYPE_TCP);
+exit:
+    if (listen_socket != -1) {
+        shutdown(listen_socket, 0);
+        close(listen_socket);
+        ESP_LOGI(TAG, "TCP Socket server is closed.");
+    }
     s_iperf_ctrl.finish = true;
-    close(sockfd);
-    return ESP_OK;
+    return ret;
 }
 
 static esp_err_t iperf_run_tcp_client(void)
 {
-    struct sockaddr_in remote_addr;
-    int actual_send = 0;
-    int want_send = 0;
-    uint8_t *buffer;
-    int sockfd;
+    int client_socket = -1;
+    int err = 0;
+    esp_err_t ret = ESP_OK;
+    struct sockaddr_storage dest_addr = { 0 };
+    struct sockaddr_in6 dest_addr6 = { 0 };
+    struct sockaddr_in dest_addr4 = { 0 };
+
+    ESP_GOTO_ON_FALSE((s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6 || s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4), ESP_FAIL, exit, TAG, "Ivalid AF types");
+
+    if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) {
+        client_socket = socket(AF_INET6, SOCK_STREAM, IPPROTO_IPV6);
+        ESP_GOTO_ON_FALSE((client_socket >= 0), ESP_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
+
+        inet6_aton(s_iperf_ctrl.cfg.destination_ip6, &dest_addr6.sin6_addr);
+        dest_addr6.sin6_family = AF_INET6;
+        dest_addr6.sin6_port = htons(s_iperf_ctrl.cfg.dport);
+
+        err = connect(client_socket, (struct sockaddr *)&dest_addr6, sizeof(struct sockaddr_in6));
+        ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to connect: errno %d", errno);
+        ESP_LOGI(TAG, "Successfully connected");
+        memcpy(&dest_addr, &dest_addr6, sizeof(dest_addr6));
+    } else if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
+        client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+        ESP_GOTO_ON_FALSE((client_socket >= 0), ESP_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
+
+        dest_addr4.sin_family = AF_INET;
+        dest_addr4.sin_port = htons(s_iperf_ctrl.cfg.dport);
+        dest_addr4.sin_addr.s_addr = s_iperf_ctrl.cfg.destination_ip4;
+        err = connect(client_socket, (struct sockaddr *)&dest_addr4, sizeof(struct sockaddr_in));
+        ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to connect: errno %d", errno);
+        ESP_LOGI(TAG, "Successfully connected");
+        memcpy(&dest_addr, &dest_addr4, sizeof(dest_addr4));
+    }
 
-    sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-    if (sockfd < 0) {
-        iperf_show_socket_error_reason("tcp client create", sockfd);
-        return ESP_FAIL;
+    socket_send(client_socket, dest_addr, IPERF_TRANS_TYPE_TCP);
+exit:
+    if (client_socket != -1) {
+        shutdown(client_socket, 0);
+        close(client_socket);
+        ESP_LOGI(TAG, "TCP Socket client is closed.");
     }
+    s_iperf_ctrl.finish = true;
+    return ret;
+}
 
-    memset(&remote_addr, 0, sizeof(remote_addr));
-    remote_addr.sin_family = AF_INET;
-    remote_addr.sin_port = htons(s_iperf_ctrl.cfg.dport);
-    remote_addr.sin_addr.s_addr = s_iperf_ctrl.cfg.dip;
-    if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(remote_addr)) < 0) {
-        iperf_show_socket_error_reason("tcp client connect", sockfd);
-        return ESP_FAIL;
+static esp_err_t IRAM_ATTR iperf_run_udp_server(void)
+{
+    int listen_socket = -1;
+    int opt = 1;
+    int err = 0;
+    esp_err_t ret = ESP_OK;
+    struct timeval timeout = { 0 };
+    struct sockaddr_storage listen_addr = { 0 };
+    struct sockaddr_in6 listen_addr6 = { 0 };
+    struct sockaddr_in listen_addr4 = { 0 };
+
+    ESP_GOTO_ON_FALSE((s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6 || s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4), ESP_FAIL, exit, TAG, "Ivalid AF types");
+
+    if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) {
+        // The UDP server listen at the address "::", which means all addresses can be listened to.
+        inet6_aton("::", &listen_addr6.sin6_addr);
+        listen_addr6.sin6_family = AF_INET6;
+        listen_addr6.sin6_port = htons(s_iperf_ctrl.cfg.sport);
+
+        listen_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+        ESP_GOTO_ON_FALSE((listen_socket >= 0), ESP_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
+        ESP_LOGI(TAG, "Socket created");
+
+        setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+
+        err = bind(listen_socket, (struct sockaddr *)&listen_addr6, sizeof(struct sockaddr_in6));
+        ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to bind: errno %d", errno);
+        ESP_LOGI(TAG, "Socket bound, port %d", listen_addr6.sin6_port);
+
+        memcpy(&listen_addr, &listen_addr6, sizeof(listen_addr6));
+    } else if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
+        listen_addr4.sin_family = AF_INET;
+        listen_addr4.sin_port = htons(s_iperf_ctrl.cfg.sport);
+        listen_addr4.sin_addr.s_addr = s_iperf_ctrl.cfg.source_ip4;
+
+        listen_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+        ESP_GOTO_ON_FALSE((listen_socket >= 0), ESP_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
+        ESP_LOGI(TAG, "Socket created");
+
+        setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+
+        err = bind(listen_socket, (struct sockaddr *)&listen_addr4, sizeof(struct sockaddr_in));
+        ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to bind: errno %d", errno);
+        ESP_LOGI(TAG, "Socket bound, port %d", listen_addr4.sin_port);
+        memcpy(&listen_addr, &listen_addr4, sizeof(listen_addr4));
     }
 
-    iperf_start_report();
-    buffer = s_iperf_ctrl.buffer;
-    want_send = s_iperf_ctrl.buffer_len;
-    while (!s_iperf_ctrl.finish) {
-        actual_send = send(sockfd, buffer, want_send, 0);
-        if (actual_send <= 0) {
-            iperf_show_socket_error_reason("tcp client send", sockfd);
-            break;
-        } else {
-            s_iperf_ctrl.total_len += actual_send;
-        }
+    timeout.tv_sec = IPERF_SOCKET_RX_TIMEOUT;
+    setsockopt(listen_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+
+    socket_recv(listen_socket, listen_addr, IPERF_TRANS_TYPE_UDP);
+exit:
+    if (listen_socket != -1) {
+        shutdown(listen_socket, 0);
+        close(listen_socket);
     }
+    ESP_LOGI(TAG, "Udp socket server is closed.");
+    s_iperf_ctrl.finish = true;
+    return ret;
+}
 
+static esp_err_t iperf_run_udp_client(void)
+{
+    int client_socket = -1;
+    int opt = 1;
+    esp_err_t ret = ESP_OK;
+    struct sockaddr_storage dest_addr = { 0 };
+    struct sockaddr_in6 dest_addr6 = { 0 };
+    struct sockaddr_in dest_addr4 = { 0 };
+
+    ESP_GOTO_ON_FALSE((s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6 || s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4), ESP_FAIL, exit, TAG, "Ivalid AF types");
+
+    if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) {
+        inet6_aton(s_iperf_ctrl.cfg.destination_ip6, &dest_addr6.sin6_addr);
+        dest_addr6.sin6_family = AF_INET6;
+        dest_addr6.sin6_port = htons(s_iperf_ctrl.cfg.dport);
+
+        client_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IPV6);
+        ESP_GOTO_ON_FALSE((client_socket >= 0), ESP_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
+        ESP_LOGI(TAG, "Socket created, sending to %s:%d", s_iperf_ctrl.cfg.destination_ip6, s_iperf_ctrl.cfg.dport);
+
+        setsockopt(client_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+        memcpy(&dest_addr, &dest_addr6, sizeof(dest_addr6));
+    } else if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
+        dest_addr4.sin_family = AF_INET;
+        dest_addr4.sin_port = htons(s_iperf_ctrl.cfg.dport);
+        dest_addr4.sin_addr.s_addr = s_iperf_ctrl.cfg.destination_ip4;
+
+        client_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+        ESP_GOTO_ON_FALSE((client_socket >= 0), ESP_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
+        ESP_LOGI(TAG, "Socket created, sending to %d:%d", s_iperf_ctrl.cfg.destination_ip4, s_iperf_ctrl.cfg.dport);
+
+        setsockopt(client_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+        memcpy(&dest_addr, &dest_addr4, sizeof(dest_addr4));
+    }
+
+    socket_send(client_socket, dest_addr, IPERF_TRANS_TYPE_UDP);
+exit:
+    if (client_socket != -1) {
+        shutdown(client_socket, 0);
+        close(client_socket);
+    }
     s_iperf_ctrl.finish = true;
-    close(sockfd);
-    return ESP_OK;
+    ESP_LOGI(TAG, "UDP Socket client is closed");
+    return ret;
 }
 
 static void iperf_task_traffic(void *arg)
@@ -374,11 +452,11 @@ static void iperf_task_traffic(void *arg)
 static uint32_t iperf_get_buffer_len(void)
 {
     if (iperf_is_udp_client()) {
-        return IPERF_UDP_TX_LEN;
+        return (s_iperf_ctrl.cfg.len_send_buf == 0 ? IPERF_UDP_TX_LEN : s_iperf_ctrl.cfg.len_send_buf);
     } else if (iperf_is_udp_server()) {
         return IPERF_UDP_RX_LEN;
     } else if (iperf_is_tcp_client()) {
-        return IPERF_TCP_TX_LEN;
+        return (s_iperf_ctrl.cfg.len_send_buf == 0 ? IPERF_TCP_TX_LEN : s_iperf_ctrl.cfg.len_send_buf);
     } else {
         return IPERF_TCP_RX_LEN;
     }
@@ -409,7 +487,6 @@ esp_err_t iperf_start(iperf_cfg_t *cfg)
         return ESP_FAIL;
     }
     memset(s_iperf_ctrl.buffer, 0, s_iperf_ctrl.buffer_len);
-
     ret = xTaskCreatePinnedToCore(iperf_task_traffic, IPERF_TRAFFIC_TASK_NAME, IPERF_TRAFFIC_TASK_STACK, NULL, IPERF_TRAFFIC_TASK_PRIORITY, NULL, portNUM_PROCESSORS - 1);
     if (ret != pdPASS) {
         ESP_LOGE(TAG, "create task %s failed", IPERF_TRAFFIC_TASK_NAME);
@@ -417,7 +494,6 @@ esp_err_t iperf_start(iperf_cfg_t *cfg)
         s_iperf_ctrl.buffer = NULL;
         return ESP_FAIL;
     }
-
     return ESP_OK;
 }
 
@@ -431,6 +507,5 @@ esp_err_t iperf_stop(void)
         ESP_LOGI(TAG, "wait current iperf to stop ...");
         vTaskDelay(300 / portTICK_PERIOD_MS);
     }
-
     return ESP_OK;
 }

+ 21 - 5
examples/ethernet/iperf/main/cmd_ethernet.c

@@ -65,7 +65,9 @@ static struct {
     struct arg_str *ip;
     struct arg_lit *server;
     struct arg_lit *udp;
+    struct arg_lit *version;
     struct arg_int *port;
+    struct arg_int *length;
     struct arg_int *interval;
     struct arg_int *time;
     struct arg_lit *abort;
@@ -84,6 +86,9 @@ static int eth_cmd_iperf(int argc, char **argv)
 
     memset(&cfg, 0, sizeof(cfg));
 
+    // ethernet iperf only support IPV4 address
+    cfg.type = IPERF_IP_TYPE_IPV4;
+
     /* iperf -a */
     if (iperf_args.abort->count != 0) {
         iperf_stop();
@@ -102,15 +107,22 @@ static int eth_cmd_iperf(int argc, char **argv)
     }
     /* iperf -c SERVER_ADDRESS */
     else {
-        cfg.dip = esp_ip4addr_aton(iperf_args.ip->sval[0]);
+        cfg.destination_ip4 = esp_ip4addr_aton(iperf_args.ip->sval[0]);
         cfg.flag |= IPERF_FLAG_CLIENT;
     }
 
+    if (iperf_args.length->count == 0) {
+        cfg.len_send_buf = 0;
+    } else {
+        cfg.len_send_buf = iperf_args.length->ival[0];
+    }
+
+
     /* acquiring for ip, could blocked here */
     xEventGroupWaitBits(eth_event_group, GOTIP_BIT, pdFALSE, pdTRUE, portMAX_DELAY);
 
-    cfg.sip = ip.ip.addr;
-    if (cfg.sip == 0) {
+    cfg.source_ip4 = ip.ip.addr;
+    if (cfg.source_ip4 == 0) {
         return 0;
     }
 
@@ -158,8 +170,10 @@ static int eth_cmd_iperf(int argc, char **argv)
     printf("mode=%s-%s sip=%d.%d.%d.%d:%d, dip=%d.%d.%d.%d:%d, interval=%d, time=%d\r\n",
            cfg.flag & IPERF_FLAG_TCP ? "tcp" : "udp",
            cfg.flag & IPERF_FLAG_SERVER ? "server" : "client",
-           cfg.sip & 0xFF, (cfg.sip >> 8) & 0xFF, (cfg.sip >> 16) & 0xFF, (cfg.sip >> 24) & 0xFF, cfg.sport,
-           cfg.dip & 0xFF, (cfg.dip >> 8) & 0xFF, (cfg.dip >> 16) & 0xFF, (cfg.dip >> 24) & 0xFF, cfg.dport,
+           cfg.source_ip4 & 0xFF, (cfg.source_ip4 >> 8) & 0xFF, (cfg.source_ip4 >> 16) & 0xFF,
+           (cfg.source_ip4 >> 24) & 0xFF, cfg.sport,
+           cfg.destination_ip4 & 0xFF, (cfg.destination_ip4 >> 8) & 0xFF,
+           (cfg.destination_ip4 >> 16) & 0xFF, (cfg.destination_ip4 >> 24) & 0xFF, cfg.dport,
            cfg.interval, cfg.time);
 
     iperf_start(&cfg);
@@ -324,8 +338,10 @@ void register_ethernet(void)
                              "run in client mode, connecting to <host>");
     iperf_args.server = arg_lit0("s", "server", "run in server mode");
     iperf_args.udp = arg_lit0("u", "udp", "use UDP rather than TCP");
+    iperf_args.version = arg_lit0("V", "ipv6_domain", "use IPV6 address rather than IPV4");
     iperf_args.port = arg_int0("p", "port", "<port>",
                                "server port to listen on/connect to");
+    iperf_args.length = arg_int0("l", "len", "<length>", "set read/write buffer size");
     iperf_args.interval = arg_int0("i", "interval", "<interval>",
                                    "seconds between periodic bandwidth reports");
     iperf_args.time = arg_int0("t", "time", "<time>", "time in seconds to transmit for (default 10 secs)");

+ 2 - 0
examples/openthread/ot_cli/CMakeLists.txt

@@ -2,5 +2,7 @@
 # in this exact order for cmake to work correctly
 cmake_minimum_required(VERSION 3.5)
 
+set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/iperf)
 include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+
 project(esp_ot_cli)

+ 2 - 0
examples/openthread/ot_cli/Makefile

@@ -5,4 +5,6 @@
 
 PROJECT_NAME := esp_ot_cli
 
+EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/iperf
+
 include $(IDF_PATH)/make/project.mk

+ 79 - 6
examples/openthread/ot_cli/README.md

@@ -84,7 +84,9 @@ leader
 Done
 ```
 
-## Example1: TCP/UDP server and client
+## Example1: Set up network
+
+You need to prepare two esp32h2(or two ESP devices each connected to a 15.4 RCP) and flashed with this example.
 
 ### Step 1 Configure the project
 
@@ -92,10 +94,7 @@ Done
 idf.py menuconfig
 ```
 
-Enable the operation: Example Configuration -> Enable custom command in ot-cli -> Enable openthread tcp/udp socket
-
 ### Step 2 Build, Flash, and Run
-You need to prepare two ESP devices each connected to a 15.4 RCP and flashed with this example.
 
 ```
 idf.py -p PORT flash monitor
@@ -136,7 +135,6 @@ Done
 leader
 Done
 ```
-
 Now the first device has formed a Thread network, on the second device run:
 
 ```bash
@@ -174,7 +172,21 @@ Done
 
 Now the second device has joined the Thread network and acting as a router (or a child).
 
-### Step 4 Set up tcp/udp socket server and client
+## Example2: TCP/UDP server and client
+
+You need to prepare two ESP devices each connected to a 15.4 RCP and flashed with this example.
+
+### Step 1 Configure the project and Set up network 
+
+```bash
+idf.py menuconfig
+```
+Enable the operation: Example Configuration -> Enable custom command in ot-cli
+
+After configuring the project project, you should follow 'Example1' to set up network.
+
+
+### Step 2 Set up tcp/udp socket server and client
 
 In leader device, run this command in command line shell.
 
@@ -243,3 +255,64 @@ I (38321) ot_secket: This message is from server
 I (38323) ot_secket: Socket client is closed.
 ```
 
+## Example3 iperf:
+
+### Step 1 Configure the project and Set up network 
+
+```bash
+idf.py menuconfig
+```
+Enable the operation: Openthread -> Enable custom command in ot-cli
+
+After configuring the project project, you should follow 'Example1' to set up network.
+
+### Step 2 Iperf test:
+
+Run this command for iperf help:
+```bash
+iperf
+I(272113) OPENTHREAD:[INFO]-CLI-----: execute command: iperf
+---iperf parameter---
+-s                  :     server mode, only receive
+-u                  :     upd mode
+-V                  :     use IPV6 address  
+-c <addr>           :     client mode, only transmit
+-i <interval>       :     seconds between periodic bandwidth reports
+-t <time>           :     time in seconds to transmit for (default 10 secs)
+-p <port>           :     server port to listen on/connect to
+-l <len_send_buf>   :     the lenth of send buffer
+---example---
+create a tcp server :     iperf -s -i 3 -p 5001 -t 60 
+create a udp client :     iperf -c <addr> -u -i 3 -t 60 -p 5001 -l 512
+Done
+```
+
+In leader device, run this command to get the leader IPv6 address.
+
+```bash
+> ipaddr
+fd00:db8:0:0:0:ff:fe00:fc00
+fd00:db8:0:0:0:ff:fe00:ac00
+fd00:db8:0:0:284a:cb4a:cb3b:2a42
+fe80:0:0:0:146e:a00:0:1
+```
+
+Then run this command in command line shell.
+
+```bash
+# for setting up an iperf tcp server
+> iperf -V -s -i 3 -p 5001 -t 20
+
+# for setting up an iperf udp server
+> iperf -V -s -u -i 3 -p 5001 -t 20
+```
+
+In router device, run this command in command line shell.
+
+```bash
+# for setting up an iperf tcp client
+> iperf -V -c fd00:db8:0:0:284a:cb4a:cb3b:2a42 -i 1 -t 14 -p 5001 -l 512
+
+# for setting up an iperf udp client
+> iperf -V -c fd00:db8:0:0:284a:cb4a:cb3b:2a42 -u -i 1 -t 14 -p 5001 -l 512
+```

+ 1 - 1
examples/openthread/ot_cli/main/CMakeLists.txt

@@ -1,7 +1,7 @@
 set(srcs "esp_ot_cli.c")
 
 if(CONFIG_OPENTHREAD_CLI_ESP_EXTENSION)
-    list(APPEND srcs "esp_ot_cli_extension.c" "esp_ot_tcp_socket.c" "esp_ot_udp_socket.c")
+    list(APPEND srcs "esp_ot_cli_extension.c" "esp_ot_tcp_socket.c" "esp_ot_udp_socket.c" "esp_ot_iperf.c")
 endif()
 
 idf_component_register(SRCS "${srcs}"

+ 5 - 13
examples/openthread/ot_cli/main/esp_ot_cli.c

@@ -1,16 +1,8 @@
-// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+*/
 
 #include <stdio.h>
 #include <unistd.h>

+ 7 - 13
examples/openthread/ot_cli/main/esp_ot_cli_extension.c

@@ -1,19 +1,12 @@
-// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+*/
 
 #include "esp_openthread.h"
 #include "esp_ot_cli_extension.h"
+#include "esp_ot_iperf.h"
 #include "esp_ot_tcp_socket.h"
 #include "esp_ot_udp_socket.h"
 #include "freertos/FreeRTOS.h"
@@ -26,6 +19,7 @@ static const otCliCommand kCommands[] = {
     {"tcpsockclient", esp_ot_process_tcp_client},
     {"udpsockserver", esp_ot_process_udp_server},
     {"udpsockclient", esp_ot_process_udp_client},
+    {"iperf", esp_ot_process_iperf}
 };
 
 void esp_cli_custom_command_init()

+ 6 - 14
examples/openthread/ot_cli/main/esp_ot_cli_extension.h

@@ -1,18 +1,10 @@
-// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-#pragma once
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+*/
 
+#pragma once
 #ifdef __cplusplus
 extern "C" {
 #endif

+ 5 - 13
examples/openthread/ot_cli/main/esp_ot_config.h

@@ -1,16 +1,8 @@
-// Copyright 2021 Espressif Systems (Shanghai) CO LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+*/
 
 #pragma once
 

+ 98 - 0
examples/openthread/ot_cli/main/esp_ot_iperf.c

@@ -0,0 +1,98 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+*/
+
+#include "esp_check.h"
+#include "esp_log.h"
+#include "esp_ot_iperf.h"
+#include "iperf.h"
+#include "openthread/cli.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define TAG "ot-iperf"
+
+void esp_ot_process_iperf(void *aContext, uint8_t aArgsLength, char *aArgs[])
+{
+    (void)(aContext);
+    (void)(aArgsLength);
+    iperf_cfg_t cfg;
+    memset(&cfg, 0, sizeof(cfg));
+    // set iperf default flag: tcp server
+    IPERF_FLAG_SET(cfg.flag, IPERF_FLAG_TCP);
+    IPERF_FLAG_SET(cfg.flag, IPERF_FLAG_SERVER);
+    cfg.time = IPERF_DEFAULT_TIME;
+    cfg.type = IPERF_IP_TYPE_IPV4;
+    if (aArgsLength == 0) {
+        otCliOutputFormat("---iperf parameter---\n");
+        otCliOutputFormat("-V                  :     use IPV6 address\n");
+        otCliOutputFormat("-s                  :     server mode, only receive\n");
+        otCliOutputFormat("-u                  :     upd mode\n");
+        otCliOutputFormat("-c <addr>           :     client mode, only transmit\n");
+        otCliOutputFormat("-i <interval>       :     seconds between periodic bandwidth reports\n");
+        otCliOutputFormat("-t <time>           :     time in seconds to transmit for (default 30 secs)\n");
+        otCliOutputFormat("-p <port>           :     server port to listen on/connect to\n");
+        otCliOutputFormat("-l <len_send_buf>   :     the lenth of send buffer\n");
+        otCliOutputFormat("---example---\n");
+        otCliOutputFormat("create a tcp server :     iperf -s -i 3 -p 5001 -t 60\n");
+        otCliOutputFormat("create a udp client :     iperf -c <addr> -u -i 3 -t 60 -p 5001 -l 512\n");
+    } else {
+        for (int i = 0; i < aArgsLength; i++) {
+            if (strcmp(aArgs[i], "-c") == 0) {
+                IPERF_FLAG_SET(cfg.flag, IPERF_FLAG_CLIENT);
+                IPERF_FLAG_CLR(cfg.flag, IPERF_FLAG_SERVER);
+                i++;
+                cfg.destination_ip6 = aArgs[i];
+                otCliOutputFormat("ip:%s\n", cfg.destination_ip6);
+            } else if (strcmp(aArgs[i], "-s") == 0) {
+                IPERF_FLAG_SET(cfg.flag, IPERF_FLAG_SERVER);
+                IPERF_FLAG_CLR(cfg.flag, IPERF_FLAG_CLIENT);
+            } else if (strcmp(aArgs[i], "-V") == 0) {
+                cfg.type = IPERF_IP_TYPE_IPV6;
+            } else if (strcmp(aArgs[i], "-u") == 0) {
+                IPERF_FLAG_SET(cfg.flag, IPERF_FLAG_UDP);
+                IPERF_FLAG_CLR(cfg.flag, IPERF_FLAG_TCP);
+            } else if (strcmp(aArgs[i], "-p") == 0) {
+                i++;
+                if (cfg.flag & IPERF_FLAG_SERVER) {
+                    cfg.sport = atoi(aArgs[i]);
+                    cfg.dport = IPERF_DEFAULT_PORT;
+                } else {
+                    cfg.sport = IPERF_DEFAULT_PORT;
+                    cfg.dport = atoi(aArgs[i]);
+                }
+                otCliOutputFormat("dp:%d\n", cfg.dport);
+                otCliOutputFormat("sp:%d\n", cfg.sport);
+            } else if (strcmp(aArgs[i], "-i") == 0) {
+                i++;
+                if (atoi(aArgs[i]) < 0) {
+                    cfg.interval = IPERF_DEFAULT_INTERVAL;
+                } else {
+                    cfg.interval = atoi(aArgs[i]);
+                }
+                otCliOutputFormat("i:%d\n", cfg.interval);
+            } else if (strcmp(aArgs[i], "-t") == 0) {
+                i++;
+                cfg.time = atoi(aArgs[i]);
+                if (cfg.time <= cfg.interval) {
+                    cfg.time = cfg.interval;
+                }
+                otCliOutputFormat("t:%d\n", cfg.time);
+            } else if (strcmp(aArgs[i], "-l") == 0) {
+                i++;
+                if (atoi(aArgs[i]) <= 0) {
+                    ESP_LOGE(TAG, "Invalid arguments.");
+                } else {
+                    cfg.len_send_buf = atoi(aArgs[i]);
+                }
+            } else if (strcmp(aArgs[i], "-a") == 0) {
+                iperf_stop();
+                return;
+            }
+        }
+        iperf_start(&cfg);
+    }
+}

+ 20 - 0
examples/openthread/ot_cli/main/esp_ot_iperf.h

@@ -0,0 +1,20 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ * @brief User command "iperf" process.
+ *
+ */
+void esp_ot_process_iperf(void *aContext, uint8_t aArgsLength, char *aArgs[]);
+
+#ifdef __cplusplus
+}
+#endif

+ 7 - 15
examples/openthread/ot_cli/main/esp_ot_tcp_socket.c

@@ -1,16 +1,8 @@
-// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+*/
 
 #include "esp_check.h"
 #include "esp_err.h"
@@ -32,7 +24,7 @@ static void tcp_socket_server_task(void *pvParameters)
     int opt = 1;
     int port = CONFIG_OPENTHREAD_CLI_TCP_SERVER_PORT;
     int client_sock = 0;
-    struct timeval timeout;
+    struct timeval timeout = { 0 };
     struct sockaddr_storage source_addr; // Large enough for both IPv6
     struct sockaddr_in6 listen_addr = { 0 };
     // The TCP server listen at the address "::", which means all addresses can be listened to.
@@ -154,7 +146,7 @@ void esp_ot_process_tcp_client(void *aContext, uint8_t aArgsLength, char *aArgs[
 {
     (void)(aContext);
     (void)(aArgsLength);
-    if (aArgs[0] == NULL) {
+    if (aArgsLength == 0) {
         ESP_LOGE(TAG, "Invalid arguments.");
     } else {
         xTaskCreate(tcp_socket_client_task, "ot_tcp_socket_client", 4096, aArgs[0], 4, NULL);

+ 5 - 13
examples/openthread/ot_cli/main/esp_ot_tcp_socket.h

@@ -1,16 +1,8 @@
-// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+*/
 
 #pragma once
 

+ 10 - 17
examples/openthread/ot_cli/main/esp_ot_udp_socket.c

@@ -1,16 +1,8 @@
-// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+*/
 
 #include "esp_check.h"
 #include "esp_err.h"
@@ -30,8 +22,9 @@ static void udp_socket_server_task(void *pvParameters)
     int err = 0;
     int len;
     int listen_sock;
+
     int port = CONFIG_OPENTHREAD_CLI_UDP_SERVER_PORT;
-    struct timeval timeout;
+    struct timeval timeout = { 0 };
     struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6
     struct sockaddr_in6 listen_addr;
 
@@ -39,7 +32,7 @@ static void udp_socket_server_task(void *pvParameters)
     listen_addr.sin6_family = AF_INET6;
     listen_addr.sin6_port = htons(port);
 
-    listen_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IPV6);
+    listen_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
     ESP_GOTO_ON_FALSE((listen_sock >= 0), ESP_OK, exit, TAG, "Unable to create socket: errno %d", errno);
     ESP_LOGI(TAG, "Socket created");
 
@@ -98,7 +91,7 @@ static void udp_socket_client_task(void *pvParameters)
     dest_addr.sin6_family = AF_INET6;
     dest_addr.sin6_port = htons(port);
 
-    client_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IPV6);
+    client_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
     ESP_GOTO_ON_FALSE((client_sock >= 0), ESP_OK, exit, TAG, "Unable to create socket: errno %d", errno);
     ESP_LOGI(TAG, "Socket created, sending to %s:%d", host_ip, port);
 
@@ -135,7 +128,7 @@ void esp_ot_process_udp_client(void *aContext, uint8_t aArgsLength, char *aArgs[
 {
     (void)(aContext);
     (void)(aArgsLength);
-    if (aArgs[0] == NULL) {
+    if (aArgsLength == 0) {
         ESP_LOGE(TAG, "Invalid arguments.");
     } else {
         xTaskCreate(udp_socket_client_task, "ot_udp_socket_client", 4096, aArgs[0], 4, NULL);

+ 5 - 13
examples/openthread/ot_cli/main/esp_ot_udp_socket.h

@@ -1,16 +1,8 @@
-// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+*/
 
 #pragma once
 

+ 1 - 0
examples/openthread/ot_cli/sdkconfig.defaults

@@ -35,6 +35,7 @@ CONFIG_OPENTHREAD_ENABLED=y
 #
 # lwIP
 #
+CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096
 CONFIG_LWIP_IPV6_NUM_ADDRESSES=8
 CONFIG_LWIP_MULTICAST_PING=y
 # end of lwIP

+ 66 - 51
examples/wifi/iperf/main/cmd_wifi.c

@@ -24,7 +24,9 @@ typedef struct {
     struct arg_str *ip;
     struct arg_lit *server;
     struct arg_lit *udp;
+    struct arg_lit *version;
     struct arg_int *port;
+    struct arg_int *length;
     struct arg_int *interval;
     struct arg_int *time;
     struct arg_lit *abort;
@@ -47,7 +49,7 @@ static wifi_args_t sta_args;
 static wifi_scan_arg_t scan_args;
 static wifi_args_t ap_args;
 static bool reconnect = true;
-static const char *TAG="cmd_wifi";
+static const char *TAG = "cmd_wifi";
 static esp_netif_t *netif_ap = NULL;
 static esp_netif_t *netif_sta = NULL;
 
@@ -55,8 +57,8 @@ static EventGroupHandle_t wifi_event_group;
 const int CONNECTED_BIT = BIT0;
 const int DISCONNECTED_BIT = BIT1;
 
-static void scan_done_handler(void* arg, esp_event_base_t event_base,
-                              int32_t event_id, void* event_data)
+static void scan_done_handler(void *arg, esp_event_base_t event_base,
+                              int32_t event_id, void *event_data)
 {
     uint16_t sta_number = 0;
     uint8_t i;
@@ -74,8 +76,8 @@ static void scan_done_handler(void* arg, esp_event_base_t event_base,
         return;
     }
 
-    if (esp_wifi_scan_get_ap_records(&sta_number,(wifi_ap_record_t *)ap_list_buffer) == ESP_OK) {
-        for(i=0; i<sta_number; i++) {
+    if (esp_wifi_scan_get_ap_records(&sta_number, (wifi_ap_record_t *)ap_list_buffer) == ESP_OK) {
+        for (i = 0; i < sta_number; i++) {
             ESP_LOGI(TAG, "[%s][rssi=%d]", ap_list_buffer[i].ssid, ap_list_buffer[i].rssi);
         }
     }
@@ -83,15 +85,15 @@ static void scan_done_handler(void* arg, esp_event_base_t event_base,
     ESP_LOGI(TAG, "sta scan done");
 }
 
-static void got_ip_handler(void* arg, esp_event_base_t event_base,
-                           int32_t event_id, void* event_data)
+static void got_ip_handler(void *arg, esp_event_base_t event_base,
+                           int32_t event_id, void *event_data)
 {
     xEventGroupClearBits(wifi_event_group, DISCONNECTED_BIT);
     xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
 }
 
-static void disconnect_handler(void* arg, esp_event_base_t event_base,
-                               int32_t event_id, void* event_data)
+static void disconnect_handler(void *arg, esp_event_base_t event_base,
+                               int32_t event_id, void *event_data)
 {
     if (reconnect) {
         ESP_LOGI(TAG, "sta disconnect, reconnect...");
@@ -123,36 +125,36 @@ void initialise_wifi(void)
     wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
     ESP_ERROR_CHECK(esp_wifi_init(&cfg));
     ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
-                                                        WIFI_EVENT_SCAN_DONE,
-                                                        &scan_done_handler,
-                                                        NULL,
-                                                        NULL));
+                    WIFI_EVENT_SCAN_DONE,
+                    &scan_done_handler,
+                    NULL,
+                    NULL));
     ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
-                                                        WIFI_EVENT_STA_DISCONNECTED,
-                                                        &disconnect_handler,
-                                                        NULL,
-                                                        NULL));
+                    WIFI_EVENT_STA_DISCONNECTED,
+                    &disconnect_handler,
+                    NULL,
+                    NULL));
     ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
-                                                        IP_EVENT_STA_GOT_IP,
-                                                        &got_ip_handler,
-                                                        NULL,
-                                                        NULL));
+                    IP_EVENT_STA_GOT_IP,
+                    &got_ip_handler,
+                    NULL,
+                    NULL));
     ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM) );
     ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL) );
     ESP_ERROR_CHECK(esp_wifi_start() );
     initialized = true;
 }
 
-static bool wifi_cmd_sta_join(const char* ssid, const char* pass)
+static bool wifi_cmd_sta_join(const char *ssid, const char *pass)
 {
     int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 0);
 
     wifi_config_t wifi_config = { 0 };
     wifi_config.sta.pmf_cfg.capable = true;
 
-    strlcpy((char*) wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid));
+    strlcpy((char *) wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid));
     if (pass) {
-        strlcpy((char*) wifi_config.sta.password, pass, sizeof(wifi_config.sta.password));
+        strlcpy((char *) wifi_config.sta.password, pass, sizeof(wifi_config.sta.password));
     }
 
     if (bits & CONNECTED_BIT) {
@@ -167,14 +169,14 @@ static bool wifi_cmd_sta_join(const char* ssid, const char* pass)
     ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
     esp_wifi_connect();
 
-    xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 5000/portTICK_RATE_MS);
+    xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 5000 / portTICK_RATE_MS);
 
     return true;
 }
 
-static int wifi_cmd_sta(int argc, char** argv)
+static int wifi_cmd_sta(int argc, char **argv)
 {
-    int nerrors = arg_parse(argc, argv, (void**) &sta_args);
+    int nerrors = arg_parse(argc, argv, (void **) &sta_args);
 
     if (nerrors != 0) {
         arg_print_errors(stderr, sta_args.end, argv[0]);
@@ -186,7 +188,7 @@ static int wifi_cmd_sta(int argc, char** argv)
     return 0;
 }
 
-static bool wifi_cmd_sta_scan(const char* ssid)
+static bool wifi_cmd_sta_scan(const char *ssid)
 {
     wifi_scan_config_t scan_config = { 0 };
     scan_config.ssid = (uint8_t *) ssid;
@@ -197,9 +199,9 @@ static bool wifi_cmd_sta_scan(const char* ssid)
     return true;
 }
 
-static int wifi_cmd_scan(int argc, char** argv)
+static int wifi_cmd_scan(int argc, char **argv)
 {
-    int nerrors = arg_parse(argc, argv, (void**) &scan_args);
+    int nerrors = arg_parse(argc, argv, (void **) &scan_args);
 
     if (nerrors != 0) {
         arg_print_errors(stderr, scan_args.end, argv[0]);
@@ -216,7 +218,7 @@ static int wifi_cmd_scan(int argc, char** argv)
 }
 
 
-static bool wifi_cmd_ap_set(const char* ssid, const char* pass)
+static bool wifi_cmd_ap_set(const char *ssid, const char *pass)
 {
     wifi_config_t wifi_config = {
         .ap = {
@@ -229,14 +231,14 @@ static bool wifi_cmd_ap_set(const char* ssid, const char* pass)
     };
 
     reconnect = false;
-    strlcpy((char*) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid));
+    strlcpy((char *) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid));
     if (pass) {
         if (strlen(pass) != 0 && strlen(pass) < 8) {
             reconnect = true;
             ESP_LOGE(TAG, "password less than 8");
             return false;
         }
-        strlcpy((char*) wifi_config.ap.password, pass, sizeof(wifi_config.ap.password));
+        strlcpy((char *) wifi_config.ap.password, pass, sizeof(wifi_config.ap.password));
     }
 
     if (strlen(pass) == 0) {
@@ -248,9 +250,9 @@ static bool wifi_cmd_ap_set(const char* ssid, const char* pass)
     return true;
 }
 
-static int wifi_cmd_ap(int argc, char** argv)
+static int wifi_cmd_ap(int argc, char **argv)
 {
-    int nerrors = arg_parse(argc, argv, (void**) &ap_args);
+    int nerrors = arg_parse(argc, argv, (void **) &ap_args);
 
     if (nerrors != 0) {
         arg_print_errors(stderr, ap_args.end, argv[0]);
@@ -262,7 +264,7 @@ static int wifi_cmd_ap(int argc, char** argv)
     return 0;
 }
 
-static int wifi_cmd_query(int argc, char** argv)
+static int wifi_cmd_query(int argc, char **argv)
 {
     wifi_config_t cfg;
     wifi_mode_t mode;
@@ -290,7 +292,7 @@ static int wifi_cmd_query(int argc, char** argv)
 static uint32_t wifi_get_local_ip(void)
 {
     int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 0);
-    esp_netif_t * netif = netif_ap;
+    esp_netif_t *netif = netif_ap;
     esp_netif_ip_info_t ip_info;
     wifi_mode_t mode;
 
@@ -303,15 +305,15 @@ static uint32_t wifi_get_local_ip(void)
             ESP_LOGE(TAG, "sta has no IP");
             return 0;
         }
-     }
+    }
 
-     esp_netif_get_ip_info(netif, &ip_info);
-     return ip_info.ip.addr;
+    esp_netif_get_ip_info(netif, &ip_info);
+    return ip_info.ip.addr;
 }
 
-static int wifi_cmd_iperf(int argc, char** argv)
+static int wifi_cmd_iperf(int argc, char **argv)
 {
-    int nerrors = arg_parse(argc, argv, (void**) &iperf_args);
+    int nerrors = arg_parse(argc, argv, (void **) &iperf_args);
     iperf_cfg_t cfg;
 
     if (nerrors != 0) {
@@ -321,13 +323,16 @@ static int wifi_cmd_iperf(int argc, char** argv)
 
     memset(&cfg, 0, sizeof(cfg));
 
+    // now wifi iperf only support IPV4 address
+    cfg.type = IPERF_IP_TYPE_IPV4;
+
     if ( iperf_args.abort->count != 0) {
         iperf_stop();
         return 0;
     }
 
     if ( ((iperf_args.ip->count == 0) && (iperf_args.server->count == 0)) ||
-         ((iperf_args.ip->count != 0) && (iperf_args.server->count != 0)) ) {
+            ((iperf_args.ip->count != 0) && (iperf_args.server->count != 0)) ) {
         ESP_LOGE(TAG, "should specific client/server mode");
         return 0;
     }
@@ -335,12 +340,12 @@ static int wifi_cmd_iperf(int argc, char** argv)
     if (iperf_args.ip->count == 0) {
         cfg.flag |= IPERF_FLAG_SERVER;
     } else {
-        cfg.dip = esp_ip4addr_aton(iperf_args.ip->sval[0]);
+        cfg.destination_ip4 = esp_ip4addr_aton(iperf_args.ip->sval[0]);
         cfg.flag |= IPERF_FLAG_CLIENT;
     }
 
-    cfg.sip = wifi_get_local_ip();
-    if (cfg.sip == 0) {
+    cfg.source_ip4 = wifi_get_local_ip();
+    if (cfg.source_ip4 == 0) {
         return 0;
     }
 
@@ -350,6 +355,12 @@ static int wifi_cmd_iperf(int argc, char** argv)
         cfg.flag |= IPERF_FLAG_UDP;
     }
 
+    if (iperf_args.length->count == 0) {
+        cfg.len_send_buf = 0;
+    } else {
+        cfg.len_send_buf = iperf_args.length->ival[0];
+    }
+
     if (iperf_args.port->count == 0) {
         cfg.sport = IPERF_DEFAULT_PORT;
         cfg.dport = IPERF_DEFAULT_PORT;
@@ -382,11 +393,13 @@ static int wifi_cmd_iperf(int argc, char** argv)
     }
 
     ESP_LOGI(TAG, "mode=%s-%s sip=%d.%d.%d.%d:%d, dip=%d.%d.%d.%d:%d, interval=%d, time=%d",
-            cfg.flag&IPERF_FLAG_TCP?"tcp":"udp",
-            cfg.flag&IPERF_FLAG_SERVER?"server":"client",
-            cfg.sip&0xFF, (cfg.sip>>8)&0xFF, (cfg.sip>>16)&0xFF, (cfg.sip>>24)&0xFF, cfg.sport,
-            cfg.dip&0xFF, (cfg.dip>>8)&0xFF, (cfg.dip>>16)&0xFF, (cfg.dip>>24)&0xFF, cfg.dport,
-            cfg.interval, cfg.time);
+             cfg.flag & IPERF_FLAG_TCP ? "tcp" : "udp",
+             cfg.flag & IPERF_FLAG_SERVER ? "server" : "client",
+             cfg.source_ip4 & 0xFF, (cfg.source_ip4 >> 8) & 0xFF, (cfg.source_ip4 >> 16) & 0xFF,
+             (cfg.source_ip4 >> 24) & 0xFF, cfg.sport,
+             cfg.destination_ip4 & 0xFF, (cfg.destination_ip4 >> 8) & 0xFF,
+             (cfg.destination_ip4 >> 16) & 0xFF, (cfg.destination_ip4 >> 24) & 0xFF, cfg.dport,
+             cfg.interval, cfg.time);
 
     iperf_start(&cfg);
 
@@ -448,7 +461,9 @@ void register_wifi(void)
     iperf_args.ip = arg_str0("c", "client", "<ip>", "run in client mode, connecting to <host>");
     iperf_args.server = arg_lit0("s", "server", "run in server mode");
     iperf_args.udp = arg_lit0("u", "udp", "use UDP rather than TCP");
+    iperf_args.version = arg_lit0("V", "ipv6_domain", "use IPV6 address rather than IPV4");
     iperf_args.port = arg_int0("p", "port", "<port>", "server port to listen on/connect to");
+    iperf_args.length = arg_int0("l", "len", "<length>", "Set read/write buffer size");
     iperf_args.interval = arg_int0("i", "interval", "<interval>", "seconds between periodic bandwidth reports");
     iperf_args.time = arg_int0("t", "time", "<time>", "time in seconds to transmit for (default 10 secs)");
     iperf_args.abort = arg_lit0("a", "abort", "abort running iperf");