From 1ab0848eab1b107b4c1796ebef9a2b0551bf3a27 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Thu, 1 Jul 2021 16:21:18 +0200 Subject: [PATCH] drivers: wifi: esp_at: close stream socket after failure to send So far send errors were silently ignored. This is okay for UDP (datagram) sockets, as there is no guarantee that packets will actually be sent successfully. In case of TCP (stream) stream sockets however, application layer expects network stack to send requested data as stream, without losing any part of it. In case of send errors on stream sockets mark that socket to be closed and stop sending any subsequent network packets, so that data stream won't have any holes. Signed-off-by: Marcin Niestroj --- drivers/wifi/esp_at/esp_offload.c | 77 ++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 21 deletions(-) diff --git a/drivers/wifi/esp_at/esp_offload.c b/drivers/wifi/esp_at/esp_offload.c index 23867c1ea7d..e3b5d2a8514 100644 --- a/drivers/wifi/esp_at/esp_offload.c +++ b/drivers/wifi/esp_at/esp_offload.c @@ -290,32 +290,67 @@ out: return ret; } +static bool esp_socket_can_send(struct esp_socket *sock) +{ + atomic_val_t flags = esp_socket_flags(sock); + + if ((flags & ESP_SOCK_CONNECTED) && !(flags & ESP_SOCK_CLOSE_PENDING)) { + return true; + } + + return false; +} + +static int esp_socket_send_one_pkt(struct esp_socket *sock) +{ + struct net_context *context = sock->context; + struct net_pkt *pkt; + int ret; + + pkt = k_fifo_get(&sock->tx_fifo, K_NO_WAIT); + if (!pkt) { + return -ENOMSG; + } + + if (!esp_socket_can_send(sock)) { + goto pkt_unref; + } + + ret = _sock_send(sock, pkt); + if (ret < 0) { + LOG_ERR("Failed to send data: link %d, ret %d", + sock->link_id, ret); + + /* + * If this is stream data, then we should stop pushing anything + * more to this socket, as there will be a hole in the data + * stream, which application layer is not expecting. + */ + if (esp_socket_type(sock) == SOCK_STREAM) { + if (!esp_socket_flags_test_and_set(sock, + ESP_SOCK_CLOSE_PENDING)) { + esp_socket_work_submit(sock, &sock->close_work); + } + } + } else if (context->send_cb) { + context->send_cb(context, ret, context->user_data); + } + +pkt_unref: + net_pkt_unref(pkt); + + return 0; +} + void esp_send_work(struct k_work *work) { struct esp_socket *sock = CONTAINER_OF(work, struct esp_socket, send_work); - struct net_context *context = sock->context; - struct net_pkt *pkt; - int ret = 0; + int err; - while (true) { - pkt = k_fifo_get(&sock->tx_fifo, K_NO_WAIT); - if (!pkt) { - break; - } - - ret = _sock_send(sock, pkt); - if (ret < 0) { - LOG_ERR("Failed to send data: link %d, ret %d", - sock->link_id, ret); - } - - if (context->send_cb) { - context->send_cb(context, ret, context->user_data); - } - - net_pkt_unref(pkt); - } + do { + err = esp_socket_send_one_pkt(sock); + } while (err != -ENOMSG); } static int esp_sendto(struct net_pkt *pkt,