Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ce1eed850 | |||
| 004057a6fa | |||
| e203db13ca |
+55
-8
@@ -20,6 +20,7 @@ typedef struct {
|
|||||||
struct pbuf *hold_pbuf;
|
struct pbuf *hold_pbuf;
|
||||||
uint16_t hold_offset;
|
uint16_t hold_offset;
|
||||||
uint32_t next_retry_ms;
|
uint32_t next_retry_ms;
|
||||||
|
uint32_t connect_start_ms;
|
||||||
uint8_t index;
|
uint8_t index;
|
||||||
tcp_client_instance_config_t config;
|
tcp_client_instance_config_t config;
|
||||||
tcp_client_status_t status;
|
tcp_client_status_t status;
|
||||||
@@ -37,6 +38,11 @@ static uint16_t ring_used(uint16_t head, uint16_t tail, uint16_t size)
|
|||||||
return (head >= tail) ? (uint16_t)(head - tail) : (uint16_t)(size - tail + head);
|
return (head >= tail) ? (uint16_t)(head - tail) : (uint16_t)(size - tail + head);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool tick_reached(uint32_t now, uint32_t deadline)
|
||||||
|
{
|
||||||
|
return ((int32_t)(now - deadline) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void tcp_client_reset_rx_state(tcp_client_ctx_t *ctx)
|
static void tcp_client_reset_rx_state(tcp_client_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
@@ -51,6 +57,31 @@ static void tcp_client_reset_rx_state(tcp_client_ctx_t *ctx)
|
|||||||
ctx->rx_tail = 0u;
|
ctx->rx_tail = 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tcp_client_abort_connect_timeout(tcp_client_ctx_t *ctx, uint32_t now)
|
||||||
|
{
|
||||||
|
if (ctx == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->pcb != NULL) {
|
||||||
|
tcp_arg(ctx->pcb, NULL);
|
||||||
|
tcp_recv(ctx->pcb, NULL);
|
||||||
|
tcp_sent(ctx->pcb, NULL);
|
||||||
|
tcp_err(ctx->pcb, NULL);
|
||||||
|
tcp_client_reset_rx_state(ctx);
|
||||||
|
tcp_abort(ctx->pcb);
|
||||||
|
ctx->pcb = NULL;
|
||||||
|
} else {
|
||||||
|
tcp_client_reset_rx_state(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->connect_start_ms = 0u;
|
||||||
|
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
|
||||||
|
ctx->status.errors++;
|
||||||
|
ctx->status.connect_timeout_count++;
|
||||||
|
ctx->next_retry_ms = now + ctx->config.reconnect_interval_ms;
|
||||||
|
}
|
||||||
|
|
||||||
static void tcp_client_fill_ring_from_pbuf(tcp_client_ctx_t *ctx)
|
static void tcp_client_fill_ring_from_pbuf(tcp_client_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
struct pbuf *q;
|
struct pbuf *q;
|
||||||
@@ -111,6 +142,7 @@ static err_t tcp_client_on_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p,
|
|||||||
tcp_err(pcb, NULL);
|
tcp_err(pcb, NULL);
|
||||||
tcp_abort(pcb);
|
tcp_abort(pcb);
|
||||||
ctx->pcb = NULL;
|
ctx->pcb = NULL;
|
||||||
|
ctx->connect_start_ms = 0u;
|
||||||
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
|
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
|
||||||
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
|
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
|
||||||
return ERR_ABRT;
|
return ERR_ABRT;
|
||||||
@@ -147,6 +179,7 @@ static void tcp_client_on_err(void *arg, err_t err)
|
|||||||
}
|
}
|
||||||
tcp_client_reset_rx_state(ctx);
|
tcp_client_reset_rx_state(ctx);
|
||||||
ctx->pcb = NULL;
|
ctx->pcb = NULL;
|
||||||
|
ctx->connect_start_ms = 0u;
|
||||||
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
|
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
|
||||||
ctx->status.errors++;
|
ctx->status.errors++;
|
||||||
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
|
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
|
||||||
@@ -162,6 +195,7 @@ static err_t tcp_client_on_connected(void *arg, struct tcp_pcb *pcb, err_t err)
|
|||||||
}
|
}
|
||||||
if (err != ERR_OK) {
|
if (err != ERR_OK) {
|
||||||
ctx->pcb = NULL;
|
ctx->pcb = NULL;
|
||||||
|
ctx->connect_start_ms = 0u;
|
||||||
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
|
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
|
||||||
ctx->status.errors++;
|
ctx->status.errors++;
|
||||||
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
|
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
|
||||||
@@ -169,6 +203,7 @@ static err_t tcp_client_on_connected(void *arg, struct tcp_pcb *pcb, err_t err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx->pcb = pcb;
|
ctx->pcb = pcb;
|
||||||
|
ctx->connect_start_ms = 0u;
|
||||||
ctx->status.state = TCP_CLIENT_STATE_CONNECTED;
|
ctx->status.state = TCP_CLIENT_STATE_CONNECTED;
|
||||||
tcp_nagle_disable(pcb);
|
tcp_nagle_disable(pcb);
|
||||||
tcp_arg(pcb, ctx);
|
tcp_arg(pcb, ctx);
|
||||||
@@ -228,6 +263,7 @@ int tcp_client_connect(uint8_t instance)
|
|||||||
if (err != ERR_OK) {
|
if (err != ERR_OK) {
|
||||||
tcp_abort(pcb);
|
tcp_abort(pcb);
|
||||||
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
|
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
|
||||||
|
ctx->connect_start_ms = 0u;
|
||||||
ctx->status.errors++;
|
ctx->status.errors++;
|
||||||
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
|
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -241,6 +277,7 @@ int tcp_client_connect(uint8_t instance)
|
|||||||
ctx->config.remote_ip[3]);
|
ctx->config.remote_ip[3]);
|
||||||
|
|
||||||
ctx->status.state = TCP_CLIENT_STATE_CONNECTING;
|
ctx->status.state = TCP_CLIENT_STATE_CONNECTING;
|
||||||
|
ctx->connect_start_ms = HAL_GetTick();
|
||||||
tcp_arg(pcb, ctx);
|
tcp_arg(pcb, ctx);
|
||||||
tcp_err(pcb, tcp_client_on_err);
|
tcp_err(pcb, tcp_client_on_err);
|
||||||
err = tcp_connect(pcb, &remote_addr, ctx->config.remote_port, tcp_client_on_connected);
|
err = tcp_connect(pcb, &remote_addr, ctx->config.remote_port, tcp_client_on_connected);
|
||||||
@@ -248,6 +285,7 @@ int tcp_client_connect(uint8_t instance)
|
|||||||
tcp_err(pcb, NULL);
|
tcp_err(pcb, NULL);
|
||||||
tcp_abort(pcb);
|
tcp_abort(pcb);
|
||||||
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
|
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
|
||||||
|
ctx->connect_start_ms = 0u;
|
||||||
ctx->status.errors++;
|
ctx->status.errors++;
|
||||||
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
|
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -274,6 +312,7 @@ int tcp_client_disconnect(uint8_t instance)
|
|||||||
tcp_abort(ctx->pcb);
|
tcp_abort(ctx->pcb);
|
||||||
ctx->pcb = NULL;
|
ctx->pcb = NULL;
|
||||||
}
|
}
|
||||||
|
ctx->connect_start_ms = 0u;
|
||||||
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
|
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
|
||||||
tcp_client_reset_rx_state(ctx);
|
tcp_client_reset_rx_state(ctx);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -368,21 +407,26 @@ uint16_t tcp_client_peek(uint8_t instance, uint8_t *data, uint16_t max_len)
|
|||||||
void tcp_client_drop(uint8_t instance, uint16_t len)
|
void tcp_client_drop(uint8_t instance, uint16_t len)
|
||||||
{
|
{
|
||||||
tcp_client_ctx_t *ctx;
|
tcp_client_ctx_t *ctx;
|
||||||
uint16_t dropped = 0u;
|
uint16_t acked = 0u;
|
||||||
|
|
||||||
if (instance >= TCP_CLIENT_INSTANCE_COUNT || len == 0u) {
|
if (instance >= TCP_CLIENT_INSTANCE_COUNT || len == 0u) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = &g_clients[instance];
|
ctx = &g_clients[instance];
|
||||||
while (dropped < len && ctx->rx_tail != ctx->rx_head) {
|
while (acked < len) {
|
||||||
ctx->rx_tail = (uint16_t)((ctx->rx_tail + 1u) % TCP_CLIENT_RX_BUFFER_SIZE);
|
tcp_client_fill_ring_from_pbuf(ctx);
|
||||||
dropped++;
|
if (ctx->rx_tail == ctx->rx_head) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (acked < len && ctx->rx_tail != ctx->rx_head) {
|
||||||
|
ctx->rx_tail = (uint16_t)((ctx->rx_tail + 1u) % TCP_CLIENT_RX_BUFFER_SIZE);
|
||||||
|
acked++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (dropped > 0u && ctx->pcb != NULL) {
|
if (acked > 0u && ctx->pcb != NULL) {
|
||||||
tcp_recved(ctx->pcb, dropped);
|
tcp_recved(ctx->pcb, acked);
|
||||||
}
|
}
|
||||||
tcp_client_fill_ring_from_pbuf(ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tcp_client_is_connected(uint8_t instance)
|
bool tcp_client_is_connected(uint8_t instance)
|
||||||
@@ -410,9 +454,12 @@ void tcp_client_poll(void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((ctx->pcb != NULL) && (ctx->status.state == TCP_CLIENT_STATE_CONNECTING)) {
|
if ((ctx->pcb != NULL) && (ctx->status.state == TCP_CLIENT_STATE_CONNECTING)) {
|
||||||
|
if ((uint32_t)(now - ctx->connect_start_ms) >= TCP_CLIENT_CONNECT_TIMEOUT_MS) {
|
||||||
|
tcp_client_abort_connect_timeout(ctx, now);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (now >= ctx->next_retry_ms) {
|
if (tick_reached(now, ctx->next_retry_ms)) {
|
||||||
ctx->status.reconnect_count++;
|
ctx->status.reconnect_count++;
|
||||||
ctx->next_retry_ms = now + ctx->config.reconnect_interval_ms;
|
ctx->next_retry_ms = now + ctx->config.reconnect_interval_ms;
|
||||||
(void)tcp_client_connect(i);
|
(void)tcp_client_connect(i);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ extern "C" {
|
|||||||
#define TCP_CLIENT_INSTANCE_COUNT 2u
|
#define TCP_CLIENT_INSTANCE_COUNT 2u
|
||||||
#define TCP_CLIENT_RX_BUFFER_SIZE 480u
|
#define TCP_CLIENT_RX_BUFFER_SIZE 480u
|
||||||
#define TCP_CLIENT_RECONNECT_DELAY_MS 3000u
|
#define TCP_CLIENT_RECONNECT_DELAY_MS 3000u
|
||||||
|
#define TCP_CLIENT_CONNECT_TIMEOUT_MS 10000u
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TCP_CLIENT_STATE_IDLE = 0,
|
TCP_CLIENT_STATE_IDLE = 0,
|
||||||
@@ -39,6 +40,7 @@ typedef struct {
|
|||||||
uint32_t rx_bytes;
|
uint32_t rx_bytes;
|
||||||
uint32_t tx_bytes;
|
uint32_t tx_bytes;
|
||||||
uint32_t reconnect_count;
|
uint32_t reconnect_count;
|
||||||
|
uint32_t connect_timeout_count;
|
||||||
uint32_t errors;
|
uint32_t errors;
|
||||||
} tcp_client_status_t;
|
} tcp_client_status_t;
|
||||||
|
|
||||||
|
|||||||
@@ -149,6 +149,19 @@ static void BootDiag_ReportCh390(void)
|
|||||||
cfg->net.mask[0], cfg->net.mask[1], cfg->net.mask[2], cfg->net.mask[3],
|
cfg->net.mask[0], cfg->net.mask[1], cfg->net.mask[2], cfg->net.mask[3],
|
||||||
cfg->net.gw[0], cfg->net.gw[1], cfg->net.gw[2], cfg->net.gw[3],
|
cfg->net.gw[0], cfg->net.gw[1], cfg->net.gw[2], cfg->net.gw[3],
|
||||||
cfg->mux_mode);
|
cfg->mux_mode);
|
||||||
|
SEGGER_RTT_printf(0,
|
||||||
|
"ETH rx ok=%u drop=%u pbuf_fail=%u filt=%u ipv6=%u udp=%u igmp=%u lldp=%u other_eth=%u other_ipv4=%u last=0x%04X\r\n",
|
||||||
|
(unsigned int)diag.rx_packets_ok,
|
||||||
|
(unsigned int)diag.rx_packets_drop,
|
||||||
|
(unsigned int)diag.rx_pbuf_alloc_failed,
|
||||||
|
(unsigned int)diag.rx_filtered_frames,
|
||||||
|
(unsigned int)diag.rx_filtered_ipv6,
|
||||||
|
(unsigned int)diag.rx_filtered_udp,
|
||||||
|
(unsigned int)diag.rx_filtered_igmp,
|
||||||
|
(unsigned int)diag.rx_filtered_lldp,
|
||||||
|
(unsigned int)diag.rx_filtered_other_eth,
|
||||||
|
(unsigned int)diag.rx_filtered_other_ipv4,
|
||||||
|
diag.last_eth_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void App_ConfigureLinks(const device_config_t *cfg)
|
static void App_ConfigureLinks(const device_config_t *cfg)
|
||||||
|
|||||||
@@ -22,11 +22,18 @@ static uint8_t ch390_runtime_drain_rx(struct netif *netif, uint8_t max_frames)
|
|||||||
{
|
{
|
||||||
struct pbuf *p;
|
struct pbuf *p;
|
||||||
uint8_t drained = 0u;
|
uint8_t drained = 0u;
|
||||||
|
uint8_t rx_ready;
|
||||||
|
|
||||||
while (drained < max_frames) {
|
while (drained < max_frames) {
|
||||||
p = ch390_runtime_input_frame(netif);
|
p = ch390_runtime_input_frame(netif);
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
break;
|
ch390_read_reg(CH390_MRCMDX);
|
||||||
|
rx_ready = ch390_read_reg(CH390_MRCMDX);
|
||||||
|
if ((rx_ready & CH390_PKT_RDY) == 0u) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
drained++;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
ch390_runtime_dispatch_frame(netif, p);
|
ch390_runtime_dispatch_frame(netif, p);
|
||||||
drained++;
|
drained++;
|
||||||
@@ -49,7 +56,179 @@ static uint8_t g_link_restart_pending;
|
|||||||
#define HEALTH_FAIL_SHIFT 4u
|
#define HEALTH_FAIL_SHIFT 4u
|
||||||
#define HEALTH_FAIL_MASK 0xF0u
|
#define HEALTH_FAIL_MASK 0xF0u
|
||||||
|
|
||||||
|
#define CH390_RX_FILTER_ENABLE 1u
|
||||||
|
#define CH390_RX_PREFIX_LEN 38u
|
||||||
|
#define CH390_ETH_HEADER_LEN 14u
|
||||||
|
#define CH390_IPV4_MIN_HEADER_LEN 20u
|
||||||
|
#define CH390_ETH_TYPE_IPV4 0x0800u
|
||||||
|
#define CH390_ETH_TYPE_ARP 0x0806u
|
||||||
|
#define CH390_ETH_TYPE_VLAN 0x8100u
|
||||||
|
#define CH390_ETH_TYPE_IPV6 0x86DDu
|
||||||
|
#define CH390_ETH_TYPE_QINQ 0x88A8u
|
||||||
|
#define CH390_ETH_TYPE_LLDP 0x88CCu
|
||||||
|
#define CH390_IP_PROTO_ICMP 1u
|
||||||
|
#define CH390_IP_PROTO_IGMP 2u
|
||||||
|
#define CH390_IP_PROTO_TCP 6u
|
||||||
|
#define CH390_IP_PROTO_UDP 17u
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CH390_RX_ACCEPT = 0,
|
||||||
|
CH390_RX_DROP_MALFORMED,
|
||||||
|
CH390_RX_DROP_IPV6,
|
||||||
|
CH390_RX_DROP_LLDP,
|
||||||
|
CH390_RX_DROP_UDP,
|
||||||
|
CH390_RX_DROP_IGMP,
|
||||||
|
CH390_RX_DROP_OTHER_ETH,
|
||||||
|
CH390_RX_DROP_OTHER_IPV4
|
||||||
|
} ch390_rx_filter_result_t;
|
||||||
|
|
||||||
static bool ch390_mac_address_valid(const uint8_t *mac);
|
static bool ch390_mac_address_valid(const uint8_t *mac);
|
||||||
|
static ch390_rx_filter_result_t ch390_runtime_filter_frame(const uint8_t *prefix, uint16_t frame_len, uint16_t prefix_len);
|
||||||
|
static void ch390_runtime_count_filtered_frame(ch390_rx_filter_result_t result);
|
||||||
|
static void ch390_runtime_copy_prefix_to_pbuf(struct pbuf *p, const uint8_t *prefix, uint16_t prefix_len);
|
||||||
|
static void ch390_runtime_read_remaining_to_pbuf(struct pbuf *p, uint16_t offset);
|
||||||
|
|
||||||
|
static ch390_rx_filter_result_t ch390_runtime_filter_frame(const uint8_t *prefix, uint16_t frame_len, uint16_t prefix_len)
|
||||||
|
{
|
||||||
|
uint16_t eth_type;
|
||||||
|
uint16_t l2_header_len = CH390_ETH_HEADER_LEN;
|
||||||
|
uint16_t ip_offset;
|
||||||
|
uint8_t ip_version;
|
||||||
|
uint8_t ip_ihl;
|
||||||
|
uint8_t ip_proto;
|
||||||
|
|
||||||
|
if ((prefix == NULL) || (frame_len < CH390_ETH_HEADER_LEN) || (prefix_len < CH390_ETH_HEADER_LEN)) {
|
||||||
|
return CH390_RX_DROP_MALFORMED;
|
||||||
|
}
|
||||||
|
|
||||||
|
eth_type = (uint16_t)(((uint16_t)prefix[12] << 8) | prefix[13]);
|
||||||
|
g_diag.last_eth_type = eth_type;
|
||||||
|
|
||||||
|
if ((eth_type == CH390_ETH_TYPE_VLAN) || (eth_type == CH390_ETH_TYPE_QINQ)) {
|
||||||
|
if ((frame_len < (CH390_ETH_HEADER_LEN + 4u)) || (prefix_len < (CH390_ETH_HEADER_LEN + 4u))) {
|
||||||
|
return CH390_RX_DROP_MALFORMED;
|
||||||
|
}
|
||||||
|
l2_header_len = (uint16_t)(CH390_ETH_HEADER_LEN + 4u);
|
||||||
|
eth_type = (uint16_t)(((uint16_t)prefix[16] << 8) | prefix[17]);
|
||||||
|
g_diag.last_eth_type = eth_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eth_type == CH390_ETH_TYPE_ARP) {
|
||||||
|
g_diag.rx_arp_frames++;
|
||||||
|
return CH390_RX_ACCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eth_type == CH390_ETH_TYPE_IPV6) {
|
||||||
|
return CH390_RX_DROP_IPV6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eth_type == CH390_ETH_TYPE_LLDP) {
|
||||||
|
return CH390_RX_DROP_LLDP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eth_type != CH390_ETH_TYPE_IPV4) {
|
||||||
|
return CH390_RX_DROP_OTHER_ETH;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_offset = l2_header_len;
|
||||||
|
if ((frame_len < (uint16_t)(ip_offset + CH390_IPV4_MIN_HEADER_LEN)) ||
|
||||||
|
(prefix_len < (uint16_t)(ip_offset + CH390_IPV4_MIN_HEADER_LEN))) {
|
||||||
|
return CH390_RX_DROP_MALFORMED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_version = (uint8_t)(prefix[ip_offset] >> 4);
|
||||||
|
ip_ihl = (uint8_t)(prefix[ip_offset] & 0x0Fu);
|
||||||
|
if ((ip_version != 4u) || (ip_ihl < 5u)) {
|
||||||
|
return CH390_RX_DROP_MALFORMED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_proto = prefix[ip_offset + 9u];
|
||||||
|
g_diag.rx_ip_frames++;
|
||||||
|
|
||||||
|
if (ip_proto == CH390_IP_PROTO_ICMP) {
|
||||||
|
g_diag.rx_ipv4_icmp_frames++;
|
||||||
|
return CH390_RX_ACCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ip_proto == CH390_IP_PROTO_TCP) {
|
||||||
|
g_diag.rx_ipv4_tcp_frames++;
|
||||||
|
return CH390_RX_ACCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ip_proto == CH390_IP_PROTO_UDP) {
|
||||||
|
g_diag.rx_ipv4_udp_frames++;
|
||||||
|
return CH390_RX_DROP_UDP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ip_proto == CH390_IP_PROTO_IGMP) {
|
||||||
|
g_diag.rx_filtered_igmp++;
|
||||||
|
return CH390_RX_DROP_IGMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CH390_RX_DROP_OTHER_IPV4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ch390_runtime_count_filtered_frame(ch390_rx_filter_result_t result)
|
||||||
|
{
|
||||||
|
g_diag.rx_filtered_frames++;
|
||||||
|
switch (result) {
|
||||||
|
case CH390_RX_DROP_MALFORMED:
|
||||||
|
g_diag.rx_filtered_malformed++;
|
||||||
|
break;
|
||||||
|
case CH390_RX_DROP_IPV6:
|
||||||
|
g_diag.rx_filtered_ipv6++;
|
||||||
|
break;
|
||||||
|
case CH390_RX_DROP_LLDP:
|
||||||
|
g_diag.rx_filtered_lldp++;
|
||||||
|
break;
|
||||||
|
case CH390_RX_DROP_UDP:
|
||||||
|
g_diag.rx_filtered_udp++;
|
||||||
|
break;
|
||||||
|
case CH390_RX_DROP_IGMP:
|
||||||
|
break;
|
||||||
|
case CH390_RX_DROP_OTHER_ETH:
|
||||||
|
g_diag.rx_filtered_other_eth++;
|
||||||
|
break;
|
||||||
|
case CH390_RX_DROP_OTHER_IPV4:
|
||||||
|
g_diag.rx_filtered_other_ipv4++;
|
||||||
|
break;
|
||||||
|
case CH390_RX_ACCEPT:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ch390_runtime_copy_prefix_to_pbuf(struct pbuf *p, const uint8_t *prefix, uint16_t prefix_len)
|
||||||
|
{
|
||||||
|
struct pbuf *q;
|
||||||
|
uint16_t copied = 0u;
|
||||||
|
|
||||||
|
for (q = p; (q != NULL) && (copied < prefix_len); q = q->next) {
|
||||||
|
uint16_t chunk = (uint16_t)(prefix_len - copied);
|
||||||
|
if (chunk > q->len) {
|
||||||
|
chunk = q->len;
|
||||||
|
}
|
||||||
|
memcpy(q->payload, &prefix[copied], chunk);
|
||||||
|
copied = (uint16_t)(copied + chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ch390_runtime_read_remaining_to_pbuf(struct pbuf *p, uint16_t offset)
|
||||||
|
{
|
||||||
|
struct pbuf *q;
|
||||||
|
uint16_t skipped = 0u;
|
||||||
|
|
||||||
|
for (q = p; q != NULL; q = q->next) {
|
||||||
|
if (skipped >= offset) {
|
||||||
|
ch390_read_mem((uint8_t *)q->payload, q->len);
|
||||||
|
} else if ((uint16_t)(skipped + q->len) > offset) {
|
||||||
|
uint16_t in_chunk_offset = (uint16_t)(offset - skipped);
|
||||||
|
uint16_t read_len = (uint16_t)(q->len - in_chunk_offset);
|
||||||
|
ch390_read_mem(&((uint8_t *)q->payload)[in_chunk_offset], read_len);
|
||||||
|
}
|
||||||
|
skipped = (uint16_t)(skipped + q->len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t ch390_runtime_is_restart_pending(void)
|
static uint8_t ch390_runtime_is_restart_pending(void)
|
||||||
{
|
{
|
||||||
@@ -154,12 +333,14 @@ struct pbuf *ch390_runtime_input_frame(struct netif *netif)
|
|||||||
{
|
{
|
||||||
struct ethernetif *ethernetif = (struct ethernetif *)netif->state;
|
struct ethernetif *ethernetif = (struct ethernetif *)netif->state;
|
||||||
struct pbuf *p = NULL;
|
struct pbuf *p = NULL;
|
||||||
struct pbuf *q;
|
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
uint16_t frame_len;
|
uint16_t frame_len;
|
||||||
|
uint16_t prefix_len;
|
||||||
uint8_t rcr;
|
uint8_t rcr;
|
||||||
uint8_t rx_ready;
|
uint8_t rx_ready;
|
||||||
uint8_t rx_header[4];
|
uint8_t rx_header[4];
|
||||||
|
uint8_t frame_prefix[CH390_RX_PREFIX_LEN];
|
||||||
|
ch390_rx_filter_result_t filter_result;
|
||||||
ch390_read_reg(CH390_MRCMDX);
|
ch390_read_reg(CH390_MRCMDX);
|
||||||
rx_ready = ch390_read_reg(CH390_MRCMDX);
|
rx_ready = ch390_read_reg(CH390_MRCMDX);
|
||||||
|
|
||||||
@@ -196,6 +377,23 @@ struct pbuf *ch390_runtime_input_frame(struct netif *netif)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ethernetif->rx_len = frame_len;
|
ethernetif->rx_len = frame_len;
|
||||||
|
prefix_len = frame_len;
|
||||||
|
if (prefix_len > CH390_RX_PREFIX_LEN) {
|
||||||
|
prefix_len = CH390_RX_PREFIX_LEN;
|
||||||
|
}
|
||||||
|
ch390_read_mem(frame_prefix, prefix_len);
|
||||||
|
|
||||||
|
#if CH390_RX_FILTER_ENABLE
|
||||||
|
filter_result = ch390_runtime_filter_frame(frame_prefix, frame_len, prefix_len);
|
||||||
|
if (filter_result != CH390_RX_ACCEPT) {
|
||||||
|
ch390_drop_packet((uint16_t)(frame_len - prefix_len));
|
||||||
|
LINK_STATS_INC(link.drop);
|
||||||
|
g_diag.rx_packets_drop++;
|
||||||
|
ch390_runtime_count_filtered_frame(filter_result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
len = ethernetif->rx_len;
|
len = ethernetif->rx_len;
|
||||||
#if ETH_PAD_SIZE
|
#if ETH_PAD_SIZE
|
||||||
len += ETH_PAD_SIZE;
|
len += ETH_PAD_SIZE;
|
||||||
@@ -206,9 +404,8 @@ struct pbuf *ch390_runtime_input_frame(struct netif *netif)
|
|||||||
#if ETH_PAD_SIZE
|
#if ETH_PAD_SIZE
|
||||||
pbuf_remove_header(p, ETH_PAD_SIZE);
|
pbuf_remove_header(p, ETH_PAD_SIZE);
|
||||||
#endif
|
#endif
|
||||||
for (q = p; q != NULL; q = q->next) {
|
ch390_runtime_copy_prefix_to_pbuf(p, frame_prefix, prefix_len);
|
||||||
ch390_read_mem((uint8_t *)q->payload, q->len);
|
ch390_runtime_read_remaining_to_pbuf(p, prefix_len);
|
||||||
}
|
|
||||||
#if ETH_PAD_SIZE
|
#if ETH_PAD_SIZE
|
||||||
pbuf_add_header(p, ETH_PAD_SIZE);
|
pbuf_add_header(p, ETH_PAD_SIZE);
|
||||||
#endif
|
#endif
|
||||||
@@ -218,10 +415,11 @@ struct pbuf *ch390_runtime_input_frame(struct netif *netif)
|
|||||||
g_diag.last_frame_len = frame_len;
|
g_diag.last_frame_len = frame_len;
|
||||||
g_diag.last_payload_len = p->tot_len;
|
g_diag.last_payload_len = p->tot_len;
|
||||||
} else {
|
} else {
|
||||||
ch390_drop_packet(ethernetif->rx_len);
|
ch390_drop_packet((uint16_t)(frame_len - prefix_len));
|
||||||
LINK_STATS_INC(link.memerr);
|
LINK_STATS_INC(link.memerr);
|
||||||
LINK_STATS_INC(link.drop);
|
LINK_STATS_INC(link.drop);
|
||||||
g_diag.rx_packets_drop++;
|
g_diag.rx_packets_drop++;
|
||||||
|
g_diag.rx_pbuf_alloc_failed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
|
|||||||
@@ -38,8 +38,20 @@ typedef struct {
|
|||||||
uint32_t rx_packets_drop;
|
uint32_t rx_packets_drop;
|
||||||
uint32_t tx_packets_ok;
|
uint32_t tx_packets_ok;
|
||||||
uint32_t tx_packets_timeout;
|
uint32_t tx_packets_timeout;
|
||||||
|
uint32_t rx_pbuf_alloc_failed;
|
||||||
|
uint32_t rx_filtered_frames;
|
||||||
|
uint32_t rx_filtered_ipv6;
|
||||||
|
uint32_t rx_filtered_udp;
|
||||||
|
uint32_t rx_filtered_igmp;
|
||||||
|
uint32_t rx_filtered_lldp;
|
||||||
|
uint32_t rx_filtered_other_eth;
|
||||||
|
uint32_t rx_filtered_other_ipv4;
|
||||||
|
uint32_t rx_filtered_malformed;
|
||||||
uint32_t rx_arp_frames;
|
uint32_t rx_arp_frames;
|
||||||
uint32_t rx_ip_frames;
|
uint32_t rx_ip_frames;
|
||||||
|
uint32_t rx_ipv4_icmp_frames;
|
||||||
|
uint32_t rx_ipv4_tcp_frames;
|
||||||
|
uint32_t rx_ipv4_udp_frames;
|
||||||
uint32_t rx_other_frames;
|
uint32_t rx_other_frames;
|
||||||
uint32_t rx_unicast_self_frames;
|
uint32_t rx_unicast_self_frames;
|
||||||
uint32_t rx_broadcast_frames;
|
uint32_t rx_broadcast_frames;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Code (inc. data) RO Data RW Data ZI Data Debug Object Name
|
Code (inc. data) RO Data RW Data ZI Data Debug Object Name
|
||||||
632 0 0 0 0 0 ch390.o
|
632 0 0 0 0 0 ch390.o
|
||||||
616 0 64 0 0 0 ch390_interface.o
|
616 0 64 0 0 0 ch390_interface.o
|
||||||
2050 0 85 6 88 0 ch390_runtime.o
|
2546 0 85 6 136 0 ch390_runtime.o
|
||||||
3958 0 591 8 1240 0 config.o
|
3958 0 591 8 1240 0 config.o
|
||||||
8 0 0 0 0 0 def.o
|
8 0 0 0 0 0 def.o
|
||||||
124 0 0 0 0 0 dma.o
|
124 0 0 0 0 0 dma.o
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
778 0 0 2 0 0 ip4.o
|
778 0 0 2 0 0 ip4.o
|
||||||
46 0 4 0 0 0 ip4_addr.o
|
46 0 4 0 0 0 ip4_addr.o
|
||||||
44 0 0 0 12 0 iwdg.o
|
44 0 0 0 12 0 iwdg.o
|
||||||
3212 0 185 12 272 0 main.o
|
3264 0 300 12 272 0 main.o
|
||||||
828 0 0 12 4115 0 mem.o
|
828 0 0 12 4115 0 mem.o
|
||||||
196 0 244 32 6464 0 memp.o
|
196 0 244 32 6464 0 memp.o
|
||||||
582 0 0 12 0 0 netif.o
|
582 0 0 12 0 0 netif.o
|
||||||
@@ -43,10 +43,10 @@
|
|||||||
490 0 0 0 0 0 stm32f1xx_it.o
|
490 0 0 0 0 0 stm32f1xx_it.o
|
||||||
2 0 24 4 0 0 system_stm32f1xx.o
|
2 0 24 4 0 0 system_stm32f1xx.o
|
||||||
3474 0 193 32 0 0 tcp.o
|
3474 0 193 32 0 0 tcp.o
|
||||||
1556 0 0 0 1072 0 tcp_client.o
|
1734 0 0 0 1088 0 tcp_client.o
|
||||||
3684 0 0 36 20 0 tcp_in.o
|
3684 0 0 36 20 0 tcp_in.o
|
||||||
3862 0 0 0 0 0 tcp_out.o
|
3862 0 0 0 0 0 tcp_out.o
|
||||||
1346 0 0 0 1048 0 tcp_server.o
|
1364 0 0 0 1048 0 tcp_server.o
|
||||||
164 0 0 0 72 0 tim.o
|
164 0 0 0 72 0 tim.o
|
||||||
374 0 16 12 0 0 timeouts.o
|
374 0 16 12 0 0 timeouts.o
|
||||||
1590 0 0 0 2936 0 uart_trans.o
|
1590 0 0 0 2936 0 uart_trans.o
|
||||||
@@ -57,8 +57,8 @@ Memory Map of the image
|
|||||||
|
|
||||||
Load Region LR_IROM1
|
Load Region LR_IROM1
|
||||||
|
|
||||||
Execution Region ER_IROM1 (Exec base: 0x08000000, Size: 0x0000DB7C, Max: 0x00010000, END)
|
Execution Region ER_IROM1 (Exec base: 0x08000000, Size: 0x0000DED8, Max: 0x00010000, END)
|
||||||
|
|
||||||
Execution Region RW_IRAM1 (Exec base: 0x20000000, Size: 0x00004F98, Max: 0x00005000, END)
|
Execution Region RW_IRAM1 (Exec base: 0x20000000, Size: 0x00004FD8, Max: 0x00005000, END)
|
||||||
|
|
||||||
Image component sizes
|
Image component sizes
|
||||||
@@ -246,6 +246,55 @@ EN,LPORT,RIP,RPORT,UART
|
|||||||
|
|
||||||
该结果说明修复后工程仍满足 `STM32F103R8T6` 的 `20KB RAM` 上限,但余量已经很小;后续若继续增加功能,应优先考虑复用现有缓冲与状态,而不是增加新的静态大数组。
|
该结果说明修复后工程仍满足 `STM32F103R8T6` 的 `20KB RAM` 上限,但余量已经很小;后续若继续增加功能,应优先考虑复用现有缓冲与状态,而不是增加新的静态大数组。
|
||||||
|
|
||||||
|
### 6.3 客户现场脏网络恢复增强
|
||||||
|
|
||||||
|
客户现场换 PC 后曾出现设备持续 ARP、`ping` 不通、TCP Client 不恢复的现象。抓包显示故障前后存在 IPv6、DHCPv6、mDNS、IGMP、LLDP 等与当前业务无关的网络噪声;当前固件为静态 IPv4、TCP2UART 与 ICMP 诊断模型,不依赖 UDP、IPv6、DHCP 或多播发现。
|
||||||
|
|
||||||
|
本阶段采用低 RAM 优先的恢复策略,不先扩大 `PBUF_POOL_SIZE`,而是在更靠近入口的位置减少无关帧对 lwIP pool 的占用:
|
||||||
|
|
||||||
|
1. `TCP Client CONNECTING` 增加应用层超时:
|
||||||
|
- `TCP_CLIENT_CONNECT_TIMEOUT_MS = 10000`
|
||||||
|
- `tcp_connect()` 返回 `ERR_OK` 后记录 `connect_start_ms`
|
||||||
|
- `tcp_client_poll()` 发现 `CONNECTING` 超过超时时间后,注销回调、`tcp_abort()` 当前 PCB、释放 `hold_pbuf`,再按原有 `reconnect_interval_ms` 重连
|
||||||
|
- `tcp_client_status_t.connect_timeout_count` 记录发生次数
|
||||||
|
2. `CH390` RX 入口增加 `pre-pbuf` 协议过滤:
|
||||||
|
- 在 `pbuf_alloc(PBUF_RAW, ..., PBUF_POOL)` 之前先读取以太网头与最小 IPv4 头
|
||||||
|
- 允许进入 lwIP 的协议限定为 `ARP`、`IPv4 ICMP`、`IPv4 TCP`
|
||||||
|
- 默认丢弃 `IPv6`、`IPv4 UDP`、`IPv4 IGMP`、`LLDP`、未知 EtherType 与畸形头
|
||||||
|
- 丢弃帧只跳过 CH390 RX FIFO 剩余字节,不分配 pbuf
|
||||||
|
3. 软件 MAC 过滤暂不启用:
|
||||||
|
- 第一版只做协议层过滤,避免误杀广播 ARP 或未来硬件过滤策略变化
|
||||||
|
- 目的 MAC 相关判断保留为后续可选增强
|
||||||
|
|
||||||
|
新增 CH390 诊断字段用于现场判断是否仍存在资源压力:
|
||||||
|
|
||||||
|
1. `rx_pbuf_alloc_failed`
|
||||||
|
2. `rx_filtered_frames`
|
||||||
|
3. `rx_filtered_ipv6`
|
||||||
|
4. `rx_filtered_udp`
|
||||||
|
5. `rx_filtered_igmp`
|
||||||
|
6. `rx_filtered_lldp`
|
||||||
|
7. `rx_filtered_other_eth`
|
||||||
|
8. `rx_filtered_other_ipv4`
|
||||||
|
9. `rx_filtered_malformed`
|
||||||
|
10. `rx_ipv4_icmp_frames`
|
||||||
|
11. `rx_ipv4_tcp_frames`
|
||||||
|
12. `rx_ipv4_udp_frames`
|
||||||
|
|
||||||
|
验收口径:
|
||||||
|
|
||||||
|
1. 正常 `ARP / ping / TCP Server / TCP Client` 功能不受影响
|
||||||
|
2. 客户脏网络中的 IPv6、UDP、IGMP、LLDP 噪声不会进入 lwIP pbuf pool
|
||||||
|
3. 若远端 TCP Server 不监听或静默丢 SYN,TCP Client 不再永久停留在 `CONNECTING`
|
||||||
|
4. 若过滤后 `rx_pbuf_alloc_failed` 仍持续增长,再评估从无关功能中回收 RAM 并调整 `PBUF_POOL_SIZE`
|
||||||
|
|
||||||
|
本阶段 Keil 构建验收结果:
|
||||||
|
|
||||||
|
1. `errors = 0`
|
||||||
|
2. `warnings = 0`
|
||||||
|
3. `flash_bytes = 57404`
|
||||||
|
4. `ram_bytes = 20440`
|
||||||
|
|
||||||
## 七、主循环实现方向
|
## 七、主循环实现方向
|
||||||
|
|
||||||
主循环仍保持裸机轮询风格:
|
主循环仍保持裸机轮询风格:
|
||||||
|
|||||||
Reference in New Issue
Block a user