/*
 * Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
 * Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 *    conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 *    of conditions and the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "../core/ipv4/etharp.c"  /* for arp_table */
#define icmp6_hdr netinet_icmp6_hdr
#include <netinet/icmp6.h>
#undef icmp6_hdr
#include "lwip/fixme.h"
#include "lwip/opt.h"

#if LWIP_ENABLE_LOS_SHELL_CMD
#include "lwip/api.h"
#include "lwip/tcpip.h"
#include "lwip/netif.h"
#include "lwip/netdb.h"
#include "lwip/stats.h"
#include "lwip/err.h"
#include "lwip/inet.h"
#include "netif/etharp.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#include "lwip/icmp.h"
#include "lwip/priv/nd6_priv.h"
#include "lwip/sockets.h"
#include "lwip/inet_chksum.h"
#include "lwip/raw.h"
#include "los_config.h"
#include <string.h>
#include "limits.h"
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
#include <ctype.h>
#include <poll.h>

#include "lwip/api_shell.h"
#include "lwip/tftpc.h"

#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "lwip/udp.h"
#include "lwip/priv/tcp_priv.h"

#include "lwip/dhcp.h"
#include "lwip/netifapi.h"
#include "los_strnlen_user.h"
#include "linux/kernel.h"
#ifdef LOSCFG_SHELL
#include "shcmd.h"
#include "shell.h"
#endif

#define LWIP_STATIC static

#if LWIP_ARP
extern sys_sem_t ip_conflict_detect;
#endif
extern volatile int tcpip_init_finish;
extern const char *const tcp_state_str[];
extern int get_unused_socket_num(void);

#if LWIP_IPV6
#define LWIP_MAX_PING6_ARG_COUNT              64
#define LWIP_PING6_STANDARD_PKT_SIZE          56
#define LWIP_PING6_STARTING_SEQ_NUM           0x2255
#define LWIP_PING6_OUT_OF_ORDER_MAGNITUDE     1

#define LWIP_PING6_COUNT_ARG           1
#define LWIP_PING6_SOURCE_ADDRESS_ARG  2
#define LWIP_PING6_INTERFACE_ARG       4
#define LWIP_PING6_HOSTNAME_ARG        8
#define LWIP_PING6_DEFAULT_SOCKET      16
#endif

/* Forward Declarations [START] */
#ifndef LWIP_TESTBED
LWIP_STATIC
#endif
int print_netif(struct netif *netif, char *print_buf, unsigned int buf_len);

#ifndef LWIP_TESTBED
LWIP_STATIC
#endif
void lwip_ifconfig_show_internal(void *arg);

#ifndef LWIP_TESTBED
LWIP_STATIC
#endif
void lwip_ifconfig_internal(void *arg);

void lwip_printsize(size_t size);
LWIP_STATIC void lwip_ifconfig_usage(const char *cmd);

#ifndef LWIP_TESTBED
LWIP_STATIC
#endif
void lwip_arp_show_internal(struct netif *netif, char *printf_buf, unsigned int buf_len);

#ifndef LWIP_TESTBED
LWIP_STATIC
#endif
void lwip_arp_internal(void *arg);

LWIP_STATIC void lwip_arp_usage(const char *cmd);
void ifup_internal(void *arg);
void ifdown_internal(void *arg);

#if LWIP_DNS
LWIP_STATIC unsigned int get_hostip(const char *hname);

#ifndef LWIP_TESTBED
LWIP_STATIC
#endif
struct hostent *gethostnameinfo(const char *host);

#endif /* LWIP_DNS */

#ifdef LWIP_DEBUG_INFO
LWIP_STATIC u32_t netdebug_memp(int argc, const char **argv);
LWIP_STATIC u32_t netdebug_sock(int argc, const char **argv);
u32_t osShellNetDebug(int argc, const char **argv);
u32_t osShellIpDebug(int argc, const char **argv);
#endif /* LWIP_DEBUG_INFO */
#if LWIP_IPV6
/* Holds params for ping6 task */
typedef struct ping6_args {
    u8_t args_found;
    u8_t interface_index;
    u8_t host_index;
    u8_t pad;
    u32_t pingcount;
    ip6_addr_t src_addr;
    ip6_addr_t dst_addr;
} ping6_args_t;

/* Holds stats for ongoing ping6 task */
typedef struct ping6_stats {
    u32_t flag;
    u32_t min_rtt;
    u32_t max_rtt;
    float avg_rtt;
} ping6_stats_t;
LWIP_STATIC void update_ping6_stats(ping6_stats_t *ping6_stats, u32_t rtt, u32_t nrecieved);
LWIP_STATIC int parse_args_ping6(int argc, const char **argv, ping6_args_t *ping6_params);

u32_t osShellPing6(int argc, const char **argv);
LWIP_STATIC int create_ping6_socket(u8_t type, const void *param);
LWIP_STATIC const char *convert_icmpv6_err_to_string(u8_t err_type);
#endif /* LWIP_IPV6 */
u32_t osTcpserver(int argc, const char **argv);
void udpserver(int argc, const char **argv);
void tcp_access(int sockfd);
#if LWIP_IPV6
int netstat_get_udp_sendQLen6(struct udp_pcb *udppcb, struct pbuf *udpbuf);
int netstat_udp_sendq6(struct udp_pcb *upcb);
#endif
#if LWIP_IPV4
int netstat_get_udp_sendQLen(struct udp_pcb *udppcb, struct pbuf *udpbuf);
#endif
int netstat_tcp_sendq(struct tcp_pcb *tpcb);
int netstat_tcp_recvq(struct tcp_pcb *tpcb);
int netstat_netconn_recvq(const struct netconn *conn);

int netstat_udp_sendq(struct udp_pcb *upcb);
int netstat_netconn_sendq(struct netconn *conn);
/* Forward Declarations [END] */

#define IFCONFIG_OPTION_SET_IP          (1)
#define IFCONFIG_OPTION_SET_NETMASK     (1 << 1)
#define IFCONFIG_OPTION_SET_GW          (1 << 2)
#define IFCONFIG_OPTION_SET_HW          (1 << 3)
#define IFCONFIG_OPTION_SET_UP          (1 << 4)
#define IFCONFIG_OPTION_SET_DOWN        (1 << 5)
#define IFCONFIG_OPTION_SET_MTU         (1 << 6)
#define IFCONFIG_OPTION_DEL_IP          (1 << 7)

#define NETSTAT_ENTRY_SIZE 120
#define MAX_NETSTAT_ENTRY (NETSTAT_ENTRY_SIZE * (MEMP_NUM_TCP_PCB + MEMP_NUM_UDP_PCB + MEMP_NUM_TCP_PCB_LISTEN + 1))

#define PRINT_BUF_LEN   1024
#define MAX_MACADDR_STRING_LENGTH    18 /* including NULL */

#define CONVERT_STRING_TO_HEX(_src, _dest)                                                      \
{                                                                                               \
    const char *_srcString = (char *)_src;                                                      \
    _dest = 0;                                                                                  \
    while (*_srcString) {                                                                       \
        _dest = (unsigned char)((_dest << 4) & 0xFF);                                           \
        if ((*_srcString >= 48) && (*_srcString <= 57))    /* between 0 to 9 */                 \
            _dest |= (unsigned char)(*_srcString - 48);                                         \
        else if ((*_srcString >= 65 && *_srcString <= 70)) /* between A to F */                 \
            _dest |= (unsigned char)((*_srcString - 65) + 10);                                  \
        else if ((*_srcString >= 97 && *_srcString <= 102)) /* between a to f */                \
            _dest |= (unsigned char)((*_srcString - 97) + 10);                                  \
        else break;                                                                             \
        ++_srcString;                                                                           \
    }                                                                                           \
}

#define ERR_IFCONFIG_STRING_PUT(ret, str)                                                       \
    do {                                                                                        \
        (ret) = snprintf_s(ifconfig_cmd->cb_print_buf + ifconfig_cmd->print_len,                \
                           PRINT_BUF_LEN - ifconfig_cmd->print_len,                             \
                           ((PRINT_BUF_LEN - ifconfig_cmd->print_len) - 1), (str));             \
        if (((ret) > 0) && ((unsigned int)(ret) < (PRINT_BUF_LEN - ifconfig_cmd->print_len)))   \
            ifconfig_cmd->print_len += (unsigned int)(ret);                                     \
    } while (0)                                                                                 \

#define LWIP_MSECS_TO_SECS(time_in_msecs) (time_in_msecs / 1000)
struct ifconfig_option {
    char iface[IFNAMSIZ];
    unsigned int option;
    ip_addr_t ip_addr;
    ip_addr_t netmask;
    ip_addr_t gw;
    unsigned char ethaddr[6];
    u16_t mtu;
    /* when using telnet, print to the telnet socket will result in system  */
    /* deadlock. So we cahe the prinf data to a buf, and when the tcpip      */
    /* callback returns, then print the data out to the telnet socket       */
    sys_sem_t cb_completed;
    char cb_print_buf[PRINT_BUF_LEN];
    unsigned int print_len;
};

struct netstat_data {
    s8_t *netstat_out_buf;
    u32_t netstat_out_buf_len;
    u32_t netstat_out_buf_updated_len;
    sys_sem_t cb_completed;
};

struct if_cmd_data {
    char *if_name;
    err_t err;
    sys_sem_t cb_completed;
};

#ifndef LWIP_TESTBED
LWIP_STATIC
#endif
int print_netif(struct netif *netif, char *print_buf, unsigned int buf_len)
{
    int i, ret;
    char *tmp = print_buf;
#if LWIP_IPV6
    char *addr = NULL;
#endif

    if (netif->link_layer_type == LOOPBACK_IF) {
        ret = snprintf_s(tmp, buf_len, (buf_len - 1), "%.2s\t", netif->name);
    } else {
        ret = snprintf_s(tmp, buf_len, (buf_len - 1), "%s\t", netif_get_name(netif));
    }
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
        goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;
#if LWIP_IPV4
    ret = snprintf_s(tmp, buf_len, (buf_len - 1), "ip:%s ", ipaddr_ntoa(&netif->ip_addr));
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
        goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    ret = snprintf_s(tmp, buf_len, (buf_len - 1), "netmask:%s ", ipaddr_ntoa(&netif->netmask));
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
        goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    ret = snprintf_s(tmp, buf_len, (buf_len - 1), "gateway:%s\n", ipaddr_ntoa(&netif->gw));
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
        goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;
#endif

#if LWIP_IPV6
    for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
        /* only PREFERRED addresses are displyaed */
        if (!ip6_addr_isvalid(netif->ip6_addr_state[i])) {
            continue;
        }
        addr = ip6addr_ntoa((const ip6_addr_t *)&netif->ip6_addr[i]);
        ret = snprintf_s(tmp, buf_len, (buf_len - 1), "\tip6: %s/64\n", addr ? addr : "::");
        if ((ret <= 0) || ((unsigned int)ret >= buf_len))
            goto out;
        tmp += ret;
        buf_len -= (unsigned int)ret;
    }
#endif

    ret = snprintf_s(tmp, buf_len, (buf_len - 1), "\tHWaddr ");
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
        goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    for (i = 0; i < netif->hwaddr_len - 1; i++) {
        ret = snprintf_s(tmp, buf_len, (buf_len - 1), "%02x:", netif->hwaddr[i]);
        if ((ret <= 0) || ((unsigned int)ret >= buf_len))
            goto out;
        tmp += ret;
        buf_len -= (unsigned int)ret;
    }

    ret = snprintf_s(tmp, buf_len, (buf_len - 1), "%02x", netif->hwaddr[i]);
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
        goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    ret = snprintf_s(tmp, buf_len, (buf_len - 1), " MTU:%d %s", netif->mtu,
                     netif->flags & NETIF_FLAG_UP ? "Running" : "Stop");
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
        goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    if (netif_default == netif && netif_is_up(netif)) {
        ret = snprintf_s(tmp, buf_len, (buf_len - 1), " %s", "Default");
        if ((ret <= 0) || ((unsigned int)ret >= buf_len))
            goto out;
        tmp += ret;
        buf_len -= (unsigned int)ret;
    }

    ret = snprintf_s(tmp, buf_len, (buf_len - 1), " %s\n", netif->flags & NETIF_FLAG_LINK_UP ? "Link UP" : "Link Down");
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
        goto out;
    tmp += ret;

#if MIB2_STATS
    ret = snprintf_s(tmp, buf_len, (buf_len - 1), "\tRX packets:%u ",
                     netif->mib2_counters.ifinucastpkts + netif->mib2_counters.ifinnucastpkts);
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
      goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    ret = snprintf_s(tmp, buf_len, (buf_len - 1), "errors:%u ", netif->mib2_counters.ifinerrors);
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
      goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    ret = snprintf_s(tmp, buf_len, (buf_len - 1), "dropped:%u ", netif->mib2_counters.ifindiscards);
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
      goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    ret = snprintf_s(tmp, buf_len, (buf_len - 1), "overruns:%u\n", netif->mib2_counters.ifinoverruns);
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
      goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    ret = snprintf_s(tmp, buf_len, (buf_len - 1), "\tTX packets:%u ",
                     netif->mib2_counters.ifoutucastpkts + netif->mib2_counters.ifoutnucastpkts);
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
      goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    ret = snprintf_s(tmp, buf_len, (buf_len - 1), "errors:%u ", netif->mib2_counters.ifouterrors);
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
      goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    ret = snprintf_s(tmp, buf_len, (buf_len - 1), "dropped:%u\n", netif->mib2_counters.ifoutdiscards);
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
      goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    ret = snprintf_s(tmp, buf_len, (buf_len - 1), "\tRX bytes:%u ", netif->mib2_counters.ifinoctets);
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
      goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    ret = snprintf_s(tmp, buf_len, (buf_len - 1), "TX bytes:%u\n", netif->mib2_counters.ifoutoctets);
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
      goto out;
    tmp += ret;
    buf_len -= (unsigned int)ret;
#endif

out:
    return (int)(tmp - print_buf);
}

#ifndef LWIP_TESTBED
LWIP_STATIC
#endif
void lwip_ifconfig_show_internal(void *arg)
{
    struct netif *netif = NULL;
    struct ifconfig_option *ifconfig_cmd = (struct ifconfig_option *)arg;
    int ret;

    if (netif_list == NULL) {
        ret = snprintf_s(ifconfig_cmd->cb_print_buf, PRINT_BUF_LEN - ifconfig_cmd->print_len,
                         ((PRINT_BUF_LEN - ifconfig_cmd->print_len) - 1), "Device not init\n");
        if ((ret > 0) && ((unsigned int)ret < (PRINT_BUF_LEN - ifconfig_cmd->print_len))) {
            ifconfig_cmd->print_len += (unsigned int)ret;
        }
        sys_sem_signal(&ifconfig_cmd->cb_completed);
        return;
    }

    if (ifconfig_cmd->iface[0] == '\0') {
        /* display all netif */
        for (netif = netif_list; netif != NULL; netif = netif->next) {
            ret = print_netif(netif, ifconfig_cmd->cb_print_buf + ifconfig_cmd->print_len,
                              PRINT_BUF_LEN - ifconfig_cmd->print_len);
            ifconfig_cmd->print_len += (unsigned int)ret;
        }
    } else {
        netif = netif_find(ifconfig_cmd->iface);
        if (netif == NULL) {
            ret = snprintf_s(ifconfig_cmd->cb_print_buf + ifconfig_cmd->print_len,
                             (PRINT_BUF_LEN - ifconfig_cmd->print_len),
                             ((PRINT_BUF_LEN - ifconfig_cmd->print_len) - 1), "Device not found\n");
            if ((ret > 0) && ((unsigned int)ret < (PRINT_BUF_LEN - ifconfig_cmd->print_len))) {
                ifconfig_cmd->print_len += (unsigned int)ret;
            }

            sys_sem_signal(&ifconfig_cmd->cb_completed);
            return;
        }

        ret = print_netif(netif, ifconfig_cmd->cb_print_buf + ifconfig_cmd->print_len,
                          PRINT_BUF_LEN - ifconfig_cmd->print_len);
        ifconfig_cmd->print_len += (unsigned int)ret;
    }
    sys_sem_signal(&ifconfig_cmd->cb_completed);
}

