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. Also set net_if to
non-dormant when enableing AP mode to make binding to a port and address
possible and back to dormant when AP is disabled.

Signed-off-by: John Johnson <john.filip.johnson@gmail.com>
  • Loading branch information
LonesomeUnixCowboy committed Feb 7, 2024
1 parent 826d67a commit d99b399
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 76 deletions.
7 changes: 7 additions & 0 deletions drivers/wifi/esp_at/esp.c
Expand Up @@ -1070,13 +1070,19 @@ static int esp_mgmt_ap_enable(const struct device *dev,

ret = esp_cmd_send(data, NULL, 0, cmd, ESP_CMD_TIMEOUT);

wifi_mgmt_raise_connect_result_event(data->net_iface, 0);
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;

wifi_mgmt_raise_disconnect_result_event(data->net_iface, 0);
net_if_dormant_on(data->net_iface);

return esp_mode_flags_clear(data, EDF_AP_ENABLED);
}

Expand Down Expand Up @@ -1123,6 +1129,7 @@ static void esp_init_work(struct k_work *work)
#endif
#if defined(CONFIG_WIFI_ESP_AT_PASSIVE_MODE)
SETUP_CMD_NOHANDLE("AT+CIPRECVMODE=1"),
SETUP_CMD_NOHANDLE("AT+CIPDINFO=1"),
#endif
SETUP_CMD("AT+"_CIPSTAMAC"?", "+"_CIPSTAMAC":",
on_cmd_cipstamac, 1U, ""),
Expand Down
145 changes: 69 additions & 76 deletions drivers/wifi/esp_at/esp_offload.c
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);
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 @@ -405,75 +426,47 @@ static int esp_send(struct net_pkt *pkt,
return esp_sendto(pkt, NULL, 0, cb, timeout, user_data);
}

#define CIPRECVDATA_CMD_MIN_LEN (sizeof("+CIPRECVDATA,L:") - 1)
#define CIPRECVDATA_CMD_MAX_LEN (sizeof("+CIPRECVDATA,LLLL:") - 1)

static int cmd_ciprecvdata_parse(struct esp_socket *sock,
struct net_buf *buf, uint16_t len,
int *data_offset, int *data_len)
MODEM_CMD_DEFINE(on_cmd_ciprecvdata)
{
char cmd_buf[CIPRECVDATA_CMD_MAX_LEN + 1];
char *endptr;
size_t frags_len;
size_t match_len;

frags_len = net_buf_frags_len(buf);
if (frags_len < CIPRECVDATA_CMD_MIN_LEN) {
return -EAGAIN;
}

match_len = net_buf_linearize(cmd_buf, CIPRECVDATA_CMD_MAX_LEN,
buf, 0, CIPRECVDATA_CMD_MAX_LEN);
cmd_buf[match_len] = 0;

*data_len = strtol(&cmd_buf[len], &endptr, 10);
if (endptr == &cmd_buf[len] ||
(*endptr == 0 && match_len >= CIPRECVDATA_CMD_MAX_LEN) ||
*data_len > CIPRECVDATA_MAX_LEN) {
LOG_ERR("Invalid cmd: %s", cmd_buf);
return -EBADMSG;
} else if (*endptr == 0) {
return -EAGAIN;
} else if (*endptr != _CIPRECVDATA_END) {
LOG_ERR("Invalid end of cmd: 0x%02x != 0x%02x", *endptr,
_CIPRECVDATA_END);
return -EBADMSG;
}
struct esp_data *dev = CONTAINER_OF(data, struct esp_data,
cmd_handler_data);
struct esp_socket *sock = dev->rx_sock;
int err;

/* data_offset is the offset to where the actual data starts */
*data_offset = (endptr - cmd_buf) + 1;
int socket_data_length = atoi(argv[0]);

/* FIXME: Inefficient way of waiting for data */
if (*data_offset + *data_len > frags_len) {
if ((net_buf_frags_len(data->rx_buf) - 2) < socket_data_length) {
LOG_DBG("Not enough data -- wait!");
return -EAGAIN;
}

*endptr = 0;
struct sockaddr_in *recv_addr =
(struct sockaddr_in *) &sock->context->remote;
int port = atoi(argv[2]);

return 0;
}
recv_addr->sin_port = ntohs(port);
recv_addr->sin_family = AF_INET;

MODEM_CMD_DIRECT_DEFINE(on_cmd_ciprecvdata)
{
struct esp_data *dev = CONTAINER_OF(data, struct esp_data,
cmd_handler_data);
struct esp_socket *sock = dev->rx_sock;
int data_offset, data_len;
int err;
/* IP addr comes within quotation marks, which is disliked by
* conv function. So we remove them by subtraction 2 from argv[1]
* length and index from &argv[1][1].
*/
char remote_ip_addr[INET_ADDRSTRLEN];
size_t remote_ip_str_len;

err = cmd_ciprecvdata_parse(sock, data->rx_buf, len, &data_offset,
&data_len);
if (err) {
if (err == -EAGAIN) {
return -EAGAIN;
}
remote_ip_str_len = MIN(sizeof(remote_ip_addr) - 1, strlen(argv[1]) - 2);
strncpy(remote_ip_addr, &argv[1][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;
}

esp_socket_rx(sock, data->rx_buf, data_offset, data_len);
esp_socket_rx(sock, data->rx_buf, 0, len);

return data_offset + data_len;
return len;
}

void esp_recvdata_work(struct k_work *work)
Expand All @@ -483,7 +476,7 @@ void esp_recvdata_work(struct k_work *work)
struct esp_data *data = esp_socket_to_dev(sock);
char cmd[sizeof("AT+CIPRECVDATA=000,"STRINGIFY(CIPRECVDATA_MAX_LEN))];
static const struct modem_cmd cmds[] = {
MODEM_CMD_DIRECT(_CIPRECVDATA, on_cmd_ciprecvdata),
MODEM_CMD(_CIPRECVDATA, on_cmd_ciprecvdata, 3U, ","),
};
int ret;

Expand Down
4 changes: 4 additions & 0 deletions drivers/wifi/esp_at/esp_socket.c
Expand Up @@ -140,6 +140,10 @@ static struct net_pkt *esp_socket_prepare_pkt(struct esp_socket *sock,
net_pkt_set_context(pkt, sock->context);
net_pkt_cursor_init(pkt);

#ifdef CONFIG_WIFI_ESP_AT_PASSIVE_MODE
memcpy(&pkt->remote, &sock->context->remote, sizeof(pkt->remote));
pkt->family = sock->dst.sa_family;
#endif
return pkt;
}

Expand Down

0 comments on commit d99b399

Please sign in to comment.