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>
1033 lines
24 KiB
C
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 */
|