zephyr/subsys/net/lib/shell/conn.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

302 lines
8.0 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"
#if defined(CONFIG_NET_TCP)
#include "tcp_internal.h"
#include <zephyr/sys/slist.h>
#endif
#if defined(CONFIG_NET_OFFLOAD) || defined(CONFIG_NET_NATIVE)
static void context_cb(struct net_context *context, void *user_data)
{
#if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4)
#define ADDR_LEN NET_IPV6_ADDR_LEN
#elif defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
#define ADDR_LEN NET_IPV4_ADDR_LEN
#else
#define ADDR_LEN NET_IPV6_ADDR_LEN
#endif
struct net_shell_user_data *data = user_data;
const struct shell *sh = data->sh;
int *count = data->user_data;
/* +7 for []:port */
char addr_local[ADDR_LEN + 7];
char addr_remote[ADDR_LEN + 7] = "";
get_addresses(context, addr_local, sizeof(addr_local),
addr_remote, sizeof(addr_remote));
PR("[%2d] %p\t%d %c%c%c %16s\t%16s\n",
(*count) + 1, context,
net_if_get_by_iface(net_context_get_iface(context)),
net_context_get_family(context) == AF_INET6 ? '6' :
(net_context_get_family(context) == AF_INET ? '4' : ' '),
net_context_get_type(context) == SOCK_DGRAM ? 'D' :
(net_context_get_type(context) == SOCK_STREAM ? 'S' :
(net_context_get_type(context) == SOCK_RAW ? 'R' : ' ')),
net_context_get_proto(context) == IPPROTO_UDP ? 'U' :
(net_context_get_proto(context) == IPPROTO_TCP ? 'T' : ' '),
addr_local, addr_remote);
(*count)++;
}
#endif /* CONFIG_NET_OFFLOAD || CONFIG_NET_NATIVE */
#if CONFIG_NET_CONN_LOG_LEVEL >= LOG_LEVEL_DBG
static void conn_handler_cb(struct net_conn *conn, void *user_data)
{
#if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4)
#define ADDR_LEN NET_IPV6_ADDR_LEN
#elif defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
#define ADDR_LEN NET_IPV4_ADDR_LEN
#else
#define ADDR_LEN NET_IPV6_ADDR_LEN
#endif
struct net_shell_user_data *data = user_data;
const struct shell *sh = data->sh;
int *count = data->user_data;
/* +7 for []:port */
char addr_local[ADDR_LEN + 7];
char addr_remote[ADDR_LEN + 7] = "";
if (IS_ENABLED(CONFIG_NET_IPV6) && conn->local_addr.sa_family == AF_INET6) {
snprintk(addr_local, sizeof(addr_local), "[%s]:%u",
net_sprint_ipv6_addr(
&net_sin6(&conn->local_addr)->sin6_addr),
ntohs(net_sin6(&conn->local_addr)->sin6_port));
snprintk(addr_remote, sizeof(addr_remote), "[%s]:%u",
net_sprint_ipv6_addr(
&net_sin6(&conn->remote_addr)->sin6_addr),
ntohs(net_sin6(&conn->remote_addr)->sin6_port));
} else if (IS_ENABLED(CONFIG_NET_IPV4) && conn->local_addr.sa_family == AF_INET) {
snprintk(addr_local, sizeof(addr_local), "%s:%d",
net_sprint_ipv4_addr(
&net_sin(&conn->local_addr)->sin_addr),
ntohs(net_sin(&conn->local_addr)->sin_port));
snprintk(addr_remote, sizeof(addr_remote), "%s:%d",
net_sprint_ipv4_addr(
&net_sin(&conn->remote_addr)->sin_addr),
ntohs(net_sin(&conn->remote_addr)->sin_port));
} else if (conn->local_addr.sa_family == AF_UNSPEC) {
snprintk(addr_local, sizeof(addr_local), "AF_UNSPEC");
} else {
snprintk(addr_local, sizeof(addr_local), "AF_UNK(%d)",
conn->local_addr.sa_family);
}
PR("[%2d] %p %p\t%s\t%16s\t%16s\n",
(*count) + 1, conn, conn->cb,
net_proto2str(conn->local_addr.sa_family, conn->proto),
addr_local, addr_remote);
(*count)++;
}
#endif /* CONFIG_NET_CONN_LOG_LEVEL >= LOG_LEVEL_DBG */
#if CONFIG_NET_TCP_LOG_LEVEL >= LOG_LEVEL_DBG
struct tcp_detail_info {
int printed_send_queue_header;
int printed_details;
int count;
};
#endif
#if defined(CONFIG_NET_TCP) && \
(defined(CONFIG_NET_OFFLOAD) || defined(CONFIG_NET_NATIVE))
static void tcp_cb(struct tcp *conn, void *user_data)
{
struct net_shell_user_data *data = user_data;
const struct shell *sh = data->sh;
int *count = data->user_data;
uint16_t recv_mss = net_tcp_get_supported_mss(conn);
PR("%p %p %5u %5u %10u %10u %5u %s\n",
conn, conn->context,
ntohs(net_sin6_ptr(&conn->context->local)->sin6_port),
ntohs(net_sin6(&conn->context->remote)->sin6_port),
conn->seq, conn->ack, recv_mss,
net_tcp_state_str(net_tcp_get_state(conn)));
(*count)++;
}
#if CONFIG_NET_TCP_LOG_LEVEL >= LOG_LEVEL_DBG
static void tcp_sent_list_cb(struct tcp *conn, void *user_data)
{
struct net_shell_user_data *data = user_data;
const struct shell *sh = data->sh;
struct tcp_detail_info *details = data->user_data;
struct net_pkt *pkt;
sys_snode_t *node;
if (conn->state != TCP_LISTEN) {
if (!details->printed_details) {
PR("\nTCP Ref Recv_win Send_win Pending "
"Unacked Flags Queue\n");
details->printed_details = true;
}
PR("%p %ld %u\t %u\t %zd\t %d\t %d/%d/%d %s\n",
conn, atomic_get(&conn->ref_count), conn->recv_win,
conn->send_win, conn->send_data_total, conn->unacked_len,
conn->in_retransmission, conn->in_connect, conn->in_close,
sys_slist_is_empty(&conn->send_queue) ? "empty" : "data");
details->count++;
}
if (sys_slist_is_empty(&conn->send_queue)) {
return;
}
if (!details->printed_send_queue_header) {
PR("\nTCP packets waiting ACK:\n");
PR("TCP net_pkt[ref/totlen]->net_buf[ref/len]..."
"\n");
}
PR("%p ", conn);
node = sys_slist_peek_head(&conn->send_queue);
if (node) {
pkt = CONTAINER_OF(node, struct net_pkt, next);
if (pkt) {
struct net_buf *frag = pkt->frags;
if (!details->printed_send_queue_header) {
PR("%p[%ld/%zd]", pkt,
atomic_get(&pkt->atomic_ref),
net_pkt_get_len(pkt));
details->printed_send_queue_header = true;
} else {
PR(" %p[%ld/%zd]",
pkt, atomic_get(&pkt->atomic_ref),
net_pkt_get_len(pkt));
}
if (frag) {
PR("->");
}
while (frag) {
PR("%p[%d/%d]", frag, frag->ref, frag->len);
frag = frag->frags;
if (frag) {
PR("->");
}
}
PR("\n");
}
}
details->printed_send_queue_header = true;
}
#endif /* CONFIG_NET_TCP_LOG_LEVEL >= LOG_LEVEL_DBG */
#endif /* TCP */
static int cmd_net_conn(const struct shell *sh, size_t argc, char *argv[])
{
ARG_UNUSED(argc);
ARG_UNUSED(argv);
#if defined(CONFIG_NET_OFFLOAD) || defined(CONFIG_NET_NATIVE)
struct net_shell_user_data user_data;
int count = 0;
PR(" Context \tIface Flags Local Remote\n");
user_data.sh = sh;
user_data.user_data = &count;
net_context_foreach(context_cb, &user_data);
if (count == 0) {
PR("No connections\n");
}
#if CONFIG_NET_CONN_LOG_LEVEL >= LOG_LEVEL_DBG
PR("\n Handler Callback \tProto\tLocal \tRemote\n");
count = 0;
net_conn_foreach(conn_handler_cb, &user_data);
if (count == 0) {
PR("No connection handlers found.\n");
}
#endif
#if defined(CONFIG_NET_TCP)
PR("\nTCP Context Src port Dst port "
"Send-Seq Send-Ack MSS State\n");
count = 0;
net_tcp_foreach(tcp_cb, &user_data);
if (count == 0) {
PR("No TCP connections\n");
} else {
#if CONFIG_NET_TCP_LOG_LEVEL >= LOG_LEVEL_DBG
/* Print information about pending packets */
struct tcp_detail_info details;
count = 0;
if (IS_ENABLED(CONFIG_NET_TCP)) {
memset(&details, 0, sizeof(details));
user_data.user_data = &details;
}
net_tcp_foreach(tcp_sent_list_cb, &user_data);
if (IS_ENABLED(CONFIG_NET_TCP)) {
if (details.count == 0) {
PR("No active connections.\n");
}
}
#endif /* CONFIG_NET_TCP_LOG_LEVEL >= LOG_LEVEL_DBG */
}
#if CONFIG_NET_TCP_LOG_LEVEL < LOG_LEVEL_DBG
PR_INFO("Set %s to enable %s support.\n",
"CONFIG_NET_TCP_LOG_LEVEL_DBG", "TCP debugging");
#endif /* CONFIG_NET_TCP_LOG_LEVEL < LOG_LEVEL_DBG */
#endif
#if defined(CONFIG_NET_IPV6_FRAGMENT)
count = 0;
net_ipv6_frag_foreach(ipv6_frag_cb, &user_data);
/* Do not print anything if no fragments are pending atm */
#endif
#else
PR_INFO("Set %s to enable %s support.\n",
"CONFIG_NET_OFFLOAD or CONFIG_NET_NATIVE",
"connection information");
#endif /* CONFIG_NET_OFFLOAD || CONFIG_NET_NATIVE */
return 0;
}
SHELL_SUBCMD_ADD((net), conn, NULL, "Print information about network connections.",
cmd_net_conn, 1, 0);