#ifndef LWIP_TESTBED
LWIP_STATIC
#endif
void lwip_ifconfig_internal(void *arg)
{
    struct ifconfig_option *ifconfig_cmd = NULL;
    struct netif *netif = NULL;
    ip_addr_t ip_addr;
    ip_addr_t netmask;
    ip_addr_t gw;
    unsigned short mtu;
    struct netif *loc_netif = NULL;
    int ret;
    s8_t idx;
    err_t err;

    ifconfig_cmd = (struct ifconfig_option *)arg;
    netif = netif_find(ifconfig_cmd->iface);
    if (netif == NULL) {
        ERR_IFCONFIG_STRING_PUT(ret, "Device not found\n");
        goto out;
    }

    if (ifconfig_cmd->option & IFCONFIG_OPTION_SET_UP) {
        (void)netif_set_up(netif);
        goto out;
    } else if (ifconfig_cmd->option & IFCONFIG_OPTION_SET_DOWN) {
        (void)netif_set_down(netif);
        goto out;
    }

    if ((ifconfig_cmd->option & IFCONFIG_OPTION_SET_IP) ||
        (ifconfig_cmd->option & IFCONFIG_OPTION_SET_NETMASK) ||
        (ifconfig_cmd->option & IFCONFIG_OPTION_SET_HW)) {
        (void)netif_set_down(netif);
    }

    if (ifconfig_cmd->option & IFCONFIG_OPTION_SET_IP) {
        ip_addr_set_val(&ip_addr, &(ifconfig_cmd->ip_addr));
        if (IP_IS_V4_VAL(ifconfig_cmd->ip_addr)) {
            /* check the address is not multicast/broadcast/0/loopback */
            if (ip_addr_ismulticast_val(&ip_addr) || ip_addr_isbroadcast_val(&ip_addr, netif) ||
                ip_addr_isany(&ip_addr) || ip_addr_isloopback(&ip_addr)) {
                ERR_IFCONFIG_STRING_PUT(ret, "Don't set ip as a multicast/broadcast/0/loopback address!\n");
                goto out;
            }

            /* reset gateway if new and previous ipaddr not in same net */
            if (!ip_addr_netcmp_val(&ip_addr, &netif->ip_addr, ip_2_ip4(&netif->netmask))) {
                ip_addr_set_zero(&netif->gw);
                if (netif == netif_default) {
                    (void)netif_set_default(NULL);
                }
            }

            /* lwip disallow two netif sit in same net at the same time */
            loc_netif = netif_list;
            while (loc_netif != NULL) {
                if (loc_netif == netif) {
                    loc_netif = loc_netif->next;
                    continue;
                }
                if (IP_IS_V4_VAL(ifconfig_cmd->ip_addr) && ip_addr_cmp(&netif->netmask, &loc_netif->netmask) &&
                    ip_addr_netcmp_val(&loc_netif->ip_addr, &ip_addr, ip_2_ip4(&netif->netmask))) {
                    ERR_IFCONFIG_STRING_PUT(ret, "Duplicate network!\n");
                    goto out;
                }
                loc_netif = loc_netif->next;
            }

#if LWIP_DHCP
            if (netif_dhcp_data(netif) && netif_dhcp_data(netif)->state != DHCP_STATE_OFF) {
                (void)netif_dhcp_off(netif);
            }
#endif
            netif_set_ipaddr(netif, ip_2_ip4(&ip_addr));
        } else if (IP_IS_V6_VAL(ifconfig_cmd->ip_addr)) {
            idx = -1;
            err = netif_add_ip6_address(netif, ip_2_ip6(&ip_addr), &idx);
            if (err != ERR_OK || idx == -1) {
                ERR_IFCONFIG_STRING_PUT(ret, "The IPv6 has reached the Global address limit, "
                                             "you should delete one address before add!\n");
                goto out;
            }
        }
    }

    if (ifconfig_cmd->option & IFCONFIG_OPTION_DEL_IP) {
        (void)netif_do_rmv_ipv6_addr(netif, &ifconfig_cmd->ip_addr);
    }

    if (ifconfig_cmd->option & IFCONFIG_OPTION_SET_NETMASK) {
        ip_addr_set_val(&netmask, &(ifconfig_cmd->netmask));
        /* check data valid */
        if (!ip_addr_netmask_valid(ip_2_ip4(&netmask))) {
            ERR_IFCONFIG_STRING_PUT(ret, "ifconfig: netmask is invalid!\n");
            goto out;
        }

#if LWIP_DHCP
        if (netif_dhcp_data(netif) && netif_dhcp_data(netif)->state != DHCP_STATE_OFF) {
            (void)netif_dhcp_off(netif);
        }
#endif
        if (netif_ip4_netmask(netif)->addr != ip_2_ip4(&netmask)->addr) {
            /* lwip disallow two netif sit in same net at the same time */
            loc_netif = netif_list;
            while (loc_netif != NULL) {
                if (loc_netif == netif) {
                    loc_netif = loc_netif->next;
                    continue;
                }
                if (ip_addr_cmp(&loc_netif->netmask, &netmask) &&
                    ip_addr_netcmp(&loc_netif->ip_addr, &netif->ip_addr, ip_2_ip4(&netmask))) {
                    ERR_IFCONFIG_STRING_PUT(ret, "Duplicate network!\n");
                    goto out;
                }
                loc_netif = loc_netif->next;
            }
            netif_set_netmask(netif, ip_2_ip4(&netmask));
            /* check if gateway still reachable */
            if (!ip_addr_netcmp(&netif->gw, &netif->ip_addr, ip_2_ip4(&netmask))) {
                ip_addr_set_zero(&(netif->gw));
                if (netif == netif_default) {
                    (void)netif_set_default(NULL);
                }
            }
        }
    }

    if ((ifconfig_cmd->option & IFCONFIG_OPTION_SET_HW) &&
        netif_set_hwaddr(netif, ifconfig_cmd->ethaddr, NETIF_MAX_HWADDR_LEN) != ERR_OK) {
        ERR_IFCONFIG_STRING_PUT(ret, "Failed to update the hwaddr of the device!\n");
        (void)netif_set_up(netif);
        goto out;
    }

    if ((ifconfig_cmd->option & IFCONFIG_OPTION_SET_IP) ||
        (ifconfig_cmd->option & IFCONFIG_OPTION_SET_NETMASK) ||
        (ifconfig_cmd->option & IFCONFIG_OPTION_SET_HW)) {
        (void)netif_set_up(netif);
    }

    if (ifconfig_cmd->option & IFCONFIG_OPTION_SET_GW) {
        ip_addr_set_val(&gw, &ifconfig_cmd->gw);

        /* check the address multicast/0/loopback */
        if (ip_addr_ismulticast_val(&gw) || ip_addr_isbroadcast_val(&gw, netif) ||
            ip_addr_isany(&gw) || ip_addr_isloopback(&gw)) {
            ERR_IFCONFIG_STRING_PUT(ret, "Don't set gateway as a multicast/broadcast/0/loopback address!\n");
            goto out;
        }

        /* check if reachable */
        if (!ip_addr_netcmp_val(&gw, &netif->ip_addr, ip_2_ip4(&netif->netmask))) {
            ERR_IFCONFIG_STRING_PUT(ret, "The address is unreachable!\n");
            goto out;
        }

        if (netif_default != netif) {
            ip_addr_set_zero(&netif->gw);
            (void)netif_set_default(netif);
        }

#if LWIP_DHCP
        if (netif_dhcp_data(netif) && netif_dhcp_data(netif)->state != DHCP_STATE_OFF) {
            (void)netif_dhcp_off(netif);
        }
#endif
        netif_set_gw(netif, ip_2_ip4(&gw));
    }

    if (ifconfig_cmd->option & IFCONFIG_OPTION_SET_MTU) {
        mtu = ifconfig_cmd->mtu;
        if (netif_set_mtu(netif, mtu) != ERR_OK) {
            ERR_IFCONFIG_STRING_PUT(ret, "Invalid MTU\n");
        }
    }
out:
    sys_sem_signal(&ifconfig_cmd->cb_completed);
}


void lwip_printsize(size_t size)
{
    static const char *SIZES[] = {"B", "KB", "MB", "GB"};
    size_t divis = 0;
    size_t rem = 0;

    while ((size >= 1024) && (divis < ((sizeof(SIZES) / sizeof(char *)) - 1))) {
        rem = (size % 1024);
        divis++;
        size /= 1024;
    }

    PRINTK("(%.1f %s) \r\n", (float)size + (float)rem / 1024.0, SIZES[divis]);
}

LWIP_STATIC void lwip_ifconfig_usage(const char *cmd)
{
    PRINTK("Usage:"\
         "\n%s [-a] "\
         "\n[interface]"\
         "\n[interface ipaddr] <netmask mask> <gateway gw>"\
         "\n[interface inet6 add|del ipaddr]"\
         "\n[interface hw ether MAC]"\
         "\n[interface mtu NN]"\
         "\n[interface up|down]\n",
           cmd);
}

u32_t lwip_ifconfig(int argc, const char **argv)
{
    int i;
    static struct ifconfig_option ifconfig_cmd;
    err_t ret;

#if LWIP_STATS
    u32_t stat_err_cnt;
    u32_t stat_drop_cnt;
    u32_t stat_rx_or_tx_cnt;
    u32_t stat_rx_or_tx_bytes;
#endif

#if LWIP_ARP
    u32_t retval;
    struct netif *netiftmp = NULL;
#if LWIP_ENABLE_IP_CONFLICT_SIGNAL
    u32_t old_ip4addr;
    err_t        err;
    extern sys_sem_t ip_conflict_detect;
    extern u32_t is_ip_conflict_signal;
#endif /* LWIP_ENABLE_IP_CONFLICT_SIGNAL */
#endif /* LWIP_ARP */
#if LWIP_IPV6
    extern sys_sem_t dup_addr_detect;
    extern u32_t is_dup_detect_initialized;
#endif
    if (!tcpip_init_finish) {
        PRINTK("%s: tcpip_init have not been called\n", __FUNCTION__);
        return 2;
    }
    /* To support "ifconfig -a" command
         RX packets:XXXX errors:X dropped:X overruns:X bytes:XXXX (Human readable format)
         TX packets:XXXX errors:X dropped:X overruns:X bytes:XXXX (Human readable format)

         Below is assumed for 'overrun' stat.
         Linux Kernel:
                RX: FIFO overrun
                    Data structure: net_device->stats->rx_fifo_errors
                    Flag which is marked when FIFO overrun: ENRSR_FO

                Function: ei_receive->ENRSR_FO

                TX: A "FIFO underrun" occurred during transmit.
                    Data structure: net_device->stats->tx_fifo_errors
                    Flag which is marked when FIFO underrun: ENTSR_FU

                Function: ei_tx_intr->ENTSR_FU

        LWIP:
            So in our case,
            while receiving a packet RX case, if the buffer is full (trypost - it is sys_mbox_trypost)
            the error will be returned, we can consider that an overflow has happend.
            So this can be RX overrun.

            But while transmitting a packet TX case, underrun cannot happen because it block on the
            message Q if it is full (NOT trypost - it is sys_mbox_post). So TX overrun is always 0.
    */
    if (argc) {
        if (strcmp("-a", argv[0]) == 0) {
#if LWIP_STATS
            stat_rx_or_tx_cnt = lwip_stats.ip.recv;
            stat_err_cnt = (u32_t)(lwip_stats.ip.ip_rx_err +
                                   lwip_stats.ip.lenerr +
                                   lwip_stats.ip.chkerr +
                                   lwip_stats.ip.opterr +
                                   lwip_stats.ip.proterr);
            stat_drop_cnt = (u32_t)(lwip_stats.ip.drop + lwip_stats.link.link_rx_drop);
            stat_rx_or_tx_bytes = lwip_stats.ip.ip_rx_bytes;

            PRINTK("%18s:%u\t errors:%u\t ip dropped:%u\t link dropped:%u\t overrun:%d\t bytes:%u ",
                   "RX packets",
                   stat_rx_or_tx_cnt,
                   stat_err_cnt,
                   stat_drop_cnt,
                   lwip_stats.link.link_rx_drop,
                   lwip_stats.ip.link_rx_overrun,
                   stat_rx_or_tx_bytes);

            /* Print in Human readable format of the incoming bytes */
            lwip_printsize(lwip_stats.ip.ip_rx_bytes);
#if IP6_STATS
            stat_rx_or_tx_cnt = lwip_stats.ip6.recv;
            stat_err_cnt = (u32_t)(lwip_stats.ip6.ip_rx_err +
                                   lwip_stats.ip6.lenerr +
                                   lwip_stats.ip6.chkerr +
                                   lwip_stats.ip6.opterr +
                                   lwip_stats.ip6.proterr);
            stat_drop_cnt = lwip_stats.ip6.drop;
            stat_rx_or_tx_bytes = lwip_stats.ip6.ip_rx_bytes;

            PRINTK("%18s:%u\t errors:%u\t dropped:%u\t overrun:%d\t bytes:%u ",
                   "RX packets(ip6)",
                   stat_rx_or_tx_cnt,
                   stat_err_cnt,
                   stat_drop_cnt,
                   lwip_stats.ip.link_rx_overrun,
                   stat_rx_or_tx_bytes);

            /* Print in Human readable format of the incoming bytes */
            lwip_printsize(lwip_stats.ip6.ip_rx_bytes);
#endif
            stat_rx_or_tx_cnt = (u32_t)(lwip_stats.ip.fw + lwip_stats.ip.xmit);
            stat_err_cnt = (u32_t)(lwip_stats.ip.rterr + lwip_stats.ip.ip_tx_err);
            /* IP layer drop stat param is not maintained, failure at IP is considered in 'errors' stat */
            stat_drop_cnt = lwip_stats.link.link_tx_drop;
            stat_rx_or_tx_bytes = lwip_stats.ip.ip_tx_bytes;

            PRINTK("%18s:%u\t errors:%u\t link dropped:%u\t overrun:0\t bytes:%u",
                   "TX packets",
                   stat_rx_or_tx_cnt,
                   stat_err_cnt,
                   stat_drop_cnt,
                   stat_rx_or_tx_bytes);

            /* Print in Human readable format of the outgoing bytes */
            lwip_printsize(lwip_stats.ip.ip_tx_bytes);

            stat_rx_or_tx_cnt = (u32_t)(lwip_stats.ip6.fw + lwip_stats.ip6.xmit);
            stat_err_cnt = (u32_t)(lwip_stats.ip6.rterr + lwip_stats.ip6.ip_tx_err);
            stat_rx_or_tx_bytes = lwip_stats.ip6.ip_tx_bytes;

            PRINTK("%18s:%u\t errors:%u\t overrun:0\t bytes:%u",
                   "TX packets(ip6)",
                   stat_rx_or_tx_cnt,
                   stat_err_cnt,
                   stat_rx_or_tx_bytes);

            /* Print in Human readable format of the outgoing bytes */
            lwip_printsize(lwip_stats.ip6.ip_tx_bytes);
#endif /* LWIP_STATS */
            return 0;
        }
    }

    (void)memset_s(&ifconfig_cmd, sizeof(ifconfig_cmd), 0, sizeof(ifconfig_cmd));
    if (sys_sem_new(&ifconfig_cmd.cb_completed, 0) != ERR_OK) {
        PRINTK("%s: sys_sem_new fail\n", __FUNCTION__);
        return 1;
    }

    i = 0;
    /* Get the interface */
    if (argc > 0) {
        if (strlen(argv[i]) < IFNAMSIZ) {
            if (strncpy_s(ifconfig_cmd.iface, IFNAMSIZ, argv[i], (strlen(argv[i]))) != EOK) {
                sys_sem_free(&ifconfig_cmd.cb_completed);
                PRINTK("ifconfig : strncpy_s error\n");
                return 1;
            }
            ifconfig_cmd.iface[IFNAMSIZ - 1] = '\0';
        } else {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            PRINTK("ifconfig : interface name is too big\n");
            return 1;
        }
        i++;
        argc--;
        if (argc == 0) {
            /* no more arguments, show the interface state. */
            ret = tcpip_callback(lwip_ifconfig_show_internal, &ifconfig_cmd);
            if (ret != ERR_OK) {
                sys_sem_free(&ifconfig_cmd.cb_completed);
                PRINTK("ifconfig : internal error, l:%d err:%d\n", __LINE__, ret);
                return 1;
            }
            (void)sys_arch_sem_wait(&ifconfig_cmd.cb_completed, 0);
            sys_sem_free(&ifconfig_cmd.cb_completed);
            ifconfig_cmd.cb_print_buf[PRINT_BUF_LEN - 1] = '\0';
            PRINTK("%s", ifconfig_cmd.cb_print_buf);
            return 0;
        }
    } else {
        /* no more arguments, show all the interface state. */
        ret = tcpip_callback(lwip_ifconfig_show_internal, &ifconfig_cmd);
        if (ret != ERR_OK) {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            PRINTK("ifconfig : internal error, l:%d err:%d\n", __LINE__, ret);
            return 1;
        }
        (void)sys_arch_sem_wait(&ifconfig_cmd.cb_completed, 0);
        sys_sem_free(&ifconfig_cmd.cb_completed);
        ifconfig_cmd.cb_print_buf[PRINT_BUF_LEN - 1] = '\0';
        PRINTK("%s", ifconfig_cmd.cb_print_buf);

        return 0;
    }

    /* ifup/ifdown */
    if (strcmp("up", argv[i]) == 0) {
        ifconfig_cmd.option |= IFCONFIG_OPTION_SET_UP;
        /* setup the interface, other arguments is ignored. */
        ret = tcpip_callback(lwip_ifconfig_internal, &ifconfig_cmd);
        if (ret != ERR_OK) {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            PRINTK("ifconfig : internal error, l:%d err:%d\n", __LINE__, ret);
            return 1;
        }
        (void)sys_arch_sem_wait(&ifconfig_cmd.cb_completed, 0);
        sys_sem_free(&ifconfig_cmd.cb_completed);
        ifconfig_cmd.cb_print_buf[PRINT_BUF_LEN - 1] = '\0';
        PRINTK("%s", ifconfig_cmd.cb_print_buf);
        return 0;
    } else if (strcmp("down", argv[i]) == 0) {
        ifconfig_cmd.option |= IFCONFIG_OPTION_SET_DOWN;
        /* setdown the interface, other arguments is ignored. */
        ret = tcpip_callback(lwip_ifconfig_internal, &ifconfig_cmd);
        if (ret != ERR_OK) {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            PRINTK("ifconfig : internal error, l:%d err:%d\n", __LINE__, ret);
            return 1;
        }
        (void)sys_arch_sem_wait(&ifconfig_cmd.cb_completed, 0);
        sys_sem_free(&ifconfig_cmd.cb_completed);
        ifconfig_cmd.cb_print_buf[PRINT_BUF_LEN - 1] = '\0';
        PRINTK("%s", ifconfig_cmd.cb_print_buf);
        return 0;
    }
    /* check if set the ip address. */
#if LWIP_ARP
    netiftmp = netifapi_netif_find_by_name(ifconfig_cmd.iface);
    if (netiftmp == NULL) {
        sys_sem_free(&ifconfig_cmd.cb_completed);
        PRINTK("ifconfig : Interface %s not found\n", ifconfig_cmd.iface);
        return 1;
    }
#if LWIP_ENABLE_IP_CONFLICT_SIGNAL
    old_ip4addr = ipaddr_addr(ipaddr_ntoa(&netiftmp->ip_addr));
#endif /* LWIP_ENABLE_IP_CONFLICT_SIGNAL */
#endif /* LWIP_ARP */
    if (!strcmp(argv[i], "inet") || ip4addr_aton(argv[i], ip_2_ip4(&ifconfig_cmd.ip_addr))) {
        if (!strcmp(argv[i], "inet")) {
            if (argc <= 1) {
                sys_sem_free(&ifconfig_cmd.cb_completed);
                goto ifconfig_error;
            }

            if (!ip4addr_aton(argv[i + 1], ip_2_ip4(&ifconfig_cmd.ip_addr))) {
                sys_sem_free(&ifconfig_cmd.cb_completed);
                PRINTK("ifconfig : Invalid IPv4 Address\n");
                return 1;
            }
            argc--;
            i++;
        }
        IP_SET_TYPE_VAL((ifconfig_cmd.ip_addr), IPADDR_TYPE_V4);
#if LWIP_ARP
        if (!ip_addr_cmp(&ifconfig_cmd.ip_addr, &netiftmp->ip_addr)) {
            ifconfig_cmd.option |= IFCONFIG_OPTION_SET_IP;
        }
#else
        ifconfig_cmd.option |= IFCONFIG_OPTION_SET_IP;
#endif /* LWIP_ARP */
        argc--;
        i++;
    } else if (!strcmp(argv[i], "inet6")) {
        if (argc < 3) {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            goto ifconfig_error;
        }
        if (strcmp(argv[i + 1], "add") && strcmp(argv[i + 1], "del")) {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            goto ifconfig_error;
        }

        if (!ip6addr_aton(argv[i + 2], ip_2_ip6(&ifconfig_cmd.ip_addr))) {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            PRINTK("ifconfig : Invalid IPv6 Address\n");
            return 1;
        }

        IP_SET_TYPE_VAL((ifconfig_cmd.ip_addr), IPADDR_TYPE_V6);
        ifconfig_cmd.option |= (!strcmp(argv[i + 1], "add") ? IFCONFIG_OPTION_SET_IP : IFCONFIG_OPTION_DEL_IP);
        argc -= 3;
        i += 3;
    }

    if (ifconfig_cmd.option & IFCONFIG_OPTION_DEL_IP) {
        if (argc != 0) {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            goto ifconfig_error;
        }
    }

    while (argc > 0) {
        if (strcmp("netmask", argv[i]) == 0 && (argc > 1) && (ipaddr_addr(argv[i + 1]) != IPADDR_NONE)) {
            /* if set netmask */
            ip_addr_set_ip4_u32_val((ifconfig_cmd.netmask), ipaddr_addr(argv[i + 1]));
            ifconfig_cmd.option |= IFCONFIG_OPTION_SET_NETMASK;
            i += 2;
            argc -= 2;
        } else if (strcmp("gateway", argv[i]) == 0 && (argc > 1) && (ipaddr_addr(argv[i + 1]) != IPADDR_NONE)) {
            /* if set gateway */
            ip_addr_set_ip4_u32_val((ifconfig_cmd.gw), ipaddr_addr(argv[i + 1]));
            ifconfig_cmd.option |= IFCONFIG_OPTION_SET_GW;
            i += 2;
            argc -= 2;
        } else if (strcmp("hw", argv[i]) == 0 && argc > 2 && strcmp("ether", argv[i + 1]) == 0) {
            /* if set HWaddr */
            char *digit = NULL;
            u32_t macaddrlen = strlen(argv[i + 2]) + 1;
            char tmpStr[MAX_MACADDR_STRING_LENGTH];
            char *tmpStr1 = NULL;
            char *saveptr = NULL;
            int j;

            if (macaddrlen != MAX_MACADDR_STRING_LENGTH) {
                sys_sem_free(&ifconfig_cmd.cb_completed);
                PRINTK("ifconfig : wrong MAC address format\n");
                return 1;
            }

            if (strncpy_s(tmpStr, MAX_MACADDR_STRING_LENGTH, argv[i + 2], macaddrlen - 1) != 0) {
                sys_sem_free(&ifconfig_cmd.cb_completed);
                PRINTK("ifconfig : wrong MAC address\n");
                return 1;
            }
            for (j = 0, tmpStr1 = tmpStr; j < 6; j++, tmpStr1 = NULL) {
                digit = strtok_r(tmpStr1, ":", &saveptr);
                if ((digit == NULL) || (strlen(digit) > 2)) {
                    sys_sem_free(&ifconfig_cmd.cb_completed);
                    PRINTK("ifconfig : wrong MAC address format\n");
                    return 1;
                }
                CONVERT_STRING_TO_HEX(digit, ifconfig_cmd.ethaddr[j]);
            }
            ifconfig_cmd.option |= IFCONFIG_OPTION_SET_HW;
            i += 3;
            argc -= 3;
        } else if (!strcmp("mtu", argv[i]) && (argc > 1)) {
            /* if set mtu */
            if ((atoi(argv[i + 1]) < 0) || (atoi(argv[i + 1]) > 0xFFFF)) {
                sys_sem_free(&ifconfig_cmd.cb_completed);
                PRINTK("\nifconfig: Invalid argument for mtu\n");
                goto ifconfig_error;
            }

            ifconfig_cmd.mtu = (u16_t)(atoi(argv[i + 1]));
            ifconfig_cmd.option |= IFCONFIG_OPTION_SET_MTU;
            i += 2;
            argc -= 2;
        } else {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            goto ifconfig_error;
        }
    }

#if LWIP_ARP && LWIP_ENABLE_IP_CONFLICT_SIGNAL
    if ((ifconfig_cmd.option & IFCONFIG_OPTION_SET_IP) && IP_IS_V4_VAL((ifconfig_cmd.ip_addr))) {
      /* Create the semaphore for ip conflict detection. */
      if (sys_sem_new(&ip_conflict_detect, 0) != ERR_OK) {
        sys_sem_free(&ifconfig_cmd.cb_completed);
        PRINTK("ifconfig: internal error\n");
        return 1;
      }
      is_ip_conflict_signal = 1;
    }
#endif /* LWIP_ARP && LWIP_ENABLE_IP_CONFLICT_SIGNAL */

#if LWIP_IPV6
    if ((ifconfig_cmd.option & IFCONFIG_OPTION_SET_IP) && IP_IS_V6_VAL((ifconfig_cmd.ip_addr))) {
        /* Create the semaphore for duplicate address detection. */
        if (sys_sem_new(&dup_addr_detect, 0) != ERR_OK) {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            PRINTK("ifconfig: internal error\n");
            return 1;
        }
        is_dup_detect_initialized = 1;
    }
#endif /* LWIP_IPV6 */

    ret = tcpip_callback(lwip_ifconfig_internal, &ifconfig_cmd);
    if (ret != ERR_OK) {
        sys_sem_free(&ifconfig_cmd.cb_completed);
#if LWIP_ARP && LWIP_ENABLE_IP_CONFLICT_SIGNAL
        if ((ifconfig_cmd.option & IFCONFIG_OPTION_SET_IP) && IP_IS_V4_VAL((ifconfig_cmd.ip_addr))) {
          is_ip_conflict_signal = 0;
          sys_sem_free(&ip_conflict_detect);
        }
#endif /* LWIP_ARP && LWIP_ENABLE_IP_CONFLICT_SIGNAL */

#if LWIP_IPV6
        if ((ifconfig_cmd.option & IFCONFIG_OPTION_SET_IP) && IP_IS_V6_VAL((ifconfig_cmd.ip_addr))) {
            is_dup_detect_initialized = 0;
            sys_sem_free(&dup_addr_detect);
        }
#endif /* LWIP_IPV6 */

        PRINTK("%s : tcpip_callback failed in line %d : errnu %d", __FUNCTION__, __LINE__, ret);
        return 1;
    }
    (void)sys_arch_sem_wait(&ifconfig_cmd.cb_completed, 0);
    ifconfig_cmd.cb_print_buf[PRINT_BUF_LEN - 1] = '\0';
    PRINTK("%s", ifconfig_cmd.cb_print_buf);
#if LWIP_ARP && LWIP_ENABLE_IP_CONFLICT_SIGNAL
    /* Pend 2 seconds for waiting the arp reply if the ip is already in use.*/
    if ((ifconfig_cmd.option & IFCONFIG_OPTION_SET_IP) && IP_IS_V4_VAL((ifconfig_cmd.ip_addr))) {
      err = (err_t)sys_arch_sem_wait(&ip_conflict_detect, DUP_ARP_DETECT_TIME);
      is_ip_conflict_signal = 0;
      sys_sem_free(&ip_conflict_detect);
      if (err < 0) {
        /* The result neither conflict nor timeout. */
        PRINT_ERR("ifconfig: internal error\n");
        sys_sem_free(&ifconfig_cmd.cb_completed);
        return 1;
      } else if (err < DUP_ARP_DETECT_TIME) {
        /* Duplicate use of new ip, restore it to the old one. */
        PRINT_ERR("ifconfig: ip conflict!\n");
        ip_addr_set_ip4_u32_val(ifconfig_cmd.ip_addr, old_ip4addr);
        ret = tcpip_callback(lwip_ifconfig_internal, &ifconfig_cmd);
        if (ret != ERR_OK) {
          sys_sem_free(&ifconfig_cmd.cb_completed);
          PRINTK("%s : tcpip_callback failed in line %d : errnu %d", __FUNCTION__, __LINE__, ret);
          return 1;
        }
        (void)sys_arch_sem_wait(&ifconfig_cmd.cb_completed, 0);
        sys_sem_free(&ifconfig_cmd.cb_completed);
        ifconfig_cmd.cb_print_buf[PRINT_BUF_LEN - 1] = '\0';
        PRINTK("%s", ifconfig_cmd.cb_print_buf);
        return 1;
      }
    }
#endif /* LWIP_ARP && LWIP_ENABLE_IP_CONFLICT_SIGNAL */
#if LWIP_IPV6
    if ((ifconfig_cmd.option & IFCONFIG_OPTION_SET_IP) && IP_IS_V6_VAL(ifconfig_cmd.ip_addr)) {
        /* Pend 2 seconds for waiting the arp reply if the ip is already in use.*/
        retval = sys_arch_sem_wait(&dup_addr_detect, DUP_ARP_DETECT_TIME);
        is_dup_detect_initialized = 0;
        sys_sem_free(&dup_addr_detect);
        if (retval == SYS_ARCH_ERROR) {
            sys_sem_free(&ifconfig_cmd.cb_completed);
            /* The result neither conflict nor timeout. */
            PRINT_ERR("ifconfig: internal error\n");
            return 1;
        } else if (retval < DUP_ARP_DETECT_TIME) {
            /* Duplicate use of new ip, restore it to the old one. */
            struct netif *netif = NULL;
            PRINT_ERR("ifconfig: IP conflict!\n");
            netif = netifapi_netif_find_by_name(ifconfig_cmd.iface);
            i = netif_get_ip6_addr_match(netif, &ifconfig_cmd.ip_addr.u_addr.ip6);
            if (i >= 0) {
                netif->ip6_addr_state[i] = IP6_ADDR_INVALID;
            }

            sys_sem_free(&ifconfig_cmd.cb_completed);
            ifconfig_cmd.cb_print_buf[PRINT_BUF_LEN - 1] = '\0';
            PRINTK("%s", ifconfig_cmd.cb_print_buf);
            return 1;
        }
    }
#endif /* LWIP_IPV6 */
    sys_sem_free(&ifconfig_cmd.cb_completed);
    return 0;
ifconfig_error:
    lwip_ifconfig_usage("ifconfig");
    return 1;
}

