zephyr/subsys/net/lib/shell/pkt.c
Jukka Rissanen 477a4a5d34 net: shell: Rename the common.h to be more unique
As the common.h is only meant to be used by the network
shell files, rename it to be more descriptive in order to
avoid possible conflicts with any other common.h file.

Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
2023-12-13 20:13:39 +01:00

184 lines
3.5 KiB
C

/*
* 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);