| /* |
| * Copyright (c) 2016 Intel Corporation |
| * Copyright (c) 2023 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_DECLARE(net_shell); |
| |
| #include "net_shell_private.h" |
| |
| static bool is_pkt_part_of_slab(const struct k_mem_slab *slab, const char *ptr) |
| { |
| size_t last_offset = (slab->info.num_blocks - 1) * slab->info.block_size; |
| size_t ptr_offset; |
| |
| /* Check if pointer fits into slab buffer area. */ |
| if ((ptr < slab->buffer) || (ptr > slab->buffer + last_offset)) { |
| return false; |
| } |
| |
| /* Check if pointer offset is correct. */ |
| ptr_offset = ptr - slab->buffer; |
| if (ptr_offset % slab->info.block_size != 0) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| struct ctx_pkt_slab_info { |
| const void *ptr; |
| bool pkt_source_found; |
| }; |
| |
| static void check_context_pool(struct net_context *context, void *user_data) |
| { |
| #if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) |
| if (!net_context_is_used(context)) { |
| return; |
| } |
| |
| if (context->tx_slab) { |
| struct ctx_pkt_slab_info *info = user_data; |
| struct k_mem_slab *slab = context->tx_slab(); |
| |
| if (is_pkt_part_of_slab(slab, info->ptr)) { |
| info->pkt_source_found = true; |
| } |
| } |
| #endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */ |
| } |
| |
| static bool is_pkt_ptr_valid(const void *ptr) |
| { |
| struct k_mem_slab *rx, *tx; |
| |
| net_pkt_get_info(&rx, &tx, NULL, NULL); |
| |
| if (is_pkt_part_of_slab(rx, ptr) || is_pkt_part_of_slab(tx, ptr)) { |
| return true; |
| } |
| |
| if (IS_ENABLED(CONFIG_NET_CONTEXT_NET_PKT_POOL)) { |
| struct ctx_pkt_slab_info info; |
| |
| info.ptr = ptr; |
| info.pkt_source_found = false; |
| |
| net_context_foreach(check_context_pool, &info); |
| |
| if (info.pkt_source_found) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| static struct net_pkt *get_net_pkt(const char *ptr_str) |
| { |
| uint8_t buf[sizeof(intptr_t)]; |
| intptr_t ptr = 0; |
| size_t len; |
| int i; |
| |
| if (ptr_str[0] == '0' && ptr_str[1] == 'x') { |
| ptr_str += 2; |
| } |
| |
| len = hex2bin(ptr_str, strlen(ptr_str), buf, sizeof(buf)); |
| if (!len) { |
| return NULL; |
| } |
| |
| for (i = len - 1; i >= 0; i--) { |
| ptr |= buf[i] << 8 * (len - 1 - i); |
| } |
| |
| return (struct net_pkt *)ptr; |
| } |
| |
| static void net_pkt_buffer_info(const struct shell *sh, struct net_pkt *pkt) |
| { |
| struct net_buf *buf = pkt->buffer; |
| |
| PR("net_pkt %p buffer chain:\n", pkt); |
| PR("%p[%ld]", pkt, atomic_get(&pkt->atomic_ref)); |
| |
| if (buf) { |
| PR("->"); |
| } |
| |
| while (buf) { |
| PR("%p[%ld/%u (%u/%u)]", buf, atomic_get(&pkt->atomic_ref), |
| buf->len, net_buf_max_len(buf), buf->size); |
| |
| buf = buf->frags; |
| if (buf) { |
| PR("->"); |
| } |
| } |
| |
| PR("\n"); |
| } |
| |
| static void net_pkt_buffer_hexdump(const struct shell *sh, |
| struct net_pkt *pkt) |
| { |
| struct net_buf *buf = pkt->buffer; |
| int i = 0; |
| |
| if (!buf || buf->ref == 0) { |
| return; |
| } |
| |
| PR("net_pkt %p buffer chain hexdump:\n", pkt); |
| |
| while (buf) { |
| PR("net_buf[%d] %p\n", i++, buf); |
| shell_hexdump(sh, buf->data, buf->len); |
| buf = buf->frags; |
| } |
| } |
| |
| static int cmd_net_pkt(const struct shell *sh, size_t argc, char *argv[]) |
| { |
| struct net_pkt *pkt; |
| |
| pkt = get_net_pkt(argv[1]); |
| if (!pkt) { |
| PR_ERROR("Invalid ptr value (%s). " |
| "Example: 0x01020304\n", argv[1]); |
| |
| return -ENOEXEC; |
| } |
| |
| if (!is_pkt_ptr_valid(pkt)) { |
| PR_ERROR("Pointer is not recognized as net_pkt (%s).\n", |
| argv[1]); |
| |
| return -ENOEXEC; |
| } |
| |
| net_pkt_buffer_info(sh, pkt); |
| PR("\n"); |
| net_pkt_buffer_hexdump(sh, pkt); |
| |
| return 0; |
| } |
| |
| SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_pkt, |
| SHELL_CMD(--help, NULL, |
| "'net pkt <ptr in hex>' " |
| "Print information about given net_pkt", |
| cmd_net_pkt), |
| SHELL_SUBCMD_SET_END |
| ); |
| |
| SHELL_SUBCMD_ADD((net), pkt, &net_cmd_pkt, |
| "net_pkt information.", |
| cmd_net_pkt, 2, 0); |