#ifdef LOSCFG_SHELL
SHELLCMD_ENTRY(ifconfig_shellcmd, CMD_TYPE_EX, "ifconfig", XARGS, (CmdCallBackFunc)lwip_ifconfig);
#endif /* LOSCFG_SHELL */
/* add arp entry to arp cache */
#define ARP_OPTION_ADD      1
/* delete arp entry to arp cache */
#define ARP_OPTION_DEL      2
/* print all arp entry in arp cache */
#define ARP_OPTION_SHOW     3

struct arp_option {
    /* see the ARP_OPTION_ above */
    int option;
    /* descriptive abbreviation of network interface */
    char iface[IFNAMSIZ];
    /* ip addr */
    unsigned int ipaddr;
    /* hw addr */
    unsigned char ethaddr[6];
    /* when using telnet, printf to the telnet socket will result in system  */
    /* deadlock.so don't do it.cahe the data to prinf to a buf, and when     */
    /* callback returns, then printf the data out to the telnet socket       */
    sys_sem_t cb_completed;
    char cb_print_buf[PRINT_BUF_LEN];
    int print_buf_len;
};

#ifndef LWIP_TESTBED
LWIP_STATIC
#endif
void lwip_arp_show_internal(struct netif *netif, char *printf_buf, unsigned int buf_len)
{
    u8_t state, i;
    int ret;
    char *tmp = printf_buf;
    ret = snprintf_s(tmp, buf_len, (buf_len - 1), "%-24s%-24s%-12s%-12s\n", "Address", "HWaddress", "Iface", "Type");
    if ((ret <= 0) || ((unsigned int)ret >= buf_len))
        return;
    tmp += ret;
    buf_len -= (unsigned int)ret;

    if (netif != NULL) {
        for (i = 0; i < ARP_TABLE_SIZE; ++i) {
            state = arp_table[i].state;
            if (((state == ETHARP_STATE_STABLE)
                 #if ETHARP_SUPPORT_STATIC_ENTRIES
                 || (state == ETHARP_STATE_STATIC)
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
                ) && arp_table[i].netif) {

                if (strcmp(netif_get_name(netif), netif_get_name(arp_table[i].netif)) != 0) {
                    continue;
                }

                ret = snprintf_s(tmp, buf_len, (buf_len - 1), "%-24s%02X:%02X:%02X:%02X:%02X:%02X       %s        %s\n",
                                 ip4addr_ntoa(&arp_table[i].ipaddr),
                                 arp_table[i].ethaddr.addr[0], arp_table[i].ethaddr.addr[1],
                                 arp_table[i].ethaddr.addr[2], arp_table[i].ethaddr.addr[3],
                                 arp_table[i].ethaddr.addr[4], arp_table[i].ethaddr.addr[5],
                                 netif_get_name(netif),
#if ETHARP_SUPPORT_STATIC_ENTRIES
                                 ((state == ETHARP_STATE_STATIC) ? "static" : "dynamic")
#else
                    "dynamic"
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
                );
                if ((ret <= 0) || ((unsigned int)ret >= buf_len))
                    return;
                tmp += ret;
                buf_len -= (unsigned int)ret;
            }
        }
    } else {
        for (i = 0; i < ARP_TABLE_SIZE; ++i) {
            state = arp_table[i].state;
            if (((state == ETHARP_STATE_STABLE)
                 #if ETHARP_SUPPORT_STATIC_ENTRIES
                 || (state == ETHARP_STATE_STATIC)
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
                ) && arp_table[i].netif) {
                ret = snprintf_s(tmp, buf_len, (buf_len - 1), "%-24s%02X:%02X:%02X:%02X:%02X:%02X       %s        %s\n",
                                 ip4addr_ntoa(&arp_table[i].ipaddr),
                                 arp_table[i].ethaddr.addr[0], arp_table[i].ethaddr.addr[1],
                                 arp_table[i].ethaddr.addr[2], arp_table[i].ethaddr.addr[3],
                                 arp_table[i].ethaddr.addr[4], arp_table[i].ethaddr.addr[5],
                                 netif_get_name(arp_table[i].netif),
#if ETHARP_SUPPORT_STATIC_ENTRIES
                                 ((state == ETHARP_STATE_STATIC) ? "static" : "dynamic")
#else
                    "dynamic"
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
                );
                if ((ret <= 0) || ((unsigned int)ret >= buf_len))
                    return;
                tmp += ret;
                buf_len -= (unsigned int)ret;
            }
        }
    }
}

#ifndef LWIP_TESTBED
LWIP_STATIC
#endif
void lwip_arp_internal(void *arg)
{
#if LWIP_IPV4
    struct arp_option *arp_cmd = (struct arp_option *)arg;
    struct netif *netif = NULL;
    struct eth_addr ethaddr;
    ip4_addr_t ipaddr;
    err_t ret = 0;
    int type = 0;

    if (arp_cmd->iface[0] == 'd' && arp_cmd->iface[1] == 'e') {
        netif = NULL;
    } else {
        /* find the specified netif by it's name */
        netif = netif_find(arp_cmd->iface);
        if (netif == NULL) {
            (void)snprintf_s(arp_cmd->cb_print_buf, PRINT_BUF_LEN, (PRINT_BUF_LEN - 1), "No such device\n");
            goto out;
        }
    }

    type = arp_cmd->option;
    switch (type) {
        case ARP_OPTION_SHOW:
            if (netif != NULL) {
                lwip_arp_show_internal(netif, arp_cmd->cb_print_buf, PRINT_BUF_LEN);
            } else {
                lwip_arp_show_internal(NULL, arp_cmd->cb_print_buf, PRINT_BUF_LEN);
            }
            break;

        case ARP_OPTION_ADD:
#if ETHARP_SUPPORT_STATIC_ENTRIES
            ipaddr.addr = arp_cmd->ipaddr;
            (void)memcpy_s(ethaddr.addr, sizeof(ethaddr.addr), arp_cmd->ethaddr, 6);
            if (netif != NULL) {
                if (ip4_addr_netcmp(&ipaddr, ip_2_ip4(&(netif->ip_addr)), ip_2_ip4(&(netif->netmask)))) {
                    ret = etharp_update_arp_entry(netif, &ipaddr, &ethaddr,
                                                  ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY);
                } else {
                    ret = ERR_RTE;
                }
            } else {
                ret = etharp_add_static_entry(&ipaddr, &ethaddr);
            }
#else
            ret = ERR_ARG;
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
            break;

        case ARP_OPTION_DEL:
            ipaddr.addr = arp_cmd->ipaddr;
            (void)memcpy_s(ethaddr.addr, sizeof(ethaddr.addr), arp_cmd->ethaddr, 6);
            if (netif != NULL) {
                ret = etharp_delete_arp_entry(netif, &ipaddr);
            } else {
                for (netif = netif_list; netif != NULL; netif = netif->next) {
                    ret = etharp_delete_arp_entry(netif, &ipaddr);
                    if (ret == ERR_OK) {
                        /*only can del success one time*/
                        break;
                    }
                }
            }
            break;

        default:
            (void)snprintf_s(arp_cmd->cb_print_buf, PRINT_BUF_LEN, (PRINT_BUF_LEN - 1), "Error\n");
            goto out;
    }

out:
    if (type == ARP_OPTION_ADD || type == ARP_OPTION_DEL) {
        if (ret == ERR_MEM) {
            (void)snprintf_s(arp_cmd->cb_print_buf, PRINT_BUF_LEN, (PRINT_BUF_LEN - 1), "Out of memory error\n");
        } else if (ret == ERR_ARG) {
            (void)snprintf_s(arp_cmd->cb_print_buf, PRINT_BUF_LEN, (PRINT_BUF_LEN - 1), "Illegal argument\n");
        } else if (ret == ERR_RTE) {
            (void)snprintf_s(arp_cmd->cb_print_buf, PRINT_BUF_LEN, (PRINT_BUF_LEN - 1), "Network is unreachable\n");
        } else {
            (void)snprintf_s(arp_cmd->cb_print_buf, PRINT_BUF_LEN, (PRINT_BUF_LEN - 1), "Successed\n");
        }
    }
#endif

    sys_sem_signal(&arp_cmd->cb_completed);
}


LWIP_STATIC void lwip_arp_usage(const char *cmd)
{
    PRINTK("Usage:"\
         "\n%s"
           "\n%s [-i IF] -s IPADDR HWADDR"\
         "\n%s [-i IF] -d IPADDR\n",
           cmd, cmd, cmd);
}

u32_t lwip_arp(int argc, const char **argv)
{
    int i;
    struct arp_option arp_cmd;
    err_t ret;
    size_t interface_len = 0;

    (void)memset_s(&arp_cmd, sizeof(struct arp_option), 0, sizeof(struct arp_option));
    if (!tcpip_init_finish) {
        PRINTK("%s: tcpip_init have not been called\n", __FUNCTION__);
        return LOS_NOK;
    }

    arp_cmd.iface[0] = 'd';
    arp_cmd.iface[1] = 'e';
    arp_cmd.iface[2] = '0';
    arp_cmd.option = ARP_OPTION_SHOW;
    arp_cmd.print_buf_len = 0;
    if (sys_sem_new(&arp_cmd.cb_completed, 0) != ERR_OK) {
        PRINTK("%s: sys_sem_new fail\n", __FUNCTION__);
        return 1;
    }

    i = 0;
    while (argc > 0) {
        if (strcmp("-i", argv[i]) == 0 && (argc > 1)) {
            /* get the network interface's name */
            interface_len = strlen(argv[i + 1]);
            if (interface_len < IFNAMSIZ) {
                if (strncmp(argv[i + 1], "lo", (sizeof("lo") - 1)) == 0) {
                    PRINTK("Illegal operation\n");
                    goto arp_error;
                }
                if (strncpy_s(arp_cmd.iface, IFNAMSIZ, argv[i + 1], interface_len) != EOK) {
                    PRINTK("strncpy_s error\n");
                    goto arp_error;
                }
                arp_cmd.iface[interface_len] = '\0';
            } else {
                PRINTK("Iface name is big \n");
                goto arp_error;
            }
            i += 2;
            argc -= 2;
        } else if (strcmp("-d", argv[i]) == 0 && (argc > 1)) {
            /* arp delete */
            arp_cmd.option = ARP_OPTION_DEL;
            arp_cmd.ipaddr = inet_addr(argv[i + 1]);

            if (arp_cmd.ipaddr == IPADDR_NONE) {
                PRINTK("IP address is not correct!\n");
                goto arp_error;
            }

            i += 2;
            argc -= 2;
        } else if (strcmp("-s", argv[i]) == 0 && (argc > 2)) {
            /* arp add */
            char *digit = NULL;
            u32_t macaddrlen = strlen(argv[i + 2]) + 1;
            char tmpStr[MAX_MACADDR_STRING_LENGTH];
            char *tmpStr1 = NULL;
            char *saveptr1 = NULL;
            char *temp = NULL;
            int j;

            arp_cmd.option = ARP_OPTION_ADD;
            arp_cmd.ipaddr = inet_addr(argv[i + 1]);

            if (arp_cmd.ipaddr == IPADDR_NONE) {
                PRINTK("IP address is not correct!\n");
                goto arp_error;
            }

            /*cannot add an arp entry of 127.*.*.* */
            if ((arp_cmd.ipaddr & (u32_t)0x0000007fUL) == (u32_t)0x0000007fUL) {
                PRINTK("IP address is not correct!\n");
                goto arp_error;
            }

            if (macaddrlen != MAX_MACADDR_STRING_LENGTH) {
                PRINTK("Wrong MAC address length\n");
                goto arp_error;
            }

            if (strncpy_s(tmpStr, MAX_MACADDR_STRING_LENGTH, argv[i + 2], macaddrlen - 1) != 0) {
                PRINTK("Wrong MAC address\n");
                goto arp_error;
            }

            for (j = 0, tmpStr1 = tmpStr; j < 6; j++, tmpStr1 = NULL) {
                digit = strtok_r(tmpStr1, ":", &saveptr1);
                if ((digit == NULL) || (strlen(digit) > 2)) {
                    PRINTK("MAC address is not correct\n");
                    goto arp_error;
                }

                for (temp = digit; *temp != '\0'; temp++) {
                    if (!isxdigit(*temp)) {
                        PRINTK("MAC address is not correct\n");
                        goto arp_error;
                    }
                }

                CONVERT_STRING_TO_HEX(digit, arp_cmd.ethaddr[j]);
            }

            i += 3;
            argc -= 3;
        } else {
            goto arp_error;
        }
    }

    ret = tcpip_callback(lwip_arp_internal, &arp_cmd);
    if (ret != ERR_OK) {
        PRINTK("%s : tcpip_callback failed in line %d : errnu %d", __FUNCTION__, __LINE__, ret);
        sys_sem_free(&arp_cmd.cb_completed);
        return 1;
    }
    (void)sys_arch_sem_wait(&arp_cmd.cb_completed, 0);
    sys_sem_free(&arp_cmd.cb_completed);
    arp_cmd.cb_print_buf[PRINT_BUF_LEN - 1] = '\0';
    PRINTK("%s", arp_cmd.cb_print_buf);
    return 0;

arp_error:
    lwip_arp_usage("arp");
    sys_sem_free(&arp_cmd.cb_completed);
    return 1;
}

