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