From 061e1e64f54c383c1205e54dd33064a34be77ed4 Mon Sep 17 00:00:00 2001 From: Ravi Dondaputi Date: Mon, 8 Sep 2025 18:42:08 +0530 Subject: [PATCH 01/24] drivers: wifi: nrf_wifi: Set SSID for P2P discovery Use `ssids` instead of `filter_ssids` to set the SSID in probe requests. `filter_ssids` are to filter scan results to include only the specified SSIDs. Signed-off-by: Ravi Dondaputi --- drivers/wifi/nrf_wifi/src/wpa_supp_if.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/wifi/nrf_wifi/src/wpa_supp_if.c b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c index f913558ffea57..1421062cb230f 100644 --- a/drivers/wifi/nrf_wifi/src/wpa_supp_if.c +++ b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c @@ -545,16 +545,16 @@ 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; } } From a161076f5230cfb416217d965d4d6e900b151c7e Mon Sep 17 00:00:00 2001 From: Ravi Dondaputi Date: Tue, 14 Oct 2025 12:09:51 +0530 Subject: [PATCH 02/24] drivers: wifi: nrf_wifi: Set P2P capability In P2P mode, inform supplicant that the driver is P2P capable. Signed-off-by: Ravi Dondaputi --- drivers/wifi/nrf_wifi/src/wpa_supp_if.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/wifi/nrf_wifi/src/wpa_supp_if.c b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c index 1421062cb230f..da63be115cdd2 100644 --- a/drivers/wifi/nrf_wifi/src/wpa_supp_if.c +++ b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c @@ -1798,6 +1798,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 | From 0075c14a2b59f29dacff6c8c472276e73683ae64 Mon Sep 17 00:00:00 2001 From: Kapil Bhatt Date: Thu, 9 Oct 2025 17:16:51 +0000 Subject: [PATCH 03/24] net: wifi: Add Wi-Fi direct P2P discovery API support Add supplicant api and mgmt ops support for P2P discovery. Signed-off-by: Kapil Bhatt --- include/zephyr/net/wifi_mgmt.h | 113 ++++++++++++++- modules/hostap/src/supp_api.c | 241 +++++++++++++++++++++++++++++++ modules/hostap/src/supp_api.h | 12 ++ modules/hostap/src/supp_events.c | 54 ++++++- modules/hostap/src/supp_events.h | 7 + modules/hostap/src/supp_main.c | 9 ++ subsys/net/l2/wifi/Kconfig | 9 ++ subsys/net/l2/wifi/wifi_mgmt.c | 29 ++++ 8 files changed, 471 insertions(+), 3 deletions(-) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 817a4fcd6fb65..0f3ce008564e9 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -139,6 +139,8 @@ enum net_request_wifi_cmd { 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 */ @@ -339,6 +341,11 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_BSS_MAX_IDLE_PERIOD); 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 { @@ -359,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, }; @@ -406,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 */ @@ -468,6 +477,38 @@ 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 +/** @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[33]; + /** Primary device type */ + uint8_t pri_dev_type[8]; + /** Primary device type string */ + char pri_dev_type_str[32]; + /** Signal strength (RSSI) */ + int8_t rssi; + /** WPS configuration methods supported */ + uint16_t config_methods; + /** WPS configuration methods string */ + char config_methods_str[16]; + /** Device capability */ + uint8_t dev_capab; + /** Group capability */ + uint8_t group_capab; + /** Manufacturer (max 64 chars + null terminator) */ + char manufacturer[65]; + /** Model name (max 32 chars + null terminator) */ + char model_name[33]; +}; +#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ + /** @brief Wi-Fi version */ struct wifi_version { /** Driver version */ @@ -1114,6 +1155,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 */ @@ -1397,6 +1441,51 @@ 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, +}; + +/** 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, +}; + +/** 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; +}; +#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ + /** Wi-Fi AP status */ enum wifi_sap_iface_state { @@ -1785,6 +1874,17 @@ struct wifi_mgmt_ops { */ 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 */ @@ -1916,6 +2016,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/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c index b5ae00e0a871e..f02688a511546 100644 --- a/modules/hostap/src/supp_api.c +++ b/modules/hostap/src/supp_api.c @@ -60,6 +60,15 @@ enum status_thread_state { static struct wifi_enterprise_creds_params enterprise_creds; #endif +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P +/* TODO: Define size with references */ +#define P2P_CMD_BUF_SIZE 256 +#define P2P_RESP_BUF_SIZE 256 +#define P2P_ADDR_SIZE 32 +#define P2P_CMD_SIZE 64 +#define P2P_PEER_INFO_SIZE 512 +#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ + K_MUTEX_DEFINE(wpa_supplicant_mutex); extern struct k_work_q *get_workq(void); @@ -2586,3 +2595,235 @@ 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) { + pos = line + 6; + /* Skip extraction for numeric values, atoi handles it */ + info->rssi = (int8_t)atoi(pos); + } else if (strncmp(line, "config_methods=", 15) == 0) { + 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')) { + info->config_methods = (uint16_t)strtol(pos, NULL, 16); + } else { + info->config_methods = (uint16_t)atoi(pos); + } + } 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) { + snprintf(cmd_buf, sizeof(cmd_buf), "P2P_FIND %u %s", + params->timeout, discovery_type_str); + } else { + snprintf(cmd_buf, sizeof(cmd_buf), "P2P_FIND %u", + params->timeout); + } + } else { + if (strlen(discovery_type_str) > 0) { + snprintf(cmd_buf, sizeof(cmd_buf), "P2P_FIND %s", + discovery_type_str); + } else { + snprintf(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: + snprintf(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; + } + + snprintf(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]); + snprintf(cmd_buf, sizeof(cmd_buf), "P2P_PEER %s", addr_str); + + ret = zephyr_wpa_cli_cmd_resp_noprint(wpa_s->ctrl_conn, + cmd_buf, resp_buf); + if (ret < 0) { + wpa_printf(MSG_ERROR, "P2P_PEER command failed: %d", ret); + return -EIO; + } + if (os_strncmp(resp_buf, "FAIL", 4) == 0) { + wpa_printf(MSG_ERROR, "Peer %s not found", addr_str); + return -ENODEV; + } + parse_peer_info_response(resp_buf, params->peer_addr, + ¶ms->peers[0]); + params->peer_count = 1; + } + 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 8ab49f177e708..692db61bf277f 100644 --- a/modules/hostap/src/supp_api.h +++ b/modules/hostap/src/supp_api.h @@ -386,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 c4175a416bea3..ee6a05a568ec5 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 1c74af528492f..6ff8812c2fb83 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 d1f8c360cb503..8afdba33b2030 100644 --- a/modules/hostap/src/supp_main.c +++ b/modules/hostap/src/supp_main.c @@ -101,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); @@ -245,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/subsys/net/l2/wifi/Kconfig b/subsys/net/l2/wifi/Kconfig index 63680dba9b30a..eddfb7d4c30a1 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 b20e5d6674d26..3f08c6ed476be 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -1474,6 +1474,35 @@ static int wifi_set_bgscan(uint64_t mgmt_request, struct net_if *iface, void *da 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, From 081ac4b3849fbf1e59f068251abc1219fd76ec2e Mon Sep 17 00:00:00 2001 From: Kapil Bhatt Date: Wed, 29 Oct 2025 13:08:44 +0000 Subject: [PATCH 04/24] net: wifi: Add Wi-Fi direct P2P discovery shell command support Add shell command support for P2P discovery. Signed-off-by: Kapil Bhatt --- subsys/net/l2/wifi/wifi_shell.c | 234 +++++++++++++++++++++++++++++++- 1 file changed, 233 insertions(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index e296a98d8eeee..1e858f56b1798 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,180 @@ 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; +} +#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); @@ -4232,6 +4432,38 @@ SHELL_SUBCMD_ADD((wifi), bgscan, NULL, 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_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" From 1e765b79faca1f55b1074f1978b8464e440ad7a2 Mon Sep 17 00:00:00 2001 From: Kapil Bhatt Date: Mon, 3 Nov 2025 12:48:53 +0000 Subject: [PATCH 05/24] manifest: Update nrf_wifi revision Update nrf_wifi revision to include support for P2P feature. Signed-off-by: Kapil Bhatt --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index bf088f3690ea0..c9bb4034d87c1 100644 --- a/west.yml +++ b/west.yml @@ -342,7 +342,7 @@ manifest: revision: 26ed181181eed53e400db8f63fa83c566a05d971 path: modules/bsim_hw_models/nrf_hw_models - name: nrf_wifi - revision: a39e9b155830461c9d1cf587afb151b894369b91 + revision: pull/85/head path: modules/lib/nrf_wifi - name: open-amp revision: c30a6d8b92fcebdb797fc1a7698e8729e250f637 From c0ffff3d587eb25e963690670312f8654a81de17 Mon Sep 17 00:00:00 2001 From: Ravi Dondaputi Date: Thu, 30 Oct 2025 19:48:21 +0530 Subject: [PATCH 06/24] drivers: wifi: nrf_wifi: Add RoC support Add ops for remain-on-channel and cancelling remain-on-channel. Signed-off-by: Ravi Dondaputi --- drivers/wifi/nrf_wifi/inc/wpa_supp_if.h | 8 ++ drivers/wifi/nrf_wifi/src/fmac_main.c | 4 + drivers/wifi/nrf_wifi/src/wpa_supp_if.c | 141 ++++++++++++++++++++++++ 3 files changed, 153 insertions(+) diff --git a/drivers/wifi/nrf_wifi/inc/wpa_supp_if.h b/drivers/wifi/nrf_wifi/inc/wpa_supp_if.h index c543644e31283..45aa9eabbf9d7 100644 --- a/drivers/wifi/nrf_wifi/inc/wpa_supp_if.h +++ b/drivers/wifi/nrf_wifi/inc/wpa_supp_if.h @@ -123,8 +123,16 @@ 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_roc_complete(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); +int nrf_wifi_supp_cancel_remain_on_channel(void *if_priv); #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 897cb76809cb6..650b55146633d 100644 --- a/drivers/wifi/nrf_wifi/src/fmac_main.c +++ b/drivers/wifi/nrf_wifi/src/fmac_main.c @@ -831,6 +831,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_roc_complete; + 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 @@ -951,6 +953,8 @@ 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, #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/wpa_supp_if.c b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c index da63be115cdd2..d506b3c1b4899 100644 --- a/drivers/wifi/nrf_wifi/src/wpa_supp_if.c +++ b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c @@ -1986,6 +1986,147 @@ void nrf_wifi_supp_event_proc_get_conn_info(void *if_priv, k_sem_give(&wait_for_event_sem); } +void nrf_wifi_supp_event_roc_complete(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); + } +} + +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); + } +} + +int nrf_wifi_supp_remain_on_channel(void *if_priv, unsigned int freq, + unsigned int duration) +{ + 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; + + 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) +{ + 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, 0); + 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; +} + #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) From 587a678cf6fc4860af0719601ab48e21d54e1126 Mon Sep 17 00:00:00 2001 From: Ravi Dondaputi Date: Thu, 30 Oct 2025 19:51:45 +0530 Subject: [PATCH 07/24] drivers: wifi: nrf_wifi: Allow off channel TX for probe responses For frames sent down by supplicant in station mode, inform RPU to allow off-channel transmission. This is needed for sending P2P probe responses. Signed-off-by: Ravi Dondaputi --- drivers/wifi/nrf_wifi/src/wpa_supp_if.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/wifi/nrf_wifi/src/wpa_supp_if.c b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c index d506b3c1b4899..7019a4d37ce52 100644 --- a/drivers/wifi/nrf_wifi/src/wpa_supp_if.c +++ b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c @@ -1435,6 +1435,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; } From 009898da1f3a6f5db7b56db072fc36d50b33d6a3 Mon Sep 17 00:00:00 2001 From: Ravi Dondaputi Date: Thu, 30 Oct 2025 20:04:00 +0530 Subject: [PATCH 08/24] drivers: wifi: nrf_wifi: Register frame without match For frames like Probe Requests, there is no match criterion. Re-arrange the checks to support registering of frames without providing any matching info. Signed-off-by: Ravi Dondaputi --- drivers/wifi/nrf_wifi/src/wpa_supp_if.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/wifi/nrf_wifi/src/wpa_supp_if.c b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c index 7019a4d37ce52..ef6e9d675aa4c 100644 --- a/drivers/wifi/nrf_wifi/src/wpa_supp_if.c +++ b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c @@ -1702,7 +1702,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; } @@ -1723,8 +1723,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); From a47a286e7a2e8ebdc699de5dbe43b00667bff9c0 Mon Sep 17 00:00:00 2001 From: Ravi Dondaputi Date: Thu, 30 Oct 2025 20:15:39 +0530 Subject: [PATCH 09/24] modules: hostap: Define heap and stack for P2P support Increase required heap and stack size for P2P. More stack was required during WPS negotiation. Signed-off-by: Ravi Dondaputi --- modules/hostap/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/hostap/Kconfig b/modules/hostap/Kconfig index ccc3b1899810a..f24b726f04d0d 100644 --- a/modules/hostap/Kconfig +++ b/modules/hostap/Kconfig @@ -53,6 +53,7 @@ config HEAP_MEM_POOL_ADD_SIZE_HOSTAP def_int 60000 if WIFI_USAGE_MODE_STA_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 50000 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 @@ -61,6 +62,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 || WIFI_USAGE_MODE_STA_AP From c12611ce142dacac2f98bda425cc37e2d2793068 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 31 Oct 2025 04:07:05 +0530 Subject: [PATCH 10/24] modules: hostap: Remove obsolete conditional We now support a single MbedTLS shim for hostap, so, this extra check is not needed, we can always use DH5 groups from Mbedtls. Signed-off-by: Chaitanya Tata --- modules/hostap/CMakeLists.txt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/modules/hostap/CMakeLists.txt b/modules/hostap/CMakeLists.txt index 41a50842b71a5..1c08b281aef55 100644 --- a/modules/hostap/CMakeLists.txt +++ b/modules/hostap/CMakeLists.txt @@ -385,14 +385,6 @@ zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPS ${HOSTAP_SRC_BASE}/crypto/dh_groups.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 From bfb61614dc29eda8681f2675ddec409c673894a9 Mon Sep 17 00:00:00 2001 From: Kapil Bhatt Date: Fri, 31 Oct 2025 07:30:40 +0000 Subject: [PATCH 11/24] net: wifi: Add Wi-Fi direct P2P connect API support Add structures and API support for P2P connect. Signed-off-by: Kapil Bhatt --- include/zephyr/net/wifi_mgmt.h | 26 +++++++++++ modules/hostap/src/supp_api.c | 82 ++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 0f3ce008564e9..8ef0790a05971 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -1452,6 +1452,8 @@ enum wifi_p2p_op { * or specific MAC address to query a single peer */ WIFI_P2P_PEER, + /** P2P connect to peer */ + WIFI_P2P_CONNECT, }; /** Wi-Fi P2P discovery type */ @@ -1464,6 +1466,16 @@ enum wifi_p2p_discovery_type { 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 @@ -1483,6 +1495,20 @@ struct wifi_p2p_params { struct wifi_p2p_device_info *peers; /** Actual number of peers returned */ uint16_t peer_count; + /** 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; }; #endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c index f02688a511546..9f9575aaaa571 100644 --- a/modules/hostap/src/supp_api.c +++ b/modules/hostap/src/supp_api.c @@ -2818,6 +2818,88 @@ int supplicant_p2p_oper(const struct device *dev, struct wifi_p2p_params *params } 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; + } + + snprintf(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) { + snprintf(freq_str, sizeof(freq_str), " freq=%u", params->connect.freq); + } + + switch (params->connect.method) { + case WIFI_P2P_METHOD_PBC: + method_str = "pbc"; + snprintf(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"; + snprintf(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; + } + snprintf(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; + } + default: wpa_printf(MSG_ERROR, "Unknown P2P operation: %d", params->oper); ret = -EINVAL; From f09dfcafcd9a0ebd03605440d2f0d7f637f0b66a Mon Sep 17 00:00:00 2001 From: Kapil Bhatt Date: Wed, 12 Nov 2025 09:53:18 +0000 Subject: [PATCH 12/24] net: wifi: Add Wi-Fi direct P2P connect shell command support Add shell command support for P2P connect. Signed-off-by: Kapil Bhatt --- subsys/net/l2/wifi/wifi_shell.c | 117 ++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 1e858f56b1798..18b0616593afa 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -3726,6 +3726,106 @@ static int cmd_wifi_p2p_stop_find(const struct shell *sh, size_t argc, char *arg 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; +} #endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ static int cmd_wifi_pmksa_flush(const struct shell *sh, size_t argc, char *argv[]) @@ -4455,6 +4555,23 @@ SHELL_STATIC_SUBCMD_SET_CREATE( ": 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_SUBCMD_SET_END ); From e7468039bf912fdcfcae8bbec1fd94fdd349d043 Mon Sep 17 00:00:00 2001 From: Kapil Bhatt Date: Fri, 7 Nov 2025 08:33:54 +0000 Subject: [PATCH 13/24] drivers: nrf_wifi: Add default value to p2p mode Kconfig The Kconfig NRF70_P2P_MODE should be enabled when WIFI_NM_WPA_SUPPLICANT_P2P is enabled. Signed-off-by: Kapil Bhatt --- drivers/wifi/nrf_wifi/Kconfig.nrfwifi | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/wifi/nrf_wifi/Kconfig.nrfwifi b/drivers/wifi/nrf_wifi/Kconfig.nrfwifi index cb45ea90b575c..7ae374d3c6a2c 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" From be26ca2f29c9f8556f0b9591df3d85ab7b0efcdc Mon Sep 17 00:00:00 2001 From: Kapil Bhatt Date: Fri, 7 Nov 2025 09:08:30 +0000 Subject: [PATCH 14/24] doc: networking: Add Wi-Fi P2P info Add Wi-Fi P2P mode build command and info. Signed-off-by: Kapil Bhatt --- doc/connectivity/networking/api/wifi.rst | 14 ++++++++++++++ doc/releases/release-notes-4.4.rst | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/doc/connectivity/networking/api/wifi.rst b/doc/connectivity/networking/api/wifi.rst index e0be448354435..4271c91f22e19 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 -- -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 95e087f86e7dc..7e36d0dd9d6cb 100644 --- a/doc/releases/release-notes-4.4.rst +++ b/doc/releases/release-notes-4.4.rst @@ -81,6 +81,12 @@ New APIs and options * :dtcompatible:`jedec,mspi-nor` now allows MSPI configuration of read, write and control commands separately via devicetree. +* Networking + + * Wi-Fi + + * Add support for Wi-Fi Direct (P2P) mode. + .. zephyr-keep-sorted-stop New Boards From c336bee29239a14078ebb09cfa35a2f5f51eb225 Mon Sep 17 00:00:00 2001 From: Ravi Dondaputi Date: Wed, 12 Nov 2025 12:32:52 +0530 Subject: [PATCH 15/24] modules: hostap: Add support for P2P GO mode ops Enable build time configs required for supporting P2P GO mode. Signed-off-by: Ravi Dondaputi --- modules/hostap/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/hostap/CMakeLists.txt b/modules/hostap/CMakeLists.txt index 1c08b281aef55..4989767ca2e7b 100644 --- a/modules/hostap/CMakeLists.txt +++ b/modules/hostap/CMakeLists.txt @@ -383,6 +383,7 @@ 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 ) zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P @@ -394,6 +395,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 From 30a9fa818be9aed2143860ccbc126a5ab90390f5 Mon Sep 17 00:00:00 2001 From: Ravi Dondaputi Date: Wed, 12 Nov 2025 12:34:04 +0530 Subject: [PATCH 16/24] modules: hostap: Increase hostap heap size Additional heap is required for supporting P2P GO mode. Signed-off-by: Ravi Dondaputi --- modules/hostap/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hostap/Kconfig b/modules/hostap/Kconfig index f24b726f04d0d..6bb9afb7be9ee 100644 --- a/modules/hostap/Kconfig +++ b/modules/hostap/Kconfig @@ -53,7 +53,7 @@ config HEAP_MEM_POOL_ADD_SIZE_HOSTAP def_int 60000 if WIFI_USAGE_MODE_STA_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 50000 if WIFI_NM_WPA_SUPPLICANT_P2P + 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 From f06af4ff71a6ecc78aa0fa46bb3fc5b415ba4973 Mon Sep 17 00:00:00 2001 From: Ravi Dondaputi Date: Wed, 12 Nov 2025 13:00:08 +0530 Subject: [PATCH 17/24] drivers: wifi: nrf_wifi: Add per-peer authorized flag Add per-peer authorized parameter. Port authorization command from supplicant will set this flag and will be used by driver to allow or nor allow data traffic. Signed-off-by: Ravi Dondaputi --- drivers/wifi/nrf_wifi/inc/fmac_main.h | 3 --- drivers/wifi/nrf_wifi/src/net_if.c | 15 +++++++++-- drivers/wifi/nrf_wifi/src/wpa_supp_if.c | 33 +++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/drivers/wifi/nrf_wifi/inc/fmac_main.h b/drivers/wifi/nrf_wifi/inc/fmac_main.h index 799beff1fbaf5..be8c9d7636793 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/src/net_if.c b/drivers/wifi/nrf_wifi/src/net_if.c index 8f7750031476c..b8635e83d54ae 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_err("%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/wpa_supp_if.c b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c index ef6e9d675aa4c..c9570f63bff5e 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); @@ -1103,7 +1104,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 +1137,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 +1154,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); @@ -2952,7 +2966,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) { @@ -2987,6 +3003,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: From dc4fdc00a0b2ce5d3fbe63be73973a10de3a5a0b Mon Sep 17 00:00:00 2001 From: Kapil Bhatt Date: Thu, 13 Nov 2025 09:09:07 +0000 Subject: [PATCH 18/24] net: wifi: Add API support for P2P GO mode Add structures and API support for P2P Go mode. Signed-off-by: Kapil Bhatt --- include/zephyr/net/wifi_mgmt.h | 50 ++++++++++++ modules/hostap/src/supp_api.c | 141 +++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 8ef0790a05971..ef8f67ed845c2 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -1454,6 +1454,12 @@ enum wifi_p2p_op { 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, }; /** Wi-Fi P2P discovery type */ @@ -1509,6 +1515,50 @@ struct wifi_p2p_params { /** 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 */ diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c index 9f9575aaaa571..d4bfbe02caf32 100644 --- a/modules/hostap/src/supp_api.c +++ b/modules/hostap/src/supp_api.c @@ -2900,6 +2900,147 @@ int supplicant_p2p_oper(const struct device *dev, struct wifi_p2p_params *params break; } + case WIFI_P2P_GROUP_ADD: { + int len = 0; + + if (!params) { + wpa_printf(MSG_ERROR, "P2P group add params are NULL"); + return -EINVAL; + } + + len = snprintf(cmd_buf, sizeof(cmd_buf), "P2P_GROUP_ADD"); + + if (params->group_add.freq > 0) { + len += snprintf(cmd_buf + len, sizeof(cmd_buf) - len, " freq=%d", + params->group_add.freq); + } + + if (params->group_add.persistent >= 0) { + len += snprintf(cmd_buf + len, sizeof(cmd_buf) - len, " persistent=%d", + params->group_add.persistent); + } + + if (params->group_add.ht40) { + len += snprintf(cmd_buf + len, sizeof(cmd_buf) - len, " ht40"); + } + + if (params->group_add.vht) { + len += snprintf(cmd_buf + len, sizeof(cmd_buf) - len, " vht"); + } + + if (params->group_add.he) { + len += snprintf(cmd_buf + len, sizeof(cmd_buf) - len, " he"); + } + + if (params->group_add.edmg) { + len += snprintf(cmd_buf + len, sizeof(cmd_buf) - len, " edmg"); + } + + if (params->group_add.go_bssid_length == WIFI_MAC_ADDR_LEN) { + len += snprintf(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; + } + + snprintf(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; + } + + snprintf(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 = snprintf(cmd_buf, sizeof(cmd_buf), "P2P_INVITE persistent=%d peer=%s", + params->invite.persistent_id, addr_str); + + if (params->invite.freq > 0) { + len += snprintf(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 = snprintf(cmd_buf, sizeof(cmd_buf), "P2P_INVITE group=%s peer=%s", + params->invite.group_ifname, addr_str); + + if (params->invite.freq > 0) { + len += snprintf(cmd_buf + len, sizeof(cmd_buf) - len, " freq=%d", + params->invite.freq); + } + + if (params->invite.go_dev_addr_length == WIFI_MAC_ADDR_LEN) { + len += snprintf(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; + } + default: wpa_printf(MSG_ERROR, "Unknown P2P operation: %d", params->oper); ret = -EINVAL; From d4e1d3997ea3acb3466ff106a47ac502937e4794 Mon Sep 17 00:00:00 2001 From: Kapil Bhatt Date: Thu, 13 Nov 2025 09:10:42 +0000 Subject: [PATCH 19/24] net: wifi: Add Wi-Fi direct P2P GO mode shell command Add shell commands support for P2P GO mode. Signed-off-by: Kapil Bhatt --- subsys/net/l2/wifi/wifi_shell.c | 275 ++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 18b0616593afa..8292317ce530c 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -3826,6 +3826,252 @@ static int cmd_wifi_p2p_connect(const struct shell *sh, size_t argc, char *argv[ } 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; + } + } + + 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 > optind && argv[optind][0] != '-') { + if (sscanf(argv[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; +} #endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P */ static int cmd_wifi_pmksa_flush(const struct shell *sh, size_t argc, char *argv[]) @@ -4572,6 +4818,35 @@ SHELL_STATIC_SUBCMD_SET_CREATE( " 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_SUBCMD_SET_END ); From c154c875787203b4749a15d1122b68114b54eab4 Mon Sep 17 00:00:00 2001 From: Ravi Dondaputi Date: Mon, 17 Nov 2025 23:32:15 +0530 Subject: [PATCH 20/24] drivers: wifi: nrf_wifi: Add P2P powersave support Add ops to handle P2P powersave configuration. Signed-off-by: Ravi Dondaputi --- drivers/wifi/nrf_wifi/inc/wpa_supp_if.h | 1 + drivers/wifi/nrf_wifi/src/fmac_main.c | 1 + drivers/wifi/nrf_wifi/src/wpa_supp_if.c | 45 +++++++++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/drivers/wifi/nrf_wifi/inc/wpa_supp_if.h b/drivers/wifi/nrf_wifi/inc/wpa_supp_if.h index 45aa9eabbf9d7..25b3972d9fab7 100644 --- a/drivers/wifi/nrf_wifi/inc/wpa_supp_if.h +++ b/drivers/wifi/nrf_wifi/inc/wpa_supp_if.h @@ -133,6 +133,7 @@ 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); int nrf_wifi_supp_cancel_remain_on_channel(void *if_priv); +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 650b55146633d..fb168da175fca 100644 --- a/drivers/wifi/nrf_wifi/src/fmac_main.c +++ b/drivers/wifi/nrf_wifi/src/fmac_main.c @@ -955,6 +955,7 @@ static const struct zep_wpa_supp_dev_ops wpa_supp_ops = { .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/wpa_supp_if.c b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c index c9570f63bff5e..ee907a505850f 100644 --- a/drivers/wifi/nrf_wifi/src/wpa_supp_if.c +++ b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c @@ -2151,6 +2151,51 @@ int nrf_wifi_supp_cancel_remain_on_channel(void *if_priv) 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) From d8870f21ece112a7f649e125732944b64443b8bc Mon Sep 17 00:00:00 2001 From: Ravi Dondaputi Date: Mon, 17 Nov 2025 23:33:01 +0530 Subject: [PATCH 21/24] drivers: wifi: nrf_wifi: Add cookie handling support Add cookie event callbacks to track RoC and cancel-RoC requests and its responses from firmware. Signed-off-by: Ravi Dondaputi --- drivers/wifi/nrf_wifi/src/fmac_main.c | 5 +++++ drivers/wifi/nrf_wifi/src/wpa_supp_if.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/wifi/nrf_wifi/src/fmac_main.c b/drivers/wifi/nrf_wifi/src/fmac_main.c index fb168da175fca..809547126603e 100644 --- a/drivers/wifi/nrf_wifi/src/fmac_main.c +++ b/drivers/wifi/nrf_wifi/src/fmac_main.c @@ -440,6 +440,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->cookie); + } } #endif /* CONFIG_NRF70_STA_MODE */ diff --git a/drivers/wifi/nrf_wifi/src/wpa_supp_if.c b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c index ee907a505850f..da7cc7aa1cc75 100644 --- a/drivers/wifi/nrf_wifi/src/wpa_supp_if.c +++ b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c @@ -2035,7 +2035,7 @@ void nrf_wifi_supp_event_roc_complete(void *if_priv, 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->dur, roc_complete->cookie); } } @@ -2064,7 +2064,7 @@ void nrf_wifi_supp_event_roc_cancel_complete(void *if_priv, 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->frequency, roc_cancel_complete->cookie); } } From 6a12e5365674dd4c94785af35cfd958de5fb5d43 Mon Sep 17 00:00:00 2001 From: Ravi Dondaputi Date: Mon, 17 Nov 2025 23:37:14 +0530 Subject: [PATCH 22/24] manifest: hostap: Pull in P2P powersave support Add P2P power save and cookie handling support. Signed-off-by: Ravi Dondaputi --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index c9bb4034d87c1..4d9b3272114a5 100644 --- a/west.yml +++ b/west.yml @@ -286,7 +286,7 @@ manifest: - hal - name: hostap path: modules/lib/hostap - revision: 6086dea5ee7406e1eede7f2ca6dff1b00b0f04e2 + revision: pull/113/head - name: liblc3 revision: 48bbd3eacd36e99a57317a0a4867002e0b09e183 path: modules/lib/liblc3 From 25f82280cfd6de13237b6a5df8dde598474b93fb Mon Sep 17 00:00:00 2001 From: Kapil Bhatt Date: Tue, 18 Nov 2025 12:39:11 +0000 Subject: [PATCH 23/24] net: wifi: Add API support for P2P power save Add API support for P2P power save. Signed-off-by: Kapil Bhatt --- include/zephyr/net/wifi_mgmt.h | 4 ++++ modules/hostap/src/supp_api.c | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index ef8f67ed845c2..60dbe5cfc2601 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -1460,6 +1460,8 @@ enum wifi_p2p_op { WIFI_P2P_GROUP_REMOVE, /** P2P invite */ WIFI_P2P_INVITE, + /** P2P power save */ + WIFI_P2P_POWER_SAVE, }; /** Wi-Fi P2P discovery type */ @@ -1501,6 +1503,8 @@ struct wifi_p2p_params { 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 */ diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c index d4bfbe02caf32..8e7d38e4d25dd 100644 --- a/modules/hostap/src/supp_api.c +++ b/modules/hostap/src/supp_api.c @@ -3041,6 +3041,20 @@ int supplicant_p2p_oper(const struct device *dev, struct wifi_p2p_params *params break; } + case WIFI_P2P_POWER_SAVE: + snprintf(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; From 289c45098dff8b51c065b0ab010f47fe773c785d Mon Sep 17 00:00:00 2001 From: Kapil Bhatt Date: Tue, 18 Nov 2025 12:40:59 +0000 Subject: [PATCH 24/24] net: wifi: Add P2P power save shell command support Add shell command support for P2P power save. Signed-off-by: Kapil Bhatt --- subsys/net/l2/wifi/wifi_shell.c | 41 +++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 8292317ce530c..61f9f2f701f6c 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -4072,6 +4072,40 @@ static int cmd_wifi_p2p_invite(const struct shell *sh, size_t argc, char *argv[] 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[]) @@ -4847,6 +4881,13 @@ SHELL_STATIC_SUBCMD_SET_CREATE( "[-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 );