/* * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. * Copyright (c) 2020-2021 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 #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 #include "limits.h" #include #include #include #include #include #include #include "lwip/api_shell.h" #include "lwip/dns.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 nreceived); 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 cache the print 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 (buf_len < 1) { goto out; } 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] "\ "\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 happened. 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, print to the telnet socket will result in system */ /* deadlock.so don't do it. cache the data to print to a buf, and when */ /* callback returns, then print 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; if (buf_len < 1) { return; } 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, ðaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY); } else { ret = ERR_RTE; } } else { ret = etharp_add_static_entry(&ipaddr, ðaddr); } #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), "Succeeded\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\n"); } 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: unknown 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: NONE or ANY\n"); 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 : NONE or ANY\n"); 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_received; 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_received = 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 Uninitialized 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 [Doesn't 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 won't 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_received - LWIP_PING6_OUT_OF_ORDER_MAGNITUDE) || iecho_resp->seqno>(u16_t)( last_received + LWIP_PING6_OUT_OF_ORDER_MAGNITUDE))) { /* Otherwise drop it and wait for more packets */ goto REDUCE_SELECT_TIME; } ++nrecieve; last_received = 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)) { /* In case 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 at least one packet is received */ 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: unknownn 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 nreceived) { 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)(nreceived))); } 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*/ #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> \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) || 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 at least 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) || 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; 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(", start dhcp for netif name\n" "-x , 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 \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 \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 = 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 } */ 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 | -udp | -tcp | -raw |-conn}\n"); PRINTK("netdebug sock {-i | -d }\n"); return LOS_NOK; usage_memp: /* netdebug memp help */ PRINTK("\nUsage:\n"); PRINTK("netdebug memp {-i | -d | -udp | -tcp | -raw |-conn}\n"); return LOS_NOK; usage_sock: /* netdebug sock help */ PRINTK("\nUsage:\n"); PRINTK("netdebug sock {-i | -d }\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), sizeof(acIPv6Addr)); 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), sizeof(acIPv6Addr)); 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), sizeof(acIPv6Addr)); PRINTK("%-50s ", acIPv6Addr); (void)ip6addr_ntoa_r((const ip6_addr_t *)(destination_cache[i].next_hop_addr.addr), (acIPv6Addr), sizeof(acIPv6Addr)); 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), sizeof(acIPv6Addr)); 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