/* * hostapd / main() * Copyright (c) 2002-2022, Jouni Malinen * * 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 #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 : : 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