diff --git a/boards/shields/nrf7002eb2/Kconfig.shield b/boards/shields/nrf7002eb2/Kconfig.shield new file mode 100644 index 000000000000..3a6309b39148 --- /dev/null +++ b/boards/shields/nrf7002eb2/Kconfig.shield @@ -0,0 +1,14 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_NRF7002EB2 + def_bool $(shields_list_contains,nrf7002eb2) + +config SHIELD_NRF7002EB2_NRF7001 + def_bool $(shields_list_contains,nrf7002eb2_nrf7001) + +config SHIELD_NRF7002EB2_NRF7000 + def_bool $(shields_list_contains,nrf7002eb2_nrf7000) + +config SHIELD_NRF7002EB2_COEX + def_bool $(shields_list_contains,nrf7002eb2_coex) diff --git a/boards/shields/nrf7002eb2/boards/nrf54l15dk_nrf54l15_cpuapp.overlay b/boards/shields/nrf7002eb2/boards/nrf54l15dk_nrf54l15_cpuapp.overlay new file mode 100644 index 000000000000..912d806b5f47 --- /dev/null +++ b/boards/shields/nrf7002eb2/boards/nrf54l15dk_nrf54l15_cpuapp.overlay @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "../nrf7002eb2_gpio_pins_1.dtsi" + +/ { + chosen { + zephyr,wifi = &wlan0; + zephyr,console = &uart30; + zephyr,shell-uart = &uart30; + zephyr,uart-mcumgr = &uart30; + zephyr,bt-mon-uart = &uart30; + zephyr,bt-c2h-uart = &uart30; + }; +}; + +&pinctrl { + spi22_default: spi22_default { + group1 { + psels = , + , + ; + bias-pull-down; + }; + }; + + spi22_sleep: spi22_sleep { + group1 { + psels = , + , + ; + bias-pull-down; + low-power-enable; + }; + }; +}; + +&spi22 { + cs-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&spi22_default>; + pinctrl-1 = <&spi22_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart20 { + status = "disabled"; +}; + +&uart30 { + status = "okay"; +}; diff --git a/boards/shields/nrf7002eb2/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay b/boards/shields/nrf7002eb2/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay new file mode 100644 index 000000000000..dcc759345bad --- /dev/null +++ b/boards/shields/nrf7002eb2/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "../nrf7002eb2_gpio_pins_2.dtsi" + +/ { + chosen { + zephyr,wifi = &wlan0; + zephyr,console = &uart30; + zephyr,shell-uart = &uart30; + zephyr,uart-mcumgr = &uart30; + zephyr,bt-mon-uart = &uart30; + zephyr,bt-c2h-uart = &uart30; + }; + + buttons { + /delete-node/ button_3; + }; + + aliases { + /delete-property/ sw3; + }; +}; + +&gpio3 { + status = "okay"; +}; + +&pinctrl { + spi22_default: spi22_default { + group1 { + psels = , + , + ; + bias-pull-down; + }; + }; + + spi22_sleep: spi22_sleep { + group1 { + psels = , + , + ; + bias-pull-down; + low-power-enable; + }; + }; + + uart30_default: uart30_default { + group1 { + psels = ; + }; + + group2 { + psels = ; + bias-pull-up; + }; + }; + + uart30_sleep: uart30_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +&spi22 { + status = "okay"; + cs-gpios = <&gpio3 2 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&spi22_default>; + pinctrl-1 = <&spi22_sleep>; + pinctrl-names = "default", "sleep"; +}; + +/* uart20 has pin conflicts with EB-II shield hence disabling that + * and enabling uart30 as console port. + */ +&uart20 { + status = "disabled"; +}; + +&uart30 { + status = "okay"; +}; diff --git a/boards/shields/nrf7002eb2/doc/index.rst b/boards/shields/nrf7002eb2/doc/index.rst new file mode 100644 index 000000000000..6fe033c21221 --- /dev/null +++ b/boards/shields/nrf7002eb2/doc/index.rst @@ -0,0 +1,72 @@ +.. _nrf7002eb2: + +nRF7002 EB II +############# + +Overview +******** + +The nRF7002 EB II is a versatile evaluation kit in the form of a thumbstick shield which connects to +compatible Nordic host boards using the Nordic edge-connector. + +The nRF7002 EB II unlocks low-power Wi-Fi 6 capabilities for your host device. It supports dual-band Wi-Fi +2.4GHz and 5GHz, and is based on the nRF7002 SoC. The shield also supports nRF7001 and nRF7000 SoCs +through variant overlays. +Seamlessly connect to Wi-Fi networks and leverage Wi-Fi-based locationing, enabling advanced +features such as SSID sniffing of local Wi-Fi hubs. + +.. figure:: nrf7002eb2.jpg + :alt: nRF7002 EB II + :align: center + + nRF7002 EB II + +Requirements +************ + +The nRF7002 EB II board is designed to fit straight into a Nordic edge-connector and uses SPI as the +communication interface. Any host board that supports the Nordic edge-connector can be used with +the nRF7002 EB II. + +Prerequisites +------------- + +The nRF70 driver requires firmware binary blobs for Wi-Fi operation. Run the command +below to retrieve those files. + +.. code-block:: console + + west update + west blobs fetch nrf_wifi + +Usage +***** + +The shield can be used in any application by setting ``--shield nrf7002eb2`` when invoking ``west build``. + +Shield Variants +*************** + +The nRF7002 EB II has several variants to support different nRF70 SoCs and features: + +- ``nrf7002eb2``: The default variant using the nRF7002 SoC. +- ``nrf7002eb2_nrf7001``: Variant using the nRF7001 SoC. +- ``nrf7002eb2_nrf7000``: Variant using the nRF7000 SoC. +- ``nrf7002eb2_coex``: Variant which includes the COEX pins. These pins are not routed to the + edge-connector on some boards, like earlier revisions of the Thingy53 than v1.0.0. + +SR Co-existence +*************** + +The nRF7002 EB II supports SR co-existence provided the host board supports it. The SR co-existence +pins are connected to the host board's GPIO pins. + +Two Kconfig options are available to enable SR co-existence: + +- :kconfig:option:`CONFIG_NRF70_SR_COEX`: Enables SR co-existence. +- :kconfig:option:`CONFIG_NRF70_SR_COEX_RF_SWITCH`: Control SR side RF switch. + +References +********** + +- `Developing with nRF7002 EB II `_ diff --git a/boards/shields/nrf7002eb2/doc/nrf7002eb2.jpg b/boards/shields/nrf7002eb2/doc/nrf7002eb2.jpg new file mode 100644 index 000000000000..458093f16620 Binary files /dev/null and b/boards/shields/nrf7002eb2/doc/nrf7002eb2.jpg differ diff --git a/boards/shields/nrf7002eb2/nrf7002eb2.overlay b/boards/shields/nrf7002eb2/nrf7002eb2.overlay new file mode 100644 index 000000000000..304814fa3040 --- /dev/null +++ b/boards/shields/nrf7002eb2/nrf7002eb2.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,wifi = &wlan0; + }; +}; + +&wifi_spi { + status = "okay"; + + nrf70: nrf7002-spi@0 { + compatible = "nordic,nrf7002-spi"; + status = "okay"; + + /* Include common nRF70 overlays */ + #include "nrf7002eb2_common.dtsi" + #include "nrf7002eb2_common_5g.dtsi" + }; +}; diff --git a/boards/shields/nrf7002eb2/nrf7002eb2_coex.overlay b/boards/shields/nrf7002eb2/nrf7002eb2_coex.overlay new file mode 100644 index 000000000000..36f352bc6a5e --- /dev/null +++ b/boards/shields/nrf7002eb2/nrf7002eb2_coex.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + nrf_radio_coex: coex { + compatible = "nordic,nrf7002-coex"; + status = "okay"; + status0-gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>; + req-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + grant-gpios = <&gpio1 7 (GPIO_PULL_DOWN | GPIO_ACTIVE_LOW)>; + }; +}; diff --git a/boards/shields/nrf7002eb2/nrf7002eb2_common.dtsi b/boards/shields/nrf7002eb2/nrf7002eb2_common.dtsi new file mode 100644 index 000000000000..efe0703ac9dd --- /dev/null +++ b/boards/shields/nrf7002eb2/nrf7002eb2_common.dtsi @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/* Common assignments for nRF70 EB-II shield */ +reg = <0>; +spi-max-frequency = ; + +/* Maximum TX power limits for 2.4 GHz */ +wifi-max-tx-pwr-2g-dsss = <21>; +wifi-max-tx-pwr-2g-mcs0 = <16>; +wifi-max-tx-pwr-2g-mcs7 = <16>; + +/* List of interfaces */ +wlan0: wlan0 { + compatible = "nordic,wlan"; +}; diff --git a/boards/shields/nrf7002eb2/nrf7002eb2_common_5g.dtsi b/boards/shields/nrf7002eb2/nrf7002eb2_common_5g.dtsi new file mode 100644 index 000000000000..05a472a32bd5 --- /dev/null +++ b/boards/shields/nrf7002eb2/nrf7002eb2_common_5g.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +wifi-max-tx-pwr-5g-low-mcs0 = <13>; +wifi-max-tx-pwr-5g-low-mcs7 = <13>; +wifi-max-tx-pwr-5g-mid-mcs0 = <13>; +wifi-max-tx-pwr-5g-mid-mcs7 = <13>; +wifi-max-tx-pwr-5g-high-mcs0 = <12>; +wifi-max-tx-pwr-5g-high-mcs7 = <12>; diff --git a/boards/shields/nrf7002eb2/nrf7002eb2_gpio_pins_1.dtsi b/boards/shields/nrf7002eb2/nrf7002eb2_gpio_pins_1.dtsi new file mode 100644 index 000000000000..95ad1ed44221 --- /dev/null +++ b/boards/shields/nrf7002eb2/nrf7002eb2_gpio_pins_1.dtsi @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + nrf_radio_coex: coex { + compatible = "nordic,nrf7002-coex"; + status = "disabled"; + status0-gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>; + req-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; + grant-gpios = <&gpio1 12 (GPIO_PULL_DOWN | GPIO_ACTIVE_LOW)>; + }; +}; + +&nrf70 { + iovdd-ctrl-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; + bucken-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; + host-irq-gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>; +}; + +&gpio1 { + status = "okay"; +}; diff --git a/boards/shields/nrf7002eb2/nrf7002eb2_gpio_pins_2.dtsi b/boards/shields/nrf7002eb2/nrf7002eb2_gpio_pins_2.dtsi new file mode 100644 index 000000000000..dc59273a0314 --- /dev/null +++ b/boards/shields/nrf7002eb2/nrf7002eb2_gpio_pins_2.dtsi @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&nrf70 { + iovdd-ctrl-gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>; + bucken-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; + host-irq-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; +}; + +&gpio1 { + status = "okay"; +}; diff --git a/boards/shields/nrf7002eb2/nrf7002eb2_nrf7000.overlay b/boards/shields/nrf7002eb2/nrf7002eb2_nrf7000.overlay new file mode 100644 index 000000000000..22b36e7b27fc --- /dev/null +++ b/boards/shields/nrf7002eb2/nrf7002eb2_nrf7000.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,wifi = &wlan0; + }; +}; + +&wifi_spi { + status = "okay"; + + nrf70: nrf7000-spi@0 { + compatible = "nordic,nrf7000-spi"; + status = "okay"; + + /* Include common nRF70 overlays */ + #include "nrf7002eb2_common.dtsi" + #include "nrf7002eb2_common_5g.dtsi" + }; +}; diff --git a/boards/shields/nrf7002eb2/nrf7002eb2_nrf7001.overlay b/boards/shields/nrf7002eb2/nrf7002eb2_nrf7001.overlay new file mode 100644 index 000000000000..9a9243063a98 --- /dev/null +++ b/boards/shields/nrf7002eb2/nrf7002eb2_nrf7001.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,wifi = &wlan0; + }; +}; + +&wifi_spi { + status = "okay"; + + nrf70: nrf7001-spi@0 { + compatible = "nordic,nrf7001-spi"; + status = "okay"; + + /* Include common nRF70 overlays */ + #include "nrf7002eb2_common.dtsi" + }; +}; diff --git a/boards/shields/nrf7002eb2/shield.yml b/boards/shields/nrf7002eb2/shield.yml new file mode 100644 index 000000000000..60349b0a3cb7 --- /dev/null +++ b/boards/shields/nrf7002eb2/shield.yml @@ -0,0 +1,26 @@ +# @Kconfig.shield + +shields: + - name: nrf7002eb2 + full_name: nRF7002 EB-II Shield + vendor: nordic + supported_features: + - wifi + + - name: nrf7002eb2_nrf7001 + full_name: nRF7002 EB-II Shield (nRF7001) + vendor: nordic + supported_features: + - wifi + + - name: nrf7002eb2_nrf7000 + full_name: nRF7002 EB-II Shield (nRF7000) + vendor: nordic + supported_features: + - wifi + + - name: nrf7002eb2_coex + full_name: nRF7002 EB-II Shield (SR Co-Existence) + vendor: nordic + supported_features: + - wifi diff --git a/doc/connectivity/networking/api/wifi.rst b/doc/connectivity/networking/api/wifi.rst index e0be44835443..e50a1f9fc74b 100644 --- a/doc/connectivity/networking/api/wifi.rst +++ b/doc/connectivity/networking/api/wifi.rst @@ -10,6 +10,7 @@ The Wi-Fi management API is used to manage Wi-Fi networks. It supports below mod * IEEE802.11 Station (STA) * IEEE802.11 Access Point (AP) +* IEEE802.11 P2P (Wi-Fi Direct) Only personal mode security is supported with below types: @@ -215,6 +216,19 @@ The test certificates in ``samples/net/wifi/test_certs/rsa2k`` are generated usi .. note:: These certificates are for testing only and should not be used in production. +Wi-Fi P2P (Wi-Fi Direct) +************************ + +Wi-Fi P2P or Wi-Fi Direct enables devices to communicate directly with each other without requiring +a traditional access point. This feature is particularly useful for device-to-device communication +scenarios. + +To enable and build with Wi-Fi P2P support: + +.. code-block:: bash + + $ west build -p -b samples/net/wifi/shell -- -DCONFIG_WIFI_NM_WPA_SUPPLICANT_P2P=y + API Reference ************* diff --git a/doc/releases/release-notes-4.4.rst b/doc/releases/release-notes-4.4.rst index 79a2bbf802e2..b74d1670107e 100644 --- a/doc/releases/release-notes-4.4.rst +++ b/doc/releases/release-notes-4.4.rst @@ -102,6 +102,24 @@ New APIs and options * :dtcompatible:`jedec,mspi-nor` now allows MSPI configuration of read, write and control commands separately via devicetree. +* NVMEM + + * Flash device support + + * :kconfig:option:`CONFIG_NVMEM_FLASH` + * :kconfig:option:`CONFIG_NVMEM_FLASH_WRITE` + +* Networking + + * Wi-Fi + + * Add support for Wi-Fi Direct (P2P) mode. + +* Settings + + * :kconfig:option:`CONFIG_SETTINGS_SAVE_SINGLE_SUBTREE_WITHOUT_MODIFICATION` + * :kconfig:option:`CONFIG_SETTINGS_SAVE_SINGLE_SUBTREE_WITHOUT_MODIFICATION_VALUE_SIZE` + .. zephyr-keep-sorted-stop New Boards diff --git a/drivers/usb/udc/udc_dwc2.c b/drivers/usb/udc/udc_dwc2.c index eb7368e1178f..7d38aa69f7ec 100644 --- a/drivers/usb/udc/udc_dwc2.c +++ b/drivers/usb/udc/udc_dwc2.c @@ -419,6 +419,11 @@ static int dwc2_ctrl_feed_dout(const struct device *dev, const size_t length) return -ENOMEM; } + if (dwc2_in_buffer_dma_mode(dev)) { + /* Get rid of all dirty cache lines */ + sys_cache_data_invd_range(buf->data, net_buf_tailroom(buf)); + } + udc_buf_put(ep_cfg, buf); atomic_set_bit(&priv->xfer_new, 16); k_event_post(&priv->drv_evt, BIT(DWC2_DRV_EVT_XFER)); @@ -589,8 +594,6 @@ static int dwc2_tx_fifo_write(const struct device *dev, sys_write32((uint32_t)buf->data, (mem_addr_t)&base->in_ep[ep_idx].diepdma); - - sys_cache_data_flush_range(buf->data, len); } diepctl = sys_read32(diepctl_reg); @@ -790,8 +793,6 @@ static void dwc2_prep_rx(const struct device *dev, struct net_buf *buf, sys_write32((uint32_t)data, (mem_addr_t)&base->out_ep[ep_idx].doepdma); - - sys_cache_data_invd_range(data, xfersize); } sys_write32(doepctl, doepctl_reg); @@ -968,6 +969,10 @@ static inline int dwc2_handle_evt_dout(const struct device *dev, return -ENODATA; } + if (dwc2_in_buffer_dma_mode(dev)) { + sys_cache_data_invd_range(buf->data, buf->len); + } + udc_ep_set_busy(cfg, false); if (cfg->addr == USB_CONTROL_EP_OUT) { @@ -1743,20 +1748,11 @@ static int udc_dwc2_ep_deactivate(const struct device *dev, dxepctl_reg = dwc2_get_dxepctl_reg(dev, cfg->addr); } - dxepctl = sys_read32(dxepctl_reg); - - if (dxepctl & USB_DWC2_DEPCTL_USBACTEP) { - LOG_DBG("Disable ep 0x%02x DxEPCTL%u %x", - cfg->addr, ep_idx, dxepctl); - - udc_dwc2_ep_disable(dev, cfg, false, true); + udc_dwc2_ep_disable(dev, cfg, false, true); - dxepctl = sys_read32(dxepctl_reg); - dxepctl &= ~USB_DWC2_DEPCTL_USBACTEP; - } else { - LOG_WRN("ep 0x%02x is not active DxEPCTL%u %x", - cfg->addr, ep_idx, dxepctl); - } + dxepctl = sys_read32(dxepctl_reg); + LOG_DBG("Disable ep 0x%02x DxEPCTL%u %x", cfg->addr, ep_idx, dxepctl); + dxepctl &= ~USB_DWC2_DEPCTL_USBACTEP; if (USB_EP_DIR_IS_IN(cfg->addr) && udc_mps_ep_size(cfg) != 0U && ep_idx != 0U) { @@ -1835,6 +1831,17 @@ static int udc_dwc2_ep_enqueue(const struct device *dev, struct udc_dwc2_data *const priv = udc_get_private(dev); LOG_DBG("%p enqueue %x %p", dev, cfg->addr, buf); + + if (dwc2_in_buffer_dma_mode(dev)) { + if (USB_EP_DIR_IS_IN(cfg->addr)) { + /* Write all dirty cache lines to memory */ + sys_cache_data_flush_range(buf->data, buf->len); + } else { + /* Get rid of all dirty cache lines */ + sys_cache_data_invd_range(buf->data, net_buf_tailroom(buf)); + } + } + udc_buf_put(cfg, buf); if (!cfg->stat.halted) { @@ -1861,6 +1868,13 @@ static int udc_dwc2_ep_dequeue(const struct device *dev, udc_dwc2_ep_disable(dev, cfg, false, true); buf = udc_buf_get_all(cfg); + + if (dwc2_in_buffer_dma_mode(dev) && USB_EP_DIR_IS_OUT(cfg->addr)) { + for (struct net_buf *iter = buf; iter; iter = iter->frags) { + sys_cache_data_invd_range(iter->data, iter->len); + } + } + if (buf) { udc_submit_ep_event(dev, buf, -ECONNABORTED); } @@ -2820,7 +2834,9 @@ static inline void dwc2_handle_out_xfercompl(const struct device *dev, } if (dwc2_in_buffer_dma_mode(dev) && bcnt) { - sys_cache_data_invd_range(net_buf_tail(buf), bcnt); + /* Update just the length, cache will be invalidated in thread + * context after transfer if finished or cancelled. + */ net_buf_add(buf, bcnt); } diff --git a/drivers/wifi/nrf_wifi/Kconfig.nrfwifi b/drivers/wifi/nrf_wifi/Kconfig.nrfwifi index 2021d25580ae..be0ea854b2e2 100644 --- a/drivers/wifi/nrf_wifi/Kconfig.nrfwifi +++ b/drivers/wifi/nrf_wifi/Kconfig.nrfwifi @@ -119,6 +119,7 @@ config NRF70_ENABLE_DUAL_VIF config NRF70_P2P_MODE bool "P2P support in driver" + default y if WIFI_NM_WPA_SUPPLICANT_P2P config NRF70_SYSTEM_WITH_RAW_MODES bool "nRF70 system mode with raw modes" diff --git a/drivers/wifi/nrf_wifi/inc/fmac_main.h b/drivers/wifi/nrf_wifi/inc/fmac_main.h index 799beff1fbaf..be8c9d763679 100644 --- a/drivers/wifi/nrf_wifi/inc/fmac_main.h +++ b/drivers/wifi/nrf_wifi/inc/fmac_main.h @@ -75,9 +75,6 @@ struct nrf_wifi_vif_ctx_zep { #endif /* CONFIG_NET_STATISTICS_ETHERNET_VENDOR */ struct net_stats_eth eth_stats; #endif /* CONFIG_NET_STATISTICS_ETHERNET */ -#if defined(CONFIG_NRF70_STA_MODE) || defined(CONFIG_NRF70_RAW_DATA_RX) - bool authorized; -#endif #ifdef CONFIG_NRF70_STA_MODE unsigned int assoc_freq; enum nrf_wifi_fmac_if_carr_state if_carr_state; diff --git a/drivers/wifi/nrf_wifi/inc/wpa_supp_if.h b/drivers/wifi/nrf_wifi/inc/wpa_supp_if.h index c543644e3128..321705308d1a 100644 --- a/drivers/wifi/nrf_wifi/inc/wpa_supp_if.h +++ b/drivers/wifi/nrf_wifi/inc/wpa_supp_if.h @@ -123,8 +123,18 @@ int nrf_wifi_supp_get_conn_info(void *if_priv, struct wpa_conn_info *info); void nrf_wifi_supp_event_proc_get_conn_info(void *os_vif_ctx, struct nrf_wifi_umac_event_conn_info *info, unsigned int event_len); +void nrf_wifi_supp_event_remain_on_channel(void *os_vif_ctx, + struct nrf_wifi_event_remain_on_channel *info, + unsigned int event_len); +void nrf_wifi_supp_event_roc_cancel_complete(void *os_vif_ctx, + struct nrf_wifi_event_remain_on_channel *info, + unsigned int event_len); int nrf_wifi_supp_set_country(void *if_priv, const char *alpha2); int nrf_wifi_supp_get_country(void *if_priv, char *alpha2); +int nrf_wifi_supp_remain_on_channel(void *if_priv, unsigned int freq, + unsigned int duration, u64 host_cookie); +int nrf_wifi_supp_cancel_remain_on_channel(void *if_priv, u64 rpu_cookie); +int nrf_wifi_supp_set_p2p_powersave(void *if_priv, int legacy_ps, int opp_ps, int ctwindow); #endif /* CONFIG_NRF70_STA_MODE */ #ifdef CONFIG_NRF70_AP_MODE diff --git a/drivers/wifi/nrf_wifi/src/fmac_main.c b/drivers/wifi/nrf_wifi/src/fmac_main.c index 47ca53d5a61c..9e8ae2aafb93 100644 --- a/drivers/wifi/nrf_wifi/src/fmac_main.c +++ b/drivers/wifi/nrf_wifi/src/fmac_main.c @@ -452,6 +452,11 @@ void nrf_wifi_event_proc_cookie_rsp(void *vif_ctx, /* TODO: When supp_callbk_fns.mgmt_tx_status is implemented, add logic * here to use the cookie and host_cookie to map requests to responses. */ + if (vif_ctx_zep->supp_drv_if_ctx && + vif_ctx_zep->supp_callbk_fns.cookie_event) { + vif_ctx_zep->supp_callbk_fns.cookie_event(vif_ctx_zep->supp_drv_if_ctx, + cookie_rsp_event->host_cookie, cookie_rsp_event->cookie); + } } #endif /* CONFIG_NRF70_STA_MODE */ @@ -843,6 +848,8 @@ static int nrf_wifi_drv_main_zep(const struct device *dev) callbk_fns.event_get_wiphy = nrf_wifi_wpa_supp_event_get_wiphy; callbk_fns.mgmt_rx_callbk_fn = nrf_wifi_wpa_supp_event_mgmt_rx_callbk_fn; callbk_fns.get_conn_info_callbk_fn = nrf_wifi_supp_event_proc_get_conn_info; + callbk_fns.roc_callbk_fn = nrf_wifi_supp_event_remain_on_channel; + callbk_fns.roc_cancel_callbk_fn = nrf_wifi_supp_event_roc_cancel_complete; #endif /* CONFIG_NRF70_STA_MODE */ /* The OSAL layer needs to be initialized before any other initialization @@ -963,6 +970,9 @@ static const struct zep_wpa_supp_dev_ops wpa_supp_ops = { .get_conn_info = nrf_wifi_supp_get_conn_info, .set_country = nrf_wifi_supp_set_country, .get_country = nrf_wifi_supp_get_country, + .remain_on_channel = nrf_wifi_supp_remain_on_channel, + .cancel_remain_on_channel = nrf_wifi_supp_cancel_remain_on_channel, + .set_p2p_powersave = nrf_wifi_supp_set_p2p_powersave, #ifdef CONFIG_NRF70_AP_MODE .init_ap = nrf_wifi_wpa_supp_init_ap, .start_ap = nrf_wifi_wpa_supp_start_ap, diff --git a/drivers/wifi/nrf_wifi/src/net_if.c b/drivers/wifi/nrf_wifi/src/net_if.c index 0662c6c80d09..1e85c2e77626 100644 --- a/drivers/wifi/nrf_wifi/src/net_if.c +++ b/drivers/wifi/nrf_wifi/src/net_if.c @@ -25,6 +25,7 @@ LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL); #include "util.h" #include "common/fmac_util.h" +#include "system/fmac_peer.h" #include "shim.h" #include "fmac_main.h" #include "wpa_supp_if.h" @@ -388,6 +389,8 @@ int nrf_wifi_if_send(const struct device *dev, struct rpu_host_stats *host_stats = NULL; void *nbuf = NULL; bool locked = false; + unsigned char *ra = NULL; + int peer_id = -1; if (!dev || !pkt) { LOG_ERR("%s: vif_ctx_zep is NULL", __func__); @@ -436,12 +439,20 @@ int nrf_wifi_if_send(const struct device *dev, nbuf); } else { #endif /* CONFIG_NRF70_RAW_DATA_TX */ + + ra = nrf_wifi_util_get_ra(sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx], nbuf); + peer_id = nrf_wifi_fmac_peer_get_id(rpu_ctx_zep->rpu_ctx, ra); + if (peer_id == -1) { + nrf_wifi_osal_log_dbg("%s: Invalid peer", + __func__); + goto out; + } + if ((vif_ctx_zep->if_carr_state != NRF_WIFI_FMAC_IF_CARR_STATE_ON) || - (!vif_ctx_zep->authorized && !is_eapol(pkt))) { + (!sys_dev_ctx->tx_config.peers[peer_id].authorized && !is_eapol(pkt))) { ret = -EPERM; goto drop; } - ret = nrf_wifi_fmac_start_xmit(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, nbuf); diff --git a/drivers/wifi/nrf_wifi/src/wifi_mgmt.c b/drivers/wifi/nrf_wifi/src/wifi_mgmt.c index 6bb31241b295..4c98ef0d8aa0 100644 --- a/drivers/wifi/nrf_wifi/src/wifi_mgmt.c +++ b/drivers/wifi/nrf_wifi/src/wifi_mgmt.c @@ -18,6 +18,7 @@ #include "system/fmac_api.h" #include "system/fmac_tx.h" #include "common/fmac_util.h" +#include "common/fmac_structs_common.h" #include "fmac_main.h" #include "wifi_mgmt.h" @@ -757,6 +758,8 @@ int nrf_wifi_mode(const struct device *dev, struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL; struct nrf_wifi_sys_fmac_dev_ctx *sys_dev_ctx = NULL; + struct peers_info *peer = NULL; + int i = 0; int ret = -1; if (!dev || !mode) { @@ -798,10 +801,16 @@ int nrf_wifi_mode(const struct device *dev, goto out; } - if (vif_ctx_zep->authorized && (mode->mode == NRF_WIFI_MONITOR_MODE)) { - LOG_ERR("%s: Cannot set monitor mode when station is connected", - __func__); - goto out; + for (i = 0; i < MAX_PEERS; i++) { + peer = &sys_dev_ctx->tx_config.peers[i]; + if (peer->peer_id == -1) { + continue; + } + if (peer->authorized && (mode->mode == NRF_WIFI_MONITOR_MODE)) { + LOG_ERR("%s: Cannot set monitor mode when station is connected", + __func__); + goto out; + } } /** @@ -851,6 +860,8 @@ int nrf_wifi_channel(const struct device *dev, struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; struct nrf_wifi_sys_fmac_dev_ctx *sys_dev_ctx = NULL; struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL; + struct peers_info *peer = NULL; + int i = 0; int ret = -1; if (!dev || !channel) { @@ -864,9 +875,16 @@ int nrf_wifi_channel(const struct device *dev, return ret; } - if (vif_ctx_zep->authorized) { - LOG_ERR("%s: Cannot change channel when in station connected mode", __func__); - return ret; + for (i = 0; i < MAX_PEERS; i++) { + peer = &sys_dev_ctx->tx_config.peers[i]; + if (peer->peer_id == -1) { + continue; + } + if (peer->authorized) { + LOG_ERR("%s: Cannot change channel when in station connected mode", + __func__); + return ret; + } } rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; diff --git a/drivers/wifi/nrf_wifi/src/wpa_supp_if.c b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c index 88ea9f9215b4..26893f2214e2 100644 --- a/drivers/wifi/nrf_wifi/src/wpa_supp_if.c +++ b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c @@ -17,6 +17,7 @@ #include "common/fmac_util.h" #include "wifi_mgmt.h" #include "wpa_supp_if.h" +#include LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL); @@ -545,19 +546,23 @@ int nrf_wifi_wpa_supp_scan2(void *if_priv, struct wpa_driver_scan_params *params scan_info->scan_params.num_scan_channels = indx; } - if (params->filter_ssids) { - scan_info->scan_params.num_scan_ssids = params->num_filter_ssids; + if (params->num_ssids) { + scan_info->scan_params.num_scan_ssids = params->num_ssids; - for (indx = 0; indx < params->num_filter_ssids; indx++) { + for (indx = 0; indx < params->num_ssids; indx++) { memcpy(scan_info->scan_params.scan_ssids[indx].nrf_wifi_ssid, - params->filter_ssids[indx].ssid, - params->filter_ssids[indx].ssid_len); + params->ssids[indx].ssid, + params->ssids[indx].ssid_len); scan_info->scan_params.scan_ssids[indx].nrf_wifi_ssid_len = - params->filter_ssids[indx].ssid_len; + params->ssids[indx].ssid_len; } } + if (params->p2p_probe) { + scan_info->scan_params.no_cck = 1; + } + scan_info->scan_reason = SCAN_CONNECT; /* Copy extra_ies */ @@ -1103,7 +1108,9 @@ int nrf_wifi_wpa_set_supp_port(void *if_priv, int authorized, char *bssid) struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; struct nrf_wifi_umac_chg_sta_info chg_sta_info; struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_sys_fmac_dev_ctx *sys_dev_ctx = NULL; enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + int peer_id = -1; int ret = -1; if (!if_priv || !bssid) { @@ -1134,8 +1141,6 @@ int nrf_wifi_wpa_set_supp_port(void *if_priv, int authorized, char *bssid) memcpy(chg_sta_info.mac_addr, bssid, ETH_ALEN); - vif_ctx_zep->authorized = authorized; - if (authorized) { /* BIT(NL80211_STA_FLAG_AUTHORIZED) */ chg_sta_info.sta_flags2.nrf_wifi_mask = 1 << 1; @@ -1153,6 +1158,19 @@ int nrf_wifi_wpa_set_supp_port(void *if_priv, int authorized, char *bssid) goto out; } + sys_dev_ctx = wifi_dev_priv(rpu_ctx_zep->rpu_ctx); + + peer_id = nrf_wifi_fmac_peer_get_id(rpu_ctx_zep->rpu_ctx, chg_sta_info.mac_addr); + if (peer_id == -1) { + nrf_wifi_osal_log_err("%s: Invalid peer", + __func__); + goto out; + } + + if (chg_sta_info.sta_flags2.nrf_wifi_set & NRF_WIFI_STA_FLAG_AUTHORIZED) { + sys_dev_ctx->tx_config.peers[peer_id].authorized = true; + } + ret = 0; out: k_mutex_unlock(&vif_ctx_zep->vif_lock); @@ -1435,6 +1453,10 @@ int nrf_wifi_nl80211_send_mlme(void *if_priv, const u8 *data, goto out; } + if (vif_ctx_zep->if_type == NRF_WIFI_IFTYPE_STATION) { + offchanok = 1; + } + if (offchanok) { mgmt_tx_info->nrf_wifi_flags |= NRF_WIFI_CMD_FRAME_OFFCHANNEL_TX_OK; } @@ -1698,7 +1720,7 @@ int nrf_wifi_supp_register_frame(void *if_priv, struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; struct nrf_wifi_umac_mgmt_frame_info frame_info; - if (!if_priv || !match || !match_len) { + if (!if_priv) { LOG_ERR("%s: Invalid parameters", __func__); return -1; } @@ -1719,8 +1741,14 @@ int nrf_wifi_supp_register_frame(void *if_priv, memset(&frame_info, 0, sizeof(frame_info)); frame_info.frame_type = type; - frame_info.frame_match.frame_match_len = match_len; - memcpy(frame_info.frame_match.frame_match, match, match_len); + if (match_len > 0) { + if (!match) { + LOG_ERR("%s: Invalid match parameters", __func__); + goto out; + } + frame_info.frame_match.frame_match_len = match_len; + memcpy(frame_info.frame_match.frame_match, match, match_len); + } status = nrf_wifi_sys_fmac_register_frame(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, &frame_info); @@ -1798,6 +1826,9 @@ int nrf_wifi_supp_get_capa(void *if_priv, struct wpa_driver_capa *capa) if (IS_ENABLED(CONFIG_NRF70_AP_MODE)) { capa->flags |= WPA_DRIVER_FLAGS_AP; } + if (IS_ENABLED(CONFIG_NRF70_P2P_MODE)) { + capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE; + } capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 | @@ -1983,6 +2014,193 @@ void nrf_wifi_supp_event_proc_get_conn_info(void *if_priv, k_sem_give(&wait_for_event_sem); } +void nrf_wifi_supp_event_remain_on_channel(void *if_priv, + struct nrf_wifi_event_remain_on_channel *roc_complete, + unsigned int event_len) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + + if (!if_priv) { + LOG_ERR("%s: Missing interface context", __func__); + return; + } + + vif_ctx_zep = if_priv; + + if (!roc_complete) { + LOG_ERR("%s: Missing ROC complete event data", __func__); + return; + } + + LOG_DBG("%s: ROC complete on freq %d, dur %d, vif_idx %d", + __func__, roc_complete->frequency, + roc_complete->dur, vif_ctx_zep->vif_idx); + + if (vif_ctx_zep->supp_drv_if_ctx && vif_ctx_zep->supp_callbk_fns.roc_complete) { + vif_ctx_zep->supp_callbk_fns.roc_complete(vif_ctx_zep->supp_drv_if_ctx, + roc_complete->frequency, + roc_complete->dur, roc_complete->cookie); + } +} + +void nrf_wifi_supp_event_roc_cancel_complete(void *if_priv, + struct nrf_wifi_event_remain_on_channel + *roc_cancel_complete, + unsigned int event_len) +{ + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + + if (!if_priv) { + LOG_ERR("%s: Missing interface context", __func__); + return; + } + + vif_ctx_zep = if_priv; + + if (!roc_cancel_complete) { + LOG_ERR("%s: Missing ROC cancel complete event data", __func__); + return; + } + + LOG_DBG("%s: ROC cancel complete on freq %d, vif_idx %d", + __func__, roc_cancel_complete->frequency, + vif_ctx_zep->vif_idx); + + if (vif_ctx_zep->supp_drv_if_ctx && vif_ctx_zep->supp_callbk_fns.roc_cancel_complete) { + vif_ctx_zep->supp_callbk_fns.roc_cancel_complete(vif_ctx_zep->supp_drv_if_ctx, + roc_cancel_complete->frequency, roc_cancel_complete->cookie); + } +} + +int nrf_wifi_supp_remain_on_channel(void *if_priv, unsigned int freq, + unsigned int duration, u64 host_cookie) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; +#ifdef NRF70_P2P_MODE + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct remain_on_channel_info roc_info; + + if (!if_priv) { + LOG_ERR("%s: Invalid params", __func__); + return -1; + } + + vif_ctx_zep = if_priv; + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep) { + LOG_ERR("%s: rpu_ctx_zep is NULL", __func__); + return -1; + } + + k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER); + if (!rpu_ctx_zep->rpu_ctx) { + LOG_DBG("%s: RPU context not initialized", __func__); + goto out; + } + + memset(&roc_info, 0, sizeof(roc_info)); + roc_info.nrf_wifi_freq_params.frequency = freq; + roc_info.nrf_wifi_freq_params.channel_width = NRF_WIFI_CHAN_WIDTH_20; + roc_info.nrf_wifi_freq_params.center_frequency1 = freq; + roc_info.nrf_wifi_freq_params.center_frequency2 = 0; + roc_info.nrf_wifi_freq_params.channel_type = NRF_WIFI_CHAN_HT20; + roc_info.dur = duration; + roc_info.host_cookie = host_cookie; + + status = nrf_wifi_sys_fmac_p2p_roc_start(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, + &roc_info); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_remain_on_channel failed", __func__); + goto out; + } +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); +#endif /* NRF70_P2P_MODE */ + return status; +} + +int nrf_wifi_supp_cancel_remain_on_channel(void *if_priv, u64 cookie) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; +#ifdef NRF70_P2P_MODE + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + + if (!if_priv) { + LOG_ERR("%s: Invalid params", __func__); + return -1; + } + + vif_ctx_zep = if_priv; + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep) { + LOG_ERR("%s: rpu_ctx_zep is NULL", __func__); + return -1; + } + + k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER); + if (!rpu_ctx_zep->rpu_ctx) { + LOG_DBG("%s: RPU context not initialized", __func__); + goto out; + } + + status = nrf_wifi_sys_fmac_p2p_roc_stop(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, cookie); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_cancel_remain_on_channel failed", __func__); + goto out; + } +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); +#endif /* NRF70_P2P_MODE */ + return status; +} + +int nrf_wifi_supp_set_p2p_powersave(void *if_priv, int legacy_ps, int opp_ps, int ctwindow) +{ + enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; +#ifdef NRF70_P2P_MODE + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + + if (!if_priv) { + LOG_ERR("%s: Invalid params", __func__); + return -1; + } + vif_ctx_zep = if_priv; + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + if (!rpu_ctx_zep) { + LOG_ERR("%s: rpu_ctx_zep is NULL", __func__); + return -1; + } + k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER); + if (!rpu_ctx_zep->rpu_ctx) { + LOG_DBG("%s: RPU context not initialized", __func__); + goto out; + } + + if (legacy_ps == -1) { + status = 0; + goto out; + } + + if (legacy_ps != 0 && legacy_ps != 1) { + LOG_ERR("%s: Invalid legacy_ps value: %d", __func__, legacy_ps); + goto out; + } + + status = nrf_wifi_sys_fmac_set_power_save(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, + legacy_ps); + if (status != NRF_WIFI_STATUS_SUCCESS) { + LOG_ERR("%s: nrf_wifi_fmac_set_p2p_powersave failed", __func__); + goto out; + } +out: + k_mutex_unlock(&vif_ctx_zep->vif_lock); +#endif /* NRF70_P2P_MODE */ + return status; +} + #ifdef CONFIG_NRF70_AP_MODE static int nrf_wifi_vif_state_change(struct nrf_wifi_vif_ctx_zep *vif_ctx_zep, enum nrf_wifi_fmac_if_op_state state) @@ -2785,7 +3003,9 @@ int nrf_wifi_wpa_supp_sta_set_flags(void *if_priv, const u8 *addr, struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; struct nrf_wifi_umac_chg_sta_info chg_sta = {0}; struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_sys_fmac_dev_ctx *sys_dev_ctx = NULL; enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL; + int peer_id = -1; int ret = -1; if (!if_priv || !addr) { @@ -2820,6 +3040,19 @@ int nrf_wifi_wpa_supp_sta_set_flags(void *if_priv, const u8 *addr, goto out; } + sys_dev_ctx = wifi_dev_priv(rpu_ctx_zep->rpu_ctx); + + peer_id = nrf_wifi_fmac_peer_get_id(rpu_ctx_zep->rpu_ctx, chg_sta.mac_addr); + if (peer_id == -1) { + nrf_wifi_osal_log_err("%s: Invalid peer", + __func__); + goto out; + } + + if (chg_sta.sta_flags2.nrf_wifi_set & NRF_WIFI_STA_FLAG_AUTHORIZED) { + sys_dev_ctx->tx_config.peers[peer_id].authorized = true; + } + ret = 0; out: diff --git a/include/zephyr/net/socket_ncs.h b/include/zephyr/net/socket_ncs.h index 6a77d6c41f13..7c8bae645f6c 100644 --- a/include/zephyr/net/socket_ncs.h +++ b/include/zephyr/net/socket_ncs.h @@ -69,6 +69,27 @@ extern "C" { #define TLS_DTLS_HANDSHAKE_STATUS_FULL 0 #define TLS_DTLS_HANDSHAKE_STATUS_CACHED 1 +/** Socket option to enable the DTLS fragmentation extension. + * Accepted values for the option are: @ref DTLS_FRAG_EXT_DISABLED, + * @ref DTLS_FRAG_EXT_512_ENABLED, @ref DTLS_FRAG_EXT_1024_ENABLED. + */ +#define TLS_DTLS_FRAG_EXT (NET_SOCKET_NCS_BASE + 22) + +/** Disabled - The DTLS fragmentation extension is not included in the Client Hello. */ +#define DTLS_FRAG_EXT_DISABLED 0 +/** Enabled - The DTLS fragmentation extension is included in the Client Hello with the fragment + * size of 512 bytes. + * + * @note The user data size in send requests also becomes limited to a maximum of 512 bytes. + */ +#define DTLS_FRAG_EXT_512_ENABLED 1 +/** Enabled - The DTLS fragmentation extension is included in the Client Hello with the fragment + * size of 1024 bytes. + * + * @note The user data size in send requests also becomes limited to a maximum of 1024 bytes. + */ +#define DTLS_FRAG_EXT_1024_ENABLED 2 + /* NCS specific socket options */ /** sockopt: enable sending data as part of exceptional events */ diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 703f634209d2..434e27941965 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -137,6 +137,10 @@ enum net_request_wifi_cmd { NET_REQUEST_WIFI_CMD_AP_WPS_CONFIG, /** Configure BSS maximum idle period */ NET_REQUEST_WIFI_CMD_BSS_MAX_IDLE_PERIOD, + /** Configure background scanning */ + NET_REQUEST_WIFI_CMD_BGSCAN, + /** Wi-Fi Direct (P2P) operations*/ + NET_REQUEST_WIFI_CMD_P2P_OPER, /** @cond INTERNAL_HIDDEN */ NET_REQUEST_WIFI_CMD_MAX /** @endcond */ @@ -332,6 +336,16 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_NEIGHBOR_REP_COMPLETE); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_BSS_MAX_IDLE_PERIOD); +#define NET_REQUEST_WIFI_BGSCAN \ + (NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_BGSCAN) + +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_BGSCAN); + +#define NET_REQUEST_WIFI_P2P_OPER \ + (NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_P2P_OPER) + +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_P2P_OPER); + /** @cond INTERNAL_HIDDEN */ enum { @@ -352,7 +366,7 @@ enum { NET_EVENT_WIFI_CMD_AP_STA_CONNECTED_VAL, NET_EVENT_WIFI_CMD_AP_STA_DISCONNECTED_VAL, NET_EVENT_WIFI_CMD_SUPPLICANT_VAL, - + NET_EVENT_WIFI_CMD_P2P_DEVICE_FOUND_VAL, NET_EVENT_WIFI_CMD_MAX, }; @@ -399,6 +413,8 @@ enum net_event_wifi_cmd { NET_MGMT_CMD(NET_EVENT_WIFI_CMD_AP_STA_DISCONNECTED), /** Supplicant specific event */ NET_MGMT_CMD(NET_EVENT_WIFI_CMD_SUPPLICANT), + /** P2P device found */ + NET_MGMT_CMD(NET_EVENT_WIFI_CMD_P2P_DEVICE_FOUND), }; /** Event emitted for Wi-Fi scan result */ @@ -461,6 +477,51 @@ enum net_event_wifi_cmd { #define NET_EVENT_WIFI_AP_STA_DISCONNECTED \ (NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_STA_DISCONNECTED) +/** Event emitted for P2P device found event */ +#define NET_EVENT_WIFI_P2P_DEVICE_FOUND \ + (NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_P2P_DEVICE_FOUND) + +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P +/** Maximum length for P2P device name */ +#define WIFI_P2P_DEVICE_NAME_MAX_LEN 32 +/** Size of P2P primary device type (8 bytes) */ +#define WIFI_P2P_PRI_DEV_TYPE_SIZE 8 +/** Maximum length for P2P primary device type string */ +#define WIFI_P2P_PRI_DEV_TYPE_STR_MAX_LEN 32 +/** Maximum length for P2P WPS configuration methods string */ +#define WIFI_P2P_CONFIG_METHODS_STR_MAX_LEN 16 +/** Maximum length for P2P manufacturer name */ +#define WIFI_P2P_MANUFACTURER_MAX_LEN 64 +/** Maximum length for P2P model name */ +#define WIFI_P2P_MODEL_NAME_MAX_LEN 32 + +/** @brief Wi-Fi P2P device info */ +struct wifi_p2p_device_info { + /** Device MAC address */ + uint8_t mac[WIFI_MAC_ADDR_LEN]; + /** Device name (max 32 chars + null terminator) */ + char device_name[WIFI_P2P_DEVICE_NAME_MAX_LEN + 1]; + /** Primary device type */ + uint8_t pri_dev_type[WIFI_P2P_PRI_DEV_TYPE_SIZE]; + /** Primary device type string */ + char pri_dev_type_str[WIFI_P2P_PRI_DEV_TYPE_STR_MAX_LEN]; + /** Signal strength (RSSI) */ + int8_t rssi; + /** WPS configuration methods supported */ + uint16_t config_methods; + /** WPS configuration methods string */ + char config_methods_str[WIFI_P2P_CONFIG_METHODS_STR_MAX_LEN]; + /** Device capability */ + uint8_t dev_capab; + /** Group capability */ + uint8_t group_capab; + /** Manufacturer (max 64 chars + null terminator) */ + char manufacturer[WIFI_P2P_MANUFACTURER_MAX_LEN + 1]; + /** Model name (max 32 chars + null terminator) */ + char model_name[WIFI_P2P_MODEL_NAME_MAX_LEN + 1]; +}; +#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ + /** @brief Wi-Fi version */ struct wifi_version { /** Driver version */ @@ -1107,6 +1168,9 @@ union wifi_mgmt_events { #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ struct wifi_twt_params twt_params; struct wifi_ap_sta_info ap_sta_info; +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P + struct wifi_p2p_device_info p2p_device_info; +#endif }; /** @endcond */ @@ -1390,6 +1454,131 @@ struct wifi_wps_config_params { char pin[WIFI_WPS_PIN_MAX_LEN + 1]; }; +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P +/** Wi-Fi P2P operation */ +enum wifi_p2p_op { + /** P2P find/discovery */ + WIFI_P2P_FIND = 0, + /** P2P stop find/discovery */ + WIFI_P2P_STOP_FIND, + /** P2P query peer info use broadcast MAC (ff:ff:ff:ff:ff:ff) to list all peers, + * or specific MAC address to query a single peer + */ + WIFI_P2P_PEER, + /** P2P connect to peer */ + WIFI_P2P_CONNECT, + /** P2P group add */ + WIFI_P2P_GROUP_ADD, + /** P2P group remove */ + WIFI_P2P_GROUP_REMOVE, + /** P2P invite */ + WIFI_P2P_INVITE, + /** P2P power save */ + WIFI_P2P_POWER_SAVE, +}; + +/** Wi-Fi P2P discovery type */ +enum wifi_p2p_discovery_type { + /** Start with full scan, then only social channels */ + WIFI_P2P_FIND_START_WITH_FULL = 0, + /** Only social channels (1, 6, 11) */ + WIFI_P2P_FIND_ONLY_SOCIAL, + /** Progressive - scan through all channels one at a time */ + WIFI_P2P_FIND_PROGRESSIVE, +}; + +/** Wi-Fi P2P connection method */ +enum wifi_p2p_connection_method { + /** Push Button Configuration */ + WIFI_P2P_METHOD_PBC = 0, + /** Display PIN (device displays PIN for peer to enter) */ + WIFI_P2P_METHOD_DISPLAY, + /** Keypad PIN (user enters PIN on device) */ + WIFI_P2P_METHOD_KEYPAD, +}; + +/** Maximum number of P2P peers that can be returned in a single query */ +#define WIFI_P2P_MAX_PEERS CONFIG_WIFI_P2P_MAX_PEERS + +/** Wi-Fi P2P parameters */ +struct wifi_p2p_params { + /** P2P operation */ + enum wifi_p2p_op oper; + /** Discovery type (for find operation) */ + enum wifi_p2p_discovery_type discovery_type; + /** Timeout in seconds (0 = no timeout, run until stopped) */ + uint16_t timeout; + /** Peer device address (for peer operation) */ + uint8_t peer_addr[WIFI_MAC_ADDR_LEN]; + /** Flag to list only discovered peers (for peers operation) */ + bool discovered_only; + /** Pointer to array for peer info results */ + struct wifi_p2p_device_info *peers; + /** Actual number of peers returned */ + uint16_t peer_count; + /** Power save enabled (for power save operation) */ + bool power_save; + /** Connect specific parameters */ + struct { + /** Connection method */ + enum wifi_p2p_connection_method method; + /** PIN for display/keypad methods (8 digits) + * - For DISPLAY: Leave empty, PIN will be generated and returned + * - For KEYPAD: Provide the PIN to use for connection + */ + char pin[WIFI_WPS_PIN_MAX_LEN + 1]; + /** GO intent (0-15, higher values indicate higher willingness to be GO) */ + uint8_t go_intent; + /** Frequency in MHz (0 = not specified, use default) */ + unsigned int freq; + } connect; + /** Group add specific parameters */ + struct { + /** Frequency in MHz (0 = auto) */ + int freq; + /** Persistent group ID (-1 = not persistent) */ + int persistent; + /** Enable HT40 */ + bool ht40; + /** Enable VHT */ + bool vht; + /** Enable HE */ + bool he; + /** Enable EDMG */ + bool edmg; + /** GO BSSID (NULL = auto) */ + uint8_t go_bssid[WIFI_MAC_ADDR_LEN]; + /** GO BSSID length */ + uint8_t go_bssid_length; + } group_add; + /** Group remove specific parameters */ + struct { + /** Interface name (e.g., "wlan0") */ + char ifname[CONFIG_NET_INTERFACE_NAME_LEN + 1]; + } group_remove; + /** Invite specific parameters */ + struct { + /** Invite type: persistent or group */ + enum { + WIFI_P2P_INVITE_PERSISTENT = 0, + WIFI_P2P_INVITE_GROUP, + } type; + /** Persistent group ID (for persistent type) */ + int persistent_id; + /** Group interface name (for group type) */ + char group_ifname[CONFIG_NET_INTERFACE_NAME_LEN + 1]; + /** Peer MAC address */ + uint8_t peer_addr[WIFI_MAC_ADDR_LEN]; + /** Frequency in MHz (0 = auto) */ + int freq; + /** GO device address (for group type, NULL = auto) */ + uint8_t go_dev_addr[WIFI_MAC_ADDR_LEN]; + /** GO device address length */ + uint8_t go_dev_addr_length; + } invite; +}; +#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ + /** Wi-Fi AP status */ enum wifi_sap_iface_state { @@ -1403,6 +1592,32 @@ enum wifi_sap_iface_state { WIFI_SAP_IFACE_ENABLED }; +#if defined(CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN) || defined(__DOXYGEN__) +/** @brief Wi-Fi background scan implementation */ +enum wifi_bgscan_type { + /** None, background scan is disabled */ + WIFI_BGSCAN_NONE = 0, + /** Simple, periodic scan based on signal strength */ + WIFI_BGSCAN_SIMPLE, + /** Learn channels used by the network (experimental) */ + WIFI_BGSCAN_LEARN, +}; + +/** @brief Wi-Fi background scan parameters */ +struct wifi_bgscan_params { + /** The type of background scanning */ + enum wifi_bgscan_type type; + /** Short scan interval in seconds */ + uint16_t short_interval; + /** Long scan interval in seconds */ + uint16_t long_interval; + /** Signal strength threshold in dBm */ + int8_t rssi_threshold; + /** Number of BSS Transition Management (BTM) queries */ + uint16_t btm_queries; +}; +#endif + /* Extended Capabilities */ enum wifi_ext_capab { WIFI_EXT_CAPAB_20_40_COEX = 0, @@ -1742,6 +1957,27 @@ struct wifi_mgmt_ops { */ int (*set_bss_max_idle_period)(const struct device *dev, unsigned short bss_max_idle_period); +#if defined(CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN) || defined(__DOXYGEN__) + /** Configure background scanning + * + * @param dev Pointer to the device structure for the driver instance. + * @param params Background scanning configuration parameters + * + * @return 0 if ok, < 0 if error + */ + int (*set_bgscan)(const struct device *dev, struct wifi_bgscan_params *params); +#endif +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P + /** Wi-Fi Direct (P2P) operations for device discovery + * + * @param dev Pointer to the device structure for the driver instance. + * @param params P2P operation parameters including operation type, discovery settings, + * timeout values and peer information retrieval options + * + * @return 0 if ok, < 0 if error + */ + int (*p2p_oper)(const struct device *dev, struct wifi_p2p_params *params); +#endif }; /** Wi-Fi management offload API */ @@ -1873,6 +2109,17 @@ void wifi_mgmt_raise_ap_sta_connected_event(struct net_if *iface, void wifi_mgmt_raise_ap_sta_disconnected_event(struct net_if *iface, struct wifi_ap_sta_info *sta_info); +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P +/** + * @brief Raise P2P device found event + * + * @param iface Network interface + * @param device_info P2P device information + */ +void wifi_mgmt_raise_p2p_device_found_event(struct net_if *iface, + struct wifi_p2p_device_info *peer_info); +#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ + /** * @} */ diff --git a/include/zephyr/storage/flash_map.h b/include/zephyr/storage/flash_map.h index 9dc6bd91438f..558a0a0b7e72 100644 --- a/include/zephyr/storage/flash_map.h +++ b/include/zephyr/storage/flash_map.h @@ -19,7 +19,7 @@ * * @defgroup flash_area_api flash area Interface * @since 1.11 - * @version 1.0.0 + * @version 1.1.0 * @ingroup storage_apis * @{ */ @@ -469,6 +469,32 @@ uint8_t flash_area_erased_val(const struct flash_area *fa); (DT_MTD_FROM_FIXED_SUBPARTITION(node)), \ (DT_MTD_FROM_FIXED_PARTITION(node)))) +/** + * Get the node identifier of the flash controller the area/partition resides on + * + * @param label DTS node label of a partition + * + * @return Pointer to a device. + */ +#define FIXED_PARTITION_MTD(label) \ + COND_CODE_1( \ + DT_FIXED_SUBPARTITION_EXISTS(DT_NODELABEL(label)), \ + (DT_MTD_FROM_FIXED_SUBPARTITION(DT_NODELABEL(label))), \ + (DT_MTD_FROM_FIXED_PARTITION(DT_NODELABEL(label)))) + +/** + * Get the node identifier of the flash controller the area/partition resides on + * + * @param node DTS node of a partition + * + * @return Pointer to a device. + */ +#define FIXED_PARTITION_NODE_MTD(node) \ + COND_CODE_1( \ + DT_FIXED_SUBPARTITION_EXISTS(node), \ + (DT_MTD_FROM_FIXED_SUBPARTITION(node)), \ + (DT_MTD_FROM_FIXED_PARTITION(node))) + /** * Get pointer to flash_area object by partition label * diff --git a/modules/hostap/CMakeLists.txt b/modules/hostap/CMakeLists.txt index f3233bb2cfbb..42ccd291fb10 100644 --- a/modules/hostap/CMakeLists.txt +++ b/modules/hostap/CMakeLists.txt @@ -78,6 +78,16 @@ zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WNM CONFIG_WNM ) +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN + CONFIG_BGSCAN +) +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN_SIMPLE + CONFIG_BGSCAN_SIMPLE +) +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN_LEARN + CONFIG_BGSCAN_LEARN +) + zephyr_library_include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/src ${HOSTAP_BASE}/ @@ -156,6 +166,16 @@ zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WNM ${WIFI_NM_WPA_SUPPLICANT_BASE}/wnm_sta.c ) +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN + ${WIFI_NM_WPA_SUPPLICANT_BASE}/bgscan.c +) +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN_SIMPLE + ${WIFI_NM_WPA_SUPPLICANT_BASE}/bgscan_simple.c +) +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN_LEARN + ${WIFI_NM_WPA_SUPPLICANT_BASE}/bgscan_learn.c +) + zephyr_library_sources_ifdef(CONFIG_WPA_CLI src/wpa_cli.c ) @@ -363,16 +383,11 @@ zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPS ${HOSTAP_SRC_BASE}/wps/wps_enrollee.c ${HOSTAP_SRC_BASE}/wps/wps_registrar.c ${HOSTAP_SRC_BASE}/crypto/dh_groups.c + ${HOSTAP_SRC_BASE}/eap_server/eap_server_wsc.c + ${HOSTAP_SRC_BASE}/eap_server/eap_server.c + ${HOSTAP_SRC_BASE}/eap_server/eap_server_methods.c ) -if(NOT CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ALT) -# dh_group5 is only needed if we are not using mbedtls, as mbedtls provides -# its own definition -zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPS - ${HOSTAP_SRC_BASE}/crypto/dh_group5.c -) -endif() - zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P CONFIG_P2P CONFIG_GAS @@ -382,6 +397,7 @@ zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPS CONFIG_WPS EAP_WSC + EAP_SERVER_WSC ) zephyr_library_sources_ifdef(CONFIG_WIFI_NM_HOSTAPD_WPS diff --git a/modules/hostap/Kconfig b/modules/hostap/Kconfig index 7799239a2840..ec8263d85a6b 100644 --- a/modules/hostap/Kconfig +++ b/modules/hostap/Kconfig @@ -46,6 +46,7 @@ config HEAP_MEM_POOL_ADD_SIZE_HOSTAP def_int 66560 if WIFI_NM_HOSTAPD_AP def_int 55000 if WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE && WIFI_CREDENTIALS def_int 48000 if WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE + def_int 80000 if WIFI_NM_WPA_SUPPLICANT_P2P def_int 41808 if WIFI_NM_WPA_SUPPLICANT_AP # 30K is mandatory, but might need more for long duration use cases def_int 30000 @@ -54,6 +55,7 @@ endif # WIFI_NM_WPA_SUPPLICANT_GLOBAL_HEAP config WIFI_NM_WPA_SUPPLICANT_THREAD_STACK_SIZE int "Stack size for wpa_supplicant thread" + default 10000 if WIFI_NM_WPA_SUPPLICANT_P2P # TODO: Providing higher stack size for Enterprise mode to fix stack # overflow issues. Need to identify the cause for higher stack usage. default 8192 if WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE @@ -451,6 +453,27 @@ config WIFI_NM_WPA_SUPPLICANT_SKIP_DHCP_ON_ROAMING needs to get new IP address after roaming to new AP. Disable this to keep DHCP after roaming. +config WIFI_NM_WPA_SUPPLICANT_BGSCAN + bool "Background scanning (for legacy roaming), recommended if 802.11r is not supported" + depends on WIFI_NM_WPA_SUPPLICANT_WNM + depends on !WIFI_NM_WPA_SUPPLICANT_ROAMING + +if WIFI_NM_WPA_SUPPLICANT_BGSCAN + +config WIFI_NM_WPA_SUPPLICANT_BGSCAN_SIMPLE + bool "Simple background scanning" + default y + help + Periodic background scans based on signal strength. + +config WIFI_NM_WPA_SUPPLICANT_BGSCAN_LEARN + bool "Learning" + help + Learn channels used by the network and try to avoid + background scans on other channels (experimental). + +endif # WIFI_NM_WPA_SUPPLICANT_BGSCAN + # Create hidden config options that are used in hostap. This way we do not need # to mark them as allowed for CI checks, and also someone else cannot use the # same name options. @@ -482,6 +505,15 @@ config NO_RANDOM_POOL config WNM bool +config BGSCAN + bool + +config BGSCAN_SIMPLE + bool + +config BGSCAN_LEARN + bool + config NO_WPA bool default y if WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c index 1b3f19b4c1c1..04c9b7d81e01 100644 --- a/modules/hostap/src/supp_api.c +++ b/modules/hostap/src/supp_api.c @@ -60,6 +60,14 @@ enum status_thread_state { static struct wifi_enterprise_creds_params enterprise_creds; #endif +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P +#define P2P_CMD_BUF_SIZE 128 +#define P2P_RESP_BUF_SIZE 64 +#define P2P_PEER_INFO_SIZE 512 +#define P2P_ADDR_SIZE 32 +#define P2P_CMD_SIZE 64 +#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ + K_MUTEX_DEFINE(wpa_supplicant_mutex); extern struct k_work_q *get_workq(void); @@ -1916,6 +1924,71 @@ int supplicant_set_bss_max_idle_period(const struct device *dev, return wifi_mgmt_api->set_bss_max_idle_period(dev, bss_max_idle_period); } +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN +int supplicant_set_bgscan(const struct device *dev, struct wifi_bgscan_params *params) +{ + struct wpa_supplicant *wpa_s; + struct wpa_ssid *ssid; + int ret = -1; + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + wpa_s = get_wpa_s_handle(dev); + if (wpa_s == NULL) { + wpa_printf(MSG_ERROR, "Interface %s not found", dev->name); + goto out; + } + + ssid = wpa_s->current_ssid; + if (ssid == NULL) { + wpa_printf(MSG_ERROR, "SSID for %s not found", dev->name); + goto out; + } + + switch (params->type) { + case WIFI_BGSCAN_SIMPLE: + if (!IS_ENABLED(CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN_SIMPLE)) { + wpa_printf(MSG_ERROR, "Invalid bgscan type, enable " + "CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN_SIMPLE"); + ret = -ENOTSUP; + goto out; + } + if (!wpa_cli_cmd_v("set_network %d bgscan \"simple:%d:%d:%d:%d\"", ssid->id, + params->short_interval, params->rssi_threshold, + params->long_interval, params->btm_queries)) { + goto out; + } + break; + case WIFI_BGSCAN_LEARN: + if (!IS_ENABLED(CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN_LEARN)) { + wpa_printf(MSG_ERROR, "Invalid bgscan type, enable " + "CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN_LEARN"); + ret = -ENOTSUP; + goto out; + } + if (!wpa_cli_cmd_v("set_network %d bgscan \"learn:%d:%d:%d\"", ssid->id, + params->short_interval, params->rssi_threshold, + params->long_interval)) { + goto out; + } + break; + case WIFI_BGSCAN_NONE: + default: + if (!wpa_cli_cmd_v("set_network %d bgscan \"\"", ssid->id)) { + goto out; + } + break; + } + + ret = 0; + +out: + k_mutex_unlock(&wpa_supplicant_mutex); + + return ret; +} +#endif + #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_WNM int supplicant_btm_query(const struct device *dev, uint8_t reason) { @@ -2511,3 +2584,485 @@ int supplicant_config_params(const struct device *dev, struct wifi_config_params k_mutex_unlock(&wpa_supplicant_mutex); return ret; } + +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P +static inline void extract_value(const char *src, char *dest, size_t dest_size) +{ + size_t i = 0; + + while (src[i] != '\0' && src[i] != '\n' && i < dest_size - 1) { + dest[i] = src[i]; + i++; + } + dest[i] = '\0'; +} + +static void parse_peer_info_line(const char *line, struct wifi_p2p_device_info *info) +{ + const char *pos; + + if (strncmp(line, "device_name=", 12) == 0) { + extract_value(line + 12, info->device_name, sizeof(info->device_name)); + } else if (strncmp(line, "pri_dev_type=", 13) == 0) { + extract_value(line + 13, info->pri_dev_type_str, sizeof(info->pri_dev_type_str)); + } else if (strncmp(line, "level=", 6) == 0) { + char *endptr; + long val; + + pos = line + 6; + val = strtol(pos, &endptr, 10); + if (endptr != pos && val >= INT8_MIN && val <= INT8_MAX) { + info->rssi = (int8_t)val; + } + } else if (strncmp(line, "config_methods=", 15) == 0) { + char *endptr; + long val; + + pos = line + 15; + extract_value(pos, info->config_methods_str, sizeof(info->config_methods_str)); + + if (pos[0] == '0' && (pos[1] == 'x' || pos[1] == 'X')) { + val = strtol(pos, &endptr, 16); + } else { + val = strtol(pos, &endptr, 10); + } + if (endptr != pos && val >= 0 && val <= UINT16_MAX) { + info->config_methods = (uint16_t)val; + } + } else if (strncmp(line, "manufacturer=", 13) == 0) { + extract_value(line + 13, info->manufacturer, sizeof(info->manufacturer)); + } else if (strncmp(line, "model_name=", 11) == 0) { + extract_value(line + 11, info->model_name, sizeof(info->model_name)); + } +} + +static void parse_peer_info_response(const char *resp, const uint8_t *mac, + struct wifi_p2p_device_info *info) +{ + const char *line = resp; + const char *next_line; + + memset(info, 0, sizeof(*info)); + + if (mac) { + memcpy(info->mac, mac, WIFI_MAC_ADDR_LEN); + } + + while (line && *line) { + if (*line == '\n') { + line++; + continue; + } + next_line = strchr(line, '\n'); + parse_peer_info_line(line, info); + if (next_line) { + line = next_line + 1; + } else { + break; + } + } +} + +int supplicant_p2p_oper(const struct device *dev, struct wifi_p2p_params *params) +{ + struct wpa_supplicant *wpa_s = get_wpa_s_handle(dev); + char cmd_buf[P2P_CMD_BUF_SIZE]; + char resp_buf[P2P_RESP_BUF_SIZE]; + int ret = -1; + const char *discovery_type_str = ""; + + if (!wpa_s || !wpa_s->ctrl_conn) { + wpa_printf(MSG_ERROR, "wpa_supplicant control interface not initialized"); + return -ENOTSUP; + } + + switch (params->oper) { + case WIFI_P2P_FIND: + switch (params->discovery_type) { + case WIFI_P2P_FIND_ONLY_SOCIAL: + discovery_type_str = "type=social"; + break; + case WIFI_P2P_FIND_PROGRESSIVE: + discovery_type_str = "type=progressive"; + break; + case WIFI_P2P_FIND_START_WITH_FULL: + default: + discovery_type_str = ""; + break; + } + + if (params->timeout > 0) { + if (strlen(discovery_type_str) > 0) { + snprintk(cmd_buf, sizeof(cmd_buf), "P2P_FIND %u %s", + params->timeout, discovery_type_str); + } else { + snprintk(cmd_buf, sizeof(cmd_buf), "P2P_FIND %u", + params->timeout); + } + } else { + if (strlen(discovery_type_str) > 0) { + snprintk(cmd_buf, sizeof(cmd_buf), "P2P_FIND %s", + discovery_type_str); + } else { + snprintk(cmd_buf, sizeof(cmd_buf), "P2P_FIND"); + } + } + ret = zephyr_wpa_cli_cmd_resp_noprint(wpa_s->ctrl_conn, cmd_buf, resp_buf); + if (ret < 0) { + wpa_printf(MSG_ERROR, "P2P_FIND command failed: %d", ret); + return -EIO; + } + ret = 0; + break; + + case WIFI_P2P_STOP_FIND: + snprintk(cmd_buf, sizeof(cmd_buf), "P2P_STOP_FIND"); + ret = zephyr_wpa_cli_cmd_resp_noprint(wpa_s->ctrl_conn, cmd_buf, resp_buf); + if (ret < 0) { + wpa_printf(MSG_ERROR, "P2P_STOP_FIND command failed: %d", ret); + return -EIO; + } + ret = 0; + break; + + case WIFI_P2P_PEER: { + char addr[P2P_ADDR_SIZE]; + char cmd[P2P_CMD_SIZE]; + char peer_info[P2P_PEER_INFO_SIZE]; + char *pos; + size_t len; + uint16_t peer_idx = 0; + uint8_t mac[WIFI_MAC_ADDR_LEN]; + struct net_eth_addr peer_mac; + bool query_all_peers; + + if (!params->peers) { + wpa_printf(MSG_ERROR, "Peer info array not provided"); + return -EINVAL; + } + + memcpy(&peer_mac, params->peer_addr, WIFI_MAC_ADDR_LEN); + query_all_peers = net_eth_is_addr_broadcast(&peer_mac); + + if (query_all_peers) { + os_strlcpy(cmd_buf, "P2P_PEER FIRST", sizeof(cmd_buf)); + + while (peer_idx < params->peer_count) { + ret = zephyr_wpa_cli_cmd_resp_noprint(wpa_s->ctrl_conn, + cmd_buf, resp_buf); + + if (ret < 0 || resp_buf[0] == '\0' || + os_strncmp(resp_buf, "FAIL", 4) == 0) { + if (peer_idx == 0) { + wpa_printf(MSG_DEBUG, "No P2P peers found"); + } + break; + } + + len = 0; + pos = resp_buf; + while (*pos != '\0' && *pos != '\n' && len < sizeof(addr) - 1) { + addr[len++] = *pos++; + } + addr[len] = '\0'; + + if (os_strncmp(addr, "00:00:00:00:00:00", 17) != 0 && + sscanf(addr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &mac[0], &mac[1], &mac[2], + &mac[3], &mac[4], &mac[5]) == + WIFI_MAC_ADDR_LEN) { + + os_snprintf(cmd, sizeof(cmd), "P2P_PEER %s", addr); + ret = zephyr_wpa_cli_cmd_resp_noprint( + wpa_s->ctrl_conn, cmd, peer_info); + + if (ret >= 0 && + (!params->discovered_only || + os_strstr(peer_info, + "[PROBE_REQ_ONLY]") == NULL)) { + parse_peer_info_response(peer_info, + mac, + ¶ms->peers[peer_idx]); + peer_idx++; + } + } + os_snprintf(cmd_buf, sizeof(cmd_buf), "P2P_PEER NEXT-%s", addr); + } + params->peer_count = peer_idx; + } else { + char addr_str[18]; + + if (params->peer_count < 1) { + wpa_printf(MSG_ERROR, "Peer count must be at least 1"); + return -EINVAL; + } + + snprintk(addr_str, sizeof(addr_str), "%02x:%02x:%02x:%02x:%02x:%02x", + params->peer_addr[0], params->peer_addr[1], params->peer_addr[2], + params->peer_addr[3], params->peer_addr[4], params->peer_addr[5]); + snprintk(cmd_buf, sizeof(cmd_buf), "P2P_PEER %s", addr_str); + + /* Use peer_info buffer for single peer query to avoid large resp_buf */ + ret = zephyr_wpa_cli_cmd_resp_noprint(wpa_s->ctrl_conn, + cmd_buf, peer_info); + if (ret < 0) { + wpa_printf(MSG_ERROR, "P2P_PEER command failed: %d", ret); + return -EIO; + } + if (os_strncmp(peer_info, "FAIL", 4) == 0) { + wpa_printf(MSG_ERROR, "Peer %s not found", addr_str); + return -ENODEV; + } + parse_peer_info_response(peer_info, params->peer_addr, + ¶ms->peers[0]); + params->peer_count = 1; + } + ret = 0; + break; + } + + case WIFI_P2P_CONNECT: { + char addr_str[18]; + const char *method_str = ""; + char freq_str[32] = ""; + + if (!params) { + wpa_printf(MSG_ERROR, "P2P connect params are NULL"); + return -EINVAL; + } + + snprintk(addr_str, sizeof(addr_str), "%02x:%02x:%02x:%02x:%02x:%02x", + params->peer_addr[0], params->peer_addr[1], params->peer_addr[2], + params->peer_addr[3], params->peer_addr[4], params->peer_addr[5]); + + /* Add frequency parameter if specified */ + if (params->connect.freq > 0) { + snprintk(freq_str, sizeof(freq_str), " freq=%u", params->connect.freq); + } + + switch (params->connect.method) { + case WIFI_P2P_METHOD_PBC: + method_str = "pbc"; + snprintk(cmd_buf, sizeof(cmd_buf), "P2P_CONNECT %s %s go_intent=%d%s", + addr_str, method_str, params->connect.go_intent, freq_str); + break; + case WIFI_P2P_METHOD_DISPLAY: + method_str = "pin"; + snprintk(cmd_buf, sizeof(cmd_buf), "P2P_CONNECT %s %s go_intent=%d%s", + addr_str, method_str, params->connect.go_intent, freq_str); + break; + case WIFI_P2P_METHOD_KEYPAD: + method_str = "keypad"; + if (params->connect.pin[0] == '\0') { + wpa_printf(MSG_ERROR, "PIN required for keypad method"); + return -EINVAL; + } + snprintk(cmd_buf, sizeof(cmd_buf), "P2P_CONNECT %s %s %s go_intent=%d%s", + addr_str, method_str, params->connect.pin, + params->connect.go_intent, freq_str); + break; + default: + wpa_printf(MSG_ERROR, "Unknown P2P connection method: %d", + params->connect.method); + return -EINVAL; + } + + ret = zephyr_wpa_cli_cmd_resp_noprint(wpa_s->ctrl_conn, cmd_buf, resp_buf); + if (ret < 0) { + wpa_printf(MSG_ERROR, "P2P_CONNECT command failed: %d", ret); + return -EIO; + } + if (os_strncmp(resp_buf, "FAIL", 4) == 0) { + wpa_printf(MSG_ERROR, "P2P connect failed: %s", resp_buf); + return -ENODEV; + } + + /* For DISPLAY method, capture the generated PIN from response */ + if (params->connect.method == WIFI_P2P_METHOD_DISPLAY) { + size_t len = 0; + char *pos = resp_buf; + + while (*pos == ' ' || *pos == '\t' || *pos == '\n') { + pos++; + } + + while (*pos != '\0' && *pos != '\n' && *pos != ' ' && + len < WIFI_WPS_PIN_MAX_LEN) { + params->connect.pin[len++] = *pos++; + } + params->connect.pin[len] = '\0'; + + if (params->connect.pin[0] == '\0') { + wpa_printf(MSG_ERROR, "P2P connect: No PIN returned"); + return -ENODEV; + } + } + + ret = 0; + break; + } + + case WIFI_P2P_GROUP_ADD: { + int len = 0; + + if (!params) { + wpa_printf(MSG_ERROR, "P2P group add params are NULL"); + return -EINVAL; + } + + len = snprintk(cmd_buf, sizeof(cmd_buf), "P2P_GROUP_ADD"); + + if (params->group_add.freq > 0) { + len += snprintk(cmd_buf + len, sizeof(cmd_buf) - len, " freq=%d", + params->group_add.freq); + } + + if (params->group_add.persistent >= 0) { + len += snprintk(cmd_buf + len, sizeof(cmd_buf) - len, " persistent=%d", + params->group_add.persistent); + } + + if (params->group_add.ht40) { + len += snprintk(cmd_buf + len, sizeof(cmd_buf) - len, " ht40"); + } + + if (params->group_add.vht) { + len += snprintk(cmd_buf + len, sizeof(cmd_buf) - len, " vht"); + } + + if (params->group_add.he) { + len += snprintk(cmd_buf + len, sizeof(cmd_buf) - len, " he"); + } + + if (params->group_add.edmg) { + len += snprintk(cmd_buf + len, sizeof(cmd_buf) - len, " edmg"); + } + + if (params->group_add.go_bssid_length == WIFI_MAC_ADDR_LEN) { + len += snprintk(cmd_buf + len, sizeof(cmd_buf) - len, + " go_bssid=%02x:%02x:%02x:%02x:%02x:%02x", + params->group_add.go_bssid[0], + params->group_add.go_bssid[1], + params->group_add.go_bssid[2], + params->group_add.go_bssid[3], + params->group_add.go_bssid[4], + params->group_add.go_bssid[5]); + } + + ret = zephyr_wpa_cli_cmd_resp_noprint(wpa_s->ctrl_conn, cmd_buf, resp_buf); + if (ret < 0) { + wpa_printf(MSG_ERROR, "P2P_GROUP_ADD command failed: %d", ret); + return -EIO; + } + ret = 0; + break; + } + + case WIFI_P2P_GROUP_REMOVE: + if (!params) { + wpa_printf(MSG_ERROR, "P2P group remove params are NULL"); + return -EINVAL; + } + + if (params->group_remove.ifname[0] == '\0') { + wpa_printf(MSG_ERROR, "Interface name required for P2P_GROUP_REMOVE"); + return -EINVAL; + } + + snprintk(cmd_buf, sizeof(cmd_buf), "P2P_GROUP_REMOVE %s", + params->group_remove.ifname); + + ret = zephyr_wpa_cli_cmd_resp_noprint(wpa_s->ctrl_conn, cmd_buf, resp_buf); + if (ret < 0) { + wpa_printf(MSG_ERROR, "P2P_GROUP_REMOVE command failed: %d", ret); + return -EIO; + } + ret = 0; + break; + + case WIFI_P2P_INVITE: { + char addr_str[18]; + int len = 0; + + if (!params) { + wpa_printf(MSG_ERROR, "P2P invite params are NULL"); + return -EINVAL; + } + + snprintk(addr_str, sizeof(addr_str), "%02x:%02x:%02x:%02x:%02x:%02x", + params->invite.peer_addr[0], params->invite.peer_addr[1], + params->invite.peer_addr[2], params->invite.peer_addr[3], + params->invite.peer_addr[4], params->invite.peer_addr[5]); + + if (params->invite.type == WIFI_P2P_INVITE_PERSISTENT) { + if (params->invite.persistent_id < 0) { + wpa_printf(MSG_ERROR, "Persistent group ID required"); + return -EINVAL; + } + len = snprintk(cmd_buf, sizeof(cmd_buf), "P2P_INVITE persistent=%d peer=%s", + params->invite.persistent_id, addr_str); + + if (params->invite.freq > 0) { + len += snprintk(cmd_buf + len, sizeof(cmd_buf) - len, " freq=%d", + params->invite.freq); + } + } else if (params->invite.type == WIFI_P2P_INVITE_GROUP) { + if (params->invite.group_ifname[0] == '\0') { + wpa_printf(MSG_ERROR, "Group interface name required"); + return -EINVAL; + } + len = snprintk(cmd_buf, sizeof(cmd_buf), "P2P_INVITE group=%s peer=%s", + params->invite.group_ifname, addr_str); + + if (params->invite.freq > 0) { + len += snprintk(cmd_buf + len, sizeof(cmd_buf) - len, " freq=%d", + params->invite.freq); + } + + if (params->invite.go_dev_addr_length == WIFI_MAC_ADDR_LEN) { + len += snprintk(cmd_buf + len, sizeof(cmd_buf) - len, + " go_dev_addr=%02x:%02x:%02x:%02x:%02x:%02x", + params->invite.go_dev_addr[0], + params->invite.go_dev_addr[1], + params->invite.go_dev_addr[2], + params->invite.go_dev_addr[3], + params->invite.go_dev_addr[4], + params->invite.go_dev_addr[5]); + } + } else { + wpa_printf(MSG_ERROR, "Invalid invite type: %d", params->invite.type); + return -EINVAL; + } + + ret = zephyr_wpa_cli_cmd_resp_noprint(wpa_s->ctrl_conn, cmd_buf, resp_buf); + if (ret < 0) { + wpa_printf(MSG_ERROR, "P2P_INVITE command failed: %d", ret); + return -EIO; + } + ret = 0; + break; + } + + case WIFI_P2P_POWER_SAVE: + snprintk(cmd_buf, sizeof(cmd_buf), "p2p_set ps %d", params->power_save ? 1 : 0); + ret = zephyr_wpa_cli_cmd_resp_noprint(wpa_s->ctrl_conn, cmd_buf, resp_buf); + if (ret < 0) { + wpa_printf(MSG_ERROR, "p2p_set ps command failed: %d", ret); + return -EIO; + } + if (os_strncmp(resp_buf, "FAIL", 4) == 0) { + wpa_printf(MSG_ERROR, "p2p_set ps command returned FAIL"); + return -EIO; + } + ret = 0; + break; + + default: + wpa_printf(MSG_ERROR, "Unknown P2P operation: %d", params->oper); + ret = -EINVAL; + break; + } + + return ret; +} +#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ diff --git a/modules/hostap/src/supp_api.h b/modules/hostap/src/supp_api.h index 1ef63474f3fb..692db61bf277 100644 --- a/modules/hostap/src/supp_api.h +++ b/modules/hostap/src/supp_api.h @@ -321,6 +321,17 @@ int supplicant_wps_config(const struct device *dev, struct wifi_wps_config_param */ int supplicant_set_bss_max_idle_period(const struct device *dev, unsigned short bss_max_idle_period); + +#if defined(CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN) || defined(__DOXYGEN__) +/** @ Set Wi-Fi background scanning parameters + * + * @param dev Wi-Fi interface handle to use + * @param params bgscan parameters + * @return 0 for OK; -1 for ERROR + */ +int supplicant_set_bgscan(const struct device *dev, struct wifi_bgscan_params *params); +#endif + #ifdef CONFIG_AP int set_ap_bandwidth(const struct device *dev, enum wifi_frequency_bandwidths bandwidth); @@ -375,4 +386,16 @@ int supplicant_dpp_dispatch(const struct device *dev, struct wifi_dpp_params *pa * @return 0 for OK; -1 for ERROR */ int supplicant_config_params(const struct device *dev, struct wifi_config_params *params); + +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P +/** + * @brief P2P operation + * + * @param dev Wi-Fi interface handle to use + * @param params P2P parameters + * @return 0 for OK; -1 for ERROR + */ +int supplicant_p2p_oper(const struct device *dev, struct wifi_p2p_params *params); +#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ + #endif /* ZEPHYR_SUPP_MGMT_H */ diff --git a/modules/hostap/src/supp_events.c b/modules/hostap/src/supp_events.c index c4175a416bea..ee6a05a568ec 100644 --- a/modules/hostap/src/supp_events.c +++ b/modules/hostap/src/supp_events.c @@ -43,6 +43,9 @@ static const struct wpa_supp_event_info { { "CTRL-EVENT-NETWORK-REMOVED", SUPPLICANT_EVENT_NETWORK_REMOVED }, { "CTRL-EVENT-DSCP-POLICY", SUPPLICANT_EVENT_DSCP_POLICY }, { "CTRL-EVENT-REGDOM-CHANGE", SUPPLICANT_EVENT_REGDOM_CHANGE }, +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P + { "P2P-DEVICE-FOUND", SUPPLICANT_EVENT_P2P_DEVICE_FOUND }, +#endif }; static void copy_mac_addr(const unsigned int *src, uint8_t *dst) @@ -174,6 +177,43 @@ static int supplicant_process_status(struct supplicant_int_event_data *event_dat event_data->data_len = sizeof(data->bss_removed); copy_mac_addr(tmp_mac_addr, data->bss_removed.bssid); break; +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P + case SUPPLICANT_EVENT_P2P_DEVICE_FOUND: + { + char *ptr, *name_start, *name_end; + unsigned int config_methods = 0; + + memset(&data->p2p_device_found, 0, sizeof(data->p2p_device_found)); + ret = sscanf(event_no_prefix, MACSTR, MACADDR2STR(tmp_mac_addr)); + if (ret > 0) { + copy_mac_addr(tmp_mac_addr, data->p2p_device_found.mac); + } + name_start = strstr(event_no_prefix, "name='"); + if (name_start) { + name_start += 6; + name_end = strchr(name_start, '\''); + if (name_end) { + size_t name_len = name_end - name_start; + + if (name_len >= sizeof(data->p2p_device_found.device_name)) { + name_len = sizeof(data->p2p_device_found.device_name) - 1; + } + memcpy(data->p2p_device_found.device_name, name_start, name_len); + data->p2p_device_found.device_name[name_len] = '\0'; + } + } + ptr = strstr(event_no_prefix, "config_methods="); + if (ptr) { + ret = sscanf(ptr, "config_methods=%x", &config_methods); + if (ret > 0) { + data->p2p_device_found.config_methods = config_methods; + } + } + event_data->data_len = sizeof(data->p2p_device_found); + ret = 1; + break; + } +#endif case SUPPLICANT_EVENT_TERMINATING: case SUPPLICANT_EVENT_SCAN_STARTED: case SUPPLICANT_EVENT_SCAN_RESULTS: @@ -386,8 +426,18 @@ int supplicant_send_wifi_mgmt_event(const char *ifname, enum net_event_wifi_cmd case NET_EVENT_WIFI_CMD_SUPPLICANT: event_data.data = &data; if (supplicant_process_status(&event_data, (char *)supplicant_status) > 0) { - net_mgmt_event_notify_with_info(NET_EVENT_SUPPLICANT_INT_EVENT, - iface, &event_data, sizeof(event_data)); +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P + /* Handle P2P events directly */ + if (event_data.event == SUPPLICANT_EVENT_P2P_DEVICE_FOUND) { + wifi_mgmt_raise_p2p_device_found_event(iface, + &data.p2p_device_found); + } else { +#endif + net_mgmt_event_notify_with_info(NET_EVENT_SUPPLICANT_INT_EVENT, + iface, &event_data, sizeof(event_data)); +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P + } +#endif } break; default: diff --git a/modules/hostap/src/supp_events.h b/modules/hostap/src/supp_events.h index 1c74af528492..6ff8812c2fb8 100644 --- a/modules/hostap/src/supp_events.h +++ b/modules/hostap/src/supp_events.h @@ -137,6 +137,10 @@ union supplicant_event_data { unsigned int id; } network_removed; +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P + struct wifi_p2p_device_info p2p_device_found; +#endif + char supplicant_event_str[NM_WIFI_EVENT_STR_LEN]; }; @@ -158,6 +162,9 @@ enum supplicant_event_num { SUPPLICANT_EVENT_NETWORK_REMOVED, SUPPLICANT_EVENT_DSCP_POLICY, SUPPLICANT_EVENT_REGDOM_CHANGE, +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P + SUPPLICANT_EVENT_P2P_DEVICE_FOUND, +#endif }; struct supplicant_int_event_data { diff --git a/modules/hostap/src/supp_main.c b/modules/hostap/src/supp_main.c index 74d195386b1f..8afdba33b203 100644 --- a/modules/hostap/src/supp_main.c +++ b/modules/hostap/src/supp_main.c @@ -85,6 +85,9 @@ static const struct wifi_mgmt_ops mgmt_ops = { .get_conn_params = supplicant_get_wifi_conn_params, .wps_config = supplicant_wps_config, .set_bss_max_idle_period = supplicant_set_bss_max_idle_period, +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN + .set_bgscan = supplicant_set_bgscan, +#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN */ #ifdef CONFIG_AP .ap_enable = supplicant_ap_enable, .ap_disable = supplicant_ap_disable, @@ -98,6 +101,9 @@ static const struct wifi_mgmt_ops mgmt_ops = { .enterprise_creds = supplicant_add_enterprise_creds, #endif .config_params = supplicant_config_params, +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P + .p2p_oper = supplicant_p2p_oper, +#endif }; DEFINE_WIFI_NM_INSTANCE(wifi_supplicant, &mgmt_ops); @@ -242,6 +248,12 @@ static void zephyr_wpa_supplicant_msg(void *ctx, const char *txt, size_t len) supplicant_send_wifi_mgmt_event(wpa_s->ifname, NET_EVENT_WIFI_CMD_NEIGHBOR_REP_RECEIVED, (void *)txt, len); +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P + } else if (strncmp(txt, "P2P-", 4) == 0) { + supplicant_send_wifi_mgmt_event(wpa_s->ifname, + NET_EVENT_WIFI_CMD_SUPPLICANT, + (void *)txt, len); +#endif } } diff --git a/soc/nordic/common/poweroff.c b/soc/nordic/common/poweroff.c index ebce3aae77cd..f659d31997f2 100644 --- a/soc/nordic/common/poweroff.c +++ b/soc/nordic/common/poweroff.c @@ -7,7 +7,9 @@ #include #include -#if defined(CONFIG_SOC_SERIES_NRF51X) || defined(CONFIG_SOC_SERIES_NRF52X) +#if defined(CONFIG_TFM_NRF_SYSTEM_OFF_SERVICE) +#include "tfm_platform_api.h" +#elif defined(CONFIG_SOC_SERIES_NRF51X) || defined(CONFIG_SOC_SERIES_NRF52X) #include #elif defined(CONFIG_SOC_SERIES_NRF54HX) #include @@ -30,6 +32,10 @@ void z_sys_poweroff(void) { +#if defined(CONFIG_TFM_NRF_SYSTEM_OFF_SERVICE) + tfm_platform_system_off(); +#else + #if defined(CONFIG_HAS_NORDIC_RAM_CTRL) uint8_t *ram_start; size_t ram_size; @@ -78,5 +84,7 @@ void z_sys_poweroff(void) nrf_regulators_system_off(NRF_REGULATORS); #endif +#endif /* CONFIG_TFM_NRF_SYSTEM_OFF_SERVICE */ + CODE_UNREACHABLE; } diff --git a/soc/nordic/ironside/CMakeLists.txt b/soc/nordic/ironside/CMakeLists.txt index ea7f68207a89..f1ae2114f2ec 100644 --- a/soc/nordic/ironside/CMakeLists.txt +++ b/soc/nordic/ironside/CMakeLists.txt @@ -10,3 +10,4 @@ zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_BOOTMODE_SERVICE bootmode.c) zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_TDD_SERVICE tdd.c) zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_UPDATE_SERVICE update.c) zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_DVFS_SERVICE dvfs.c) +zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_COUNTER_SERVICE counter.c) diff --git a/soc/nordic/ironside/Kconfig b/soc/nordic/ironside/Kconfig index 32c6ef38165f..ff1d01f99e81 100644 --- a/soc/nordic/ironside/Kconfig +++ b/soc/nordic/ironside/Kconfig @@ -69,6 +69,12 @@ config NRF_IRONSIDE_DVFS_SERVICE help Service used to handle DVFS operating point requests. +config NRF_IRONSIDE_COUNTER_SERVICE + bool "IronSide counter service" + select NRF_IRONSIDE_CALL + help + Service used to manage secure monotonic counters. + if NRF_IRONSIDE_DVFS_SERVICE config NRF_IRONSIDE_ABB_STATUSANA_CHECK_MAX_ATTEMPTS diff --git a/soc/nordic/ironside/counter.c b/soc/nordic/ironside/counter.c new file mode 100644 index 000000000000..b4506621851d --- /dev/null +++ b/soc/nordic/ironside/counter.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +int ironside_counter_set(enum ironside_counter counter_id, uint32_t value) +{ + int err; + struct ironside_call_buf *const buf = ironside_call_alloc(); + + buf->id = IRONSIDE_CALL_ID_COUNTER_SET_V1; + buf->args[IRONSIDE_COUNTER_SET_SERVICE_COUNTER_ID_IDX] = (uint32_t)counter_id; + buf->args[IRONSIDE_COUNTER_SET_SERVICE_VALUE_IDX] = value; + + ironside_call_dispatch(buf); + + if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) { + err = buf->args[IRONSIDE_COUNTER_SET_SERVICE_RETCODE_IDX]; + } else { + err = buf->status; + } + + ironside_call_release(buf); + + return err; +} + +int ironside_counter_get(enum ironside_counter counter_id, uint32_t *value) +{ + int err; + struct ironside_call_buf *buf; + + if (value == NULL) { + return -IRONSIDE_COUNTER_ERROR_INVALID_PARAM; + } + + buf = ironside_call_alloc(); + + buf->id = IRONSIDE_CALL_ID_COUNTER_GET_V1; + buf->args[IRONSIDE_COUNTER_GET_SERVICE_COUNTER_ID_IDX] = (uint32_t)counter_id; + + ironside_call_dispatch(buf); + + if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) { + err = buf->args[IRONSIDE_COUNTER_GET_SERVICE_RETCODE_IDX]; + if (err == 0) { + *value = buf->args[IRONSIDE_COUNTER_GET_SERVICE_VALUE_IDX]; + } + } else { + err = buf->status; + } + + ironside_call_release(buf); + + return err; +} + +int ironside_counter_lock(enum ironside_counter counter_id) +{ + int err; + struct ironside_call_buf *const buf = ironside_call_alloc(); + + buf->id = IRONSIDE_CALL_ID_COUNTER_LOCK_V1; + buf->args[IRONSIDE_COUNTER_LOCK_SERVICE_COUNTER_ID_IDX] = (uint32_t)counter_id; + + ironside_call_dispatch(buf); + + if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) { + err = buf->args[IRONSIDE_COUNTER_LOCK_SERVICE_RETCODE_IDX]; + } else { + err = buf->status; + } + + ironside_call_release(buf); + + return err; +} diff --git a/soc/nordic/ironside/include/nrf_ironside/counter.h b/soc/nordic/ironside/include/nrf_ironside/counter.h new file mode 100644 index 000000000000..37866c43a684 --- /dev/null +++ b/soc/nordic/ironside/include/nrf_ironside/counter.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_COUNTER_H_ +#define ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_COUNTER_H_ + +#include +#include +#include + +/** + * @name Counter service error codes. + * @{ + */ + +/** Counter value is lower than current value (monotonic violation). */ +#define IRONSIDE_COUNTER_ERROR_TOO_LOW (1) +/** Invalid counter ID. */ +#define IRONSIDE_COUNTER_ERROR_INVALID_ID (2) +/** Counter is locked and cannot be modified. */ +#define IRONSIDE_COUNTER_ERROR_LOCKED (3) +/** Invalid parameter. */ +#define IRONSIDE_COUNTER_ERROR_INVALID_PARAM (4) +/** Storage operation failed. */ +#define IRONSIDE_COUNTER_ERROR_STORAGE_FAILURE (5) + +/** + * @} + */ + +/** Maximum value for a counter */ +#define IRONSIDE_COUNTER_MAX_VALUE UINT32_MAX + +/** Number of counters */ +#define IRONSIDE_COUNTER_NUM 4 + +/** + * @brief Counter identifiers. + */ +enum ironside_counter { + IRONSIDE_COUNTER_0 = 0, + IRONSIDE_COUNTER_1, + IRONSIDE_COUNTER_2, + IRONSIDE_COUNTER_3 +}; + +/* IronSide call identifiers with implicit versions. */ +#define IRONSIDE_CALL_ID_COUNTER_SET_V1 6 +#define IRONSIDE_CALL_ID_COUNTER_GET_V1 7 +#define IRONSIDE_CALL_ID_COUNTER_LOCK_V1 8 + +enum { + IRONSIDE_COUNTER_SET_SERVICE_COUNTER_ID_IDX, + IRONSIDE_COUNTER_SET_SERVICE_VALUE_IDX, + /* The last enum value is reserved for the number of arguments */ + IRONSIDE_COUNTER_SET_NUM_ARGS +}; + +enum { + IRONSIDE_COUNTER_GET_SERVICE_COUNTER_ID_IDX, + /* The last enum value is reserved for the number of arguments */ + IRONSIDE_COUNTER_GET_NUM_ARGS +}; + +enum { + IRONSIDE_COUNTER_LOCK_SERVICE_COUNTER_ID_IDX, + /* The last enum value is reserved for the number of arguments */ + IRONSIDE_COUNTER_LOCK_NUM_ARGS +}; + +/* Index of the return code within the service buffer. */ +#define IRONSIDE_COUNTER_SET_SERVICE_RETCODE_IDX (0) +#define IRONSIDE_COUNTER_GET_SERVICE_RETCODE_IDX (0) +#define IRONSIDE_COUNTER_LOCK_SERVICE_RETCODE_IDX (0) + +/* Index of the value within the GET response buffer. */ +#define IRONSIDE_COUNTER_GET_SERVICE_VALUE_IDX (1) + +BUILD_ASSERT(IRONSIDE_COUNTER_SET_NUM_ARGS <= NRF_IRONSIDE_CALL_NUM_ARGS); +BUILD_ASSERT(IRONSIDE_COUNTER_GET_NUM_ARGS <= NRF_IRONSIDE_CALL_NUM_ARGS); +BUILD_ASSERT(IRONSIDE_COUNTER_LOCK_NUM_ARGS <= NRF_IRONSIDE_CALL_NUM_ARGS); + +/** + * @brief Set a counter value. + * + * This sets the specified counter to the given value. The counter is monotonic, + * so the new value must be greater than or equal to the current value. + * If the counter is locked, the operation will fail. + * + * @note Counters are automatically initialized to 0 during the first boot in LCS ROT. + * The monotonic constraint applies to all subsequent writes. + * + * @param counter_id Counter identifier. + * @param value New counter value. + * + * @retval 0 on success. + * @retval -IRONSIDE_COUNTER_ERROR_INVALID_ID if counter_id is invalid. + * @retval -IRONSIDE_COUNTER_ERROR_TOO_LOW if value is lower than current value. + * @retval -IRONSIDE_COUNTER_ERROR_LOCKED if counter is locked. + * @retval -IRONSIDE_COUNTER_ERROR_STORAGE_FAILURE if storage operation failed. + * @retval Positive error status if reported by IronSide call (see error codes in @ref call.h). + */ +int ironside_counter_set(enum ironside_counter counter_id, uint32_t value); + +/** + * @brief Get a counter value. + * + * This retrieves the current value of the specified counter. + * + * @note Counters are automatically initialized to 0 during the first boot in LCS ROT, + * so this function will always succeed for valid counter IDs. + * + * @param counter_id Counter identifier. + * @param value Pointer to store the counter value. + * + * @retval 0 on success. + * @retval -IRONSIDE_COUNTER_ERROR_INVALID_ID if counter_id is invalid. + * @retval -IRONSIDE_COUNTER_ERROR_INVALID_PARAM if value is NULL. + * @retval -IRONSIDE_COUNTER_ERROR_STORAGE_FAILURE if storage operation failed. + * @retval Positive error status if reported by IronSide call (see error codes in @ref call.h). + */ +int ironside_counter_get(enum ironside_counter counter_id, uint32_t *value); + +/** + * @brief Lock a counter for the current boot. + * + * This locks the specified counter, preventing any further modifications until the next reboot. + * The lock state is not persistent and will be cleared on reboot. + * + * @note The intended use case is for a bootloader to lock a counter before transferring control + * to the next boot stage, preventing that image from modifying the counter value. + * + * @param counter_id Counter identifier. + * + * @retval 0 on success. + * @retval -IRONSIDE_COUNTER_ERROR_INVALID_ID if counter_id is invalid. + * @retval Positive error status if reported by IronSide call (see error codes in @ref call.h). + */ +int ironside_counter_lock(enum ironside_counter counter_id); + +#endif /* ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_COUNTER_H_ */ diff --git a/soc/nordic/nrf54h/soc.c b/soc/nordic/nrf54h/soc.c index c291767d0906..7886689dbb8d 100644 --- a/soc/nordic/nrf54h/soc.c +++ b/soc/nordic/nrf54h/soc.c @@ -41,14 +41,20 @@ LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); DT_REG_ADDR(COND_CODE_1(DT_FIXED_SUBPARTITION_EXISTS(DT_NODELABEL(label)), \ (DT_GPARENT(DT_PARENT(DT_NODELABEL(label)))), \ (DT_GPARENT(DT_NODELABEL(label)))))) +#define FIXED_PARTITION_NODE_MTD(node) \ + COND_CODE_1( \ + DT_FIXED_SUBPARTITION_EXISTS(node), \ + (DT_MTD_FROM_FIXED_SUBPARTITION(node)), \ + (DT_MTD_FROM_FIXED_PARTITION(node))) #ifdef CONFIG_USE_DT_CODE_PARTITION #define FLASH_LOAD_OFFSET DT_REG_ADDR(DT_CHOSEN(zephyr_code_partition)) #elif defined(CONFIG_FLASH_LOAD_OFFSET) #define FLASH_LOAD_OFFSET CONFIG_FLASH_LOAD_OFFSET #endif - -#define PARTITION_IS_RUNNING_APP_PARTITION(label) \ +#define FIXED_PARTITION_IS_RUNNING_APP_PARTITION(label) \ + DT_SAME_NODE(FIXED_PARTITION_NODE_MTD(DT_CHOSEN(zephyr_code_partition)), \ + FIXED_PARTITION_NODE_MTD(DT_NODELABEL(label))) && \ (DT_REG_ADDR(DT_NODELABEL(label)) <= FLASH_LOAD_OFFSET && \ DT_REG_ADDR(DT_NODELABEL(label)) + DT_REG_SIZE(DT_NODELABEL(label)) > FLASH_LOAD_OFFSET) @@ -210,7 +216,7 @@ void soc_late_init_hook(void) void *radiocore_address = NULL; #if DT_NODE_EXISTS(DT_NODELABEL(cpurad_slot1_partition)) - if (PARTITION_IS_RUNNING_APP_PARTITION(cpuapp_slot1_partition)) { + if (FIXED_PARTITION_IS_RUNNING_APP_PARTITION(cpuapp_slot1_partition)) { radiocore_address = (void *)(FIXED_PARTITION_ADDRESS(cpurad_slot1_partition) + CONFIG_ROM_START_OFFSET); } else { diff --git a/subsys/dfu/img_util/flash_img.c b/subsys/dfu/img_util/flash_img.c index 24e95a8dc1a9..d3c9749401b2 100644 --- a/subsys/dfu/img_util/flash_img.c +++ b/subsys/dfu/img_util/flash_img.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -24,10 +25,11 @@ LOG_MODULE_REGISTER(flash_img, CONFIG_IMG_MANAGER_LOG_LEVEL); #endif #define FIXED_PARTITION_IS_RUNNING_APP_PARTITION(label) \ + DT_SAME_NODE(FIXED_PARTITION_NODE_MTD(DT_CHOSEN(zephyr_code_partition)), \ + FIXED_PARTITION_MTD(label)) && \ (FIXED_PARTITION_OFFSET(label) <= CONFIG_FLASH_LOAD_OFFSET && \ FIXED_PARTITION_OFFSET(label) + FIXED_PARTITION_SIZE(label) > CONFIG_FLASH_LOAD_OFFSET) -#include #if defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) && (CONFIG_TFM_MCUBOOT_IMAGE_NUMBER == 2) #define UPLOAD_FLASH_AREA_LABEL slot1_ns_partition #else diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c index a2bf006b9474..97fc430e374a 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018-2021 mcumgr authors - * Copyright (c) 2022-2024 Nordic Semiconductor ASA + * Copyright (c) 2022-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -49,6 +49,8 @@ #endif #define FIXED_PARTITION_IS_RUNNING_APP_PARTITION(label) \ + DT_SAME_NODE(FIXED_PARTITION_NODE_MTD(DT_CHOSEN(zephyr_code_partition)), \ + FIXED_PARTITION_MTD(label)) && \ (FIXED_PARTITION_OFFSET(label) <= CONFIG_FLASH_LOAD_OFFSET && \ FIXED_PARTITION_OFFSET(label) + FIXED_PARTITION_SIZE(label) > CONFIG_FLASH_LOAD_OFFSET) diff --git a/subsys/net/l2/wifi/Kconfig b/subsys/net/l2/wifi/Kconfig index 63680dba9b30..eddfb7d4c30a 100644 --- a/subsys/net/l2/wifi/Kconfig +++ b/subsys/net/l2/wifi/Kconfig @@ -72,6 +72,15 @@ config WIFI_SHELL_MAX_AP_STA This option defines the maximum number of APs and STAs that can be managed in Wi-Fi shell. +config WIFI_P2P_MAX_PEERS + int "Maximum number of P2P peers that can be returned in a single query" + depends on WIFI_NM_WPA_SUPPLICANT_P2P + default 32 + range 1 256 + help + This option defines the maximum number of P2P peers that can be returned + in a single query operation. + config WIFI_NM bool "Wi-Fi Network manager support" help diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index a962fe317664..58d269e277be 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -1449,6 +1449,60 @@ static int wifi_set_bss_max_idle_period(uint64_t mgmt_request, struct net_if *if NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_BSS_MAX_IDLE_PERIOD, wifi_set_bss_max_idle_period); +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN +static int wifi_set_bgscan(uint64_t mgmt_request, struct net_if *iface, void *data, size_t len) +{ + const struct device *dev = net_if_get_device(iface); + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); + struct wifi_bgscan_params *params = data; + + if (wifi_mgmt_api == NULL || wifi_mgmt_api->set_bgscan == NULL) { + return -ENOTSUP; + } + + if (!net_if_is_admin_up(iface)) { + return -ENETDOWN; + } + + if (data == NULL || len != sizeof(*params)) { + return -EINVAL; + } + + return wifi_mgmt_api->set_bgscan(dev, params); +} + +NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_BGSCAN, wifi_set_bgscan); +#endif +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P +static int wifi_p2p_oper(uint64_t mgmt_request, struct net_if *iface, + void *data, size_t len) +{ + const struct device *dev = net_if_get_device(iface); + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); + struct wifi_p2p_params *params = data; + + if (wifi_mgmt_api == NULL || wifi_mgmt_api->p2p_oper == NULL) { + return -ENOTSUP; + } + + if (!data || len != sizeof(*params)) { + return -EINVAL; + } + + return wifi_mgmt_api->p2p_oper(dev, params); +} + +NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_P2P_OPER, wifi_p2p_oper); + +void wifi_mgmt_raise_p2p_device_found_event(struct net_if *iface, + struct wifi_p2p_device_info *peer_info) +{ + net_mgmt_event_notify_with_info(NET_EVENT_WIFI_P2P_DEVICE_FOUND, + iface, peer_info, + sizeof(*peer_info)); +} +#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ + #ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS void wifi_mgmt_raise_raw_scan_result_event(struct net_if *iface, struct wifi_raw_scan_result *raw_scan_result) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 5a90d2ccf4c4..f27fe5a6ffcd 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -46,7 +46,8 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); NET_EVENT_WIFI_AP_STA_CONNECTED |\ NET_EVENT_WIFI_AP_STA_DISCONNECTED|\ NET_EVENT_WIFI_SIGNAL_CHANGE |\ - NET_EVENT_WIFI_NEIGHBOR_REP_COMP) + NET_EVENT_WIFI_NEIGHBOR_REP_COMP |\ + NET_EVENT_WIFI_P2P_DEVICE_FOUND) #ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS_ONLY #define WIFI_SHELL_SCAN_EVENTS ( \ @@ -519,6 +520,26 @@ static void handle_wifi_neighbor_rep_complete(struct net_mgmt_event_callback *cb } #endif +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P +static void handle_wifi_p2p_device_found(struct net_mgmt_event_callback *cb) +{ + const struct wifi_p2p_device_info *peer_info = + (const struct wifi_p2p_device_info *)cb->info; + const struct shell *sh = context.sh; + + if (!peer_info || peer_info->device_name[0] == '\0') { + return; + } + + PR("Device Name: %-20s MAC Address: %02x:%02x:%02x:%02x:%02x:%02x " + "Config Methods: 0x%x\n", + peer_info->device_name, + peer_info->mac[0], peer_info->mac[1], peer_info->mac[2], + peer_info->mac[3], peer_info->mac[4], peer_info->mac[5], + peer_info->config_methods); +} +#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ + static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface) { @@ -552,6 +573,11 @@ static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, handle_wifi_neighbor_rep_complete(cb, iface); break; #endif +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P + case NET_EVENT_WIFI_P2P_DEVICE_FOUND: + handle_wifi_p2p_device_found(cb); + break; +#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ default: break; } @@ -3528,6 +3554,564 @@ static int cmd_wifi_dpp_reconfig(const struct shell *sh, size_t argc, char *argv } #endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_DPP */ + +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P +static void print_peer_info(const struct shell *sh, int index, + const struct wifi_p2p_device_info *peer) +{ + uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; + const char *device_name; + const char *device_type; + const char *config_methods; + + device_name = (peer->device_name[0] != '\0') ? + peer->device_name : ""; + device_type = (peer->pri_dev_type_str[0] != '\0') ? + peer->pri_dev_type_str : "-"; + config_methods = (peer->config_methods_str[0] != '\0') ? + peer->config_methods_str : "-"; + + PR("%-4d | %-32s | %-17s | %-4d | %-20s | %s\n", + index, + device_name, + net_sprint_ll_addr_buf(peer->mac, WIFI_MAC_ADDR_LEN, + mac_string_buf, + sizeof(mac_string_buf)), + peer->rssi, + device_type, + config_methods); +} + +static int cmd_wifi_p2p_peer(const struct shell *sh, size_t argc, char *argv[]) +{ + struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv); + struct wifi_p2p_params params = {0}; + uint8_t mac_addr[WIFI_MAC_ADDR_LEN]; + static struct wifi_p2p_device_info peers[WIFI_P2P_MAX_PEERS]; + int ret; + int max_peers = (argc < 2) ? WIFI_P2P_MAX_PEERS : 1; + + context.sh = sh; + + memset(peers, 0, sizeof(peers)); + + params.peers = peers; + params.oper = WIFI_P2P_PEER; + params.peer_count = max_peers; + + if (argc >= 2) { + if (sscanf(argv[1], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &mac_addr[0], &mac_addr[1], &mac_addr[2], + &mac_addr[3], &mac_addr[4], &mac_addr[5]) != WIFI_MAC_ADDR_LEN) { + PR_ERROR("Invalid MAC address format. Use: XX:XX:XX:XX:XX:XX\n"); + return -EINVAL; + } + memcpy(params.peer_addr, mac_addr, WIFI_MAC_ADDR_LEN); + params.peer_count = 1; + } else { + /* Use broadcast MAC to query all peers */ + memset(params.peer_addr, 0xFF, WIFI_MAC_ADDR_LEN); + } + + ret = net_mgmt(NET_REQUEST_WIFI_P2P_OPER, iface, ¶ms, sizeof(params)); + if (ret) { + PR_WARNING("P2P peer info request failed\n"); + return -ENOEXEC; + } + + if (params.peer_count > 0) { + PR("\n%-4s | %-32s | %-17s | %-4s | %-20s | %s\n", + "Num", "Device Name", "MAC Address", "RSSI", "Device Type", "Config Methods"); + for (int i = 0; i < params.peer_count; i++) { + print_peer_info(sh, i + 1, &peers[i]); + } + } else { + if (argc >= 2) { + shell_print(sh, "No information available for peer %s", argv[1]); + } else { + shell_print(sh, "No P2P peers found"); + } + } + + return 0; +} + + +static int cmd_wifi_p2p_find(const struct shell *sh, size_t argc, char *argv[]) +{ + struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv); + struct wifi_p2p_params params = {0}; + + context.sh = sh; + + params.oper = WIFI_P2P_FIND; + params.discovery_type = WIFI_P2P_FIND_START_WITH_FULL; + params.timeout = 10; /* Default 10 second timeout */ + + if (argc > 1) { + int opt; + int opt_index = 0; + struct getopt_state *state; + static const struct option long_options[] = { + {"timeout", required_argument, 0, 't'}, + {"type", required_argument, 0, 'T'}, + {"iface", required_argument, 0, 'i'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + long val; + + while ((opt = getopt_long(argc, argv, "t:T:i:h", + long_options, &opt_index)) != -1) { + state = getopt_state_get(); + switch (opt) { + case 't': + if (!parse_number(sh, &val, state->optarg, "timeout", 0, 65535)) { + return -EINVAL; + } + params.timeout = (uint16_t)val; + break; + case 'T': + if (!parse_number(sh, &val, state->optarg, "type", 0, 2)) { + return -EINVAL; + } + switch (val) { + case 0: + params.discovery_type = WIFI_P2P_FIND_ONLY_SOCIAL; + break; + case 1: + params.discovery_type = WIFI_P2P_FIND_PROGRESSIVE; + break; + case 2: + params.discovery_type = WIFI_P2P_FIND_START_WITH_FULL; + break; + default: + return -EINVAL; + } + break; + case 'i': + /* Unused, but parsing to avoid unknown option error */ + break; + case 'h': + shell_help(sh); + return -ENOEXEC; + default: + PR_ERROR("Invalid option %c\n", state->optopt); + return -EINVAL; + } + } + } + + if (net_mgmt(NET_REQUEST_WIFI_P2P_OPER, iface, ¶ms, sizeof(params))) { + PR_WARNING("P2P find request failed\n"); + return -ENOEXEC; + } + PR("P2P find started\n"); + return 0; +} + +static int cmd_wifi_p2p_stop_find(const struct shell *sh, size_t argc, char *argv[]) +{ + struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv); + struct wifi_p2p_params params = {0}; + + context.sh = sh; + + params.oper = WIFI_P2P_STOP_FIND; + + if (net_mgmt(NET_REQUEST_WIFI_P2P_OPER, iface, ¶ms, sizeof(params))) { + PR_WARNING("P2P stop find request failed\n"); + return -ENOEXEC; + } + PR("P2P find stopped\n"); + return 0; +} + +static int cmd_wifi_p2p_connect(const struct shell *sh, size_t argc, char *argv[]) +{ + struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv); + struct wifi_p2p_params params = {0}; + uint8_t mac_addr[WIFI_MAC_ADDR_LEN]; + const char *method_arg = NULL; + int opt; + int opt_index = 0; + struct getopt_state *state; + static const struct option long_options[] = { + {"go-intent", required_argument, 0, 'g'}, + {"freq", required_argument, 0, 'f'}, + {"iface", required_argument, 0, 'i'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + long val; + + context.sh = sh; + + if (argc < 3) { + PR_ERROR("Usage: wifi p2p connect [PIN] " + "[--go-intent=<0-15>] [--freq=]\n"); + return -EINVAL; + } + + /* Parse MAC address */ + if (sscanf(argv[1], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &mac_addr[0], &mac_addr[1], &mac_addr[2], + &mac_addr[3], &mac_addr[4], &mac_addr[5]) != WIFI_MAC_ADDR_LEN) { + PR_ERROR("Invalid MAC address format. Use: XX:XX:XX:XX:XX:XX\n"); + return -EINVAL; + } + memcpy(params.peer_addr, mac_addr, WIFI_MAC_ADDR_LEN); + + method_arg = argv[2]; + if (strcmp(method_arg, "pbc") == 0) { + params.connect.method = WIFI_P2P_METHOD_PBC; + } else if (strcmp(method_arg, "pin") == 0) { + if (argc > 3 && argv[3][0] != '-') { + params.connect.method = WIFI_P2P_METHOD_KEYPAD; + strncpy(params.connect.pin, argv[3], WIFI_WPS_PIN_MAX_LEN); + params.connect.pin[WIFI_WPS_PIN_MAX_LEN] = '\0'; + } else { + params.connect.method = WIFI_P2P_METHOD_DISPLAY; + params.connect.pin[0] = '\0'; + } + } else { + PR_ERROR("Invalid connection method. Use: pbc or pin\n"); + return -EINVAL; + } + + /* Set default GO intent */ + params.connect.go_intent = 0; + /* Set default frequency to 2462 MHz (channel 11, 2.4 GHz) */ + params.connect.freq = 2462; + + while ((opt = getopt_long(argc, argv, "g:f:i:h", long_options, &opt_index)) != -1) { + state = getopt_state_get(); + switch (opt) { + case 'g': + if (!parse_number(sh, &val, state->optarg, "go-intent", 0, 15)) { + return -EINVAL; + } + params.connect.go_intent = (uint8_t)val; + break; + case 'f': + if (!parse_number(sh, &val, state->optarg, "freq", 0, 6000)) { + return -EINVAL; + } + params.connect.freq = (unsigned int)val; + break; + case 'i': + /* Unused, but parsing to avoid unknown option error */ + break; + case 'h': + shell_help(sh); + return -ENOEXEC; + default: + PR_ERROR("Invalid option %c\n", state->optopt); + return -EINVAL; + } + } + + params.oper = WIFI_P2P_CONNECT; + + if (net_mgmt(NET_REQUEST_WIFI_P2P_OPER, iface, ¶ms, sizeof(params))) { + PR_WARNING("P2P connect request failed\n"); + return -ENOEXEC; + } + + /* Display the generated PIN for DISPLAY method */ + if (params.connect.method == WIFI_P2P_METHOD_DISPLAY && params.connect.pin[0] != '\0') { + PR("%s\n", params.connect.pin); + } else { + PR("P2P connection initiated\n"); + } + return 0; +} + +static int cmd_wifi_p2p_group_add(const struct shell *sh, size_t argc, char *argv[]) +{ + struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv); + struct wifi_p2p_params params = {0}; + int opt; + int opt_index = 0; + struct getopt_state *state; + static const struct option long_options[] = { + {"freq", required_argument, 0, 'f'}, + {"persistent", required_argument, 0, 'p'}, + {"ht40", no_argument, 0, 'h'}, + {"vht", no_argument, 0, 'v'}, + {"he", no_argument, 0, 'H'}, + {"edmg", no_argument, 0, 'e'}, + {"go-bssid", required_argument, 0, 'b'}, + {"iface", required_argument, 0, 'i'}, + {"help", no_argument, 0, '?'}, + {0, 0, 0, 0} + }; + long val; + uint8_t mac_addr[WIFI_MAC_ADDR_LEN]; + + context.sh = sh; + + params.oper = WIFI_P2P_GROUP_ADD; + params.group_add.freq = 0; + params.group_add.persistent = -1; + params.group_add.ht40 = false; + params.group_add.vht = false; + params.group_add.he = false; + params.group_add.edmg = false; + params.group_add.go_bssid_length = 0; + + while ((opt = getopt_long(argc, argv, "f:p:hvHeb:i:?", long_options, + &opt_index)) != -1) { + state = getopt_state_get(); + switch (opt) { + case 'f': + if (!parse_number(sh, &val, state->optarg, "freq", 0, 6000)) { + return -EINVAL; + } + params.group_add.freq = (int)val; + break; + case 'p': + if (!parse_number(sh, &val, state->optarg, "persistent", -1, 255)) { + return -EINVAL; + } + params.group_add.persistent = (int)val; + break; + case 'h': + params.group_add.ht40 = true; + break; + case 'v': + params.group_add.vht = true; + params.group_add.ht40 = true; + break; + case 'H': + params.group_add.he = true; + break; + case 'e': + params.group_add.edmg = true; + break; + case 'b': + if (sscanf(state->optarg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &mac_addr[0], &mac_addr[1], &mac_addr[2], &mac_addr[3], + &mac_addr[4], &mac_addr[5]) != WIFI_MAC_ADDR_LEN) { + PR_ERROR("Invalid GO BSSID format. Use: XX:XX:XX:XX:XX:XX\n"); + return -EINVAL; + } + memcpy(params.group_add.go_bssid, mac_addr, WIFI_MAC_ADDR_LEN); + params.group_add.go_bssid_length = WIFI_MAC_ADDR_LEN; + break; + case 'i': + /* Unused, but parsing to avoid unknown option error */ + break; + case '?': + shell_help(sh); + return -ENOEXEC; + default: + PR_ERROR("Invalid option %c\n", state->optopt); + return -EINVAL; + } + } + + if (net_mgmt(NET_REQUEST_WIFI_P2P_OPER, iface, ¶ms, sizeof(params))) { + PR_WARNING("P2P group add request failed\n"); + return -ENOEXEC; + } + PR("P2P group add initiated\n"); + return 0; +} + +static int cmd_wifi_p2p_group_remove(const struct shell *sh, size_t argc, char *argv[]) +{ + struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv); + struct wifi_p2p_params params = {0}; + + context.sh = sh; + + if (argc < 2) { + PR_ERROR("Interface name required. Usage: wifi p2p group_remove \n"); + return -EINVAL; + } + + params.oper = WIFI_P2P_GROUP_REMOVE; + strncpy(params.group_remove.ifname, argv[1], + CONFIG_NET_INTERFACE_NAME_LEN); + params.group_remove.ifname[CONFIG_NET_INTERFACE_NAME_LEN] = '\0'; + + if (net_mgmt(NET_REQUEST_WIFI_P2P_OPER, iface, ¶ms, sizeof(params))) { + PR_WARNING("P2P group remove request failed\n"); + return -ENOEXEC; + } + PR("P2P group remove initiated\n"); + return 0; +} + +static int cmd_wifi_p2p_invite(const struct shell *sh, size_t argc, char *argv[]) +{ + struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv); + struct wifi_p2p_params params = {0}; + uint8_t mac_addr[WIFI_MAC_ADDR_LEN]; + int opt; + int opt_index = 0; + struct getopt_state *state; + static const struct option long_options[] = { + {"persistent", required_argument, 0, 'p'}, + {"group", required_argument, 0, 'g'}, + {"peer", required_argument, 0, 'P'}, + {"freq", required_argument, 0, 'f'}, + {"go-dev-addr", required_argument, 0, 'd'}, + {"iface", required_argument, 0, 'i'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + long val; + + context.sh = sh; + + params.oper = WIFI_P2P_INVITE; + params.invite.type = WIFI_P2P_INVITE_PERSISTENT; + params.invite.persistent_id = -1; + params.invite.group_ifname[0] = '\0'; + params.invite.freq = 0; + params.invite.go_dev_addr_length = 0; + memset(params.invite.peer_addr, 0, WIFI_MAC_ADDR_LEN); + + if (argc < 2) { + PR_ERROR("Usage: wifi p2p invite --persistent= OR " + "wifi p2p invite --group= --peer= [options]\n"); + return -EINVAL; + } + + while ((opt = getopt_long(argc, argv, "p:g:P:f:d:i:h", long_options, + &opt_index)) != -1) { + state = getopt_state_get(); + switch (opt) { + case 'p': + if (!parse_number(sh, &val, state->optarg, "persistent", 0, 255)) { + return -EINVAL; + } + params.invite.type = WIFI_P2P_INVITE_PERSISTENT; + params.invite.persistent_id = (int)val; + break; + case 'g': + params.invite.type = WIFI_P2P_INVITE_GROUP; + strncpy(params.invite.group_ifname, state->optarg, + CONFIG_NET_INTERFACE_NAME_LEN); + params.invite.group_ifname[CONFIG_NET_INTERFACE_NAME_LEN] = '\0'; + break; + case 'P': + if (sscanf(state->optarg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &mac_addr[0], &mac_addr[1], &mac_addr[2], &mac_addr[3], + &mac_addr[4], &mac_addr[5]) != WIFI_MAC_ADDR_LEN) { + PR_ERROR("Invalid peer MAC address format\n"); + return -EINVAL; + } + memcpy(params.invite.peer_addr, mac_addr, WIFI_MAC_ADDR_LEN); + break; + case 'f': + if (!parse_number(sh, &val, state->optarg, "freq", 0, 6000)) { + return -EINVAL; + } + params.invite.freq = (int)val; + break; + case 'd': + if (sscanf(state->optarg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &mac_addr[0], &mac_addr[1], &mac_addr[2], &mac_addr[3], + &mac_addr[4], &mac_addr[5]) != WIFI_MAC_ADDR_LEN) { + PR_ERROR("Invalid GO device address format\n"); + return -EINVAL; + } + memcpy(params.invite.go_dev_addr, mac_addr, WIFI_MAC_ADDR_LEN); + params.invite.go_dev_addr_length = WIFI_MAC_ADDR_LEN; + break; + case 'i': + /* Unused, but parsing to avoid unknown option error */ + break; + case 'h': + shell_help(sh); + return -ENOEXEC; + default: + PR_ERROR("Invalid option %c\n", state->optopt); + return -EINVAL; + } + } + + state = getopt_state_get(); + + if (params.invite.type == WIFI_P2P_INVITE_PERSISTENT && + params.invite.persistent_id >= 0 && + params.invite.peer_addr[0] == 0 && params.invite.peer_addr[1] == 0 && + argc > state->optind && argv[state->optind][0] != '-') { + if (sscanf(argv[state->optind], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &mac_addr[0], &mac_addr[1], &mac_addr[2], &mac_addr[3], + &mac_addr[4], &mac_addr[5]) != WIFI_MAC_ADDR_LEN) { + PR_ERROR("Invalid peer MAC address format\n"); + return -EINVAL; + } + memcpy(params.invite.peer_addr, mac_addr, WIFI_MAC_ADDR_LEN); + } + + if (params.invite.type == WIFI_P2P_INVITE_PERSISTENT) { + if (params.invite.persistent_id < 0) { + PR_ERROR("Persistent group ID required. Use --persistent=\n"); + return -EINVAL; + } + if (params.invite.peer_addr[0] == 0 && params.invite.peer_addr[1] == 0) { + PR_ERROR("Peer MAC address required\n"); + return -EINVAL; + } + } else if (params.invite.type == WIFI_P2P_INVITE_GROUP) { + if (params.invite.group_ifname[0] == '\0') { + PR_ERROR("Group interface name required. Use --group=\n"); + return -EINVAL; + } + if (params.invite.peer_addr[0] == 0 && params.invite.peer_addr[1] == 0) { + PR_ERROR("Peer MAC address required. Use --peer=\n"); + return -EINVAL; + } + } + + if (net_mgmt(NET_REQUEST_WIFI_P2P_OPER, iface, ¶ms, sizeof(params))) { + PR_WARNING("P2P invite request failed\n"); + return -ENOEXEC; + } + PR("P2P invite initiated\n"); + return 0; +} + +static int cmd_wifi_p2p_power_save(const struct shell *sh, size_t argc, char *argv[]) +{ + struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv); + struct wifi_p2p_params params = {0}; + bool power_save_enable = false; + + context.sh = sh; + + if (argc < 2) { + PR_ERROR("Usage: wifi p2p power_save \n"); + return -EINVAL; + } + + if (strcmp(argv[1], "on") == 0) { + power_save_enable = true; + } else if (strcmp(argv[1], "off") == 0) { + power_save_enable = false; + } else { + PR_ERROR("Invalid argument. Use 'on' or 'off'\n"); + return -EINVAL; + } + + params.oper = WIFI_P2P_POWER_SAVE; + params.power_save = power_save_enable; + + if (net_mgmt(NET_REQUEST_WIFI_P2P_OPER, iface, ¶ms, sizeof(params))) { + PR_WARNING("P2P power save request failed\n"); + return -ENOEXEC; + } + + PR("P2P power save %s\n", power_save_enable ? "enabled" : "disabled"); + return 0; +} +#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ + static int cmd_wifi_pmksa_flush(const struct shell *sh, size_t argc, char *argv[]) { struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv); @@ -3567,6 +4151,113 @@ static int cmd_wifi_set_bss_max_idle_period(const struct shell *sh, size_t argc, return 0; } +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN +static int wifi_bgscan_args_to_params(const struct shell *sh, size_t argc, char *argv[], + struct wifi_bgscan_params *params) +{ + int err; + int opt; + int opt_index = 0; + struct getopt_state *state; + static const struct option long_options[] = { + {"type", required_argument, 0, 't'}, + {"short-interval", required_argument, 0, 's'}, + {"rss-threshold", required_argument, 0, 'r'}, + {"long-interval", required_argument, 0, 'l'}, + {"btm-queries", required_argument, 0, 'b'}, + {"iface", required_argument, 0, 'i'}, + {0, 0, 0, 0}}; + unsigned long uval; + long val; + + while ((opt = getopt_long(argc, argv, "t:s:r:l:b:i:", long_options, &opt_index)) != -1) { + state = getopt_state_get(); + switch (opt) { + case 't': + if (strcmp("simple", state->optarg) == 0) { + params->type = WIFI_BGSCAN_SIMPLE; + } else if (strcmp("learn", state->optarg) == 0) { + params->type = WIFI_BGSCAN_LEARN; + } else if (strcmp("none", state->optarg) == 0) { + params->type = WIFI_BGSCAN_NONE; + } else { + PR_ERROR("Invalid type %s\n", state->optarg); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + break; + case 's': + uval = shell_strtoul(state->optarg, 10, &err); + if (err < 0) { + PR_ERROR("Invalid short interval %s\n", state->optarg); + return err; + } + params->short_interval = uval; + break; + case 'l': + uval = shell_strtoul(state->optarg, 10, &err); + if (err < 0) { + PR_ERROR("Invalid long interval %s\n", state->optarg); + return err; + } + params->long_interval = uval; + break; + case 'b': + uval = shell_strtoul(state->optarg, 10, &err); + if (err < 0) { + PR_ERROR("Invalid BTM queries %s\n", state->optarg); + return err; + } + params->btm_queries = uval; + break; + case 'r': + val = shell_strtol(state->optarg, 10, &err); + if (err < 0) { + PR_ERROR("Invalid RSSI threshold %s\n", state->optarg); + return err; + } + params->rssi_threshold = val; + break; + case 'i': + /* Unused, but parsing to avoid unknown option error */ + break; + default: + PR_ERROR("Invalid option %c\n", state->optopt); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + } + + return 0; +} + +static int cmd_wifi_set_bgscan(const struct shell *sh, size_t argc, char *argv[]) +{ + struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv); + struct wifi_bgscan_params bgscan_params = { + .type = WIFI_BGSCAN_NONE, + .short_interval = 30, + .long_interval = 300, + .rssi_threshold = 0, + .btm_queries = 0, + }; + int ret; + + if (wifi_bgscan_args_to_params(sh, argc, argv, &bgscan_params) != 0) { + return -ENOEXEC; + } + + ret = net_mgmt(NET_REQUEST_WIFI_BGSCAN, iface, &bgscan_params, + sizeof(struct wifi_bgscan_params)); + if (ret != 0) { + PR_WARNING("Setting background scanning parameters failed: %s\n", strerror(-ret)); + return -ENOEXEC; + } + + return 0; +} +#endif + static int wifi_config_args_to_params(const struct shell *sh, size_t argc, char *argv[], struct wifi_config_params *params) { @@ -4112,6 +4803,104 @@ SHELL_SUBCMD_ADD((wifi), bss_max_idle_period, NULL, cmd_wifi_set_bss_max_idle_period, 2, 2); +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN +SHELL_SUBCMD_ADD((wifi), bgscan, NULL, + "Configure background scanning.\n" + "<-t, --type simple/learn/none> : The scanning type, use none to disable.\n" + "[-s, --short-interval ] : Short scan interval (default: 30).\n" + "[-l, --long-interval ] : Long scan interval (default: 300).\n" + "[-r, --rssi-threshold ] : Signal strength threshold (default: disabled).\n" + "[-b, --btm-queries ] : BTM queries before scanning (default: disabled).\n" + "[-i, --iface=] : Interface index.\n", + cmd_wifi_set_bgscan, + 2, 6); +#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_BGSCAN */ + +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P +SHELL_STATIC_SUBCMD_SET_CREATE( + wifi_cmd_p2p, + SHELL_CMD_ARG(find, NULL, + "Start P2P device discovery\n" + "[-t, --timeout=]: Discovery timeout\n" + "[-T, --type=<0|1|2>]: Discovery type\n" + " 0: Social channels only (1, 6, 11)\n" + " 1: Progressive scan (all channels)\n" + " 2: Full scan first, then social (default)\n" + "[-i, --iface=]: Interface index\n" + "[-h, --help]: Show help\n", + cmd_wifi_p2p_find, 1, 6), + SHELL_CMD_ARG(stop_find, NULL, + "Stop P2P device discovery\n" + "[-i, --iface=]: Interface index\n", + cmd_wifi_p2p_stop_find, 1, 2), + SHELL_CMD_ARG(peer, NULL, + "Show information about P2P peers\n" + "Usage: peer []\n" + ": Show detailed info for specific peer (format: XX:XX:XX:XX:XX:XX)\n" + "[-i, --iface=]: Interface index\n", + cmd_wifi_p2p_peer, 1, 3), + SHELL_CMD_ARG(connect, NULL, + "Connect to a P2P peer\n" + "Usage: connect [PIN] [options]\n" + ": Peer device MAC address (format: XX:XX:XX:XX:XX:XX)\n" + ": Use Push Button Configuration\n" + ": Use PIN method\n" + " - Without PIN: Device displays generated PIN for peer to enter\n" + " - With PIN: Device uses provided PIN to connect\n" + "[PIN]: 8-digit PIN (optional, generates if omitted)\n" + "[-g, --go-intent=<0-15>]: GO intent (0=client, 15=GO, default: 0)\n" + "[-f, --freq=]: Frequency in MHz (default: 2462)\n" + "[-i, --iface=]: Interface index\n" + "[-h, --help]: Show help\n" + "Examples:\n" + " wifi p2p connect 9c:b1:50:e3:81:96 pin -g 0 (displays PIN)\n" + " wifi p2p connect 9c:b1:50:e3:81:96 pin 12345670 -g 0 (uses PIN)\n", + cmd_wifi_p2p_connect, 3, 5), + SHELL_CMD_ARG(group_add, NULL, + "Add a P2P group (start as GO)\n" + "Usage: group_add [options]\n" + "[-f, --freq=]: Frequency in MHz (0 = auto)\n" + "[-p, --persistent=]: Persistent group ID (-1 = not persistent)\n" + "[-h, --ht40]: Enable HT40\n" + "[-v, --vht]: Enable VHT (also enables HT40)\n" + "[-H, --he]: Enable HE\n" + "[-e, --edmg]: Enable EDMG\n" + "[-b, --go-bssid=]: GO BSSID (format: XX:XX:XX:XX:XX:XX)\n" + "[-i, --iface=]: Interface index\n", + cmd_wifi_p2p_group_add, 1, 10), + SHELL_CMD_ARG(group_remove, NULL, + "Remove a P2P group\n" + "Usage: group_remove \n" + ": Interface name (e.g., wlan0)\n" + "[-i, --iface=]: Interface index\n", + cmd_wifi_p2p_group_remove, 2, 3), + SHELL_CMD_ARG(invite, NULL, + "Invite a peer to a P2P group\n" + "Usage: invite --persistent= OR\n" + " invite --group= --peer= [options]\n" + "[-p, --persistent=]: Persistent group ID\n" + "[-g, --group=]: Group interface name\n" + "[-P, --peer=]: Peer MAC address (format: XX:XX:XX:XX:XX:XX)\n" + "[-f, --freq=]: Frequency in MHz (0 = auto)\n" + "[-d, --go-dev-addr=]: GO device address (for group type)\n" + "[-i, --iface=]: Interface index\n", + cmd_wifi_p2p_invite, 2, 8), + SHELL_CMD_ARG(power_save, NULL, + "Set P2P power save mode\n" + "Usage: power_save \n" + ": Enable P2P power save\n" + ": Disable P2P power save\n" + "[-i, --iface=]: Interface index\n", + cmd_wifi_p2p_power_save, 2, 3), + SHELL_SUBCMD_SET_END +); + +SHELL_SUBCMD_ADD((wifi), p2p, &wifi_cmd_p2p, + "Wi-Fi Direct (P2P) commands.", + NULL, + 0, 0); +#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ + SHELL_SUBCMD_ADD((wifi), config, NULL, "Configure STA parameters.\n" "-o, --okc=<0/1>: Opportunistic Key Caching. 0: disable, 1: enable\n" diff --git a/subsys/usb/device_next/class/Kconfig.msc b/subsys/usb/device_next/class/Kconfig.msc index d85d0561cbf4..d4ff01cf17b1 100644 --- a/subsys/usb/device_next/class/Kconfig.msc +++ b/subsys/usb/device_next/class/Kconfig.msc @@ -30,6 +30,13 @@ config USBD_MSC_SCSI_BUFFER_SIZE Buffer size must be able to hold at least one sector. All LUNs within single instance share the SCSI buffer. +config USBD_MSC_DOUBLE_BUFFERING + bool "SCSI double buffering" + default y + help + Allocate two SCSI buffers instead of one to increase throughput by + using one buffer by disk subsystem and one by USB at the same time. + module = USBD_MSC module-str = usbd msc default-count = 1 diff --git a/subsys/usb/device_next/class/usbd_msc.c b/subsys/usb/device_next/class/usbd_msc.c index 6e6c75f671e9..6aefb1aefb64 100644 --- a/subsys/usb/device_next/class/usbd_msc.c +++ b/subsys/usb/device_next/class/usbd_msc.c @@ -60,9 +60,14 @@ struct CSW { /* Single instance is likely enough because it can support multiple LUNs */ #define MSC_NUM_INSTANCES CONFIG_USBD_MSC_INSTANCES_COUNT -UDC_BUF_POOL_DEFINE(msc_ep_pool, - MSC_NUM_INSTANCES * 2, USBD_MAX_BULK_MPS, - sizeof(struct udc_buf_info), NULL); +#define MSC_NUM_BUFFERS UTIL_INC(IS_ENABLED(CONFIG_USBD_MSC_DOUBLE_BUFFERING)) + +#if USBD_MAX_BULK_MPS > CONFIG_USBD_MSC_SCSI_BUFFER_SIZE +#error "SCSI buffer must be at least USB bulk endpoint wMaxPacketSize" +#endif + +UDC_BUF_POOL_DEFINE(msc_ep_pool, MSC_NUM_INSTANCES * (1 + MSC_NUM_BUFFERS), + 0, sizeof(struct udc_buf_info), NULL); struct msc_event { struct usbd_class_data *c_data; @@ -91,8 +96,6 @@ struct msc_bot_desc { enum { MSC_CLASS_ENABLED, - MSC_BULK_OUT_QUEUED, - MSC_BULK_IN_QUEUED, MSC_BULK_IN_WEDGED, MSC_BULK_OUT_WEDGED, }; @@ -112,33 +115,20 @@ struct msc_bot_ctx { struct msc_bot_desc *const desc; const struct usb_desc_header **const fs_desc; const struct usb_desc_header **const hs_desc; + uint8_t *scsi_bufs[MSC_NUM_BUFFERS]; atomic_t bits; enum msc_bot_state state; + uint8_t scsi_bufs_used; + uint8_t num_in_queued; + uint8_t num_out_queued; uint8_t registered_luns; struct scsi_ctx luns[CONFIG_USBD_MSC_LUNS_PER_INSTANCE]; struct CBW cbw; struct CSW csw; - uint8_t *scsi_buf; uint32_t transferred_data; size_t scsi_bytes; }; -static struct net_buf *msc_buf_alloc(const uint8_t ep) -{ - struct net_buf *buf = NULL; - struct udc_buf_info *bi; - - buf = net_buf_alloc(&msc_ep_pool, K_NO_WAIT); - if (!buf) { - return NULL; - } - - bi = udc_get_buf_info(buf); - bi->ep = ep; - - return buf; -} - static struct net_buf *msc_buf_alloc_data(const uint8_t ep, uint8_t *data, size_t len) { struct net_buf *buf = NULL; @@ -160,13 +150,34 @@ static struct net_buf *msc_buf_alloc_data(const uint8_t ep, uint8_t *data, size_ return buf; } -static size_t msc_next_transfer_length(struct usbd_class_data *const c_data) +static uint8_t *msc_alloc_scsi_buf(struct msc_bot_ctx *ctx) { - struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data); - struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); - struct scsi_ctx *lun = &ctx->luns[ctx->cbw.bCBWLUN]; - size_t len = scsi_cmd_remaining_data_len(lun); + for (int i = 0; i < MSC_NUM_BUFFERS; i++) { + if (!(ctx->scsi_bufs_used & BIT(i))) { + ctx->scsi_bufs_used |= BIT(i); + return ctx->scsi_bufs[i]; + } + } + + /* Code must not attempt to queue more than MSC_NUM_BUFFERS at once */ + __ASSERT(false, "MSC ran out of SCSI buffers"); + return NULL; +} + +void msc_free_scsi_buf(struct msc_bot_ctx *ctx, uint8_t *buf) +{ + for (int i = 0; i < MSC_NUM_BUFFERS; i++) { + if (buf == ctx->scsi_bufs[i]) { + ctx->scsi_bufs_used &= ~BIT(i); + return; + } + } +} +static size_t clamp_transfer_length(struct usbd_context *uds_ctx, + struct scsi_ctx *lun, + size_t len) +{ len = MIN(CONFIG_USBD_MSC_SCSI_BUFFER_SIZE, len); /* Limit transfer to bulk endpoint wMaxPacketSize multiple */ @@ -186,6 +197,39 @@ static size_t msc_next_transfer_length(struct usbd_class_data *const c_data) return len; } +static size_t msc_next_in_transfer_length(struct usbd_class_data *const c_data) +{ + struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data); + struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); + struct scsi_ctx *lun = &ctx->luns[ctx->cbw.bCBWLUN]; + size_t len = scsi_cmd_remaining_data_len(lun); + + return clamp_transfer_length(uds_ctx, lun, len); +} + +static size_t msc_next_out_transfer_length(struct usbd_class_data *const c_data) +{ + struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data); + struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); + struct scsi_ctx *lun = &ctx->luns[ctx->cbw.bCBWLUN]; + size_t remaining = scsi_cmd_remaining_data_len(lun); + size_t len = clamp_transfer_length(uds_ctx, lun, remaining); + + /* This function can only estimate one more transfer after the current + * one. Queueing more buffers is not supported. + */ + __ASSERT_NO_MSG(ctx->num_out_queued < 2); + + if (ctx->num_out_queued == 0) { + return len; + } + + /* MSC BOT specification requires host to send all the data it intends + * to send. Therefore it should be safe to use "remaining - len" here. + */ + return clamp_transfer_length(uds_ctx, lun, remaining - len); +} + static uint8_t msc_get_bulk_in(struct usbd_class_data *const c_data) { struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data); @@ -214,27 +258,86 @@ static uint8_t msc_get_bulk_out(struct usbd_class_data *const c_data) return desc->if0_out_ep.bEndpointAddress; } -static void msc_queue_bulk_out_ep(struct usbd_class_data *const c_data, bool data) +static void msc_stall_bulk_out_ep(struct usbd_class_data *const c_data) +{ + uint8_t ep; + + ep = msc_get_bulk_out(c_data); + usbd_ep_set_halt(usbd_class_get_ctx(c_data), ep); +} + +static void msc_stall_bulk_in_ep(struct usbd_class_data *const c_data) +{ + uint8_t ep; + + ep = msc_get_bulk_in(c_data); + usbd_ep_set_halt(usbd_class_get_ctx(c_data), ep); +} + +static void msc_stall_and_wait_for_recovery(struct msc_bot_ctx *ctx) +{ + atomic_set_bit(&ctx->bits, MSC_BULK_IN_WEDGED); + atomic_set_bit(&ctx->bits, MSC_BULK_OUT_WEDGED); + msc_stall_bulk_in_ep(ctx->class_node); + msc_stall_bulk_out_ep(ctx->class_node); + ctx->state = MSC_BBB_WAIT_FOR_RESET_RECOVERY; +} + +static void msc_queue_write(struct msc_bot_ctx *ctx) +{ + struct net_buf *buf; + uint8_t *scsi_buf; + uint8_t ep; + size_t len; + int ret; + + ep = msc_get_bulk_out(ctx->class_node); + + /* Ensure there are as many OUT transfers queued as possible */ + while ((ctx->num_out_queued < MSC_NUM_BUFFERS) && + (len = msc_next_out_transfer_length(ctx->class_node))) { + scsi_buf = msc_alloc_scsi_buf(ctx); + buf = msc_buf_alloc_data(ep, scsi_buf, len); + + /* The pool is large enough to support all allocations. Failing + * alloc indicates either a memory leak or logic error. + */ + __ASSERT_NO_MSG(buf); + + ret = usbd_ep_enqueue(ctx->class_node, buf); + if (ret) { + LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep); + net_buf_unref(buf); + msc_free_scsi_buf(ctx, scsi_buf); + /* 6.6.2 Internal Device Error */ + msc_stall_and_wait_for_recovery(ctx); + return; + } + + ctx->num_out_queued++; + } +} + +static void msc_queue_cbw(struct usbd_class_data *const c_data) { struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); struct net_buf *buf; - uint8_t *scsi_buf = ctx->scsi_buf; + uint8_t *scsi_buf; uint8_t ep; int ret; - if (atomic_test_and_set_bit(&ctx->bits, MSC_BULK_OUT_QUEUED)) { + if (ctx->num_out_queued) { /* Already queued */ return; } + __ASSERT(ctx->scsi_bufs_used == 0, + "CBW can only be queued when SCSI buffers are free"); + LOG_DBG("Queuing OUT"); ep = msc_get_bulk_out(c_data); - - if (data) { - buf = msc_buf_alloc_data(ep, scsi_buf, msc_next_transfer_length(c_data)); - } else { - buf = msc_buf_alloc(ep); - } + scsi_buf = msc_alloc_scsi_buf(ctx); + buf = msc_buf_alloc_data(ep, scsi_buf, USBD_MAX_BULK_MPS); /* The pool is large enough to support all allocations. Failing alloc * indicates either a memory leak or logic error. @@ -245,26 +348,14 @@ static void msc_queue_bulk_out_ep(struct usbd_class_data *const c_data, bool dat if (ret) { LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep); net_buf_unref(buf); - atomic_clear_bit(&ctx->bits, MSC_BULK_OUT_QUEUED); + msc_free_scsi_buf(ctx, scsi_buf); + /* 6.6.2 Internal Device Error */ + msc_stall_and_wait_for_recovery(ctx); + } else { + ctx->num_out_queued++; } } -static void msc_stall_bulk_out_ep(struct usbd_class_data *const c_data) -{ - uint8_t ep; - - ep = msc_get_bulk_out(c_data); - usbd_ep_set_halt(usbd_class_get_ctx(c_data), ep); -} - -static void msc_stall_bulk_in_ep(struct usbd_class_data *const c_data) -{ - uint8_t ep; - - ep = msc_get_bulk_in(c_data); - usbd_ep_set_halt(usbd_class_get_ctx(c_data), ep); -} - static void msc_reset_handler(struct usbd_class_data *c_data) { struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); @@ -300,49 +391,58 @@ static bool is_cbw_meaningful(struct msc_bot_ctx *const ctx) return true; } -static void msc_process_read(struct msc_bot_ctx *ctx) +static void msc_queue_bulk_in_ep(struct msc_bot_ctx *ctx, uint8_t *data, int len) { - struct scsi_ctx *lun = &ctx->luns[ctx->cbw.bCBWLUN]; - int bytes_queued = 0; struct net_buf *buf; - uint8_t *scsi_buf = ctx->scsi_buf; uint8_t ep; int ret; - /* Fill SCSI Data IN buffer if there is no data available */ - if (ctx->scsi_bytes == 0) { - size_t len = msc_next_transfer_length(ctx->class_node); - - bytes_queued = scsi_read_data(lun, scsi_buf, len); - } else { - bytes_queued = ctx->scsi_bytes; - } - - /* All data is submitted in one go. Any potential new data will - * have to be retrieved using scsi_read_data() on next call. - */ - ctx->scsi_bytes = 0; - - if (atomic_test_and_set_bit(&ctx->bits, MSC_BULK_IN_QUEUED)) { - __ASSERT_NO_MSG(false); - LOG_ERR("IN already queued"); - return; - } - ep = msc_get_bulk_in(ctx->class_node); - buf = msc_buf_alloc_data(ep, scsi_buf, bytes_queued); + buf = msc_buf_alloc_data(ep, data, len); /* The pool is large enough to support all allocations. Failing alloc * indicates either a memory leak or logic error. */ __ASSERT_NO_MSG(buf); /* Either the net buf is full or there is no more SCSI data */ - ctx->csw.dCSWDataResidue -= bytes_queued; + ctx->csw.dCSWDataResidue -= len; ret = usbd_ep_enqueue(ctx->class_node, buf); if (ret) { LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep); + msc_free_scsi_buf(ctx, data); net_buf_unref(buf); - atomic_clear_bit(&ctx->bits, MSC_BULK_IN_QUEUED); + /* 6.6.2 Internal Device Error */ + msc_stall_and_wait_for_recovery(ctx); + } else { + ctx->num_in_queued++; + } +} + +static void msc_process_read(struct msc_bot_ctx *ctx) +{ + struct scsi_ctx *lun = &ctx->luns[ctx->cbw.bCBWLUN]; + int bytes_queued = 0; + uint8_t *scsi_buf; + size_t len; + + /* Data can be already in scsi_buf0 only on first call after CBW */ + if (ctx->scsi_bytes) { + __ASSERT_NO_MSG(ctx->scsi_bufs_used == 0); + ctx->scsi_bufs_used = BIT(0); + msc_queue_bulk_in_ep(ctx, ctx->scsi_bufs[0], ctx->scsi_bytes); + /* All data is submitted in one go. Any potential new data will + * have to be retrieved using scsi_read_data() later. + */ + ctx->scsi_bytes = 0; + } + + /* Fill SCSI Data IN buffer if there is avaialble buffer and data */ + while ((ctx->num_in_queued < MSC_NUM_BUFFERS) && + (ctx->state == MSC_BBB_PROCESS_READ) && + (len = msc_next_in_transfer_length(ctx->class_node))) { + scsi_buf = msc_alloc_scsi_buf(ctx); + bytes_queued = scsi_read_data(lun, scsi_buf, len); + msc_queue_bulk_in_ep(ctx, scsi_buf, bytes_queued); } } @@ -353,8 +453,11 @@ static void msc_process_cbw(struct msc_bot_ctx *ctx) size_t data_len; int cb_len; + /* All SCSI buffers must be available */ + __ASSERT_NO_MSG(ctx->scsi_bufs_used == 0); + cb_len = scsi_usb_boot_cmd_len(ctx->cbw.CBWCB, ctx->cbw.bCBWCBLength); - data_len = scsi_cmd(lun, ctx->cbw.CBWCB, cb_len, ctx->scsi_buf); + data_len = scsi_cmd(lun, ctx->cbw.CBWCB, cb_len, ctx->scsi_bufs[0]); ctx->scsi_bytes = data_len; cmd_is_data_read = scsi_cmd_is_data_read(lun); cmd_is_data_write = scsi_cmd_is_data_write(lun); @@ -500,11 +603,7 @@ static void msc_handle_bulk_out(struct msc_bot_ctx *ctx, } else { /* 6.6.1 CBW Not Valid */ LOG_INF("Invalid CBW"); - atomic_set_bit(&ctx->bits, MSC_BULK_IN_WEDGED); - atomic_set_bit(&ctx->bits, MSC_BULK_OUT_WEDGED); - msc_stall_bulk_in_ep(ctx->class_node); - msc_stall_bulk_out_ep(ctx->class_node); - ctx->state = MSC_BBB_WAIT_FOR_RESET_RECOVERY; + msc_stall_and_wait_for_recovery(ctx); } } else if (ctx->state == MSC_BBB_PROCESS_WRITE) { msc_process_write(ctx, buf, len); @@ -521,7 +620,7 @@ static void msc_handle_bulk_in(struct msc_bot_ctx *ctx, struct scsi_ctx *lun = &ctx->luns[ctx->cbw.bCBWLUN]; ctx->transferred_data += len; - if (msc_next_transfer_length(ctx->class_node) == 0) { + if (msc_next_in_transfer_length(ctx->class_node) == 0) { if (ctx->csw.dCSWDataResidue > 0) { /* Case (5) Hi > Di * While we may have sent short packet, device @@ -543,32 +642,41 @@ static void msc_handle_bulk_in(struct msc_bot_ctx *ctx, static void msc_send_csw(struct msc_bot_ctx *ctx) { struct net_buf *buf; + uint8_t *scsi_buf; uint8_t ep; int ret; - if (atomic_test_and_set_bit(&ctx->bits, MSC_BULK_IN_QUEUED)) { + if (ctx->num_in_queued) { __ASSERT_NO_MSG(false); LOG_ERR("IN already queued"); return; } + __ASSERT(ctx->scsi_bufs_used == 0, + "CSW can be sent only if SCSI buffers are free"); + /* Convert dCSWDataResidue to LE, other fields are already set */ ctx->csw.dCSWDataResidue = sys_cpu_to_le32(ctx->csw.dCSWDataResidue); ep = msc_get_bulk_in(ctx->class_node); - buf = msc_buf_alloc(ep); + scsi_buf = msc_alloc_scsi_buf(ctx); + memcpy(scsi_buf, &ctx->csw, sizeof(ctx->csw)); + buf = msc_buf_alloc_data(ep, scsi_buf, sizeof(ctx->csw)); /* The pool is large enough to support all allocations. Failing alloc * indicates either a memory leak or logic error. */ __ASSERT_NO_MSG(buf); - net_buf_add_mem(buf, &ctx->csw, sizeof(ctx->csw)); ret = usbd_ep_enqueue(ctx->class_node, buf); if (ret) { LOG_ERR("Failed to enqueue net_buf for 0x%02x", ep); net_buf_unref(buf); - atomic_clear_bit(&ctx->bits, MSC_BULK_IN_QUEUED); + msc_free_scsi_buf(ctx, scsi_buf); + /* 6.6.2 Internal Device Error */ + msc_stall_and_wait_for_recovery(ctx); + } else { + ctx->num_in_queued++; + ctx->state = MSC_BBB_WAIT_FOR_CSW_SENT; } - ctx->state = MSC_BBB_WAIT_FOR_CSW_SENT; } static void usbd_msc_handle_request(struct usbd_class_data *c_data, @@ -599,9 +707,19 @@ static void usbd_msc_handle_request(struct usbd_class_data *c_data, ep_request_error: if (bi->ep == msc_get_bulk_out(c_data)) { - atomic_clear_bit(&ctx->bits, MSC_BULK_OUT_QUEUED); + ctx->num_out_queued--; + if (buf->frags) { + ctx->num_out_queued--; + } } else if (bi->ep == msc_get_bulk_in(c_data)) { - atomic_clear_bit(&ctx->bits, MSC_BULK_IN_QUEUED); + ctx->num_in_queued--; + if (buf->frags) { + ctx->num_in_queued--; + } + } + msc_free_scsi_buf(ctx, buf->__buf); + if (buf->frags) { + msc_free_scsi_buf(ctx, buf->frags->__buf); } usbd_ep_buf_free(uds_ctx, buf); } @@ -630,11 +748,14 @@ static void usbd_msc_thread(void *arg1, void *arg2, void *arg3) switch (ctx->state) { case MSC_BBB_EXPECT_CBW: - msc_queue_bulk_out_ep(evt.c_data, false); + msc_queue_cbw(evt.c_data); break; case MSC_BBB_PROCESS_WRITE: /* Ensure we can accept next OUT packet */ - msc_queue_bulk_out_ep(evt.c_data, true); + msc_queue_write(ctx); + break; + case MSC_BBB_PROCESS_READ: + msc_process_read(ctx); break; default: break; @@ -643,7 +764,7 @@ static void usbd_msc_thread(void *arg1, void *arg2, void *arg3) /* Skip (potentially) response generating code if there is * IN data already available for the host to pick up. */ - if (atomic_test_bit(&ctx->bits, MSC_BULK_IN_QUEUED)) { + if (ctx->num_in_queued) { continue; } @@ -654,7 +775,7 @@ static void usbd_msc_thread(void *arg1, void *arg2, void *arg3) if (ctx->state == MSC_BBB_PROCESS_READ) { msc_process_read(ctx); } else if (ctx->state == MSC_BBB_PROCESS_WRITE) { - msc_queue_bulk_out_ep(evt.c_data, true); + msc_queue_write(ctx); } else if (ctx->state == MSC_BBB_SEND_CSW) { msc_send_csw(ctx); } @@ -873,14 +994,27 @@ struct usbd_class_api msc_bot_api = { .init = msc_bot_init, }; +#define BUF_NAME(x, i) scsi_buf##i##_##x + +#define DEFINE_SCSI_BUF(x, i) \ + UDC_STATIC_BUF_DEFINE(BUF_NAME(x, i), CONFIG_USBD_MSC_SCSI_BUFFER_SIZE); + +#define DEFINE_SCSI_BUFS(x) \ + DEFINE_SCSI_BUF(x, 0) \ + IF_ENABLED(CONFIG_USBD_MSC_DOUBLE_BUFFERING, (DEFINE_SCSI_BUF(x, 1))) + +#define NAME_SCSI_BUFS(x) \ + BUF_NAME(x, 0) \ + IF_ENABLED(CONFIG_USBD_MSC_DOUBLE_BUFFERING, (, BUF_NAME(x, 1))) + #define DEFINE_MSC_BOT_CLASS_DATA(x, _) \ - UDC_STATIC_BUF_DEFINE(scsi_buf_##x, CONFIG_USBD_MSC_SCSI_BUFFER_SIZE); \ + DEFINE_SCSI_BUFS(x) \ \ static struct msc_bot_ctx msc_bot_ctx_##x = { \ .desc = &msc_bot_desc_##x, \ .fs_desc = msc_bot_fs_desc_##x, \ .hs_desc = msc_bot_hs_desc_##x, \ - .scsi_buf = scsi_buf_##x \ + .scsi_bufs = { NAME_SCSI_BUFS(x) }, \ }; \ \ USBD_DEFINE_CLASS(msc_##x, &msc_bot_api, &msc_bot_ctx_##x, \ diff --git a/tests/subsys/dfu/img_util/src/main.c b/tests/subsys/dfu/img_util/src/main.c index 33956be6251e..c0b5d96daeb1 100644 --- a/tests/subsys/dfu/img_util/src/main.c +++ b/tests/subsys/dfu/img_util/src/main.c @@ -6,6 +6,7 @@ */ #include +#include #include #include @@ -13,6 +14,8 @@ #define SLOT1_PARTITION slot1_partition #define FIXED_PARTITION_IS_RUNNING_APP_PARTITION(label) \ + DT_SAME_NODE(FIXED_PARTITION_NODE_MTD(DT_CHOSEN(zephyr_code_partition)), \ + FIXED_PARTITION_MTD(label)) && \ (FIXED_PARTITION_OFFSET(label) <= CONFIG_FLASH_LOAD_OFFSET && \ FIXED_PARTITION_OFFSET(label) + FIXED_PARTITION_SIZE(label) > CONFIG_FLASH_LOAD_OFFSET) diff --git a/west.yml b/west.yml index a00bfc9e1318..8eb988998a78 100644 --- a/west.yml +++ b/west.yml @@ -281,7 +281,7 @@ manifest: - hal - name: hostap path: modules/lib/hostap - revision: 6086dea5ee7406e1eede7f2ca6dff1b00b0f04e2 + revision: 528eb2d95e35c7c9b187a15d2fb7f6e5bb983181 - name: liblc3 revision: 48bbd3eacd36e99a57317a0a4867002e0b09e183 path: modules/lib/liblc3 @@ -337,7 +337,7 @@ manifest: revision: 40403f5f2805cca210d2a47c8717d89c4e816cda path: modules/bsim_hw_models/nrf_hw_models - name: nrf_wifi - revision: e269670cd17fb8ccc4b7004544276bc7d9578496 + revision: f0b6706cac522371e651f589d53d3026cc6f97dd path: modules/lib/nrf_wifi - name: open-amp revision: c30a6d8b92fcebdb797fc1a7698e8729e250f637