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