Files
esp-idf/components/lwip/port/esp32/debug/lwip_debug.c
2020-07-20 17:10:00 +08:00

882 lines
25 KiB
C

// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "debug/lwip_debug.h"
#include "lwip/api.h"
#include "lwip/netbuf.h"
#include "lwip/tcp.h"
#include "lwip/udp.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/stats.h"
#include "lwip/priv/memp_priv.h"
#include "lwip/memp.h"
#include "esp_log.h"
#include "freertos/task.h"
#include "string.h"
#include "lwip/tcpip.h"
#include "lwip/priv/sockets_priv.h"
#define TAG "lwipd"
extern struct lwip_sock* lwip_socket_debug_get_socket(int fd);
extern void lwip_socket_debug_done_socket(struct lwip_sock *sock);
extern struct tcp_pcb *tcp_bound_pcbs;
extern struct tcp_pcb *tcp_active_pcbs;
extern struct tcp_pcb *tcp_tw_pcbs;
extern struct udp_pcb *udp_pcbs;
extern sys_mbox_t mbox;
extern sys_thread_t g_lwip_task;
#if LWIP_STATS
//extern struct stats lwip_stats;
#endif
static sys_sem_t s_lwip_debug_api_sem = NULL;
esp_lwip_stats_t g_esp_lwip_stats = {0};
typedef struct {
struct lwip_sock sock;
bool valid;
uint32_t recvmbox_cnt;
uint32_t acceptmbox_cnt;
} lwip_debug_sock_t;
typedef struct lwip_debug_tcp_pcb_s {
struct tcp_pcb pcb;
uint16_t unsent_cnt;
uint16_t unack_cnt;
uint16_t oos_cnt;
uint16_t refused_cnt;
struct lwip_debug_tcp_pcb_s *next;
} lwip_debug_tcp_pcb_t;
typedef struct lwip_debug_udp_pcb_s {
struct udp_pcb pcb;
struct lwip_debug_udp_pcb_s *next;
} lwip_debug_udp_pcb_t;
typedef struct {
void *sockets;
lwip_debug_tcp_pcb_t *active_pcbs;
lwip_debug_tcp_pcb_t *bound_pcbs;
lwip_debug_tcp_pcb_t *tw_pcbs;
lwip_debug_udp_pcb_t *udp_pcbs;
} lwip_debug_info_t;
struct lwip_debug_api_msg_s;
typedef int (*lwip_debug_api_fn_t)(struct lwip_debug_api_msg_s *msg);
typedef struct lwip_debug_api_msg_s {
lwip_debug_api_fn_t api_fn;
int ret;
void *arg;
} lwip_debug_api_msg_t;
err_t tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t* sem);
void dbg_lwip_task_show(void)
{
if (mbox && mbox->os_mbox) {
ESP_LOGI(TAG, "lwip mbox=%p msg=%u", mbox->os_mbox, uxQueueMessagesWaiting(mbox->os_mbox));
}
if (g_lwip_task) {
ESP_LOGI(TAG, "lwip task=%p state=%d", g_lwip_task, eTaskGetState(g_lwip_task));
}
}
static uint32_t lwip_debug_pbuf_len(struct pbuf *buf)
{
uint32_t cnt = 0;
while (buf) {
cnt ++;
buf = buf->next;
}
return cnt;
}
static uint32_t lwip_debug_tcp_seg_len(struct tcp_seg *seg)
{
uint32_t cnt = 0;
while (seg) {
cnt ++;
seg = seg->next;
}
return cnt;
}
static int lwip_debug_deep_copy_tcp_pcb_list(struct tcp_pcb *pcb, lwip_debug_tcp_pcb_t **pdbgpcb)
{
lwip_debug_tcp_pcb_t *dbgpcb = NULL;
lwip_debug_tcp_pcb_t *pre = NULL;
while(pcb){
dbgpcb = (lwip_debug_tcp_pcb_t*)mem_malloc(sizeof(lwip_debug_tcp_pcb_t));
if (!dbgpcb) {
ESP_LOGI(TAG, "Failed to allocate TCP PCB");
return -1;
}
memset(dbgpcb, 0, sizeof(lwip_debug_tcp_pcb_t));
memcpy((void*)dbgpcb, (void*)pcb, sizeof(struct tcp_pcb));
dbgpcb->unsent_cnt = lwip_debug_tcp_seg_len(pcb->unsent);
dbgpcb->unack_cnt = lwip_debug_tcp_seg_len(pcb->unacked);
dbgpcb->oos_cnt = lwip_debug_tcp_seg_len(pcb->ooseq);
dbgpcb->refused_cnt = lwip_debug_pbuf_len(pcb->refused_data);
if ( (*pdbgpcb) == NULL) {
*pdbgpcb = dbgpcb;
pre = dbgpcb;
} else {
pre->next = dbgpcb;
pre = pre->next;
}
pcb = pcb->next;
}
return 0;
}
static int lwip_debug_get_tcp_pcbs(lwip_debug_info_t *info)
{
lwip_debug_deep_copy_tcp_pcb_list(tcp_active_pcbs, &info->active_pcbs);
lwip_debug_deep_copy_tcp_pcb_list(tcp_bound_pcbs, &info->bound_pcbs);
lwip_debug_deep_copy_tcp_pcb_list(tcp_tw_pcbs, &info->tw_pcbs);
return 0;
}
static int lwip_debug_deep_copy_udp_pcb_list(struct udp_pcb *pcb, lwip_debug_udp_pcb_t **pdbgpcb)
{
lwip_debug_udp_pcb_t *dbgpcb = NULL;
lwip_debug_udp_pcb_t *pre = NULL;
while (pcb) {
dbgpcb = (lwip_debug_udp_pcb_t*)mem_malloc(sizeof(lwip_debug_udp_pcb_t));
if (!dbgpcb) {
ESP_LOGI(TAG, "Failed to allocate UDP PCB");
return -1;
}
memset(dbgpcb, 0, sizeof(lwip_debug_udp_pcb_t));
memcpy((void*)dbgpcb, (void*)pcb, sizeof(struct udp_pcb));
if ( (*pdbgpcb) == NULL) {
*pdbgpcb = dbgpcb;
pre = dbgpcb;
} else {
pre->next = dbgpcb;
pre = pre->next;
}
pcb = pcb->next;
}
return 0;
}
static int lwip_debug_get_udp_pcbs(lwip_debug_info_t *info)
{
lwip_debug_deep_copy_udp_pcb_list(udp_pcbs, &info->udp_pcbs);
return 0;
}
static void lwip_socket_debug_free_sockets(lwip_debug_sock_t *dbgsock)
{
struct lwip_sock *sock = NULL;
int i=0;
for (i=0; i<NUM_SOCKETS; i++) {
sock = (struct lwip_sock*)&dbgsock[i];
if (sock->conn) {
if (sock->conn->pcb.tcp) {
free(sock->conn->pcb.tcp);
}
free(sock->conn);
}
}
free(dbgsock);
}
int lwip_socket_debug_deep_copy_socket(struct lwip_sock *sock, lwip_debug_sock_t *dbgsock)
{
struct lwip_sock *dbgsock_base = (struct lwip_sock*)dbgsock;
struct tcp_pcb *tcp_pcb_copy = NULL;
struct udp_pcb *udp_pcb_copy = NULL;
struct netconn *conn_copy = NULL;
struct netconn *conn = NULL;
conn = sock->conn;
if (!conn) {
return 0;
}
conn_copy = (struct netconn*)mem_malloc(sizeof(struct netconn));
if (!conn_copy) {
return -1;
}
memcpy(conn_copy, conn, sizeof(struct netconn));
dbgsock_base->conn = conn_copy;
conn_copy->pcb.tcp = NULL;
if (conn->recvmbox && conn->recvmbox->os_mbox) {
dbgsock->recvmbox_cnt = uxQueueMessagesWaiting(conn->recvmbox->os_mbox);
}
#if LWIP_TCP
if (conn->acceptmbox && conn->acceptmbox->os_mbox) {
dbgsock->acceptmbox_cnt = uxQueueMessagesWaiting(conn->acceptmbox->os_mbox);
}
#endif
if (conn->pcb.tcp) {
switch (conn->type) {
case NETCONN_TCP:
tcp_pcb_copy = (struct tcp_pcb*) mem_malloc(sizeof(struct tcp_pcb));
if (!tcp_pcb_copy) {
goto _exit;
}
memcpy(tcp_pcb_copy, conn->pcb.tcp, sizeof(struct tcp_pcb));
conn_copy->pcb.tcp = tcp_pcb_copy;
break;
case NETCONN_UDP:
udp_pcb_copy = (struct udp_pcb*) mem_malloc(sizeof(struct udp_pcb));
if (!udp_pcb_copy) {
goto _exit;
}
memcpy(udp_pcb_copy, sock->conn->pcb.udp, sizeof(struct udp_pcb));
conn_copy->pcb.udp = udp_pcb_copy;
break;
default:
break;
}
}
return 0;
_exit:
if (tcp_pcb_copy) {
free(tcp_pcb_copy);
}
if (udp_pcb_copy) {
free(udp_pcb_copy);
}
if (conn_copy) {
free(conn_copy);
}
dbgsock_base->conn = NULL;
return -1;
}
static int lwip_socket_debug_get_all_sockets(void **arg)
{
lwip_debug_sock_t **pdbgsocks = (lwip_debug_sock_t**)arg;
lwip_debug_sock_t *dbgsock = NULL;
struct lwip_sock *sock;
int i;
if (!pdbgsocks) {
return -1;
}
*pdbgsocks = NULL;
dbgsock = (lwip_debug_sock_t*) mem_malloc(sizeof(lwip_debug_sock_t) * NUM_SOCKETS);
if (!dbgsock) {
return -1;
}
memset(dbgsock, 0, sizeof(lwip_debug_sock_t) * NUM_SOCKETS);
*pdbgsocks = dbgsock;
for (i=0; i<NUM_SOCKETS; i++) {
sock = lwip_socket_debug_get_socket(i+LWIP_SOCKET_OFFSET);
if (sock) {
memcpy (&dbgsock[i], sock, sizeof(struct lwip_sock));
if (0 != lwip_socket_debug_deep_copy_socket(sock, &dbgsock[i])) {
lwip_socket_debug_done_socket(sock);
goto _exit;
}
dbgsock[i].valid = true;
lwip_socket_debug_done_socket(sock);
} else {
dbgsock[i].valid = false;
}
}
return 0;
_exit:
lwip_socket_debug_free_sockets(dbgsock);
*pdbgsocks = NULL;
return -1;
}
void lwip_debug_dump_open_sockets(void *arg)
{
lwip_debug_sock_t *sockets = (lwip_debug_sock_t*)arg;
struct lwip_sock *sock = NULL;
struct netconn *conn = NULL;
int recv_bufsize = 0;
int recv_avail = 0;
s32_t send_timeout = 0;
u32_t recv_timeout = 0;
int socket_num = 0;
s16_t linger = 0;
ip_addr_t empty_ip;
ip_addr_t *local_ip;
ip_addr_t *remote_ip;
uint16_t local_port;
uint16_t remote_port;
int i=0;
ESP_LOGI(TAG, "");
ESP_LOGI(TAG, "========> socket list");
if (!sockets) {
return;
}
for (i=0; i<NUM_SOCKETS; i++) {
if (true == sockets[i].valid) {
socket_num ++;
break;
}
}
if (socket_num == 0) {
return;
}
ESP_LOGI(TAG, "%2s %2s %13s %13s %3s %3s %3s %2s %2s %2s %4s %3s %4s %2s %4s %4s %4s %3s %3s %5s %3s %3s",
"id", "46", "src ip:port", "dst ip:port", "re", "se", "ee", "sw", "st", "rf",
"ctye", "cst", "cerr", "cw", "ctto", "crto", "crbs", "cra", "cli", "cflag",
"rmb", "amb");
memset(&empty_ip, 0, sizeof(empty_ip));
for (i=0; i<NUM_SOCKETS; i++) {
sock = (struct lwip_sock*) &sockets[i];
if (false == sockets[i].valid) {
continue;
}
conn = sock->conn;
recv_bufsize = recv_avail = send_timeout = recv_timeout = linger = 0;
if (conn) {
#if LWIP_SO_SNDTIMEO
send_timeout = conn->send_timeout;
#endif
#if LWIP_SO_RCVTIMEO
recv_timeout = conn->recv_timeout;
#endif
#if LWIP_SO_LINGER
linger = conn->linger;
#endif
#if LWIP_SO_RCVBUF
recv_bufsize = conn->recv_bufsize;
recv_avail = conn->recv_avail;
#endif
if ( (conn->type == NETCONN_TCP) && conn->pcb.tcp) {
local_ip = &conn->pcb.tcp->local_ip;
remote_ip = &conn->pcb.tcp->remote_ip;
local_port = conn->pcb.tcp->local_port;
remote_port = conn->pcb.tcp->remote_port;
} else if ( (conn->type == NETCONN_UDP) && conn->pcb.udp) {
local_ip = &conn->pcb.udp->local_ip;
remote_ip = &conn->pcb.udp->remote_ip;
local_port = conn->pcb.udp->local_port;
remote_port = conn->pcb.udp->remote_port;
} else {
local_ip = remote_ip = &empty_ip;
local_port = remote_port = 0;
}
ESP_LOGI(TAG, "%2x %2x %8x:%4x %8x:%4x %3x %3x %3x %2x %2x %2x %4x %3x %4x %2x %4x %4x %4x %3x %3x %5x %3x %3x",
i+LWIP_SOCKET_OFFSET, local_ip->type, local_ip->u_addr.ip4.addr, local_port, remote_ip->u_addr.ip4.addr, remote_port,
sock->rcvevent, sock->sendevent, sock->errevent, sock->select_waiting, sock->state, sock->ref,
conn->type, conn->state, conn->last_err, 0, send_timeout, recv_timeout, recv_bufsize,
recv_avail, linger, conn->flags, sockets[i].recvmbox_cnt, sockets[i].acceptmbox_cnt);
} else {
ESP_LOGI(TAG, "%2x %21s %21s %3x %3x %3x %2x %2x %2x %4s %3s %4s %2s %4s %4s %4s %3s %3s %5s %3s %3s",
i+LWIP_SOCKET_OFFSET, "-:-", "-:-", sock->rcvevent, sock->sendevent, sock->errevent, sock->select_waiting, sock->state, sock->ref,
"-", "-", "-", "-", "-", "-", "-",
"-", "-", "-", "-", "-");
}
}
}
static void lwip_debug_dump_tcp_pcb_list_part1(lwip_debug_tcp_pcb_t* dbgpcb, uint32_t type, uint32_t *id)
{
char t[] = {'A', 'B', 'T'};
struct tcp_pcb *pcb;
uint8_t i = *id;
while(dbgpcb){
pcb = (struct tcp_pcb *)&dbgpcb->pcb;
ESP_LOGI(TAG, "%2d %c %2x %8x:%4x %8x:%4x %2x %2x %5x %5x %6x %5x %5x %4x %4s %4s %4s %4s %4s",
i++, t[type], pcb->local_ip.type, pcb->local_ip.u_addr.ip4.addr, pcb->local_port, pcb->remote_ip.u_addr.ip4.addr, pcb->remote_port, pcb->state, pcb->prio,
pcb->flags, pcb->polltmr, pcb->pollinterval, pcb->last_timer, pcb->tmr, pcb->mss, pcb->sent?"x":"0", pcb->recv?"x":"0", pcb->connected?"x":"0",
pcb->poll?"x":"0", pcb->errf?"x":"0");
dbgpcb = dbgpcb->next;
}
*id = *id + i;
}
static void lwip_debug_dump_tcp_pcb_list_part2(lwip_debug_tcp_pcb_t* dbgpcb, uint32_t type, uint32_t *id)
{
struct tcp_pcb *pcb;
uint8_t i = *id;
while(dbgpcb){
pcb = (struct tcp_pcb *)&dbgpcb->pcb;
ESP_LOGI(TAG, "%2x %8x %8x %8x %8x %8x %3x %6x",
i++, pcb->rcv_nxt, pcb->rcv_wnd, pcb->rcv_ann_wnd, pcb->rcv_ann_right_edge, 0, dbgpcb->oos_cnt, dbgpcb->refused_cnt);
dbgpcb = dbgpcb->next;
}
*id = *id + i;
}
static void lwip_debug_dump_tcp_pcb_list_part3(lwip_debug_tcp_pcb_t* dbgpcb, uint32_t type, uint32_t *id)
{
struct tcp_pcb *pcb;
uint8_t i = *id;
while(dbgpcb){
pcb = (struct tcp_pcb *)&dbgpcb->pcb;
ESP_LOGI(TAG, "%2x %6x %8x %4x %4x %4x %4x %4x %8x %8x %8x %8x %4x %4x %4x",
i++, pcb->rttest, pcb->rtseq, pcb->sa, pcb->sv, pcb->rto, pcb->nrtx, pcb->dupacks, pcb->lastack, pcb->cwnd,
pcb->ssthresh, 0, pcb->persist_cnt, pcb->persist_backoff, 0);
dbgpcb = dbgpcb->next;
}
*id = *id + i;
}
static void lwip_debug_dump_tcp_pcb_list_part4(lwip_debug_tcp_pcb_t* dbgpcb, uint32_t type, uint32_t *id)
{
uint32_t unsent_oversize = 0;
struct tcp_pcb *pcb;
uint8_t i = *id;
while(dbgpcb){
pcb = (struct tcp_pcb *)&dbgpcb->pcb;
#if TCP_OVERSIZE
unsent_oversize = pcb->unsent_oversize;
#endif
ESP_LOGI(TAG, "%2x %8x %8x %8x %8x %8x %8x %5x %5x %6x %3x %3x",
i++, pcb->snd_nxt, pcb->snd_wl1, pcb->snd_wl2, pcb->snd_lbb, pcb->snd_wnd, pcb->snd_wnd_max, pcb->snd_buf,
pcb->snd_queuelen, unsent_oversize, dbgpcb->unsent_cnt, dbgpcb->unack_cnt);
dbgpcb = dbgpcb->next;
}
*id = *id + i;
}
static void lwip_debug_dump_tcp_pcbs_part1(lwip_debug_info_t *info)
{
uint32_t id = 0;
ESP_LOGI(TAG, "");
ESP_LOGI(TAG, "%2s %1s %2s %13s %13s %2s %2s %5s %5s %6s %5s %5s %4s %4s %4s %4s %4s %4s",
"id", "t", "46", "src ip:port", "dst ip:port", "st", "pr", "flags", "p_tmr", "p_itvl",
"l_tmr", "tmr", "mss", "sent", "recv", "conn", "poll", "errf");
lwip_debug_dump_tcp_pcb_list_part1(info->active_pcbs, 0, &id);
lwip_debug_dump_tcp_pcb_list_part1(info->bound_pcbs, 1, &id);
lwip_debug_dump_tcp_pcb_list_part1(info->tw_pcbs, 2, &id);
}
static void lwip_debug_dump_tcp_pcbs_part2(lwip_debug_info_t *info)
{
uint32_t id = 0;
ESP_LOGI(TAG, "");
ESP_LOGI(TAG, "%2s %8s %8s %8s %8s %8s %3s %6s", "id", "r_next", "r_wnd", "r_a_wnd", "r_a_r_e", "b_acked", "oos", "refuse");
lwip_debug_dump_tcp_pcb_list_part2(info->active_pcbs, 0, &id);
lwip_debug_dump_tcp_pcb_list_part2(info->bound_pcbs, 1, &id);
lwip_debug_dump_tcp_pcb_list_part2(info->tw_pcbs, 2, &id);
}
static void lwip_debug_dump_tcp_pcbs_part3(lwip_debug_info_t *info)
{
uint32_t id = 0;
ESP_LOGI(TAG, "");
ESP_LOGI(TAG, "%2s %6s %8s %4s %4s %4s %4s %4s %8s %8s %8s %8s %4s %4s %4s",
"id", "rttest", "rtseq", "sa", "sv", "rto", "nrtx", "dup", "last", "cwnd", "ssthresh", "rto_end", "pist", "p_bo", "p_p");
lwip_debug_dump_tcp_pcb_list_part3(info->active_pcbs, 0, &id);
lwip_debug_dump_tcp_pcb_list_part3(info->bound_pcbs, 1, &id);
lwip_debug_dump_tcp_pcb_list_part3(info->tw_pcbs, 2, &id);
}
static void lwip_debug_dump_tcp_pcbs_part4(lwip_debug_info_t *info)
{
uint32_t id = 0;
ESP_LOGI(TAG, "");
ESP_LOGI(TAG, "%2s %8s %8s %8s %8s %8s %8s %5s %5s %6s %3s %3s",
"id", "snd_next", "snd_wl1", "snd_wl2", "wnd_lbb", "s_wnd", "s_wm", "s_buf", "s_qlen", "uns_os", "uns", "una");
lwip_debug_dump_tcp_pcb_list_part4(info->active_pcbs, 0, &id);
lwip_debug_dump_tcp_pcb_list_part4(info->bound_pcbs, 1, &id);
lwip_debug_dump_tcp_pcb_list_part4(info->tw_pcbs, 2, &id);
}
static void lwip_debug_dump_tcp_pcbs(lwip_debug_info_t *info)
{
ESP_LOGI(TAG, "");
ESP_LOGI(TAG, "========> tcp pcb list");
if ( !(info->active_pcbs) && !(info->bound_pcbs) && !(info->tw_pcbs) ) {
return;
}
lwip_debug_dump_tcp_pcbs_part1(info);
lwip_debug_dump_tcp_pcbs_part3(info);
lwip_debug_dump_tcp_pcbs_part4(info);
lwip_debug_dump_tcp_pcbs_part2(info);
}
static void lwip_debug_dump_udp_pcbs(lwip_debug_info_t *info)
{
lwip_debug_udp_pcb_t *dbgpcb = info->udp_pcbs;
struct udp_pcb *pcb;
uint32_t i = 0;
uint32_t mcast_ip = 0;
uint8_t mcast_ttl = 0;
ESP_LOGI(TAG, "");
ESP_LOGI(TAG, "========> udp pcb list");
if ( !dbgpcb ) {
return;
}
ESP_LOGI(TAG, "%2s %2s %13s %13s %5s %4s %4s %5s %4s %3s",
"id", "46", "src ip:port", "dst ip:port", "flags", "m_ip", "m_if", "m_ttl", "recv", "arg");
while (dbgpcb) {
pcb = (struct udp_pcb *)dbgpcb;
#if LWIP_MULTICAST_TX_OPTIONS
mcast_ip = pcb->multicast_ip.u_addr.ip4.addr;
mcast_ttl = pcb->mcast_ttl;
#endif
ESP_LOGI(TAG, "%2x %2x %8x:%4x %8x:%4x %5x %4x %4x %5x %4s %3s",
i++, pcb->local_ip.type, pcb->local_ip.u_addr.ip4.addr, pcb->local_port, pcb->remote_ip.u_addr.ip4.addr, pcb->remote_port,
pcb->flags, mcast_ip, mcast_ttl, pcb->mcast_ttl, pcb->recv?"x":"0", pcb->recv_arg?"x":"0");
dbgpcb = dbgpcb->next;
}
}
static void lwip_debug_dump_sockets(lwip_debug_info_t *info)
{
lwip_debug_dump_open_sockets(info->sockets);
lwip_debug_dump_tcp_pcbs(info);
lwip_debug_dump_udp_pcbs(info);
}
static void lwip_debug_api_cb(void *api_msg)
{
lwip_debug_api_msg_t *msg = (lwip_debug_api_msg_t *)api_msg;
if (!msg || !msg->api_fn) {
return;
}
msg->ret = msg->api_fn(msg);
sys_sem_signal(&s_lwip_debug_api_sem);
return;
}
static int lwip_debug_api_call(lwip_debug_api_msg_t *msg)
{
int ret;
if (!msg || (!msg->api_fn)) {
ESP_LOGI(TAG, "null msg/fn");
return ESP_ERR_INVALID_ARG;
}
msg->ret = ESP_FAIL;
if (!s_lwip_debug_api_sem) {
ret = sys_sem_new(&s_lwip_debug_api_sem, 1);
if (ESP_OK != ret) {
ESP_LOGI(TAG, "failed to create lwip sync sem");
return ESP_ERR_NO_MEM;
}
}
sys_arch_sem_wait(&s_lwip_debug_api_sem, 0);
tcpip_send_msg_wait_sem((tcpip_callback_fn)lwip_debug_api_cb, msg, &s_lwip_debug_api_sem);
sys_sem_signal(&s_lwip_debug_api_sem);
return msg->ret;
}
int lwip_debug_get_sockets_local(lwip_debug_api_msg_t *msg)
{
lwip_debug_info_t *info = (lwip_debug_info_t*) msg->arg;
if (0 != lwip_socket_debug_get_all_sockets(&info->sockets)) {
return -1;
}
if (0 != lwip_debug_get_tcp_pcbs(info)) {
return -1;
}
if (0 != lwip_debug_get_udp_pcbs(info)) {
return -1;
}
return 0;
}
static int lwip_debug_get_sockets(lwip_debug_info_t *info)
{
lwip_debug_api_msg_t msg;
msg.api_fn = lwip_debug_get_sockets_local;
msg.arg = (void*)info;
msg.ret = ESP_FAIL;
lwip_debug_api_call(&msg);
return msg.ret;
}
static void lwip_debug_free_tcp_pcb_list(lwip_debug_tcp_pcb_t *pcb)
{
lwip_debug_tcp_pcb_t *tmp;
while (pcb) {
tmp = pcb;
pcb = pcb->next;
free(tmp);
}
}
static void lwip_debug_free_tcp_pcbs(lwip_debug_info_t *info)
{
if (!info) {
return;
}
if (info->active_pcbs) {
lwip_debug_free_tcp_pcb_list(info->active_pcbs);
info->active_pcbs = 0;
}
if (info->bound_pcbs) {
lwip_debug_free_tcp_pcb_list(info->bound_pcbs);
info->bound_pcbs = 0;
}
if (info->tw_pcbs) {
lwip_debug_free_tcp_pcb_list(info->tw_pcbs);
info->tw_pcbs = 0;
}
}
static void lwip_debug_free_udp_pcb_list(lwip_debug_udp_pcb_t *pcb)
{
lwip_debug_udp_pcb_t *tmp;
while (pcb) {
tmp = pcb;
pcb = pcb->next;
free(tmp);
}
}
static void lwip_debug_free_udp_pcbs(lwip_debug_info_t *info)
{
if (!info) {
return;
}
if (info->udp_pcbs) {
lwip_debug_free_udp_pcb_list(info->udp_pcbs);
}
}
static void lwip_debug_free_sockets(lwip_debug_info_t *info)
{
if (!info) {
return;
}
if (info->sockets) {
lwip_socket_debug_free_sockets(info->sockets);
info->sockets = NULL;
}
lwip_debug_free_tcp_pcbs(info);
lwip_debug_free_udp_pcbs(info);
}
#if LWIP_STATS
static void lwip_debug_dump_igmp_statistics(struct stats_igmp *proto, const char *name)
{
ESP_LOGI(TAG, "%8s %8x %8x %4x %4x %4x %4x %4x %5x %5x %5x %5x %5x %5x %5x",
name, proto->xmit, proto->recv, proto->drop, proto->chkerr, proto->lenerr,
proto->memerr, proto->proterr, proto->rx_v1, proto->rx_group, proto->rx_general,
proto->rx_report, proto->tx_join, proto->tx_leave, proto->tx_report);
}
static void lwip_debug_dump_multicast_statistics(void)
{
ESP_LOGI(TAG, "");
ESP_LOGI(TAG, "========> LWIP multicast statistics");
ESP_LOGI(TAG, "%8s %8s %8s %4s %4s %4s %4s %4s %5s %5s %5s %5s %5s %5s %5s",
"name", "xmit", "recv", "drop", "chk", "len", "mem", "prot", "rxv1", "rx_gr", "rx_gl", "rx_rp", "tx_jn", "tx_lv", "tx_rp");
#if IGMP_STATS
lwip_debug_dump_igmp_statistics(&lwip_stats.igmp, "IGMP");
#endif
#if MLD6_STATS
lwip_debug_dump_igmp_statistics(&lwip_stats.mld6, "MLDv1");
#endif
}
static void lwip_debug_dump_protocol_statistics(struct stats_proto *proto, const char *name)
{
ESP_LOGI(TAG, "%8s %8x %8x %8x %4x %4x %4x %4x %4x %4x %4x %4x %8x",
name, proto->xmit, proto->recv, proto->fw, proto->drop, proto->chkerr, proto->lenerr,
proto->memerr, proto->rterr, proto->proterr, proto->opterr, proto->err, proto->cachehit);
}
static void lwip_debug_dump_unicast_statistics(void)
{
ESP_LOGI(TAG, "");
ESP_LOGI(TAG, "========> LWIP counters");
ESP_LOGI(TAG, "%8s %8s %8s %8s %4s %4s %4s %4s %4s %4s %4s %4s %8s",
"name", "xmit", "recv", "forward", "drop", "chk", "len", "mem", "rt", "prot", "opt", "err", "hit");
#if TCP_STATS
lwip_debug_dump_protocol_statistics(&lwip_stats.tcp, "TCP");
#endif
#if UDP_STATS
lwip_debug_dump_protocol_statistics(&lwip_stats.udp, "UDP");
#endif
#if ICMP_STATS
lwip_debug_dump_protocol_statistics(&lwip_stats.icmp, "ICMP");
#endif
#if IP_STATS
lwip_debug_dump_protocol_statistics(&lwip_stats.ip, "IP");
#endif
#if IPFRAG_STATS
lwip_debug_dump_protocol_statistics(&lwip_stats.ip_frag, "IPFRAG");
#endif
#if ETHARP_STATS
lwip_debug_dump_protocol_statistics(&lwip_stats.etharp, "ETHARP");
#endif
#if LINK_STATS
lwip_debug_dump_protocol_statistics(&lwip_stats.link, "LINK");
#endif
#if IP6_STATS
lwip_debug_dump_protocol_statistics(&lwip_stats.ip6, "IPV6");
#endif
#if ICMP6_STATS
lwip_debug_dump_protocol_statistics(&lwip_stats.icmp6, "ICMP6");
#endif
#if IP6_FRAG_STATS
lwip_debug_dump_protocol_statistics(&lwip_stats.ip6_frag, "IPV6FRAG");
#endif
#if ND6_FRAG_STATS
lwip_debug_dump_protocol_statistics(&lwip_stats.nd6, "ND");
#endif
}
#endif
void esp_lwip_debug_dump_sockets(void)
{
lwip_debug_info_t info;
memset(&info, 0, sizeof(info));
if (ESP_OK == lwip_debug_get_sockets(&info)) {
lwip_debug_dump_sockets(&info);
lwip_debug_free_sockets(&info);
}
}
static void lwip_debug_dump_sys_statistics(void)
{
ESP_LOGI(TAG, "");
ESP_LOGI(TAG, "========> LWIP system counters");
ESP_LOGI(TAG, "%8s %8s %8s", "tpost_f", "fetch_f", "tfetch_f");
ESP_LOGI(TAG, "%8x %8x %8x", g_esp_lwip_stats.trypost_fail, g_esp_lwip_stats.fetch_fail, g_esp_lwip_stats.tryfetch_fail);
}
void esp_lwip_debug_dump_stats(void)
{
#if LWIP_STATS
lwip_debug_dump_sys_statistics();
lwip_debug_dump_unicast_statistics();
lwip_debug_dump_multicast_statistics();
#endif
//TODO
// 1. mbox post fail/recv timeout
// 2. tcpip mbox counter
// 3. tcp abort
// 4. ARP drop
// 5. DHCP drop
// 6. DNS fail
// 7. DHCP renew time, renew fail time, rebind timer
// 8.
}
void esp_lwip_dump(uint64_t modules)
{
if (modules & LWIP_MODULE_SOCKETS) {
esp_lwip_debug_dump_sockets();
}
if (modules & LWIP_MODULE_STATS) {
esp_lwip_debug_dump_stats();
}
}