/************************************************************************************************************** * altobeam RTOS WSM host interface (HI) implementation * * Copyright (c) 2018, altobeam.inc All rights reserved. * * The source code contains proprietary information of AltoBeam, and shall not be distributed, * copied, reproduced, or disclosed in whole or in part without prior written permission of AltoBeam. *****************************************************************************************************************/ /* #define WLAN_FC_GET_STYPE(fc) (fc & ATBM_IEEE80211_FCTL_STYPE) #define WLAN_FC_STYPE_BEACON IEEE80211_STYPE_BEACON #define WLAN_FC_STYPE_ACTION ATBM_IEEE80211_STYPE_ACTION #define WLAN_FC_STYPE_AUTH ATBM_IEEE80211_STYPE_AUTH #define WLAN_FC_STYPE_ASSOC_REQ ATBM_IEEE80211_STYPE_ASSOC_REQ */ #include "atbm_hal.h" #include "atbm_sha1.h" static atbm_uint32 dot11RSNAConfigPairwiseUpdateCount = 4; static atbm_uint32 dot11RSNAConfigGroupUpdateCount = 4; struct hostapd_data *g_hostapd; atbm_void __wpa_send_eapol(struct atbmwifi_cfg *config, struct atbmwifi_wpa_state_machine *sm, int key_info, const atbm_uint8 *key_rsc, const atbm_uint8 *nonce, const atbm_uint8 *kde, atbm_size_t kde_len, int keyidx, int encr, int force_version); int hostapd_eapol_init(struct atbmwifi_vif *priv,struct atbmwifi_wpa_state_machine *sm); static atbm_void hostapd_4_way_handshake_err(struct atbmwifi_vif *priv,struct atbmwifi_wpa_state_machine *sm); atbm_void hostapd_4_way_handshake_start(struct atbmwifi_vif *priv,struct hostapd_sta_info *sta); atbm_void hostapd_link_sta_sm(struct atbmwifi_vif *priv, struct atbmwifi_sta_priv *sta_priv,atbm_uint8* mac); extern atbm_void handle_eap(struct hostapd_data *hapd, struct hostapd_sta_info *sta, atbm_uint8 *buf, atbm_size_t len); extern atbm_void hostapd_deinit_wps(struct hostapd_data *hapd); extern int hostapd_init_wps(struct atbmwifi_vif *priv); struct atbmwifi_vif *wpa_sm_get_priv(struct atbmwifi_wpa_state_machine *sm) { struct atbmwifi_wpa_group *group = sm->group; struct hostapd_data *hostapd = atbm_container_of(group,struct hostapd_data,group); return hostapd->priv; } static atbm_void wpa_send_eapol_timeout(atbm_void *data1,atbm_void *data2) { struct atbmwifi_wpa_state_machine *sm = (struct atbmwifi_wpa_state_machine *)data1; struct atbmwifi_vif *priv = wpa_sm_get_priv(sm); hostapd_4_way_handshake_err(priv,sm); } atbm_size_t merge_byte_arrays(atbm_uint8 *res, atbm_size_t res_len, const atbm_uint8 *src1, atbm_size_t src1_len, const atbm_uint8 *src2, atbm_size_t src2_len) { atbm_size_t len = 0; atbm_memset(res, 0, res_len); if (src1) { if (src1_len >= res_len) { atbm_memcpy(res, src1, res_len); return res_len; } atbm_memcpy(res, src1, src1_len); len += src1_len; } if (src2) { if (len + src2_len >= res_len) { atbm_memcpy(res + len, src2, res_len - len); return res_len; } atbm_memcpy(res + len, src2, src2_len); len += src2_len; } return len; } static atbm_void wpa_send_eapol(struct atbmwifi_cfg *config, struct atbmwifi_wpa_state_machine *sm, int key_info, const atbm_uint8 *key_rsc, const atbm_uint8 *nonce, const atbm_uint8 *kde, atbm_size_t kde_len, int keyidx, int encr) { int pairwise = key_info & ATBM_WPA_KEY_INFO_KEY_TYPE; int ctr; if (sm == ATBM_NULL) return; __wpa_send_eapol(config, sm, key_info, key_rsc, nonce, kde, kde_len, keyidx, encr, 0); ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr; if (pairwise && ctr == 1 && !(key_info & ATBM_WPA_KEY_INFO_MIC)) sm->pending_1_of_4_timeout = 1; atbmwifi_eloop_cancel_timeout(wpa_send_eapol_timeout, (atbm_void *)sm, ATBM_NULL); atbmwifi_eloop_register_timeout(WPA_SEND_EAPOL_TIMEOUT, 0, wpa_send_eapol_timeout, (atbm_void *)sm, ATBM_NULL); } static int wpa_gmk_to_gtk(const atbm_uint8 *gmk, const char *label, const atbm_uint8 *addr, const atbm_uint8 *gnonce, atbm_uint8 *gtk, atbm_size_t gtk_len) { atbm_uint8 data[ATBM_ETH_ALEN + ATBM_WPA_NONCE_LEN + 8 + 16]; atbm_uint8 *pos; int ret = 0; /* GTK = PRF-X(GMK, "Group key expansion", * AA || GNonce || Time || atbm_os_random data) * The example described in the IEEE 802.11 standard uses only AA and * GNonce as inputs here. Add some more entropy since this derivation * is done only at the Authenticator and as such, does not need to be * exactly same. */ atbm_memcpy(data, addr, ATBM_ETH_ALEN); atbm_memcpy(data + ATBM_ETH_ALEN, gnonce, ATBM_WPA_NONCE_LEN); pos = data + ATBM_ETH_ALEN + ATBM_WPA_NONCE_LEN; // wpa_get_ntp_timestamp(pos); pos += 8; if (atbmwifi_os_get_random(pos, 16) < 0) ret = -1; #if CONFIG_IEEE80211W atbmwifi_sha256_prf(gmk, ATBM_WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len); #else /* CONFIG_IEEE80211W */ if (atbm_sha1_prf(gmk, ATBM_WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len) < 0) ret = -1; #endif /* CONFIG_IEEE80211W */ return ret; } static int wpa_gtk_update(struct atbmwifi_cfg *config, struct atbmwifi_wpa_group *group) { int ret = 0; atbm_memcpy(group->GNonce, group->Counter, ATBM_WPA_NONCE_LEN); atbmwifi_inc_byte_array(group->Counter, ATBM_WPA_NONCE_LEN); if (wpa_gmk_to_gtk(group->GMK, "Group key expansion", config->bssid, group->GNonce, group->GTK[group->GN - 1], group->GTK_len) < 0) ret = -1; /* wpa_hexdump_key(MSG_DEBUG, "GTK", group->GTK[group->GN - 1], group->GTK_len); */ #if CONFIG_IEEE80211W if (config->ieee80211w != ATBM_NO_MGMT_FRAME_PROTECTION) { atbm_memcpy(group->GNonce, group->Counter, ATBM_WPA_NONCE_LEN); atbmwifi_inc_byte_array(group->Counter, ATBM_WPA_NONCE_LEN); if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion", config->bssid, group->GNonce, group->IGTK[group->GN_igtk - 4], ATBM_WPA_IGTK_LEN) < 0) ret = -1; wpa_hexdump_key(MSG_DEBUG, "IGTK", group->IGTK[group->GN_igtk - 4], ATBM_WPA_IGTK_LEN); } #endif /* CONFIG_IEEE80211W */ return ret; } static atbm_void wpa_group_gtk_init(struct atbmwifi_cfg *config, struct atbmwifi_wpa_group *group) { #if 0 wpa_printf(MSG_DEBUG, "WPA: group state machine entering state " "GTK_INIT (VLAN-ID %d)", group->vlan_id); #endif group->changed = ATBM_FALSE; /* GInit is not cleared here; avoid loop */ group->wpa_group_state = ATBM_WPA_GROUP_GTK_INIT; /* GTK[0..N] = 0 */ atbm_memset(group->GTK, 0, sizeof(group->GTK)); group->GN = 1; group->GM = 2; #if CONFIG_IEEE80211W group->GN_igtk = 4; group->GM_igtk = 5; #endif /* CONFIG_IEEE80211W */ /* GTK[GN] = CalcGTK() */ wpa_gtk_update(config, group); } static int wpa_group_init_gmk_and_counter(struct atbmwifi_cfg *config, struct atbmwifi_wpa_group *group) { #define RKEY_LEN 32 #define RBUF_LEN (ATBM_ETH_ALEN + 8 + sizeof(group)) //atbm_uint8 buf[ATBM_ETH_ALEN + 8 + sizeof(group)]; //atbm_uint8 rkey[32]; int ret =0; atbm_uint8 * buf = (atbm_uint8 *)atbm_kmalloc(RBUF_LEN/*buf*/+RKEY_LEN/*rkey*/,GFP_KERNEL); atbm_uint8 * rkey = &buf[RBUF_LEN]; if (atbmwifi_os_get_random(group->GMK, ATBM_WPA_GMK_LEN) < 0) { ret= -1; goto __ret ; } /* * Counter = PRF-256(Random number, "Init Counter", * Local MAC Address || Time) */ atbm_memcpy(buf, config->bssid, ATBM_ETH_ALEN); atbm_memcpy(buf + ATBM_ETH_ALEN + 8, &group, sizeof(group)); if (atbmwifi_os_get_random(rkey, RKEY_LEN) < 0){ ret= -1; goto __ret ; } if (atbm_sha1_prf(rkey, RKEY_LEN, "Init Counter", buf, RBUF_LEN, group->Counter, ATBM_WPA_NONCE_LEN) < 0) ret= -1; __ret: atbm_kfree(buf); return ret; } static struct atbmwifi_wpa_group * wpa_group_init(struct atbmwifi_cfg *config, struct atbmwifi_wpa_group *group, int vlan_id) { if (group == ATBM_NULL) return ATBM_NULL; group->GTKAuthenticator = ATBM_TRUE; // group->vlan_id = vlan_id; group->GTK_len = wpa_commom_key_len(config->group_cipher); /* * Set initial GMK/Counter value here. The actual values that will be * used in negotiations will be set once the first station tries to * connect. This allows more time for collecting additional randomness * on embedded devices. */ if (wpa_group_init_gmk_and_counter(config, group) < 0) { #if 0 wpa_printf(MSG_ERROR, "Failed to get atbm_os_random data for WPA " "initialization."); #endif // wifi_printk(WIFI_DBG_MSG,"group init err\n\r"); atbm_kfree(group); return ATBM_NULL; } // group->GInit = TRUE; wpa_group_gtk_init(config, group); // group->GInit = FALSE; // wpa_group_sm_step(wpa_auth, group); return group; } atbm_uint16 check_ssid(struct atbmwifi_cfg *config, const atbm_uint8 *ssid_ie, atbm_size_t ssid_ie_len) { if (ssid_ie == ATBM_NULL) return ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE; if (ssid_ie_len != config->ssid_len|| atbm_memcmp(ssid_ie, config->ssid, ssid_ie_len) != 0) { return ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE; } return ATBM_WLAN_STATUS_SUCCESS; } static atbm_uint16 copy_supp_rates(struct atbmwifi_cfg *config, struct hostapd_sta_info *sta, struct atbmwifi_ieee802_11_elems *elems) { if (!elems->supp_rates) { return ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE; } if (elems->supp_rates_len + elems->ext_supp_rates_len > sizeof(sta->supported_rates)) { return ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE; } sta->supported_rates_len = merge_byte_arrays( sta->supported_rates, sizeof(sta->supported_rates), elems->supp_rates, elems->supp_rates_len, elems->ext_supp_rates, elems->ext_supp_rates_len); return ATBM_WLAN_STATUS_SUCCESS; } struct atbmwifi_wpa_state_machine * wpa_auth_sta_init(struct atbmwifi_cfg *config,const atbm_uint8 *addr) { struct atbmwifi_wpa_state_machine *sm; sm = (struct atbmwifi_wpa_state_machine *)atbm_kzalloc(sizeof(struct atbmwifi_wpa_state_machine)+sizeof(struct atbmwifi_wpa_group),GFP_KERNEL); if (sm == ATBM_NULL) return ATBM_NULL; atbm_memcpy(sm->addr, addr, ATBM_ETH_ALEN); { struct atbmwifi_vif * priv =(struct atbmwifi_vif * )atbmwifi_config_get_priv(config); struct hostapd_data * hostapd =(struct hostapd_data *)(priv->appdata); sm->group = &hostapd->group; } //wpa_group_init(config,sm->group,0); return sm; } int wpa_validate_wpa_ie(struct atbmwifi_vif *priv, struct atbmwifi_wpa_state_machine *sm, const atbm_uint8 *wpa_ie, atbm_size_t wpa_ie_len) { struct atbmwifi_wpa_ie_data data; int ciphers, key_mgmt, res, version; struct atbmwifi_cfg *config = atbmwifi_get_config(priv); // atbm_uint32 selector; // atbm_size_t i; // const atbm_uint8 *pmkid = NULL; #if CONFIG_SAE struct hostapd_data *hapd = (struct hostapd_data *)priv->appdata; struct hostapd_sta_info *sta = ap_get_sta(hapd, sm->addr); int i; #endif if (config == ATBM_NULL || sm == ATBM_NULL) { // wifi_printk(WIFI_DBG_INIT,"parame ATBM_FALSE(1)\n"); return ATBM_WLAN_STATUS_INVALID_IE; } if (wpa_ie == ATBM_NULL || wpa_ie_len < 1) { // wifi_printk(WIFI_DBG_INIT,"parame ATBM_FALSE(2)\n"); return ATBM_WLAN_STATUS_INVALID_IE; } if (wpa_ie[0] == ATBM_WLAN_EID_RSN) version = ATBM_WPA_PROTO_RSN; else version = ATBM_WPA_PROTO_WPA; if (!(config->wpa& version)) { // wifi_printk(WIFI_DBG_INIT,"version ATBM_FALSE(%d)\n",version); return ATBM_WLAN_STATUS_INVALID_IE; } if (version == ATBM_WPA_PROTO_RSN) { res = atbmwifi_wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data); } else { if((res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data))<0) { // wifi_printk(WIFI_DBG_INIT,"data ie ATBM_FALSE\n"); return ATBM_WLAN_STATUS_INVALID_IE; } } if (res<0) { #ifdef LINUX_DEBUG wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from " MACSTR " (res=%d)", MAC2STR(sm->addr), res); wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len); #endif // wifi_printk(WIFI_DBG_INIT,"pase ie ATBM_FALSE\n"); return ATBM_WLAN_STATUS_INVALID_IE; } if (data.group_cipher != config->group_cipher) { #ifdef LINUX_DEBUG wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from " MACSTR, data.group_cipher, MAC2STR(sm->addr)); #endif // wifi_printk(WIFI_DBG_INIT,"g ATBM_FALSE\n"); return ATBM_WLAN_STATUS_INVALID_IE; } key_mgmt = data.key_mgmt & config->key_mgmt; if (!key_mgmt) { #ifdef LINUX_DEBUG wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from " MACSTR, data.key_mgmt, MAC2STR(sm->addr)); #endif wifi_printk(WIFI_DBG_INIT,"k ATBM_FALSE\n"); return ATBM_WLAN_STATUS_INVALID_IE; } if (key_mgmt & ATBM_WPA_KEY_MGMT_IEEE8021X) sm->wpa_key_mgmt =ATBM_WPA_KEY_MGMT_IEEE8021X; #ifdef CONFIG_IEEE80211W else if (key_mgmt & ATBM_WPA_KEY_MGMT_IEEE8021X_SHA256) sm->wpa_key_mgmt = ATBM_WPA_KEY_MGMT_IEEE8021X_SHA256; else if (key_mgmt & ATBM_WPA_KEY_MGMT_PSK_SHA256) sm->wpa_key_mgmt = ATBM_WPA_KEY_MGMT_PSK_SHA256; #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_SAE else if (key_mgmt & ATBM_WPA_KEY_MGMT_SAE) sm->wpa_key_mgmt = ATBM_WPA_KEY_MGMT_SAE; else if (key_mgmt & ATBM_WPA_KEY_MGMT_FT_SAE) sm->wpa_key_mgmt = ATBM_WPA_KEY_MGMT_FT_SAE; #endif /* CONFIG_SAE */ else sm->wpa_key_mgmt = ATBM_WPA_KEY_MGMT_PSK; ciphers = data.pairwise_cipher & config->pairwise_cipher; if (!ciphers) { #ifdef LINUX_DEBUG wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) " "from " MACSTR, version == ATBM_WPA_PROTO_RSN ? "RSN" : "WPA", data.pairwise_cipher, MAC2STR(sm->addr)); #endif // wifi_printk(WIFI_DBG_INIT,"p ATBM_FALSE\n"); return ATBM_WLAN_STATUS_INVALID_IE; } #if CONFIG_IEEE80211W if (data.mgmt_group_cipher != ATBM_WPA_CIPHER_AES_128_CMAC) { #ifdef LINUX_DEBUG wpa_printf(MSG_DEBUG, "Unsupported management group " "cipher %d", data.mgmt_group_cipher); #endif return ATBM_WLAN_STATUS_INVALID_IE; } #endif if (!(data.capabilities & ATBM_WPA_CAPABILITY_MFPC)) sm->mgmt_frame_prot = 0; else sm->mgmt_frame_prot = 1; if (ciphers & ATBM_WPA_CIPHER_CCMP) sm->pairwise = ATBM_WPA_CIPHER_CCMP; else if (ciphers & ATBM_WPA_CIPHER_GCMP) sm->pairwise = ATBM_WPA_CIPHER_GCMP; else sm->pairwise = ATBM_WPA_CIPHER_TKIP; /* TODO: clear WPA/WPA2 state if STA changes from one to another */ if (wpa_ie[0] == ATBM_WLAN_EID_RSN) sm->wpa = ATBM_WPA_VERSION_WPA2; else sm->wpa = ATBM_WPA_VERSION_WPA; #if CONFIG_SAE sm->pmksa = ATBM_NULL; for (i = 0; i < data.num_pmkid; i++) { wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID", &data.pmkid[i * ATBM_PMKID_LEN], ATBM_PMKID_LEN); sm->pmksa = pmksa_cache_get(hapd->pmksa, sm->addr, &data.pmkid[i * ATBM_PMKID_LEN], ATBM_NULL, ATBM_WPA_KEY_MGMT_SAE); if (sm->pmksa) { // pmkid = sm->pmksa->pmkid; break; } } if (sm->wpa_key_mgmt == ATBM_WPA_KEY_MGMT_SAE && data.num_pmkid && !sm->pmksa) { return ATBM_WLAN_STATUS_INVALID_PMKID; } if (sta && sta->auth_alg == ATBM_WLAN_AUTH_SAE) { atbm_memcpy(sm->PMK, sta->sae.pmk, ATBM_PMK_LEN); } #endif /* CONFIG_SAE */ if (sm->wpa_ie == ATBM_NULL || sm->wpa_ie_len < wpa_ie_len) { atbm_kfree(sm->wpa_ie); sm->wpa_ie = (atbm_uint8 *)atbm_kmalloc(wpa_ie_len,GFP_KERNEL); if (sm->wpa_ie == ATBM_NULL) { // wifi_printk(WIFI_DBG_INIT,"sm ie ATBM_FALSE\n"); return ATBM_WLAN_STATUS_INVALID_IE; } } atbm_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len); sm->wpa_ie_len = wpa_ie_len; return ATBM_WLAN_STATUS_SUCCESS; } atbm_void wpa_auth_sta_no_wpa(struct atbmwifi_wpa_state_machine *sm) { /* WPA/RSN was not used - clear WPA state. This is needed if the STA * reassociates back to the same AP while the previous entry for the * STA has not yet been removed. */ if (sm == ATBM_NULL) return; sm->wpa_key_mgmt = 0; } #if CONFIG_SAE int wpa_auth_uses_sae(struct atbmwifi_wpa_state_machine *sm) { if (sm == NULL) return 0; return atbmwifi_wpa_key_mgmt_sae(sm->wpa_key_mgmt); } int wpa_auth_uses_ft_sae(struct atbmwifi_wpa_state_machine *sm) { if (sm == NULL) return 0; return sm->wpa_key_mgmt == ATBM_WPA_KEY_MGMT_FT_SAE; } int wpa_auth_pmksa_add_sae(struct hostapd_data *hapd, const atbm_uint8 *addr, const atbm_uint8 *pmk, const atbm_uint8 *pmkid) { wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE", pmk, ATBM_PMK_LEN); if (pmksa_cache_add(hapd->pmksa, pmk, ATBM_PMK_LEN, pmkid, NULL, 0, addr, hapd->own_addr, ATBM_NULL, ATBM_WPA_KEY_MGMT_SAE, ATBM_NULL)); return 0; return -1; } void wpa_auth_add_sae_pmkid(struct atbmwifi_wpa_state_machine *sm, const atbm_uint8 *pmkid) { atbm_memcpy(sm->pmkid, pmkid, ATBM_PMKID_LEN); sm->pmkid_set = 1; } struct rsn_pmksa_cache_entry * wpa_auth_sta_get_pmksa(struct atbmwifi_wpa_state_machine *sm) { return sm ? sm->pmksa : NULL; } #endif static atbm_uint16 check_assoc_ies(struct atbmwifi_vif *priv, struct hostapd_sta_info *sta, struct atbmwifi_ieee802_11_elems *elems, int reassoc) { atbm_uint16 resp; const atbm_uint8 *wpa_ie; atbm_size_t wpa_ie_len; struct atbmwifi_cfg *config = atbmwifi_get_config(priv); resp = copy_supp_rates(config, sta, elems); if (resp != ATBM_WLAN_STATUS_SUCCESS){ return resp; } if ((config->wpa & ATBM_WPA_PROTO_RSN) && elems->rsn) { wpa_ie = elems->rsn; wpa_ie_len = elems->rsn_len; } else if ((config->wpa & ATBM_WPA_PROTO_WPA) && elems->wpa) { wpa_ie = elems->wpa; wpa_ie_len = elems->wpa_len; } else { wpa_ie = ATBM_NULL; wpa_ie_len = 0; } #if CONFIG_WPS if((priv->pbc || priv->pin) && (elems->wps_ie)){ wpa_ie = ATBM_NULL; wpa_ie_len = 0; }else #endif if (config->wpa && wpa_ie == ATBM_NULL) { return ATBM_WLAN_STATUS_INVALID_IE; } if (config->wpa && wpa_ie) { int res; wpa_ie -= 2; wpa_ie_len += 2; if (sta->atbmwifi_wpa_sm == ATBM_NULL) sta->atbmwifi_wpa_sm = wpa_auth_sta_init(config, sta->addr); if (sta->atbmwifi_wpa_sm == ATBM_NULL) { return ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE; } resp = wpa_validate_wpa_ie(priv, sta->atbmwifi_wpa_sm, wpa_ie, wpa_ie_len); if (resp != ATBM_WLAN_STATUS_SUCCESS) return resp; #if CONFIG_IEEE80211N if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) && sta->atbmwifi_wpa_sm->pairwise == ATBM_WPA_CIPHER_TKIP) { return ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE; } #endif /* CONFIG_IEEE80211N */ #if CONFIG_SAE if (wpa_auth_uses_sae(sta->atbmwifi_wpa_sm) && sta->sae.state == SAE_ACCEPTED) wpa_auth_add_sae_pmkid(sta->atbmwifi_wpa_sm, sta->sae.pmkid); if (wpa_auth_uses_sae(sta->atbmwifi_wpa_sm) && sta->auth_alg == ATBM_WLAN_AUTH_OPEN) { struct rsn_pmksa_cache_entry *sa; sa = wpa_auth_sta_get_pmksa(sta->atbmwifi_wpa_sm); if (!sa || sa->akmp != ATBM_WPA_KEY_MGMT_SAE) { wpa_printf(MSG_DEBUG, "SAE: No PMKSA cache entry found for " MACSTR, MAC2STR(sta->addr)); return ATBM_WLAN_STATUS_INVALID_PMKID; } wpa_printf(MSG_DEBUG, "SAE: " MACSTR " using PMKSA caching", MAC2STR(sta->addr)); } else if (wpa_auth_uses_sae(sta->atbmwifi_wpa_sm) && sta->auth_alg != ATBM_WLAN_AUTH_SAE && !(sta->auth_alg == ATBM_WLAN_AUTH_FT && wpa_auth_uses_ft_sae(sta->atbmwifi_wpa_sm))) { wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use " "SAE AKM after non-SAE auth_alg %u", MAC2STR(sta->addr), sta->auth_alg); return ATBM_WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; } #endif /* CONFIG_SAE */ } else{ wpa_auth_sta_no_wpa(sta->atbmwifi_wpa_sm); } return ATBM_WLAN_STATUS_SUCCESS; } atbm_uint8 * wpa_add_kde(atbm_uint8 *pos, atbm_uint32 kde, const atbm_uint8 *data, atbm_size_t data_len, const atbm_uint8 *data2, atbm_size_t data2_len) { *pos++ = ATBM_WLAN_EID_VENDOR_SPECIFIC; *pos++ = ATBM_RSN_SELECTOR_LEN + data_len + data2_len; ATBM_RSN_SELECTOR_PUT(pos, kde); pos += ATBM_RSN_SELECTOR_LEN; atbm_memcpy(pos, data, data_len); pos += data_len; if (data2) { atbm_memcpy(pos, data2, data2_len); pos += data2_len; } return pos; } #if CONFIG_IEEE80211W static int atbmwifi_ieee80211w_kde_len(struct atbmwifi_wpa_state_machine *sm) { if (sm->mgmt_frame_prot) { atbm_size_t len; len = wpa_commom_key_len(ATBM_WPA_CIPHER_AES_128_CMAC); return 2 + ATBM_RSN_SELECTOR_LEN + ATBM_WPA_IGTK_KDE_PREFIX_LEN + len; } return 0; } static atbm_uint8 *atbmwifi_ieee80211w_kde_add(struct atbmwifi_wpa_state_machine *sm, atbm_uint8 *pos) { struct wpa_igtk_kde igtk; struct atbmwifi_wpa_group *gsm = sm->group; atbm_uint8 rsc[ATBM_WPA_KEY_RSC_LEN]; atbm_size_t len = wpa_commom_key_len(ATBM_WPA_CIPHER_AES_128_CMAC); if (!sm->mgmt_frame_prot) return pos; igtk.keyid[0] = gsm->GN_igtk; igtk.keyid[1] = 0; if (gsm->wpa_group_state != ATBM_WPA_GROUP_SETKEYSDONE) atbm_memset(igtk.pn, 0, sizeof(igtk.pn)); //else // atbm_memcpy(igtk.pn, rsc, sizeof(igtk.pn)); atbm_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len); #if 0 if (sm->wpa_auth->conf.disable_gtk || sm->wpa_key_mgmt == ATBM_WPA_KEY_MGMT_OSEN) { /* * Provide unique random IGTK to each STA to prevent use of * IGTK in the BSS. */ if (random_get_bytes(igtk.igtk, len) < 0) return pos; } #endif pos = wpa_add_kde(pos, ATBM_RSN_KEY_DATA_IGTK, (const atbm_uint8 *) &igtk, ATBM_WPA_IGTK_KDE_PREFIX_LEN + len, NULL, 0); return pos; } #else static int atbmwifi_ieee80211w_kde_len(struct atbmwifi_wpa_state_machine *sm) { return 0; } static atbm_uint8 * atbmwifi_ieee80211w_kde_add(struct atbmwifi_wpa_state_machine *sm, atbm_uint8 *pos) { return pos; } #endif static int wpa_verify_key_mic(struct atbmwifi_wpa_ptk *PTK, atbm_uint8 *data, atbm_size_t data_len) { struct atbmwifi_ieee802_1x_hdr *hdr; struct atbmwifi_wpa_eapol_key *key; atbm_uint16 key_info; int ret = 0; atbm_uint8 mic[16]; if (data_len < sizeof(*hdr) + sizeof(*key)) { // wifi_printk(WIFI_DBG_MSG,"ptk len err \n\r"); return -1; } hdr = (struct atbmwifi_ieee802_1x_hdr *) data; key = (struct atbmwifi_wpa_eapol_key *) (hdr + 1); key_info = ATBM_WPA_GET_BE16(key->key_info); atbm_memset(mic,0,16); atbm_memcpy(mic, key->key_mic, 16); atbm_memset(key->key_mic, 0, 16); #if 0 wifi_printk(WIFI_DBG_MSG, "wpa kck mic:mic[1](%x),mic[5](%x),mic[10](%x),mic[15](%x)\n" ,mic[1],mic[5],mic[10],mic[15]); #endif if (wpa_eapol_key_mic(PTK->kck, key_info & ATBM_WPA_KEY_INFO_TYPE_MASK, data, data_len, key->key_mic) || atbm_memcmp(mic, key->key_mic, 16) != 0) ret = -1; #if 0 wifi_printk(WIFI_DBG_MSG, "wpa kck mic:mic[1](%x),mic[5](%x),mic[10](%x),mic[15](%x)\n" ,key->key_mic[1],key->key_mic[5],key->key_mic[10],key->key_mic[15]); #endif atbm_memcpy(key->key_mic, mic, 16); return ret; } /** * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs * @buf: Pointer to the Key Data buffer * @len: Key Data Length * @ie: Pointer to parsed IE data * Returns: 0 on success, -1 on failure */ int wpa_parse_kde_ies(const atbm_uint8 *buf, atbm_size_t len, struct wpa_eapol_ie_parse *ie) { const atbm_uint8 *pos, *end; int ret = 0; atbm_memset(ie, 0, sizeof(*ie)); for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { if (pos[0] == 0xdd && ((pos == buf + len - 1) || pos[1] == 0)) { /* Ignore padding */ break; } if (pos + 2 + pos[1] > end) { #if 0 wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " "underflow (ie=%d len=%d pos=%d)", pos[0], pos[1], (int) (pos - buf)); wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", buf, len); #endif ret = -1; break; } if (*pos == ATBM_WLAN_EID_RSN) { ie->rsn_ie = pos; ie->rsn_ie_len = pos[1] + 2; #if CONFIG_IEEE80211R } else if (*pos == ATBM_WLAN_EID_MOBILITY_DOMAIN) { ie->mdie = pos; ie->mdie_len = pos[1] + 2; } else if (*pos == ATBM_WLAN_EID_FAST_BSS_TRANSITION) { ie->ftie = pos; ie->ftie_len = pos[1] + 2; #endif /* CONFIG_IEEE80211R */ } else if (*pos == ATBM_WLAN_EID_VENDOR_SPECIFIC) { ret = wpa_parse_generic(pos, end, ie); if (ret < 0) break; if (ret > 0) { ret = 0; break; } } else { #if 0 wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " "Key Data IE", pos, 2 + pos[1]); #endif } } return ret; } static int wpa_replay_counter_valid(struct atbmwifi_wpa_key_replay_counter *ctr, const atbm_uint8 *replay_counter) { int i; for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { if (!ctr[i].valid) break; if (atbm_memcmp(replay_counter, ctr[i].counter, ATBM_WPA_REPLAY_COUNTER_LEN) == 0) return 1; } return 0; } static atbm_void wpa_replay_counter_mark_invalid(struct atbmwifi_wpa_key_replay_counter *ctr, const atbm_uint8 *replay_counter) { int i; for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { if (ctr[i].valid && (replay_counter == ATBM_NULL || atbm_memcmp(replay_counter, ctr[i].counter, ATBM_WPA_REPLAY_COUNTER_LEN) == 0)) ctr[i].valid = ATBM_FALSE; } } static int wpa_use_aes_cmac(struct atbmwifi_wpa_state_machine *sm) { int ret = 0; #if CONFIG_IEEE80211R if (atbmwifi_wpa_key_mgmt_ft(sm->wpa_key_mgmt)) ret = 1; #endif /* CONFIG_IEEE80211R */ #if CONFIG_IEEE80211W if (atbmwifi_wpa_key_mgmt_sha256(sm->wpa_key_mgmt)) ret = 1; #endif /* CONFIG_IEEE80211W */ return ret; } static int wpa_derive_ptk(struct atbmwifi_cfg *config,struct atbmwifi_wpa_state_machine *sm, const atbm_uint8 *pmk, struct atbmwifi_wpa_ptk *ptk) { atbm_size_t ptk_len = sm->pairwise != ATBM_WPA_CIPHER_TKIP ? 48 : 64; #if CONFIG_IEEE80211R if (atbmwifi_wpa_key_mgmt_ft(sm->wpa_key_mgmt)) return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len); #endif /* CONFIG_IEEE80211R */ /* wpa_pmk_to_ptk(pmk, ATBM_PMK_LEN, "Pairwise key expansion", config->bssid, sm->addr, sm->ANonce, sm->SNonce, (atbm_uint8 *) ptk, ptk_len, atbmwifi_wpa_key_mgmt_sha256(sm->wpa_key_mgmt)); */ wpa_pmk_to_ptk(pmk, ATBM_PMK_LEN, "Pairwise key expansion", config->bssid, sm->addr, sm->ANonce, sm->SNonce, (atbm_uint8 *) ptk, ptk_len, atbmwifi_wpa_key_mgmt_sha256(sm->wpa_key_mgmt)); return 0; } static int hostapd_prepare_pmk(struct atbmwifi_cfg *config,struct atbmwifi_wpa_state_machine *sm) { struct atbmwifi_wpa_ptk PTK; int ok = 0; const atbm_uint8 *pmk = ATBM_NULL; sm->EAPOLKeyReceived = ATBM_FALSE; sm->update_snonce = ATBM_FALSE; #if CONFIG_SAE if (sm->pmksa) { wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache"); atbm_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len); //sm->pmk_len = sm->pmksa->pmk_len; } #endif /* CONFIG_SAE */ /* WPA with IEEE 802.1X: use the derived PMK from EAP * WPA-PSK: iterate through possible PSKs and select the one matching * the packet */ for (;;) { if (atbmwifi_wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && !atbmwifi_wpa_key_mgmt_sae(sm->wpa_key_mgmt)) { if(config->psk_set == 1) pmk = config->psk; if (pmk == ATBM_NULL) break; } else{//if atbmwifi_ieee80211X or WPS or 802.11r pmk = sm->PMK; } #if 0 wifi_printk(WIFI_DBG_MSG, "pmk[0](%d),pmk[10](%d),pmk[16](%d),pmk[20](%d)\n" "pmk[25](%d),pmk[28](%d),pmk[30](%d),pmk[31](%d)\n", pmk[0],pmk[10],pmk[16],pmk[20], pmk[25],pmk[28],pmk[30],pmk[31]); #endif wpa_derive_ptk(config,sm, pmk, &PTK); // wifi_printk(WIFI_DBG_MSG,"ptk over \n\r"); if (wpa_verify_key_mic(&PTK, sm->last_rx_eapol_key, sm->last_rx_eapol_key_len) == 0) { ok = 1; break; } #if 0 wifi_printk(WIFI_DBG_MSG, "wpa kck:kck[1](%x),kck[5](%x),kck[10](%x),kck[15](%x)\n" ,PTK.kck[1],PTK.kck[5],PTK.kck[10],PTK.kck[15]); #endif if (!atbmwifi_wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) break; return -1; } if (!ok) { wifi_printk(WIFI_DBG_MSG,"mic err \n\r"); return -1; } #if CONFIG_IEEE80211R if (sm->wpa == ATBM_WPA_VERSION_WPA2 && atbmwifi_wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { /* * Verify that PMKR1Name from EAPOL-Key message 2/4 matches * with the value we derived. */ if (atbm_memcmp(sm->sup_pmk_r1_name, sm->pmk_r1_name, ATBM_WPA_PMK_NAME_LEN) != 0) { wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, "PMKR1Name mismatch in FT 4-way " "handshake"); wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from " "Supplicant", sm->sup_pmk_r1_name, ATBM_WPA_PMK_NAME_LEN); wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name", sm->pmk_r1_name, ATBM_WPA_PMK_NAME_LEN); return; } } #endif /* CONFIG_IEEE80211R */ sm->pending_1_of_4_timeout = 0; if (atbmwifi_wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { /* PSK may have changed from the previous choice, so update * state machine data based on whatever PSK was selected here. */ atbm_memcpy(sm->PMK, pmk, ATBM_PMK_LEN); } sm->MICVerified = ATBM_TRUE; //wifi_printk(WIFI_DBG_MSG,"MIC TRUE\n\r"); atbm_memcpy(&sm->PTK, &PTK, sizeof(PTK)); sm->PTK_valid = ATBM_TRUE; atbmwifi_eloop_cancel_timeout(wpa_send_eapol_timeout,(atbm_void *)sm,ATBM_NULL); // sm->TimeoutCtr = 0; return 0; } static int hostapd_send_4_of_3_msg(struct atbmwifi_vif *priv,struct atbmwifi_wpa_state_machine *sm) { atbm_uint8 rsc[ATBM_WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32]; atbm_size_t gtk_len, kde_len; struct atbmwifi_wpa_group *gsm = sm->group; atbm_uint8 *wpa_ie; int wpa_ie_len, secure, keyidx, encr = 0; struct atbmwifi_cfg *config = atbmwifi_get_config(priv); sm->TimeoutCtr++; sm->TimeoutEvt = ATBM_FALSE; if(hostapd_prepare_pmk(config,sm)<0) { wifi_printk(WIFI_DBG_MSG,"hostapd_pmk err\n\r"); return -1; } if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) { /* No point in sending the EAPOL-Key - we will disconnect * immediately following this. */ wifi_printk(WIFI_DBG_ERROR,"hostap tx 3/4 Timeout err\n\r"); return -1; } /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE], GTK[GN], IGTK, [FTIE], [TIE * 2]) */ atbm_memset(rsc, 0, ATBM_WPA_KEY_RSC_LEN); /* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */ /* wpa_ie = sm->wpa_auth->wpa_ie; wpa_ie_len = sm->wpa_auth->wpa_ie_len; */ wpa_ie = priv->bss.information_elements; wpa_ie_len = priv->bss.len_information_elements; if (sm->wpa == ATBM_WPA_VERSION_WPA && (config->wpa & ATBM_WPA_PROTO_RSN) && wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == ATBM_WLAN_EID_RSN) { /* WPA-only STA, remove RSN IE */ wpa_ie = wpa_ie + wpa_ie[1] + 2; wpa_ie_len = wpa_ie[1] + 2; } if (sm->wpa == ATBM_WPA_VERSION_WPA2) { /* WPA2 send GTK in the 4-way handshake */ secure = 1; gtk = gsm->GTK[gsm->GN - 1]; gtk_len = gsm->GTK_len; if (0) { /* * Provide unique atbm_os_random GTK to each STA to prevent use * of GTK in the BSS. */ if (atbmwifi_os_get_random(dummy_gtk, gtk_len) < 0) return -1; gtk = dummy_gtk; } keyidx = gsm->GN; _rsc = rsc; encr = 1; } else { /* WPA does not include GTK in msg 3/4 */ secure = 0; gtk = ATBM_NULL; gtk_len = 0; keyidx = 0; _rsc = ATBM_NULL; } kde_len = wpa_ie_len + atbmwifi_ieee80211w_kde_len(sm); if (gtk) kde_len += 2 + ATBM_RSN_SELECTOR_LEN + 2 + gtk_len; kde = (atbm_uint8 *)atbm_kmalloc(kde_len,GFP_KERNEL); if (kde == ATBM_NULL) { wifi_printk(WIFI_DBG_MSG,"kde err\n\r"); return -1; } pos = kde; atbm_memcpy(pos, wpa_ie, wpa_ie_len); pos += wpa_ie_len; if (gtk) { atbm_uint8 hdr[2]; hdr[0] = keyidx & 0x03; hdr[1] = 0; pos = wpa_add_kde(pos, ATBM_RSN_KEY_DATA_GROUPKEY, hdr, 2, gtk, gtk_len); } pos = atbmwifi_ieee80211w_kde_add(sm, pos); wifi_printk(WIFI_DBG_MSG,"ie len(%d),kde len(%d)\n",wpa_ie_len,pos - kde); wpa_send_eapol(config, sm, (secure ? ATBM_WPA_KEY_INFO_SECURE : 0) | ATBM_WPA_KEY_INFO_MIC | ATBM_WPA_KEY_INFO_ACK | ATBM_WPA_KEY_INFO_INSTALL | ATBM_WPA_KEY_INFO_KEY_TYPE, _rsc, sm->ANonce, kde, pos - kde, keyidx, encr); atbm_kfree(kde); wifi_printk(WIFI_DBG_MSG,"hostapd 3/4\n\r"); return 0; } atbm_void wpa_receive(struct atbmwifi_vif *priv, struct atbmwifi_wpa_state_machine *sm, atbm_uint8 *data, atbm_size_t data_len) { struct atbmwifi_ieee802_1x_hdr *hdr; struct atbmwifi_wpa_eapol_key *key; atbm_uint16 key_info, key_data_length; enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST} msg; // char *msgtxt; struct wpa_eapol_ie_parse kde; int ft; const atbm_uint8 *eapol_key_ie; atbm_size_t eapol_key_ie_len; // wifi_printk(WIFI_DBG_MSG, "wpa_receive:++\n"); if (priv == ATBM_NULL || sm == ATBM_NULL) return; if (data_len < sizeof(*hdr) + sizeof(*key)) return; hdr = (struct atbmwifi_ieee802_1x_hdr *) data; key = (struct atbmwifi_wpa_eapol_key *) (hdr + 1); key_info = ATBM_WPA_GET_BE16(key->key_info); key_data_length = ATBM_WPA_GET_BE16(key->key_data_length); if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) { return; } if (sm->wpa == ATBM_WPA_VERSION_WPA2) { if (key->type == ATBM_EAPOL_KEY_TYPE_WPA) { /* * Some deployed station implementations seem to send * msg 4/4 with incorrect type value in WPA2 mode. */ wifi_printk(WIFI_DBG_MSG, "wpa_rx:wpa2\n"); } else if (key->type != ATBM_EAPOL_KEY_TYPE_RSN) { wifi_printk(WIFI_DBG_MSG, "wpa_rx:rsn\n"); return; } } else { if (key->type != ATBM_EAPOL_KEY_TYPE_WPA) { wifi_printk(WIFI_DBG_MSG, "wpa_rx:wpa\n"); return; } } /* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys * are set */ if (key_info & ATBM_WPA_KEY_INFO_REQUEST) { msg = REQUEST; // msgtxt = "Request"; } else if (!(key_info & ATBM_WPA_KEY_INFO_KEY_TYPE)) { msg = GROUP_2; // msgtxt = "2/2 Group"; } else if (key_data_length == 0) { msg = PAIRWISE_4; // msgtxt = "4/4 Pairwise"; } else { msg = PAIRWISE_2; // msgtxt = "2/4 Pairwise"; } /* TODO: key_info type validation for PeerKey */ if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 || msg == GROUP_2) { atbm_uint16 ver = key_info & ATBM_WPA_KEY_INFO_TYPE_MASK; if (sm->pairwise == ATBM_WPA_CIPHER_CCMP || sm->pairwise == ATBM_WPA_CIPHER_GCMP) { if (wpa_use_aes_cmac(sm) && #if CONFIG_SAE !atbmwifi_wpa_key_mgmt_sae(sm->wpa_key_mgmt) && #endif ver != ATBM_WPA_KEY_INFO_TYPE_AES_128_CMAC) { wifi_printk(WIFI_DBG_MSG,"wpa_rx :AES-128-CMAC,ERR\n\r"); return; } if (!wpa_use_aes_cmac(sm) && #if CONFIG_SAE !atbmwifi_wpa_key_mgmt_sae(sm->wpa_key_mgmt) && #endif ver != ATBM_WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { wifi_printk(WIFI_DBG_MSG,"wpa_rx: HMAC-SHA1-AES ERR\n\r"); return; } } } if (key_info & ATBM_WPA_KEY_INFO_REQUEST) { if (sm->req_replay_counter_used && atbm_memcmp(key->replay_counter, sm->req_replay_counter, ATBM_WPA_REPLAY_COUNTER_LEN) <= 0) { wifi_printk(WIFI_DBG_MSG,"wpa_rx PN err\n\r"); return; } } if (!(key_info & ATBM_WPA_KEY_INFO_REQUEST) && !wpa_replay_counter_valid(sm->key_replay, key->replay_counter)) { int i; if (msg == PAIRWISE_2 && wpa_replay_counter_valid(sm->prev_key_replay, key->replay_counter) && sm->wpa_ptk_state == ATBM_WPA_PTK_PTKINITNEGOTIATING && atbm_memcmp(sm->SNonce, key->key_nonce, ATBM_WPA_NONCE_LEN) != 0) { /* * Some supplicant implementations (e.g., Windows XP * WZC) update SNonce for each EAPOL-Key 2/4. This * breaks the workaround on accepting any of the * pending requests, so allow the SNonce to be updated * even if we have already sent out EAPOL-Key 3/4. */ wifi_printk(WIFI_DBG_MSG,"wpa_receive:""STA" "EAPOL-Key1/4\n\r"); sm->update_snonce = 1; wpa_replay_counter_mark_invalid(sm->prev_key_replay, key->replay_counter); goto continue_processing; } if (msg == PAIRWISE_2 && wpa_replay_counter_valid(sm->prev_key_replay, key->replay_counter) && sm->wpa_ptk_state == ATBM_WPA_PTK_PTKINITNEGOTIATING) { wifi_printk(WIFI_DBG_MSG,"wpa_receive:" "SNonce did not change\n\r"); } else { #ifdef LINUX_DEBUG wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, "received EAPOL-Key %s with " "unexpected replay counter", msgtxt); #endif } for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { if (!sm->key_replay[i].valid) break; #ifdef LINUX_DEBUG wpa_hexdump(MSG_DEBUG, "pending replay counter", sm->key_replay[i].counter, ATBM_WPA_REPLAY_COUNTER_LEN); #endif } #ifdef LINUX_DEBUG wpa_hexdump(MSG_DEBUG, "received replay counter", key->replay_counter, ATBM_WPA_REPLAY_COUNTER_LEN); #endif return; } continue_processing: switch (msg) { case PAIRWISE_2: if (sm->wpa_ptk_state != ATBM_WPA_PTK_PTKSTART && sm->wpa_ptk_state != ATBM_WPA_PTK_PTKCALCNEGOTIATING && (!sm->update_snonce || sm->wpa_ptk_state != ATBM_WPA_PTK_PTKINITNEGOTIATING)) { #if 0 wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key msg 2/4 in " "invalid state (%d) - dropped", sm->wpa_ptk_state); #endif return; } // random_add_randomness(key->key_nonce, ATBM_WPA_NONCE_LEN); if (wpa_parse_kde_ies((atbm_uint8 *) (key + 1), key_data_length, &kde) < 0) { #if 0 wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key msg 2/4 with " "invalid Key Data contents"); #endif wifi_printk(WIFI_DBG_ERROR, "kde err\n"); return; } if (kde.rsn_ie) { eapol_key_ie = kde.rsn_ie; eapol_key_ie_len = kde.rsn_ie_len; } else { eapol_key_ie = kde.wpa_ie; eapol_key_ie_len = kde.wpa_ie_len; } ft = sm->wpa == ATBM_WPA_VERSION_WPA2 && atbmwifi_wpa_key_mgmt_ft(sm->wpa_key_mgmt); if (sm->wpa_ie == ATBM_NULL || wpa_compare_rsn_ie(ft, sm->wpa_ie, sm->wpa_ie_len, eapol_key_ie, eapol_key_ie_len)) { wifi_printk(WIFI_DBG_ERROR,"wpa_rx:""WPA IE not match M2/4\n"); /* MLME-DEAUTHENTICATE.request */ // wpa_sta_disconnect(wpa_auth, sm->addr); return; } break; case PAIRWISE_4: if (sm->wpa_ptk_state != ATBM_WPA_PTK_PTKINITNEGOTIATING || !sm->PTK_valid) { wifi_printk(WIFI_DBG_MSG,"wpa_rx:invalid state (%d) - dropped\n\r", sm->wpa_ptk_state); return; } break; case GROUP_2: if (sm->wpa_ptk_group_state != ATBM_WPA_PTK_GROUP_REKEYNEGOTIATING || !sm->PTK_valid) { wifi_printk(WIFI_DBG_ERROR, "wpa_rx:groop 2 err\n\r"); return; } break; case REQUEST: break; } // wifi_printk(WIFI_DBG_MSG,"received EAPOL-Key frame(%s)\n\r",msgtxt); if (key_info & ATBM_WPA_KEY_INFO_ACK) { wifi_printk(WIFI_DBG_ERROR,"wpa_receive:Key Ack set\n\r"); return; } if (!(key_info & ATBM_WPA_KEY_INFO_MIC)) { wifi_printk(WIFI_DBG_ERROR,"wpa:Key MIC not set\n\r"); return; } sm->MICVerified = ATBM_FALSE; if (sm->PTK_valid && !sm->update_snonce) { if (wpa_verify_key_mic(&sm->PTK, data, data_len)) { wifi_printk(WIFI_DBG_ERROR,"wpa_receive:MIC err(1)\n\r"); return; } sm->MICVerified = ATBM_TRUE; atbmwifi_eloop_cancel_timeout(wpa_send_eapol_timeout, (atbm_void *)sm,ATBM_NULL); sm->pending_1_of_4_timeout = 0; wifi_printk(WIFI_DBG_ERROR,"wpa_receive: MIC OK\n\r"); } if (key_info & ATBM_WPA_KEY_INFO_REQUEST) { if (sm->MICVerified) { sm->req_replay_counter_used = 1; atbm_memcpy(sm->req_replay_counter, key->replay_counter, ATBM_WPA_REPLAY_COUNTER_LEN); } else { wifi_printk(WIFI_DBG_ERROR,"wpa rx:MIC err(2)\n\r"); return; } #if 0 /* * TODO: should decrypt key data field if encryption was used; * even though MAC address KDE is not normally encrypted, * supplicant is allowed to encrypt it. */ if (msg == SMK_ERROR) { #if CONFIG_PEERKEY wpa_smk_error(wpa_auth, sm, key); #endif /* CONFIG_PEERKEY */ return; } else if (key_info & WPA_KEY_INFO_ERROR) { wpa_receive_error_report( wpa_auth, sm, !(key_info & ATBM_WPA_KEY_INFO_KEY_TYPE)); } else if (key_info & ATBM_WPA_KEY_INFO_KEY_TYPE) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key Request for new " "4-Way Handshake"); wpa_request_new_ptk(sm); #if CONFIG_PEERKEY } else if (msg == SMK_M1) { wpa_smk_m1(wpa_auth, sm, key); #endif /* CONFIG_PEERKEY */ } else if (key_data_length > 0 && wpa_parse_kde_ies((const atbm_uint8 *) (key + 1), key_data_length, &kde) == 0 && kde.mac_addr) { } else { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "received EAPOL-Key Request for GTK " "rekeying"); atbmwifi_eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, ATBM_NULL); wpa_rekey_gtk(wpa_auth, ATBM_NULL); } #endif } else { /* Do not allow the same key replay counter to be reused. */ wpa_replay_counter_mark_invalid(sm->key_replay, key->replay_counter); if (msg == PAIRWISE_2) { /* * Maintain a copy of the pending EAPOL-Key frames in * case the EAPOL-Key frame was retransmitted. This is * needed to allow EAPOL-Key msg 2/4 reply to another * pending msg 1/4 to update the SNonce to work around * unexpected supplicant behavior. */ atbm_memcpy(sm->prev_key_replay, sm->key_replay, sizeof(sm->key_replay)); } else { atbm_memset(sm->prev_key_replay, 0, sizeof(sm->prev_key_replay)); } /* * Make sure old valid counters are not accepted anymore and * do not get copied again. */ wpa_replay_counter_mark_invalid(sm->key_replay, ATBM_NULL); } atbm_kfree(sm->last_rx_eapol_key); sm->last_rx_eapol_key = (atbm_uint8 *)atbm_kmalloc(data_len,GFP_KERNEL); if (sm->last_rx_eapol_key == ATBM_NULL) return; atbm_memcpy(sm->last_rx_eapol_key, data, data_len); sm->last_rx_eapol_key_len = data_len; sm->rx_eapol_key_secure = !!(key_info & ATBM_WPA_KEY_INFO_SECURE); sm->EAPOLKeyReceived = ATBM_TRUE; sm->EAPOLKeyPairwise = !!(key_info & ATBM_WPA_KEY_INFO_KEY_TYPE); sm->EAPOLKeyRequest = !!(key_info & ATBM_WPA_KEY_INFO_REQUEST); atbm_memcpy(sm->SNonce, key->key_nonce, ATBM_WPA_NONCE_LEN); if(msg == PAIRWISE_2) { if(sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && sm->EAPOLKeyPairwise) { wifi_printk(WIFI_WPA,"2/4 ok\n\r"); sm->wpa_ptk_state = ATBM_WPA_PTK_PTKINITNEGOTIATING; } else { sm->wpa_ptk_state = ATBM_WPA_PTK_PTKSTART; wifi_printk(WIFI_WPA,"2/4 err\n\r"); } } else if(msg == PAIRWISE_4) { if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && sm->EAPOLKeyPairwise && sm->MICVerified) { wifi_printk(WIFI_WPA,"4/4 ok\n\r"); sm->wpa_ptk_state = ATBM_WPA_PTK_PTKINITDONE; } else { wifi_printk(WIFI_WPA,"4/4 err\n\r"); sm->wpa_ptk_state = ATBM_WPA_PTK_PTKINITNEGOTIATING; } } else if(msg == GROUP_2) { if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && !sm->EAPOLKeyPairwise && sm->MICVerified) { wifi_printk(WIFI_WPA,"2/2 ok\n\r"); sm->wpa_ptk_group_state = ATBM_WPA_PTK_GROUP_KEYINSTALLED; atbmwifi_eloop_cancel_timeout(wpa_send_eapol_timeout, (atbm_void *)sm, ATBM_NULL); } } else { } eloop_register_task((atbm_void *)priv,ap_get_sta((struct hostapd_data *)priv->appdata,sm->addr)); } struct hostapd_sta_info * ap_get_sta(struct hostapd_data * hapd, const atbm_uint8 *sta) { struct hostapd_sta_info *tmp; int i = 0; for(i=0;ista_list[i]; if(tmp==ATBM_NULL) { continue; } if((tmp != ATBM_NULL)&&(atbm_memcmp(tmp->addr, sta, 6) == 0)) { return tmp; } } return ATBM_NULL; } /* return empty stainfo id if no empty return ATBMWIFI__MAX_STA_IN_AP_MODE */ int ap_get_emtpy_stainfo(struct hostapd_data * hapd) { struct hostapd_sta_info *tmp; int i = 0; for(i=0;ista_list[i]; if(tmp==ATBM_NULL) { return i; } } return ATBMWIFI__MAX_STA_IN_AP_MODE; } struct hostapd_sta_info * ap_sta_add(struct hostapd_data *hapd, const atbm_uint8 *addr,atbm_uint8 linkid) { struct hostapd_sta_info *sta; int id=0; int IrqState; for(id=0;idsta_list[id]; if(sta==ATBM_NULL) { continue; } if(atbm_memcmp(addr, sta, 6) == 0) { if((linkid-1) != id){ //return tmp; //because the new sta have been alloc in new linkid free the old ap_sta_del(hapd,sta); } } else if((linkid-1) == id){ //if the same linkid but macaddr not the same,just free //because the new sta have been alloc in new linkid free the old ap_sta_del(hapd,sta); } } sta = ap_get_sta(hapd, addr); if(sta) return sta; IrqState =atbm_local_irq_save(); if (hapd->num_sta >= ATBMWIFI__MAX_STA_IN_AP_MODE) { /* FIX: might try to remove some old STAs first? */ atbm_local_irq_restore(IrqState); return ATBM_NULL; } sta = (struct hostapd_sta_info *)atbm_kzalloc(sizeof(struct hostapd_sta_info),GFP_KERNEL); if (sta == ATBM_NULL) { atbm_local_irq_restore(IrqState); return ATBM_NULL; } /* initialize STA info data */ atbm_memcpy(sta->addr, addr, ATBM_ETH_ALEN); hapd->sta_list[(linkid-1)] = sta; hapd->num_sta++; sta->deauth_reason = 1; sta->disassoc_reason = 1; sta->atbmwifi_wpa_sm = ATBM_NULL; atbm_local_irq_restore(IrqState); return sta; } atbm_void ap_sta_del(struct hostapd_data *hostapd,struct hostapd_sta_info *sta) { int i=0; int IrqState; IrqState =atbm_local_irq_save(); hostapd->num_sta--; wifi_printk(WIFI_DBG_INIT,"hostapd sta_del\n"); atbmwifi_eloop_cancel_timeout(wpa_send_eapol_timeout,sta->atbmwifi_wpa_sm,ATBM_NULL);; if(sta->atbmwifi_wpa_sm) { if (sta->atbmwifi_wpa_sm->wpa_ie) { atbm_kfree(sta->atbmwifi_wpa_sm->wpa_ie); } if(sta->atbmwifi_wpa_sm->last_rx_eapol_key) { atbm_kfree(sta->atbmwifi_wpa_sm->last_rx_eapol_key); } atbm_kfree(sta->atbmwifi_wpa_sm); sta->atbmwifi_wpa_sm=ATBM_NULL; } for(i=0;ista_list[i]==sta) { hostapd->sta_list[i]=ATBM_NULL; break; } } atbm_local_irq_restore(IrqState); atbm_kfree(sta); #if CONFIG_WPS if(hostapd->num_sta <= 0){ if(hostapd->wpsdata == ATBM_NULL){ if(hostapd->wps){ if(!hostapd->wps->wpa_success_deauth){ #if CONFIG_P2P //if(hostapd->priv->p2p_ap) //atbm_p2p_restart(hostapd->priv); #endif }else{ hostapd->wps->wpa_success_deauth = 0; } } } } #endif } atbm_void hostap_sta_del(struct atbmwifi_vif *priv,atbm_uint8 * staMacAddr) { struct hostapd_data *hostapd = (struct hostapd_data *)priv->appdata; struct hostapd_sta_info *sta = ap_get_sta(hostapd,staMacAddr); wifi_printk(WIFI_ALWAYS,"hostap_sta_del\n"); if(sta){ ap_sta_del(hostapd,sta); } } int hostapd_get_aid(struct hostapd_data *hapd, struct hostapd_sta_info *sta) { if(sta->aid > ATBMWIFI__MAX_STA_IN_AP_MODE) return -1; else return sta->aid; } /** * ieee802_1x_receive - Process the EAPOL frames from the Supplicant * @hapd: hostapd BSS data * @sa: Source address (sender of the EAPOL frame) * @buf: EAPOL frame * @len: Length of buf in octets * * This function is called for each incoming EAPOL frame from the interface */ atbm_void ieee802_1x_receive(struct atbmwifi_vif *priv, const atbm_uint8 *sa, const atbm_uint8 *buf, atbm_size_t len) { struct hostapd_sta_info *sta; struct atbmwifi_ieee802_1x_hdr *hdr; struct atbmwifi_ieee802_1x_eapol_key *key; atbm_uint16 datalen; #if CONFIG_WPS //struct atbm_eap_hdr *eap_headr = ATBM_NULL; #endif // int key_mgmt; sta = ap_get_sta((struct hostapd_data *)priv->appdata, sa); if(ATBM_NULL == sta) { return; } if (len < sizeof(*hdr)) { return; } hdr = (struct atbmwifi_ieee802_1x_hdr *) buf; datalen = atbm_be_to_host16(hdr->length); if (len - sizeof(*hdr) < datalen) { return; } if (len - sizeof(*hdr) > datalen) { #ifdef LINUX_DEBUG wpa_printf(MSG_DEBUG, " ignoring %lu extra octets after " "IEEE 802.1X packet", (unsigned long) len - sizeof(*hdr) - datalen); #endif } key = (struct atbmwifi_ieee802_1x_eapol_key *) (hdr + 1); if (datalen >= sizeof(struct atbmwifi_ieee802_1x_eapol_key) && hdr->type == ATBM_IEEE802_1X_TYPE_EAPOL_KEY && (key->type == ATBM_EAPOL_KEY_TYPE_WPA || key->type == ATBM_EAPOL_KEY_TYPE_RSN)) { wpa_receive(priv, sta->atbmwifi_wpa_sm, (atbm_uint8 *) hdr, sizeof(*hdr) + datalen); return; } #if CONFIG_WPS switch(hdr->type){ case ATBM_IEEE802_1X_TYPE_EAP_PACKET: case ATBM_IEEE802_1X_TYPE_EAPOL_START: hostapd_wps_handshake_process(priv, sta, hdr, datalen); break; case ATBM_IEEE802_1X_TYPE_EAPOL_LOGOFF: break; default: wifi_printk(WIFI_DBG_MSG, " unknown IEEE 802.1X packet type"); break; } #endif } int hostapd_rx_assoc_req(struct atbmwifi_vif *priv,struct atbm_buff *skb) { int len = 0; struct hostapd_sta_info *sta; atbm_uint8 * data = ATBM_NULL; struct hostapd_data *hapd = (struct hostapd_data *)priv->appdata; struct atbmwifi_ieee80211_mgmt *mgmt = (struct atbmwifi_ieee80211_mgmt *) ATBM_OS_SKB_DATA(skb); struct atbmwifi_ieee80211_tx_info * tx_info = ATBM_IEEE80211_SKB_TXCB(skb); atbm_uint16 type = mgmt->frame_control & atbm_cpu_to_le16(ATBM_IEEE80211_FCTL_STYPE); atbm_uint16 resp = ATBM_WLAN_STATUS_SUCCESS; struct atbmwifi_ieee802_11_elems elems; /*This function can be modify ,FIX Later*/ sta = ap_get_sta(hapd, mgmt->sa); if(sta == ATBM_NULL) { sta = ap_sta_add(hapd, mgmt->sa,tx_info->link_id); if(sta == ATBM_NULL) { wifi_printk(WIFI_DBG_ERROR,"Sta " MACSTR " add FAIL.\n", MAC2STR(mgmt->sa)); resp = ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } sta->aid = tx_info->link_id; } if(type == ATBM_IEEE80211_STYPE_ASSOC_REQ) { data = (atbm_uint8 *)ATBM_OS_SKB_DATA(skb)+offsetof(struct atbmwifi_ieee80211_mgmt, u.assoc_req.variable); len = ATBM_OS_SKB_LEN(skb)-offsetof(struct atbmwifi_ieee80211_mgmt, u.assoc_req.variable); } else if(type == ATBM_IEEE80211_STYPE_REASSOC_REQ) { data = (atbm_uint8 *)ATBM_OS_SKB_DATA(skb)+offsetof(struct atbmwifi_ieee80211_mgmt, u.reassoc_req.variable); len = ATBM_OS_SKB_LEN(skb)-offsetof(struct atbmwifi_ieee80211_mgmt, u.reassoc_req.variable); } atbm_ieee802_11_parse_elems((atbm_uint8 *)data, len, &elems); resp = check_assoc_ies(priv, sta, &elems, 0); if (resp != ATBM_WLAN_STATUS_SUCCESS) goto fail; if (hostapd_get_aid(hapd, sta) <= 0) { resp = ATBM_WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; goto fail; } fail: if (resp != ATBM_WLAN_STATUS_SUCCESS){ //FIXME add deauth } else { hostapd_link_sta_sm(priv,atbmwifi_sta_find_form_hard_linkid(priv,tx_info->link_id),mgmt->sa); } return resp; } int hostapd_rx_assoc_req_event(struct atbmwifi_vif *priv,struct atbm_buff *skb) { struct atbmwifi_ieee80211_tx_info * tx_info = ATBM_IEEE80211_SKB_TXCB(skb); /*if not encrypt*/ if(priv->config.key_mgmt == ATBM_WPA_KEY_MGMT_NONE){ priv->connect_ok = 1; }else if(priv->config.key_mgmt == ATBM_WPA_KEY_MGMT_WEP){ extern atbm_void atbmwifi_wep_key_work(struct atbmwifi_vif *priv); wpa_common_install_wepkey(priv,(char *)priv->config.password,priv->config.group_cipher,priv->config.key_id/*KeyIndex 0...3*/,tx_info->link_id); atbmwifi_wep_key_work(priv); priv->connect_ok = 1; }else{/*Deal With WPA/WPA2*/ return hostapd_rx_assoc_req(priv,skb); } return 0; } atbm_void __wpa_send_eapol(struct atbmwifi_cfg *config, struct atbmwifi_wpa_state_machine *sm, int key_info, const atbm_uint8 *key_rsc, const atbm_uint8 *nonce, const atbm_uint8 *kde, atbm_size_t kde_len, int keyidx, int encr, int force_version) { struct atbmwifi_ieee802_1x_hdr *hdr; struct atbmwifi_wpa_eapol_key *key; atbm_size_t len; int alg; int key_data_len, pad_len = 0; atbm_uint8 *buf, *pos; int version, pairwise; int i; len = sizeof(struct atbmwifi_ieee802_1x_hdr) + sizeof(struct atbmwifi_wpa_eapol_key); if (force_version) version = force_version; #if CONFIG_SAE else if (atbmwifi_wpa_key_mgmt_sae(sm->wpa_key_mgmt)) version = ATBM_WPA_KEY_INFO_TYPE_AKM_DEFINED; #endif else if (wpa_use_aes_cmac(sm)) version = ATBM_WPA_KEY_INFO_TYPE_AES_128_CMAC; else if (sm->pairwise != ATBM_WPA_CIPHER_TKIP) version = ATBM_WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; else version = ATBM_WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; pairwise = key_info & ATBM_WPA_KEY_INFO_KEY_TYPE; key_data_len = kde_len; if ((version == ATBM_WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || atbmwifi_wpa_key_mgmt_sae(sm->wpa_key_mgmt) || version == ATBM_WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) { pad_len = key_data_len % 8; if (pad_len) pad_len = 8 - pad_len; key_data_len += pad_len + 8; } len += key_data_len; hdr = (struct atbmwifi_ieee802_1x_hdr *)atbm_kzalloc(len,GFP_KERNEL); if (hdr == ATBM_NULL) return; // TO DO GET VERSION hdr->version = 2;////???? need FIX ME ,dlink_655 version =1 hdr->type = ATBM_IEEE802_1X_TYPE_EAPOL_KEY; hdr->length = atbm_host_to_be16(len - sizeof(*hdr)); key = (struct atbmwifi_wpa_eapol_key *) (hdr + 1); key->type = sm->wpa == ATBM_WPA_VERSION_WPA2 ? ATBM_EAPOL_KEY_TYPE_RSN : ATBM_EAPOL_KEY_TYPE_WPA; key_info |= version; if (encr && sm->wpa == ATBM_WPA_VERSION_WPA2) key_info |= ATBM_WPA_KEY_INFO_ENCR_KEY_DATA; if (sm->wpa != ATBM_WPA_VERSION_WPA2) key_info |= keyidx << ATBM_WPA_KEY_INFO_KEY_INDEX_SHIFT; ATBM_WPA_PUT_BE16(key->key_info, key_info); alg = pairwise ? sm->pairwise : config->group_cipher; ATBM_WPA_PUT_BE16(key->key_length, wpa_commom_key_len(alg)); if (key_info & ATBM_WPA_KEY_INFO_SMK_MESSAGE) ATBM_WPA_PUT_BE16(key->key_length, 0); /* FIX: STSL: what to use as key_replay_counter? */ for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) { sm->key_replay[i].valid = sm->key_replay[i - 1].valid; atbm_memcpy(sm->key_replay[i].counter, sm->key_replay[i - 1].counter, ATBM_WPA_REPLAY_COUNTER_LEN); } atbmwifi_inc_byte_array(sm->key_replay[0].counter, ATBM_WPA_REPLAY_COUNTER_LEN); atbm_memcpy(key->replay_counter, sm->key_replay[0].counter, ATBM_WPA_REPLAY_COUNTER_LEN); sm->key_replay[0].valid = ATBM_TRUE; if (nonce) atbm_memcpy(key->key_nonce, nonce, ATBM_WPA_NONCE_LEN); if (key_rsc) atbm_memcpy(key->key_rsc, key_rsc, ATBM_WPA_KEY_RSC_LEN); if (kde && !encr) { atbm_memcpy(key + 1, kde, kde_len); ATBM_WPA_PUT_BE16(key->key_data_length, kde_len); } else if (encr && kde) { buf = (atbm_uint8 *)atbm_kzalloc(key_data_len,GFP_KERNEL); if (buf == ATBM_NULL) { atbm_kfree(hdr); return; } pos = buf; atbm_memcpy(pos, kde, kde_len); pos += kde_len; if (pad_len) *pos++ = 0xdd; if (version == ATBM_WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || atbmwifi_wpa_key_mgmt_sae(sm->wpa_key_mgmt) || version == ATBM_WPA_KEY_INFO_TYPE_AES_128_CMAC) { if (atbmwifi_aes_wrap(sm->PTK.kek, (key_data_len - 8) / 8, buf, (atbm_uint8 *) (key + 1))) { atbm_kfree(hdr); atbm_kfree(buf); return; } ATBM_WPA_PUT_BE16(key->key_data_length, key_data_len); } else { atbm_uint8 ek[32]; wifi_printk(WIFI_DBG_MSG,"WPA_HMAC_MD5_RC4\n\r"); atbm_memcpy(key->key_iv, sm->group->Counter + ATBM_WPA_NONCE_LEN - 16, 16); atbmwifi_inc_byte_array(sm->group->Counter, ATBM_WPA_NONCE_LEN); atbm_memcpy(ek, key->key_iv, 16); atbm_memcpy(ek + 16, sm->PTK.kek, 16); atbm_memcpy(key + 1, buf, key_data_len); atbmwifi_rc4_skip(ek, 32, 256, (atbm_uint8 *) (key + 1), key_data_len); ATBM_WPA_PUT_BE16(key->key_data_length, key_data_len); } atbm_kfree(buf); } if (key_info & ATBM_WPA_KEY_INFO_MIC) { if (!sm->PTK_valid) { atbm_kfree(hdr); return; } wpa_eapol_key_mic(sm->PTK.kck, version, (atbm_uint8 *) hdr, len, key->key_mic); } // wifi_printk(WIFI_DBG_MSG,"__wpa_send_eapol len+kde(%d)\n\r",len); wifi_printk(WIFI_DBG_MSG,"hostap_tx_eap\n"); hostapd_send_eapol((struct atbmwifi_vif * )atbmwifi_config_get_priv(config),sm->addr,ATBM_ETH_P_EAPOL,(atbm_uint8 *)hdr,len); atbm_kfree(hdr); } #if CONFIG_WPS atbm_void hostapd_wps_handshake_process(struct atbmwifi_vif *priv, struct hostapd_sta_info *sta, struct atbmwifi_ieee802_1x_hdr *hdr, atbm_uint16 datalen) { struct hostapd_data *hostapd = (struct hostapd_data *)priv->appdata; wpabuf_free(hostapd->wps_last_rx_data); hostapd->wps_last_rx_data = wpabuf_alloc_copy(hdr, datalen + sizeof(*hdr)); if(hostapd->wps_last_rx_data == ATBM_NULL){ wifi_printk(WIFI_DBG_ERROR, "wps_handshake_process alloc_copy failed"); return; } hostapd_run(priv,sta); } #endif atbm_void hostapd_4_way_handshake_start(struct atbmwifi_vif *priv,struct hostapd_sta_info *sta) { wifi_printk(WIFI_WPA,"hostapd_4way_start\n\r"); sta->timeout = STA_START; hostapd_run(priv,sta); } atbm_void hostapd_setup_4_way_handshake(struct atbmwifi_vif *priv,atbm_uint8 *da) { int link_id; struct hostapd_sta_info *sta; link_id = atbmwifi_find_link_id(priv, da); if(link_id==0){ wifi_printk(WIFI_WPA,"hostapd_setup_4_way_handshake drop1\n\r"); return; } sta = (struct hostapd_sta_info *)priv->link_id_db[link_id-1].sta_priv.reserved; if((sta==ATBM_NULL) ||(sta->atbmwifi_wpa_sm==ATBM_NULL)){ wifi_printk(WIFI_WPA,"hostapd_setup_4_way_handshake drop\n\r"); return; } atbmwifi_wpa_event_queue((atbm_void*)priv,(atbm_void*)&priv->link_id_db[link_id-1],ATBM_NULL,WPA_EVENT__HOSTAPD_STA_HANDSHAKE_START,ATBM_WPA_EVENT_NOACK); } int hostapd_send_4_of_1_msg(struct atbmwifi_vif *priv,struct atbmwifi_wpa_state_machine *sm) { atbm_uint8 buf[2 + ATBM_RSN_SELECTOR_LEN + ATBM_PMKID_LEN], *pmkid = ATBM_NULL; atbm_size_t pmkid_len = 0; sm->TimeoutCtr=0; sm->TimeoutCtr++; sm->TimeoutEvt = 0; if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) { /* No point in sending the EAPOL-Key - we will disconnect * immediately following this. */ return -1; } atbmwifi_os_get_random(sm->ANonce,32); if (atbmwifi_wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { if (atbmwifi_get_config(priv)->psk) { atbm_memcpy(sm->PMK,atbmwifi_get_config(priv)->psk, ATBM_PMK_LEN); } else { sm->wpa_ptk_state = ATBM_WPA_PTK_INITIALIZE; return -1; } } #if CONFIG_SAE if (sm->wpa == ATBM_WPA_VERSION_WPA2 && (atbmwifi_wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) || atbmwifi_wpa_key_mgmt_sae(sm->wpa_key_mgmt))) { pmkid = buf; pmkid_len = 2 + ATBM_RSN_SELECTOR_LEN + ATBM_PMKID_LEN; pmkid[0] = ATBM_WLAN_EID_VENDOR_SPECIFIC; pmkid[1] = ATBM_RSN_SELECTOR_LEN + ATBM_PMKID_LEN; ATBM_RSN_SELECTOR_PUT(&pmkid[2], ATBM_RSN_KEY_DATA_PMKID); if (sm->pmksa) { wpa_hexdump(MSG_DEBUG, "RSN: Message 1/4 PMKID from PMKSA entry", sm->pmksa->pmkid, ATBM_PMKID_LEN); atbm_memcpy(&pmkid[2 + ATBM_RSN_SELECTOR_LEN], sm->pmksa->pmkid, ATBM_PMKID_LEN); } else if (atbmwifi_wpa_key_mgmt_sae(sm->wpa_key_mgmt)) { if (sm->pmkid_set) { wpa_hexdump(MSG_DEBUG, "RSN: Message 1/4 PMKID from SAE", sm->pmkid, ATBM_PMKID_LEN); atbm_memcpy(&pmkid[2 + ATBM_RSN_SELECTOR_LEN], sm->pmkid, ATBM_PMKID_LEN); } else { /* No PMKID available */ wpa_printf(MSG_DEBUG, "RSN: No SAE PMKID available for message 1/4"); pmkid = ATBM_NULL; } } } #endif /* CONFIG_SAE */ wpa_send_eapol(atbmwifi_get_config(priv), sm, ATBM_WPA_KEY_INFO_ACK | ATBM_WPA_KEY_INFO_KEY_TYPE, ATBM_NULL, sm->ANonce,pmkid,pmkid_len, 0, 0); return 0; } int hostapd_handshake_over(struct atbmwifi_vif *priv,struct atbmwifi_wpa_state_machine *sm) { sm->EAPOLKeyReceived = ATBM_FALSE; if (sm->Pair) { #if (CONFIG_WPA2_REINSTALL_CERTIFICATION) if(sm->pairwise_set==0) #endif //(CONFIG_WPA2_REINSTALL_CERTIFICATION) { if (wpa_common_install_ptk(priv,&sm->PTK, sm->pairwise,1 | (sm->linkid << 8))) { wifi_printk(WIFI_DBG_ERROR,"install pk err\n"); return -1; } } /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */ sm->pairwise_set = ATBM_TRUE; atbmwifi_eloop_cancel_timeout(wpa_send_eapol_timeout, (atbm_void *)sm,ATBM_NULL); } if (sm->wpa == ATBM_WPA_VERSION_WPA) { sm->PInitAKeys = ATBM_TRUE; sm->wpa_ptk_group_state = ATBM_WPA_PTK_GROUP_REKEYNEGOTIATING; } else { sm->has_GTK = ATBM_TRUE; sm->wpa_ptk_group_state = ATBM_WPA_PTK_GROUP_KEYINSTALLED; } sm->wpa_ptk_state = ATBM_WPA_PTK_INSTALL; sm->GTimeoutCtr = 0; #if CONFIG_IEEE80211W if(sm->mgmt_frame_prot){ struct atbmwifi_sta_priv *sta = (struct atbmwifi_sta_priv * )atbmwifi_sta_find(priv,sm->addr); if(sta) sta->ieee_80211w = 1; } #endif return 0; } static atbm_void hostapd_4_way_handshake_err(struct atbmwifi_vif *priv,struct atbmwifi_wpa_state_machine *sm) { atbm_uint32 IrqState = 0; struct hostapd_data *hostapd = (struct hostapd_data *)(priv->appdata); wifi_printk(WIFI_DBG_ERROR,"handshake err\n\r"); if(hostapd->num_sta < 1) { return ; } if(sm->linkid > ATBMWIFI__MAX_STA_IN_AP_MODE){ wifi_printk(WIFI_DBG_ERROR,"hostapd_4_way_handshake_err linkid %d \n\r",sm->linkid); return; } IrqState =atbm_local_irq_save(); hostapd->sta_list[sm->linkid-1]->timeout = STA_HANDSHAKE; atbm_local_irq_restore(IrqState); eloop_register_task(priv,hostapd->sta_list[sm->linkid-1]); } int hostapd_4_way_handshake_process(struct atbmwifi_vif *priv,struct atbmwifi_wpa_state_machine *sm) { int res = 0; if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) { wifi_printk(WIFI_DBG_ERROR,"hostapd err Timeout %d>%d\n\r",sm->TimeoutCtr,dot11RSNAConfigPairwiseUpdateCount); hostapd_4_way_handshake_err(priv,sm); return res; } switch(sm->wpa_ptk_state) { case ATBM_WPA_PTK_DISCONNECT: break; case ATBM_WPA_PTK_INITIALIZE: if(atbmwifi_get_config(priv)->key_mgmt== ATBM_WPA_KEY_MGMT_PSK) { hostapd_eapol_init(priv,sm); } break; case ATBM_WPA_PTK_PTKSTART: res = hostapd_send_4_of_1_msg(priv,sm); break; case ATBM_WPA_PTK_PTKINITNEGOTIATING: wifi_printk(WIFI_DBG_MSG,"start 3/4\n\r"); res = hostapd_send_4_of_3_msg(priv,sm); break; case ATBM_WPA_PTK_PTKINITDONE: res = hostapd_handshake_over(priv,sm); break; default: res = -1; break; } return res; } int hostapd_send_1_of_group(struct atbmwifi_vif *priv,struct atbmwifi_wpa_state_machine *sm) { atbm_uint8 rsc[ATBM_WPA_KEY_RSC_LEN]; struct atbmwifi_wpa_group *gsm = sm->group; atbm_uint8 *kde, *pos, hdr[2]; atbm_size_t kde_len; atbm_uint8 *gtk; sm->GTimeoutCtr++; if (sm->GTimeoutCtr > (int) dot11RSNAConfigGroupUpdateCount) { /* No point in sending the EAPOL-Key - we will disconnect * immediately following this. */ return -1; } if (sm->wpa == ATBM_WPA_VERSION_WPA) sm->PInitAKeys = ATBM_FALSE; sm->TimeoutEvt = ATBM_FALSE; /* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */ atbm_memset(rsc, 0, ATBM_WPA_KEY_RSC_LEN); gtk = gsm->GTK[gsm->GN - 1]; if (sm->wpa == ATBM_WPA_VERSION_WPA2) { kde_len = 2 + ATBM_RSN_SELECTOR_LEN + 2 + gsm->GTK_len + atbmwifi_ieee80211w_kde_len(sm); kde = (atbm_uint8 *)atbm_kmalloc(kde_len,GFP_KERNEL); if (kde == ATBM_NULL) return -1; pos = kde; hdr[0] = gsm->GN & 0x03; hdr[1] = 0; pos = wpa_add_kde(pos, ATBM_RSN_KEY_DATA_GROUPKEY, hdr, 2, gtk, gsm->GTK_len); pos = atbmwifi_ieee80211w_kde_add(sm, pos); } else { kde = gtk; pos = kde + gsm->GTK_len; } wifi_printk(WIFI_WPA,"tx g 1/2\n\r"); wpa_send_eapol(atbmwifi_get_config(priv), sm, ATBM_WPA_KEY_INFO_SECURE | ATBM_WPA_KEY_INFO_MIC | ATBM_WPA_KEY_INFO_ACK | (!sm->Pair ? ATBM_WPA_KEY_INFO_INSTALL : 0), rsc, gsm->GNonce, kde, pos - kde, gsm->GN, 1); if (sm->wpa == ATBM_WPA_VERSION_WPA2) { atbm_kfree(kde); } return 0; } int hostapd_2_way_group_err(struct atbmwifi_vif *priv,struct atbmwifi_wpa_state_machine *sm) { return 0; } int hostapd_2_way_group_process(struct atbmwifi_vif *priv,struct atbmwifi_wpa_state_machine *sm) { int res = 0; if (sm->GTimeoutCtr > (int) dot11RSNAConfigGroupUpdateCount) { /* No point in sending the EAPOL-Key - we will disconnect * immediately following this. */ sm->wpa_ptk_group_state = ATBM_WPA_PTK_GROUP_KEYERROR; res = -1; return res; } switch(sm->wpa_ptk_group_state) { case ATBM_WPA_PTK_GROUP_IDLE: break; case ATBM_WPA_PTK_GROUP_REKEYNEGOTIATING: hostapd_send_1_of_group(priv,sm); break; case ATBM_WPA_PTK_GROUP_REKEYESTABLISHED: { atbm_uint8 *gtk; struct atbmwifi_wpa_group *group = sm->group; struct atbmwifi_cfg *config = atbmwifi_get_config(priv); group->changed = ATBM_TRUE; atbmwifi_eloop_cancel_timeout(wpa_send_eapol_timeout,(atbm_void *)sm,ATBM_NULL); group->wpa_group_state = ATBM_WPA_GROUP_SETKEYSDONE; gtk = group->GTK[group->GN - 1]; res = wpa_common_install_gtk(priv,gtk,config->group_cipher,group->GN); if(res == 0) { wifi_printk(WIFI_WPA,"finish g 2/2\n\r"); sm->wpa_ptk_group_state = ATBM_WPA_PTK_GROUP_KEYINSTALLED; priv->connect.encrype = 1; priv->connect_ok = 1; } else { sm->wpa_ptk_group_state = ATBM_WPA_PTK_GROUP_REKEYNEGOTIATING; } } break; case ATBM_WPA_PTK_GROUP_KEYERROR: res = hostapd_2_way_group_err(priv,sm); break; default: res = -1; break; } return res; } atbm_void hostapd_run_handshake(struct atbmwifi_vif *priv,struct atbmwifi_wpa_state_machine *sm) { int res = 0 ; int loop = 0; retry: loop++; if(sm->wpa_ptk_state != ATBM_WPA_PTK_INSTALL) { res = hostapd_4_way_handshake_process(priv,sm); } else { if(sm->wpa_ptk_group_state != ATBM_WPA_PTK_GROUP_KEYINSTALLED) { res = hostapd_2_way_group_process(priv,sm); }else { struct atbmwifi_wpa_group *group = sm->group; atbmwifi_eloop_cancel_timeout(wpa_send_eapol_timeout,(atbm_void *)sm,ATBM_NULL); group->wpa_group_state = ATBM_WPA_GROUP_SETKEYSDONE; priv->connect.encrype = 1; priv->connect_ok = 1; res = 0; } } if((res<0) && loop < 10) { wifi_printk(WIFI_DBG_ERROR,"hostapd err Timeout %d wpa_ptk_state %d group_state %d\n\r",sm->TimeoutCtr,sm->wpa_ptk_state,sm->wpa_ptk_group_state ); goto retry; } if(loop>=10){ wifi_printk(WIFI_DBG_ERROR,"hostapd err Timeout %d wpa_ptk_state %d group_state %d\n\r",sm->TimeoutCtr,sm->wpa_ptk_state,sm->wpa_ptk_group_state ); } } atbm_void hostapd_run(struct atbmwifi_vif *priv,struct hostapd_sta_info *sta) { struct hostapd_data *hostapd = (struct hostapd_data *)(priv->appdata); #if CONFIG_WPS //struct hostapd_sta_info *sta = hostapd->sta_list[hostapd->num_sta-1]; struct atbmwifi_ieee802_1x_hdr *hdr = ATBM_NULL; atbm_size_t datalen = 0; atbm_size_t len = 0; struct atbm_eap_hdr *eap_headr = 0; wifi_printk(WIFI_DBG_MSG, "hostapd run start wps = %d \n", hostapd->wps_last_rx_data?1:0); if(hostapd->wps_last_rx_data) { datalen = hostapd->wps_last_rx_data->used; hdr = (struct atbmwifi_ieee802_1x_hdr *)wpabuf_head_u8(hostapd->wps_last_rx_data); if(hdr) { switch(hdr->type){ case ATBM_IEEE802_1X_TYPE_EAP_PACKET: handle_eap((struct hostapd_data *)priv->appdata, sta, (atbm_uint8 *)(hdr + 1), datalen); break; case ATBM_IEEE802_1X_TYPE_EAPOL_START: wifi_printk(WIFI_DBG_MSG, "received EAPOL-Start from STA\n"); len = sizeof(struct atbmwifi_ieee802_1x_hdr) + sizeof(struct atbm_eap_hdr) + 1; hdr = (struct atbmwifi_ieee802_1x_hdr *)atbm_kmalloc(len, GFP_KERNEL); if(hdr == ATBM_NULL) goto wps_out; hdr->version = EAPOL_VERSION; hdr->type = ATBM_IEEE802_1X_TYPE_EAP_PACKET; hdr->length = atbm_host_to_be16(sizeof(struct atbm_eap_hdr) + 1); eap_headr = (struct atbm_eap_hdr *)(hdr + 1); eap_headr->code = EAP_CODE_REQUEST; eap_headr->identifier = 0; eap_headr->length = atbm_host_to_be16(sizeof(struct atbm_eap_hdr) + 1); *(atbm_uint8 *)(eap_headr + 1) = ATBM_EAP_TYPE_IDENTITY; hostapd_send_eapol(priv, sta->addr, ATBM_ETH_P_EAPOL, (atbm_uint8 *)hdr, len); atbm_kfree(hdr); hdr = ATBM_NULL; break; default: break; } } wps_out: wpabuf_free(hostapd->wps_last_rx_data); hostapd->wps_last_rx_data = ATBM_NULL; return; } #endif switch(sta->timeout) { case STA_START: { sta->atbmwifi_wpa_sm->linkid = sta->aid; hostapd_run_handshake(priv,sta->atbmwifi_wpa_sm); break; } case STA_DISASSOC: case STA_HANDSHAKE: { atbmwifi_ieee80211_send_deauth_disassoc(priv, sta->addr,priv->bssid, ATBM_IEEE80211_STYPE_DEAUTH, ATBM_WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, ATBM_NULL, ATBM_TRUE); wifi_printk(WIFI_WPA,"hostapd deauth\n"); atbmwifi_ap_deauth(priv, sta->addr); break; } default: { } } } int hostapd_derive_psk(struct atbmwifi_cfg *config) { if(config->psk_set == 1) { return 0; } atbm_pbkdf2_sha1((const char*)config->password, (const char*)config->ssid, config->ssid_len, 4096, config->psk, ATBM_PMK_LEN);//pmk=psk; config->psk_set = 1; return 0; } int hostapd_eapol_init(struct atbmwifi_vif *priv,struct atbmwifi_wpa_state_machine *sm) { if (sm->Init) { /* Init flag is not cleared here, so avoid busy * loop by claiming nothing changed. */ sm->changed = ATBM_FALSE; } sm->keycount = 0; if (sm->GUpdateStationKeys) sm->group->GKeyDoneStations--; sm->GUpdateStationKeys = ATBM_FALSE; if (sm->wpa == ATBM_WPA_VERSION_WPA) sm->PInitAKeys = ATBM_FALSE; if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and * Local AA > Remote AA)) */) { sm->Pair = ATBM_TRUE; } atbm_memset(&sm->PTK, 0, sizeof(sm->PTK)); sm->PTK_valid = ATBM_FALSE; sm->AuthenticationRequest = ATBM_FALSE; sm->req_replay_counter_used = 0; sm->TimeoutCtr = 0; return 0; } atbm_void hostapd_link_sta_sm(struct atbmwifi_vif *priv, struct atbmwifi_sta_priv *sta_priv,atbm_uint8* mac) { struct hostapd_sta_info *sta; sta = ap_get_sta((struct hostapd_data *)priv->appdata, mac); if(ATBM_NULL == sta) { return; } sta_priv->reserved = sta; } struct hostapd_data *init_hostapd(struct atbmwifi_vif *priv) { struct hostapd_data *hostapd; hostapd = (struct hostapd_data *)atbm_kzalloc(sizeof(struct hostapd_data),GFP_KERNEL); g_hostapd = hostapd; hostapd->priv = priv; return hostapd; } atbm_void free_hostapd(struct atbmwifi_vif *priv) { if(priv->appdata){ #if CONFIG_WPS hostapd_deinit_wps(priv->appdata); #endif atbm_kfree(priv->appdata); priv->appdata = ATBM_NULL; g_hostapd = ATBM_NULL; } } #if CONFIG_SAE static int wpa_auth_pmksa_clear_cb(struct atbmwifi_wpa_state_machine *sm, void *ctx) { if (sm->pmksa == ctx) sm->pmksa = NULL; return 0; } static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry, void *ctx) { // struct wpa_authenticator *wpa_auth = ctx; // wpa_auth_for_each_sta(wpa_auth, wpa_auth_pmksa_clear_cb, entry); } #endif int hostapd_start(struct atbmwifi_vif *priv) { struct atbmwifi_cfg *config = NULL; struct hostapd_data *hostapd = (struct hostapd_data *)priv->appdata; config = atbmwifi_get_config(priv); //TO DO CLEAN KEY switch(config->key_mgmt) { case ATBM_KEY_WEP: case ATBM_KEY_WEP_SHARE: { config->auth_alg = (config->key_mgmt == ATBM_KEY_WEP) ? ATBM_WPA_AUTH_ALG_OPEN : ATBM_WPA_AUTH_ALG_SHARED; config->key_mgmt = ATBM_WPA_KEY_MGMT_WEP; config->key_id=0; if(config->password_len== 5) { config->group_cipher = ATBM_WPA_CIPHER_WEP40; config->pairwise_cipher = ATBM_WPA_CIPHER_WEP40; } else if(config->password_len == 13) { config->group_cipher = ATBM_WPA_CIPHER_WEP104; config->pairwise_cipher = ATBM_WPA_CIPHER_WEP104; } break; } case ATBM_KEY_WPA: case ATBM_KEY_WPA2: { atbm_uint8 keytype = (config->key_mgmt == ATBM_KEY_WPA) ? 0 : 1; config->auth_alg = ATBM_WPA_AUTH_ALG_OPEN; config->key_mgmt = ATBM_WPA_KEY_MGMT_PSK; config->group_cipher = keytype ? ATBM_WPA_CIPHER_CCMP : ATBM_WPA_CIPHER_TKIP; config->pairwise_cipher = config->group_cipher; config->wpa = keytype ? ATBM_WPA_PROTO_RSN : ATBM_WPA_PROTO_WPA; wifi_printk(WIFI_DBG_INIT,"hostapd key_mgmt(%d) wpa(%d)\n",config->key_mgmt,config->wpa); break; } case ATBM_KEY_MIX: { config->auth_alg = ATBM_WPA_AUTH_ALG_OPEN; config->key_mgmt = ATBM_WPA_KEY_MGMT_PSK; config->group_cipher = ATBM_WPA_CIPHER_TKIP; config->pairwise_cipher = ATBM_WPA_CIPHER_CCMP; config->wpa = ATBM_WPA_PROTO_RSN;//can do it break; } case ATBM_KEY_NONE: { config->auth_alg = ATBM_WPA_AUTH_ALG_OPEN; config->key_mgmt =ATBM_WPA_KEY_MGMT_NONE; config->group_cipher = ATBM_WPA_CIPHER_NONE; config->pairwise_cipher = ATBM_WPA_CIPHER_NONE; config->wpa =0; break; } #if CONFIG_SAE case ATBM_KEY_SAE: { config->auth_alg = ATBM_WPA_AUTH_ALG_SAE; config->key_mgmt = ATBM_WPA_KEY_MGMT_SAE; config->group_cipher = ATBM_WPA_CIPHER_CCMP; config->pairwise_cipher = ATBM_WPA_CIPHER_CCMP; config->group_mgmt_cipher = ATBM_WPA_CIPHER_AES_128_CMAC; config->ieee80211w = ATBM_MGMT_FRAME_PROTECTION_REQUIRED; config->wpa = ATBM_WPA_PROTO_RSN;//can do it break; } case ATBM_KEY_SAE_COMPIT: { config->auth_alg = ATBM_WPA_AUTH_ALG_SAE | ATBM_WPA_AUTH_ALG_OPEN; config->key_mgmt = ATBM_WPA_KEY_MGMT_SAE|ATBM_WPA_KEY_MGMT_PSK; config->group_cipher = ATBM_WPA_CIPHER_CCMP; config->pairwise_cipher = ATBM_WPA_CIPHER_CCMP; config->group_mgmt_cipher = ATBM_WPA_CIPHER_AES_128_CMAC; config->ieee80211w = ATBM_MGMT_FRAME_PROTECTION_OPTIONAL; config->wpa = ATBM_WPA_PROTO_RSN;//can do it break; } #endif default: { wifi_printk(WIFI_DBG_ERROR," hostapd key_mgmt(%d)\n",config->key_mgmt); return -1; } } if(config->key_mgmt & ATBM_WPA_KEY_MGMT_PSK) { config->psk_set = 0; hostapd_derive_psk(config); } hostapd_init_extra_ie(priv); wifi_printk(WIFI_WPA,"hostapd(%s)(%d %d) start to beacon\n",priv->ssid,config->key_mgmt,config->group_cipher); wpa_group_init(config,&hostapd->group,0); #if CONFIG_5G_SUPPORT if(config->channel_index >= 36) config->band = ATBM_IEEE80211_BAND_5GHZ; else #endif config->band = ATBM_IEEE80211_BAND_2GHZ; priv->bss.sta_priv.band = config->band; atbm_start_ap(priv); atbm_memcpy(hostapd->own_addr, priv->bssid, ATBM_ETH_ALEN); atbm_kfree(priv->extra_ie); priv->extra_ie = ATBM_NULL; priv->extra_ie_len = 0; #if CONFIG_WPS hostapd_init_wps(priv); #endif #if CONFIG_SAE { int sae_groups[4] = {19, 20, 21, 0}; hostapd->wpa_passphrase = priv->config.password; hostapd->sae_sync = 5; hostapd->sae_anti_clogging_threshold = 5; atbm_memcpy(&hostapd->sae_groups, sae_groups, sizeof(sae_groups)); hostapd->pmksa = pmksa_cache_init(wpa_auth_pmksa_free_cb, ATBM_NULL, ATBM_NULL); } #endif /* hera:for light sleep, must set after ap up to avoid lmac restart firmware BUG, group key not resume after light sleep */ if(config->group_cipher != ATBM_WPA_CIPHER_NONE){ wpa_common_install_gtk(priv,hostapd->group.GTK[hostapd->group.GN-1],config->group_cipher,hostapd->group.GN); } #if CONFIG_IEEE80211W if(config->ieee80211w != ATBM_NO_MGMT_FRAME_PROTECTION){ wpa_common_install_igtk(priv, hostapd->group.IGTK[hostapd->group.GN_igtk - 4], config->group_mgmt_cipher, hostapd->group.GN_igtk); } #endif return 0; }