1 /*
2  * Copyright (c) 2016 Intel Corporation
3  * Copyright (c) 2023 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_DECLARE(net_shell);
10 
11 #include "net_shell_private.h"
12 
13 #if defined(CONFIG_NET_TCP)
14 #include "tcp_internal.h"
15 #include <zephyr/sys/slist.h>
16 #endif
17 
18 #if defined(CONFIG_NET_OFFLOAD) || defined(CONFIG_NET_NATIVE)
context_cb(struct net_context * context,void * user_data)19 static void context_cb(struct net_context *context, void *user_data)
20 {
21 #if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4)
22 #define ADDR_LEN NET_IPV6_ADDR_LEN
23 #elif defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
24 #define ADDR_LEN NET_IPV4_ADDR_LEN
25 #else
26 #define ADDR_LEN NET_IPV6_ADDR_LEN
27 #endif
28 	struct net_shell_user_data *data = user_data;
29 	const struct shell *sh = data->sh;
30 	int *count = data->user_data;
31 	/* +7 for []:port */
32 	char addr_local[ADDR_LEN + 7];
33 	char addr_remote[ADDR_LEN + 7] = "";
34 
35 	get_addresses(context, addr_local, sizeof(addr_local),
36 		      addr_remote, sizeof(addr_remote));
37 
38 	PR("[%2d] %p\t%d      %c%c%c   %16s\t%16s\n",
39 	   (*count) + 1, context,
40 	   net_if_get_by_iface(net_context_get_iface(context)),
41 	   net_context_get_family(context) == AF_INET6 ? '6' :
42 	   (net_context_get_family(context) == AF_INET ? '4' : ' '),
43 	   net_context_get_type(context) == SOCK_DGRAM ? 'D' :
44 	   (net_context_get_type(context) == SOCK_STREAM ? 'S' :
45 	    (net_context_get_type(context) == SOCK_RAW ? 'R' : ' ')),
46 	   net_context_get_proto(context) == IPPROTO_UDP ? 'U' :
47 	   (net_context_get_proto(context) == IPPROTO_TCP ? 'T' : ' '),
48 	   addr_local, addr_remote);
49 
50 	(*count)++;
51 }
52 #endif /* CONFIG_NET_OFFLOAD || CONFIG_NET_NATIVE */
53 
54 #if CONFIG_NET_CONN_LOG_LEVEL >= LOG_LEVEL_DBG
conn_handler_cb(struct net_conn * conn,void * user_data)55 static void conn_handler_cb(struct net_conn *conn, void *user_data)
56 {
57 #if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4)
58 #define ADDR_LEN NET_IPV6_ADDR_LEN
59 #elif defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
60 #define ADDR_LEN NET_IPV4_ADDR_LEN
61 #else
62 #define ADDR_LEN NET_IPV6_ADDR_LEN
63 #endif
64 	struct net_shell_user_data *data = user_data;
65 	const struct shell *sh = data->sh;
66 	int *count = data->user_data;
67 	/* +7 for []:port */
68 	char addr_local[ADDR_LEN + 7];
69 	char addr_remote[ADDR_LEN + 7] = "";
70 
71 	if (IS_ENABLED(CONFIG_NET_IPV6) && conn->local_addr.sa_family == AF_INET6) {
72 		snprintk(addr_local, sizeof(addr_local), "[%s]:%u",
73 			 net_sprint_ipv6_addr(
74 				 &net_sin6(&conn->local_addr)->sin6_addr),
75 			 ntohs(net_sin6(&conn->local_addr)->sin6_port));
76 		snprintk(addr_remote, sizeof(addr_remote), "[%s]:%u",
77 			 net_sprint_ipv6_addr(
78 				 &net_sin6(&conn->remote_addr)->sin6_addr),
79 			 ntohs(net_sin6(&conn->remote_addr)->sin6_port));
80 
81 	} else if (IS_ENABLED(CONFIG_NET_IPV4) && conn->local_addr.sa_family == AF_INET) {
82 		snprintk(addr_local, sizeof(addr_local), "%s:%d",
83 			 net_sprint_ipv4_addr(
84 				 &net_sin(&conn->local_addr)->sin_addr),
85 			 ntohs(net_sin(&conn->local_addr)->sin_port));
86 		snprintk(addr_remote, sizeof(addr_remote), "%s:%d",
87 			 net_sprint_ipv4_addr(
88 				 &net_sin(&conn->remote_addr)->sin_addr),
89 			 ntohs(net_sin(&conn->remote_addr)->sin_port));
90 
91 	} else if (conn->local_addr.sa_family == AF_UNSPEC) {
92 		snprintk(addr_local, sizeof(addr_local), "AF_UNSPEC");
93 	} else {
94 		snprintk(addr_local, sizeof(addr_local), "AF_UNK(%d)",
95 			 conn->local_addr.sa_family);
96 	}
97 
98 	PR("[%2d] %p %p\t%s\t%16s\t%16s\n",
99 	   (*count) + 1, conn, conn->cb,
100 	   net_proto2str(conn->local_addr.sa_family, conn->proto),
101 	   addr_local, addr_remote);
102 
103 	(*count)++;
104 }
105 #endif /* CONFIG_NET_CONN_LOG_LEVEL >= LOG_LEVEL_DBG */
106 
107 #if CONFIG_NET_TCP_LOG_LEVEL >= LOG_LEVEL_DBG
108 struct tcp_detail_info {
109 	int printed_send_queue_header;
110 	int printed_details;
111 	int count;
112 };
113 #endif
114 
115 #if defined(CONFIG_NET_TCP) && \
116 	(defined(CONFIG_NET_OFFLOAD) || defined(CONFIG_NET_NATIVE))
tcp_cb(struct tcp * conn,void * user_data)117 static void tcp_cb(struct tcp *conn, void *user_data)
118 {
119 	struct net_shell_user_data *data = user_data;
120 	const struct shell *sh = data->sh;
121 	int *count = data->user_data;
122 	uint16_t recv_mss = net_tcp_get_supported_mss(conn);
123 
124 	PR("%p %p   %5u    %5u %10u %10u %5u   %s\n",
125 	   conn, conn->context,
126 	   ntohs(net_sin6_ptr(&conn->context->local)->sin6_port),
127 	   ntohs(net_sin6(&conn->context->remote)->sin6_port),
128 	   conn->seq, conn->ack, recv_mss,
129 	   net_tcp_state_str(net_tcp_get_state(conn)));
130 
131 	(*count)++;
132 }
133 
134 #if CONFIG_NET_TCP_LOG_LEVEL >= LOG_LEVEL_DBG
tcp_sent_list_cb(struct tcp * conn,void * user_data)135 static void tcp_sent_list_cb(struct tcp *conn, void *user_data)
136 {
137 	struct net_shell_user_data *data = user_data;
138 	const struct shell *sh = data->sh;
139 	struct tcp_detail_info *details = data->user_data;
140 	struct net_pkt *pkt;
141 	sys_snode_t *node;
142 
143 	if (conn->state != TCP_LISTEN) {
144 		if (!details->printed_details) {
145 			PR("\nTCP        Ref  Recv_win Send_win Pending "
146 			   "Unacked Flags Queue\n");
147 			details->printed_details = true;
148 		}
149 
150 		PR("%p   %ld    %u\t %u\t  %zd\t  %d\t  %d/%d/%d %s\n",
151 		   conn, atomic_get(&conn->ref_count), conn->recv_win,
152 		   conn->send_win, conn->send_data_total, conn->unacked_len,
153 		   conn->in_retransmission, conn->in_connect, conn->in_close,
154 		   sys_slist_is_empty(&conn->send_queue) ? "empty" : "data");
155 
156 		details->count++;
157 	}
158 
159 	if (sys_slist_is_empty(&conn->send_queue)) {
160 		return;
161 	}
162 
163 	if (!details->printed_send_queue_header) {
164 		PR("\nTCP packets waiting ACK:\n");
165 		PR("TCP             net_pkt[ref/totlen]->net_buf[ref/len]..."
166 		   "\n");
167 	}
168 
169 	PR("%p      ", conn);
170 
171 	node = sys_slist_peek_head(&conn->send_queue);
172 	if (node) {
173 		pkt = CONTAINER_OF(node, struct net_pkt, next);
174 		if (pkt) {
175 			struct net_buf *frag = pkt->frags;
176 
177 			if (!details->printed_send_queue_header) {
178 				PR("%p[%ld/%zd]", pkt,
179 				   atomic_get(&pkt->atomic_ref),
180 				   net_pkt_get_len(pkt));
181 				details->printed_send_queue_header = true;
182 			} else {
183 				PR("                %p[%ld/%zd]",
184 				   pkt, atomic_get(&pkt->atomic_ref),
185 				   net_pkt_get_len(pkt));
186 			}
187 
188 			if (frag) {
189 				PR("->");
190 			}
191 
192 			while (frag) {
193 				PR("%p[%d/%d]", frag, frag->ref, frag->len);
194 
195 				frag = frag->frags;
196 				if (frag) {
197 					PR("->");
198 				}
199 			}
200 
201 			PR("\n");
202 		}
203 	}
204 
205 	details->printed_send_queue_header = true;
206 }
207 #endif /* CONFIG_NET_TCP_LOG_LEVEL >= LOG_LEVEL_DBG */
208 #endif /* TCP */
209 
cmd_net_conn(const struct shell * sh,size_t argc,char * argv[])210 static int cmd_net_conn(const struct shell *sh, size_t argc, char *argv[])
211 {
212 	ARG_UNUSED(argc);
213 	ARG_UNUSED(argv);
214 
215 #if defined(CONFIG_NET_OFFLOAD) || defined(CONFIG_NET_NATIVE)
216 	struct net_shell_user_data user_data;
217 	int count = 0;
218 
219 	PR("     Context   \tIface  Flags            Local             Remote\n");
220 
221 	user_data.sh = sh;
222 	user_data.user_data = &count;
223 
224 	net_context_foreach(context_cb, &user_data);
225 
226 	if (count == 0) {
227 		PR("No connections\n");
228 	}
229 
230 #if CONFIG_NET_CONN_LOG_LEVEL >= LOG_LEVEL_DBG
231 	PR("\n     Handler    Callback  \tProto\tLocal           \tRemote\n");
232 
233 	count = 0;
234 
235 	net_conn_foreach(conn_handler_cb, &user_data);
236 
237 	if (count == 0) {
238 		PR("No connection handlers found.\n");
239 	}
240 #endif
241 
242 #if defined(CONFIG_NET_TCP)
243 	PR("\nTCP        Context   Src port Dst port   "
244 	   "Send-Seq   Send-Ack  MSS    State\n");
245 
246 	count = 0;
247 
248 	net_tcp_foreach(tcp_cb, &user_data);
249 
250 	if (count == 0) {
251 		PR("No TCP connections\n");
252 	} else {
253 #if CONFIG_NET_TCP_LOG_LEVEL >= LOG_LEVEL_DBG
254 		/* Print information about pending packets */
255 		struct tcp_detail_info details;
256 
257 		count = 0;
258 
259 		if (IS_ENABLED(CONFIG_NET_TCP)) {
260 			memset(&details, 0, sizeof(details));
261 			user_data.user_data = &details;
262 		}
263 
264 		net_tcp_foreach(tcp_sent_list_cb, &user_data);
265 
266 		if (IS_ENABLED(CONFIG_NET_TCP)) {
267 			if (details.count == 0) {
268 				PR("No active connections.\n");
269 			}
270 		}
271 #endif /* CONFIG_NET_TCP_LOG_LEVEL >= LOG_LEVEL_DBG */
272 	}
273 
274 #if CONFIG_NET_TCP_LOG_LEVEL < LOG_LEVEL_DBG
275 	PR_INFO("Set %s to enable %s support.\n",
276 		"CONFIG_NET_TCP_LOG_LEVEL_DBG", "TCP debugging");
277 #endif /* CONFIG_NET_TCP_LOG_LEVEL < LOG_LEVEL_DBG */
278 
279 #endif
280 
281 #if defined(CONFIG_NET_IPV6_FRAGMENT)
282 	count = 0;
283 
284 	net_ipv6_frag_foreach(ipv6_frag_cb, &user_data);
285 
286 	/* Do not print anything if no fragments are pending atm */
287 #endif
288 
289 #else
290 	PR_INFO("Set %s to enable %s support.\n",
291 		"CONFIG_NET_OFFLOAD or CONFIG_NET_NATIVE",
292 		"connection information");
293 
294 #endif /* CONFIG_NET_OFFLOAD || CONFIG_NET_NATIVE */
295 
296 	return 0;
297 }
298 
299 
300 SHELL_SUBCMD_ADD((net), conn, NULL, "Print information about network connections.",
301 		 cmd_net_conn, 1, 0);
302