Skip to content

Commit

Permalink
drivers: esp_at: implement bind() and recvfrom() for UDP sockets
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
LonesomeUnixCowboy authored and aescolar committed Feb 26, 2024
1 parent 9cf3e08 commit dbf3d6e
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 23 deletions.
5 changes: 5 additions & 0 deletions drivers/wifi/esp_at/Kconfig.esp_at
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 12 additions & 1 deletion drivers/wifi/esp_at/esp.c
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,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);
}

Expand Down Expand Up @@ -1074,13 +1076,19 @@ 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;
}

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);
}

Expand Down Expand Up @@ -1127,6 +1135,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, ""),
Expand Down
121 changes: 99 additions & 22 deletions drivers/wifi/esp_at/esp_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}

Expand All @@ -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,
Expand Down Expand Up @@ -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);

This comment has been minimized.

Copy link
@WilliamGFish

WilliamGFish Feb 26, 2024

Collaborator

UDP previously worked for devices connecting to an AP, this needs to either be implemented if CIPDINFO is enabled or if working as AP.

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,
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand All @@ -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);
}
}

Expand All @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions drivers/wifi/esp_at/esp_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down

0 comments on commit dbf3d6e

Please sign in to comment.