blob: 97367d35c531cb5d09909e822154fe08da47b053 [file] [log] [blame]
/**
* 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 */