zephyr/modules/hostap/src/hapd_api.c
Hui Bai 58c932cc46 hostap: Relocate hostapd related source code to new files
Created new files and relocate hostapd support code in glue layer to new
files. The new files will be compiled only if hostapd support is enabled.

Signed-off-by: Hui Bai <hui.bai@nxp.com>
2025-04-09 12:35:27 +02:00

1033 lines
24 KiB
C

/**
* Copyright 2023-2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/net/wifi_mgmt.h>
#include "includes.h"
#include "common.h"
#include "common/defs.h"
#include "wpa_supplicant_i.h"
#include "hostapd.h"
#include "hostapd_cli_zephyr.h"
#include "ap_drv_ops.h"
#include "hapd_main.h"
#include "hapd_api.h"
#include "supp_events.h"
#include "supp_api.h"
K_MUTEX_DEFINE(hostapd_mutex);
#ifdef CONFIG_WIFI_NM_HOSTAPD_CRYPTO_ENTERPRISE
static struct wifi_eap_config hapd_eap_config[] = {
{WIFI_SECURITY_TYPE_EAP_TLS, WIFI_EAP_TYPE_TLS, WIFI_EAP_TYPE_NONE, "TLS", NULL},
{WIFI_SECURITY_TYPE_EAP_PEAP_MSCHAPV2, WIFI_EAP_TYPE_PEAP, WIFI_EAP_TYPE_MSCHAPV2, "PEAP",
"auth=MSCHAPV2"},
{WIFI_SECURITY_TYPE_EAP_PEAP_GTC, WIFI_EAP_TYPE_PEAP, WIFI_EAP_TYPE_GTC, "PEAP",
"auth=GTC"},
{WIFI_SECURITY_TYPE_EAP_TTLS_MSCHAPV2, WIFI_EAP_TYPE_TTLS, WIFI_EAP_TYPE_NONE, "TTLS",
"auth=MSCHAPV2"},
{WIFI_SECURITY_TYPE_EAP_PEAP_TLS, WIFI_EAP_TYPE_PEAP, WIFI_EAP_TYPE_TLS, "PEAP",
"auth=TLS"},
};
static struct wifi_enterprise_creds_params hapd_enterprise_creds;
#endif
#define hostapd_cli_cmd_v(cmd, ...) ({ \
bool status; \
\
if (zephyr_hostapd_cli_cmd_v(cmd, ##__VA_ARGS__) < 0) { \
wpa_printf(MSG_ERROR, \
"Failed to execute wpa_cli command: %s", \
cmd); \
status = false; \
} else { \
status = true; \
} \
\
status; \
})
static inline struct hostapd_iface *get_hostapd_handle(const struct device *dev)
{
struct net_if *iface = net_if_lookup_by_dev(dev);
char if_name[CONFIG_NET_INTERFACE_NAME_LEN + 1];
struct hostapd_iface *hapd;
int ret;
if (!iface) {
wpa_printf(MSG_ERROR, "Interface for device %s not found", dev->name);
return NULL;
}
ret = net_if_get_name(iface, if_name, sizeof(if_name));
if (!ret) {
wpa_printf(MSG_ERROR, "Cannot get interface name (%d)", ret);
return NULL;
}
hapd = zephyr_get_hapd_handle_by_ifname(if_name);
if (!hapd) {
wpa_printf(MSG_ERROR, "Interface %s not found", if_name);
return NULL;
}
return hapd;
}
#ifdef CONFIG_WIFI_NM_HOSTAPD_CRYPTO_ENTERPRISE
static int hapd_process_cert_data(struct hostapd_bss_config *conf,
char *type, uint8_t *data, uint32_t data_len)
{
if (os_strcmp(type, "ca_cert_blob") == 0) {
conf->ca_cert_blob = data;
conf->ca_cert_blob_len = data_len;
} else if (os_strcmp(type, "server_cert_blob") == 0) {
conf->server_cert_blob = data;
conf->server_cert_blob_len = data_len;
} else if (os_strcmp(type, "private_key_blob") == 0) {
conf->private_key_blob = data;
conf->private_key_blob_len = data_len;
} else if (os_strcmp(type, "dh_blob") == 0) {
conf->dh_blob = data;
conf->dh_blob_len = data_len;
} else {
wpa_printf(MSG_ERROR, "input type error");
return -ENOTSUP;
}
return 0;
}
static int hapd_get_eap_config(struct wifi_connect_req_params *params,
struct wifi_eap_config *eap_cfg)
{
unsigned int index = 0;
for (index = 0; index < ARRAY_SIZE(hapd_eap_config); index++) {
if (params->security == hapd_eap_config[index].type) {
memcpy(eap_cfg, &hapd_eap_config[index], sizeof(struct wifi_eap_config));
break;
}
}
if (index == ARRAY_SIZE(hapd_eap_config)) {
wpa_printf(MSG_ERROR, "Get eap method type with security type: %d",
params->security);
return -ENOTSUP;
}
return 0;
}
static struct hostapd_eap_user *hapd_process_eap_user_phase1(
struct wifi_connect_req_params *params, struct hostapd_eap_user **pnew_user)
{
struct hostapd_eap_user *user = NULL, *tail = NULL, *new_user = NULL;
struct wifi_eap_config eap_cfg;
user = os_zalloc(sizeof(*user));
if (user == NULL) {
wpa_printf(MSG_ERROR, "EAP user allocation failed");
goto failed;
}
user->force_version = -1;
if (params->eap_ver >= 0) {
user->force_version = params->eap_ver;
}
if (hapd_get_eap_config(params, &eap_cfg)) {
goto failed;
}
user->methods[0].method = eap_cfg.eap_type_phase1;
user->methods[0].vendor = 0;
if (tail == NULL) {
tail = new_user = user;
} else {
tail->next = user;
tail = user;
}
*pnew_user = new_user;
return tail;
failed:
if (user) {
hostapd_config_free_eap_user(user);
}
return NULL;
}
static int hapd_process_eap_user(struct wifi_connect_req_params *params,
struct hostapd_bss_config *conf)
{
struct hostapd_eap_user *user = NULL, *tail = NULL, *user_list = NULL;
int i, nusers = params->nusers;
const char *identity, *password;
struct wifi_eap_config eap_cfg;
int ret = 0;
if (hapd_get_eap_config(params, &eap_cfg)) {
goto failed;
}
if (eap_cfg.phase2 != NULL) {
tail = hapd_process_eap_user_phase1(params, &user_list);
}
if (eap_cfg.phase2 != NULL && !nusers) {
wpa_printf(MSG_ERROR, "EAP users not found.");
goto failed;
}
for (i = 0; i < nusers; i++) {
user = os_zalloc(sizeof(*user));
if (user == NULL) {
wpa_printf(MSG_ERROR, "EAP user allocation failed");
goto failed;
}
user->force_version = -1;
if (params->eap_ver >= 0) {
user->force_version = params->eap_ver;
}
identity = params->identities[i];
password = params->passwords[i];
user->identity = os_memdup(identity, os_strlen(identity));
if (user->identity == NULL) {
wpa_printf(MSG_ERROR,
"Failed to allocate "
"memory for EAP identity");
goto failed;
}
user->identity_len = os_strlen(identity);
user->methods[0].method = eap_cfg.eap_type_phase1;
user->methods[0].vendor = 0;
if (eap_cfg.phase2 != NULL) {
user->methods[0].method = eap_cfg.eap_type_phase2;
user->password = os_memdup(password, os_strlen(password));
if (user->password == NULL) {
wpa_printf(MSG_ERROR,
"Failed to allocate "
"memory for EAP password");
goto failed;
}
user->password_len = os_strlen(password);
user->phase2 = 1;
}
if (params->security == WIFI_SECURITY_TYPE_EAP_TTLS_MSCHAPV2) {
user->ttls_auth |= 0x1E;
}
if (tail == NULL) {
tail = user_list = user;
} else {
tail->next = user;
tail = user;
}
continue;
failed:
if (user) {
hostapd_config_free_eap_user(user);
}
ret = -1;
break;
}
if (ret == 0) {
hostapd_config_free_eap_users(conf->eap_user);
conf->eap_user = user_list;
} else {
hostapd_config_free_eap_users(user_list);
}
return ret;
}
int hapd_process_enterprise_config(struct hostapd_iface *iface,
struct wifi_connect_req_params *params)
{
struct wifi_eap_cipher_config cipher_config = {
NULL, "DEFAULT:!EXP:!LOW", "CCMP", "CCMP", "AES-128-CMAC", NULL};
int ret = 0;
if (process_cipher_config(params, &cipher_config)) {
goto out;
}
if (!hostapd_cli_cmd_v("set wpa %d", WPA_PROTO_RSN)) {
goto out;
}
if (!hostapd_cli_cmd_v("set wpa_key_mgmt %s", cipher_config.key_mgmt)) {
goto out;
}
if (!hostapd_cli_cmd_v("set rsn_pairwise %s", cipher_config.pairwise_cipher)) {
goto out;
}
if (!hostapd_cli_cmd_v("set wpa_pairwise %s", cipher_config.pairwise_cipher)) {
goto out;
}
if (!hostapd_cli_cmd_v("set group_cipher %s", cipher_config.group_cipher)) {
goto out;
}
if (!hostapd_cli_cmd_v("set group_mgmt_cipher %s", cipher_config.group_mgmt_cipher)) {
goto out;
}
if (cipher_config.tls_flags != NULL) {
if (!hostapd_cli_cmd_v("set tls_flags %s", cipher_config.tls_flags)) {
goto out;
}
}
if (!hostapd_cli_cmd_v("set ieee8021x %d", 1)) {
goto out;
}
if (!hostapd_cli_cmd_v("set eapol_version %d", 2)) {
goto out;
}
if (!hostapd_cli_cmd_v("set eap_server %d", 1)) {
goto out;
}
if (hapd_process_cert_data(iface->bss[0]->conf, "ca_cert_blob",
hapd_enterprise_creds.ca_cert, hapd_enterprise_creds.ca_cert_len)) {
goto out;
}
if (hapd_process_cert_data(iface->bss[0]->conf, "server_cert_blob",
hapd_enterprise_creds.server_cert, hapd_enterprise_creds.server_cert_len)) {
goto out;
}
if (hapd_process_cert_data(iface->bss[0]->conf, "private_key_blob",
hapd_enterprise_creds.server_key, hapd_enterprise_creds.server_key_len)) {
goto out;
}
if (hapd_process_cert_data(iface->bss[0]->conf, "dh_blob",
hapd_enterprise_creds.dh_param, hapd_enterprise_creds.dh_param_len)) {
goto out;
}
if (!hostapd_cli_cmd_v("set private_key_passwd %s", params->key_passwd)) {
goto out;
}
if (hapd_process_eap_user(params, iface->bss[0]->conf)) {
goto out;
}
return ret;
out:
return -1;
}
int hostapd_add_enterprise_creds(const struct device *dev,
struct wifi_enterprise_creds_params *creds)
{
int ret = 0;
if (!creds) {
ret = -1;
wpa_printf(MSG_ERROR, "enterprise creds is NULL");
goto out;
}
memcpy((void *)&hapd_enterprise_creds, (void *)creds,
sizeof(struct wifi_enterprise_creds_params));
out:
return ret;
}
#endif
bool hostapd_ap_reg_domain(struct wifi_reg_domain *reg_domain)
{
return hostapd_cli_cmd_v("set country_code %s", reg_domain->country_code);
}
static int hapd_config_chan_center_seg0(struct wifi_connect_req_params *params)
{
int ret = 0;
uint8_t center_freq_seg0_idx = 0;
uint8_t oper_chwidth = CHANWIDTH_USE_HT;
const uint8_t *center_freq = NULL;
static const uint8_t center_freq_40MHz[] = {38, 46, 54, 62, 102, 110,
118, 126, 134, 142, 151, 159};
static const uint8_t center_freq_80MHz[] = {42, 58, 106, 122, 138, 155};
uint8_t index, index_max, chan_idx, ch_offset = 0;
/* Unless ACS is being used, both "channel" and "vht_oper_centr_freq_seg0_idx"
* parameters must be set.
*/
switch (params->bandwidth) {
case WIFI_FREQ_BANDWIDTH_20MHZ:
oper_chwidth = CHANWIDTH_USE_HT;
center_freq_seg0_idx = params->channel;
break;
case WIFI_FREQ_BANDWIDTH_40MHZ:
oper_chwidth = CHANWIDTH_USE_HT;
center_freq = center_freq_40MHz;
index_max = ARRAY_SIZE(center_freq_40MHz);
ch_offset = 2;
break;
case WIFI_FREQ_BANDWIDTH_80MHZ:
oper_chwidth = CHANWIDTH_80MHZ;
center_freq = center_freq_80MHz;
index_max = ARRAY_SIZE(center_freq_80MHz);
ch_offset = 6;
break;
default:
return -EINVAL;
}
if (params->bandwidth != WIFI_FREQ_BANDWIDTH_20MHZ) {
chan_idx = params->channel;
for (index = 0; index < index_max; index++) {
if ((chan_idx >= (center_freq[index] - ch_offset)) &&
(chan_idx <= (center_freq[index] + ch_offset))) {
center_freq_seg0_idx = center_freq[index];
break;
}
}
}
if (!hostapd_cli_cmd_v("set vht_oper_chwidth %d", oper_chwidth)) {
goto out;
}
if (!hostapd_cli_cmd_v("set vht_oper_centr_freq_seg0_idx %d", center_freq_seg0_idx)) {
goto out;
}
#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_11AX
if (!hostapd_cli_cmd_v("set he_oper_chwidth %d", oper_chwidth)) {
goto out;
}
if (!hostapd_cli_cmd_v("set he_oper_centr_freq_seg0_idx %d", center_freq_seg0_idx)) {
goto out;
}
#endif
return ret;
out:
return -EINVAL;
}
int hapd_config_network(struct hostapd_iface *iface,
struct wifi_connect_req_params *params)
{
int ret = 0;
if (!hostapd_cli_cmd_v("set ssid %s", params->ssid)) {
goto out;
}
if (params->channel == 0) {
if (params->band == 0) {
if (!hostapd_cli_cmd_v("set hw_mode g")) {
goto out;
}
} else if (params->band == 1) {
if (!hostapd_cli_cmd_v("set hw_mode a")) {
goto out;
}
} else {
wpa_printf(MSG_ERROR, "Invalid band %d", params->band);
goto out;
}
} else if (params->channel > 14) {
if (!hostapd_cli_cmd_v("set hw_mode a")) {
goto out;
}
} else {
if (!hostapd_cli_cmd_v("set hw_mode g")) {
goto out;
}
}
if (!hostapd_cli_cmd_v("set channel %d", params->channel)) {
goto out;
}
ret = hapd_config_chan_center_seg0(params);
if (ret) {
goto out;
}
if (params->security != WIFI_SECURITY_TYPE_NONE) {
if (params->security == WIFI_SECURITY_TYPE_WPA_PSK) {
if (!hostapd_cli_cmd_v("set wpa 1")) {
goto out;
}
if (!hostapd_cli_cmd_v("set wpa_key_mgmt WPA-PSK")) {
goto out;
}
if (!hostapd_cli_cmd_v("set wpa_passphrase %s", params->psk)) {
goto out;
}
if (!hostapd_cli_cmd_v("set wpa_pairwise CCMP")) {
goto out;
}
} else if (params->security == WIFI_SECURITY_TYPE_PSK) {
if (!hostapd_cli_cmd_v("set wpa 2")) {
goto out;
}
if (!hostapd_cli_cmd_v("set wpa_key_mgmt WPA-PSK")) {
goto out;
}
if (!hostapd_cli_cmd_v("set wpa_passphrase %s", params->psk)) {
goto out;
}
if (!hostapd_cli_cmd_v("set rsn_pairwise CCMP")) {
goto out;
}
} else if (params->security == WIFI_SECURITY_TYPE_PSK_SHA256) {
if (!hostapd_cli_cmd_v("set wpa 2")) {
goto out;
}
if (!hostapd_cli_cmd_v("set wpa_key_mgmt WPA-PSK-SHA256")) {
goto out;
}
if (!hostapd_cli_cmd_v("set wpa_passphrase %s", params->psk)) {
goto out;
}
if (!hostapd_cli_cmd_v("set rsn_pairwise CCMP")) {
goto out;
}
} else if (params->security == WIFI_SECURITY_TYPE_SAE_HNP ||
params->security == WIFI_SECURITY_TYPE_SAE_H2E ||
params->security == WIFI_SECURITY_TYPE_SAE_AUTO) {
if (!hostapd_cli_cmd_v("set wpa 2")) {
goto out;
}
if (!hostapd_cli_cmd_v("set wpa_key_mgmt SAE")) {
goto out;
}
if (!hostapd_cli_cmd_v("set sae_password %s",
params->sae_password ? params->sae_password :
params->psk)) {
goto out;
}
if (!hostapd_cli_cmd_v("set rsn_pairwise CCMP")) {
goto out;
}
if (params->security == WIFI_SECURITY_TYPE_SAE_H2E ||
params->security == WIFI_SECURITY_TYPE_SAE_AUTO) {
if (!hostapd_cli_cmd_v("set sae_pwe %d",
(params->security == WIFI_SECURITY_TYPE_SAE_H2E)
? 1
: 2)) {
goto out;
}
}
} else if (params->security == WIFI_SECURITY_TYPE_WPA_AUTO_PERSONAL) {
if (!hostapd_cli_cmd_v("set wpa 2")) {
goto out;
}
if (!hostapd_cli_cmd_v("set wpa_key_mgmt WPA-PSK SAE")) {
goto out;
}
if (!hostapd_cli_cmd_v("set wpa_passphrase %s", params->psk)) {
goto out;
}
if (!hostapd_cli_cmd_v("set sae_password %s",
params->sae_password ? params->sae_password
: params->psk)) {
goto out;
}
if (!hostapd_cli_cmd_v("set rsn_pairwise CCMP")) {
goto out;
}
if (!hostapd_cli_cmd_v("set sae_pwe 2")) {
goto out;
}
} else if (params->security == WIFI_SECURITY_TYPE_DPP) {
if (!hostapd_cli_cmd_v("set wpa 2")) {
goto out;
}
if (!hostapd_cli_cmd_v("set wpa_key_mgmt WPA-PSK DPP")) {
goto out;
}
if (!hostapd_cli_cmd_v("set wpa_passphrase %s", params->psk)) {
goto out;
}
if (!hostapd_cli_cmd_v("set wpa_pairwise CCMP")) {
goto out;
}
if (!hostapd_cli_cmd_v("set rsn_pairwise CCMP")) {
goto out;
}
if (!hostapd_cli_cmd_v("set dpp_configurator_connectivity 1")) {
goto out;
}
#ifdef CONFIG_WIFI_NM_HOSTAPD_CRYPTO_ENTERPRISE
} else if (is_eap_valid_security(params->security)) {
if (hapd_process_enterprise_config(iface, params)) {
goto out;
}
#endif
} else {
wpa_printf(MSG_ERROR, "Security type %d is not supported",
params->security);
goto out;
}
} else {
if (!hostapd_cli_cmd_v("set wpa 0")) {
goto out;
}
iface->bss[0]->conf->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
}
if (!hostapd_cli_cmd_v("set ieee80211w %d", params->mfp)) {
goto out;
}
if (!hostapd_cli_cmd_v("set ignore_broadcast_ssid %d", params->ignore_broadcast_ssid)) {
goto out;
}
return ret;
out:
return -1;
}
static int set_ap_config_params(const struct device *dev, struct wifi_ap_config_params *params)
{
const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev);
if (wifi_mgmt_api == NULL || wifi_mgmt_api->ap_config_params == NULL) {
return -ENOTSUP;
}
return wifi_mgmt_api->ap_config_params(dev, params);
}
int hostapd_ap_config_params(const struct device *dev, struct wifi_ap_config_params *params)
{
struct hostapd_iface *iface;
int ret = 0;
ret = set_ap_config_params(dev, params);
if (ret && (ret != -ENOTSUP)) {
wpa_printf(MSG_ERROR, "Failed to set ap config params");
return -EINVAL;
}
k_mutex_lock(&hostapd_mutex, K_FOREVER);
iface = get_hostapd_handle(dev);
if (iface == NULL) {
ret = -ENOENT;
wpa_printf(MSG_ERROR, "Interface %s not found", dev->name);
goto out;
}
if (iface->state > HAPD_IFACE_DISABLED) {
ret = -EBUSY;
wpa_printf(MSG_ERROR, "Interface %s is not in disable state", dev->name);
goto out;
}
if (params->type & WIFI_AP_CONFIG_PARAM_MAX_NUM_STA) {
if (!hostapd_cli_cmd_v("set max_num_sta %d", params->max_num_sta)) {
ret = -EINVAL;
wpa_printf(MSG_ERROR, "Failed to set maximum number of stations");
goto out;
}
wpa_printf(MSG_INFO, "Set maximum number of stations: %d", params->max_num_sta);
}
if (params->type & WIFI_AP_CONFIG_PARAM_HT_CAPAB) {
if (!hostapd_cli_cmd_v("set ht_capab %s", params->ht_capab)) {
ret = -EINVAL;
wpa_printf(MSG_ERROR, "Failed to set HT capabilities");
goto out;
}
wpa_printf(MSG_INFO, "Set HT capabilities: %s", params->ht_capab);
}
if (params->type & WIFI_AP_CONFIG_PARAM_VHT_CAPAB) {
if (!hostapd_cli_cmd_v("set vht_capab %s", params->vht_capab)) {
ret = -EINVAL;
wpa_printf(MSG_ERROR, "Failed to set VHT capabilities");
goto out;
}
wpa_printf(MSG_INFO, "Set VHT capabilities: %s", params->vht_capab);
}
out:
k_mutex_unlock(&hostapd_mutex);
return ret;
}
int hostapd_ap_status(const struct device *dev, struct wifi_iface_status *status)
{
int ret = 0;
struct hostapd_iface *iface;
struct hostapd_config *conf;
struct hostapd_data *hapd;
struct hostapd_bss_config *bss;
struct hostapd_ssid *ssid;
struct hostapd_hw_modes *hw_mode;
int proto; /* Wi-Fi secure protocol */
int key_mgmt; /* Wi-Fi key management */
int sae_pwe;
k_mutex_lock(&hostapd_mutex, K_FOREVER);
iface = get_hostapd_handle(dev);
if (!iface) {
ret = -1;
wpa_printf(MSG_ERROR, "Interface %s not found", dev->name);
goto out;
}
conf = iface->conf;
if (!conf) {
ret = -1;
wpa_printf(MSG_ERROR, "Conf %s not found", dev->name);
goto out;
}
bss = conf->bss[0];
if (!bss) {
ret = -1;
wpa_printf(MSG_ERROR, "Bss_conf %s not found", dev->name);
goto out;
}
hapd = iface->bss[0];
if (!hapd) {
ret = -1;
wpa_printf(MSG_ERROR, "Bss %s not found", dev->name);
goto out;
}
status->state = iface->state;
ssid = &bss->ssid;
os_memcpy(status->bssid, hapd->own_addr, WIFI_MAC_ADDR_LEN);
status->iface_mode = WIFI_MODE_AP;
status->band = wpas_band_to_zephyr(wpas_freq_to_band(iface->freq));
key_mgmt = bss->wpa_key_mgmt;
proto = bss->wpa;
sae_pwe = bss->sae_pwe;
status->wpa3_ent_type = wpas_key_mgmt_to_zephyr_wpa3_ent(key_mgmt);
status->security = wpas_key_mgmt_to_zephyr(1, hapd->conf, key_mgmt, proto, sae_pwe);
status->mfp = get_mfp(bss->ieee80211w);
status->channel = conf->channel;
os_memcpy(status->ssid, ssid->ssid, ssid->ssid_len);
status->dtim_period = bss->dtim_period;
status->beacon_interval = conf->beacon_int;
hw_mode = iface->current_mode;
status->link_mode = conf->ieee80211ax ? WIFI_6
: conf->ieee80211ac ? WIFI_5
: conf->ieee80211n ? WIFI_4
: hw_mode->mode == HOSTAPD_MODE_IEEE80211G ? WIFI_3
: hw_mode->mode == HOSTAPD_MODE_IEEE80211A ? WIFI_2
: hw_mode->mode == HOSTAPD_MODE_IEEE80211B ? WIFI_1
: WIFI_0;
status->twt_capable = (hw_mode->he_capab[IEEE80211_MODE_AP].mac_cap[0] & 0x04);
out:
k_mutex_unlock(&hostapd_mutex);
return ret;
}
#ifdef CONFIG_WIFI_NM_HOSTAPD_WPS
static int hapd_ap_wps_pbc(const struct device *dev)
{
struct hostapd_iface *iface;
int ret = -1;
k_mutex_lock(&hostapd_mutex, K_FOREVER);
iface = get_hostapd_handle(dev);
if (!iface) {
ret = -1;
wpa_printf(MSG_ERROR, "Interface %s not found", dev->name);
goto out;
}
if (iface->state != HAPD_IFACE_ENABLED) {
ret = -EBUSY;
wpa_printf(MSG_ERROR, "Interface %s is not in enable state", dev->name);
goto out;
}
if (!hostapd_cli_cmd_v("wps_pbc")) {
goto out;
}
ret = 0;
out:
k_mutex_unlock(&hostapd_mutex);
return ret;
}
static int hapd_ap_wps_pin(const struct device *dev, struct wifi_wps_config_params *params)
{
#define WPS_PIN_EXPIRE_TIME 120
struct hostapd_iface *iface;
char *get_pin_cmd = "WPS_AP_PIN random";
int ret = 0;
k_mutex_lock(&hostapd_mutex, K_FOREVER);
iface = get_hostapd_handle(dev);
if (!iface) {
ret = -1;
wpa_printf(MSG_ERROR, "Interface %s not found", dev->name);
goto out;
}
if (iface->state != HAPD_IFACE_ENABLED) {
ret = -EBUSY;
wpa_printf(MSG_ERROR, "Interface %s is not in enable state", dev->name);
goto out;
}
if (params->oper == WIFI_WPS_PIN_GET) {
if (zephyr_hostapd_cli_cmd_resp(get_pin_cmd, params->pin)) {
goto out;
}
} else if (params->oper == WIFI_WPS_PIN_SET) {
if (!hostapd_cli_cmd_v("wps_check_pin %s", params->pin)) {
goto out;
}
if (!hostapd_cli_cmd_v("wps_pin any %s %d", params->pin, WPS_PIN_EXPIRE_TIME)) {
goto out;
}
} else {
wpa_printf(MSG_ERROR, "Error wps pin operation : %d", params->oper);
goto out;
}
ret = 0;
out:
k_mutex_unlock(&hostapd_mutex);
return ret;
}
int hostapd_ap_wps_config(const struct device *dev, struct wifi_wps_config_params *params)
{
int ret = 0;
if (params->oper == WIFI_WPS_PBC) {
ret = hapd_ap_wps_pbc(dev);
} else if (params->oper == WIFI_WPS_PIN_GET || params->oper == WIFI_WPS_PIN_SET) {
ret = hapd_ap_wps_pin(dev, params);
}
return ret;
}
#endif
int hostapd_ap_enable(const struct device *dev,
struct wifi_connect_req_params *params)
{
struct hostapd_iface *iface;
struct hostapd_data *hapd;
struct wpa_driver_capa capa;
int ret;
if (!net_if_is_admin_up(net_if_lookup_by_dev(dev))) {
wpa_printf(MSG_ERROR,
"Interface %s is down, dropping connect",
dev->name);
return -1;
}
ret = set_ap_bandwidth(dev, params->bandwidth);
if (ret && (ret != -ENOTSUP)) {
wpa_printf(MSG_ERROR, "Failed to set ap bandwidth");
return -EINVAL;
}
k_mutex_lock(&hostapd_mutex, K_FOREVER);
iface = get_hostapd_handle(dev);
if (!iface) {
ret = -1;
wpa_printf(MSG_ERROR, "Interface %s not found", dev->name);
goto out;
}
iface->owner = iface;
if (iface->state == HAPD_IFACE_ENABLED) {
ret = -EBUSY;
wpa_printf(MSG_ERROR, "Interface %s is not in disable state", dev->name);
goto out;
}
ret = hapd_config_network(iface, params);
if (ret) {
wpa_printf(MSG_ERROR, "Failed to configure network for AP: %d", ret);
goto out;
}
hapd = iface->bss[0];
if (!iface->extended_capa || !iface->extended_capa_mask) {
if (hapd->driver->get_capa && hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
iface->extended_capa = capa.extended_capa;
iface->extended_capa_mask = capa.extended_capa_mask;
iface->extended_capa_len = capa.extended_capa_len;
iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
/*
* Override extended capa with per-interface type (AP), if
* available from the driver.
*/
hostapd_get_ext_capa(iface);
} else {
ret = -1;
wpa_printf(MSG_ERROR, "Failed to get capability for AP: %d", ret);
goto out;
}
}
if (!hostapd_cli_cmd_v("enable")) {
goto out;
}
out:
k_mutex_unlock(&hostapd_mutex);
return ret;
}
int hostapd_ap_disable(const struct device *dev)
{
struct hostapd_iface *iface;
int ret = 0;
k_mutex_lock(&hostapd_mutex, K_FOREVER);
iface = get_hostapd_handle(dev);
if (!iface) {
ret = -ENOENT;
wpa_printf(MSG_ERROR, "Interface %s not found", dev->name);
goto out;
}
if (iface->state != HAPD_IFACE_ENABLED) {
ret = -EBUSY;
wpa_printf(MSG_ERROR, "Interface %s is not in enable state", dev->name);
goto out;
}
if (!hostapd_cli_cmd_v("disable")) {
goto out;
}
iface->freq = 0;
out:
k_mutex_unlock(&hostapd_mutex);
return ret;
}
int hostapd_ap_sta_disconnect(const struct device *dev,
const uint8_t *mac_addr)
{
struct hostapd_iface *iface;
int ret = 0;
k_mutex_lock(&hostapd_mutex, K_FOREVER);
iface = get_hostapd_handle(dev);
if (!iface) {
ret = -1;
wpa_printf(MSG_ERROR, "Interface %s not found", dev->name);
goto out;
}
if (iface->state != HAPD_IFACE_ENABLED) {
ret = -EBUSY;
wpa_printf(MSG_ERROR, "Interface %s is not in enable state", dev->name);
goto out;
}
if (!mac_addr) {
ret = -EINVAL;
wpa_printf(MSG_ERROR, "Invalid MAC address");
goto out;
}
if (!hostapd_cli_cmd_v("deauthenticate %02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2],
mac_addr[3], mac_addr[4], mac_addr[5])) {
goto out;
}
out:
k_mutex_unlock(&hostapd_mutex);
return ret;
}
#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_DPP
int hostapd_dpp_dispatch(const struct device *dev, struct wifi_dpp_params *params)
{
int ret;
char *cmd = NULL;
if (params == NULL) {
return -EINVAL;
}
cmd = os_zalloc(SUPPLICANT_DPP_CMD_BUF_SIZE);
if (cmd == NULL) {
return -ENOMEM;
}
/* leave one byte always be 0 */
ret = dpp_params_to_cmd(params, cmd, SUPPLICANT_DPP_CMD_BUF_SIZE - 2);
if (ret) {
os_free(cmd);
return ret;
}
wpa_printf(MSG_DEBUG, "hostapd_cli %s", cmd);
if (zephyr_hostapd_cli_cmd_resp(cmd, params->resp)) {
os_free(cmd);
return -ENOEXEC;
}
os_free(cmd);
return 0;
}
#endif /* CONFIG_WIFI_NM_WPA_SUPPLICANT_DPP */