1254 lines
33 KiB
C
Executable File
1254 lines
33 KiB
C
Executable File
/*
|
|
* hostapd / main()
|
|
* Copyright (c) 2002-2022, Jouni Malinen <j@w1.fi>
|
|
*
|
|
* This software may be distributed under the terms of the BSD license.
|
|
* See README for more details.
|
|
*/
|
|
#include "includes.h"
|
|
#include "hostapd_cfg.h"
|
|
#include "common.h"
|
|
#include "ap/hostapd.h"
|
|
#include "eloop.h"
|
|
#include "main_none.h"
|
|
#include "ap/sta_info.h"
|
|
//#include "ps.h"
|
|
#include "bk_wifi_types.h"
|
|
#include "utils/os.h"
|
|
#include <common/bk_kernel_err.h>
|
|
#include "modules/wifi.h"
|
|
#include "bk_wifi.h"
|
|
#include "ap/ap_drv_ops.h"
|
|
#include "common/eapol_common.h"
|
|
#include "signal.h"
|
|
#include "crypto/sha1.h"
|
|
|
|
#include "wpa_ctrl.h"
|
|
#include "wpa_err.h"
|
|
#include "main_none.h"
|
|
|
|
beken_queue_t wpah_queue = NULL;
|
|
static struct hapd_global s_hapd_global;
|
|
struct hapd_interfaces g_hapd_interfaces;
|
|
|
|
const char *bss_iface = "wlan0";
|
|
|
|
extern int ap_channel_switch(struct hostapd_iface *ap_iface, int new_freq);
|
|
|
|
struct hapd_interfaces *hostapd_ctrl_get_interfaces()
|
|
{
|
|
return &g_hapd_interfaces;
|
|
}
|
|
|
|
int hostap_interfaces_is_valid(void)
|
|
{
|
|
return ((g_hapd_interfaces.iface) && (0 < g_hapd_interfaces.count));
|
|
}
|
|
|
|
struct hostapd_iface **hostapd_ctrl_get_hostapd_iface(void)
|
|
{
|
|
return g_hapd_interfaces.iface;
|
|
}
|
|
|
|
int hostapd_ctrl_get_hostapd_iface_count(void)
|
|
{
|
|
return g_hapd_interfaces.count;
|
|
}
|
|
|
|
struct hostapd_config *hostapd_config_read(const char *fname)
|
|
{
|
|
struct hostapd_config *conf = 0;
|
|
int i;
|
|
int errors = 0;
|
|
struct hostapd_bss_config *bss;
|
|
#if CONFIG_WIFI_AP_CUSTOM_RATES
|
|
int len;
|
|
#endif
|
|
|
|
conf = hostapd_config_defaults();
|
|
if (NULL == conf)
|
|
return NULL;
|
|
|
|
conf->last_bss = conf->bss[0];
|
|
bss = conf->last_bss;
|
|
|
|
os_strcpy(bss->iface, bss_iface);
|
|
bk_wifi_ap_get_mac((uint8_t *)&bss->bssid);
|
|
/* set default driver based on configuration */
|
|
conf->driver = wpa_drivers[0];
|
|
conf->last_bss = conf->bss[0];
|
|
conf->channel = g_ap_param_ptr->chann;
|
|
|
|
if (conf->channel >= 1 && conf->channel<= 14)
|
|
conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
|
|
#if CONFIG_SOC_BK7239XX || CONFIG_SOC_BK7286XX
|
|
else if (conf->channel >= 36 && conf->channel<= 165)
|
|
conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
|
|
#endif
|
|
#if CONFIG_AP_HT_IE
|
|
conf->ieee80211n = 1;
|
|
conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED | HT_CAP_INFO_SHORT_GI20MHZ
|
|
| HT_CAP_INFO_TX_STBC
|
|
| HT_CAP_INFO_RX_STBC_1
|
|
| HT_CAP_INFO_MAX_AMSDU_SIZE;
|
|
#endif
|
|
|
|
#if CONFIG_WIFI_AP_HW_MODE
|
|
switch (g_ap_param_ptr->hw_mode) {
|
|
default:
|
|
/* fall through, select first supported hw mode */
|
|
#if CONFIG_AP_HT_IE
|
|
case BK_HW_MODE_BGN:
|
|
conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
|
|
conf->ieee80211n = 1;
|
|
conf->ieee80211ac = 0;
|
|
conf->ieee80211ax = 0;
|
|
break;
|
|
#endif
|
|
case BK_HW_MODE_BG:
|
|
conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
|
|
conf->ieee80211n = 0;
|
|
conf->ieee80211ac = 0;
|
|
conf->ieee80211ax = 0;
|
|
break;
|
|
case BK_HW_MODE_B:
|
|
conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
|
|
conf->ieee80211n = 0;
|
|
conf->ieee80211ac = 0;
|
|
conf->ieee80211ax = 0;
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#if CONFIG_AP_VHT
|
|
conf->ieee80211ac = 1;
|
|
#endif
|
|
|
|
#if CONFIG_AP_HE
|
|
conf->ieee80211ax = 1;
|
|
#endif
|
|
|
|
bss->ssid.ssid_len = g_ap_param_ptr->ssid.length;
|
|
os_memcpy(bss->ssid.ssid, g_ap_param_ptr->ssid.array, bss->ssid.ssid_len);
|
|
bss->max_listen_interval = 65535;
|
|
bss->ieee802_1x = 0;
|
|
bss->ssid.ssid_set = 1;
|
|
bss->ignore_broadcast_ssid = g_ap_param_ptr->hidden_ssid;
|
|
|
|
if (g_ap_param_ptr->cipher_suite == BK_SECURITY_TYPE_WEP) {
|
|
#ifdef CONFIG_WEP_AP
|
|
bss->default_wep_key_len = 0;
|
|
bss->ssid.wep.keys_set = 1;
|
|
bss->ssid.wep.default_len = 10;
|
|
bss->ssid.wep.idx = 0;
|
|
bss->ssid.wep.len[0] = 5;
|
|
bss->ssid.wep.key[0] = (u8 *)os_malloc(bss->ssid.wep.len[0]);
|
|
if (bss->ssid.wep.key[0]) {
|
|
int wkey;
|
|
const char *wep_key = (char *)g_ap_param_ptr->key;
|
|
if (g_ap_param_ptr->key_len == 5) {
|
|
os_memcpy(bss->ssid.wep.key[0], wep_key, g_ap_param_ptr->key_len);
|
|
} else if (g_ap_param_ptr->key_len == 10) {
|
|
for (i = 0; i < bss->ssid.wep.len[0]; i ++) {
|
|
wkey = hex2byte(&wep_key[2 * i]);
|
|
BK_ASSERT(-1 != wkey); /* ASSERT VERIFIED */
|
|
|
|
bss->ssid.wep.key[0][i] = wkey;
|
|
}
|
|
} else {
|
|
WPA_LOGE("WEP_KEY_len_exception\r\n");
|
|
}
|
|
}
|
|
#endif
|
|
} else if (g_ap_param_ptr->cipher_suite == BK_SECURITY_TYPE_WPA_TKIP) {
|
|
bss->wpa = 1;
|
|
bss->wpa_pairwise = WPA_CIPHER_TKIP;
|
|
} else if (g_ap_param_ptr->cipher_suite == BK_SECURITY_TYPE_WPA2_AES) {
|
|
bss->wpa = 2;
|
|
bss->wpa_pairwise = WPA_CIPHER_CCMP;
|
|
} else if (g_ap_param_ptr->cipher_suite == BK_SECURITY_TYPE_WPA2_MIXED) {
|
|
bss->wpa = 2;
|
|
bss->wpa_pairwise = WPA_CIPHER_TKIP | WPA_CIPHER_CCMP;
|
|
} else if (g_ap_param_ptr->cipher_suite == BK_SECURITY_TYPE_WPA3_SAE ||
|
|
g_ap_param_ptr->cipher_suite == BK_SECURITY_TYPE_WPA3_WPA2_MIXED) {
|
|
bss->wpa = 2;
|
|
bss->wpa_pairwise = WPA_CIPHER_CCMP;
|
|
}
|
|
|
|
bss->wpa_key_mgmt = 0;
|
|
if (g_ap_param_ptr->cipher_suite > BK_SECURITY_TYPE_WEP) {
|
|
const char *wpa_key = (char *)g_ap_param_ptr->key;
|
|
if (os_strlen(wpa_key) == 2 * PMK_LEN) {
|
|
WPA_LOGI("Use PSK instead of passphrase for softap\n");
|
|
hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
|
|
bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
|
|
if (!bss->ssid.wpa_psk) {
|
|
WPA_LOGE("%s: OOM\n", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
if (hexstr2bin(wpa_key, bss->ssid.wpa_psk->psk, PMK_LEN)) {
|
|
WPA_LOGE("Key contains non-hex value\n");
|
|
hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
|
|
return NULL;
|
|
}
|
|
bss->ssid.wpa_psk->group = 1;
|
|
os_free(bss->ssid.wpa_passphrase);
|
|
bss->ssid.wpa_passphrase = NULL;
|
|
bss->ssid.wpa_psk_set = 1;
|
|
} else {
|
|
os_free(bss->ssid.wpa_passphrase);
|
|
bss->ssid.wpa_passphrase = os_strdup(wpa_key);
|
|
if (bss->ssid.wpa_passphrase) {
|
|
hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
|
|
bss->ssid.wpa_passphrase_set = 1;
|
|
}
|
|
}
|
|
bss->wpa_key_mgmt |= WPA_KEY_MGMT_PSK;
|
|
}
|
|
|
|
#if CONFIG_AP_VSIE
|
|
if (g_ap_param_ptr->vsie_len) {
|
|
bss->vendor_elements = wpabuf_alloc_copy(g_ap_param_ptr->vsie, g_ap_param_ptr->vsie_len);
|
|
if (!bss->vendor_elements) {
|
|
wpa_printf(MSG_ERROR, "%s OOM\n", __func__);
|
|
errors++;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if CONFIG_WIFI_AP_CUSTOM_RATES
|
|
/* read basic rates */
|
|
len = int_array_len(g_ap_param_ptr->basic_rates);
|
|
if (len > 0) {
|
|
conf->basic_rates = os_zalloc((len + 1) * sizeof(int));
|
|
if (conf->basic_rates) {
|
|
for (i = 0; i < len; i++)
|
|
conf->basic_rates[i] = g_ap_param_ptr->basic_rates[i];
|
|
/* mark last one be -1 */
|
|
conf->basic_rates[len] = -1;
|
|
}
|
|
}
|
|
|
|
/* read supported rates */
|
|
len = int_array_len(g_ap_param_ptr->supported_rates);
|
|
if (len > 0) {
|
|
conf->supported_rates = os_zalloc((len + 1) * sizeof(int));
|
|
if (conf->supported_rates) {
|
|
for (i = 0; i < len; i++)
|
|
conf->supported_rates[i] = g_ap_param_ptr->supported_rates[i];
|
|
/* mark last one be -1 */
|
|
conf->supported_rates[len] = -1;
|
|
}
|
|
}
|
|
|
|
/* read mcs set */
|
|
len = char_array_len(g_ap_param_ptr->mcs_set);
|
|
if (len > 0) {
|
|
conf->mcs_set = os_memdup(g_ap_param_ptr->mcs_set,
|
|
sizeof(g_ap_param_ptr->mcs_set));
|
|
}
|
|
#endif
|
|
|
|
//if (g_ap_param_ptr->cipher_suite >= BK_SECURITY_TYPE_WPA3_SAE) {
|
|
// bss->wpa_key_mgmt = WPA_KEY_MGMT_SAE;;
|
|
// bss->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
|
|
//}
|
|
if (g_ap_param_ptr->cipher_suite == BK_SECURITY_TYPE_WPA3_SAE) {
|
|
bss->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
|
|
} else if (g_ap_param_ptr->cipher_suite == BK_SECURITY_TYPE_WPA3_WPA2_MIXED) {
|
|
bss->wpa_key_mgmt |= WPA_KEY_MGMT_SAE;
|
|
}
|
|
//WPA_LOGI("%s: wpa_key_mgmt 0x%x, cipher_suite %d\n", __func__,
|
|
// bss->wpa_key_mgmt, g_ap_param_ptr->cipher_suite);
|
|
|
|
for (i = 0; i < conf->num_bss; i++)
|
|
hostapd_set_security_params(conf->bss[i], 1);
|
|
|
|
if (hostapd_config_check(conf, 1))
|
|
errors++;
|
|
|
|
return conf;
|
|
}
|
|
|
|
static int hostapd_config_parse_key_mgmt(int line, const char *value)
|
|
{
|
|
int val = 0, last;
|
|
char *start, *end, *buf;
|
|
|
|
buf = os_strdup(value);
|
|
if (buf == NULL)
|
|
return -1;
|
|
start = buf;
|
|
|
|
while (*start != '\0') {
|
|
while (*start == ' ' || *start == '\t')
|
|
start++;
|
|
if (*start == '\0')
|
|
break;
|
|
end = start;
|
|
while (*end != ' ' && *end != '\t' && *end != '\0')
|
|
end++;
|
|
last = *end == '\0';
|
|
*end = '\0';
|
|
if (os_strcmp(start, "WPA-PSK") == 0)
|
|
val |= WPA_KEY_MGMT_PSK;
|
|
else if (os_strcmp(start, "WPA-EAP") == 0)
|
|
val |= WPA_KEY_MGMT_IEEE8021X;
|
|
#ifdef CONFIG_SAE_AP
|
|
else if (os_strcmp(start, "SAE") == 0)
|
|
val |= WPA_KEY_MGMT_SAE;
|
|
else if (os_strcmp(start, "FT-SAE") == 0)
|
|
val |= WPA_KEY_MGMT_FT_SAE;
|
|
#endif /* CONFIG_SAE_AP */
|
|
else {
|
|
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
|
|
line, start);
|
|
os_free(buf);
|
|
return -1;
|
|
}
|
|
|
|
if (last)
|
|
break;
|
|
start = end + 1;
|
|
}
|
|
|
|
os_free(buf);
|
|
if (val == 0) {
|
|
wpa_printf(MSG_ERROR, "Line %d: no key_mgmt values "
|
|
"configured.", line);
|
|
return -1;
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
static int hostapd_config_parse_cipher(int line, const char *value)
|
|
{
|
|
int val = wpa_parse_cipher(value);
|
|
if (val < 0) {
|
|
wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
|
|
line, value);
|
|
return -1;
|
|
}
|
|
if (val == 0) {
|
|
wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
|
|
line);
|
|
return -1;
|
|
}
|
|
return val;
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_WEP_AP
|
|
static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx, char *val)
|
|
{
|
|
size_t len = os_strlen(val);
|
|
|
|
if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL)
|
|
return -1;
|
|
|
|
if (val[0] == '"') {
|
|
if (len < 2 || val[len - 1] != '"')
|
|
return -1;
|
|
len -= 2;
|
|
wep->key[keyidx] = os_malloc(len);
|
|
if (wep->key[keyidx] == NULL)
|
|
return -1;
|
|
os_memcpy(wep->key[keyidx], val + 1, len);
|
|
wep->len[keyidx] = len;
|
|
} else {
|
|
if (len & 1)
|
|
return -1;
|
|
len /= 2;
|
|
wep->key[keyidx] = os_malloc(len);
|
|
if (wep->key[keyidx] == NULL)
|
|
return -1;
|
|
wep->len[keyidx] = len;
|
|
if (hexstr2bin(val, wep->key[keyidx], len) < 0)
|
|
return -1;
|
|
}
|
|
|
|
wep->keys_set++;
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
__maybe_unused static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val);
|
|
static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val)
|
|
{
|
|
char *pos;
|
|
|
|
/* for backwards compatibility, translate ' ' in conf str to ',' */
|
|
pos = val;
|
|
while (pos) {
|
|
pos = os_strchr(pos, ' ');
|
|
if (pos)
|
|
*pos++ = ',';
|
|
}
|
|
if (freq_range_list_parse(&conf->acs_ch_list, val))
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int hostapd_parse_intlist(int **int_list, char *val)
|
|
{
|
|
int *list;
|
|
int count;
|
|
char *pos, *end;
|
|
|
|
os_free(*int_list);
|
|
*int_list = NULL;
|
|
|
|
pos = val;
|
|
count = 0;
|
|
while (*pos != '\0') {
|
|
if (*pos == ' ')
|
|
count++;
|
|
pos++;
|
|
}
|
|
|
|
list = os_malloc(sizeof(int) * (count + 2));
|
|
if (list == NULL)
|
|
return -1;
|
|
pos = val;
|
|
count = 0;
|
|
while (*pos != '\0') {
|
|
end = os_strchr(pos, ' ');
|
|
if (end)
|
|
*end = '\0';
|
|
|
|
list[count++] = atoi(pos);
|
|
if (!end)
|
|
break;
|
|
pos = end + 1;
|
|
}
|
|
list[count] = -1;
|
|
|
|
*int_list = list;
|
|
return 0;
|
|
}
|
|
|
|
static int hostapd_config_fill(struct hostapd_config *conf,
|
|
struct hostapd_bss_config *bss,
|
|
const char *buf, char *pos, int line)
|
|
{
|
|
if (os_strcmp(buf, "ssid") == 0) {
|
|
bss->ssid.ssid_len = os_strlen(pos);
|
|
if (bss->ssid.ssid_len > SSID_MAX_LEN ||
|
|
bss->ssid.ssid_len < 1) {
|
|
wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
|
|
line, pos);
|
|
return 1;
|
|
}
|
|
os_memcpy(bss->ssid.ssid, pos, bss->ssid.ssid_len);
|
|
bss->ssid.ssid_set = 1;
|
|
} else if (os_strcmp(buf, "utf8_ssid") == 0) {
|
|
bss->ssid.utf8_ssid = atoi(pos) > 0;
|
|
} else if (os_strcmp(buf, "ap_isolate") == 0) {
|
|
bss->isolate = atoi(pos);
|
|
} else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
|
|
bss->ap_max_inactivity = atoi(pos);
|
|
} else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
|
|
bss->skip_inactivity_poll = atoi(pos);
|
|
} else if (os_strcmp(buf, "country_code") == 0) {
|
|
os_memcpy(conf->country, pos, 2);
|
|
/* FIX: make this configurable */
|
|
conf->country[2] = ' ';
|
|
} else if (os_strcmp(buf, "ieee80211d") == 0) {
|
|
conf->ieee80211d = atoi(pos);
|
|
} else if (os_strcmp(buf, "ieee80211h") == 0) {
|
|
conf->ieee80211h = atoi(pos);
|
|
} else if (os_strcmp(buf, "eapol_version") == 0) {
|
|
bss->eapol_version = atoi(pos);
|
|
if (bss->eapol_version < 1 || bss->eapol_version > 2) {
|
|
wpa_printf(MSG_ERROR,
|
|
"Line %d: invalid EAPOL version (%d): '%s'.",
|
|
line, bss->eapol_version, pos);
|
|
return 1;
|
|
}
|
|
wpa_printf(MSG_DEBUG, "eapol_version=%d", bss->eapol_version);
|
|
#ifdef CONFIG_WEP_AP
|
|
} else if (os_strcmp(buf, "wep_rekey_period") == 0) {
|
|
bss->wep_rekeying_period = atoi(pos);
|
|
if (bss->wep_rekeying_period < 0) {
|
|
wpa_printf(MSG_ERROR, "Line %d: invalid period %d",
|
|
line, bss->wep_rekeying_period);
|
|
return 1;
|
|
}
|
|
#endif
|
|
} else if (os_strcmp(buf, "eap_reauth_period") == 0) {
|
|
bss->eap_reauth_period = atoi(pos);
|
|
if (bss->eap_reauth_period < 0) {
|
|
wpa_printf(MSG_ERROR, "Line %d: invalid period %d",
|
|
line, bss->eap_reauth_period);
|
|
return 1;
|
|
}
|
|
} else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) {
|
|
bss->eapol_key_index_workaround = atoi(pos);
|
|
} else if (os_strcmp(buf, "auth_algs") == 0) {
|
|
bss->auth_algs = atoi(pos);
|
|
if (bss->auth_algs == 0) {
|
|
wpa_printf(MSG_ERROR, "Line %d: no authentication algorithms allowed",
|
|
line);
|
|
return 1;
|
|
}
|
|
} else if (os_strcmp(buf, "max_num_sta") == 0) {
|
|
bss->max_num_sta = atoi(pos);
|
|
if (bss->max_num_sta < 0 ||
|
|
bss->max_num_sta > MAX_STA_COUNT) {
|
|
wpa_printf(MSG_ERROR, "Line %d: Invalid max_num_sta=%d; allowed range 0..%d",
|
|
line, bss->max_num_sta, MAX_STA_COUNT);
|
|
return 1;
|
|
}
|
|
} else if (os_strcmp(buf, "wpa") == 0) {
|
|
bss->wpa = atoi(pos);
|
|
} else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
|
|
bss->wpa_group_rekey = atoi(pos);
|
|
} else if (os_strcmp(buf, "wpa_strict_rekey") == 0) {
|
|
bss->wpa_strict_rekey = atoi(pos);
|
|
} else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
|
|
bss->wpa_gmk_rekey = atoi(pos);
|
|
} else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
|
|
bss->wpa_ptk_rekey = atoi(pos);
|
|
} else if (os_strcmp(buf, "wpa_passphrase") == 0) {
|
|
int len = os_strlen(pos);
|
|
if (len < 8 || len > 63) {
|
|
wpa_printf(MSG_ERROR, "Line %d: invalid WPA passphrase length %d (expected 8..63)",
|
|
line, len);
|
|
return 1;
|
|
}
|
|
os_free(bss->ssid.wpa_passphrase);
|
|
bss->ssid.wpa_passphrase = os_strdup(pos);
|
|
if (bss->ssid.wpa_passphrase) {
|
|
hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
|
|
bss->ssid.wpa_passphrase_set = 1;
|
|
}
|
|
} else if (os_strcmp(buf, "wpa_psk") == 0) {
|
|
hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
|
|
bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
|
|
if (bss->ssid.wpa_psk == NULL)
|
|
return 1;
|
|
if (hexstr2bin(pos, bss->ssid.wpa_psk->psk, PMK_LEN) ||
|
|
pos[PMK_LEN * 2] != '\0') {
|
|
wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
|
|
line, pos);
|
|
hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
|
|
return 1;
|
|
}
|
|
bss->ssid.wpa_psk->group = 1;
|
|
os_free(bss->ssid.wpa_passphrase);
|
|
bss->ssid.wpa_passphrase = NULL;
|
|
bss->ssid.wpa_psk_set = 1;
|
|
} else if (os_strcmp(buf, "wpa_key_mgmt") == 0) {
|
|
bss->wpa_key_mgmt = hostapd_config_parse_key_mgmt(line, pos);
|
|
if (bss->wpa_key_mgmt == -1)
|
|
return 1;
|
|
} else if (os_strcmp(buf, "wpa_pairwise") == 0) {
|
|
bss->wpa_pairwise = hostapd_config_parse_cipher(line, pos);
|
|
if (bss->wpa_pairwise == -1 || bss->wpa_pairwise == 0)
|
|
return 1;
|
|
if (bss->wpa_pairwise &
|
|
(WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)) {
|
|
wpa_printf(MSG_ERROR, "Line %d: unsupported pairwise cipher suite '%s'",
|
|
bss->wpa_pairwise, pos);
|
|
return 1;
|
|
}
|
|
} else if (os_strcmp(buf, "rsn_pairwise") == 0) {
|
|
bss->rsn_pairwise = hostapd_config_parse_cipher(line, pos);
|
|
if (bss->rsn_pairwise == -1 || bss->rsn_pairwise == 0)
|
|
return 1;
|
|
if (bss->rsn_pairwise &
|
|
(WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)) {
|
|
wpa_printf(MSG_ERROR, "Line %d: unsupported pairwise cipher suite '%s'",
|
|
bss->rsn_pairwise, pos);
|
|
return 1;
|
|
}
|
|
#ifdef CONFIG_PEERKEY
|
|
} else if (os_strcmp(buf, "peerkey") == 0) {
|
|
bss->peerkey = atoi(pos);
|
|
#endif /* CONFIG_PEERKEY */
|
|
} else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
|
|
bss->use_pae_group_addr = atoi(pos);
|
|
} else if (os_strcmp(buf, "hw_mode") == 0) {
|
|
if (0) {}
|
|
#ifdef CONFIG_FULL_HOSTAPD
|
|
else if (os_strcmp(pos, "a") == 0)
|
|
conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
|
|
#endif
|
|
else if (os_strcmp(pos, "b") == 0)
|
|
conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
|
|
else if (os_strcmp(pos, "g") == 0)
|
|
conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
|
|
#ifdef CONFIG_FULL_HOSTAPD
|
|
else if (os_strcmp(pos, "ad") == 0)
|
|
conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
|
|
#endif
|
|
else if (os_strcmp(pos, "any") == 0)
|
|
conf->hw_mode = HOSTAPD_MODE_IEEE80211ANY;
|
|
else {
|
|
wpa_printf(MSG_ERROR, "Line %d: unknown hw_mode '%s'",
|
|
line, pos);
|
|
return 1;
|
|
}
|
|
#ifdef CONFIG_WPS
|
|
} else if (os_strcmp(buf, "wps_rf_bands") == 0) {
|
|
if (os_strcmp(pos, "ad") == 0)
|
|
bss->wps_rf_bands = WPS_RF_60GHZ;
|
|
else if (os_strcmp(pos, "a") == 0)
|
|
bss->wps_rf_bands = WPS_RF_50GHZ;
|
|
else if (os_strcmp(pos, "g") == 0 ||
|
|
os_strcmp(pos, "b") == 0)
|
|
bss->wps_rf_bands = WPS_RF_24GHZ;
|
|
else if (os_strcmp(pos, "ag") == 0 ||
|
|
os_strcmp(pos, "ga") == 0)
|
|
bss->wps_rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ;
|
|
else {
|
|
wpa_printf(MSG_ERROR,
|
|
"Line %d: unknown wps_rf_band '%s'",
|
|
line, pos);
|
|
return 1;
|
|
}
|
|
#endif
|
|
} else if (os_strcmp(buf, "channel") == 0) {
|
|
conf->channel = atoi(pos);
|
|
conf->acs = conf->channel == 0;
|
|
} else if (os_strcmp(buf, "beacon_int") == 0) {
|
|
int val = atoi(pos);
|
|
/* MIB defines range as 1..65535, but very small values
|
|
* cause problems with the current implementation.
|
|
* Since it is unlikely that this small numbers are
|
|
* useful in real life scenarios, do not allow beacon
|
|
* period to be set below 15 TU. */
|
|
if (val < 15 || val > 65535) {
|
|
wpa_printf(MSG_ERROR, "Line %d: invalid beacon_int %d (expected 15..65535)",
|
|
line, val);
|
|
return 1;
|
|
}
|
|
conf->beacon_int = val;
|
|
} else if (os_strcmp(buf, "dtim_period") == 0) {
|
|
bss->dtim_period = atoi(pos);
|
|
if (bss->dtim_period < 1 || bss->dtim_period > 255) {
|
|
wpa_printf(MSG_ERROR, "Line %d: invalid dtim_period %d",
|
|
line, bss->dtim_period);
|
|
return 1;
|
|
}
|
|
} else if (os_strcmp(buf, "supported_rates") == 0) {
|
|
if (hostapd_parse_intlist(&conf->supported_rates, pos)) {
|
|
wpa_printf(MSG_ERROR, "Line %d: invalid rate list",
|
|
line);
|
|
return 1;
|
|
}
|
|
} else if (os_strcmp(buf, "basic_rates") == 0) {
|
|
if (hostapd_parse_intlist(&conf->basic_rates, pos)) {
|
|
wpa_printf(MSG_ERROR, "Line %d: invalid rate list",
|
|
line);
|
|
return 1;
|
|
}
|
|
} else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
|
|
bss->ignore_broadcast_ssid = atoi(pos);
|
|
#ifdef CONFIG_WEP_AP
|
|
} else if (os_strcmp(buf, "wep_default_key") == 0) {
|
|
bss->ssid.wep.idx = atoi(pos);
|
|
if (bss->ssid.wep.idx > 3) {
|
|
wpa_printf(MSG_ERROR,
|
|
"Invalid wep_default_key index %d",
|
|
bss->ssid.wep.idx);
|
|
return 1;
|
|
}
|
|
} else if (os_strcmp(buf, "wep_key0") == 0 ||
|
|
os_strcmp(buf, "wep_key1") == 0 ||
|
|
os_strcmp(buf, "wep_key2") == 0 ||
|
|
os_strcmp(buf, "wep_key3") == 0) {
|
|
if (hostapd_config_read_wep(&bss->ssid.wep,
|
|
buf[7] - '0', pos)) {
|
|
wpa_printf(MSG_ERROR, "Line %d: invalid WEP key '%s'",
|
|
line, buf);
|
|
return 1;
|
|
}
|
|
#endif
|
|
} else if (os_strcmp(buf, "ap_table_max_size") == 0) {
|
|
conf->ap_table_max_size = atoi(pos);
|
|
} else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
|
|
conf->ap_table_expiration_time = atoi(pos);
|
|
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
|
|
bss->max_listen_interval = atoi(pos);
|
|
} else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
|
|
bss->disable_pmksa_caching = atoi(pos);
|
|
} else if (os_strcmp(buf, "okc") == 0) {
|
|
bss->okc = atoi(pos);
|
|
} else if (os_strcmp(buf, "disassoc_low_ack") == 0) {
|
|
bss->disassoc_low_ack = atoi(pos);
|
|
#ifdef CONFIG_SAE_AP
|
|
} else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
|
|
bss->sae_anti_clogging_threshold = atoi(pos);
|
|
} else if (os_strcmp(buf, "sae_groups") == 0) {
|
|
if (hostapd_parse_intlist(&bss->sae_groups, pos)) {
|
|
wpa_printf(MSG_ERROR,
|
|
"Line %d: Invalid sae_groups value '%s'",
|
|
line, pos);
|
|
return 1;
|
|
}
|
|
#endif
|
|
} else {
|
|
wpa_printf(MSG_ERROR,
|
|
"Line %d: unknown configuration item '%s'",
|
|
line, buf);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int hostapd_set_iface(struct hostapd_config *conf,
|
|
struct hostapd_bss_config *bss, const char *field,
|
|
char *value)
|
|
{
|
|
int errors;
|
|
size_t i;
|
|
|
|
errors = hostapd_config_fill(conf, bss, field, value, 0);
|
|
if (errors) {
|
|
wpa_printf(MSG_INFO, "Failed to set configuration field '%s' "
|
|
"to value '%s'", field, value);
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < conf->num_bss; i++)
|
|
hostapd_set_security_params(conf->bss[i], 0);
|
|
|
|
if (hostapd_config_check(conf, 0)) {
|
|
wpa_printf(MSG_ERROR, "Configuration check failed");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* hostapd_driver_init - Preparate driver interface
|
|
*/
|
|
static int hostapd_driver_init(struct hostapd_iface *iface)
|
|
{
|
|
struct wpa_init_params params;
|
|
size_t i;
|
|
struct hostapd_data *hapd = iface->bss[0];
|
|
struct hostapd_bss_config *conf = hapd->conf;
|
|
u8 *b = conf->bssid;
|
|
struct wpa_driver_capa capa;
|
|
|
|
if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
|
|
wpa_printf(MSG_ERROR, "No hostapd driver wrapper available");
|
|
return -1;
|
|
}
|
|
|
|
/* Initialize the driver interface */
|
|
if (is_zero_ether_addr(b)) {
|
|
b = NULL;
|
|
WPA_LOGE("hostapd_driver_init conf->bssid is null\r\n");
|
|
return -1;
|
|
}
|
|
|
|
os_memset(¶ms, 0, sizeof(params));
|
|
for (i = 0; wpa_drivers[i]; i++) {
|
|
if (wpa_drivers[i] != hapd->driver)
|
|
continue;
|
|
|
|
if (s_hapd_global.drv_priv[i] == NULL &&
|
|
wpa_drivers[i]->global_init) {
|
|
s_hapd_global.drv_priv[i] = wpa_drivers[i]->global_init(iface->interfaces);
|
|
if (s_hapd_global.drv_priv[i] == NULL) {
|
|
wpa_printf(MSG_ERROR, "Failed to initialize "
|
|
"driver '%s'",
|
|
wpa_drivers[i]->name);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
params.global_priv = s_hapd_global.drv_priv[i];
|
|
break;
|
|
}
|
|
params.bssid = b;
|
|
params.ifname = hapd->conf->iface;
|
|
params.driver_params = hapd->iconf->driver_params;
|
|
params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
|
|
|
|
params.num_bridge = hapd->iface->num_bss;
|
|
params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *));
|
|
if (params.bridge == NULL)
|
|
return -1;
|
|
|
|
for (i = 0; i < hapd->iface->num_bss; i++) {
|
|
struct hostapd_data *bss = hapd->iface->bss[i];
|
|
#ifdef CONFIG_FULL_HOSTAPD
|
|
if (bss->conf->bridge[0]) {
|
|
params.bridge[i] = bss->conf->bridge;
|
|
}
|
|
#endif
|
|
WPA_LOGD("clear CSA in progress flag [%d:%d]\r\n", i, bss->csa_in_progress);
|
|
bss->csa_in_progress = 0;
|
|
}
|
|
|
|
os_memcpy(hapd->own_addr, b, ETH_ALEN);
|
|
params.own_addr = hapd->own_addr;
|
|
|
|
hapd->drv_priv = hapd->driver->hapd_init(hapd, ¶ms);
|
|
os_free(params.bridge);
|
|
if (hapd->drv_priv == NULL) {
|
|
wpa_printf(MSG_ERROR, "%s driver initialization failed.",
|
|
hapd->driver->name);
|
|
hapd->driver = NULL;
|
|
return -1;
|
|
}
|
|
|
|
if (hapd->driver->get_capa &&
|
|
hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
|
|
#ifdef CONFIG_FULL_HOSTAPD
|
|
struct wowlan_triggers *triggs;
|
|
#endif
|
|
|
|
iface->drv_flags = capa.flags;
|
|
iface->drv_flags2 = capa.flags2;
|
|
iface->probe_resp_offloads = capa.probe_resp_offloads;
|
|
/*
|
|
* Use default extended capa values from per-radio information
|
|
*/
|
|
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);
|
|
|
|
#ifdef CONFIG_FULL_HOSTAPD
|
|
triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa);
|
|
if (triggs && hapd->driver->set_wowlan) {
|
|
if (hapd->driver->set_wowlan(hapd->drv_priv, triggs))
|
|
wpa_printf(MSG_ERROR, "set_wowlan failed");
|
|
}
|
|
os_free(triggs);
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* hostapd_interface_init - Read configuration file and init BSS data
|
|
*
|
|
* This function is used to parse configuration file for a full interface (one
|
|
* or more BSSes sharing the same radio) and allocate memory for the BSS
|
|
* g_hapd_interfaces. No actiual driver operations are started.
|
|
*/
|
|
static struct hostapd_iface *
|
|
hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name,
|
|
const char *config_fname, int debug)
|
|
{
|
|
struct hostapd_iface *iface;
|
|
int k;
|
|
|
|
wpa_printf(MSG_DEBUG, "Configuration file: %s", config_fname);
|
|
iface = hostapd_init(interfaces, config_fname);
|
|
if (!iface)
|
|
return NULL;
|
|
|
|
if (if_name) {
|
|
os_strlcpy(iface->conf->bss[0]->iface, if_name,
|
|
sizeof(iface->conf->bss[0]->iface));
|
|
}
|
|
|
|
iface->interfaces = interfaces;
|
|
|
|
for (k = 0; k < debug; k++) {
|
|
if (iface->bss[0]->conf->logger_stdout_level > 0)
|
|
iface->bss[0]->conf->logger_stdout_level--;
|
|
}
|
|
|
|
if (iface->conf->bss[0]->iface[0] == '\0' &&
|
|
!hostapd_drv_none(iface->bss[0])) {
|
|
wpa_printf(MSG_ERROR,
|
|
"Interface name not specified in %s, nor by '-i' parameter",
|
|
config_fname);
|
|
hostapd_interface_deinit_free(iface);
|
|
return NULL;
|
|
}
|
|
|
|
return iface;
|
|
}
|
|
|
|
static int hostapd_global_init(struct hapd_interfaces *interfaces,
|
|
const char *entropy_file)
|
|
{
|
|
int i;
|
|
|
|
os_memset(&s_hapd_global, 0, sizeof(s_hapd_global));
|
|
|
|
//hostapd_logger_register_cb(hostapd_logger_cb);
|
|
|
|
#ifdef CONFIG_IEEE8021X_AP
|
|
if (eap_server_register_methods()) {
|
|
wpa_printf(MSG_ERROR, "Failed to register EAP methods");
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
for (i = 0; wpa_drivers[i]; i++)
|
|
s_hapd_global.drv_count++;
|
|
if (s_hapd_global.drv_count == 0) {
|
|
wpa_printf(MSG_ERROR, "No drivers enabled");
|
|
return -1;
|
|
}
|
|
s_hapd_global.drv_priv = os_calloc(s_hapd_global.drv_count, sizeof(void *));
|
|
if (s_hapd_global.drv_priv == NULL)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void hostapd_global_deinit(const char *pid_file, int eloop_initialized)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; wpa_drivers[i] && s_hapd_global.drv_priv; i++) {
|
|
if (!s_hapd_global.drv_priv[i])
|
|
continue;
|
|
|
|
if(wpa_drivers[i]->global_deinit)
|
|
wpa_drivers[i]->global_deinit(s_hapd_global.drv_priv[i]);
|
|
}
|
|
os_free(s_hapd_global.drv_priv);
|
|
s_hapd_global.drv_priv = NULL;
|
|
|
|
#ifdef EAP_SERVER_TNC
|
|
tncs_global_deinit();
|
|
#endif /* EAP_SERVER_TNC */
|
|
|
|
eloop_free_resource();
|
|
|
|
#ifdef CONFIG_IEEE8021X_AP
|
|
eap_server_unregister_methods();
|
|
#endif
|
|
|
|
os_daemonize_terminate(pid_file);
|
|
}
|
|
|
|
static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
|
|
const char *pid_file)
|
|
{
|
|
if (daemonize && os_daemonize(pid_file)) {
|
|
return -1;
|
|
}
|
|
|
|
eloop_run();
|
|
|
|
return 0;
|
|
}
|
|
|
|
__maybe_unused static const char * hostapd_msg_ifname_cb(void *ctx);
|
|
static const char * hostapd_msg_ifname_cb(void *ctx)
|
|
{
|
|
struct hostapd_data *hapd = ctx;
|
|
if (hapd && hapd->conf)
|
|
return hapd->conf->iface;
|
|
return NULL;
|
|
}
|
|
|
|
/* Periodic cleanup tasks */
|
|
static void hostapd_periodic(void *eloop_ctx, void *timeout_ctx)
|
|
{
|
|
}
|
|
|
|
int hostapd_main_exit(void)
|
|
{
|
|
size_t i;
|
|
|
|
if (0 == g_hapd_interfaces.count)
|
|
return 0;
|
|
|
|
for (i = 0; i < g_hapd_interfaces.count; i++) {
|
|
if (!g_hapd_interfaces.iface[i])
|
|
continue;
|
|
|
|
g_hapd_interfaces.iface[i]->driver_ap_teardown =
|
|
!!(g_hapd_interfaces.iface[i]->drv_flags &
|
|
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
|
|
|
|
hostapd_interface_deinit_free(g_hapd_interfaces.iface[i]);
|
|
g_hapd_interfaces.iface[i] = NULL;
|
|
}
|
|
os_free(g_hapd_interfaces.iface);
|
|
g_hapd_interfaces.iface = NULL;
|
|
g_hapd_interfaces.count = 0;
|
|
|
|
eloop_cancel_timeout(hostapd_periodic, &g_hapd_interfaces, NULL);
|
|
hostapd_global_deinit(NULL, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Usage:
|
|
* hostapd -g /var/run/hostapd/global -b phy0:ath10k.conf -b phy0:ath10k-1.conf -b phy0:ath10k-2.conf
|
|
* -b <phyX>:<bss.conf> : add a bss config
|
|
*
|
|
* ath10k-1.conf:
|
|
* interface=wlan0-1
|
|
* ssid=ath10k-1
|
|
* bssid=02:00:00:00:03:01
|
|
*
|
|
* ath10k-2.conf:
|
|
* interface=wlan0-2
|
|
* ssid=ath10k-2
|
|
* bssid=02:00:00:00:03:02
|
|
* wpa=2
|
|
* wpa_passphrase=0987654321
|
|
* wpa_key_mgmt=WPA-PSK
|
|
* rsn_pairwise=CCMP
|
|
*
|
|
*/
|
|
int hostapd_main_entry(int argc, char *argv[])
|
|
{
|
|
int ret = 1;
|
|
size_t i;
|
|
int debug = 0;
|
|
char *pid_file = NULL;
|
|
const char *log_file = NULL;
|
|
const char *entropy_file = NULL;
|
|
#ifdef CONFIG_MBSSID
|
|
char *bss_config[1] = {CFG_BSS_CONFIG}; //"wangzhilei_config:bss_fname"
|
|
#endif
|
|
size_t num_bss_configs = 0;
|
|
//int start_ifaces_in_sync = 0;
|
|
//char **if_names = NULL;
|
|
//size_t if_names_size = 0;
|
|
#ifdef CONFIG_DPP
|
|
struct dpp_global_config dpp_conf;
|
|
#endif /* CONFIG_DPP */
|
|
|
|
if (os_program_init()) {
|
|
//os_free(ap_iface_buf);
|
|
return -1;
|
|
}
|
|
|
|
os_memset(&g_hapd_interfaces, 0, sizeof(g_hapd_interfaces));
|
|
g_hapd_interfaces.reload_config = hostapd_reload_config;
|
|
g_hapd_interfaces.config_read_cb = hostapd_config_read;
|
|
g_hapd_interfaces.for_each_interface = hostapd_for_each_interface;
|
|
g_hapd_interfaces.ctrl_iface_init = 0;
|
|
g_hapd_interfaces.ctrl_iface_deinit = 0;
|
|
g_hapd_interfaces.driver_init = hostapd_driver_init;
|
|
#ifdef CONFIG_DPP
|
|
os_memset(&dpp_conf, 0, sizeof(dpp_conf));
|
|
/* TODO: dpp_conf.msg_ctx? */
|
|
interfaces.dpp = dpp_global_init(&dpp_conf);
|
|
if (!interfaces.dpp)
|
|
return -1;
|
|
#endif /* CONFIG_DPP */
|
|
|
|
wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
|
|
|
|
g_hapd_interfaces.count = argc - 1;
|
|
if (g_hapd_interfaces.count || num_bss_configs) {
|
|
g_hapd_interfaces.iface = os_calloc(g_hapd_interfaces.count + num_bss_configs,
|
|
sizeof(struct hostapd_iface *));
|
|
if (g_hapd_interfaces.iface == NULL) {
|
|
//os_free(ap_iface_buf);
|
|
WPA_LOGE("malloc failed\r\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (hostapd_global_init(&g_hapd_interfaces, entropy_file)) {
|
|
//os_free(ap_iface_buf);
|
|
WPA_LOGE("Failed to initialize global context\r\n");
|
|
return -1;
|
|
}
|
|
|
|
/* Allocate and parse configuration for full interface files */
|
|
for (i = 0; i < g_hapd_interfaces.count; i++) {
|
|
char *config_fname = CFG_CONFIG_FNAME; //"beken_cfg_fname"
|
|
|
|
g_hapd_interfaces.iface[i] = hostapd_interface_init(&g_hapd_interfaces,
|
|
"wlan0",
|
|
config_fname,
|
|
debug);
|
|
if (!g_hapd_interfaces.iface[i]) {
|
|
WPA_LOGE("Failed to initialize interface\r\n");
|
|
goto out;
|
|
}
|
|
//if (start_ifaces_in_sync)
|
|
// interfaces.iface[i]->need_to_start_in_sync = 1;
|
|
}
|
|
|
|
#ifdef CONFIG_MBSSID
|
|
/* Allocate and parse configuration for per-BSS files */
|
|
for (i = 0; i < num_bss_configs; i++) {
|
|
struct hostapd_iface *iface;
|
|
char *fname;
|
|
|
|
wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]);
|
|
fname = os_strchr(bss_config[i], ':');
|
|
if (fname == NULL) {
|
|
wpa_printf(MSG_ERROR,
|
|
"Invalid BSS config identifier '%s'",
|
|
bss_config[i]);
|
|
goto out;
|
|
}
|
|
*fname++ = '\0';
|
|
iface = hostapd_interface_init_bss(&g_hapd_interfaces, bss_config[i],
|
|
fname, debug);
|
|
if (iface == NULL)
|
|
goto out;
|
|
for (j = 0; j < g_hapd_interfaces.count; j++) {
|
|
if (g_hapd_interfaces.iface[j] == iface)
|
|
break;
|
|
}
|
|
if (j == g_hapd_interfaces.count) {
|
|
struct hostapd_iface **tmp;
|
|
tmp = os_realloc_array(g_hapd_interfaces.iface,
|
|
g_hapd_interfaces.count + 1,
|
|
sizeof(struct hostapd_iface *));
|
|
if (tmp == NULL) {
|
|
hostapd_interface_deinit_free(iface);
|
|
goto out;
|
|
}
|
|
g_hapd_interfaces.iface = tmp;
|
|
g_hapd_interfaces.iface[g_hapd_interfaces.count++] = iface;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Enable configured g_hapd_interfaces. Depending on channel configuration,
|
|
* this may complete full initialization before returning or use a
|
|
* callback mechanism to complete setup in case of operations like HT
|
|
* co-ex scans, ACS, or DFS are needed to determine channel parameters.
|
|
* In such case, the interface will be enabled from eloop context within
|
|
* hostapd_global_run().
|
|
*/
|
|
g_hapd_interfaces.terminate_on_error = g_hapd_interfaces.count;
|
|
for (i = 0; i < g_hapd_interfaces.count; i++) {
|
|
if (hostapd_driver_init(g_hapd_interfaces.iface[i]) ||
|
|
hostapd_setup_interface(g_hapd_interfaces.iface[i]))
|
|
goto out;
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
return ret;
|
|
|
|
out:
|
|
/* Deinitialize all g_hapd_interfaces */
|
|
WPA_LOGE("hostapd_main_init_failed\r\n");
|
|
for (i = 0; i < g_hapd_interfaces.count; i++) {
|
|
if (!g_hapd_interfaces.iface[i])
|
|
continue;
|
|
|
|
g_hapd_interfaces.iface[i]->driver_ap_teardown =
|
|
!!(g_hapd_interfaces.iface[i]->drv_flags &
|
|
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
|
|
|
|
hostapd_interface_deinit_free(g_hapd_interfaces.iface[i]);
|
|
g_hapd_interfaces.iface[i] = NULL;
|
|
}
|
|
os_free(g_hapd_interfaces.iface);
|
|
g_hapd_interfaces.iface = NULL;
|
|
g_hapd_interfaces.count = 0;
|
|
#ifdef CONFIG_DPP
|
|
dpp_global_deinit(g_hapd_interfaces.dpp);
|
|
#endif /* CONFIG_DPP */
|
|
|
|
eloop_cancel_timeout(hostapd_periodic, &g_hapd_interfaces, NULL);
|
|
hostapd_global_deinit(pid_file, 1);
|
|
|
|
os_free(pid_file);
|
|
pid_file = NULL;
|
|
|
|
//os_free(ap_iface_buf);
|
|
//ap_iface_buf = NULL;
|
|
|
|
if (log_file)
|
|
wpa_debug_close_file();
|
|
wpa_debug_close_linux_tracing();
|
|
|
|
os_program_deinit();
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
__maybe_unused static void hostapd_thread_main( void *arg );
|
|
static void hostapd_thread_main( void *arg )
|
|
{
|
|
int daemonize = 0;
|
|
char *pid_file = NULL;
|
|
|
|
if (hostapd_global_run(&g_hapd_interfaces, daemonize, pid_file)) {
|
|
wpa_printf(MSG_ERROR, "Failed to start eloop");
|
|
}
|
|
}
|
|
|
|
int hostapd_channel_switch(int new_freq)
|
|
{
|
|
return wpa_ctrl_request_async(WPA_CTRL_CMD_AP_CHAN_SWITCH, (void *)new_freq);
|
|
}
|
|
|
|
int wpa_hostapd_queue_command(wpah_msg_t *msg)
|
|
{
|
|
int ret = WPA_FAIL;
|
|
|
|
if (!wpah_queue)
|
|
return WPA_ERR_WPAH_QUEUE_INIT;
|
|
|
|
ret = rtos_push_to_queue(&wpah_queue, msg, BEKEN_NO_WAIT);
|
|
if (kNoErr != ret)
|
|
WPA_LOGE("wpa_hostapd_queue_command:%d\r\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t wpa_hostapd_queue_poll(uint32_t param)
|
|
{
|
|
bk_err_t ret = 0;
|
|
wpah_msg_t msg = {0};
|
|
|
|
if (NULL == wpah_queue)
|
|
goto poll_exit;
|
|
|
|
msg.cmd = WPA_CTRL_CMD_SOCKET;
|
|
msg.argu = (u32)param;
|
|
ret = rtos_push_to_queue(&wpah_queue, &msg, BEKEN_NO_WAIT);
|
|
if (kNoErr != ret)
|
|
WPA_LOGE("wpa_hostapd_queue_poll_failed:%d\r\n", ret);
|
|
|
|
poll_exit:
|
|
return ret;
|
|
}
|
|
|
|
bool is_wpah_queue_full()
|
|
{
|
|
return rtos_is_queue_full(&wpah_queue);
|
|
}
|
|
|
|
int wpas_calculate_ap_pmk(const char *passphrase, const uint8_t *ssid, uint8_t *pmk)
|
|
{
|
|
int ret;
|
|
|
|
const char *p = (const char*)(char *)ssid;
|
|
ret = pbkdf2_sha1(passphrase, ssid, os_strlen(p), 4096, pmk, 32);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// eof
|
|
|