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