#ifdef LOSCFG_SHELL_CMD_DEBUG
SHELLCMD_ENTRY(arp_shellcmd, CMD_TYPE_EX, "arp", 1, (CmdCallBackFunc)lwip_arp);
#endif /* LOSCFG_SHELL_CMD_DEBUG */

void ifup_internal(void *arg)
{
    struct netif *netif = NULL;
    struct if_cmd_data *ifcmd_data;

    ifcmd_data = (struct if_cmd_data *)arg;
    if (ifcmd_data == NULL) {
        return;
    }
    netif = netif_find(ifcmd_data->if_name);
    if (netif == NULL) {
        ifcmd_data->err = ERR_VAL;
    } else {
        (void)netif_set_up(netif);
        ifcmd_data->err = ERR_OK;
    }

    sys_sem_signal(&ifcmd_data->cb_completed);
}

void ifdown_internal(void *arg)
{
    struct netif *netif = NULL;
    struct if_cmd_data *ifcmd_data = NULL;

    ifcmd_data = (struct if_cmd_data *)arg;
    if (ifcmd_data == NULL) {
        return;
    }
    netif = netif_find(ifcmd_data->if_name);
    if (netif == NULL) {
        ifcmd_data->err = ERR_VAL;
    } else {
        (void)netif_set_down(netif);
        ifcmd_data->err = ERR_OK;
    }

    sys_sem_signal(&ifcmd_data->cb_completed);
}

#if LWIP_DNS
#ifndef LWIP_TESTBED
LWIP_STATIC
#endif
struct hostent *gethostnameinfo(const char *host)
{
    static struct hostent hostbuf;
    struct hostent *hp = NULL;
    const size_t hstbuflen = 1024;
    char tmphstbuf[1024];
    int res;
    int herr;

    res = lwip_gethostbyname_r(host, &hostbuf, tmphstbuf, hstbuflen, &hp, &herr);
    /*  Check for errors.  */
    if (res || hp == NULL)
        return NULL;
    return hp;
}

LWIP_STATIC unsigned int get_hostip(const char *hname)
{
    unsigned int ip = 0;
    int ret;

    struct hostent *pent = gethostnameinfo(hname);
    if (pent == NULL || pent->h_addr == NULL)
        return 0;
    ret = memcpy_s(&ip, sizeof(ip), pent->h_addr, 4);
    if (ret != 0) {
        return 0;
    }
    return ip;
}
#endif

#if LWIP_EXT_POLL_SUPPORT
static int ping_taskid = -1;
static int ping_kill = 0;
#define PING_ZERO_DATA_LEN 8
static void lwip_ping_usage(void)
{
    PRINTK("Usage:"\
         "\n  ping"
           "\n  ping [-n cnt] [-w interval] [-l data_len] destination"
           "\n  ping [-t] [-w interval] destination"
           "\n  ping -k");
    PRINTK("\n  -t means ping forever, user can use -k to stop the forever ping");
}

LWIP_STATIC int osPingFunc(u32_t destip, u32_t cnt, u32_t interval, u32_t data_len)
{
    int sfd;
    struct sockaddr_in to;
    struct pbuf *pbuf_resp = NULL;
    struct icmp_echo_hdr *iecho = NULL;
    struct icmp_echo_hdr *iecho_resp = NULL;
    struct ip_hdr *iphdr_resp = NULL;
    u32_t iecho_len;
    s16_t ip_hlen;
    u32_t forever;
    u32_t i = 0;
    u32_t succ_cnt = 0;
    u32_t failed_cnt = 0;
    struct timespec start, end;
    long timout_ms = 0;
    struct pollfd pfd;
    long rtt;
    int ret = 0;
    u32_t intrvl = 0;
    char *data_buf = NULL;
    BOOL timeout_flag = false;
    char buf[50];

    iecho_len = sizeof(struct icmp_echo_hdr) + data_len;
    sfd = lwip_socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sfd < 0) {
        perror("Ping socket");
        return -1;
    }
    pbuf_resp = pbuf_alloc(PBUF_RAW, IP_HLEN + sizeof(struct icmp_echo_hdr), PBUF_RAM);
    if (pbuf_resp == NULL) {
        PRINTK("Ping: pbuf_resp malloc failed\n");
        ret = -1;
        goto FAILURE;
    }
    iecho = (struct icmp_echo_hdr *)mem_malloc(iecho_len);
    if (iecho == NULL) {
        PRINTK("Ping: echo request malloc failed\n");
        ret = -1;
        goto FAILURE;
    }

    to.sin_family = AF_INET;
    to.sin_addr.s_addr = destip; /* already in network order */
    to.sin_port = 0;

    if (data_len > PING_ZERO_DATA_LEN) {
        (void)memset_s(iecho, sizeof(struct icmp_echo_hdr) + PING_ZERO_DATA_LEN,
                       0, sizeof(struct icmp_echo_hdr) + PING_ZERO_DATA_LEN);
        data_buf = (char *)iecho + sizeof(struct icmp_echo_hdr) + PING_ZERO_DATA_LEN;
        for (i = 0; i < data_len - PING_ZERO_DATA_LEN; i++) {
            *(data_buf + i) = i + 0x10;
        }
    } else {
        (void)memset_s(iecho, sizeof(struct icmp_echo_hdr) + data_len, 0, sizeof(struct icmp_echo_hdr) + data_len);
    }
    iecho->id = htons((u16_t)LOS_CurTaskIDGet());
    ICMPH_TYPE_SET(iecho, (u8_t)ICMP_ECHO);
    forever = (cnt ? 0 : 1);
    i = 0;
    while (!ping_kill && (forever || (i < cnt))) {
        iecho->seqno = htons((u16_t)i);
        iecho->chksum = 0;
        iecho->chksum = inet_chksum((void *)iecho, iecho_len);

        ret = sendto(sfd, iecho, iecho_len, 0, (struct sockaddr *)&to, (socklen_t)sizeof(to));
        if (ret < 0) {
            perror("Ping: sending ICMP echo request failed\n");
            goto FAILURE;
        }

        /* capture the start time to calculate RTT */
        (void)clock_gettime(CLOCK_MONOTONIC_RAW, &start);

        /* poll for ICMP echo response msg */
        pfd.fd = sfd;

        do {
            pfd.events = POLLIN;
            pfd.revents = 0;
            timeout_flag = false;
            ret = poll(&pfd, 1, LWIP_SHELL_CMD_PING_TIMEOUT);
            if (ret < 0) {
                perror("Ping: poll\n");
                goto FAILURE;
            } else if (ret == 0) {
                /* first type timeout event */
                timeout_flag = true;
                break;
            }

            ret = recv(sfd, pbuf_resp->payload, pbuf_resp->len, MSG_DONTWAIT);
            if (ret < 0) {
                perror("Ping: recv echo reply failed\n");
                goto FAILURE;
            }

            /* Accessing ip header and icmp header */
            iphdr_resp = pbuf_resp->payload;

            ip_hlen = (IPH_HL(iphdr_resp) << 2);
            if (pbuf_header(pbuf_resp, -ip_hlen)) {
                /* this failure will never happen, but failure handle is written just to be in safe side */
                PRINTK("Ping : memory management failure\n");
                goto FAILURE;
            }
            iecho_resp = (struct icmp_echo_hdr *)pbuf_resp->payload;
            /* Reverting back pbuf to its original state */
            if (pbuf_header(pbuf_resp, ip_hlen)) {
                /* this failure will never happen, but failure handle is written just to be in safe side */
                PRINTK("ping : memory management failure\n");
                goto FAILURE;
            }

            if ((iphdr_resp->src.addr != to.sin_addr.s_addr) ||
                ((ICMPH_TYPE(iecho_resp) == ICMP_ECHO) && (iphdr_resp->src.addr == to.sin_addr.s_addr))) {
                /* second type timeout event */
                (void)clock_gettime(CLOCK_MONOTONIC_RAW, &end);
                timout_ms = ((end.tv_sec - start.tv_sec) * 1000 + (end.tv_nsec - start.tv_nsec) / 1000000);
                timout_ms = LWIP_SHELL_CMD_PING_TIMEOUT - timout_ms;
            } else {
                timout_ms = 0;
                break;
            }
        } while (timout_ms >= 0);

        /* all timeout events are true timeout */
        if ((timout_ms < 0) || (timeout_flag == true)) {
            failed_cnt++;
            i++;
            PRINTK("\nPing: destination unreachable ...");
            continue;
        }
        /* capture the end time to calculate round trip time */
        (void)clock_gettime(CLOCK_MONOTONIC_RAW, &end);
        rtt = ((end.tv_sec - start.tv_sec) * 1000 + (end.tv_nsec - start.tv_nsec) / 1000000);

        if (iphdr_resp->src.addr == to.sin_addr.s_addr) {
            switch (ICMPH_TYPE(iecho_resp)) {
                case ICMP_ER:
                    PRINTK("\n[%u]Reply from %s: ", i, inet_ntop(AF_INET, &to.sin_addr, buf, sizeof(buf)));
                    if (rtt > 0) {
                        PRINTK("time=%ims ", rtt);
                    } else {
                        PRINTK("time<1ms ");
                    }
                    PRINTK("TTL=%u", iphdr_resp->_ttl);

                    /* delay 1s for every successful ping */
                    intrvl = interval;
                    do {
                        if (intrvl < 1000) {
                            sys_msleep(intrvl);
                            break;
                        }
                        intrvl -= 1000;
                        sys_msleep(1000);
                        if (ping_kill == 1)
                            break;
                    } while (intrvl > 0);
                    succ_cnt++;
                    break;
                case ICMP_DUR:
                    PRINTK("\nPing: destination host unreachable ...");
                    break;
                case ICMP_SQ:
                    PRINTK("\nPing: source quench ...");
                    break;
                case ICMP_RD:
                    PRINTK("\nPing: redirect ...");
                    break;
                case ICMP_TE:
                    PRINTK("\nPing: time exceeded ...");
                    break;
                case ICMP_PP:
                    PRINTK("\nPing: parameter problem ...");
                    break;
                default :
                    PRINTK("\nPing: unknow error ...");
                    break;
            }
            i++;
        }
    }

    PRINTK("\n--- %s ping statistics ---\n", inet_ntop(AF_INET, &to.sin_addr, buf, sizeof(buf)));
    PRINTK("%u packets transmitted, %u received, %u loss\n", i, succ_cnt, failed_cnt);

FAILURE:
    ping_kill = 0;
    (void)lwip_close(sfd);
    if (pbuf_resp != NULL) {
        (void)pbuf_free(pbuf_resp);
    }
    if (iecho != NULL) {
        mem_free(iecho);
    }
    return ret;
}

static void ping_cmd(unsigned int p0, unsigned int p1, unsigned int p2, unsigned int p3)
{
    u32_t destip = p0;
    u32_t count = p1;
    u32_t interval = p2;
    u32_t data_len = p3;
    int ret;

    ret = osPingFunc(destip, count, interval, data_len);
    if (ret < 0) {
        PRINTK("Ping cmd failed due to some errors\n");
    }

    ping_taskid = -1;
}

u32_t osShellPing(int argc, const char **argv)
{
    int ret;
    u32_t i = 0;
    u32_t count = 0;
    int count_set = 0;
    u32_t interval = 1000; /* default ping interval */
    u32_t data_len = 48; /* default data length */
    ip4_addr_t dst_ipaddr;
    TSK_INIT_PARAM_S stPingTask;

    if (!tcpip_init_finish) {
        PRINTK("Ping: tcpip_init have not been called\n");
        return LOS_NOK;
    }

    if ((argc < 1) || (argv == NULL)) {
        PRINTK("Ping: require dest ipaddr at least\n");
        goto ping_error;
    }

    /* could add more param support */
    while (argc > 0) {
        if (strcmp("-n", argv[i]) == 0 && (argc > 1)) {
            ret = atoi(argv[i + 1]);
            if (ret <= 0) {
                PRINTK("Ping count should be greater than 0 \n");
                goto ping_error;
            }
            count = ret;
            count_set = 1;
            i += 2;
            argc -= 2;
        } else if (strcmp("-t", argv[i]) == 0) {
            count = 0; /* ping forerver */
            count_set = 1;
            i++;
            argc--;
        } else if (strcmp("-w", argv[i]) == 0 && (argc > 1)) {
            ret = atoi(argv[i + 1]);
            if (ret <= 0) {
                PRINTK("Ping interval should be greater than 0 \n");
                goto ping_error;
            }

            interval = ret;
            i += 2;
            argc -= 2;
        } else if (strcmp("-l", argv[i]) == 0 && (argc > 1)) {
            ret = atoi(argv[i + 1]);
            if (ret < 0 || ret > (int)(LWIP_MAX_UDP_RAW_SEND_SIZE - sizeof(struct icmp_echo_hdr))) {
                PRINTK("Ping data length error, should be in range of [0, %d] \n",
                       LWIP_MAX_UDP_RAW_SEND_SIZE - sizeof(struct icmp_echo_hdr));
                goto ping_error;
            }
            data_len = ret;
            i += 2;
            argc -= 2;
        } else if (strcmp("-k", argv[i]) == 0) {
            if (ping_taskid > 0) {
                ping_kill = 1; /* stop the current ping task */
                return LOS_OK;
            } else {
                PRINTK("No ping task running...\n");
                return LOS_NOK;
            }
        } else {
            if (argc == 1) {
                break;
            } else {
                PRINTK("Invalid Ping param\n");
                goto ping_error;
            }
        }
    }

    if (!count_set) {
        count = LWIP_SHELL_CMD_PING_RETRY_TIMES;
    }

    /* initialize dst IP address */
    if (argc <= 0) {
        goto ping_error;
    }
#if LWIP_DNS
    dst_ipaddr.addr = get_hostip(argv[i]);
#else /* LWIP_DNS */
    dst_ipaddr.addr = inet_addr(argv[i]);
#endif /* LWIP_DNS */

    if (dst_ipaddr.addr == IPADDR_NONE || dst_ipaddr.addr == IPADDR_ANY) {
        PRINTK("Invalid dest ipaddr: %s\n", argv[i]);
        return LOS_NOK;
    }

    /* start one task if ping forever or ping count greater than 60 */
    if (count == 0 || count > LWIP_SHELL_CMD_PING_RETRY_TIMES) {
        if (ping_taskid > 0) {
            PRINTK("Ping task already running and only support one now\n");
            return LOS_NOK;
        }
        stPingTask.pfnTaskEntry = (TSK_ENTRY_FUNC)ping_cmd;
        stPingTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
        stPingTask.pcName = "ping_task";
        stPingTask.usTaskPrio = 8; /* higher than shell */
        stPingTask.uwResved = LOS_TASK_STATUS_DETACHED;
        stPingTask.auwArgs[0] = dst_ipaddr.addr; /* network order */
        stPingTask.auwArgs[1] = count;
        stPingTask.auwArgs[2] = interval;
        stPingTask.auwArgs[3] = data_len;
        ret = LOS_TaskCreate((UINT32 *)(&ping_taskid), &stPingTask);
        if (ret != LOS_OK) {
            PRINTK("ping_task create failed 0x%08x.\n", ret);
            count = LWIP_SHELL_CMD_PING_RETRY_TIMES;
        } else {
            return LOS_OK;
        }
    }

    /* two cases:
     1, ping cout less than LWIP_SHELL_CMD_PING_RETRY_TIMES;
     2, ping task create failed;
    */
    if (osPingFunc(dst_ipaddr.addr, count, interval, data_len) < 0) {
        PRINTK("Ping cmd failed due some errors\n");
    }

    return LOS_OK;
ping_error:
    lwip_ping_usage();
    return LOS_NOK;
}
#ifdef LOSCFG_SHELL
SHELLCMD_ENTRY(ping_shellcmd, CMD_TYPE_EX, "ping", XARGS, (CmdCallBackFunc)osShellPing);
#endif /* LOSCFG_SHELL */

#else /* LWIP_EXT_POLL_SUPPORT*/

u32_t osShellPing(int argc, const char **argv)
{
    int sfd;
    struct sockaddr_in to;
    struct icmp_echo_hdr iecho;
    struct pbuf *pbuf_resp = NULL;
    struct icmp_echo_hdr *iecho_resp = NULL;
    struct ip_hdr *iphdr_resp = NULL;
    s16_t ip_hlen;
    ip_addr_t dst_ipaddr;
    fd_set fdReadSet;
    struct timeval stTimeVal;
    struct timespec start, end;
    int ret;
    s32_t i;
    long rtt;
    s32_t pingcount;
    char buf[50];

    if (!tcpip_init_finish) {
        PRINTK("ping: tcpip_init have not been called\n");
        return LOS_NOK;
    }

    if ((argc < 1) || (argv == NULL)) {
        PRINTK("ping : invalid arguments, ping command receives ip as command line argument \n");
        return LOS_NOK;
    }

    if (argc == 2) {
        pingcount = atoi(argv[1]);
        if (pingcount < 1)
            pingcount = LWIP_SHELL_CMD_PING_RETRY_TIMES;
    } else {
        pingcount = LWIP_SHELL_CMD_PING_RETRY_TIMES;
    }
    PRINTK("ping %u packets start.\n", pingcount);

    /* initialize dst IP address */
#if LWIP_DNS
    ip_2_ip4(&dst_ipaddr)->addr = get_hostip(argv[0]);
#else /* LWIP_DNS */
    ip_2_ip4(&dst_ipaddr)->addr = inet_addr(argv[0]);
#endif /* LWIP_DNS */

    to.sin_family = AF_INET;
    to.sin_addr.s_addr = ip_2_ip4(&dst_ipaddr)->addr;
    to.sin_port = 0;

    if (to.sin_addr.s_addr == IPADDR_NONE || to.sin_addr.s_addr == IPADDR_ANY) {
        PRINTK("ping : invalid ip address : %s\n", argv[0]);
        return LOS_NOK;
    }

    sfd = lwip_socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sfd == -1) {
        PRINTK("ping : failed, socket creation failed\n");
        return LOS_NOK;
    }

    pbuf_resp = pbuf_alloc(PBUF_RAW, IP_HLEN + sizeof(struct icmp_echo_hdr), PBUF_RAM);
    if (pbuf_resp == NULL) {
        PRINTK("ping : memory allocation failed\n");
        goto FAILURE;
    }

    for (i = 0; i < pingcount; i++) {
        (void)memset_s(&iecho, sizeof(iecho), 0, sizeof(iecho));
        ICMPH_TYPE_SET(&iecho, (u8_t)ICMP_ECHO);
        iecho.chksum = inet_chksum(&iecho, sizeof(struct icmp_echo_hdr));

        ret = lwip_sendto(sfd, &iecho, sizeof(struct icmp_echo_hdr), 0, (struct sockaddr *)&to, (socklen_t)sizeof(to));
        if (ret == -1) {
            PRINTK("ping : sending ICMP echo msg failed\n");
            goto FAILURE;
        }

        /* capture the start time to calculate round trip time */
        (void)clock_gettime(CLOCK_MONOTONIC_RAW, &start);
        /* Wait in select for ICMP response msg */
        FD_ZERO(&fdReadSet);
        FD_SET(sfd, &fdReadSet);
        stTimeVal.tv_sec = LWIP_SHELL_CMD_PING_TIMEOUT / 1000;
        stTimeVal.tv_usec = 0;

DO_SELECT:
        ret = select(sfd + 1, &fdReadSet, 0, 0, &stTimeVal);
        if (ret < 0) {
            PRINTK("ping : select failure\n");
            goto FAILURE;
        } else if (ret == 0) {
            PRINTK("Request timed out.\n");
            continue;
        }

        /* capture the end time to calculate round trip time */
        (void)clock_gettime(CLOCK_MONOTONIC_RAW, &end);
        rtt = ((end.tv_sec - start.tv_sec) * 1000 + (end.tv_nsec - start.tv_nsec) / 1000000);

        ret = lwip_recv(sfd, pbuf_resp->payload, pbuf_resp->len, 0);
        if (ret == -1) {
            PRINTK("ping : receiving ICMP echo response msg failed\n");
            goto FAILURE;
        }

        /* Accessing ip header and icmp header */
        iphdr_resp = (struct ip_hdr *)(pbuf_resp->payload);
        ip_hlen = (s16_t)(IPH_HL(iphdr_resp) * 4);
        if (pbuf_header(pbuf_resp, (s16_t)(-ip_hlen))) {
            /* this failure will never happen, but failure handle is written just to be in safe side */
            PRINTK("ping : memory management failure\n");
            goto FAILURE;
        }
        iecho_resp = (struct icmp_echo_hdr *)pbuf_resp->payload;

        /* Reverting back pbuf to its original state */
        if (pbuf_header(pbuf_resp, ip_hlen)) {
            /* this failure will never happen, but failure handle is written just to be in safe side */
            PRINTK("ping : memory management failure\n");
            goto FAILURE;
        }

        if (iphdr_resp->src.addr == to.sin_addr.s_addr) {
            if (ICMPH_TYPE(iecho_resp) == ICMP_ER) {
                PRINTK("[%u]Reply from %s: time=%ims TTL=%u\n", i,
                       inet_ntoa_r(to.sin_addr.s_addr, buf, sizeof(buf)), rtt, iphdr_resp->_ttl);
            } else if (ICMPH_TYPE(iecho_resp) == ICMP_ECHO) {
                /* If ping self, stack will receive a ICMP_ECHO request message flowing a ICMP_ER reply message,
                    and we need reply only, do select again */
                goto DO_SELECT;
            }
        }
    }

    (void)lwip_close(sfd);
    (void)pbuf_free(pbuf_resp);
    return LOS_OK;

