From 3a187c965d67607fcb4bd5760b42d4d7ee35c484 Mon Sep 17 00:00:00 2001 From: John Johnson Date: Mon, 5 Feb 2024 15:04:15 +0100 Subject: [PATCH] drivers: esp_at: implement bind() and recvfrom() for UDP sockets Implement bind() and recvfrom() for UDP sockets. This is achived by setting remote field in net_pkt which in return makes recvfrom() fill in *src_addr. This is only implemented for passiv mode and CIPDINFO needs to be enabled. Also set net_if to non-dormant when enabling AP mode to make binding to a port and address possible. Signed-off-by: John Johnson --- drivers/wifi/esp_at/Kconfig.esp_at | 5 ++ drivers/wifi/esp_at/esp.c | 13 +++- drivers/wifi/esp_at/esp_offload.c | 121 +++++++++++++++++++++++------ drivers/wifi/esp_at/esp_socket.c | 5 ++ 4 files changed, 121 insertions(+), 23 deletions(-) diff --git a/drivers/wifi/esp_at/Kconfig.esp_at b/drivers/wifi/esp_at/Kconfig.esp_at index 9b7e38045d95..6c418db9d0e4 100644 --- a/drivers/wifi/esp_at/Kconfig.esp_at +++ b/drivers/wifi/esp_at/Kconfig.esp_at @@ -161,6 +161,11 @@ config WIFI_ESP_AT_DNS_USE Fetch DNS servers from ESP chip with AT+CIPDNS? command and apply that list to system DNS resolver. +config WIFI_ESP_AT_CIPDINFO_USE + bool "Use CIPDINFO to get peer ip and port" + help + Enable AT+CIPDINFO got get peer ip-address and port. + config WIFI_ESP_AT_FETCH_VERSION bool "Fetch and log ESP-AT firmware version" default y diff --git a/drivers/wifi/esp_at/esp.c b/drivers/wifi/esp_at/esp.c index e71a9b2bc1c6..868f1c8f1ec2 100644 --- a/drivers/wifi/esp_at/esp.c +++ b/drivers/wifi/esp_at/esp.c @@ -447,7 +447,9 @@ static void esp_mgmt_disconnect_work(struct k_work *work) #if defined(CONFIG_NET_NATIVE_IPV4) net_if_ipv4_addr_rm(dev->net_iface, &dev->ip); #endif - net_if_dormant_on(dev->net_iface); + if (!esp_flags_are_set(dev, EDF_AP_ENABLED)) { + net_if_dormant_on(dev->net_iface); + } wifi_mgmt_raise_disconnect_result_event(dev->net_iface, 0); } @@ -1070,6 +1072,8 @@ static int esp_mgmt_ap_enable(const struct device *dev, ret = esp_cmd_send(data, NULL, 0, cmd, ESP_CMD_TIMEOUT); + net_if_dormant_off(data->net_iface); + return ret; } @@ -1077,6 +1081,10 @@ static int esp_mgmt_ap_disable(const struct device *dev) { struct esp_data *data = dev->data; + if (!esp_flags_are_set(data, EDF_STA_CONNECTED)) { + net_if_dormant_on(data->net_iface); + } + return esp_mode_flags_clear(data, EDF_AP_ENABLED); } @@ -1123,6 +1131,9 @@ static void esp_init_work(struct k_work *work) #endif #if defined(CONFIG_WIFI_ESP_AT_PASSIVE_MODE) SETUP_CMD_NOHANDLE("AT+CIPRECVMODE=1"), +#endif +#if defined(CONFIG_WIFI_ESP_AT_CIPDINFO_USE) + SETUP_CMD_NOHANDLE("AT+CIPDINFO=1"), #endif SETUP_CMD("AT+"_CIPSTAMAC"?", "+"_CIPSTAMAC":", on_cmd_cipstamac, 1U, ""), diff --git a/drivers/wifi/esp_at/esp_offload.c b/drivers/wifi/esp_at/esp_offload.c index e8055b22b36c..96e2b143a219 100644 --- a/drivers/wifi/esp_at/esp_offload.c +++ b/drivers/wifi/esp_at/esp_offload.c @@ -20,16 +20,6 @@ LOG_MODULE_REGISTER(wifi_esp_at_offload, CONFIG_WIFI_LOG_LEVEL); #include "esp.h" -static int esp_bind(struct net_context *context, const struct sockaddr *addr, - socklen_t addrlen) -{ - if (IS_ENABLED(CONFIG_NET_IPV4) && addr->sa_family == AF_INET) { - return 0; - } - - return -EAFNOSUPPORT; -} - static int esp_listen(struct net_context *context, int backlog) { return -ENOTSUP; @@ -43,7 +33,7 @@ static int _sock_connect(struct esp_data *dev, struct esp_socket *sock) struct sockaddr dst; int ret; - if (!esp_flags_are_set(dev, EDF_STA_CONNECTED)) { + if (!esp_flags_are_set(dev, EDF_STA_CONNECTED | EDF_AP_ENABLED)) { return -ENETUNREACH; } @@ -62,9 +52,9 @@ static int _sock_connect(struct esp_data *dev, struct esp_socket *sock) ntohs(net_sin(&dst)->sin_port)); } else { snprintk(connect_msg, sizeof(connect_msg), - "AT+CIPSTART=%d,\"UDP\",\"%s\",%d", + "AT+CIPSTART=%d,\"UDP\",\"%s\",%d,%d", sock->link_id, addr_str, - ntohs(net_sin(&dst)->sin_port)); + ntohs(net_sin(&dst)->sin_port), ntohs(net_sin(&dst)->sin_port)); } LOG_DBG("link %d, ip_proto %s, addr %s", sock->link_id, @@ -106,6 +96,40 @@ void esp_connect_work(struct k_work *work) k_mutex_unlock(&sock->lock); } +static int esp_bind(struct net_context *context, const struct sockaddr *addr, + socklen_t addrlen) +{ + struct esp_socket *sock; + struct esp_data *dev; + + sock = (struct esp_socket *)context->offload_context; + dev = esp_socket_to_dev(sock); + + if (esp_socket_ip_proto(sock) == IPPROTO_TCP) { + return 0; + } + + if (IS_ENABLED(CONFIG_NET_IPV4) && addr->sa_family == AF_INET) { + LOG_DBG("link %d", sock->link_id); + + if (esp_socket_connected(sock)) { + return -EISCONN; + } + + k_mutex_lock(&sock->lock, K_FOREVER); + sock->dst = *addr; + sock->connect_cb = NULL; + sock->conn_user_data = NULL; + k_mutex_unlock(&sock->lock); + + _sock_connect(dev, sock); + + return 0; + } + + return -EAFNOSUPPORT; +} + static int esp_connect(struct net_context *context, const struct sockaddr *addr, socklen_t addrlen, @@ -204,7 +228,7 @@ static int _sock_send(struct esp_socket *sock, struct net_pkt *pkt) }; struct sockaddr dst; - if (!esp_flags_are_set(dev, EDF_STA_CONNECTED)) { + if (!esp_flags_are_set(dev, EDF_STA_CONNECTED | EDF_AP_ENABLED)) { return -ENETUNREACH; } @@ -360,7 +384,7 @@ static int esp_sendto(struct net_pkt *pkt, LOG_DBG("link %d, timeout %d", sock->link_id, timeout); - if (!esp_flags_are_set(dev, EDF_STA_CONNECTED)) { + if (!esp_flags_are_set(dev, EDF_STA_CONNECTED | EDF_AP_ENABLED)) { return -ENETUNREACH; } @@ -386,11 +410,8 @@ static int esp_sendto(struct net_pkt *pkt, if (ret < 0) { return ret; } - } else if (dst_addr && memcmp(dst_addr, &sock->dst, addrlen)) { - /* This might be unexpected behaviour but the ESP - * doesn't support changing endpoint. - */ - return -EISCONN; + } else if (esp_socket_type(sock) == SOCK_DGRAM) { + memcpy(&sock->dst, dst_addr, addrlen); } } @@ -406,11 +427,17 @@ static int esp_send(struct net_pkt *pkt, } #define CIPRECVDATA_CMD_MIN_LEN (sizeof("+CIPRECVDATA,L:") - 1) + +#if defined(CONFIG_WIFI_ESP_AT_CIPDINFO_USE) +#define CIPRECVDATA_CMD_MAX_LEN (sizeof("+CIPRECVDATA,LLLL,\"255.255.255.255\",65535:") - 1) +#else #define CIPRECVDATA_CMD_MAX_LEN (sizeof("+CIPRECVDATA,LLLL:") - 1) +#endif static int cmd_ciprecvdata_parse(struct esp_socket *sock, struct net_buf *buf, uint16_t len, - int *data_offset, int *data_len) + int *data_offset, int *data_len, char *ip_str, + int *port) { char cmd_buf[CIPRECVDATA_CMD_MAX_LEN + 1]; char *endptr; @@ -427,6 +454,23 @@ static int cmd_ciprecvdata_parse(struct esp_socket *sock, cmd_buf[match_len] = 0; *data_len = strtol(&cmd_buf[len], &endptr, 10); + +#if defined(CONFIG_WIFI_ESP_AT_CIPDINFO_USE) + char *strstart = endptr + 1; + char *strend = strchr(strstart, ','); + + if (strstart == NULL || strend == NULL) { + return -EAGAIN; + } + + memcpy(ip_str, strstart, strend - strstart); + ip_str[strend - strstart] = '\0'; + *port = strtol(strend + 1, &endptr, 10); +#else + ARG_UNUSED(ip_str); + ARG_UNUSED(port); +#endif + if (endptr == &cmd_buf[len] || (*endptr == 0 && match_len >= CIPRECVDATA_CMD_MAX_LEN) || *data_len > CIPRECVDATA_MAX_LEN) { @@ -461,8 +505,16 @@ MODEM_CMD_DIRECT_DEFINE(on_cmd_ciprecvdata) int data_offset, data_len; int err; +#if defined(CONFIG_WIFI_ESP_AT_CIPDINFO_USE) + char raw_remote_ip[INET_ADDRSTRLEN + 3] = {0}; + int port = 0; + + err = cmd_ciprecvdata_parse(sock, data->rx_buf, len, &data_offset, + &data_len, raw_remote_ip, &port); +#else err = cmd_ciprecvdata_parse(sock, data->rx_buf, len, &data_offset, - &data_len); + &data_len, NULL, NULL); +#endif if (err) { if (err == -EAGAIN) { return -EAGAIN; @@ -471,6 +523,31 @@ MODEM_CMD_DIRECT_DEFINE(on_cmd_ciprecvdata) return err; } +#if defined(CONFIG_WIFI_ESP_AT_CIPDINFO_USE) + struct sockaddr_in *recv_addr = + (struct sockaddr_in *) &sock->context->remote; + + recv_addr->sin_port = ntohs(port); + recv_addr->sin_family = AF_INET; + + /* IP addr comes within quotation marks, which is disliked by + * conv function. So we remove them by subtraction 2 from + * raw_remote_ip length and index from &raw_remote_ip[1]. + */ + char remote_ip_addr[INET_ADDRSTRLEN]; + size_t remote_ip_str_len; + + remote_ip_str_len = MIN(sizeof(remote_ip_addr) - 1, + strlen(raw_remote_ip) - 2); + strncpy(remote_ip_addr, &raw_remote_ip[1], remote_ip_str_len); + remote_ip_addr[remote_ip_str_len] = '\0'; + + if (net_addr_pton(AF_INET, remote_ip_addr, &recv_addr->sin_addr) < 0) { + LOG_ERR("Invalid src addr %s", remote_ip_addr); + err = -EIO; + return err; + } +#endif esp_socket_rx(sock, data->rx_buf, data_offset, data_len); return data_offset + data_len; diff --git a/drivers/wifi/esp_at/esp_socket.c b/drivers/wifi/esp_at/esp_socket.c index 6a4147e528b8..c32bbae21f99 100644 --- a/drivers/wifi/esp_at/esp_socket.c +++ b/drivers/wifi/esp_at/esp_socket.c @@ -140,6 +140,11 @@ static struct net_pkt *esp_socket_prepare_pkt(struct esp_socket *sock, net_pkt_set_context(pkt, sock->context); net_pkt_cursor_init(pkt); +#if defined(CONFIG_WIFI_ESP_AT_CIPDINFO_USE) + memcpy(&pkt->remote, &sock->context->remote, sizeof(pkt->remote)); + pkt->family = sock->dst.sa_family; +#endif + return pkt; }