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 <john.filip.johnson@gmail.com>
This commit is contained in:
parent
9cf3e08429
commit
dbf3d6e911
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -1074,6 +1076,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;
|
||||
}
|
||||
|
||||
|
@ -1081,6 +1085,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);
|
||||
}
|
||||
|
||||
|
@ -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, ""),
|
||||
|
|
|
@ -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);
|
||||
&data_len, raw_remote_ip, &port);
|
||||
#else
|
||||
err = cmd_ciprecvdata_parse(sock, data->rx_buf, len, &data_offset,
|
||||
&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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue