Files
luban-lite/bsp/peripheral/wireless/atbm603x/net/wpa/hostapd_main.c
刘可亮 8bca5e8332 v1.0.4
2024-04-03 16:40:57 +08:00

2606 lines
73 KiB
C

/**************************************************************************************************************
* 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;i<ATBMWIFI__MAX_STA_IN_AP_MODE;i++){
tmp = hapd->sta_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;i<ATBMWIFI__MAX_STA_IN_AP_MODE;i++){
tmp = hapd->sta_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;id<ATBMWIFI__MAX_STA_IN_AP_MODE;id++){
sta = hapd->sta_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;i<ATBMWIFI__MAX_STA_IN_AP_MODE;i++){
if( hostapd->sta_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,"<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,"<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;
}