FAILURE:
    (void)lwip_close(sfd);
    if (pbuf_resp != NULL) {
        (void)pbuf_free(pbuf_resp);
    }

    return LOS_NOK;
}

#ifdef LOSCFG_SHELL
SHELLCMD_ENTRY(ping_shellcmd, CMD_TYPE_EX, "ping", XARGS, (CmdCallBackFunc)osShellPing);
#endif /* LOSCFG_SHELL */

#endif /* LWIP_EXT_POLL_SUPPORT*/

#if LWIP_IPV6
u32_t osShellPing6(int argc, const char **argv)
{
    u16_t icmpv6_id;
    u16_t icmpv6_seq;
    u32_t nsent;
    u32_t nrecieve;
    u32_t last_recieved;
    struct timespec start, end, start_in_reply;
    struct timespec first, last;
    long rtt;
    int ret;
    fd_set fdReadSet;
    void *param = NULL;
    ping6_args_t ping6_params;
    ping6_stats_t ping6_stats;
    struct sockaddr_in6 to;
    struct icmp6_echo_hdr *iecho_resp = NULL;
    struct icmp6_echo_hdr *iecho = NULL;
    struct timeval stTimeVal;
    struct timeval deltaTimeVal;
    struct pbuf *pbuf_resp = NULL;
    struct pbuf *pbuf_req = NULL;
    int sfd = -1;
    u8_t type;
    u8_t select_on_socket = 0;
    char buf[INET6_ADDRSTRLEN];

    if (!tcpip_init_finish) {
        PRINTK("%s: tcpip_init have not been called\n", __FUNCTION__);
        ret = -1;
        goto exit;
    }

    if ((argc < 1) || (argc > LWIP_MAX_PING6_ARG_COUNT) || (argv == NULL)) {
        goto usage;
    }

    ret = parse_args_ping6(argc, argv, &ping6_params);
    if (ret == -1) {
        goto exit;
    }

    if (ping6_params.args_found & LWIP_PING6_SOURCE_ADDRESS_ARG) {
        type = LWIP_PING6_SOURCE_ADDRESS_ARG;
        param = (void *)(&ping6_params.src_addr);
    } else if (ping6_params.args_found & LWIP_PING6_INTERFACE_ARG) {
        type = LWIP_PING6_INTERFACE_ARG;
        param = (void *)(argv[ping6_params.interface_index]);
    } else {
        type = LWIP_PING6_DEFAULT_SOCKET;
        param = NULL;
    }

    /* Create a socket for sending and receiving pings with appropriate bindings */
    sfd = create_ping6_socket(type, param);
    if (sfd == -1) {
        ret = -1;
        goto exit;
    }

    pbuf_req = pbuf_alloc(PBUF_RAW, LWIP_PING6_STANDARD_PKT_SIZE, PBUF_RAM);
    pbuf_resp = pbuf_alloc(PBUF_RAW, LWIP_PING6_STANDARD_PKT_SIZE, PBUF_RAM);
    if ((pbuf_resp == NULL) || (pbuf_req == NULL)) {
        PRINTK("ping6 : Memory Allocation Failed\n");
        ret = -1;
        goto exit;
    }

    to.sin6_family = AF_INET6;
    inet6_addr_from_ip6addr(&to.sin6_addr, &(ping6_params.dst_addr));
    to.sin6_port = htons(IPPROTO_ICMPV6);

#if LWIP_DNS
    if (lwip_strnicmp(inet_ntop(AF_INET6, &to.sin6_addr, buf, sizeof(buf)), argv[ping6_params.host_index],
                      sizeof(to.sin6_addr))) {
        /* If There Was A DNS Resolution */
        PRINTK("PING %s (%s) with %d bytes of data.\n",
               argv[ping6_params.host_index], buf, LWIP_PING6_STANDARD_PKT_SIZE);
    } else {
        PRINTK("PING %s with %d bytes of data.\n", buf, LWIP_PING6_STANDARD_PKT_SIZE);
    }
#else
    PRINTK("PING %s with %d bytes of data\n", inet_ntop(AF_INET6, &to.sin6_addr, buf, sizeof(buf)), LWIP_PING6_STANDARD_PKT_SIZE);
#endif /* LWIP_DNS */

    nrecieve = 0;
    ping6_stats.flag = 0;
    ping6_stats.avg_rtt = 0;
    ping6_stats.max_rtt = 0;
    ping6_stats.min_rtt = 0;
    last_recieved = LWIP_PING6_STARTING_SEQ_NUM + LWIP_PING6_OUT_OF_ORDER_MAGNITUDE + 1;
    icmpv6_id = (u16_t)LWIP_RAND();
    icmpv6_seq = LWIP_PING6_STARTING_SEQ_NUM;
    /* Setting the start time of the entire ping task for statistics */
    (void)clock_gettime(CLOCK_MONOTONIC_RAW, &first);

    nsent = 0;

    for (nsent = 0; nsent < ping6_params.pingcount; nsent++) {
        /* capture the start tick to calculate rtt */
        (void)clock_gettime(CLOCK_MONOTONIC_RAW, &start);
        /* Initialize Memory To Prevent Unintialized Memory Read Write Issues */
        if (memset_s(pbuf_req->payload, pbuf_req->len, (int)(start.tv_nsec), pbuf_req->len) != 0) {
            goto exit;
        }

        iecho = (struct icmp6_echo_hdr *)pbuf_req->payload;
        iecho->type = ICMP6_TYPE_EREQ;
        iecho->id = icmpv6_id;
        icmpv6_seq++;
        iecho->seqno = icmpv6_seq;
        iecho->code = 0;

        /* Embedding the start_tick as data into the icmp_payload */
        (void)pbuf_header(pbuf_req, (s16_t)(-(s16_t)(sizeof(struct icmp6_echo_hdr))));
        if (memcpy_s(pbuf_req->payload, pbuf_req->len, (void *)&start, sizeof(start)) != 0) {
            goto exit;
        }
        (void)pbuf_header(pbuf_req, (s16_t)((s16_t)(sizeof(struct icmp6_echo_hdr))));

        ret = lwip_sendto(sfd, iecho, pbuf_req->len, 0, (struct sockaddr *)&to, (socklen_t)sizeof(to));
        if (ret == -1) {
            PRINTK("ping6 : Sending ICMP Echo message failed\n");
            goto exit;
        }

        /* Wait in select for ICMP response msg */
        FD_ZERO(&fdReadSet);
        FD_SET(sfd, &fdReadSet);
        stTimeVal.tv_sec = LWIP_MSECS_TO_SECS(LWIP_SHELL_CMD_PING_TIMEOUT);
        stTimeVal.tv_usec = 0;
        select_on_socket = 1;

        while (select_on_socket) {
            select_on_socket = 0;
            ret = select(sfd + 1, &fdReadSet, 0, 0, &stTimeVal);
            if (ret < 0) {
                PRINTK("ping6 : select failure\n");
                goto exit;
            } else if (ret == 0) {
                (void)clock_gettime(CLOCK_MONOTONIC_RAW, &end);
                PRINTK("Request timed out\n");
                continue;
            }

            /* capture the end time to calculate round trip time */
            (void)clock_gettime(CLOCK_MONOTONIC_RAW, &end);

            ret = lwip_recv(sfd, pbuf_resp->payload, pbuf_resp->len, 0);
            if (ret == -1) {
                PRINTK("ping6 : receiving ICMP echo response msg failed\n");
                goto exit;
            }

            if ((u32_t)ret < sizeof(struct icmp6_echo_hdr *)) {
                /* Drop the packet if its too short [Doesnot contain even the header !!] */
                PRINTK("ping6 : received ICMP echo response too short\n");
                goto REDUCE_SELECT_TIME;
            }

            /* Acceping the ICMPv6 payload. */
            /* Here, pbuf_resp->payload wont contain IPv6 Header since its an AF_INET6 RAW Socket */
            iecho_resp = (struct icmp6_echo_hdr *)pbuf_resp->payload;

            if (iecho_resp->id == icmpv6_id) {
                if (iecho_resp->type == ICMP6_TYPE_EREP) {
                    if (ret < LWIP_PING6_STANDARD_PKT_SIZE) {
                        /* Drop the packet if its too short */
                        PRINTK("ping6 : received ICMP echo response too short\n");
                        goto REDUCE_SELECT_TIME;
                    }
                    /* Accept and process only those delayed EREP only if its sequence num is within out-of-order magnitude */
                    if (nsent && iecho_resp->seqno != icmpv6_seq &&
                        (iecho_resp->seqno<(u16_t)(last_recieved - LWIP_PING6_OUT_OF_ORDER_MAGNITUDE) ||
                                           iecho_resp->seqno>(u16_t)(
                            last_recieved + LWIP_PING6_OUT_OF_ORDER_MAGNITUDE))) {
                        /* Otherwise drop it and wait for more packets */
                        goto REDUCE_SELECT_TIME;
                    }
                    ++nrecieve;
                    last_recieved = iecho_resp->seqno;
                    /* Retrieving the start_tick from the packet which was embedded when the request was transmitted */
                    (void)pbuf_header(pbuf_resp, (s16_t)(-(s16_t)(sizeof(struct icmp6_echo_hdr))));
                    if (memcpy_s((void *)&start_in_reply, sizeof(start_in_reply),
                                 pbuf_resp->payload, sizeof(start_in_reply)) != EOK) {
                        goto REDUCE_SELECT_TIME;
                    }
                    (void)pbuf_header(pbuf_resp, (s16_t)((s16_t)(sizeof(struct icmp6_echo_hdr))));

                    rtt = ((end.tv_sec - start.tv_sec) * 1000 + (end.tv_nsec - start.tv_nsec) / 1000000);

                    PRINTK("%d bytes from %s : icmp_seq=%d time", ret,
                           inet_ntop(AF_INET6, &to.sin6_addr, buf, sizeof(buf)),
                           ((iecho_resp->seqno) - LWIP_PING6_STARTING_SEQ_NUM));
                    if (rtt < 1) {
                        PRINTK("<1 ms\n");
                    } else {
                        PRINTK("=%i ms\n", rtt);
                    }

                    update_ping6_stats(&ping6_stats, (u32_t)(rtt), nrecieve);

                    /* Checking if its a delayed packet */
                    if ((iecho_resp->seqno != icmpv6_seq) && (nsent < ping6_params.pingcount)) {
                        /* Incase of delayed packet wait on socket for other response before sending a new PING */
                        /* We have to reduce the timeout value now when selecting on socket */
                        goto REDUCE_SELECT_TIME;
                    }
                } else {
                    PRINTK("[%u]ping6 : %s\n", nsent, convert_icmpv6_err_to_string(iecho_resp->type));
                }
            } else {
                /* If incoming packet does not matches with icmp_id, it should be ignored  */
                /* Reduce the timeout for select on socket */
REDUCE_SELECT_TIME:
                deltaTimeVal.tv_sec = (long)(end.tv_sec - start.tv_sec);
                deltaTimeVal.tv_usec = (long)((end.tv_nsec - start.tv_nsec) / 1000);
                /* Subtract deltaTime from stTime and store in stTime */
                /* This will reduce the select time on the socket */
                timersub(&stTimeVal, &deltaTimeVal, &stTimeVal);
                select_on_socket = 1;
            }
        }
    }

    ret = ERR_OK;

    (void)clock_gettime(CLOCK_MONOTONIC_RAW, &last);
    /* Display ping stats */
    PRINTK("--- %s ping statistics ---\n", argv[ping6_params.host_index]);
    PRINTK("%d packets transmitted, %d received, %.2f%% packet loss, time %dms\n",
           nsent, nrecieve, (float)(((float)(nsent - nrecieve)) * ((float)(100)) / ((float)(nsent))),
           ((last.tv_sec - first.tv_sec) * 1000 + (last.tv_nsec - first.tv_nsec) / 1000000));
    if (nrecieve) {
        /* Display rtt stats only if atleast one packet is recieved */
        PRINTK("rtt min/avg/max = %u/%.2f/%u ms\n", ping6_stats.min_rtt, ping6_stats.avg_rtt, ping6_stats.max_rtt);
    }

exit:
    if (sfd != -1) {
        (void)lwip_close(sfd);
    }

    if (pbuf_resp != NULL) {
        (void)pbuf_free(pbuf_resp);
    }

    if (pbuf_req != NULL) {
        (void)pbuf_free(pbuf_req);
    }
    return (u32_t)((ret == (int)ERR_OK) ? LOS_OK : LOS_NOK);

usage:
    PRINTK("Usage:\n");
    PRINTK("\tping6 [-c count] [-I interface/sourceAddress] destination\n");
    return LOS_NOK;
}

LWIP_STATIC int create_ping6_socket(u8_t type, const void *param)
{
    int sfd;
    int ret;
    struct sockaddr_in6 stHostAddr6;
    struct icmp6_filter icmp6_sock_filter;

    sfd = lwip_socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
    if (sfd == -1) {
        PRINTK("ping6 : Failed, socket creation failed\n");
        return -1;
    }

    if (param != NULL) {
        if (type == LWIP_PING6_SOURCE_ADDRESS_ARG) {
            /* Binding socket to the provided source address */
            (void)memset_s(&stHostAddr6, sizeof(stHostAddr6), 0, sizeof(stHostAddr6));
            stHostAddr6.sin6_family = AF_INET6;
            inet6_addr_from_ip6addr(&stHostAddr6.sin6_addr, (ip6_addr_t *)param);
            stHostAddr6.sin6_port = htons(IPPROTO_ICMPV6);
            stHostAddr6.sin6_scope_id = 0;

            ret = lwip_bind(sfd, (struct sockaddr *)&stHostAddr6, sizeof(stHostAddr6));
            if (ret == -1) {
                (void)lwip_close(sfd);
                PRINTK("ping6 : bind icmp socket: cannot assign requested address\n");
                return ret;
            }
        } else if (type == LWIP_PING6_INTERFACE_ARG) {
            /* Binding socket to the provided netif */
            ret = lwip_setsockopt(sfd, SOL_SOCKET, SO_BINDTODEVICE, (char *)(param), strlen((char *)(param)));
            if (ret == -1) {
                (void)lwip_close(sfd);
                PRINTK("ping6: unknown iface %s\n", (char *)(param));
                return ret;
            }
        }
    }

    /* Setting socket filter since we are interested only in ECHO REPLY and ERROR messages */
    ICMP6_FILTER_SETBLOCKALL (&icmp6_sock_filter);
    ICMP6_FILTER_SETPASS (ICMP6_TYPE_EREP, &icmp6_sock_filter);
    ICMP6_FILTER_SETPASS (ICMP6_TYPE_DUR, &icmp6_sock_filter);
    ICMP6_FILTER_SETPASS (ICMP6_TYPE_PTB, &icmp6_sock_filter);
    ICMP6_FILTER_SETPASS (ICMP6_TYPE_TE, &icmp6_sock_filter);

    ret = lwip_setsockopt(sfd, IPPROTO_ICMPV6, ICMP6_FILTER, &icmp6_sock_filter, sizeof(struct icmp6_filter));
    if (ret == -1) {
        (void)lwip_close(sfd);
        PRINTK("ping6 : setsockopt: Invalid Argument\n");
        return -1;
    }

    return sfd;
}

/*
 * Function to parse the command line args for ping6 shell utility
 * @return:
 *   Success: ERR_OK
 *   Failure: -1
 */
LWIP_STATIC int parse_args_ping6(int argc, const char **argv, ping6_args_t *ping6_params)
{
    int pingcount;
    int ret = -1;
#if LWIP_DNS
    struct addrinfo *res = NULL;
    struct addrinfo hints_structure;
#endif
    u8_t i = 0;

    IP6_ADDR(&(ping6_params->dst_addr), 0, 0, 0, 0);
    IP6_ADDR(&(ping6_params->src_addr), 0, 0, 0, 0);

    ping6_params->pingcount = LWIP_SHELL_CMD_PING_RETRY_TIMES;
    ping6_params->host_index = 0;
    ping6_params->args_found = 0;

    while (i < argc) {
        if (strcmp("-c", argv[i]) == 0) {
            /* Handle number of ICMP packets to transmit :: -c [number_of_packets] */
            if (ping6_params->args_found & LWIP_PING6_COUNT_ARG) {
                PRINTK("ping6: -c option present multiple times \n");
                ret = -1;
                goto exit;
            }

            if (i + 2 > argc) {
                PRINTK("ping6: ping count(-c) should require an argument \n");
                ret = -1;
                goto exit;
            }

            pingcount = atoi(argv[i + 1]);
            if (pingcount <= 0) {
                PRINTK("ping6: bad number of packets to transmit \n");
                ret = -1;
                goto exit;
            }

            ping6_params->args_found |= LWIP_PING6_COUNT_ARG;
            ping6_params->pingcount = (u32_t)pingcount;
            i = (u8_t)(i + 2);
        } else if (strcmp("-I", argv[i]) == 0) {
            /* Handle interface ID / sourceAddress using which the ICMP Packets has to be transmitted :: -I [interface_id/source_address] */

            if ((ping6_params->args_found & LWIP_PING6_SOURCE_ADDRESS_ARG) ||
                (ping6_params->args_found & LWIP_PING6_INTERFACE_ARG)) {
                PRINTK("ping6: -I option present multiple times \n");
                ret = -1;
                goto exit;
            }

            if (i + 2 > argc) {
                PRINTK("ping6: interface/source address(-I) should require an argument \n");
                ret = -1;
                goto exit;
            }

            /* Check whether the given argument to -I is source address */
            if (ip6addr_aton(argv[i + 1], &(ping6_params->src_addr))) {
                ping6_params->args_found |= LWIP_PING6_SOURCE_ADDRESS_ARG;
                i = (u8_t)(i + 2);
                continue;
            }

            /* Storing the index where interface name is found */
            /* If this name is not valid, then it will fail later in setsockopt(BIND_TO_DEVICE) */
            ping6_params->interface_index = (u8_t)(i + 1);
            ping6_params->args_found |= LWIP_PING6_INTERFACE_ARG;

            i = (u8_t)(i + 2);
        } else {
            if (argv[i][0] == '-') {
                /* Check whether its a bad option */
                PRINTK("ping6: bad option %s\n", argv[i]);
                ret = -1;
                goto exit;
            } else if (ping6_params->args_found & LWIP_PING6_HOSTNAME_ARG) {
                /* Check whether hostname is already found and there are extra arguments */
                PRINTK("ping6: bad parameter %s\n", argv[i]);
                ret = -1;
                goto exit;
            }

#if LWIP_DNS
            /* Resolve the given hostname */
            hints_structure.ai_family = AF_INET6;
            hints_structure.ai_flags = 0;
            ret = lwip_getaddrinfo(argv[i], NULL, &hints_structure, &res);
            if (ret != ERR_OK) {
                PRINTK("ping6 : Host : %s can't be resolved to IPv6 address\n", argv[i]);
                ret = -1;
                goto exit;
            }

            inet6_addr_to_ip6addr(&(ping6_params->dst_addr),
                                  &(((const struct sockaddr_in6 *)(res->ai_addr))->sin6_addr));
#else
            /* Convert the string representation to network form */
            if (!ip6addr_aton(argv[i], &(ping6_params->dst_addr))) {
                PRINTK("ping6 : Invalid IPv6 Address : %s\n", argv[i]);
                ret = -1;
                goto exit;
            }
#endif /* LWIP_DNS */
            if (ip6_addr_isany(&(ping6_params->dst_addr)) || ip6_addr_isnone(&(ping6_params->dst_addr))) {
#if LWIP_DNS
                PRINTK("ping6 : IPv6 address of host : %s (%s) is invalid\n", argv[i],
                       ip6addr_ntoa((const ip6_addr_t *)&(ping6_params->dst_addr)));
#else
                PRINTK("ping6 : Invalid IPv6 address : %s\n", argv[i]);
#endif /* LWIP_DNS */
                goto exit;
            }
            /* Setting host_index to the index of argv[] where the host/IP is present */
            ping6_params->args_found |= LWIP_PING6_HOSTNAME_ARG;
            ping6_params->host_index = (u8_t)(i);
            i = (u8_t)(i + 1);
        }
    }

    if (!(ping6_params->args_found & LWIP_PING6_HOSTNAME_ARG)) {
        /* Hostname/IPv6 address not found */
        PRINTK("ping6 : Hostname/IPv6 address to ping is not specified\n");
        ret = -1;
        goto exit;
    }

    if (ip6_addr_islinklocal(&(ping6_params->dst_addr)) &&
        !(ping6_params->args_found & (LWIP_PING6_INTERFACE_ARG | LWIP_PING6_SOURCE_ADDRESS_ARG))) {
        /* For link-local addresses, -I is mandatory */
        PRINTK("ping6 : Interface specification is mandatory for link-local addresses\n");
        ret = -1;
        goto exit;
    }

    ret = ERR_OK;

exit:
#if LWIP_DNS
    lwip_freeaddrinfo(res);
#endif /* LWIP_DNS */

    return ret;
}

