blob: 3306b05d1a79825eebad7e9218a18e50a0679ecd [file] [log] [blame]
/*
* 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);