• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  * Description: netstat shell cmd API implementation
15  * Author: none
16  * Create: 2020
17  */
18 
19 #include "lwip/nettool/netstat.h"
20 #include "lwip/sockets.h"
21 #include "lwip/priv/nd6_priv.h"
22 #include "lwip/ip.h"
23 #include "lwip/tcpip.h"
24 #include "lwip/priv/tcp_priv.h"
25 #include "lwip/api.h"
26 #include "lwip/prot/udp.h"
27 #include "lwip/udp.h"
28 #include "lwip/etharp.h"
29 #include "lwip/raw.h"
30 #include "lwip/priv/api_msg.h"
31 #include "lwip/nettool/utility.h"
32 #if LWIP_LITEOS_COMPAT
33 #include "los_config.h"
34 #endif
35 
36 #ifdef CUSTOM_AT_COMMAND
37 #include "soc_at.h"
38 typedef enum netstat_trans_type {
39   TCP_IP6,
40   TCP,
41   UDP_IP6,
42   UDP,
43   RAW,
44   PKT_RAW,
45 } netstat_trans_type;
46 #endif
47 
48 #if LWIP_ENABLE_BASIC_SHELL_CMD
49 
50 #define MAX_PRINT_SIZE 128
51 
52 #define NETSTAT_ENTRY_SIZE 120
53 #define MAX_NETSTAT_ENTRY (NETSTAT_ENTRY_SIZE * (MEMP_NUM_TCP_PCB + MEMP_NUM_UDP_PCB + MEMP_NUM_TCP_PCB_LISTEN + 1))
54 
55 struct netstat_data {
56   s8_t *netstat_out_buf;
57   u32_t netstat_out_buf_len;
58   u32_t netstat_out_buf_updated_len;
59   sys_sem_t cb_completed;
60 };
61 
62 #if LWIP_IPV6
63 
64 extern struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS];
65 
66 int
netstat_get_udp_sendq_len6(struct udp_pcb * udppcb,struct pbuf * udpbuf)67 netstat_get_udp_sendq_len6(struct udp_pcb *udppcb, struct pbuf *udpbuf)
68 {
69   int send_len = -1;
70   u16_t offset = 0;
71   u16_t len;
72   struct ip6_hdr *iphdr = NULL;
73   struct udp_hdr *udphdr = NULL;
74   struct ip6_dest_hdr *dest_hdr = NULL;
75   struct ip6_frag_hdr *frag_hdr = NULL;
76   u8_t nexth;
77   u16_t hlen = 0;
78 
79   LWIP_ERROR("netstat_get_udp6_sendQLen: NULL pcb received"CRLF, (udppcb != NULL), return -1);
80   LWIP_ERROR("netstat_get_udp6_sendQLen: NULL pbuf received"CRLF, (udpbuf != NULL), return -1);
81 
82   iphdr = (struct ip6_hdr *)udpbuf->payload;
83   LWIP_ERROR("netstat_get_udp6_sendQLen: NULL iphdr received"CRLF, (iphdr != NULL), return -1);
84   if (!(ip6_addr_cmp_zoneless(&iphdr->dest, ip_2_ip6(&udppcb->remote_ip)) &&
85         (ip_addr_isany(&udppcb->local_ip) ||
86          ip_get_option(udppcb, SOF_BINDNONUNICAST) ||
87          ip6_addr_cmp_zoneless(&iphdr->src, ip_2_ip6(&udppcb->local_ip))))) {
88     goto FUNC_OUT;
89   }
90 
91   len = IP6_HLEN;
92   if (pbuf_header(udpbuf, (s16_t)(-(s16_t)(len)))) {
93     goto FUNC_OUT;
94   }
95 
96   offset = len;
97 
98   nexth = IP6H_NEXTH(iphdr);
99   while (offset < udpbuf->tot_len) {
100     if ((nexth == IP6_NEXTH_NONE) || (nexth == IP6_NEXTH_UDP) || (nexth == IP6_NEXTH_UDPLITE)) {
101       break;
102     }
103     switch (nexth) {
104       case IP6_NEXTH_HOPBYHOP:
105       case IP6_NEXTH_ROUTING:
106         nexth = *((u8_t *)udpbuf->payload);
107         /* 8 : hlen will Multiply by 8 in ipv6 option segment */
108         hlen = 8 * (1 + (u16_t)*((u8_t *)udpbuf->payload + 1));
109         break;
110       case IP6_NEXTH_DESTOPTS:
111         nexth = *((u8_t *)udpbuf->payload);
112         dest_hdr = (struct ip6_dest_hdr *)udpbuf->payload;
113         /* 8 : hlen will Multiply by 8 in ipv6 option segment */
114         hlen = 8 * (1 + (u16_t)dest_hdr->_hlen);
115         break;
116       case IP6_NEXTH_FRAGMENT:
117         frag_hdr = (struct ip6_frag_hdr *)udpbuf->payload;
118         nexth = frag_hdr->_nexth;
119         hlen = IP6_FRAG_HLEN;
120         break;
121       default:
122         /* Unknown next_header */
123         goto FUNC_OUT;
124     }
125 
126     (void)pbuf_header(udpbuf, (s16_t)(-(s16_t)hlen));
127     offset = (u16_t)(offset + hlen);
128   }
129 
130   /* If the while loop test condition failed , then revert the last offset change */
131   if (offset >= udpbuf->tot_len) {
132     offset = (u16_t)(offset - hlen);
133     goto FUNC_OUT;
134   }
135 
136   LWIP_ERROR("Transport option should be UDP", (nexth == IP6_NEXTH_UDP || nexth == IP6_NEXTH_UDPLITE), goto FUNC_OUT);
137 
138   if (offset > iphdr->_plen) {
139     goto FUNC_OUT;
140   }
141 
142   /* check if there is enough space for atleast udp header available */
143   if (udpbuf->tot_len < UDP_HLEN) {
144     goto FUNC_OUT;
145   }
146 
147   udphdr = (struct udp_hdr *)udpbuf->payload;
148   if ((ntohs(udphdr->dest) == udppcb->remote_port) && (ntohs(udphdr->src) == udppcb->local_port)) {
149     if (ntohs(udphdr->len) > UDP_HLEN) {
150       send_len = ntohs(udphdr->len) - UDP_HLEN;
151     } else {
152       send_len = udpbuf->tot_len - UDP_HLEN;
153     }
154   }
155 
156 FUNC_OUT:
157   (void)pbuf_header(udpbuf, (s16_t)offset); // canot not cross max limit of s16_t
158   return send_len;
159 }
160 #endif
161 
162 #if LWIP_IPV4
163 int
netstat_get_udp_sendq_len(struct udp_pcb * udppcb,struct pbuf * udpbuf)164 netstat_get_udp_sendq_len(struct udp_pcb *udppcb, struct pbuf *udpbuf)
165 {
166   int send_len = -1;
167   u16_t offset = 0;
168   u16_t len;
169   struct ip_hdr *iphdr = NULL;
170   struct udp_hdr *udphdr = NULL;
171 
172   LWIP_ERROR("netstat_get_udp_sendQLen: NULL pcb received"CRLF, (udppcb != NULL), return -1);
173   LWIP_ERROR("netstat_get_udp_sendQLen: NULL pbuf received"CRLF, (udpbuf != NULL), return -1);
174 
175   iphdr = (struct ip_hdr *)udpbuf->payload;
176 
177   if (!(ip4_addr_cmp(&iphdr->dest, ip_2_ip4(&udppcb->remote_ip))
178         && (ip_addr_isany(&udppcb->local_ip) ||
179             ip_get_option(udppcb, SOF_BINDNONUNICAST) ||
180             ip4_addr_cmp(&iphdr->src, ip_2_ip4(&udppcb->local_ip))))) {
181     goto FUNC_OUT;
182   }
183 #if LWIP_UDPLITE
184   if ((IPH_PROTO(iphdr) != IP_PROTO_UDP) && (IPH_PROTO(iphdr) != IP_PROTO_UDPLITE))
185 #else
186   if (IPH_PROTO(iphdr) != IP_PROTO_UDP)
187 #endif
188   {
189     goto FUNC_OUT;
190   }
191 
192   if ((ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK) != 0) {
193     goto FUNC_OUT;
194   }
195 
196   len = (u16_t)(IPH_HL(iphdr) * 4); /* 4: IP Header Length Multiply by 4 */
197   if (pbuf_header(udpbuf, (s16_t)(-len))) {
198     goto FUNC_OUT;
199   }
200 
201   offset = (u16_t)(offset + len);
202 
203   udphdr = (struct udp_hdr *)udpbuf->payload;
204   if ((ntohs(udphdr->dest) == udppcb->remote_port) && (ntohs(udphdr->src) == udppcb->local_port)) {
205     send_len = ntohs(udphdr->len) - UDP_HLEN;
206   }
207 
208 FUNC_OUT:
209   (void)pbuf_header(udpbuf, (s16_t)offset);
210   return send_len;
211 }
212 #endif
213 
214 int
netstat_tcp_recvq(struct tcp_pcb * tpcb)215 netstat_tcp_recvq(struct tcp_pcb *tpcb)
216 {
217   unsigned int ret_val = 0;
218 #if LWIP_SO_RCVBUF
219   struct netconn *conn = NULL;
220 #endif
221 
222   LWIP_ERROR("netstat_tcp_recvq: Received NULL pcb"CRLF, (tpcb != NULL), return 0);
223 
224 #if LWIP_SO_RCVBUF
225   conn = (struct netconn *)tpcb->callback_arg;
226   if (conn != NULL) {
227     switch (conn->type) {
228       case NETCONN_TCP:
229       case NETCONN_RAW:
230 #if LWIP_IPV6
231       case NETCONN_RAW_IPV6:
232       case NETCONN_UDP_IPV6:
233 #endif
234       case NETCONN_UDP:
235         SYS_ARCH_GET(((unsigned int)conn->recv_avail + conn->lrcv_left), ret_val);
236         break;
237       default:
238         ret_val = 0; /* ur... very ugly, damn DHCP DNS and SNTP */
239     }
240   }
241 #endif
242 
243   return (int)ret_val;
244 }
245 
246 int
netstat_tcp_sendq(struct tcp_pcb * tpcb)247 netstat_tcp_sendq(struct tcp_pcb *tpcb)
248 {
249   int ret_val = 0;
250   struct tcp_seg *useg = NULL;
251 
252   LWIP_ERROR("netstat_tcp_sendq: Received NULL pcb"CRLF, (tpcb != NULL), return 0);
253 
254   for (useg = tpcb->unacked; useg != NULL; useg = useg->next) {
255     ret_val = ret_val + useg->len;
256   }
257 
258   return ret_val;
259 }
260 
261 #if LWIP_IPV6
262 int
netstat_udp_sendq6(struct udp_pcb * upcb)263 netstat_udp_sendq6(struct udp_pcb *upcb)
264 {
265   int ret_len = 0;
266   int idx = 0;
267   int i, ret;
268 #if LWIP_ND6_QUEUEING
269   struct nd6_q_entry *neibq = NULL;
270 #endif
271 
272   LWIP_ERROR("netstat_udp_sendq6: Received NULL pcb"CRLF, (upcb != NULL), return 0);
273 
274   for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
275     if (neighbor_cache[i].state != ND6_NO_ENTRY) {
276       if (ip6_addr_cmp(&upcb->remote_ip.u_addr.ip6, &neighbor_cache[i].next_hop_address)) {
277         idx = i;
278         break;
279       }
280     }
281   }
282 #if LWIP_ND6_QUEUEING
283   for (neibq = neighbor_cache[idx].q; neibq != NULL; neibq = neibq->next) {
284     if (neibq->p == NULL) {
285       return 0;
286     }
287     ret = netstat_get_udp_sendq_len6(upcb, neibq->p);
288     if (ret >= 0) {
289       ret_len += ret;
290     }
291   }
292 #else
293   ret = netstat_get_udp_sendq_len6(upcb, neighbor_cache[idx].q);
294   if (ret >= 0) {
295     ret_len += ret;
296   }
297 #endif
298   return ret_len;
299 }
300 #endif
301 
302 #if LWIP_IPV4
303 int
netstat_udp_sendq(struct udp_pcb * upcb)304 netstat_udp_sendq(struct udp_pcb *upcb)
305 {
306   int ret_len = 0;
307   int arpidx = -1;
308   int i, ret;
309 #if ARP_QUEUEING
310   struct etharp_q_entry *arpq = NULL;
311 #endif
312 
313   LWIP_ERROR("netstat_udp_sendq: Received NULL pcb"CRLF, (upcb != NULL), return 0);
314 
315   for (i = 0; i < ARP_TABLE_SIZE; ++i) {
316     if (arp_table[i].state != ETHARP_STATE_EMPTY) {
317       if (ip4_addr_cmp(ip_2_ip4(&upcb->remote_ip), &arp_table[i].ipaddr)) {
318         arpidx = i;
319         break;
320       }
321     }
322   }
323 
324   if (arpidx >= 0) {
325 #if ARP_QUEUEING
326     for (arpq = arp_table[arpidx].q; arpq != NULL; arpq = arpq->next) {
327       ret = netstat_get_udp_sendq_len(upcb, arpq->p);
328       if (ret <= 0) {
329         continue;
330       }
331       ret_len += ret;
332       if (ret_len <= 0) { // overflow, set rteLen = -1 to indicate
333         ret_len = -1;
334         break;
335       }
336     }
337 #else
338     ret = netstat_get_udp_sendq_len(upcb, arp_table[arpidx].q);
339     if (ret > 0) {
340       ret_len += ret;
341       if (ret_len <= 0) { // overflow, set rteLen = -1 to indicate
342         ret_len = -1;
343       }
344     }
345 #endif
346   }
347   return ret_len;
348 }
349 #endif
350 int
netstat_netconn_recvq(const struct netconn * conn)351 netstat_netconn_recvq(const struct netconn *conn)
352 {
353   unsigned int ret_val = 0;
354 
355 #if LWIP_SO_RCVBUF
356   if (conn == NULL) {
357     return 0;
358   }
359 
360   switch (NETCONNTYPE_GROUP(conn->type)) {
361     case NETCONN_TCP:
362     case NETCONN_RAW:
363 #if PF_PKT_SUPPORT
364     case NETCONN_PKT_RAW:
365 #endif
366     case NETCONN_UDP:
367       SYS_ARCH_GET(((unsigned int)conn->recv_avail + conn->lrcv_left), ret_val);
368       break;
369     default:
370       ret_val = 0; /* ur... very ugly, damn DHCP DNS and SNTP */
371   }
372 #else
373   (void)conn;
374 #endif
375   return (int)ret_val;
376 }
377 int
netstat_netconn_sendq(struct netconn * conn)378 netstat_netconn_sendq(struct netconn *conn)
379 {
380   int ret_val;
381 
382   if (conn == NULL) {
383     return 0;
384   }
385 
386   switch (NETCONNTYPE_GROUP(conn->type)) {
387     case NETCONN_TCP:
388       ret_val = netstat_tcp_sendq(conn->pcb.tcp);
389       break;
390     case NETCONN_RAW:
391       ret_val = 0;
392       break;
393 #if PF_PKT_SUPPORT
394     case NETCONN_PKT_RAW:
395       ret_val = 0; /* always be 0 as frame send to driver directly */
396       break;
397 #endif
398     case NETCONN_UDP:
399       ret_val = netstat_udp_sendq(conn->pcb.udp);
400       break;
401     default:
402       ret_val = 0; /* ur... very ugly, damn DHCP DNS and SNTP */
403   }
404 
405   return ret_val;
406 }
407 
408 #ifndef CUSTOM_AT_COMMAND
409 #if PF_PKT_SUPPORT
410 static s32_t
print_netstat_pkt_raw(struct netstat_data * ndata,u32_t * entry_buf_offset)411 print_netstat_pkt_raw(struct netstat_data *ndata, u32_t *entry_buf_offset)
412 {
413   u8_t netif_name[NETIF_NAMESIZE];
414   struct netif *netif = NULL;
415   s8_t *entry_buf = ndata->netstat_out_buf;
416   u32_t entry_buf_len = ndata->netstat_out_buf_len;
417   int recv_qlen, send_qlen, i_ret;
418   u_int proto;
419   struct raw_pcb *rpcb = NULL;
420   if (entry_buf == NULL) {
421     return ERR_VAL;
422   }
423   if (pkt_raw_pcbs != NULL) {
424     i_ret = snprintf_s((char *)(entry_buf + (*entry_buf_offset)), entry_buf_len, entry_buf_len - 1,
425                        "\n%-12s%-12s%-12s%-16s%-12s"CRLF, "Type", "Recv-Q", "Send-Q", "Protocol", "netif");
426     if ((i_ret <= 0) || ((u32_t)(i_ret) >= entry_buf_len)) {
427       return ERR_VAL;
428     }
429     entry_buf_len -= (u32_t)(i_ret);
430     (*entry_buf_offset) += (u32_t)(i_ret);
431 
432     for (rpcb = pkt_raw_pcbs; rpcb != NULL; rpcb = rpcb->next) {
433       recv_qlen = netstat_netconn_recvq(rpcb->recv_arg);
434       send_qlen = netstat_netconn_sendq(rpcb->recv_arg);
435       for (netif = netif_list; netif != NULL; netif = netif->next) {
436         if (netif->ifindex != rpcb->netifindex) {
437           continue;
438         }
439         i_ret = snprintf_s((char *)netif_name, NETIF_NAMESIZE, NETIF_NAMESIZE - 1, "%s%u", netif->name, netif->num);
440         if ((i_ret <= 0) || ((u32_t)(i_ret) >= NETIF_NAMESIZE)) {
441           return ERR_VAL;
442         }
443         break;
444       }
445 
446       if (netif == NULL) {
447         (void)snprintf_s((char *)netif_name, NETIF_NAMESIZE, NETIF_NAMESIZE - 1, "%s", "None");
448       }
449 
450       proto = ntohs(rpcb->proto.eth_proto);
451 
452       i_ret = snprintf_s((char *)(entry_buf + (*entry_buf_offset)), entry_buf_len, entry_buf_len - 1,
453                          "%-12s%-12d%-12d%-16x%-12s"CRLF, "pkt-raw", recv_qlen, send_qlen, proto, netif_name);
454       if ((i_ret <= 0) || ((u32_t)(i_ret) >= entry_buf_len)) {
455         return ERR_VAL;
456       }
457       entry_buf_len -= (u32_t)(i_ret);
458       (*entry_buf_offset) += (u32_t)(i_ret);
459     }
460   }
461   ndata->netstat_out_buf_len = entry_buf_len;
462   return ERR_OK;
463 }
464 #endif
465 
466 #if LWIP_RAW
467 static s32_t
print_netstat_raw(struct netstat_data * ndata,u32_t * entry_buf_offset)468 print_netstat_raw(struct netstat_data *ndata, u32_t *entry_buf_offset)
469 {
470   struct raw_pcb *rpcb = NULL;
471   s8_t local_ip_port[64] = {0};
472   s8_t remote_ip_port[64] = {0};
473   s8_t *entry_buf = ndata->netstat_out_buf;
474   u32_t entry_buf_len = ndata->netstat_out_buf_len;
475   int recv_qlen, send_qlen, i_ret;
476   if (entry_buf == NULL) {
477     return ERR_VAL;
478   }
479   if (raw_pcbs != NULL) {
480     char buf[IPADDR_STRLEN_MAX];
481     i_ret = snprintf_s((char *)(entry_buf + (*entry_buf_offset)), entry_buf_len, entry_buf_len - 1,
482                        "\n%-8s%-12s%-12s%-20s%-20s%-16s%-16s"CRLF,
483                        "Type", "Recv-Q", "Send-Q", "Local Address", "Foreign Address", "Protocol", "HDRINCL");
484     if ((i_ret <= 0) || ((u32_t)(i_ret) >= entry_buf_len)) {
485       return ERR_VAL;
486     }
487     entry_buf_len -= (u32_t)(i_ret);
488     (*entry_buf_offset) += (u32_t)(i_ret);
489 
490     for (rpcb = raw_pcbs; rpcb != NULL; rpcb = rpcb->next) {
491       (void)ipaddr_ntoa_r(&rpcb->local_ip, buf, IPADDR_STRLEN_MAX);
492       i_ret = snprintf_s((char *)local_ip_port, sizeof(local_ip_port), (sizeof(local_ip_port) - 1), "%s",
493                          buf);
494       if ((i_ret <= 0) || ((u32_t)(i_ret) >= sizeof(local_ip_port))) {
495         return ERR_VAL;
496       }
497       (void)ipaddr_ntoa_r(&rpcb->remote_ip, buf, IPADDR_STRLEN_MAX);
498       i_ret = snprintf_s((char *)remote_ip_port, sizeof(remote_ip_port), (sizeof(remote_ip_port) - 1), "%s",
499                          buf);
500       if ((i_ret <= 0) || ((u32_t)(i_ret) >= sizeof(remote_ip_port))) {
501         return ERR_VAL;
502       }
503 
504       recv_qlen = netstat_netconn_recvq(rpcb->recv_arg);
505       send_qlen = netstat_netconn_sendq(rpcb->recv_arg);
506       i_ret = snprintf_s((char *)(entry_buf + (*entry_buf_offset)), entry_buf_len, entry_buf_len - 1,
507                          "%-8s%-12d%-12d%-20s%-20s%-16u%-16d"CRLF, "raw",
508                          recv_qlen, send_qlen, local_ip_port, remote_ip_port,
509                          rpcb->raw_proto, raw_is_flag_set(rpcb, RAW_FLAGS_HDRINCL));
510       if ((i_ret <= 0) || ((u32_t)(i_ret) >= entry_buf_len)) {
511         return ERR_VAL;
512       }
513       entry_buf_len -= (u32_t)(i_ret);
514       (*entry_buf_offset) += (u32_t)(i_ret);
515     }
516   }
517   ndata->netstat_out_buf_len = entry_buf_len;
518 #if PF_PKT_SUPPORT
519   s32_t pkt_ret = print_netstat_pkt_raw(ndata, entry_buf_offset);
520   if (pkt_ret == ERR_VAL) {
521     return ERR_VAL;
522   }
523 #endif
524   return ERR_OK;
525 }
526 #endif
527 #endif
528 
529 #if LWIP_UDP
530 static s32_t
print_netstat_udp(struct netstat_data * ndata,u32_t * entry_buf_offset)531 print_netstat_udp(struct netstat_data *ndata, u32_t *entry_buf_offset)
532 {
533   s8_t local_ip_port[64] = {0};
534   s8_t remote_ip_port[64] = {0};
535   struct udp_pcb *upcb = NULL;
536   s8_t *entry_buf = ndata->netstat_out_buf;
537   u32_t entry_buf_len = ndata->netstat_out_buf_len;
538   int recv_qlen, send_qlen, i_ret;
539   if (entry_buf == NULL) {
540     return ERR_VAL;
541   }
542   if (udp_pcbs != NULL) {
543     char buf[IPADDR_STRLEN_MAX];
544 #ifndef CUSTOM_AT_COMMAND
545     i_ret = snprintf_s((char *)(entry_buf + (*entry_buf_offset)), entry_buf_len, entry_buf_len - 1,
546                        "\n%-8s%-12s%-12s%-24s%-24s"CRLF, "Proto", "Recv-Q", "Send-Q",
547                        "Local Address", "Foreign Address");
548     if ((i_ret <= 0) || ((u32_t)(i_ret) >= entry_buf_len)) {
549       return ERR_VAL;
550     }
551     entry_buf_len -= (u32_t)(i_ret);
552     (*entry_buf_offset) += (u32_t)(i_ret);
553 #endif
554 
555     for (upcb = udp_pcbs; upcb != NULL; upcb = upcb->next) {
556       (void)ipaddr_ntoa_r(&upcb->local_ip, buf, IPADDR_STRLEN_MAX);
557       i_ret = snprintf_s((char *)local_ip_port, sizeof(local_ip_port), (sizeof(local_ip_port) - 1), "%s:%d",
558                          buf, upcb->local_port);
559       if ((i_ret <= 0) || ((u32_t)(i_ret) >= sizeof(local_ip_port))) {
560         return ERR_VAL;
561       }
562 
563       (void)ipaddr_ntoa_r(&upcb->remote_ip, buf, IPADDR_STRLEN_MAX);
564       i_ret = snprintf_s((char *)remote_ip_port, sizeof(remote_ip_port), (sizeof(remote_ip_port) - 1), "%s:%d",
565                          buf, upcb->remote_port);
566       if ((i_ret <= 0) || ((u32_t)(i_ret) >= sizeof(remote_ip_port))) {
567         return ERR_VAL;
568       }
569 
570       recv_qlen = (upcb->recv == recv_udp) ? netstat_netconn_recvq(upcb->recv_arg) : 0;
571 #if LWIP_IPV6
572       send_qlen = IP_IS_V6(&upcb->local_ip) ? netstat_udp_sendq6(upcb) : netstat_udp_sendq(upcb);
573 #else
574       send_qlen = netstat_udp_sendq(upcb);
575 #endif
576       if (entry_buf_len <= 1) {
577         return ERR_VAL;
578       }
579 #ifdef CUSTOM_AT_COMMAND
580       /* Proto 2:udp-ip6; 3:udp */
581       i_ret = snprintf_s((char *)(entry_buf + (*entry_buf_offset)), entry_buf_len, entry_buf_len - 1,
582                          "+NETSTAT:%d,%d,%d,%s,%s,%d"CRLF,
583                          (IP_IS_V6(&upcb->local_ip) ? UDP_IP6 : UDP), recv_qlen, send_qlen, local_ip_port,
584                          remote_ip_port, 0);
585 #else
586       i_ret = snprintf_s((char *)(entry_buf + (*entry_buf_offset)), entry_buf_len, entry_buf_len - 1,
587                          (IP_IS_V6(&upcb->local_ip) ? "%-8s%-12d%-12d%-39s%-39s%-16s\n" :
588                           "%-8s%-12d%-12d%-24s%-24s%-16s"CRLF),
589                          IP_IS_V6(&upcb->local_ip) ? "udp-ip6" : "udp",
590                          recv_qlen, send_qlen, local_ip_port, remote_ip_port, " ");
591 #endif
592       if ((i_ret <= 0) || ((u32_t)(i_ret) >= entry_buf_len)) {
593         return ERR_VAL;
594       }
595       entry_buf_len -= (u32_t)(i_ret);
596       (*entry_buf_offset) += (u32_t)(i_ret);
597     }
598   }
599   ndata->netstat_out_buf_len = entry_buf_len;
600   return ERR_OK;
601 }
602 #endif
603 
604 #if LWIP_TCP
605 static s32_t
print_netstat_tcp(struct netstat_data * ndata,u32_t * entry_buf_offset)606 print_netstat_tcp(struct netstat_data *ndata, u32_t *entry_buf_offset)
607 {
608   s8_t local_ip_port[64] = {0};
609   s8_t remote_ip_port[64] = {0};
610   struct tcp_pcb *tpcb = NULL;
611   u16_t remote_port;
612   s8_t *entry_buf = ndata->netstat_out_buf;
613   u32_t entry_buf_len = ndata->netstat_out_buf_len;
614   int recv_qlen, send_qlen, i_ret;
615   if (entry_buf == NULL) {
616     return ERR_VAL;
617   }
618   if ((tcp_active_pcbs == NULL) && (tcp_bound_pcbs == NULL) &&
619       (tcp_tw_pcbs == NULL) && (tcp_listen_pcbs.pcbs == NULL)) {
620     return ERR_OK;
621   }
622 #ifndef CUSTOM_AT_COMMAND
623   i_ret = snprintf_s((char *)(entry_buf + (*entry_buf_offset)), entry_buf_len, entry_buf_len - 1,
624                      "%-8s%-12s%-12s%-24s%-24s%-16s"CRLF,
625                      "Proto", "Recv-Q", "Send-Q", "Local Address", "Foreign Address", "State");
626   if ((i_ret <= 0) || ((u32_t)(i_ret) >= entry_buf_len)) {
627     return ERR_VAL;
628   }
629   entry_buf_len -= (u32_t)(i_ret);
630   (*entry_buf_offset) += (u32_t)(i_ret);
631 #endif
632 
633   int i;
634   char buf[IPADDR_STRLEN_MAX];
635   for (i = 0; i < NUM_TCP_PCB_LISTS; i++) {
636     struct tcp_pcb *pcblist = *tcp_pcb_lists[i];
637     for (tpcb = pcblist; tpcb != NULL; tpcb = tpcb->next) {
638       /* DON'T access a tcp_pcb's remote_port if it's casted from a tcp_pcb_listen */
639       remote_port = (pcblist == tcp_listen_pcbs.pcbs) ? 0 : tpcb->remote_port;
640       (void)ipaddr_ntoa_r(&tpcb->local_ip, buf, IPADDR_STRLEN_MAX);
641       i_ret = snprintf_s((char *)local_ip_port, sizeof(local_ip_port), (sizeof(local_ip_port) - 1), "%s:%u",
642                          buf, tpcb->local_port);
643       if ((i_ret <= 0) || ((u32_t)(i_ret) >= sizeof(local_ip_port))) {
644         return ERR_VAL;
645       }
646       (void)ipaddr_ntoa_r(&tpcb->remote_ip, buf, IPADDR_STRLEN_MAX);
647       i_ret = snprintf_s((char *)remote_ip_port, sizeof(remote_ip_port), (sizeof(remote_ip_port) - 1), "%s:%u",
648                          buf, remote_port);
649       if ((i_ret <= 0) || ((u32_t)(i_ret) >= sizeof(remote_ip_port))) {
650         return ERR_VAL;
651       }
652 
653       if (pcblist == tcp_bound_pcbs) {
654         send_qlen = 0;
655         recv_qlen = 0;
656       } else if (pcblist == tcp_listen_pcbs.pcbs) {
657         recv_qlen = netstat_netconn_recvq(tpcb->callback_arg);
658         send_qlen = 0;
659       } else {
660         recv_qlen = (tpcb->state == SYN_RCVD) ? 0 : netstat_netconn_recvq(tpcb->callback_arg);
661         send_qlen = (tpcb->state == SYN_RCVD) ? 0 : netstat_netconn_sendq(tpcb->callback_arg);
662       }
663 
664 #ifdef CUSTOM_AT_COMMAND
665       /* Proto 0:tcp-ip6; 1:tcp .State for tcp_state_str */
666       i_ret = snprintf_s((char *)(entry_buf + (*entry_buf_offset)), entry_buf_len, entry_buf_len - 1,
667                          "+NETSTAT:%d,%d,%d,%s,%s,%d"CRLF,
668                          (IP_IS_V6(&tpcb->local_ip) ? TCP_IP6 : TCP), recv_qlen, send_qlen, local_ip_port,
669                          remote_ip_port, tpcb->state);
670 #else
671       i_ret = snprintf_s((char *)(entry_buf + (*entry_buf_offset)), entry_buf_len, entry_buf_len - 1,
672                          (IP_IS_V6(&tpcb->local_ip) ? "%-8s%-12d%-12d%-39s%-39s%-16s"CRLF :
673                           "%-8s%-12d%-12d%-24s%-24s%-16s"CRLF),
674                          IP_IS_V6(&tpcb->local_ip) ? "tcp-ip6" : "tcp",
675                          recv_qlen, send_qlen, local_ip_port, remote_ip_port, tcp_state_str[tpcb->state]);
676 #endif
677       if ((i_ret <= 0) || ((u32_t)(i_ret) >= entry_buf_len)) {
678         return ERR_VAL;
679       }
680       entry_buf_len -= (u32_t)(i_ret);
681       (*entry_buf_offset) += (u32_t)(i_ret);
682     }
683   }
684 
685   ndata->netstat_out_buf_len = entry_buf_len;
686   return ERR_OK;
687 }
688 #endif
689 
690 void
netstat_internal(void * ctx)691 netstat_internal(void *ctx)
692 {
693   s8_t *entry_buf = NULL;
694   u32_t entry_buf_offset = 0;
695   struct netstat_data *ndata = (struct netstat_data *)ctx;
696   entry_buf = ndata->netstat_out_buf;
697 
698   if (entry_buf == NULL) {
699     goto out;
700   }
701 
702 #ifndef CUSTOM_AT_COMMAND
703   int i_ret;
704   i_ret = snprintf_s((char *)(entry_buf), ndata->netstat_out_buf_len, ndata->netstat_out_buf_len - 1,
705                      "========== total sockets %d ======  unused sockets %d =========="CRLF, LWIP_CONFIG_NUM_SOCKETS,
706                      get_unused_socket_num());
707   if ((i_ret <= 0) || ((u32_t)(i_ret) >= ndata->netstat_out_buf_len)) {
708     goto out;
709   }
710   ndata->netstat_out_buf_len -= (u32_t)(i_ret);
711   entry_buf_offset = (u32_t)(i_ret);
712 #endif
713 #if LWIP_TCP
714   s32_t tcp_ret = print_netstat_tcp(ndata, &entry_buf_offset);
715   if (tcp_ret == ERR_VAL) {
716     goto out;
717   }
718 #endif
719 #if LWIP_UDP
720   s32_t udp_ret = print_netstat_udp(ndata, &entry_buf_offset);
721   if (udp_ret == ERR_VAL) {
722     goto out;
723   }
724 #endif
725 #ifndef CUSTOM_AT_COMMAND
726 #if LWIP_RAW
727   s32_t raw_ret = print_netstat_raw(ndata, &entry_buf_offset);
728   if (raw_ret == ERR_VAL) {
729     goto out;
730   }
731 #endif
732 #endif
733 out:
734   ndata->netstat_out_buf_updated_len = entry_buf_offset;
735   sys_sem_signal(&ndata->cb_completed);
736   return;
737 }
738 
739 static void
print_netstat_out_buf_updated_len(struct netstat_data * ndata)740 print_netstat_out_buf_updated_len(struct netstat_data *ndata)
741 {
742   u32_t print_len = 0;
743   char print_out_buff[MAX_PRINT_SIZE] = {0};
744   if (ndata->netstat_out_buf_updated_len < MAX_PRINT_SIZE) {
745 #ifdef CUSTOM_AT_COMMAND
746     (void)uapi_at_printf("%s", (char *)(ndata->netstat_out_buf));
747 #else
748     LWIP_PLATFORM_PRINT("%s"CRLF, (char *)(ndata->netstat_out_buf));
749 #endif
750   } else {
751     do {
752       (void)memset_s(print_out_buff, sizeof(print_out_buff), 0x0, sizeof(print_out_buff));
753       (void)memcpy_s(print_out_buff, sizeof(print_out_buff) - 1, ndata->netstat_out_buf + print_len,
754                      sizeof(print_out_buff) - 1);
755 #ifdef CUSTOM_AT_COMMAND
756       (void)uapi_at_printf("%s", print_out_buff);
757 #else
758        LWIP_PLATFORM_PRINT("%s", print_out_buff);
759 #endif
760        ndata->netstat_out_buf_updated_len -= sizeof(print_out_buff) - 1;
761        print_len += sizeof(print_out_buff) - 1;
762     } while (ndata->netstat_out_buf_updated_len >= (MAX_PRINT_SIZE - 1));
763 
764     if (ndata->netstat_out_buf_updated_len > 0) {
765 #ifdef CUSTOM_AT_COMMAND
766       (void)uapi_at_printf("%s", (char *)(ndata->netstat_out_buf + print_len));
767 #else
768        LWIP_PLATFORM_PRINT("%s", (char *)(ndata->netstat_out_buf + print_len));
769 #endif
770     }
771     LWIP_PLATFORM_PRINT(CRLF);
772   }
773 #ifdef CUSTOM_AT_COMMAND
774   (void)uapi_at_printf("OK"CRLF);
775 #endif
776 }
777 
778 u32_t
os_shell_netstat(int argc,const char ** argv)779 os_shell_netstat(int argc, const char **argv)
780 {
781   struct netstat_data ndata;
782   err_t err;
783 
784   if (argc > 0) {
785     PRINT_ERRCODE(API_SHELL_ERRCODE_USAGE);
786     return OS_NOK;
787   }
788 
789   if (tcpip_init_finish == 0) {
790     PRINT_ERRCODE(API_SHELL_ERRCODE_TCPIP_UNINTED);
791     return OS_NOK;
792   }
793   (void)memset_s(&ndata, sizeof(struct netstat_data), 0, sizeof(struct netstat_data));
794   ndata.netstat_out_buf = mem_malloc(MAX_NETSTAT_ENTRY);
795   if (ndata.netstat_out_buf == NULL) {
796     PRINT_ERRCODE(API_SHELL_ERRCODE_MEM_ERR);
797     return OS_NOK;
798   }
799   ndata.netstat_out_buf_len = MAX_NETSTAT_ENTRY;
800   ndata.netstat_out_buf_updated_len = 0;
801 
802   if (sys_sem_new(&ndata.cb_completed, 0) != ERR_OK) {
803     goto err_hand;
804   }
805 
806   err = tcpip_callback(netstat_internal, &ndata);
807   if (err != ERR_OK) {
808     sys_sem_free(&ndata.cb_completed);
809     goto err_hand;
810   }
811 
812   (void)sys_arch_sem_wait(&ndata.cb_completed, 0);
813   sys_sem_free(&ndata.cb_completed);
814   if ((ndata.netstat_out_buf_updated_len > 0) && (ndata.netstat_out_buf_updated_len < MAX_NETSTAT_ENTRY)) {
815     print_netstat_out_buf_updated_len(&ndata);
816     mem_free(ndata.netstat_out_buf);
817     return OS_OK;
818   } else if (ndata.netstat_out_buf_updated_len >= MAX_NETSTAT_ENTRY) {
819     goto err_hand;
820   } else {
821 #ifdef CUSTOM_AT_COMMAND
822     (void)uapi_at_printf("OK"CRLF);
823 #endif
824     mem_free(ndata.netstat_out_buf);
825     return OS_OK;
826   }
827 
828 err_hand:
829   mem_free(ndata.netstat_out_buf);
830   ndata.netstat_out_buf = NULL;
831   (void)(argv);
832   return OS_NOK;
833 }
834 
835 #endif /* LWIP_ENABLE_BASIC_SHELL_CMD */
836