/*
 * Function to update ping6_stats
 * stats is maintained in ping6_stats structure
 */
LWIP_STATIC void update_ping6_stats(ping6_stats_t *ping6_stats, u32_t rtt, u32_t nrecieved)
{
    if (rtt > ping6_stats->max_rtt) {
        ping6_stats->max_rtt = rtt;
    }

    if (ping6_stats->flag == 0 || rtt < ping6_stats->min_rtt) {
        ping6_stats->min_rtt = rtt;
        ping6_stats->flag = 1;
    }

    ping6_stats->avg_rtt = (float)(ping6_stats->avg_rtt +
                                   (float)((float)((float)rtt - ping6_stats->avg_rtt) / (float)(nrecieved)));
}

LWIP_STATIC const char *convert_icmpv6_err_to_string(u8_t err_type)
{
    switch (err_type) {
        case ICMP6_TYPE_DUR:
            return "Destination Unreachable";
        case ICMP6_TYPE_PTB:
            return "Packet too big";
        case ICMP6_TYPE_TE:
            return "Time Exceeded";
        case ICMP6_TYPE_PP:
            return "Parameter Problem";
        default:
            break;
    }
    return "Unknown Error";
}

#ifdef LOSCFG_SHELL_CMD_DEBUG
SHELLCMD_ENTRY(ping6_shellcmd, CMD_TYPE_EX, "ping6", XARGS, (CmdCallBackFunc)osShellPing6);
#endif /* LOSCFG_SHELL_CMD_DEBUG */
#endif /* LWIP_IPV6 */

#if LWIP_SNTP
u32_t osShellNtpdate(int argc, const char **argv)
{
    int server_num = 0;
    char *ret = NULL;
    struct timeval get_time;
    char buf[50];

    (void)memset_s(&get_time, sizeof(struct timeval), 0, sizeof(struct timeval));

    if (!tcpip_init_finish) {
        PRINTK("%s: tcpip_init have not been called\n", __FUNCTION__);
        return LOS_NOK;
    }

    if (argc < 1 || argv == NULL) {
        goto usage;
    }

    server_num = lwip_sntp_start(argc, (char **)argv, &get_time);
    if (server_num >= 0 && server_num < argc) {
        ret = ctime_r((time_t *)&get_time.tv_sec, buf);
        if (ret != NULL) {
            PRINTK("time server %s: %s\n", argv[server_num], ret);
        } else {
            PRINTK("ctime return null error\n");
        }
    } else {
        PRINTK("no server suitable for synchronization found\n");
    }

    return LOS_OK;

usage:
    PRINTK("\nUsage:\n");
    PRINTK("ntpdate [SERVER_IP1] [SERVER_IP2] ...\n");
    return LOS_NOK;
}

#ifdef LOSCFG_SHELL_CMD_DEBUG
SHELLCMD_ENTRY(ntpdate_shellcmd, CMD_TYPE_EX, "ntpdate", XARGS, (CmdCallBackFunc)osShellNtpdate);
#endif /* LOSCFG_SHELL_CMD_DEBUG */

#endif /* LWIP_SNTP*/


#ifdef LOSCFG_NET_LWIP_SACK_TFTP
static char *TftpError[] = {
    "TFTP transfer finish\n",
    "Error while creating UDP socket\n",
    "Error while binding to the UDP socket\n",
    "Error returned by select() system call\n",
    "Error while receiving data from the peer\n",
    "Error while sending data to the peer\n",
    "Requested file is not found\n",
    "This is the error sent by the server when hostname cannot be resolved\n",
    "Input paramters passed to TFTP interfaces are invalid\n",
    "Error detected in TFTP packet or the error received from the TFTP server\n",
    "Error during packet synhronization while sending or unexpected packet is received\n",
    "File size limit crossed, Max block can be 0xFFFF, each block containing 512 bytes\n",
    "File name lenght greater than 256\n",
    "Hostname IP is not valid\n",
    "TFTP server returned file access error\n",
    "TFTP server returned error signifying that the DISK is full to write\n",
    "TFTP server returned error signifying that the file exist\n",
    "The source file name do not exisits\n",
    "Memory allocaion failed in TFTP client\n",
    "File open failed\n",
    "File read error\n",
    "File create error\n",
    "File write error\n",
    "Max time expired while waiting for file to be recived\n",
    "Error when the received packet is less than 4bytes(error lenght) or greater than 512bytes\n",
    "Returned by TFTP server for protocol user error\n",
    "The destination file path length greater than 256\n",
    "Returned by TFTP server for undefined transfer ID\n",
    "IOCTL fucntion failed at TFTP client while setting the socket to non-block\n",
};

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
#endif

u32_t osShellTftp(int argc, const char **argv)
{
    u32_t ulRemoteAddr = IPADDR_NONE;
    const u16_t usTftpServPort = 69;
    u8_t ucTftpGet = 0;
    s8_t *szLocalFileName = NULL;
    s8_t *szRemoteFileName = NULL;
    u32_t ret;

    int i = 0;
    if (argc < 1 || argv == NULL) {
        goto usage;
    }

    if (!tcpip_init_finish) {
        PRINTK("%s: tcpip_init have not been called\n", __FUNCTION__);
        return LOS_NOK;
    }

    while (i < argc) {
        if (strcmp(argv[i], "-p") == 0) {
            ucTftpGet = 0;
            i++;
            continue;
        }

        if (strcmp(argv[i], "-g") == 0) {
            ucTftpGet = 1;
            i++;
            continue;
        }

        if (strcmp(argv[i], "-l") == 0 && ((i + 1) < argc)) {
            szLocalFileName = (s8_t *)argv[i + 1];
            i += 2;
            continue;
        }

        if (strcmp(argv[i], "-r") == 0 && ((i + 1) < argc)) {
            szRemoteFileName = (s8_t *)argv[i + 1];
            i += 2;
            continue;
        }

        if ((i + 1) == argc) {
            ulRemoteAddr = inet_addr(argv[i]);
            break;
        }

        goto usage;
    }

    if (ulRemoteAddr == IPADDR_NONE || szLocalFileName == NULL || szRemoteFileName == NULL) {
        goto usage;
    }

    if (ucTftpGet) {
        ret = lwip_tftp_get_file_by_filename(ntohl(ulRemoteAddr), usTftpServPort,
                                             TRANSFER_MODE_BINARY, szRemoteFileName, szLocalFileName);
    } else {
        ret = lwip_tftp_put_file_by_filename(ntohl(ulRemoteAddr), usTftpServPort,
                                             TRANSFER_MODE_BINARY, szLocalFileName, szRemoteFileName);
    }

    LWIP_ASSERT("TFTP UNKNOW ERROR!", ret < ARRAY_SIZE(TftpError));
    PRINTK("%s", TftpError[ret]);
    if (ret) {
        return LOS_NOK;
    } else {
        return LOS_OK;
    }
usage:
    PRINTK("usage:\nTransfer a file from/to tftp server\n");
    PRINTK("tftp <-g/-p> -l FullPathLocalFile -r RemoteFile Host\n");
    return LOS_NOK;
}
#ifdef LOSCFG_SHELL_CMD_DEBUG
SHELLCMD_ENTRY(tftp_shellcmd, CMD_TYPE_EX, "tftp", XARGS, (CmdCallBackFunc)osShellTftp);
#endif /* LOSCFG_SHELL_CMD_DEBUG */
#endif /* LOSCFG_NET_LWIP_SACK_TFTP */


#if LWIP_DNS
u32_t osShellDns(int argc, const char **argv)
{
    ip_addr_t dns = {0};
    err_t err;
    int i;
    if (argc < 1 || argv == NULL) {
        goto usage;
    }

    if (tcpip_init_finish == 0) {
        PRINTK("%s: tcpip_init have not been called\n", __FUNCTION__);
        return LOS_NOK;
    }

    if (argc == 1 && (strcmp(argv[0], "-a") == 0)) {
        for (i = 0; i < DNS_MAX_SERVERS; i++) {
            err = lwip_dns_getserver((u8_t)i, &dns);
            if (err == ERR_OK) {
                PRINTK("dns %d: %s\n", i + 1, ipaddr_ntoa_unsafe(&dns));
            } else {
                PRINTK("dns: failed\n");
                return LOS_NOK;
            }
        }
        return LOS_OK;
    } else if (argc == 2) {
        i = atoi(argv[0]);
        if ((i <= 0) || (i > DNS_MAX_SERVERS))
            goto usage;
#if LWIP_IPV6
        if (ip6addr_aton(argv[1], ((ip6_addr_t *)&dns))) {
#if LWIP_IPV4 && LWIP_IPV6
            dns.type = IPADDR_TYPE_V6;
#endif
            if (!ip6_addr_isglobal((ip6_addr_t *)&dns)) {
                PRINTK("ip address<%s> is wrong\n", argv[1]);
                return LOS_NOK;
            }
        } else
#endif
        {
#if LWIP_IPV4
            ((ip4_addr_t *)&dns)->addr = ipaddr_addr(argv[1]);
            if (((ip4_addr_t *)&dns)->addr == IPADDR_NONE) {
                PRINTK("ip address<%s> is wrong\n", argv[1]);
                return LOS_NOK;
            }
#if LWIP_IPV4 && LWIP_IPV6
            dns.type = IPADDR_TYPE_V4;
#endif
#endif
        }

        err = lwip_dns_setserver((u8_t)(i - 1), &dns);
        if (err != ERR_OK) {
            PRINTK("dns : failed\n");
            return LOS_NOK;
        }
        return LOS_OK;
    }
usage:
    PRINTK("usage:\n");
    PRINTK("\tdns <1-%d> <IP>\n", DNS_MAX_SERVERS);
    PRINTK("\tdns -a\n");
    return LOS_NOK;
}

#ifdef LOSCFG_SHELL_CMD_DEBUG
SHELLCMD_ENTRY(dns_shellcmd, CMD_TYPE_EX, "dns", XARGS, (CmdCallBackFunc)osShellDns);
#endif /* LOSCFG_SHELL_CMD_DEBUG */
#endif /* LWIP_DNS */
#if LWIP_IPV6
extern struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS];
#endif
#if LWIP_IPV6
int netstat_get_udp_sendQLen6(struct udp_pcb *udppcb, struct pbuf *udpbuf)
{
    int sendLen = -1;
    u16_t offset = 0, len;
    struct ip6_hdr *iphdr = NULL;
    struct udp_hdr *udphdr = NULL;
    struct ip6_dest_hdr *dest_hdr = NULL;
    struct ip6_frag_hdr *frag_hdr = NULL;
    u8_t nexth;
    u16_t hlen = 0;

    LWIP_ERROR("netstat_get_udp6_sendQLen: NULL pcb received\n", (udppcb != NULL), return -1);
    LWIP_ERROR("netstat_get_udp6_sendQLen: NULL pbuf received\n", (udpbuf != NULL), return -1);

    iphdr = (struct ip6_hdr *)udpbuf->payload;

    if (!(ip6_addr_cmp(&iphdr->dest, ip_2_ip6(&udppcb->remote_ip)) &&
          (ip_addr_isany(&udppcb->local_ip) ||
           ip_get_option(udppcb, SOF_BINDNONUNICAST) ||
           ip6_addr_cmp(&iphdr->src, ip_2_ip6(&udppcb->local_ip))))) {
        goto FUNC_OUT;
    }

    len = IP6_HLEN;
    if (pbuf_header(udpbuf, (s16_t)(-(s16_t)(len)))) {
        goto FUNC_OUT;
    }

    offset = len;

    nexth = IP6H_NEXTH(iphdr);
    while (offset < udpbuf->tot_len) {
        if (nexth == IP6_NEXTH_NONE || nexth == IP6_NEXTH_UDP || nexth == IP6_NEXTH_UDPLITE) {
            break;
        }
        switch (nexth) {
            case IP6_NEXTH_HOPBYHOP:
            case IP6_NEXTH_ROUTING:
                nexth = *((u8_t *)udpbuf->payload);
                hlen = (u16_t)(8 * (1 + *((u8_t *)udpbuf->payload + 1)));
                break;
            case IP6_NEXTH_DESTOPTS:
                nexth = *((u8_t *)udpbuf->payload);
                dest_hdr = (struct ip6_dest_hdr *)udpbuf->payload;
                hlen = (u16_t)(8 * (1 + dest_hdr->_hlen));
                break;
            case IP6_NEXTH_FRAGMENT:
                frag_hdr = (struct ip6_frag_hdr *)udpbuf->payload;
                nexth = frag_hdr->_nexth;
                hlen = IP6_FRAG_HLEN;
                break;
            default:
                /* Unknown next_header */
                goto FUNC_OUT;
        }

        (void)pbuf_header(udpbuf, (s16_t)(-(s16_t)hlen));
        offset = (u16_t)(offset + hlen);
    }

    /* If the while loop test condition failed , then revert the last offset change */
    if (offset >= udpbuf->tot_len) {
        offset = (u16_t)(offset - hlen);
        goto FUNC_OUT;
    }

    LWIP_ERROR("Transport option should be UDP", (nexth == IP6_NEXTH_UDP || nexth == IP6_NEXTH_UDPLITE), goto FUNC_OUT);

    if (offset > iphdr->_plen) {
        goto FUNC_OUT;
    }

    /* check if there is enough space for atleast udp header available */
    if (udpbuf->tot_len < UDP_HLEN) {
        goto FUNC_OUT;
    }

    udphdr = (struct udp_hdr *)udpbuf->payload;
    if ((ntohs(udphdr->dest) == udppcb->remote_port) && (ntohs(udphdr->src) == udppcb->local_port)) {
        if (ntohs(udphdr->len) > UDP_HLEN) {
            sendLen = ntohs(udphdr->len) - UDP_HLEN;
        } else {
            sendLen = udpbuf->tot_len - UDP_HLEN;
        }
    }

FUNC_OUT:
    (void)pbuf_header(udpbuf, (s16_t)offset); // can not cross max limit of s16_t
    return sendLen;
}
#endif

#if LWIP_IPV4
int netstat_get_udp_sendQLen(struct udp_pcb *udppcb, struct pbuf *udpbuf)
{
    int sendLen = -1;
    u16_t offset = 0, len;
    struct ip_hdr *iphdr = NULL;
    struct udp_hdr *udphdr = NULL;

    LWIP_ERROR("netstat_get_udp_sendQLen: NULL pcb received\n", (udppcb != NULL), return -1);
    LWIP_ERROR("netstat_get_udp_sendQLen: NULL pbuf received\n", (udpbuf != NULL), return -1);

    iphdr = (struct ip_hdr *)udpbuf->payload;

    if (!(ip4_addr_cmp(&iphdr->dest, ip_2_ip4(&udppcb->remote_ip)) &&
          (ip_addr_isany(&udppcb->local_ip) ||
           ip_get_option(udppcb, SOF_BINDNONUNICAST) ||
           ip4_addr_cmp(&iphdr->src, ip_2_ip4(&udppcb->local_ip))))) {
        goto FUNC_OUT;
    }
#if LWIP_UDPLITE
    if ((IPH_PROTO(iphdr) != IP_PROTO_UDP) && (IPH_PROTO(iphdr) != IP_PROTO_UDPLITE)) {
#else
    if (IPH_PROTO(iphdr) != IP_PROTO_UDP) {
#endif
        goto FUNC_OUT;
    }

    if ((ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK) != 0) {
        goto FUNC_OUT;
    }

    len = (u16_t)(IPH_HL(iphdr) * 4);
    if (pbuf_header(udpbuf, (s16_t)(-len))) {
        goto FUNC_OUT;
    }

    offset = (u16_t)(offset + len);

    udphdr = (struct udp_hdr *)udpbuf->payload;
    if ((ntohs(udphdr->dest) == udppcb->remote_port) && (ntohs(udphdr->src) == udppcb->local_port)) {
        sendLen = ntohs(udphdr->len) - UDP_HLEN;
    }

FUNC_OUT:
    (void)pbuf_header(udpbuf, (s16_t)offset);
    return sendLen;
}
#endif

int netstat_tcp_recvq(struct tcp_pcb *tpcb)
{
    unsigned int retVal = 0;
#if LWIP_SO_RCVBUF
    struct netconn *conn = NULL;
#endif

    LWIP_ERROR("netstat_tcp_recvq: Received NULL pcb\n", (tpcb != NULL), return 0);

#if LWIP_SO_RCVBUF
    conn = (struct netconn *)tpcb->callback_arg;
    if (conn != NULL) {
        switch (conn->type) {
            case NETCONN_TCP:
            case NETCONN_RAW:
#if LWIP_IPV6
            case NETCONN_RAW_IPV6:
            case NETCONN_UDP_IPV6:
#endif
            case NETCONN_UDP:
                SYS_ARCH_GET(((unsigned int)conn->recv_avail /*+ conn->lrcv_left*/), retVal);
                break;
            default:
                retVal = 0; /* ur... very ugly, damn DHCP DNS and SNTP */
        }
    }
#endif

    return (int)retVal;
}

int netstat_tcp_sendq(struct tcp_pcb *tpcb)
{
    int retVal = 0;
    struct tcp_seg *useg = NULL;

    LWIP_ERROR("netstat_tcp_sendq: Received NULL pcb\n", (tpcb != NULL), return 0);

    for (useg = tpcb->unacked; useg != NULL; useg = useg->next) {
        retVal = retVal + useg->len;
    }

    return retVal;
}

#if LWIP_IPV6
int netstat_udp_sendq6(struct udp_pcb *upcb)
{
    int retLen = 0;
    int ret;
    int idx = 0;
    int i;
#if LWIP_ND6_QUEUEING
    struct nd6_q_entry *neibq = NULL;
#endif

    LWIP_ERROR("netstat_udp_sendq6: Received NULL pcb\n", (upcb != NULL), return 0);

    for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
        if (neighbor_cache[i].state != ND6_NO_ENTRY) {
            if (ip6_addr_cmp(&upcb->remote_ip.u_addr.ip6, &neighbor_cache[i].next_hop_address)) {
                idx = i;
                break;
            }
        }
    }
#if LWIP_ND6_QUEUEING
    for (neibq = neighbor_cache[idx].q; neibq != NULL; neibq = neibq->next) {
        ret = netstat_get_udp_sendQLen6(upcb, neibq->p);
        if (ret >= 0) {
            retLen += ret;
        }
    }
#else
    ret = netstat_get_udp_sendQLen6(upcb, neighbor_cache[idx].q);
    if (ret >= 0) {
      retLen += ret;
    }
#endif
    return retLen;
}
#endif

#if LWIP_IPV4
int netstat_udp_sendq(struct udp_pcb *upcb)
{
    int retLen = 0;
    int ret;
    int arpidx = -1;
    int i;
#if ARP_QUEUEING
    struct etharp_q_entry *arpq = NULL;
#endif

    LWIP_ERROR("netstat_udp_sendq: Received NULL pcb\n", (upcb != NULL), return 0);

    for (i = 0; i < ARP_TABLE_SIZE; ++i) {
        if (arp_table[i].state != ETHARP_STATE_EMPTY) {
            if (ip4_addr_cmp(ip_2_ip4(&upcb->remote_ip), &arp_table[i].ipaddr)) {
                arpidx = i;
                break;
            }
        }
    }

    if (arpidx >= 0) {
#if ARP_QUEUEING
        for (arpq = arp_table[arpidx].q; arpq != NULL; arpq = arpq->next) {
            ret = netstat_get_udp_sendQLen(upcb, arpq->p);
            if (ret > 0) {
                retLen += ret;
                if (retLen <= 0) { // overflow, set rteLen = -1 to indicate
                    retLen = -1;
                    break;
                }
            }
        }
#else
        ret = netstat_get_udp_sendQLen(upcb, arp_table[arpidx].q);
        if (ret > 0) {
          retLen += ret;
          if (retLen <= 0) { // overflow, set rteLen = -1 to indicate
            retLen = -1;
          }
        }
#endif
    }
    return retLen;
}
#endif
int netstat_netconn_recvq(const struct netconn *conn)
{
    unsigned int retVal = 0;

#if LWIP_SO_RCVBUF
    if (conn == NULL) {
        return 0;
    }

    switch (NETCONNTYPE_GROUP((unsigned int)(conn->type))) {
        case NETCONN_TCP:
        case NETCONN_RAW:
#if PF_PKT_SUPPORT
        case NETCONN_PKT_RAW:
#endif
        case NETCONN_UDP:
            SYS_ARCH_GET(((unsigned int)conn->recv_avail /*+ conn->lrcv_left*/), retVal);
            break;
        default:
            retVal = 0; /* ur... very ugly, damn DHCP DNS and SNTP */
    }
#endif
    return (int)retVal;
}

int netstat_netconn_sendq(struct netconn *conn)
{
    int retVal = 0;

    if (conn == NULL) {
        return 0;
    }

    switch (NETCONNTYPE_GROUP((unsigned int)(conn->type))) {
        case NETCONN_TCP:
            retVal = netstat_tcp_sendq(conn->pcb.tcp);
            break;
        case NETCONN_RAW:
            retVal = 0; /* todo */
            break;
#if PF_PKT_SUPPORT
        case NETCONN_PKT_RAW:
            retVal = 0; /* always be 0 as frame send to driver directly */
#endif
            break;
        case NETCONN_UDP:
            retVal = netstat_udp_sendq(conn->pcb.udp);
            break;
        default:
            retVal = 0; /* ur... very ugly, damn DHCP DNS and SNTP */
    }

    return retVal;
}
void netstat_internal(void *ctx)
{
    s8_t local_ip_port[64] = {0};
    s8_t remote_ip_port[64] = {0};
    struct tcp_pcb *tpcb = NULL;
    struct tcp_pcb_listen *lpcb = NULL;
    struct udp_pcb *upcb = NULL;
    struct raw_pcb *rpcb = NULL;
    s8_t *entry_buf = NULL;
    u32_t entry_buf_len;
    u32_t entry_buf_offset;
    struct netstat_data *ndata = (struct netstat_data *)ctx;
    int iRet;
    int recvQlen = 0;
    int sendQlen = 0;
    u_int proto;
#if PF_PKT_SUPPORT
    u8_t netif_name[IFNAMSIZ];
    struct netif *netif = NULL;
#endif

    if (ndata == NULL) {
        return;
    }
    entry_buf = ndata->netstat_out_buf;
    entry_buf_len = ndata->netstat_out_buf_len;
    entry_buf_offset = 0;

    if (entry_buf == NULL) {
        goto out;
    }
    iRet = snprintf_s((char *)(entry_buf + entry_buf_offset), entry_buf_len, entry_buf_len - 1,
                      "========== total sockets %d ======  unused sockets %d ==========\n",
                      LWIP_CONFIG_NUM_SOCKETS, get_unused_socket_num());
    if ((iRet <= 0) || ((u32_t)(iRet) >= entry_buf_len)) {
        goto out;
    }
    entry_buf_len -= (u32_t)(iRet);
    entry_buf_offset += (u32_t)(iRet);

#if LWIP_TCP
    if (tcp_active_pcbs != NULL || tcp_bound_pcbs != NULL || tcp_tw_pcbs != NULL || tcp_listen_pcbs.pcbs != NULL) {
        iRet = snprintf_s((char *)(entry_buf + entry_buf_offset), entry_buf_len, entry_buf_len - 1,
                          "%-8s%-12s%-12s%-24s%-24s%-16s\n",
                          "Proto", "Recv-Q", "Send-Q", "Local Address", "Foreign Address", "State");
        if ((iRet <= 0) || ((u32_t)(iRet) >= entry_buf_len)) {
            goto out;
        }
        entry_buf_len -= (u32_t)(iRet);
        entry_buf_offset += (u32_t)(iRet);

        for (tpcb = tcp_active_pcbs; tpcb != NULL; tpcb = tpcb->next) {
            iRet = snprintf_s((char *)local_ip_port, sizeof(local_ip_port), (sizeof(local_ip_port) - 1),
                              "%s:%d", ipaddr_ntoa(&tpcb->local_ip), tpcb->local_port);
            if ((iRet <= 0) || ((u32_t)(iRet) >= sizeof(local_ip_port))) {
                goto out;
            }

            iRet = snprintf_s((char *)remote_ip_port, sizeof(remote_ip_port), (sizeof(remote_ip_port) - 1),
                              "%s:%d", ipaddr_ntoa(&tpcb->remote_ip), tpcb->remote_port);
            if ((iRet <= 0) || ((u32_t)(iRet) >= sizeof(remote_ip_port))) {
                goto out;
            }
            if (tpcb->state == SYN_RCVD) {
                recvQlen = 0;
                sendQlen = 0;
            } else {
                recvQlen = netstat_netconn_recvq(tpcb->callback_arg);
                sendQlen = netstat_netconn_sendq(tpcb->callback_arg);
            }
            iRet = snprintf_s((char *)(entry_buf + entry_buf_offset), entry_buf_len, entry_buf_len - 1,
                              IP_IS_V6(&tpcb->local_ip) ? "%-8s%-12d%-12d%-39s%-39s%-16s\n" :
                              "%-8s%-12d%-12d%-24s%-24s%-16s\n",
                              IP_IS_V6(&tpcb->local_ip) ? "tcp-ip6" : "tcp",
                              recvQlen, sendQlen, local_ip_port, remote_ip_port, tcp_state_str[tpcb->state]);
            if ((iRet <= 0) || ((u32_t)(iRet) >= entry_buf_len)) {
                goto out;
            }
            entry_buf_len -= (u32_t)(iRet);
            entry_buf_offset += (u32_t)(iRet);
        }

        /* For bound PCBs */
        sendQlen = 0;
        recvQlen = 0;

        for (tpcb = tcp_bound_pcbs; tpcb != NULL; tpcb = tpcb->next) {
            iRet = snprintf_s((char *)local_ip_port, sizeof(local_ip_port), (sizeof(local_ip_port) - 1),
                              "%s:%d", ipaddr_ntoa(&tpcb->local_ip), tpcb->local_port);
            if ((iRet <= 0) || ((u32_t)(iRet) >= sizeof(local_ip_port))) {
                goto out;
            }

            iRet = snprintf_s((char *)remote_ip_port, sizeof(remote_ip_port), (sizeof(remote_ip_port) - 1),
                              "%s:%d", ipaddr_ntoa(&tpcb->remote_ip), tpcb->remote_port);
            if ((iRet <= 0) || ((u32_t)(iRet) >= sizeof(remote_ip_port))) {
                goto out;
            }

            iRet = snprintf_s((char *)(entry_buf + entry_buf_offset), entry_buf_len, entry_buf_len - 1,
                              IP_IS_V6(&tpcb->local_ip) ? "%-8s%-12d%-12d%-39s%-39s%-16s\n" :
                              "%-8s%-12d%-12d%-24s%-24s%-16s\n",
                              IP_IS_V6(&tpcb->local_ip) ? "tcp-ip6" : "tcp",
                              recvQlen, sendQlen, local_ip_port, remote_ip_port, tcp_state_str[tpcb->state]);
            if ((iRet <= 0) || ((u32_t)(iRet) >= entry_buf_len)) {
                goto out;
            }
            entry_buf_len -= (u32_t)(iRet);
            entry_buf_offset += (u32_t)(iRet);
        }

        for (tpcb = tcp_tw_pcbs; tpcb != NULL; tpcb = tpcb->next) {
            iRet = snprintf_s((char *)local_ip_port, sizeof(local_ip_port), (sizeof(local_ip_port) - 1),
                              "%s:%d", ipaddr_ntoa(&tpcb->local_ip), tpcb->local_port);
            if ((iRet <= 0) || ((u32_t)(iRet) >= sizeof(local_ip_port))) {
                goto out;
            }

            iRet = snprintf_s((char *)remote_ip_port, sizeof(remote_ip_port), (sizeof(remote_ip_port) - 1),
                              "%s:%d", ipaddr_ntoa(&tpcb->remote_ip), tpcb->remote_port);
            if ((iRet <= 0) || ((u32_t)(iRet) >= sizeof(remote_ip_port))) {
                goto out;
            }

            recvQlen = netstat_netconn_recvq(tpcb->callback_arg);
            sendQlen = netstat_netconn_sendq(tpcb->callback_arg);
            iRet = snprintf_s((char *)(entry_buf + entry_buf_offset), entry_buf_len, entry_buf_len - 1,
                              IP_IS_V6(&tpcb->local_ip) ? "%-8s%-12d%-12d%-39s%-39s%-16s\n" :
                              "%-8s%-12d%-12d%-24s%-24s%-16s\n",
                              IP_IS_V6(&tpcb->local_ip) ? "tcp-ip6" : "tcp",
                              recvQlen, sendQlen, local_ip_port, remote_ip_port, tcp_state_str[tpcb->state]);
            if ((iRet <= 0) || ((u32_t)(iRet) >= entry_buf_len)) {
                goto out;
            }
            entry_buf_len -= (u32_t)(iRet);
            entry_buf_offset += (u32_t)(iRet);
        }

        /* For listen PCBs */
        recvQlen = 0;
        sendQlen = 0;

        for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
            iRet = snprintf_s((char *)local_ip_port, sizeof(local_ip_port), (sizeof(local_ip_port) - 1),
                              "%s:%d", ipaddr_ntoa(&lpcb->local_ip), lpcb->local_port);
            if ((iRet <= 0) || ((u32_t)(iRet) >= sizeof(local_ip_port))) {
                goto out;
            }

            iRet = snprintf_s((char *)remote_ip_port, sizeof(remote_ip_port), (sizeof(remote_ip_port) - 1),
                              "%s:%d", ipaddr_ntoa(&lpcb->remote_ip), 0);
            if ((iRet <= 0) || ((u32_t)(iRet) >= sizeof(remote_ip_port))) {
                goto out;
            }

            recvQlen = netstat_netconn_recvq(lpcb->callback_arg);

            iRet = snprintf_s((char *)(entry_buf + entry_buf_offset), entry_buf_len, entry_buf_len - 1,
                              IP_IS_V6(&lpcb->local_ip) ? "%-8s%-12d%-12d%-39s%-39s%-16s\n" :
                              "%-8s%-12d%-12d%-24s%-24s%-16s\n",
                              IP_IS_V6(&lpcb->local_ip) ? "tcp-ip6" : "tcp",
                              recvQlen, sendQlen, local_ip_port, remote_ip_port, tcp_state_str[lpcb->state]);
            if ((iRet <= 0) || ((u32_t)(iRet) >= entry_buf_len)) {
                goto out;
            }
            entry_buf_len -= (u32_t)(iRet);
            entry_buf_offset += (u32_t)(iRet);
        }
    }
#endif
#if LWIP_UDP
    if (udp_pcbs != NULL) {
        iRet = snprintf_s((char *)(entry_buf + entry_buf_offset), entry_buf_len, entry_buf_len - 1,
                          "\n%-8s%-12s%-12s%-24s%-24s\n",
                          "Proto", "Recv-Q", "Send-Q", "Local Address", "Foreign Address");
        if ((iRet <= 0) || ((u32_t)(iRet) >= entry_buf_len)) {
            goto out;
        }
        entry_buf_len -= (u32_t)(iRet);
        entry_buf_offset += (u32_t)(iRet);

        for (upcb = udp_pcbs; upcb != NULL; upcb = upcb->next) {
            iRet = snprintf_s((char *)local_ip_port, sizeof(local_ip_port), (sizeof(local_ip_port) - 1),
                              "%s:%d", ipaddr_ntoa(&upcb->local_ip), upcb->local_port);
            if ((iRet <= 0) || ((u32_t)(iRet) >= sizeof(local_ip_port))) {
                goto out;
            }

            iRet = snprintf_s((char *)remote_ip_port, sizeof(remote_ip_port), (sizeof(remote_ip_port) - 1),
                              "%s:%d", ipaddr_ntoa(&upcb->remote_ip), upcb->remote_port);
            if ((iRet <= 0) || ((u32_t)(iRet) >= sizeof(remote_ip_port))) {
                goto out;
            }

            recvQlen = netstat_netconn_recvq(upcb->recv_arg);
#if LWIP_IPV6
            sendQlen = IP_IS_V6(&upcb->local_ip) ? netstat_udp_sendq6(upcb) : netstat_netconn_sendq(upcb->recv_arg);
#else
            sendQlen = netstat_netconn_sendq(upcb->recv_arg);
#endif
            iRet = snprintf_s((char *)(entry_buf + entry_buf_offset), entry_buf_len, entry_buf_len - 1,
                              IP_IS_V6(&upcb->local_ip) ? "%-8s%-12d%-12d%-39s%-39s%-16s\n" :
                              "%-8s%-12d%-12d%-24s%-24s%-16s\n",
                              IP_IS_V6(&upcb->local_ip) ? "udp-ip6" : "udp",
                              recvQlen, sendQlen, local_ip_port, remote_ip_port, " ");
            if ((iRet <= 0) || ((u32_t)(iRet) >= entry_buf_len)) {
                goto out;
            }
            entry_buf_len -= (u32_t)(iRet);
            entry_buf_offset += (u32_t)(iRet);
        }
    }
#endif

#if LWIP_RAW
    if (raw_pcbs != NULL) {
        iRet = snprintf_s((char *)(entry_buf + entry_buf_offset), entry_buf_len, entry_buf_len - 1,
                          "\n%-8s%-12s%-12s%-20s%-20s%-16s%-16s\n",
                          "Type", "Recv-Q", "Send-Q", "Local Address", "Foreign Address", "Protocol", "HDRINCL");
        if ((iRet <= 0) || ((u32_t)(iRet) >= entry_buf_len)) {
            goto out;
        }
        entry_buf_len -= (u32_t)(iRet);
        entry_buf_offset += (u32_t)(iRet);

        for (rpcb = raw_pcbs; rpcb != NULL; rpcb = rpcb->next) {
            iRet = snprintf_s((char *)local_ip_port, sizeof(local_ip_port), (sizeof(local_ip_port) - 1),
                              "%s", ipaddr_ntoa(&rpcb->local_ip));
            if ((iRet <= 0) || ((u32_t)(iRet) >= sizeof(local_ip_port))) {
                goto out;
            }

            iRet = snprintf_s((char *)remote_ip_port, sizeof(remote_ip_port), (sizeof(remote_ip_port) - 1),
                              "%s", ipaddr_ntoa(&rpcb->remote_ip));
            if ((iRet <= 0) || ((u32_t)(iRet) >= sizeof(remote_ip_port))) {
                goto out;
            }

            recvQlen = netstat_netconn_recvq(rpcb->recv_arg);
            sendQlen = netstat_netconn_sendq(rpcb->recv_arg);

            proto = rpcb->protocol;//raw_proto;
            iRet = snprintf_s((char *)(entry_buf + entry_buf_offset), entry_buf_len, entry_buf_len - 1,
                              "%-8s%-12d%-12d%-20s%-20s%-16u%-16d\n",
                              "raw", recvQlen, sendQlen, local_ip_port, remote_ip_port, proto, /*rpcb->hdrincl*/0);
            if ((iRet <= 0) || ((u32_t)(iRet) >= entry_buf_len)) {
                goto out;
            }
            entry_buf_len -= (u32_t)(iRet);
            entry_buf_offset += (u32_t)(iRet);
        }
    }
#if PF_PKT_SUPPORT
    if (pkt_raw_pcbs != NULL) {
        iRet = snprintf_s((char *)(entry_buf + entry_buf_offset), entry_buf_len, entry_buf_len - 1,
                          "\n%-12s%-12s%-12s%-16s%-12s\n", "Type", "Recv-Q", "Send-Q", "Protocol", "netif");
        if ((iRet <= 0) || ((u32_t)(iRet) >= entry_buf_len)) {
            goto out;
        }
        entry_buf_len -= (u32_t)(iRet);
        entry_buf_offset += (u32_t)(iRet);

        for (rpcb = pkt_raw_pcbs; rpcb != NULL; rpcb = rpcb->next) {
            recvQlen = netstat_netconn_recvq(rpcb->recv_arg);
            sendQlen = netstat_netconn_sendq(rpcb->recv_arg);

            for (netif = netif_list; netif != NULL; netif = netif->next) {
                if (netif_get_index(netif)/*netif->ifindex*/ == rpcb->netif_idx/*index*/) {
                    (void)snprintf_s((char *)netif_name, IFNAMSIZ, IFNAMSIZ - 1, "%s", netif_get_name(netif));
                    break;
                }
            }

            if (netif == NULL) {
                (void)snprintf_s((char *)netif_name, IFNAMSIZ, IFNAMSIZ - 1, "%s", "None");
            }

            proto = rpcb->protocol;//ntohs(rpcb->proto.eth_proto);

            iRet = snprintf_s((char *)(entry_buf + entry_buf_offset), entry_buf_len, entry_buf_len - 1,
                              "%-12s%-12d%-12d%-16x%-12s\n", "pkt-raw", recvQlen, sendQlen, proto, netif_name);
            if ((iRet <= 0) || ((u32_t)(iRet) >= entry_buf_len)) {
                goto out;
            }
            entry_buf_len -= (u32_t)(iRet);
            entry_buf_offset += (u32_t)(iRet);
        }
    }
#endif
#endif

out:
    ndata->netstat_out_buf_updated_len = entry_buf_offset;
    sys_sem_signal(&ndata->cb_completed);
    return;
}

