From 008c46f019d12bd411b3229b639f16284f0d586c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= Date: Mon, 7 Oct 2024 17:40:31 +0200 Subject: [PATCH 1/7] drivers: wifi: siwx917: Fix support for WPA3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WPA3 relies on 802.11w that was not enabled. Signed-off-by: Jérôme Pouiller --- soc/silabs/silabs_siwx917/siwg917/nwp_init.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/soc/silabs/silabs_siwx917/siwg917/nwp_init.c b/soc/silabs/silabs_siwx917/siwg917/nwp_init.c index ee12532..d598fe5 100644 --- a/soc/silabs/silabs_siwx917/siwg917/nwp_init.c +++ b/soc/silabs/silabs_siwx917/siwg917/nwp_init.c @@ -43,7 +43,9 @@ static int silabs_siwx917_nwp_init(void) .config_feature_bit_map = SL_SI91X_ENABLE_ENHANCED_MAX_PSP, .custom_feature_bit_map = SL_SI91X_CUSTOM_FEAT_EXTENSION_VALID, .ext_custom_feature_bit_map = - MEMORY_CONFIG | SL_SI91X_EXT_FEAT_XTAL_CLK | + MEMORY_CONFIG | + SL_SI91X_EXT_FEAT_XTAL_CLK | + SL_SI91X_EXT_FEAT_IEEE_80211W | SL_SI91X_EXT_FEAT_FRONT_END_SWITCH_PINS_ULP_GPIO_4_5_0, }}; sl_si91x_boot_configuration_t *cfg = &network_config.boot_config; From 1512ffe58a3e6d88513d37ce572f438f8f8b2793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= Date: Tue, 8 Oct 2024 10:48:32 +0200 Subject: [PATCH 2/7] drivers: wifi: siwx917: Fix mac address configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Zephyr only saves a pointer to the memory area provided to net_if_set_link_addr(). So the MAC address has to be stored in a static area (while it was stored in the stack). Signed-off-by: Jérôme Pouiller --- drivers/wifi/siwx917/siwx917_wifi.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/wifi/siwx917/siwx917_wifi.c b/drivers/wifi/siwx917/siwx917_wifi.c index cddd3ca..d790ba1 100644 --- a/drivers/wifi/siwx917/siwx917_wifi.c +++ b/drivers/wifi/siwx917/siwx917_wifi.c @@ -26,6 +26,7 @@ LOG_MODULE_REGISTER(siwx917_wifi); struct siwx917_dev { struct net_if *iface; + sl_mac_address_t macaddr; enum wifi_iface_state state; scan_result_cb_t scan_res_cb; @@ -621,7 +622,6 @@ static struct net_offload siwx917_offload = { static void siwx917_iface_init(struct net_if *iface) { struct siwx917_dev *sidev = iface->if_dev->dev->data; - sl_mac_address_t mac_addr; iface->if_dev->offload = &siwx917_offload; sidev->state = WIFI_STATE_INTERFACE_DISABLED; @@ -630,8 +630,15 @@ static void siwx917_iface_init(struct net_if *iface) sl_wifi_set_scan_callback(siwx917_on_scan, sidev); sl_wifi_set_join_callback(siwx917_on_join, sidev); - sl_wifi_get_mac_address(SL_WIFI_CLIENT_INTERFACE, &mac_addr); - net_if_set_link_addr(iface, mac_addr.octet, sizeof(mac_addr.octet), NET_LINK_ETHERNET); + + status = sl_wifi_get_mac_address(SL_WIFI_CLIENT_INTERFACE, &sidev->macaddr); + if (status) { + LOG_ERR("sl_wifi_get_mac_address(): %#04x", status); + return; + } + net_if_set_link_addr(iface, sidev->macaddr.octet, sizeof(sidev->macaddr.octet), + NET_LINK_ETHERNET); + sidev->state = WIFI_STATE_INACTIVE; } From 041110f2bd0ec0d4c69b4163f30c389f91285496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= Date: Wed, 25 Sep 2024 21:48:29 +0200 Subject: [PATCH 3/7] drivers: wifi: siwx917: Split out NET_OFFLOAD code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit siwx917_wifi.c is currently pretty large while a big part is in fact only used to manage socket API. Split out the socket management and only keep 802.11 management in siwx917_wifi.c. This commit do not introduce any change in the code. The code is only relocated. Signed-off-by: Jérôme Pouiller --- drivers/wifi/siwx917/CMakeLists.txt | 2 +- drivers/wifi/siwx917/siwx917_wifi.c | 418 +-------------------- drivers/wifi/siwx917/siwx917_wifi.h | 32 ++ drivers/wifi/siwx917/siwx917_wifi_socket.c | 413 ++++++++++++++++++++ drivers/wifi/siwx917/siwx917_wifi_socket.h | 19 + 5 files changed, 472 insertions(+), 412 deletions(-) create mode 100644 drivers/wifi/siwx917/siwx917_wifi.h create mode 100644 drivers/wifi/siwx917/siwx917_wifi_socket.c create mode 100644 drivers/wifi/siwx917/siwx917_wifi_socket.h diff --git a/drivers/wifi/siwx917/CMakeLists.txt b/drivers/wifi/siwx917/CMakeLists.txt index 3983097..fc8891a 100644 --- a/drivers/wifi/siwx917/CMakeLists.txt +++ b/drivers/wifi/siwx917/CMakeLists.txt @@ -1,4 +1,4 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2024 Silicon Laboratories Inc. -zephyr_library_sources_ifdef(CONFIG_WIFI_SIWX917 siwx917_wifi.c) +zephyr_library_sources_ifdef(CONFIG_WIFI_SIWX917 siwx917_wifi.c siwx917_wifi_socket.c) diff --git a/drivers/wifi/siwx917/siwx917_wifi.c b/drivers/wifi/siwx917/siwx917_wifi.c index d790ba1..bfb68b6 100644 --- a/drivers/wifi/siwx917/siwx917_wifi.c +++ b/drivers/wifi/siwx917/siwx917_wifi.c @@ -5,120 +5,19 @@ */ #define DT_DRV_COMPAT silabs_siwx917_wifi -#include -#include -#include #include -#include -#include -#include "sl_si91x_socket.h" -#include "sl_si91x_socket_utility.h" +#include "siwx917_wifi.h" +#include "siwx917_wifi_socket.h" + +#include "sl_net_constants.h" +#include "sl_wifi_types.h" #include "sl_wifi_callback_framework.h" #include "sl_wifi.h" -#include "sl_net_si91x.h" #include "sl_net.h" -BUILD_ASSERT(NUMBER_OF_BSD_SOCKETS < sizeof(uint32_t) * 8); -BUILD_ASSERT(NUMBER_OF_BSD_SOCKETS < SIZEOF_FIELD(sl_si91x_fd_set, __fds_bits) * 8); - LOG_MODULE_REGISTER(siwx917_wifi); -struct siwx917_dev { - struct net_if *iface; - sl_mac_address_t macaddr; - enum wifi_iface_state state; - scan_result_cb_t scan_res_cb; - - struct k_event fds_recv_event; - sl_si91x_fd_set fds_watch; - struct { - net_context_recv_cb_t cb; - void *user_data; - struct net_context *context; - } fds_cb[NUMBER_OF_BSD_SOCKETS]; -}; - -NET_BUF_POOL_FIXED_DEFINE(siwx917_tx_pool, 1, NET_ETH_MTU, 0, NULL); -NET_BUF_POOL_FIXED_DEFINE(siwx917_rx_pool, 10, NET_ETH_MTU, 0, NULL); - -/* SiWx917 does not use the standard struct sockaddr (despite it uses the same - * name): - * - uses Little Endian for port number while Posix uses big endian - * - IPv6 addresses are bytes swapped - * Note: this function allows to have in == out. - */ -static void siwx917_sockaddr_swap_bytes(struct sockaddr *out, - const struct sockaddr *in, socklen_t in_len) -{ - const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *)in; - struct sockaddr_in6 *out6 = (struct sockaddr_in6 *)out; - int i; - - /* In Zephyr, size of sockaddr == size of sockaddr_storage - * (while in Posix sockaddr is smaller than sockaddr_storage). - */ - memcpy(out, in, in_len); - if (in->sa_family == AF_INET6) { - for (i = 0; i < ARRAY_SIZE(in6->sin6_addr.s6_addr32); i++) { - out6->sin6_addr.s6_addr32[i] = ntohl(in6->sin6_addr.s6_addr32[i]); - } - out6->sin6_port = ntohs(in6->sin6_port); - } else if (in->sa_family == AF_INET) { - out6->sin6_port = ntohs(in6->sin6_port); - } -} - -static void siwx917_on_join_ipv4(struct siwx917_dev *sidev) -{ -#ifdef CONFIG_NET_IPV4 - sl_net_ip_configuration_t ip_config4 = { - .mode = SL_IP_MANAGEMENT_DHCP, - .type = SL_IPV4, - }; - struct in_addr addr4 = { }; - int ret; - - /* FIXME: support for static IP configuration */ - ret = sl_si91x_configure_ip_address(&ip_config4, SL_SI91X_WIFI_CLIENT_VAP_ID); - if (!ret) { - memcpy(addr4.s4_addr, ip_config4.ip.v4.ip_address.bytes, sizeof(addr4.s4_addr)); - /* FIXME: also report gateway (net_if_ipv4_router_add()) */ - net_if_ipv4_addr_add(sidev->iface, &addr4, NET_ADDR_DHCP, 0); - } else { - LOG_ERR("sl_si91x_configure_ip_address(): %#04x", ret); - } -#endif -} - -static void siwx917_on_join_ipv6(struct siwx917_dev *sidev) -{ -#ifdef CONFIG_NET_IPV6 - sl_net_ip_configuration_t ip_config6 = { - .mode = SL_IP_MANAGEMENT_DHCP, - .type = SL_IPV6, - }; - struct in6_addr addr6 = { }; - int ret, i; - - /* FIXME: support for static IP configuration */ - ret = sl_si91x_configure_ip_address(&ip_config6, SL_SI91X_WIFI_CLIENT_VAP_ID); - if (!ret) { - for (i = 0; i < ARRAY_SIZE(addr6.s6_addr32); i++) { - addr6.s6_addr32[i] = ntohl(ip_config6.ip.v6.global_address.value[i]); - } - /* SiWx917 already take care of DAD and sending ND is not - * supported anyway. - */ - net_if_flag_set(sidev->iface, NET_IF_IPV6_NO_ND); - /* FIXME: also report gateway and link local address */ - net_if_ipv6_addr_add(sidev->iface, &addr6, NET_ADDR_AUTOCONF, 0); - } else { - LOG_ERR("sl_si91x_configure_ip_address(): %#04x", ret); - } -#endif -} - static unsigned int siwx917_on_join(sl_wifi_event_t event, char *result, uint32_t result_size, void *arg) { @@ -321,313 +220,15 @@ static int siwx917_status(const struct device *dev, struct wifi_iface_status *st return 0; } -static int siwx917_sock_recv_sync(struct net_context *context, - net_context_recv_cb_t cb, void *user_data) -{ - struct net_if *iface = net_context_get_iface(context); - int sockfd = (int)context->offload_context; - struct net_pkt *pkt; - struct net_buf *buf; - int ret; - - pkt = net_pkt_rx_alloc_on_iface(iface, K_MSEC(100)); - if (!pkt) { - return -ENOBUFS; - } - buf = net_buf_alloc(&siwx917_rx_pool, K_MSEC(100)); - if (!buf) { - net_pkt_unref(pkt); - return -ENOBUFS; - } - net_pkt_append_buffer(pkt, buf); - - ret = sl_si91x_recvfrom(sockfd, buf->data, NET_ETH_MTU, 0, NULL, NULL); - if (ret < 0) { - net_pkt_unref(pkt); - ret = -errno; - } else { - net_buf_add(buf, ret); - net_pkt_cursor_init(pkt); - ret = 0; - } - if (cb) { - cb(context, pkt, NULL, NULL, ret, user_data); - } - return ret; -} - -static void siwx917_sock_on_recv(sl_si91x_fd_set *read_fd, sl_si91x_fd_set *write_fd, - sl_si91x_fd_set *except_fd, int status) -{ - /* When CONFIG_NET_SOCKETS_OFFLOAD is set, only one interface exist */ - struct siwx917_dev *sidev = net_if_get_default()->if_dev->dev->data; - - ARRAY_FOR_EACH(sidev->fds_cb, i) { - if (SL_SI91X_FD_ISSET(i, read_fd)) { - if (sidev->fds_cb[i].cb) { - siwx917_sock_recv_sync(sidev->fds_cb[i].context, - sidev->fds_cb[i].cb, - sidev->fds_cb[i].user_data); - } else { - SL_SI91X_FD_CLR(i, &sidev->fds_watch); - k_event_post(&sidev->fds_recv_event, 1U << i); - } - } - } - - sl_si91x_select(NUMBER_OF_BSD_SOCKETS, &sidev->fds_watch, NULL, NULL, NULL, - siwx917_sock_on_recv); -} - -static int siwx917_sock_get(sa_family_t family, enum net_sock_type type, - enum net_ip_protocol ip_proto, struct net_context **context) -{ - struct siwx917_dev *sidev = net_if_get_default()->if_dev->dev->data; - int sockfd; - - sockfd = sl_si91x_socket(family, type, ip_proto); - if (sockfd < 0) { - return -errno; - } - assert(!sidev->fds_cb[sockfd].cb); - (*context)->offload_context = (void *)sockfd; - return sockfd; -} - -static int siwx917_sock_put(struct net_context *context) -{ - struct siwx917_dev *sidev = net_context_get_iface(context)->if_dev->dev->data; - int sockfd = (int)context->offload_context; - int ret; - - SL_SI91X_FD_CLR(sockfd, &sidev->fds_watch); - memset(&sidev->fds_cb[sockfd], 0, sizeof(sidev->fds_cb[sockfd])); - sl_si91x_select(NUMBER_OF_BSD_SOCKETS, &sidev->fds_watch, NULL, NULL, NULL, - siwx917_sock_on_recv); - ret = sl_si91x_shutdown(sockfd, 0); - if (ret < 0) { - ret = -errno; - } - return ret; -} - -static int siwx917_sock_bind(struct net_context *context, - const struct sockaddr *addr, socklen_t addrlen) -{ - struct siwx917_dev *sidev = net_context_get_iface(context)->if_dev->dev->data; - int sockfd = (int)context->offload_context; - struct sockaddr addr_le; - int ret; - - /* Zephyr tends to call bind() even if the TCP socket is a client. 917 - * return an error in this case. - */ - if (net_context_get_proto(context) == IPPROTO_TCP && - !((struct sockaddr_in *)addr)->sin_port) { - return 0; - } - siwx917_sockaddr_swap_bytes(&addr_le, addr, addrlen); - ret = sl_si91x_bind(sockfd, &addr_le, addrlen); - if (ret) { - return -errno; - } - /* WiseConnect refuses to run select on TCP listening sockets */ - if (net_context_get_proto(context) == IPPROTO_UDP) { - SL_SI91X_FD_SET(sockfd, &sidev->fds_watch); - sl_si91x_select(NUMBER_OF_BSD_SOCKETS, &sidev->fds_watch, NULL, NULL, NULL, - siwx917_sock_on_recv); - } - return 0; -} - -static int siwx917_sock_connect(struct net_context *context, - const struct sockaddr *addr, socklen_t addrlen, - net_context_connect_cb_t cb, int32_t timeout, void *user_data) -{ - struct siwx917_dev *sidev = net_context_get_iface(context)->if_dev->dev->data; - int sockfd = (int)context->offload_context; - struct sockaddr addr_le; - int ret; - - printk("foo\n"); - /* sl_si91x_connect() always return immediately, so we ignore timeout */ - siwx917_sockaddr_swap_bytes(&addr_le, addr, addrlen); - ret = sl_si91x_connect(sockfd, &addr_le, addrlen); - if (ret) { - ret = -errno; - } - SL_SI91X_FD_SET(sockfd, &sidev->fds_watch); - sl_si91x_select(NUMBER_OF_BSD_SOCKETS, &sidev->fds_watch, NULL, NULL, NULL, - siwx917_sock_on_recv); - net_context_set_state(context, NET_CONTEXT_CONNECTED); - if (cb) { - cb(context, ret, user_data); - } - return ret; -} - -static int siwx917_sock_listen(struct net_context *context, int backlog) -{ - int sockfd = (int)context->offload_context; - int ret; - - ret = sl_si91x_listen(sockfd, backlog); - if (ret) { - return -errno; - } - net_context_set_state(context, NET_CONTEXT_LISTENING); - return 0; -} - -static int siwx917_sock_accept(struct net_context *context, - net_tcp_accept_cb_t cb, int32_t timeout, void *user_data) -{ - struct siwx917_dev *sidev = net_context_get_iface(context)->if_dev->dev->data; - int sockfd = (int)context->offload_context; - struct net_context *newcontext; - struct sockaddr addr_le; - int ret; - - /* TODO: support timeout != K_FOREVER */ - assert(timeout < 0); - - ret = net_context_get(net_context_get_family(context), - net_context_get_type(context), - net_context_get_proto(context), &newcontext); - if (ret < 0) { - return ret; - } - /* net_context_get() calls siwx917_sock_get() but sl_si91x_accept() also - * allocates a socket. - */ - ret = siwx917_sock_put(newcontext); - if (ret < 0) { - return ret; - } - /* The iface is reset when getting a new context. */ - newcontext->iface = context->iface; - ret = sl_si91x_accept(sockfd, &addr_le, sizeof(addr_le)); - if (ret < 0) { - return -errno; - } - newcontext->flags |= NET_CONTEXT_REMOTE_ADDR_SET; - newcontext->offload_context = (void *)ret; - siwx917_sockaddr_swap_bytes(&newcontext->remote, &addr_le, sizeof(addr_le)); - - SL_SI91X_FD_SET(ret, &sidev->fds_watch); - sl_si91x_select(NUMBER_OF_BSD_SOCKETS, &sidev->fds_watch, NULL, NULL, NULL, - siwx917_sock_on_recv); - if (cb) { - cb(newcontext, &addr_le, sizeof(addr_le), 0, user_data); - } - - return 0; -} - -static int siwx917_sock_sendto(struct net_pkt *pkt, - const struct sockaddr *addr, socklen_t addrlen, - net_context_send_cb_t cb, int32_t timeout, void *user_data) -{ - struct net_context *context = pkt->context; - int sockfd = (int)context->offload_context; - struct sockaddr addr_le; - struct net_buf *buf; - int ret; - - /* struct net_pkt use fragmented buffers while SiWx917 API need a - * continuous buffer. - */ - if (net_pkt_get_len(pkt) > NET_ETH_MTU) { - LOG_ERR("unexpected buffer size"); - ret = -ENOBUFS; - goto out_cb; - } - buf = net_buf_alloc(&siwx917_tx_pool, K_FOREVER); - if (!buf) { - ret = -ENOBUFS; - goto out_cb; - } - if (net_pkt_read(pkt, buf->data, net_pkt_get_len(pkt))) { - ret = -ENOBUFS; - goto out_release_buf; - } - net_buf_add(buf, net_pkt_get_len(pkt)); - - /* sl_si91x_sendto() always return immediately, so we ignore timeout */ - siwx917_sockaddr_swap_bytes(&addr_le, addr, addrlen); - ret = sl_si91x_sendto(sockfd, buf->data, net_pkt_get_len(pkt), 0, &addr_le, addrlen); - if (ret < 0) { - ret = -errno; - goto out_release_buf; - } - net_pkt_unref(pkt); - -out_release_buf: - net_buf_unref(buf); - -out_cb: - if (cb) { - cb(pkt->context, ret, user_data); - } - return ret; -} - -static int siwx917_sock_send(struct net_pkt *pkt, - net_context_send_cb_t cb, int32_t timeout, void *user_data) -{ - return siwx917_sock_sendto(pkt, NULL, 0, cb, timeout, user_data); -} - -static int siwx917_sock_recv(struct net_context *context, - net_context_recv_cb_t cb, int32_t timeout, void *user_data) -{ - struct net_if *iface = net_context_get_iface(context); - struct siwx917_dev *sidev = iface->if_dev->dev->data; - int sockfd = (int)context->offload_context; - int ret; - - ret = k_event_wait(&sidev->fds_recv_event, 1U << sockfd, false, - timeout < 0 ? K_FOREVER : K_MSEC(timeout)); - if (timeout == 0) { - sidev->fds_cb[sockfd].context = context; - sidev->fds_cb[sockfd].cb = cb; - sidev->fds_cb[sockfd].user_data = user_data; - } else { - memset(&sidev->fds_cb[sockfd], 0, sizeof(sidev->fds_cb[sockfd])); - } - - if (ret) { - k_event_clear(&sidev->fds_recv_event, 1U << sockfd); - ret = siwx917_sock_recv_sync(context, cb, user_data); - SL_SI91X_FD_SET(sockfd, &sidev->fds_watch); - } - - sl_si91x_select(NUMBER_OF_BSD_SOCKETS, &sidev->fds_watch, NULL, NULL, NULL, - siwx917_sock_on_recv); - return ret; -} - -static struct net_offload siwx917_offload = { - .get = siwx917_sock_get, - .put = siwx917_sock_put, - .bind = siwx917_sock_bind, - .listen = siwx917_sock_listen, - .connect = siwx917_sock_connect, - .accept = siwx917_sock_accept, - .sendto = siwx917_sock_sendto, - .send = siwx917_sock_send, - .recv = siwx917_sock_recv, -}; - static void siwx917_iface_init(struct net_if *iface) { struct siwx917_dev *sidev = iface->if_dev->dev->data; + sl_status_t status; - iface->if_dev->offload = &siwx917_offload; sidev->state = WIFI_STATE_INTERFACE_DISABLED; sidev->iface = iface; - k_event_init(&sidev->fds_recv_event); + siwx917_sock_init(iface); sl_wifi_set_scan_callback(siwx917_on_scan, sidev); sl_wifi_set_join_callback(siwx917_on_join, sidev); @@ -647,11 +248,6 @@ static int siwx917_dev_init(const struct device *dev) return 0; } -static enum offloaded_net_if_types siwx917_get_type(void) -{ - return L2_OFFLOADED_NET_IF_TYPE_WIFI; -} - static const struct wifi_mgmt_ops siwx917_mgmt = { .scan = siwx917_scan, .connect = siwx917_connect, diff --git a/drivers/wifi/siwx917/siwx917_wifi.h b/drivers/wifi/siwx917/siwx917_wifi.h new file mode 100644 index 0000000..e6d530e --- /dev/null +++ b/drivers/wifi/siwx917/siwx917_wifi.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024 Silicon Laboratories Inc. + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef SIWX917_WIFI_H +#define SIWX917_WIFI_H + +#include +#include +#include +#include + +#include "sl_ieee802_types.h" +#include "sl_si91x_socket_types.h" +#include "sl_si91x_protocol_types.h" + +struct siwx917_dev { + struct net_if *iface; + sl_mac_address_t macaddr; + enum wifi_iface_state state; + scan_result_cb_t scan_res_cb; + + struct k_event fds_recv_event; + sl_si91x_fd_set fds_watch; + struct { + net_context_recv_cb_t cb; + void *user_data; + struct net_context *context; + } fds_cb[NUMBER_OF_BSD_SOCKETS]; +}; + +#endif diff --git a/drivers/wifi/siwx917/siwx917_wifi_socket.c b/drivers/wifi/siwx917/siwx917_wifi_socket.c new file mode 100644 index 0000000..44990a1 --- /dev/null +++ b/drivers/wifi/siwx917/siwx917_wifi_socket.c @@ -0,0 +1,413 @@ +/* + * Copyright (c) 2023 Antmicro + * Copyright (c) 2024 Silicon Laboratories Inc. + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +#include "siwx917_wifi.h" +#include "siwx917_wifi_socket.h" + +#include "sl_status.h" +#include "sl_net_ip_types.h" +#include "sl_net_si91x.h" +#include "sl_si91x_types.h" +#include "sl_si91x_socket.h" +#include "sl_si91x_socket_utility.h" + +LOG_MODULE_DECLARE(siwx917_wifi); + +BUILD_ASSERT(NUMBER_OF_BSD_SOCKETS < sizeof(uint32_t) * 8); +BUILD_ASSERT(NUMBER_OF_BSD_SOCKETS < SIZEOF_FIELD(sl_si91x_fd_set, __fds_bits) * 8); + +NET_BUF_POOL_FIXED_DEFINE(siwx917_tx_pool, 1, NET_ETH_MTU, 0, NULL); +NET_BUF_POOL_FIXED_DEFINE(siwx917_rx_pool, 10, NET_ETH_MTU, 0, NULL); + +enum offloaded_net_if_types siwx917_get_type(void) +{ + return L2_OFFLOADED_NET_IF_TYPE_WIFI; +} + +/* SiWx917 does not use the standard struct sockaddr (despite it uses the same + * name): + * - uses Little Endian for port number while Posix uses big endian + * - IPv6 addresses are bytes swapped + * Note: this function allows to have in == out. + */ +static void siwx917_sockaddr_swap_bytes(struct sockaddr *out, + const struct sockaddr *in, socklen_t in_len) +{ + const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *)in; + struct sockaddr_in6 *out6 = (struct sockaddr_in6 *)out; + int i; + + /* In Zephyr, size of sockaddr == size of sockaddr_storage + * (while in Posix sockaddr is smaller than sockaddr_storage). + */ + memcpy(out, in, in_len); + if (in->sa_family == AF_INET6) { + for (i = 0; i < ARRAY_SIZE(in6->sin6_addr.s6_addr32); i++) { + out6->sin6_addr.s6_addr32[i] = ntohl(in6->sin6_addr.s6_addr32[i]); + } + out6->sin6_port = ntohs(in6->sin6_port); + } else if (in->sa_family == AF_INET) { + out6->sin6_port = ntohs(in6->sin6_port); + } +} + +void siwx917_on_join_ipv4(struct siwx917_dev *sidev) +{ +#ifdef CONFIG_NET_IPV4 + sl_net_ip_configuration_t ip_config4 = { + .mode = SL_IP_MANAGEMENT_DHCP, + .type = SL_IPV4, + }; + struct in_addr addr4 = { }; + int ret; + + /* FIXME: support for static IP configuration */ + ret = sl_si91x_configure_ip_address(&ip_config4, SL_SI91X_WIFI_CLIENT_VAP_ID); + if (!ret) { + memcpy(addr4.s4_addr, ip_config4.ip.v4.ip_address.bytes, sizeof(addr4.s4_addr)); + /* FIXME: also report gateway (net_if_ipv4_router_add()) */ + net_if_ipv4_addr_add(sidev->iface, &addr4, NET_ADDR_DHCP, 0); + } else { + LOG_ERR("sl_si91x_configure_ip_address(): %#04x", ret); + } +#endif +} + +void siwx917_on_join_ipv6(struct siwx917_dev *sidev) +{ +#ifdef CONFIG_NET_IPV6 + sl_net_ip_configuration_t ip_config6 = { + .mode = SL_IP_MANAGEMENT_DHCP, + .type = SL_IPV6, + }; + struct in6_addr addr6 = { }; + int ret, i; + + /* FIXME: support for static IP configuration */ + ret = sl_si91x_configure_ip_address(&ip_config6, SL_SI91X_WIFI_CLIENT_VAP_ID); + if (!ret) { + for (i = 0; i < ARRAY_SIZE(addr6.s6_addr32); i++) { + addr6.s6_addr32[i] = ntohl(ip_config6.ip.v6.global_address.value[i]); + } + /* SiWx917 already take care of DAD and sending ND is not + * supported anyway. + */ + net_if_flag_set(sidev->iface, NET_IF_IPV6_NO_ND); + /* FIXME: also report gateway and link local address */ + net_if_ipv6_addr_add(sidev->iface, &addr6, NET_ADDR_AUTOCONF, 0); + } else { + LOG_ERR("sl_si91x_configure_ip_address(): %#04x", ret); + } +#endif +} + +static int siwx917_sock_recv_sync(struct net_context *context, + net_context_recv_cb_t cb, void *user_data) +{ + struct net_if *iface = net_context_get_iface(context); + int sockfd = (int)context->offload_context; + struct net_pkt *pkt; + struct net_buf *buf; + int ret; + + pkt = net_pkt_rx_alloc_on_iface(iface, K_MSEC(100)); + if (!pkt) { + return -ENOBUFS; + } + buf = net_buf_alloc(&siwx917_rx_pool, K_MSEC(100)); + if (!buf) { + net_pkt_unref(pkt); + return -ENOBUFS; + } + net_pkt_append_buffer(pkt, buf); + + ret = sl_si91x_recvfrom(sockfd, buf->data, NET_ETH_MTU, 0, NULL, NULL); + if (ret < 0) { + net_pkt_unref(pkt); + ret = -errno; + } else { + net_buf_add(buf, ret); + net_pkt_cursor_init(pkt); + ret = 0; + } + if (cb) { + cb(context, pkt, NULL, NULL, ret, user_data); + } + return ret; +} + +static void siwx917_sock_on_recv(sl_si91x_fd_set *read_fd, sl_si91x_fd_set *write_fd, + sl_si91x_fd_set *except_fd, int status) +{ + /* When CONFIG_NET_SOCKETS_OFFLOAD is set, only one interface exist */ + struct siwx917_dev *sidev = net_if_get_default()->if_dev->dev->data; + + ARRAY_FOR_EACH(sidev->fds_cb, i) { + if (SL_SI91X_FD_ISSET(i, read_fd)) { + if (sidev->fds_cb[i].cb) { + siwx917_sock_recv_sync(sidev->fds_cb[i].context, + sidev->fds_cb[i].cb, + sidev->fds_cb[i].user_data); + } else { + SL_SI91X_FD_CLR(i, &sidev->fds_watch); + k_event_post(&sidev->fds_recv_event, 1U << i); + } + } + } + + sl_si91x_select(NUMBER_OF_BSD_SOCKETS, &sidev->fds_watch, NULL, NULL, NULL, + siwx917_sock_on_recv); +} + +static int siwx917_sock_get(sa_family_t family, enum net_sock_type type, + enum net_ip_protocol ip_proto, struct net_context **context) +{ + struct siwx917_dev *sidev = net_if_get_default()->if_dev->dev->data; + int sockfd; + + sockfd = sl_si91x_socket(family, type, ip_proto); + if (sockfd < 0) { + return -errno; + } + assert(!sidev->fds_cb[sockfd].cb); + (*context)->offload_context = (void *)sockfd; + return sockfd; +} + +static int siwx917_sock_put(struct net_context *context) +{ + struct siwx917_dev *sidev = net_context_get_iface(context)->if_dev->dev->data; + int sockfd = (int)context->offload_context; + int ret; + + SL_SI91X_FD_CLR(sockfd, &sidev->fds_watch); + memset(&sidev->fds_cb[sockfd], 0, sizeof(sidev->fds_cb[sockfd])); + sl_si91x_select(NUMBER_OF_BSD_SOCKETS, &sidev->fds_watch, NULL, NULL, NULL, + siwx917_sock_on_recv); + ret = sl_si91x_shutdown(sockfd, 0); + if (ret < 0) { + ret = -errno; + } + return ret; +} + +static int siwx917_sock_bind(struct net_context *context, + const struct sockaddr *addr, socklen_t addrlen) +{ + struct siwx917_dev *sidev = net_context_get_iface(context)->if_dev->dev->data; + int sockfd = (int)context->offload_context; + struct sockaddr addr_le; + int ret; + + /* Zephyr tends to call bind() even if the TCP socket is a client. 917 + * return an error in this case. + */ + if (net_context_get_proto(context) == IPPROTO_TCP && + !((struct sockaddr_in *)addr)->sin_port) { + return 0; + } + siwx917_sockaddr_swap_bytes(&addr_le, addr, addrlen); + ret = sl_si91x_bind(sockfd, &addr_le, addrlen); + if (ret) { + return -errno; + } + /* WiseConnect refuses to run select on TCP listening sockets */ + if (net_context_get_proto(context) == IPPROTO_UDP) { + SL_SI91X_FD_SET(sockfd, &sidev->fds_watch); + sl_si91x_select(NUMBER_OF_BSD_SOCKETS, &sidev->fds_watch, NULL, NULL, NULL, + siwx917_sock_on_recv); + } + return 0; +} + +static int siwx917_sock_connect(struct net_context *context, + const struct sockaddr *addr, socklen_t addrlen, + net_context_connect_cb_t cb, int32_t timeout, void *user_data) +{ + struct siwx917_dev *sidev = net_context_get_iface(context)->if_dev->dev->data; + int sockfd = (int)context->offload_context; + struct sockaddr addr_le; + int ret; + + /* sl_si91x_connect() always return immediately, so we ignore timeout */ + siwx917_sockaddr_swap_bytes(&addr_le, addr, addrlen); + ret = sl_si91x_connect(sockfd, &addr_le, addrlen); + if (ret) { + ret = -errno; + } + SL_SI91X_FD_SET(sockfd, &sidev->fds_watch); + sl_si91x_select(NUMBER_OF_BSD_SOCKETS, &sidev->fds_watch, NULL, NULL, NULL, + siwx917_sock_on_recv); + net_context_set_state(context, NET_CONTEXT_CONNECTED); + if (cb) { + cb(context, ret, user_data); + } + return ret; +} + +static int siwx917_sock_listen(struct net_context *context, int backlog) +{ + int sockfd = (int)context->offload_context; + int ret; + + ret = sl_si91x_listen(sockfd, backlog); + if (ret) { + return -errno; + } + net_context_set_state(context, NET_CONTEXT_LISTENING); + return 0; +} + +static int siwx917_sock_accept(struct net_context *context, + net_tcp_accept_cb_t cb, int32_t timeout, void *user_data) +{ + struct siwx917_dev *sidev = net_context_get_iface(context)->if_dev->dev->data; + int sockfd = (int)context->offload_context; + struct net_context *newcontext; + struct sockaddr addr_le; + int ret; + + /* TODO: support timeout != K_FOREVER */ + assert(timeout < 0); + + ret = net_context_get(net_context_get_family(context), + net_context_get_type(context), + net_context_get_proto(context), &newcontext); + if (ret < 0) { + return ret; + } + /* net_context_get() calls siwx917_sock_get() but sl_si91x_accept() also + * allocates a socket. + */ + ret = siwx917_sock_put(newcontext); + if (ret < 0) { + return ret; + } + /* The iface is reset when getting a new context. */ + newcontext->iface = context->iface; + ret = sl_si91x_accept(sockfd, &addr_le, sizeof(addr_le)); + if (ret < 0) { + return -errno; + } + newcontext->flags |= NET_CONTEXT_REMOTE_ADDR_SET; + newcontext->offload_context = (void *)ret; + siwx917_sockaddr_swap_bytes(&newcontext->remote, &addr_le, sizeof(addr_le)); + + SL_SI91X_FD_SET(ret, &sidev->fds_watch); + sl_si91x_select(NUMBER_OF_BSD_SOCKETS, &sidev->fds_watch, NULL, NULL, NULL, + siwx917_sock_on_recv); + if (cb) { + cb(newcontext, &addr_le, sizeof(addr_le), 0, user_data); + } + + return 0; +} + +static int siwx917_sock_sendto(struct net_pkt *pkt, + const struct sockaddr *addr, socklen_t addrlen, + net_context_send_cb_t cb, int32_t timeout, void *user_data) +{ + struct net_context *context = pkt->context; + int sockfd = (int)context->offload_context; + struct sockaddr addr_le; + struct net_buf *buf; + int ret; + + /* struct net_pkt use fragmented buffers while SiWx917 API need a + * continuous buffer. + */ + if (net_pkt_get_len(pkt) > NET_ETH_MTU) { + LOG_ERR("unexpected buffer size"); + ret = -ENOBUFS; + goto out_cb; + } + buf = net_buf_alloc(&siwx917_tx_pool, K_FOREVER); + if (!buf) { + ret = -ENOBUFS; + goto out_cb; + } + if (net_pkt_read(pkt, buf->data, net_pkt_get_len(pkt))) { + ret = -ENOBUFS; + goto out_release_buf; + } + net_buf_add(buf, net_pkt_get_len(pkt)); + + /* sl_si91x_sendto() always return immediately, so we ignore timeout */ + siwx917_sockaddr_swap_bytes(&addr_le, addr, addrlen); + ret = sl_si91x_sendto(sockfd, buf->data, net_pkt_get_len(pkt), 0, &addr_le, addrlen); + if (ret < 0) { + ret = -errno; + goto out_release_buf; + } + net_pkt_unref(pkt); + +out_release_buf: + net_buf_unref(buf); + +out_cb: + if (cb) { + cb(pkt->context, ret, user_data); + } + return ret; +} + +static int siwx917_sock_send(struct net_pkt *pkt, + net_context_send_cb_t cb, int32_t timeout, void *user_data) +{ + return siwx917_sock_sendto(pkt, NULL, 0, cb, timeout, user_data); +} + +static int siwx917_sock_recv(struct net_context *context, + net_context_recv_cb_t cb, int32_t timeout, void *user_data) +{ + struct net_if *iface = net_context_get_iface(context); + struct siwx917_dev *sidev = iface->if_dev->dev->data; + int sockfd = (int)context->offload_context; + int ret; + + ret = k_event_wait(&sidev->fds_recv_event, 1U << sockfd, false, + timeout < 0 ? K_FOREVER : K_MSEC(timeout)); + if (timeout == 0) { + sidev->fds_cb[sockfd].context = context; + sidev->fds_cb[sockfd].cb = cb; + sidev->fds_cb[sockfd].user_data = user_data; + } else { + memset(&sidev->fds_cb[sockfd], 0, sizeof(sidev->fds_cb[sockfd])); + } + + if (ret) { + k_event_clear(&sidev->fds_recv_event, 1U << sockfd); + ret = siwx917_sock_recv_sync(context, cb, user_data); + SL_SI91X_FD_SET(sockfd, &sidev->fds_watch); + } + + sl_si91x_select(NUMBER_OF_BSD_SOCKETS, &sidev->fds_watch, NULL, NULL, NULL, + siwx917_sock_on_recv); + return ret; +} + +static struct net_offload siwx917_offload = { + .get = siwx917_sock_get, + .put = siwx917_sock_put, + .bind = siwx917_sock_bind, + .listen = siwx917_sock_listen, + .connect = siwx917_sock_connect, + .accept = siwx917_sock_accept, + .sendto = siwx917_sock_sendto, + .send = siwx917_sock_send, + .recv = siwx917_sock_recv, +}; + +void siwx917_sock_init(struct net_if *iface) +{ + struct siwx917_dev *sidev = iface->if_dev->dev->data; + + iface->if_dev->offload = &siwx917_offload; + k_event_init(&sidev->fds_recv_event); +} diff --git a/drivers/wifi/siwx917/siwx917_wifi_socket.h b/drivers/wifi/siwx917/siwx917_wifi_socket.h new file mode 100644 index 0000000..5e2c565 --- /dev/null +++ b/drivers/wifi/siwx917/siwx917_wifi_socket.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Antmicro + * Copyright (c) 2024 Silicon Laboratories Inc. + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef SIWX917_WIFI_SOCKET_H +#define SIWX917_WIFI_SOCKET_H + +#include +#include + +struct siwx917_dev; + +enum offloaded_net_if_types siwx917_get_type(void); +void siwx917_on_join_ipv4(struct siwx917_dev *sidev); +void siwx917_on_join_ipv6(struct siwx917_dev *sidev); +void siwx917_sock_init(struct net_if *iface) + +#endif From 4ff8bd10100d1478df7dc58b7a4f55ccc77bc3d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= Date: Wed, 9 Oct 2024 13:02:41 +0200 Subject: [PATCH 4/7] drivers: wifi: siwx917: Get rid of #ifdef MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We try to avoid #ifdef when possible, especially in .c files. Signed-off-by: Jérôme Pouiller --- drivers/wifi/siwx917/siwx917_wifi_socket.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/wifi/siwx917/siwx917_wifi_socket.c b/drivers/wifi/siwx917/siwx917_wifi_socket.c index 44990a1..ac2f30d 100644 --- a/drivers/wifi/siwx917/siwx917_wifi_socket.c +++ b/drivers/wifi/siwx917/siwx917_wifi_socket.c @@ -59,7 +59,6 @@ static void siwx917_sockaddr_swap_bytes(struct sockaddr *out, void siwx917_on_join_ipv4(struct siwx917_dev *sidev) { -#ifdef CONFIG_NET_IPV4 sl_net_ip_configuration_t ip_config4 = { .mode = SL_IP_MANAGEMENT_DHCP, .type = SL_IPV4, @@ -67,6 +66,9 @@ void siwx917_on_join_ipv4(struct siwx917_dev *sidev) struct in_addr addr4 = { }; int ret; + if (!IS_ENABLED(CONFIG_NET_IPV4)) { + return; + } /* FIXME: support for static IP configuration */ ret = sl_si91x_configure_ip_address(&ip_config4, SL_SI91X_WIFI_CLIENT_VAP_ID); if (!ret) { @@ -76,12 +78,10 @@ void siwx917_on_join_ipv4(struct siwx917_dev *sidev) } else { LOG_ERR("sl_si91x_configure_ip_address(): %#04x", ret); } -#endif } void siwx917_on_join_ipv6(struct siwx917_dev *sidev) { -#ifdef CONFIG_NET_IPV6 sl_net_ip_configuration_t ip_config6 = { .mode = SL_IP_MANAGEMENT_DHCP, .type = SL_IPV6, @@ -89,6 +89,9 @@ void siwx917_on_join_ipv6(struct siwx917_dev *sidev) struct in6_addr addr6 = { }; int ret, i; + if (!IS_ENABLED(CONFIG_NET_IPV6)) { + return; + } /* FIXME: support for static IP configuration */ ret = sl_si91x_configure_ip_address(&ip_config6, SL_SI91X_WIFI_CLIENT_VAP_ID); if (!ret) { @@ -104,7 +107,6 @@ void siwx917_on_join_ipv6(struct siwx917_dev *sidev) } else { LOG_ERR("sl_si91x_configure_ip_address(): %#04x", ret); } -#endif } static int siwx917_sock_recv_sync(struct net_context *context, From 6d0f90217f2471da57b364e0b4cea53c49778291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= Date: Tue, 8 Oct 2024 15:21:08 +0200 Subject: [PATCH 5/7] drivers: wifi: siwx917: Make offloading optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This new mode allows a better compatibility with Zephyr features. Support for offloading is still supported since it can provide better performances in some cases (power and memory consumption). Signed-off-by: Jérôme Pouiller --- drivers/wifi/siwx917/CMakeLists.txt | 7 +- drivers/wifi/siwx917/Kconfig.siwx917 | 20 +++- drivers/wifi/siwx917/siwx917_wifi.c | 98 +++++++++++++++++++- drivers/wifi/siwx917/siwx917_wifi.h | 2 + drivers/wifi/siwx917/siwx917_wifi_socket.h | 24 +++++ soc/silabs/silabs_siwx917/siwg917/nwp_init.c | 3 + 6 files changed, 151 insertions(+), 3 deletions(-) diff --git a/drivers/wifi/siwx917/CMakeLists.txt b/drivers/wifi/siwx917/CMakeLists.txt index fc8891a..acfa215 100644 --- a/drivers/wifi/siwx917/CMakeLists.txt +++ b/drivers/wifi/siwx917/CMakeLists.txt @@ -1,4 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2024 Silicon Laboratories Inc. -zephyr_library_sources_ifdef(CONFIG_WIFI_SIWX917 siwx917_wifi.c siwx917_wifi_socket.c) +if(CONFIG_WIFI_SIWX917) + +zephyr_library_sources(siwx917_wifi.c) +zephyr_library_sources_ifdef(CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD siwx917_wifi_socket.c) + +endif() diff --git a/drivers/wifi/siwx917/Kconfig.siwx917 b/drivers/wifi/siwx917/Kconfig.siwx917 index 5a6f923..9de0993 100644 --- a/drivers/wifi/siwx917/Kconfig.siwx917 +++ b/drivers/wifi/siwx917/Kconfig.siwx917 @@ -7,13 +7,31 @@ config WIFI_SIWX917 depends on DT_HAS_SILABS_SIWX917_WIFI_ENABLED select WISECONNECT_NETWORK_STACK select EVENTS - select WIFI_OFFLOAD select NET_L2_WIFI_MGMT help Enable WiFi driver for the Silabs SiWx917 SoC series. if WIFI_SIWX917 +choice + prompt "Network stack" + default WIFI_SIWX917_NET_STACK_NATIVE + help + Choose "Native" stack if you want a better compatibility with Zephyr + features. "Offloaded" stack may provide better resource (power and + memory) consumption. + +config WIFI_SIWX917_NET_STACK_NATIVE + bool "Native" + select WIFI_USE_NATIVE_NETWORKING + select NET_L2_ETHERNET + +config WIFI_SIWX917_NET_STACK_OFFLOAD + bool "Offloaded" + select WIFI_OFFLOAD + +endchoice + config NET_TCP_WORKQ_STACK_SIZE default 2048 diff --git a/drivers/wifi/siwx917/siwx917_wifi.c b/drivers/wifi/siwx917/siwx917_wifi.c index bfb68b6..3059a43 100644 --- a/drivers/wifi/siwx917/siwx917_wifi.c +++ b/drivers/wifi/siwx917/siwx917_wifi.c @@ -10,6 +10,7 @@ #include "siwx917_wifi.h" #include "siwx917_wifi_socket.h" +#include "sl_rsi_utility.h" #include "sl_net_constants.h" #include "sl_wifi_types.h" #include "sl_wifi_callback_framework.h" @@ -18,6 +19,8 @@ LOG_MODULE_REGISTER(siwx917_wifi); +NET_BUF_POOL_FIXED_DEFINE(siwx917_tx_pool, 1, NET_ETH_MTU, 0, NULL); + static unsigned int siwx917_on_join(sl_wifi_event_t event, char *result, uint32_t result_size, void *arg) { @@ -32,6 +35,9 @@ static unsigned int siwx917_on_join(sl_wifi_event_t event, wifi_mgmt_raise_connect_result_event(sidev->iface, WIFI_STATUS_CONN_SUCCESS); sidev->state = WIFI_STATE_COMPLETED; +#ifndef CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD + net_eth_carrier_on(sidev->iface); +#endif siwx917_on_join_ipv4(sidev); siwx917_on_join_ipv6(sidev); @@ -124,6 +130,9 @@ static int siwx917_disconnect(const struct device *dev) if (ret) { return -EIO; } +#ifndef CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD + net_eth_carrier_off(sidev->iface); +#endif sidev->state = WIFI_STATE_INACTIVE; return 0; } @@ -220,6 +229,83 @@ static int siwx917_status(const struct device *dev, struct wifi_iface_status *st return 0; } +#ifndef CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD + +static int siwx917_send(const struct device *dev, struct net_pkt *pkt) +{ + size_t pkt_len = net_pkt_get_len(pkt); + struct net_buf *buf = NULL; + int ret; + + if (net_pkt_get_len(pkt) > NET_ETH_MTU) { + LOG_ERR("unexpected buffer size"); + return -ENOBUFS; + } + buf = net_buf_alloc(&siwx917_tx_pool, K_FOREVER); + if (!buf) { + return -ENOBUFS; + } + if (net_pkt_read(pkt, buf->data, pkt_len)) { + net_buf_unref(buf); + return -ENOBUFS; + } + net_buf_add(buf, pkt_len); + + ret = sl_wifi_send_raw_data_frame(SL_WIFI_CLIENT_INTERFACE, buf->data, pkt_len); + if (ret) { + return -EIO; + } + + net_pkt_unref(pkt); + net_buf_unref(buf); + + return 0; +} + +/* Receive callback. Keep the name as it is declared weak in WiseConnect */ +sl_status_t sl_si91x_host_process_data_frame(sl_wifi_interface_t interface, + sl_wifi_buffer_t *buffer) +{ + sl_si91x_packet_t *si_pkt = sl_si91x_host_get_buffer_data(buffer, 0, NULL); + struct net_if *iface = net_if_get_default(); + struct net_pkt *pkt; + int ret; + + pkt = net_pkt_rx_alloc_with_buffer(iface, buffer->length, AF_UNSPEC, 0, K_NO_WAIT); + if (!pkt) { + LOG_ERR("net_pkt_rx_alloc_with_buffer() failed"); + return SL_STATUS_FAIL; + } + ret = net_pkt_write(pkt, si_pkt->data, si_pkt->length); + if (ret < 0) { + LOG_ERR("net_pkt_write(): %d", ret); + goto unref; + } + ret = net_recv_data(iface, pkt); + if (ret < 0) { + LOG_ERR("net_recv_data((): %d", ret); + goto unref; + } + return 0; + +unref: + net_pkt_unref(pkt); + return SL_STATUS_FAIL; +} + +#endif + +static void siwx917_ethernet_init(struct net_if *iface) +{ +#ifndef CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD + struct ethernet_context *eth_ctx; + + eth_ctx = net_if_l2_data(iface); + eth_ctx->eth_if_type = L2_ETH_IF_TYPE_WIFI; + ethernet_init(iface); +#endif +} + static void siwx917_iface_init(struct net_if *iface) { struct siwx917_dev *sidev = iface->if_dev->dev->data; @@ -228,7 +314,6 @@ static void siwx917_iface_init(struct net_if *iface) sidev->state = WIFI_STATE_INTERFACE_DISABLED; sidev->iface = iface; - siwx917_sock_init(iface); sl_wifi_set_scan_callback(siwx917_on_scan, sidev); sl_wifi_set_join_callback(siwx917_on_join, sidev); @@ -239,6 +324,8 @@ static void siwx917_iface_init(struct net_if *iface) } net_if_set_link_addr(iface, sidev->macaddr.octet, sizeof(sidev->macaddr.octet), NET_LINK_ETHERNET); + siwx917_sock_init(iface); + siwx917_ethernet_init(iface); sidev->state = WIFI_STATE_INACTIVE; } @@ -257,10 +344,19 @@ static const struct wifi_mgmt_ops siwx917_mgmt = { static const struct net_wifi_mgmt_offload siwx917_api = { .wifi_iface.iface_api.init = siwx917_iface_init, +#ifdef CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD .wifi_iface.get_type = siwx917_get_type, +#else + .wifi_iface.send = siwx917_send, +#endif .wifi_mgmt_api = &siwx917_mgmt, }; static struct siwx917_dev siwx917_dev; +#ifdef CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, siwx917_dev_init, NULL, &siwx917_dev, NULL, CONFIG_WIFI_INIT_PRIORITY, &siwx917_api, NET_ETH_MTU); +#else +ETH_NET_DEVICE_DT_INST_DEFINE(0, siwx917_dev_init, NULL, &siwx917_dev, NULL, + CONFIG_WIFI_INIT_PRIORITY, &siwx917_api, NET_ETH_MTU); +#endif diff --git a/drivers/wifi/siwx917/siwx917_wifi.h b/drivers/wifi/siwx917/siwx917_wifi.h index e6d530e..f02f7e2 100644 --- a/drivers/wifi/siwx917/siwx917_wifi.h +++ b/drivers/wifi/siwx917/siwx917_wifi.h @@ -20,6 +20,7 @@ struct siwx917_dev { enum wifi_iface_state state; scan_result_cb_t scan_res_cb; +#ifdef CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD struct k_event fds_recv_event; sl_si91x_fd_set fds_watch; struct { @@ -27,6 +28,7 @@ struct siwx917_dev { void *user_data; struct net_context *context; } fds_cb[NUMBER_OF_BSD_SOCKETS]; +#endif }; #endif diff --git a/drivers/wifi/siwx917/siwx917_wifi_socket.h b/drivers/wifi/siwx917/siwx917_wifi_socket.h index 5e2c565..955982e 100644 --- a/drivers/wifi/siwx917/siwx917_wifi_socket.h +++ b/drivers/wifi/siwx917/siwx917_wifi_socket.h @@ -8,12 +8,36 @@ #include #include +#include struct siwx917_dev; +#ifdef CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD + enum offloaded_net_if_types siwx917_get_type(void); void siwx917_on_join_ipv4(struct siwx917_dev *sidev); void siwx917_on_join_ipv6(struct siwx917_dev *sidev); +void siwx917_sock_init(struct net_if *iface); + +#else /* CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD */ + +enum offloaded_net_if_types siwx917_get_type(void) +{ + assert(0); +} + +void siwx917_on_join_ipv4(struct siwx917_dev *sidev) +{ +} + +void siwx917_on_join_ipv6(struct siwx917_dev *sidev) +{ +} + void siwx917_sock_init(struct net_if *iface) +{ +} + +#endif /* CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD */ #endif diff --git a/soc/silabs/silabs_siwx917/siwg917/nwp_init.c b/soc/silabs/silabs_siwx917/siwg917/nwp_init.c index d598fe5..fb8a3dc 100644 --- a/soc/silabs/silabs_siwx917/siwg917/nwp_init.c +++ b/soc/silabs/silabs_siwx917/siwg917/nwp_init.c @@ -54,6 +54,9 @@ static int silabs_siwx917_nwp_init(void) cfg->tcp_ip_feature_bit_map |= #ifdef CONFIG_NET_IPV6 SL_SI91X_TCP_IP_FEAT_DHCPV6_CLIENT | SL_SI91X_TCP_IP_FEAT_IPV6 | +#endif +#ifndef CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD + SL_SI91X_TCP_IP_FEAT_BYPASS | #endif SL_SI91X_TCP_IP_FEAT_DHCPV4_CLIENT | SL_SI91X_TCP_IP_FEAT_DNS_CLIENT | SL_SI91X_TCP_IP_FEAT_SSL | SL_SI91X_TCP_IP_FEAT_MDNSD | SL_SI91X_TCP_IP_FEAT_ICMP; From 0dd9c71583abbd33160a99877f24df2e7a803a02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= Date: Tue, 8 Oct 2024 16:51:27 +0200 Subject: [PATCH 6/7] drivers: wifi: siwx917: Drop unused features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since SiWx917 is able to use natice network stack, some NWP features are not needed anymore. This commit also try to keep WiFi features inside the "#ifdef CONFIG_WIFI_SIWX917" statement. Signed-off-by: Jérôme Pouiller --- soc/silabs/silabs_siwx917/siwg917/nwp_init.c | 32 +++++++++++--------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/soc/silabs/silabs_siwx917/siwg917/nwp_init.c b/soc/silabs/silabs_siwx917/siwg917/nwp_init.c index fb8a3dc..94b7fc7 100644 --- a/soc/silabs/silabs_siwx917/siwg917/nwp_init.c +++ b/soc/silabs/silabs_siwx917/siwg917/nwp_init.c @@ -37,7 +37,6 @@ static int silabs_siwx917_nwp_init(void) .boot_config = { .oper_mode = SL_SI91X_CLIENT_MODE, .coex_mode = NWP_INIT_COEX_MODE, - .feature_bit_map = SL_SI91X_FEAT_SECURITY_OPEN | SL_SI91X_FEAT_WPS_DISABLE, .tcp_ip_feature_bit_map = SL_SI91X_TCP_IP_FEAT_EXTENSION_VALID, .ext_tcp_ip_feature_bit_map = SL_SI91X_CONFIG_FEAT_EXTENSION_VALID, .config_feature_bit_map = SL_SI91X_ENABLE_ENHANCED_MAX_PSP, @@ -45,23 +44,28 @@ static int silabs_siwx917_nwp_init(void) .ext_custom_feature_bit_map = MEMORY_CONFIG | SL_SI91X_EXT_FEAT_XTAL_CLK | - SL_SI91X_EXT_FEAT_IEEE_80211W | SL_SI91X_EXT_FEAT_FRONT_END_SWITCH_PINS_ULP_GPIO_4_5_0, - }}; + } + }; sl_si91x_boot_configuration_t *cfg = &network_config.boot_config; #ifdef CONFIG_WIFI_SIWX917 - cfg->tcp_ip_feature_bit_map |= -#ifdef CONFIG_NET_IPV6 - SL_SI91X_TCP_IP_FEAT_DHCPV6_CLIENT | SL_SI91X_TCP_IP_FEAT_IPV6 | -#endif -#ifndef CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD - SL_SI91X_TCP_IP_FEAT_BYPASS | -#endif - SL_SI91X_TCP_IP_FEAT_DHCPV4_CLIENT | SL_SI91X_TCP_IP_FEAT_DNS_CLIENT | - SL_SI91X_TCP_IP_FEAT_SSL | SL_SI91X_TCP_IP_FEAT_MDNSD | SL_SI91X_TCP_IP_FEAT_ICMP; - cfg->ext_tcp_ip_feature_bit_map |= - SL_SI91X_EXT_TCP_IP_WINDOW_SCALING | SL_SI91X_EXT_TCP_IP_TOTAL_SELECTS(10); + cfg->feature_bit_map |= SL_SI91X_FEAT_SECURITY_OPEN | SL_SI91X_FEAT_WPS_DISABLE, + cfg->ext_custom_feature_bit_map |= SL_SI91X_EXT_FEAT_IEEE_80211W; + if (IS_ENABLED(CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD)) { + cfg->ext_tcp_ip_feature_bit_map |= SL_SI91X_EXT_TCP_IP_WINDOW_SCALING; + cfg->ext_tcp_ip_feature_bit_map |= SL_SI91X_EXT_TCP_IP_TOTAL_SELECTS(10); + cfg->tcp_ip_feature_bit_map |= SL_SI91X_TCP_IP_FEAT_ICMP; + if (IS_ENABLED(CONFIG_NET_IPV6)) { + cfg->tcp_ip_feature_bit_map |= SL_SI91X_TCP_IP_FEAT_DHCPV6_CLIENT; + cfg->tcp_ip_feature_bit_map |= SL_SI91X_TCP_IP_FEAT_IPV6; + } + if (IS_ENABLED(CONFIG_NET_IPV4)) { + cfg->tcp_ip_feature_bit_map |= SL_SI91X_TCP_IP_FEAT_DHCPV4_CLIENT; + } + } else { + cfg->tcp_ip_feature_bit_map |= SL_SI91X_TCP_IP_FEAT_BYPASS; + } #endif #ifdef CONFIG_BT_SIWX917 From cbf33f48d8bfbef87bd31190b56bbaba68b98bb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= Date: Tue, 15 Oct 2024 16:56:50 +0200 Subject: [PATCH 7/7] drivers: wifi: siwx917: Simplify #ifdef MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some #ifdef can be easily changed in IS_ENABLED(). Signed-off-by: Jérôme Pouiller --- drivers/wifi/siwx917/siwx917_wifi.c | 39 +++++++++++++++-------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/drivers/wifi/siwx917/siwx917_wifi.c b/drivers/wifi/siwx917/siwx917_wifi.c index 3059a43..14093fb 100644 --- a/drivers/wifi/siwx917/siwx917_wifi.c +++ b/drivers/wifi/siwx917/siwx917_wifi.c @@ -35,9 +35,10 @@ static unsigned int siwx917_on_join(sl_wifi_event_t event, wifi_mgmt_raise_connect_result_event(sidev->iface, WIFI_STATUS_CONN_SUCCESS); sidev->state = WIFI_STATE_COMPLETED; -#ifndef CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD - net_eth_carrier_on(sidev->iface); -#endif + + if (IS_ENABLED(CONFIG_WIFI_SIWX917_NET_STACK_NATIVE)) { + net_eth_carrier_on(sidev->iface); + } siwx917_on_join_ipv4(sidev); siwx917_on_join_ipv6(sidev); @@ -130,9 +131,9 @@ static int siwx917_disconnect(const struct device *dev) if (ret) { return -EIO; } -#ifndef CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD - net_eth_carrier_off(sidev->iface); -#endif + if (IS_ENABLED(CONFIG_WIFI_SIWX917_NET_STACK_NATIVE)) { + net_eth_carrier_off(sidev->iface); + } sidev->state = WIFI_STATE_INACTIVE; return 0; } @@ -229,7 +230,7 @@ static int siwx917_status(const struct device *dev, struct wifi_iface_status *st return 0; } -#ifndef CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD +#ifdef CONFIG_WIFI_SIWX917_NET_STACK_NATIVE static int siwx917_send(const struct device *dev, struct net_pkt *pkt) { @@ -297,13 +298,13 @@ sl_status_t sl_si91x_host_process_data_frame(sl_wifi_interface_t interface, static void siwx917_ethernet_init(struct net_if *iface) { -#ifndef CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD struct ethernet_context *eth_ctx; - eth_ctx = net_if_l2_data(iface); - eth_ctx->eth_if_type = L2_ETH_IF_TYPE_WIFI; - ethernet_init(iface); -#endif + if (IS_ENABLED(CONFIG_WIFI_SIWX917_NET_STACK_NATIVE)) { + eth_ctx = net_if_l2_data(iface); + eth_ctx->eth_if_type = L2_ETH_IF_TYPE_WIFI; + ethernet_init(iface); + } } static void siwx917_iface_init(struct net_if *iface) @@ -344,19 +345,19 @@ static const struct wifi_mgmt_ops siwx917_mgmt = { static const struct net_wifi_mgmt_offload siwx917_api = { .wifi_iface.iface_api.init = siwx917_iface_init, -#ifdef CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD - .wifi_iface.get_type = siwx917_get_type, -#else +#ifdef CONFIG_WIFI_SIWX917_NET_STACK_NATIVE .wifi_iface.send = siwx917_send, +#else + .wifi_iface.get_type = siwx917_get_type, #endif .wifi_mgmt_api = &siwx917_mgmt, }; static struct siwx917_dev siwx917_dev; -#ifdef CONFIG_WIFI_SIWX917_NET_STACK_OFFLOAD -NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, siwx917_dev_init, NULL, &siwx917_dev, NULL, - CONFIG_WIFI_INIT_PRIORITY, &siwx917_api, NET_ETH_MTU); -#else +#ifdef CONFIG_WIFI_SIWX917_NET_STACK_NATIVE ETH_NET_DEVICE_DT_INST_DEFINE(0, siwx917_dev_init, NULL, &siwx917_dev, NULL, CONFIG_WIFI_INIT_PRIORITY, &siwx917_api, NET_ETH_MTU); +#else +NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, siwx917_dev_init, NULL, &siwx917_dev, NULL, + CONFIG_WIFI_INIT_PRIORITY, &siwx917_api, NET_ETH_MTU); #endif