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 
is_pkt_part_of_slab(const struct k_mem_slab * slab,const char * ptr)13 static bool is_pkt_part_of_slab(const struct k_mem_slab *slab, const char *ptr)
14 {
15 	size_t last_offset = (slab->info.num_blocks - 1) * slab->info.block_size;
16 	size_t ptr_offset;
17 
18 	/* Check if pointer fits into slab buffer area. */
19 	if ((ptr < slab->buffer) || (ptr > slab->buffer + last_offset)) {
20 		return false;
21 	}
22 
23 	/* Check if pointer offset is correct. */
24 	ptr_offset = ptr - slab->buffer;
25 	if (ptr_offset % slab->info.block_size != 0) {
26 		return false;
27 	}
28 
29 	return true;
30 }
31 
32 struct ctx_pkt_slab_info {
33 	const void *ptr;
34 	bool pkt_source_found;
35 };
36 
check_context_pool(struct net_context * context,void * user_data)37 static void check_context_pool(struct net_context *context, void *user_data)
38 {
39 #if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL)
40 	if (!net_context_is_used(context)) {
41 		return;
42 	}
43 
44 	if (context->tx_slab) {
45 		struct ctx_pkt_slab_info *info = user_data;
46 		struct k_mem_slab *slab = context->tx_slab();
47 
48 		if (is_pkt_part_of_slab(slab, info->ptr)) {
49 			info->pkt_source_found = true;
50 		}
51 	}
52 #endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */
53 }
54 
is_pkt_ptr_valid(const void * ptr)55 static bool is_pkt_ptr_valid(const void *ptr)
56 {
57 	struct k_mem_slab *rx, *tx;
58 
59 	net_pkt_get_info(&rx, &tx, NULL, NULL);
60 
61 	if (is_pkt_part_of_slab(rx, ptr) || is_pkt_part_of_slab(tx, ptr)) {
62 		return true;
63 	}
64 
65 	if (IS_ENABLED(CONFIG_NET_CONTEXT_NET_PKT_POOL)) {
66 		struct ctx_pkt_slab_info info;
67 
68 		info.ptr = ptr;
69 		info.pkt_source_found = false;
70 
71 		net_context_foreach(check_context_pool, &info);
72 
73 		if (info.pkt_source_found) {
74 			return true;
75 		}
76 	}
77 
78 	return false;
79 }
80 
get_net_pkt(const char * ptr_str)81 static struct net_pkt *get_net_pkt(const char *ptr_str)
82 {
83 	uint8_t buf[sizeof(intptr_t)];
84 	intptr_t ptr = 0;
85 	size_t len;
86 	int i;
87 
88 	if (ptr_str[0] == '0' && ptr_str[1] == 'x') {
89 		ptr_str += 2;
90 	}
91 
92 	len = hex2bin(ptr_str, strlen(ptr_str), buf, sizeof(buf));
93 	if (!len) {
94 		return NULL;
95 	}
96 
97 	for (i = len - 1; i >= 0; i--) {
98 		ptr |= buf[i] << 8 * (len - 1 - i);
99 	}
100 
101 	return (struct net_pkt *)ptr;
102 }
103 
net_pkt_buffer_info(const struct shell * sh,struct net_pkt * pkt)104 static void net_pkt_buffer_info(const struct shell *sh, struct net_pkt *pkt)
105 {
106 	struct net_buf *buf = pkt->buffer;
107 
108 	PR("net_pkt %p buffer chain:\n", pkt);
109 	PR("%p[%ld]", pkt, atomic_get(&pkt->atomic_ref));
110 
111 	if (buf) {
112 		PR("->");
113 	}
114 
115 	while (buf) {
116 		PR("%p[%ld/%u (%u/%u)]", buf, atomic_get(&pkt->atomic_ref),
117 		   buf->len, net_buf_max_len(buf), buf->size);
118 
119 		buf = buf->frags;
120 		if (buf) {
121 			PR("->");
122 		}
123 	}
124 
125 	PR("\n");
126 }
127 
net_pkt_buffer_hexdump(const struct shell * sh,struct net_pkt * pkt)128 static void net_pkt_buffer_hexdump(const struct shell *sh,
129 				   struct net_pkt *pkt)
130 {
131 	struct net_buf *buf = pkt->buffer;
132 	int i = 0;
133 
134 	if (!buf || buf->ref == 0) {
135 		return;
136 	}
137 
138 	PR("net_pkt %p buffer chain hexdump:\n", pkt);
139 
140 	while (buf) {
141 		PR("net_buf[%d] %p\n", i++, buf);
142 		shell_hexdump(sh, buf->data, buf->len);
143 		buf = buf->frags;
144 	}
145 }
146 
cmd_net_pkt(const struct shell * sh,size_t argc,char * argv[])147 static int cmd_net_pkt(const struct shell *sh, size_t argc, char *argv[])
148 {
149 	struct net_pkt *pkt;
150 
151 	pkt = get_net_pkt(argv[1]);
152 	if (!pkt) {
153 		PR_ERROR("Invalid ptr value (%s). "
154 			 "Example: 0x01020304\n", argv[1]);
155 
156 		return -ENOEXEC;
157 	}
158 
159 	if (!is_pkt_ptr_valid(pkt)) {
160 		PR_ERROR("Pointer is not recognized as net_pkt (%s).\n",
161 			 argv[1]);
162 
163 		return -ENOEXEC;
164 	}
165 
166 	net_pkt_buffer_info(sh, pkt);
167 	PR("\n");
168 	net_pkt_buffer_hexdump(sh, pkt);
169 
170 	return 0;
171 }
172 
173 SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_pkt,
174 	SHELL_CMD(--help, NULL,
175 		  "'net pkt <ptr in hex>' "
176 		  "Print information about given net_pkt",
177 		  cmd_net_pkt),
178 	SHELL_SUBCMD_SET_END
179 );
180 
181 SHELL_SUBCMD_ADD((net), pkt, &net_cmd_pkt,
182 		 "net_pkt information.",
183 		 cmd_net_pkt, 2, 0);
184