u32_t osShellNetstat(int argc, const char **argv)
{
    struct netstat_data ndata;
    err_t err;

    if (argc > 0) {
        PRINTK("\nUsage: netstat\n");
        return LOS_NOK;
    }

    if (tcpip_init_finish == 0) {
        PRINTK("%s: tcpip_init have not been called\n", __FUNCTION__);
        return LOS_NOK;
    }

    ndata.netstat_out_buf = mem_malloc(MAX_NETSTAT_ENTRY);
    if (ndata.netstat_out_buf == NULL) {
        PRINTK("%s: no free mem\n", __FUNCTION__);
        return LOS_NOK;
    }
    ndata.netstat_out_buf_len = MAX_NETSTAT_ENTRY;
    ndata.netstat_out_buf_updated_len = 0;

    if (sys_sem_new(&ndata.cb_completed, 0) != ERR_OK) {
        goto err_hand;
    }

    err = tcpip_callback(netstat_internal, &ndata);
    if (err != ERR_OK) {
        sys_sem_free(&ndata.cb_completed);
        goto err_hand;
    }

    (void)sys_arch_sem_wait(&ndata.cb_completed, 0);
    sys_sem_free(&ndata.cb_completed);
    if ((ndata.netstat_out_buf_updated_len > 0) && (ndata.netstat_out_buf_updated_len < MAX_NETSTAT_ENTRY)) {
        PRINTK("%s\n", (char *)(ndata.netstat_out_buf));
        mem_free(ndata.netstat_out_buf);
        return LOS_OK;
    }

err_hand:
    mem_free(ndata.netstat_out_buf);
    ndata.netstat_out_buf = NULL;
    (void)(argv);
    return LOS_NOK;
}
#ifdef LOSCFG_SHELL
SHELLCMD_ENTRY(netstat_shellcmd, CMD_TYPE_EX, "netstat", XARGS, (CmdCallBackFunc)osShellNetstat);
#endif /* LOSCFG_SHELL */

#define NETIF_NAME_LEN 10
STATIC VOID OsShellDhclientUsage(VOID)
{
    PRINTK("<netif name>,       start dhcp for netif name\n"
           "-x <netif name>,    stop dhcp for netif name\n"
           "-h | --help,        print dhclient command usage\n");
}

u32_t OsShellDhclient(int argc, const char **argv)
{
    struct netif *netif = NULL;

    if (argc == 0) {
        OsShellDhclientUsage();
    } else if (argc == 1) {
        if (strcmp(argv[0], "-h") == 0 || strcmp(argv[0], "--help") == 0) {
            OsShellDhclientUsage();
        } else {
            netif = netif_find(argv[0]);
            if (netif != NULL) {
                (VOID)netifapi_dhcp_start(netif);
            } else {
                PRINTK("dhclient: invalid option: %s\n", argv[0]);
                OsShellDhclientUsage();
            }
        }
    } else if (argc == 2) {
        if (strcmp(argv[0], "-x") == 0) {
            netif = netif_find(argv[1]);
            if (netif != NULL) {
                (VOID)netifapi_dhcp_stop(netif);
            } else {
                PRINTK("dhclient: invalid option: %s\n", argv[1]);
                OsShellDhclientUsage();
            }
        } else {
            PRINTK("dhclient: invalid option: %s\n", argv[0]);
            OsShellDhclientUsage();
        }
    } else {
        OsShellDhclientUsage();
    }

    return 0;
}

#ifdef LOSCFG_SHELL
SHELLCMD_ENTRY(dhclient_shellcmd, CMD_TYPE_EX, "dhclient", XARGS, (CmdCallBackFunc)OsShellDhclient);
#endif /* LOSCFG_SHELL */

#ifdef LWIP_DEBUG_TCPSERVER

#define MAX_SIZE 1024
void tcp_access(int sockfd)
{
    size_t n, i;
    ssize_t ret;
    char msg[MAX_SIZE] = {0};
    while (1) {
        PRINTK("waiting for recv\n");
        (void)memset_s(msg, MAX_SIZE, 0, MAX_SIZE);
        ret = recv(sockfd, msg, MAX_SIZE - 1, 0);
        if (ret < 0) {
            PRINTK("recv failed, %d.\n", (u32_t)ret);
            (void)closesocket(sockfd);
            return;
        } else if (ret == 0) {
            (void)closesocket(sockfd);
            PRINTK("client disconnect.\n");
            return;
        }

        n = strlen(msg);
        for (i = 0; i < n; ++i) {
            if (msg[i] >= 'a' && msg[i] <= 'z') {
                msg[i] = (char)(msg[i] + ('A' - 'a'));
            } else if (msg[i] >= 'A' && msg[i] <= 'Z') {
                msg[i] = (char)(msg[i] + ('a' - 'A'));
            }
        }

        if (send(sockfd, msg, n, 0) < 0) {
            PRINTK("send failed!\r\n");
            continue;
        }
    }
}

u32_t osTcpserver(int argc, const char **argv)
{
    uint16_t port;
    int sockfd = -1;
    int ret;
    struct sockaddr_in seraddr;
    struct sockaddr_in cliaddr;
    u32_t cliaddr_size = (u32_t)sizeof(cliaddr);
    int reuse, iPortVal;

    if (tcpip_init_finish == 0) {
        PRINTK("tcpip_init have not been called\n");
        return LOS_NOK;
    }

    if (argc < 1 || argv == NULL) {
        PRINTK("\nUsage: tcpserver <port>\n");
        return LOS_NOK;
    }

    iPortVal = atoi(argv[0]);
    /* Port 0 not supported , negative values not supported , max port limit is 65535 */
    if (iPortVal <= 0 || iPortVal > 65535) {
        PRINTK("\nUsage: Invalid port\n");
        return LOS_NOK;
    }

    port = (uint16_t)iPortVal;

    /* removed the print of argv[1] as its accessing argv[1] without verifying argc and
     * argv[1] not used anywhere else */
    PRINTK("argv[0]:%s, argc:%d\r\n", argv[0], argc);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        PRINTK("\nUsage: create socket fail!\n");
        return LOS_NOK;
    }
    reuse = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse, sizeof(reuse)) != 0) {
        (void)closesocket(sockfd);
        PRINTK("set SO_REUSEADDR failed\n");
        return LOS_NOK;
    }

    (void)memset_s(&seraddr, sizeof(seraddr), 0, sizeof(seraddr));
    seraddr.sin_family = AF_INET;
    seraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    seraddr.sin_port = htons(port);

    ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));
    if (ret < 0) {
        PRINTK("bind ip and port failed");
        (void)closesocket(sockfd);
        return LOS_NOK;
    }

    ret = listen(sockfd, 5);
    if (ret < 0) {
        (void)closesocket(sockfd);
        PRINTK("listen failed\n");
        return LOS_NOK;
    }
    while (1) {
        PRINTK("waiting for accept\n");
        (void)memset_s(&cliaddr, sizeof(struct sockaddr_in), 0, sizeof(struct sockaddr_in));
        ret = (int)accept(sockfd, (struct sockaddr *)&cliaddr, &cliaddr_size);
        if (ret < 0) {
            (void)closesocket(sockfd);
            PRINTK("Accept failed, %d\n", ret);
            break;
        }
        tcp_access(ret);
    }
    return LOS_NOK;            // Hits Only If Accept Fails
}

#ifdef LOSCFG_SHELL_CMD_DEBUG
SHELLCMD_ENTRY(tcpserver_shellcmd, CMD_TYPE_EX, "tcpserver", XARGS, (CmdCallBackFunc)osTcpserver);
#endif /* LOSCFG_SHELL_CMD_DEBUG */
#endif /* LWIP_DEBUG_TCPSERVER */

#ifdef LWIP_DEBUG_UDPSERVER
void udpserver(int argc, const char **argv)
{
    int sockfd, fromlen;
    int ret, iPortVal;
    struct sockaddr_in seraddr;
    struct sockaddr_in cliaddr;
    size_t n, i;

    char msg[MAX_SIZE] = {0};
    uint16_t port;

    if (argc < 1) {
        PRINTK("\nUsage: udpserver <port>\n");
        return;
    }

    iPortVal = atoi(argv[0]);
    /* Port 0 not supported , negative values not supported , max port limit is 65535 */
    if (iPortVal <= 0 || iPortVal > 65535) {
        PRINTK("\nUsage: Invalid Port\n");
        return;
    }

    port = (uint16_t)iPortVal;

    PRINTK("port:%d\r\n", port);

    sockfd = lwip_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sockfd == -1) {
        PRINTK("\ncreate socket fail\n");
        return;
    }

    (void)memset_s(&seraddr, sizeof(seraddr), 0, sizeof(seraddr));
    (void)memset_s(&cliaddr, sizeof(cliaddr), 0, sizeof(cliaddr));
    seraddr.sin_family = AF_INET;
    seraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    seraddr.sin_port = htons(port);
    ret = lwip_bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));
    if (ret < 0) {
        PRINTK("bind ip and port failed:%d\n", errno);
        (void)closesocket(sockfd);
        return;
    }

    while (1) {
        ret = recvfrom(sockfd, msg, MAX_SIZE - 1, 0, (struct sockaddr *)&cliaddr, (socklen_t *)&fromlen);
        if (ret >= 0) {
            n = strlen(msg);
            for (i = 0; i < n; ++i) {
                if (msg[i] >= 'a' && msg[i] <= 'z') {
                    msg[i] = (char)(msg[i] + 'A' - 'a');
                } else if (msg[i] >= 'A' && msg[i] <= 'Z') {
                    msg[i] = (char)(msg[i] + 'a' - 'A');
                }
            }
            ret = sendto(sockfd, msg, n + 1, 0, (struct sockaddr *)&cliaddr, (socklen_t)fromlen);
            if (ret <= 0 && errno == EPIPE) {
                break;
            }
        } else {
            break;
        }
    }

    (void)closesocket(sockfd);
    return;
}

#ifdef LOSCFG_SHELL_CMD_DEBUG
SHELLCMD_ENTRY(udpserver_shellcmd, CMD_TYPE_EX, "udpserver", XARGS, (CmdCallBackFunc)udpserver);
#endif /* LOSCFG_SHELL_CMD_DEBUG */
#endif /* LWIP_DEBUG_UDPSERVER */

#ifdef LWIP_DEBUG_INFO
LWIP_STATIC
u32_t netdebug_memp(int argc, const char **argv)
{
    u32_t ret = LOS_OK;
    int type;

    if (argc == 2) {
        if (!strcmp("-i", argv[1])) {
            debug_memp_info();
        } else if (!strcmp("-udp", argv[1])) {
            debug_memp_type_info(MEMP_UDP_PCB);
        } else if (!strcmp("-tcp", argv[1])) {
            debug_memp_type_info(MEMP_TCP_PCB);
        } else if (!strcmp("-raw", argv[1])) {
            debug_memp_type_info(MEMP_RAW_PCB);
        } else if (!strcmp("-conn", argv[1])) {
            debug_memp_type_info(MEMP_NETCONN);
        } else {
            ret = LOS_NOK;
        }
    } else if (argc == 3) {
        if (!strcmp("-d", argv[1])) {
            type = atoi(argv[2]);
            if (type >= 0) {
                debug_memp_detail(type);
            } else {
                PRINTK("Error: type < 0\n");
                ret = LOS_NOK;
            }
        } else {
            ret = LOS_NOK;
        }
    } else {
        ret = LOS_NOK;
    }

    return ret;
}

LWIP_STATIC
u32_t netdebug_sock(int argc, const char **argv)
{
    int idx;
    u32_t ret = LOS_NOK;

    if (argc == 2) {
        if (!strcmp("-i", argv[1])) {
            /* netdebug sock -i */
            for (idx = 0; idx < (int)LWIP_CONFIG_NUM_SOCKETS; idx++) {
                debug_socket_info(idx, 1, 0);
            }
            ret = LOS_OK;
        }
    } else if (argc == 3) {
        if (!strcmp("-d", argv[1])) {
            /* netdebug sock -d <idx> */
            idx = atoi(argv[2]);
            if (idx >= 0) {
                debug_socket_info(idx, 1, 1);
                ret = LOS_OK;
            } else {
                PRINTK("Error: idx < 0\n");
            }
        }
    }

    return ret;
}


u32_t osShellNetDebug(int argc, const char **argv)
{
    u32_t ret = LOS_NOK;

    if (argc < 1 || argv == NULL) {
        goto usage;
    }

    if (!strcmp("memp", argv[0])) {
        ret = netdebug_memp(argc, argv);
        if (ret != LOS_OK) {
            goto usage_memp;
        }
    } else if (!strcmp("sock", argv[0])) {
        /* netdebug sock {-i | -d <idx>} */
        ret = netdebug_sock(argc, argv);
        if (ret != LOS_OK) {
            goto usage_sock;
        }
    } else {
        goto usage;
    }
    return ret;

usage:
    /* Cmd help */
    PRINTK("\nUsage:\n");
    PRINTK("netdebug memp {-i | -d <type> | -udp | -tcp | -raw |-conn}\n");
    PRINTK("netdebug sock {-i | -d <idx>}\n");
    return LOS_NOK;

usage_memp:
    /* netdebug memp help */
    PRINTK("\nUsage:\n");
    PRINTK("netdebug memp {-i | -d <type> | -udp | -tcp | -raw |-conn}\n");
    return LOS_NOK;

usage_sock:
    /* netdebug sock help */
    PRINTK("\nUsage:\n");
    PRINTK("netdebug sock {-i | -d <idx>}\n");
    return LOS_NOK;
}
#endif /* LWIP_DEBUG_INFO */

#if defined(LOSCFG_SHELL_CMD_DEBUG) && defined(LWIP_DEBUG_INFO)
SHELLCMD_ENTRY(netdebug_shellcmd, CMD_TYPE_EX, "netdebug", XARGS, (CmdCallBackFunc)osShellNetDebug);
#endif /* LOSCFG_SHELL_CMD_DEBUG && LWIP_DEBUG_INFO */

u32_t osShellIpDebug(int argc, const char **argv)
{
    u8_t i = 0;
    char acIPv6Addr[IP6ADDR_STRLEN_MAX + 1] = {0};
    char aclladdr[20] = {0};
    const char *acStates[] = {"NO_ENTRY", "INCOMPLETE", "REACHABLE", "STALE", "DELAY", "PROBE"};
    u8_t atleastOneEntry = 0;

    if (!tcpip_init_finish) {
        PRINTK("%s: tcpip_init have not been called\n", __FUNCTION__);
        goto exit;
    }

    /* Display prefix */
    PRINTK("=================\n");
    PRINTK("|| Prefix List ||\n");
    PRINTK("=================\n");
    PRINTK("%-50s %-16s %-20s\n", "Prefix", "netif", "validLifetime");
    PRINTK("---------------------------------------------------------------------------------\n");
    /* Display neighbour Cache Entry */
    for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) {
        if (prefix_list[i].netif != NULL && prefix_list[i].invalidation_timer > 0) {
            atleastOneEntry = 1;
            (void)ip6addr_ntoa_r((const ip6_addr_t *)(prefix_list[i].prefix.addr), (acIPv6Addr), INET6_ADDRSTRLEN);
            PRINTK("%-50s ", acIPv6Addr);
            PRINTK("%-16s ", netif_get_name(prefix_list[i].netif));
            PRINTK("%-20u\n", prefix_list[i].invalidation_timer);
        }
    }

    if (!atleastOneEntry) {
        PRINTK("**** NO VALID PREFIXES FOUND CONFIGURED ****\n");
    }
    PRINTK("---------------------------------------------------------------------------------\n");

    atleastOneEntry = 0;

    PRINTK("\n\n");
    PRINTK("============================\n");
    PRINTK("|| Neighbor Cache Entries ||\n");
    PRINTK("============================\n");
    PRINTK("%-50s %-25s %-16s %-15s %-10s\n", "Neighbor", "MAC", "netif", "state", "IsRouter");
    PRINTK("------------------------------------------------------------"
           "----------------------------------------------------------\n");

    /* Display neighbour Cache Entry */
    for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
        if (neighbor_cache[i].state != ND6_NO_ENTRY) {
            atleastOneEntry = 1;
            (void)ip6addr_ntoa_r((const ip6_addr_t *)(neighbor_cache[i].next_hop_address.addr), (acIPv6Addr),
                                 INET6_ADDRSTRLEN);
            PRINTK("%-50s ", acIPv6Addr);

            if (snprintf_s(aclladdr, sizeof(aclladdr), sizeof(aclladdr) - 1, "%02X:%02X:%02X:%02X:%02X:%02X",
                           neighbor_cache[i].lladdr[0], neighbor_cache[i].lladdr[1], neighbor_cache[i].lladdr[2],
                           neighbor_cache[i].lladdr[3], neighbor_cache[i].lladdr[4], neighbor_cache[i].lladdr[5]) < 0) {
                return LOS_NOK;
            }
            PRINTK("%-25s ", aclladdr);
            PRINTK("%-16s ", netif_get_name(neighbor_cache[i].netif));
            PRINTK("%-15s ", acStates[neighbor_cache[i].state]);
            PRINTK("%-10s\n", (neighbor_cache[i].isrouter ? "Yes" : "No"));
        }
    }
    if (!atleastOneEntry) {
        PRINTK("**** NO NEIGHBOURS FOUND ****\n");
    }
    PRINTK("------------------------------------------------------------"
           "----------------------------------------------------------\n");

    atleastOneEntry = 0;

    PRINTK("\n\n");
    PRINTK("===============================\n");
    PRINTK("|| Destination Cache Entries ||\n");
    PRINTK("===============================\n");
    PRINTK("%-50s %-50s %-10s %-10s\n", "Destination", "NextHop", "PMTU", "age");
    PRINTK("------------------------------------------------------------"
           "--------------------------------------------------------\n");
    /* Display destination Cache Entry */
    for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) {
        if (!ip6_addr_isany(&(destination_cache[i].destination_addr))) {
            atleastOneEntry = 1;
            (void)ip6addr_ntoa_r((const ip6_addr_t *)(destination_cache[i].destination_addr.addr), (acIPv6Addr),
                                 INET6_ADDRSTRLEN);
            PRINTK("%-50s ", acIPv6Addr);
            (void)ip6addr_ntoa_r((const ip6_addr_t *)(destination_cache[i].next_hop_addr.addr), (acIPv6Addr),
                                 INET6_ADDRSTRLEN);
            PRINTK("%-50s ", acIPv6Addr);
            PRINTK("%-10u ", destination_cache[i].pmtu);
            PRINTK("%-10u\n", destination_cache[i].age);
        }
    }
    if (!atleastOneEntry) {
        PRINTK("**** NO DESTINATION CACHE FOUND ****\n");
    }
    PRINTK("------------------------------------------------------------"
           "--------------------------------------------------------\n");

    atleastOneEntry = 0;
    PRINTK("\n\n");
    PRINTK("============================\n");
    PRINTK("|| Default Router Entries ||\n");
    PRINTK("============================\n");
    PRINTK("%-50s %-20s %-10s\n", "Router", "invalidation_timer", "flags");
    PRINTK("-----------------------------------------------------------------------------\n");
    /* Display Default Router Cache Entry */
    for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) {
        if (default_router_list[i].neighbor_entry) {
            atleastOneEntry = 1;
            (void)ip6addr_ntoa_r((const ip6_addr_t *)((default_router_list[i].neighbor_entry)->next_hop_address.addr),
                                 (acIPv6Addr), INET6_ADDRSTRLEN);
            PRINTK("%-50s ", acIPv6Addr);
            PRINTK("%-20u ", default_router_list[i].invalidation_timer);
            PRINTK("%-10u\n", default_router_list[i].flags);
        }
    }
    if (!atleastOneEntry) {
        PRINTK("**** NO DEFAULT ROUTERS FOUND ****\n");
    }
    PRINTK("-----------------------------------------------------------------------------\n");

exit:
    return LOS_OK;
}

#ifdef LOSCFG_SHELL_CMD_DEBUG
SHELLCMD_ENTRY(ipdebug_shellcmd, CMD_TYPE_EX, "ipdebug", XARGS, (CmdCallBackFunc)osShellIpDebug);
#endif
#ifdef LWIP_TESTBED
extern void cmd_reset(void);

void osShellReboot(int argc, const char **argv)
{
    cmd_reset();
}

#ifdef LOSCFG_SHELL_CMD_DEBUG
SHELLCMD_ENTRY(reboot_shellcmd, CMD_TYPE_EX, "reboot", XARGS, (CmdCallBackFunc)osShellReboot);
#endif /* LOSCFG_SHELL_CMD_DEBUG */
#endif

#endif //LWIP_ENABLE_LOS_SHELL_CMD
