2023-09-27 18:43:10 +08:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
|
2023-12-13 21:46:45 +08:00
|
|
|
#include "net_shell_private.h"
|
2023-09-27 18:43:10 +08:00
|
|
|
|
|
|
|
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);
|