wifi: eswifi: Implement TCP/UDP socket offload with TLS
Newly implement socket based communication on eswifi mainly to achive TLS. Tested with Inventek ISM43362-M3G-L44. Signed-off-by: Saravanan Sekar <saravanan@linumiz.com>
This commit is contained in:
parent
207943c2a7
commit
1aa696bc2b
|
@ -12,5 +12,7 @@ if(CONFIG_WIFI_ESWIFI)
|
|||
eswifi_core.c
|
||||
eswifi_bus_spi.c
|
||||
eswifi_offload.c
|
||||
eswifi_socket.c
|
||||
)
|
||||
zephyr_sources_ifdef(CONFIG_NET_SOCKETS_OFFLOAD eswifi_socket_offload.c)
|
||||
endif()
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <zephyr.h>
|
||||
#include <kernel.h>
|
||||
#include <stdio.h>
|
||||
#include <kernel_structs.h>
|
||||
|
||||
#include <net/wifi_mgmt.h>
|
||||
|
@ -110,12 +111,37 @@ static inline void eswifi_unlock(struct eswifi_dev *eswifi)
|
|||
}
|
||||
}
|
||||
|
||||
int eswifi_at_cmd(struct eswifi_dev *eswifi, char *cmd);
|
||||
static inline int __select_socket(struct eswifi_dev *eswifi, u8_t idx)
|
||||
{
|
||||
snprintf(eswifi->buf, sizeof(eswifi->buf), "P0=%d\r", idx);
|
||||
return eswifi_at_cmd(eswifi, eswifi->buf);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct eswifi_dev *eswifi_socket_to_dev(struct eswifi_off_socket *socket)
|
||||
{
|
||||
return CONTAINER_OF(socket - socket->index, struct eswifi_dev, socket);
|
||||
}
|
||||
|
||||
extern struct eswifi_bus_ops eswifi_bus_ops_spi;
|
||||
int eswifi_offload_init(struct eswifi_dev *eswifi);
|
||||
struct eswifi_dev *eswifi_by_iface_idx(u8_t iface);
|
||||
int eswifi_at_cmd_rsp(struct eswifi_dev *eswifi, char *cmd, char **rsp);
|
||||
int eswifi_at_cmd(struct eswifi_dev *eswifi, char *cmd);
|
||||
void eswifi_async_msg(struct eswifi_dev *eswifi, char *msg, size_t len);
|
||||
void eswifi_offload_async_msg(struct eswifi_dev *eswifi, char *msg, size_t len);
|
||||
|
||||
int __eswifi_socket_free(struct eswifi_dev *eswifi,
|
||||
struct eswifi_off_socket *socket);
|
||||
int __eswifi_socket_new(struct eswifi_dev *eswifi, int family, int type,
|
||||
int proto, void *context);
|
||||
int __eswifi_off_start_client(struct eswifi_dev *eswifi,
|
||||
struct eswifi_off_socket *socket);
|
||||
int __eswifi_accept(struct eswifi_dev *eswifi, struct eswifi_off_socket *socket);
|
||||
int __eswifi_bind(struct eswifi_dev *eswifi, struct eswifi_off_socket *socket,
|
||||
const struct sockaddr *addr, socklen_t addrlen);
|
||||
#if defined(CONFIG_NET_SOCKETS_OFFLOAD)
|
||||
int eswifi_socket_offload_init(struct eswifi_dev *leswifi);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -401,6 +401,10 @@ static void eswifi_iface_init(struct net_if *iface)
|
|||
eswifi_unlock(eswifi);
|
||||
|
||||
eswifi_offload_init(eswifi);
|
||||
#if defined(CONFIG_NET_SOCKETS_OFFLOAD)
|
||||
eswifi_socket_offload_init(eswifi);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static int eswifi_mgmt_scan(struct device *dev, scan_result_cb_t cb)
|
||||
|
|
|
@ -20,124 +20,6 @@ LOG_MODULE_REGISTER(wifi_eswifi_offload);
|
|||
|
||||
#include "eswifi.h"
|
||||
|
||||
static inline int __select_socket(struct eswifi_dev *eswifi, u8_t idx)
|
||||
{
|
||||
snprintf(eswifi->buf, sizeof(eswifi->buf), "P0=%d\r", idx);
|
||||
return eswifi_at_cmd(eswifi, eswifi->buf);
|
||||
}
|
||||
|
||||
static int __stop_socket(struct eswifi_dev *eswifi,
|
||||
struct eswifi_off_socket *socket)
|
||||
{
|
||||
char cmd_srv[] = "P5=0\r";
|
||||
char cmd_cli[] = "P6=0\r";
|
||||
|
||||
LOG_DBG("Stopping socket %d", socket->index);
|
||||
|
||||
if (socket->state != ESWIFI_SOCKET_STATE_CONNECTED) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
socket->state = ESWIFI_SOCKET_STATE_NONE;
|
||||
return eswifi_at_cmd(eswifi, socket->is_server ? cmd_srv : cmd_cli);
|
||||
}
|
||||
|
||||
static int __read_data(struct eswifi_dev *eswifi, size_t len, char **data)
|
||||
{
|
||||
char cmd[] = "R0\r";
|
||||
char size[] = "R1=9999\r";
|
||||
char timeout[] = "R2=30000\r";
|
||||
int ret;
|
||||
|
||||
/* Set max read size */
|
||||
snprintf(size, sizeof(size), "R1=%u\r", len);
|
||||
ret = eswifi_at_cmd(eswifi, size);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Unable to set read size");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Set timeout */
|
||||
snprintf(timeout, sizeof(timeout), "R2=%u\r", 30); /* 30 ms */
|
||||
ret = eswifi_at_cmd(eswifi, timeout);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Unable to set timeout");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return eswifi_at_cmd_rsp(eswifi, cmd, data);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct eswifi_dev *eswifi_socket_to_dev(struct eswifi_off_socket *socket)
|
||||
{
|
||||
return CONTAINER_OF(socket - socket->index, struct eswifi_dev, socket);
|
||||
}
|
||||
|
||||
static void eswifi_off_read_work(struct k_work *work)
|
||||
{
|
||||
struct eswifi_off_socket *socket;
|
||||
struct eswifi_dev *eswifi;
|
||||
struct net_pkt *pkt;
|
||||
int err, len;
|
||||
char *data;
|
||||
|
||||
LOG_DBG("");
|
||||
|
||||
socket = CONTAINER_OF(work, struct eswifi_off_socket, read_work);
|
||||
eswifi = eswifi_socket_to_dev(socket);
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
|
||||
if (socket->type == ESWIFI_TRANSPORT_TCP &&
|
||||
socket->state != ESWIFI_SOCKET_STATE_CONNECTED) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
__select_socket(eswifi, socket->index);
|
||||
|
||||
len = __read_data(eswifi, 1460, &data); /* 1460 is max size */
|
||||
if (len < 0) {
|
||||
__stop_socket(eswifi, socket);
|
||||
goto done;
|
||||
} else if (!len || !socket->recv_cb) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
LOG_DBG("payload sz = %d", len);
|
||||
|
||||
pkt = net_pkt_rx_alloc_with_buffer(eswifi->iface, len,
|
||||
AF_UNSPEC, 0, K_NO_WAIT);
|
||||
if (!pkt) {
|
||||
LOG_ERR("Cannot allocate rx packet");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!net_pkt_write(pkt, data, len)) {
|
||||
LOG_WRN("Incomplete buffer copy");
|
||||
}
|
||||
|
||||
eswifi_unlock(eswifi);
|
||||
|
||||
net_pkt_cursor_init(pkt);
|
||||
socket->recv_cb(socket->context, pkt,
|
||||
NULL, NULL, 0, socket->recv_data);
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
|
||||
k_sem_give(&socket->read_sem);
|
||||
k_yield();
|
||||
|
||||
done:
|
||||
err = k_delayed_work_submit_to_queue(&eswifi->work_q,
|
||||
&socket->read_work,
|
||||
500);
|
||||
if (err) {
|
||||
LOG_ERR("Rescheduling socket read error");
|
||||
}
|
||||
|
||||
eswifi_unlock(eswifi);
|
||||
}
|
||||
|
||||
static int eswifi_off_bind(struct net_context *context,
|
||||
const struct sockaddr *addr,
|
||||
|
@ -147,30 +29,12 @@ static int eswifi_off_bind(struct net_context *context,
|
|||
struct eswifi_dev *eswifi = eswifi_by_iface_idx(context->iface);
|
||||
int err;
|
||||
|
||||
if (addr->sa_family != AF_INET) {
|
||||
LOG_ERR("Only AF_INET is supported!");
|
||||
return -EPFNOSUPPORT;
|
||||
}
|
||||
|
||||
LOG_DBG("");
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
|
||||
__select_socket(eswifi, socket->index);
|
||||
socket->port = sys_be16_to_cpu(net_sin(addr)->sin_port);
|
||||
|
||||
/* Set Local Port */
|
||||
snprintf(eswifi->buf, sizeof(eswifi->buf), "P2=%d\r", socket->port);
|
||||
err = eswifi_at_cmd(eswifi, eswifi->buf);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to set local port");
|
||||
eswifi_unlock(eswifi);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
err = __eswifi_bind(eswifi, socket, addr, addrlen);
|
||||
eswifi_unlock(eswifi);
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int eswifi_off_listen(struct net_context *context, int backlog)
|
||||
|
@ -200,48 +64,6 @@ static int eswifi_off_listen(struct net_context *context, int backlog)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int __eswifi_off_start_client(struct eswifi_dev *eswifi,
|
||||
struct eswifi_off_socket *socket)
|
||||
{
|
||||
struct sockaddr *addr = &socket->peer_addr;
|
||||
struct in_addr *sin_addr = &net_sin(addr)->sin_addr;
|
||||
int err;
|
||||
|
||||
LOG_DBG("");
|
||||
|
||||
__select_socket(eswifi, socket->index);
|
||||
|
||||
/* Set Remote IP */
|
||||
snprintf(eswifi->buf, sizeof(eswifi->buf), "P3=%u.%u.%u.%u\r",
|
||||
sin_addr->s4_addr[0], sin_addr->s4_addr[1],
|
||||
sin_addr->s4_addr[2], sin_addr->s4_addr[3]);
|
||||
|
||||
err = eswifi_at_cmd(eswifi, eswifi->buf);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to set remote ip");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Set Remote Port */
|
||||
snprintf(eswifi->buf, sizeof(eswifi->buf), "P4=%d\r",
|
||||
(u16_t)sys_be16_to_cpu(net_sin(addr)->sin_port));
|
||||
err = eswifi_at_cmd(eswifi, eswifi->buf);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to set remote port");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Start TCP/UDP client */
|
||||
snprintf(eswifi->buf, sizeof(eswifi->buf), "P6=1\r");
|
||||
err = eswifi_at_cmd(eswifi, eswifi->buf);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to start TCP/UDP client");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void eswifi_off_connect_work(struct k_work *work)
|
||||
{
|
||||
struct eswifi_off_socket *socket;
|
||||
|
@ -333,28 +155,16 @@ static int eswifi_off_accept(struct net_context *context,
|
|||
{
|
||||
struct eswifi_off_socket *socket = context->offload_context;
|
||||
struct eswifi_dev *eswifi = eswifi_by_iface_idx(context->iface);
|
||||
char cmd[] = "P5=1\r";
|
||||
int ret;
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
|
||||
if (socket->state != ESWIFI_SOCKET_STATE_NONE) {
|
||||
/* we can only handle one connection at a time */
|
||||
ret = __eswifi_accept(eswifi, socket);
|
||||
if (ret < 0) {
|
||||
eswifi_unlock(eswifi);
|
||||
return -EBUSY;
|
||||
return ret;
|
||||
}
|
||||
|
||||
__select_socket(eswifi, socket->index);
|
||||
|
||||
/* Start TCP Server */
|
||||
if (eswifi_at_cmd(eswifi, cmd) < 0) {
|
||||
LOG_ERR("Unable to start TCP server");
|
||||
eswifi_unlock(eswifi);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
LOG_DBG("TCP Server started");
|
||||
|
||||
socket->state = ESWIFI_SOCKET_STATE_ACCEPTING;
|
||||
socket->accept_cb = cb;
|
||||
socket->accept_data = user_data;
|
||||
k_sem_reset(&socket->accept_sem);
|
||||
|
@ -575,31 +385,23 @@ static int eswifi_off_put(struct net_context *context)
|
|||
{
|
||||
struct eswifi_off_socket *socket = context->offload_context;
|
||||
struct eswifi_dev *eswifi = eswifi_by_iface_idx(context->iface);
|
||||
int ret;
|
||||
|
||||
LOG_DBG("");
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
|
||||
if (socket->type == ESWIFI_TRANSPORT_TCP &&
|
||||
socket->state != ESWIFI_SOCKET_STATE_CONNECTED) {
|
||||
eswifi_unlock(eswifi);
|
||||
return -ENOTCONN;
|
||||
ret = __eswifi_socket_free(eswifi, socket);
|
||||
if (ret) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
__select_socket(eswifi, socket->index);
|
||||
|
||||
k_delayed_work_cancel(&socket->read_work);
|
||||
|
||||
__select_socket(eswifi, socket->index);
|
||||
__stop_socket(eswifi, socket);
|
||||
|
||||
if (--socket->usage <= 0) {
|
||||
memset(socket, 0, sizeof(*socket));
|
||||
}
|
||||
|
||||
done:
|
||||
eswifi_unlock(eswifi);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int eswifi_off_get(sa_family_t family,
|
||||
|
@ -609,75 +411,33 @@ static int eswifi_off_get(sa_family_t family,
|
|||
{
|
||||
struct eswifi_dev *eswifi = eswifi_by_iface_idx((*context)->iface);
|
||||
struct eswifi_off_socket *socket = NULL;
|
||||
int err, i;
|
||||
int idx;
|
||||
|
||||
LOG_DBG("");
|
||||
|
||||
if (family != AF_INET) {
|
||||
LOG_ERR("Only AF_INET is supported!");
|
||||
return -EPFNOSUPPORT;
|
||||
}
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
|
||||
/* pickup available socket */
|
||||
for (i = 0; i < ESWIFI_OFFLOAD_MAX_SOCKETS; i++) {
|
||||
if (!eswifi->socket[i].context) {
|
||||
socket = &eswifi->socket[i];
|
||||
socket->index = i;
|
||||
socket->context = *context;
|
||||
(*context)->offload_context = socket;
|
||||
break;
|
||||
}
|
||||
idx = __eswifi_socket_new(eswifi, family, type, ip_proto, *context);
|
||||
if (idx < 0) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!socket) {
|
||||
LOG_ERR("No socket resource available");
|
||||
eswifi_unlock(eswifi);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
err = __select_socket(eswifi, socket->index);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to select socket %u", socket->index);
|
||||
eswifi_unlock(eswifi);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Set Transport Protocol */
|
||||
if (ip_proto == IPPROTO_TCP) {
|
||||
socket->type = ESWIFI_TRANSPORT_TCP;
|
||||
} else if (ip_proto == IPPROTO_UDP) {
|
||||
socket->type = ESWIFI_TRANSPORT_UDP;
|
||||
} else {
|
||||
LOG_ERR("Only TCP & UDP is supported");
|
||||
eswifi_unlock(eswifi);
|
||||
return -EPFNOSUPPORT;
|
||||
}
|
||||
|
||||
snprintf(eswifi->buf, sizeof(eswifi->buf), "P1=%d\r", socket->type);
|
||||
|
||||
err = eswifi_at_cmd(eswifi, eswifi->buf);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to set transport protocol");
|
||||
eswifi_unlock(eswifi);
|
||||
return -EIO;
|
||||
}
|
||||
socket = &eswifi->socket[idx];
|
||||
(*context)->offload_context = socket;
|
||||
|
||||
LOG_DBG("Socket index %d", socket->index);
|
||||
|
||||
k_work_init(&socket->connect_work, eswifi_off_connect_work);
|
||||
k_work_init(&socket->send_work, eswifi_off_send_work);
|
||||
k_delayed_work_init(&socket->read_work, eswifi_off_read_work);
|
||||
k_sem_init(&socket->read_sem, 1, 1);
|
||||
k_sem_init(&socket->accept_sem, 1, 1);
|
||||
socket->usage = 1;
|
||||
|
||||
k_delayed_work_submit_to_queue(&eswifi->work_q, &socket->read_work,
|
||||
500);
|
||||
eswifi_unlock(eswifi);
|
||||
|
||||
return 0;
|
||||
unlock:
|
||||
eswifi_unlock(eswifi);
|
||||
return idx;
|
||||
}
|
||||
|
||||
void eswifi_offload_async_msg(struct eswifi_dev *eswifi, char *msg, size_t len)
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#define ZEPHYR_DRIVERS_WIFI_ESWIFI_ESWIFI_OFFLOAD_H_
|
||||
|
||||
#include <net/net_offload.h>
|
||||
|
||||
#include "eswifi.h"
|
||||
|
||||
#define ESWIFI_OFFLOAD_MAX_SOCKETS 4
|
||||
|
@ -50,6 +49,7 @@ struct eswifi_off_socket {
|
|||
u16_t port;
|
||||
bool is_server;
|
||||
int usage;
|
||||
struct k_fifo fifo;
|
||||
struct net_pkt *prev_pkt_rem;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
292
drivers/wifi/eswifi/eswifi_socket.c
Normal file
292
drivers/wifi/eswifi/eswifi_socket.c
Normal file
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Linumiz
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(wifi_eswifi, CONFIG_WIFI_LOG_LEVEL);
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <kernel.h>
|
||||
#include <device.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "eswifi.h"
|
||||
#include <net/net_pkt.h>
|
||||
|
||||
static int __stop_socket(struct eswifi_dev *eswifi,
|
||||
struct eswifi_off_socket *socket)
|
||||
{
|
||||
char cmd_srv[] = "P5=0\r";
|
||||
char cmd_cli[] = "P6=0\r";
|
||||
|
||||
LOG_DBG("Stopping socket %d", socket->index);
|
||||
if (socket->state != ESWIFI_SOCKET_STATE_CONNECTED) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
socket->state = ESWIFI_SOCKET_STATE_NONE;
|
||||
return eswifi_at_cmd(eswifi, socket->is_server ? cmd_srv : cmd_cli);
|
||||
}
|
||||
|
||||
static int __read_data(struct eswifi_dev *eswifi, size_t len, char **data)
|
||||
{
|
||||
char cmd[] = "R0\r";
|
||||
char size[] = "R1=9999\r";
|
||||
char timeout[] = "R2=30000\r";
|
||||
int ret;
|
||||
|
||||
/* Set max read size */
|
||||
snprintf(size, sizeof(size), "R1=%u\r", len);
|
||||
ret = eswifi_at_cmd(eswifi, size);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Unable to set read size");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Set timeout */
|
||||
snprintf(timeout, sizeof(timeout), "R2=%u\r", 30); /* 30 ms */
|
||||
ret = eswifi_at_cmd(eswifi, timeout);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Unable to set timeout");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return eswifi_at_cmd_rsp(eswifi, cmd, data);
|
||||
}
|
||||
|
||||
int __eswifi_bind(struct eswifi_dev *eswifi, struct eswifi_off_socket *socket,
|
||||
const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (addr->sa_family != AF_INET) {
|
||||
LOG_ERR("Only AF_INET is supported!");
|
||||
return -EPFNOSUPPORT;
|
||||
}
|
||||
|
||||
__select_socket(eswifi, socket->index);
|
||||
socket->port = sys_be16_to_cpu(net_sin(addr)->sin_port);
|
||||
|
||||
/* Set Local Port */
|
||||
snprintf(eswifi->buf, sizeof(eswifi->buf), "P2=%d\r", socket->port);
|
||||
err = eswifi_at_cmd(eswifi, eswifi->buf);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to set local port");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void eswifi_off_read_work(struct k_work *work)
|
||||
{
|
||||
struct eswifi_off_socket *socket;
|
||||
struct eswifi_dev *eswifi;
|
||||
struct net_pkt *pkt;
|
||||
int err, len;
|
||||
char *data;
|
||||
|
||||
LOG_DBG("");
|
||||
|
||||
socket = CONTAINER_OF(work, struct eswifi_off_socket, read_work);
|
||||
eswifi = eswifi_socket_to_dev(socket);
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
|
||||
if ((socket->type == ESWIFI_TRANSPORT_TCP ||
|
||||
socket->type == ESWIFI_TRANSPORT_TCP_SSL) &&
|
||||
socket->state != ESWIFI_SOCKET_STATE_CONNECTED) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
__select_socket(eswifi, socket->index);
|
||||
|
||||
len = __read_data(eswifi, 1460, &data); /* 1460 is max size */
|
||||
if (len < 0) {
|
||||
__stop_socket(eswifi, socket);
|
||||
goto done;
|
||||
} else if (!len || !socket->recv_cb) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
LOG_DBG("payload sz = %d", len);
|
||||
|
||||
pkt = net_pkt_rx_alloc_with_buffer(eswifi->iface, len,
|
||||
AF_UNSPEC, 0, K_NO_WAIT);
|
||||
if (!pkt) {
|
||||
LOG_ERR("Cannot allocate rx packet");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!net_pkt_write(pkt, data, len)) {
|
||||
LOG_WRN("Incomplete buffer copy");
|
||||
}
|
||||
|
||||
eswifi_unlock(eswifi);
|
||||
|
||||
net_pkt_cursor_init(pkt);
|
||||
socket->recv_cb(socket->context, pkt,
|
||||
NULL, NULL, 0, socket->recv_data);
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
|
||||
k_sem_give(&socket->read_sem);
|
||||
k_yield();
|
||||
|
||||
done:
|
||||
err = k_delayed_work_submit_to_queue(&eswifi->work_q,
|
||||
&socket->read_work,
|
||||
500);
|
||||
if (err) {
|
||||
LOG_ERR("Rescheduling socket read error");
|
||||
}
|
||||
|
||||
eswifi_unlock(eswifi);
|
||||
}
|
||||
|
||||
int __eswifi_off_start_client(struct eswifi_dev *eswifi,
|
||||
struct eswifi_off_socket *socket)
|
||||
{
|
||||
struct sockaddr *addr = &socket->peer_addr;
|
||||
struct in_addr *sin_addr = &net_sin(addr)->sin_addr;
|
||||
int err;
|
||||
|
||||
LOG_DBG("");
|
||||
|
||||
__select_socket(eswifi, socket->index);
|
||||
|
||||
/* Set Remote IP */
|
||||
snprintf(eswifi->buf, sizeof(eswifi->buf), "P3=%u.%u.%u.%u\r",
|
||||
sin_addr->s4_addr[0], sin_addr->s4_addr[1],
|
||||
sin_addr->s4_addr[2], sin_addr->s4_addr[3]);
|
||||
|
||||
err = eswifi_at_cmd(eswifi, eswifi->buf);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to set remote ip");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Set Remote Port */
|
||||
snprintf(eswifi->buf, sizeof(eswifi->buf), "P4=%d\r",
|
||||
(u16_t)sys_be16_to_cpu(net_sin(addr)->sin_port));
|
||||
err = eswifi_at_cmd(eswifi, eswifi->buf);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to set remote port");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Start TCP/UDP client */
|
||||
snprintf(eswifi->buf, sizeof(eswifi->buf), "P6=1\r");
|
||||
err = eswifi_at_cmd(eswifi, eswifi->buf);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to start TCP/UDP client");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __eswifi_accept(struct eswifi_dev *eswifi, struct eswifi_off_socket *socket)
|
||||
{
|
||||
char cmd[] = "P5=1\r";
|
||||
|
||||
if (socket->state != ESWIFI_SOCKET_STATE_NONE) {
|
||||
/* we can only handle one connection at a time */
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
__select_socket(eswifi, socket->index);
|
||||
|
||||
/* Start TCP Server */
|
||||
if (eswifi_at_cmd(eswifi, cmd) < 0) {
|
||||
LOG_ERR("Unable to start TCP server");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
LOG_DBG("TCP Server started");
|
||||
socket->state = ESWIFI_SOCKET_STATE_ACCEPTING;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __eswifi_socket_free(struct eswifi_dev *eswifi,
|
||||
struct eswifi_off_socket *socket)
|
||||
{
|
||||
if ((socket->type == ESWIFI_TRANSPORT_TCP ||
|
||||
socket->type == ESWIFI_TRANSPORT_TCP_SSL) &&
|
||||
socket->state != ESWIFI_SOCKET_STATE_CONNECTED)
|
||||
return -ENOTCONN;
|
||||
|
||||
__select_socket(eswifi, socket->index);
|
||||
k_delayed_work_cancel(&socket->read_work);
|
||||
|
||||
__select_socket(eswifi, socket->index);
|
||||
__stop_socket(eswifi, socket);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __eswifi_socket_new(struct eswifi_dev *eswifi, int family, int type,
|
||||
int proto, void *context)
|
||||
{
|
||||
struct eswifi_off_socket *socket = NULL;
|
||||
int err, i;
|
||||
|
||||
LOG_DBG("");
|
||||
|
||||
if (family != AF_INET) {
|
||||
LOG_ERR("Only AF_INET is supported!");
|
||||
return -EPFNOSUPPORT;
|
||||
}
|
||||
|
||||
/* pickup available socket */
|
||||
for (i = 0; i < ESWIFI_OFFLOAD_MAX_SOCKETS; i++) {
|
||||
if (!eswifi->socket[i].context) {
|
||||
socket = &eswifi->socket[i];
|
||||
socket->index = i;
|
||||
socket->context = context;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!socket) {
|
||||
LOG_ERR("No socket resource available");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS) &&
|
||||
proto >= IPPROTO_TLS_1_0 && proto <= IPPROTO_TLS_1_2) {
|
||||
socket->type = ESWIFI_TRANSPORT_TCP_SSL;
|
||||
} else if (proto == IPPROTO_TCP) {
|
||||
socket->type = ESWIFI_TRANSPORT_TCP;
|
||||
} else if (proto == IPPROTO_UDP) {
|
||||
socket->type = ESWIFI_TRANSPORT_UDP;
|
||||
} else {
|
||||
LOG_ERR("Only TCP & UDP is supported");
|
||||
return -EPFNOSUPPORT;
|
||||
}
|
||||
|
||||
err = __select_socket(eswifi, socket->index);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to select socket %u", socket->index);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
snprintf(eswifi->buf, sizeof(eswifi->buf), "P1=%d\r", socket->type);
|
||||
err = eswifi_at_cmd(eswifi, eswifi->buf);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to set transport protocol");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
k_delayed_work_init(&socket->read_work, eswifi_off_read_work);
|
||||
socket->usage = 1;
|
||||
LOG_DBG("Socket index %d", socket->index);
|
||||
|
||||
return socket->index;
|
||||
}
|
413
drivers/wifi/eswifi/eswifi_socket_offload.c
Normal file
413
drivers/wifi/eswifi/eswifi_socket_offload.c
Normal file
|
@ -0,0 +1,413 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Linumiz
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(wifi_eswifi, CONFIG_WIFI_LOG_LEVEL);
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <kernel.h>
|
||||
#include <device.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <net/socket_offload.h>
|
||||
#include <net/tls_credentials.h>
|
||||
#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
|
||||
#include "tls_internal.h"
|
||||
#endif
|
||||
#include "eswifi.h"
|
||||
#include <net/net_pkt.h>
|
||||
|
||||
static struct eswifi_dev *eswifi;
|
||||
|
||||
static void __process_received(struct net_context *context,
|
||||
struct net_pkt *pkt,
|
||||
union net_ip_header *ip_hdr,
|
||||
union net_proto_header *proto_hdr,
|
||||
int status,
|
||||
void *user_data)
|
||||
{
|
||||
struct eswifi_off_socket *socket = user_data;
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
k_fifo_put(&socket->fifo, pkt);
|
||||
eswifi_unlock(eswifi);
|
||||
}
|
||||
|
||||
static int eswifi_socket_connect(int sock, const struct sockaddr *addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
struct eswifi_off_socket *socket;
|
||||
int ret;
|
||||
|
||||
if ((addrlen == 0) || (addr == NULL) ||
|
||||
(sock > ESWIFI_OFFLOAD_MAX_SOCKETS)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (addr->sa_family != AF_INET) {
|
||||
LOG_ERR("Only AF_INET is supported!");
|
||||
return -EPFNOSUPPORT;
|
||||
}
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
socket = &eswifi->socket[sock];
|
||||
|
||||
if (socket->state != ESWIFI_SOCKET_STATE_NONE) {
|
||||
eswifi_unlock(eswifi);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
socket->peer_addr = *addr;
|
||||
socket->state = ESWIFI_SOCKET_STATE_CONNECTING;
|
||||
|
||||
ret = __eswifi_off_start_client(eswifi, socket);
|
||||
if (!ret) {
|
||||
socket->state = ESWIFI_SOCKET_STATE_CONNECTED;
|
||||
} else {
|
||||
socket->state = ESWIFI_SOCKET_STATE_NONE;
|
||||
}
|
||||
|
||||
eswifi_unlock(eswifi);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int eswifi_socket_accept(int sock, struct sockaddr *addr,
|
||||
socklen_t *addrlen)
|
||||
{
|
||||
struct eswifi_off_socket *socket;
|
||||
int ret;
|
||||
|
||||
if ((addrlen == NULL) || (addr == NULL) ||
|
||||
(sock > ESWIFI_OFFLOAD_MAX_SOCKETS)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
socket = &eswifi->socket[sock];
|
||||
|
||||
ret = __eswifi_accept(eswifi, socket);
|
||||
eswifi_unlock(eswifi);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
|
||||
static int map_credentials(int sd, const void *optval, socklen_t optlen)
|
||||
{
|
||||
sec_tag_t *sec_tags = (sec_tag_t *)optval;
|
||||
int ret = 0;
|
||||
int tags_len;
|
||||
sec_tag_t tag;
|
||||
int id;
|
||||
int i, bytes;
|
||||
struct tls_credential *cert;
|
||||
|
||||
if ((optlen % sizeof(sec_tag_t)) != 0 || (optlen == 0)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tags_len = optlen / sizeof(sec_tag_t);
|
||||
/* For each tag, retrieve the credentials value and type: */
|
||||
for (i = 0; i < tags_len; i++) {
|
||||
tag = sec_tags[i];
|
||||
cert = credential_next_get(tag, NULL);
|
||||
while (cert != NULL) {
|
||||
/* Map Zephyr cert types to Simplelink cert options: */
|
||||
switch (cert->type) {
|
||||
case TLS_CREDENTIAL_CA_CERTIFICATE:
|
||||
id = 0;
|
||||
break;
|
||||
case TLS_CREDENTIAL_SERVER_CERTIFICATE:
|
||||
id = 1;
|
||||
break;
|
||||
case TLS_CREDENTIAL_PRIVATE_KEY:
|
||||
id = 2;
|
||||
break;
|
||||
case TLS_CREDENTIAL_NONE:
|
||||
case TLS_CREDENTIAL_PSK:
|
||||
case TLS_CREDENTIAL_PSK_ID:
|
||||
default:
|
||||
/* Not handled */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snprintf(eswifi->buf, sizeof(eswifi->buf),
|
||||
"PG=%d,%d,%d\r", 0, id, cert->len);
|
||||
bytes = strlen(eswifi->buf);
|
||||
memcpy(&eswifi->buf[bytes], cert->buf, cert->len);
|
||||
bytes += cert->len;
|
||||
LOG_DBG("cert write len %d\n", cert->len);
|
||||
ret = eswifi_request(eswifi, eswifi->buf, bytes + 1,
|
||||
eswifi->buf, sizeof(eswifi->buf));
|
||||
LOG_DBG("cert write err %d\n", ret);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
snprintf(eswifi->buf, sizeof(eswifi->buf), "PF=0,0\r");
|
||||
ret = eswifi_at_cmd(eswifi, eswifi->buf);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
cert = credential_next_get(tag, cert);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int map_credentials(int sd, const void *optval, socklen_t optlen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int eswifi_socket_setsockopt(int sd, int level, int optname,
|
||||
const void *optval, socklen_t optlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS) && level == SOL_TLS) {
|
||||
switch (optname) {
|
||||
case TLS_SEC_TAG_LIST:
|
||||
ret = map_credentials(sd, optval, optlen);
|
||||
break;
|
||||
case TLS_HOSTNAME:
|
||||
case TLS_PEER_VERIFY:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t eswifi_socket_send(int sock, const void *buf, size_t len,
|
||||
int flags)
|
||||
{
|
||||
struct eswifi_off_socket *socket;
|
||||
int ret;
|
||||
int offset;
|
||||
|
||||
if (!buf) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
socket = &eswifi->socket[sock];
|
||||
|
||||
if (socket->state != ESWIFI_SOCKET_STATE_CONNECTED) {
|
||||
eswifi_unlock(eswifi);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
__select_socket(eswifi, socket->index);
|
||||
|
||||
/* header */
|
||||
snprintf(eswifi->buf, sizeof(eswifi->buf), "S3=%u\r", len);
|
||||
offset = strlen(eswifi->buf);
|
||||
|
||||
/* copy payload */
|
||||
memcpy(&eswifi->buf[offset], buf, len);
|
||||
offset += len;
|
||||
|
||||
ret = eswifi_request(eswifi, eswifi->buf, offset + 1, eswifi->buf,
|
||||
sizeof(eswifi->buf));
|
||||
if (ret < 0) {
|
||||
LOG_DBG("Unable to send data");
|
||||
ret = -EIO;
|
||||
} else {
|
||||
ret = len;
|
||||
}
|
||||
|
||||
eswifi_unlock(eswifi);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t eswifi_socket_recv(int sock, void *buf, size_t max_len,
|
||||
int flags)
|
||||
{
|
||||
struct eswifi_off_socket *socket;
|
||||
int len = 0, ret = 0;
|
||||
struct net_pkt *pkt;
|
||||
|
||||
if ((max_len == 0) || (buf == NULL) ||
|
||||
(sock > ESWIFI_OFFLOAD_MAX_SOCKETS)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
socket = &eswifi->socket[sock];
|
||||
|
||||
if (socket->prev_pkt_rem) {
|
||||
pkt = socket->prev_pkt_rem;
|
||||
goto skip_wait;
|
||||
}
|
||||
|
||||
pkt = k_fifo_get(&socket->fifo, K_NO_WAIT);
|
||||
if (!pkt) {
|
||||
errno = EAGAIN;
|
||||
len = -EAGAIN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
skip_wait:
|
||||
len = net_pkt_remaining_data(pkt);
|
||||
if (len > max_len) {
|
||||
len = max_len;
|
||||
socket->prev_pkt_rem = pkt;
|
||||
} else {
|
||||
socket->prev_pkt_rem = NULL;
|
||||
}
|
||||
|
||||
ret = net_pkt_read(pkt, buf, len);
|
||||
|
||||
if (!socket->prev_pkt_rem) {
|
||||
net_pkt_unref(pkt);
|
||||
}
|
||||
|
||||
done:
|
||||
LOG_DBG("read %d %d %p", len, ret, pkt);
|
||||
eswifi_unlock(eswifi);
|
||||
if (ret) {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int eswifi_socket_close(int sock)
|
||||
{
|
||||
struct eswifi_off_socket *socket;
|
||||
struct net_pkt *pkt;
|
||||
int ret;
|
||||
|
||||
if (sock > ESWIFI_OFFLOAD_MAX_SOCKETS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
|
||||
socket = &eswifi->socket[sock];
|
||||
ret = __eswifi_socket_free(eswifi, socket);
|
||||
if (ret) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* consume all net pkt */
|
||||
while (1) {
|
||||
pkt = k_fifo_get(&socket->fifo, K_NO_WAIT);
|
||||
if (!pkt) {
|
||||
break;
|
||||
}
|
||||
net_pkt_unref(pkt);
|
||||
}
|
||||
|
||||
if (--socket->usage <= 0) {
|
||||
memset(socket, 0, sizeof(*socket));
|
||||
}
|
||||
|
||||
done:
|
||||
eswifi_unlock(eswifi);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int eswifi_socket_open(int family, int type, int proto)
|
||||
{
|
||||
struct eswifi_off_socket *socket = NULL;
|
||||
int idx;
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
|
||||
/* Assign dummy context SOCkEt(50CE) */
|
||||
idx = __eswifi_socket_new(eswifi, family, type, proto, 0x50CE);
|
||||
if (idx < 0) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
socket = &eswifi->socket[idx];
|
||||
k_fifo_init(&socket->fifo);
|
||||
k_sem_init(&socket->read_sem, 0, 200);
|
||||
socket->prev_pkt_rem = NULL;
|
||||
socket->recv_cb = __process_received;
|
||||
socket->recv_data = socket;
|
||||
|
||||
k_delayed_work_submit_to_queue(&eswifi->work_q, &socket->read_work,
|
||||
500);
|
||||
|
||||
unlock:
|
||||
eswifi_unlock(eswifi);
|
||||
return idx;
|
||||
}
|
||||
|
||||
static int eswifi_socket_poll(struct pollfd *fds, int nfds, int msecs)
|
||||
{
|
||||
struct eswifi_off_socket *socket;
|
||||
int sock, ret;
|
||||
|
||||
if (nfds > 1 ||
|
||||
fds[0].fd > ESWIFI_OFFLOAD_MAX_SOCKETS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
sock = fds[0].fd;
|
||||
socket = &eswifi->socket[sock];
|
||||
eswifi_unlock(eswifi);
|
||||
if (socket->state != ESWIFI_SOCKET_STATE_CONNECTED) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = k_sem_take(&socket->read_sem, msecs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ewifi_socket_bind(int sock, const struct sockaddr *addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
struct eswifi_off_socket *socket;
|
||||
int ret;
|
||||
|
||||
if ((addrlen == NULL) || (addr == NULL) ||
|
||||
(sock > ESWIFI_OFFLOAD_MAX_SOCKETS)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
eswifi_lock(eswifi);
|
||||
socket = &eswifi->socket[sock];
|
||||
ret = __eswifi_bind(eswifi, socket, addr, addrlen);
|
||||
eswifi_unlock(eswifi);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct socket_offload eswifi_socket_ops = {
|
||||
/* POSIX Socket Functions: */
|
||||
.socket = eswifi_socket_open,
|
||||
.close = eswifi_socket_close,
|
||||
.accept = eswifi_socket_accept,
|
||||
.bind = ewifi_socket_bind,
|
||||
.connect = eswifi_socket_connect,
|
||||
.setsockopt = eswifi_socket_setsockopt,
|
||||
.recv = eswifi_socket_recv,
|
||||
.send = eswifi_socket_send,
|
||||
.poll = eswifi_socket_poll,
|
||||
};
|
||||
|
||||
int eswifi_socket_offload_init(struct eswifi_dev *leswifi)
|
||||
{
|
||||
eswifi = leswifi;
|
||||
socket_offload_register(&eswifi_socket_ops);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue