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 
conn_handler_cb(struct net_conn * conn,void * user_data)54 static void conn_handler_cb(struct net_conn *conn, void *user_data)
55 {
56 #if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4)
57 #define ADDR_LEN NET_IPV6_ADDR_LEN
58 #elif defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
59 #define ADDR_LEN NET_IPV4_ADDR_LEN
60 #else
61 #define ADDR_LEN NET_IPV6_ADDR_LEN
62 #endif
63 	struct net_shell_user_data *data = user_data;
64 	const struct shell *sh = data->sh;
65 	int *count = data->user_data;
66 	/* +7 for []:port */
67 	char addr_local[ADDR_LEN + 7];
68 	char addr_remote[ADDR_LEN + 7] = "";
69 
70 	if (IS_ENABLED(CONFIG_NET_IPV6) && conn->local_addr.sa_family == AF_INET6) {
71 		snprintk(addr_local, sizeof(addr_local), "[%s]:%u",
72 			 net_sprint_ipv6_addr(
73 				 &net_sin6(&conn->local_addr)->sin6_addr),
74 			 ntohs(net_sin6(&conn->local_addr)->sin6_port));
75 		snprintk(addr_remote, sizeof(addr_remote), "[%s]:%u",
76 			 net_sprint_ipv6_addr(
77 				 &net_sin6(&conn->remote_addr)->sin6_addr),
78 			 ntohs(net_sin6(&conn->remote_addr)->sin6_port));
79 
80 	} else if (IS_ENABLED(CONFIG_NET_IPV4) && conn->local_addr.sa_family == AF_INET) {
81 		snprintk(addr_local, sizeof(addr_local), "%s:%d",
82 			 net_sprint_ipv4_addr(
83 				 &net_sin(&conn->local_addr)->sin_addr),
84 			 ntohs(net_sin(&conn->local_addr)->sin_port));
85 		snprintk(addr_remote, sizeof(addr_remote), "%s:%d",
86 			 net_sprint_ipv4_addr(
87 				 &net_sin(&conn->remote_addr)->sin_addr),
88 			 ntohs(net_sin(&conn->remote_addr)->sin_port));
89 
90 	} else if (conn->local_addr.sa_family == AF_UNSPEC) {
91 		snprintk(addr_local, sizeof(addr_local), "AF_UNSPEC");
92 	} else if (conn->local_addr.sa_family == AF_PACKET) {
93 		snprintk(addr_local, sizeof(addr_local), "AF_PACKET");
94 	} else {
95 		snprintk(addr_local, sizeof(addr_local), "AF_UNK(%d)",
96 			 conn->local_addr.sa_family);
97 	}
98 
99 	PR("[%2d] %p %p  %s\t%16s\t%16s\n",
100 	   (*count) + 1, conn, conn->cb,
101 	   net_proto2str(conn->local_addr.sa_family, conn->proto),
102 	   addr_local, addr_remote);
103 
104 	(*count)++;
105 }
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", conn,
151 		   atomic_get(&conn->ref_count), conn->recv_win, conn->send_win,
152 		   conn->send_data_total, conn->unacked_len,
153 		   conn->data_mode == TCP_DATA_MODE_RESEND ? 1 : 0, conn->in_connect,
154 		   conn->in_close, 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 	PR("\n     Handler    Callback  Proto            Local                  Remote\n");
231 
232 	count = 0;
233 
234 	net_conn_foreach(conn_handler_cb, &user_data);
235 
236 	if (count == 0) {
237 		PR("No connection handlers found.\n");
238 	}
239 
240 #if defined(CONFIG_NET_TCP)
241 	PR("\nTCP        Context   Src port Dst port   "
242 	   "Send-Seq   Send-Ack  MSS    State\n");
243 
244 	count = 0;
245 
246 	net_tcp_foreach(tcp_cb, &user_data);
247 
248 	if (count == 0) {
249 		PR("No TCP connections\n");
250 	} else {
251 #if CONFIG_NET_TCP_LOG_LEVEL >= LOG_LEVEL_DBG
252 		/* Print information about pending packets */
253 		struct tcp_detail_info details;
254 
255 		count = 0;
256 
257 		if (IS_ENABLED(CONFIG_NET_TCP)) {
258 			memset(&details, 0, sizeof(details));
259 			user_data.user_data = &details;
260 		}
261 
262 		net_tcp_foreach(tcp_sent_list_cb, &user_data);
263 
264 		if (IS_ENABLED(CONFIG_NET_TCP)) {
265 			if (details.count == 0) {
266 				PR("No active connections.\n");
267 			}
268 		}
269 #endif /* CONFIG_NET_TCP_LOG_LEVEL >= LOG_LEVEL_DBG */
270 	}
271 
272 #if CONFIG_NET_TCP_LOG_LEVEL < LOG_LEVEL_DBG
273 	PR_INFO("Set %s to enable %s support.\n",
274 		"CONFIG_NET_TCP_LOG_LEVEL_DBG", "TCP debugging");
275 #endif /* CONFIG_NET_TCP_LOG_LEVEL < LOG_LEVEL_DBG */
276 
277 #endif
278 
279 #if defined(CONFIG_NET_IPV6_FRAGMENT)
280 	count = 0;
281 
282 	net_ipv6_frag_foreach(ipv6_frag_cb, &user_data);
283 
284 	/* Do not print anything if no fragments are pending atm */
285 #endif
286 
287 #else
288 	PR_INFO("Set %s to enable %s support.\n",
289 		"CONFIG_NET_OFFLOAD or CONFIG_NET_NATIVE",
290 		"connection information");
291 
292 #endif /* CONFIG_NET_OFFLOAD || CONFIG_NET_NATIVE */
293 
294 	return 0;
295 }
296 
297 
298 SHELL_SUBCMD_ADD((net), conn, NULL, "Print information about network connections.",
299 		 cmd_net_conn, 1, 0);
300