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

3285 lines
101 KiB
C

#include "atbm_hal.h"
#if CONFIG_WPS
extern int wps_parse_msg_attr(const atbm_uint8 *msg, atbm_uint8 length, struct wps_parse_attr *attr);
#endif
extern atbm_void atbmwifi_ap_join_timeout(atbm_void *data1,atbm_void *data2);
int atbmwifi_rx_authen(struct atbmwifi_vif *priv,struct atbm_buff *skb);
#if CONFIG_IEEE80211W
static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
static int sme_check_sa_query_timeout(struct wpa_supplicant *wpa_s)
{
atbm_uint32 now, passed;
now = atbm_GetOsTime();
passed = now - wpa_s->sa_query_start;
if (1000 < passed) {
wpa_printf(MSG_WARNING, "SME: SA Query timed out");
sme_stop_sa_query(wpa_s);
sta_deauth(wpa_s->priv);
return 1;
}
return 0;
}
static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
unsigned int timeout, sec, usec;
atbm_uint8 *trans_id, *nbuf;
struct atbm_buff *skb;
struct atbmwifi_vif *priv = wpa_s->priv;
if (wpa_s->sa_query_count > 0 &&
sme_check_sa_query_timeout(wpa_s))
return;
nbuf = atbm_realloc_array(wpa_s->sa_query_trans_id,
wpa_s->sa_query_count + 1,
WLAN_SA_QUERY_TR_ID_LEN);
if (nbuf == NULL) {
sme_stop_sa_query(wpa_s);
return;
}
if (wpa_s->sa_query_count == 0) {
/* Starting a new SA Query procedure */
wpa_s->sa_query_start = atbm_GetOsTime();
}
trans_id = nbuf + wpa_s->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
wpa_s->sa_query_trans_id = nbuf;
wpa_s->sa_query_count++;
if (atbmwifi_os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
wpa_printf(MSG_DEBUG, "Could not generate SA Query ID");
sme_stop_sa_query(wpa_s);
return;
}
atbmwifi_eloop_register_timeout(0, 250, sme_sa_query_timer, wpa_s, NULL);
wpa_printf(MSG_DEBUG, "SME: Association SA Query attempt %d",
wpa_s->sa_query_count);
skb = atbmwifi_ieee80211_send_saquery(wpa_s->priv, priv->bssid, priv->bssid, ATBM_WLAN_ACTION_SA_QUERY_REQUEST, trans_id);
atbmwifi_tx(priv->hw_priv, skb, priv);
}
static void sme_stop_sa_query(struct wpa_supplicant *wpa_s)
{
if (wpa_s->sa_query_trans_id)
wpa_printf(MSG_DEBUG, "SME: Stop SA Query");
atbmwifi_eloop_cancel_timeout(sme_sa_query_timer, wpa_s, NULL);
atbm_kfree(wpa_s->sa_query_trans_id);
wpa_s->sa_query_trans_id = NULL;
wpa_s->sa_query_count = 0;
}
static void sme_start_sa_query(struct wpa_supplicant *wpa_s)
{
sme_sa_query_timer(wpa_s, NULL);
}
void atbmwifi_handle_unprot_disassoc(struct atbmwifi_vif *priv,struct atbm_buff *skb){
struct atbmwifi_ieee80211_mgmt *mgmt = ATBM_OS_SKB_DATA(skb);
struct wpa_supplicant *wpa_s;
atbm_uint16 reason_code = -1;
atbm_uint32 now;
if(priv->iftype == ATBM_NL80211_IFTYPE_STATION){
wpa_s = (struct wpa_supplicant *)priv->appdata;
if(wpa_s->wpa_state != ATBM_WPA_COMPLETED){
return;
}
if (atbm_memcmp(mgmt->sa, priv->bssid, ATBM_ETH_ALEN) != 0){
return;
}
reason_code = mgmt->u.deauth.reason_code;
if(reason_code != ATBM_WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA &&
reason_code != ATBM_WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA){
return;
}
now = atbm_GetOsTime();
if(wpa_s->last_unprot_disconnect &&
(now - wpa_s->last_unprot_disconnect) < 10 * 1000){
return;
}
wpa_s->last_unprot_disconnect = now;
sme_start_sa_query(wpa_s);
}
}
int
atbmwifi_ieee80211_drop_unencrypted_mgmt(struct atbmwifi_vif *priv,struct atbm_buff *skb)
{
struct atbmwifi_ieee80211_hdr *hdr = ATBM_OS_SKB_DATA(skb);
struct atbmwifi_ieee80211_rx_status *status = ATBM_IEEE80211_SKB_RXCB(skb);
atbm_uint16 fc = hdr->frame_control;
/*
* Pass through unencrypted frames if the hardware has
* decrypted them already.
*/
if (status->flag & ATBM_RX_FLAG_DECRYPTED)
return 0;
if (priv->iftype == ATBM_NL80211_IFTYPE_STATION && priv->connect.crypto_igtkgroup) {
if (atbm_unlikely(!atbmwifi_ieee80211_has_protected(fc) &&
!atbm_is_multicast_ether_addr(hdr->addr1) &&
atbmwifi_ieee80211_is_robust_mgmt_frame(hdr))) {
if(atbmwifi_ieee80211_is_deauth(fc) ||
atbmwifi_ieee80211_is_disassoc(fc)){
atbmwifi_handle_unprot_disassoc(priv, skb);
}
return -ATBM_EACCES;
}
/* BIP does not use Protected field, so need to check MMIE */
if(atbm_unlikely(atbm_is_multicast_ether_addr(hdr->addr1) &&
atbmwifi_ieee80211_is_robust_mgmt_frame(hdr)
)){
if(atbmwifi_ieee80211_is_deauth(fc) ||
atbmwifi_ieee80211_is_disassoc(fc)){
atbmwifi_handle_unprot_disassoc(priv, skb);
}
return -ATBM_EACCES;
}
/*
* When using MFP, Action frames are not allowed prior to
* having configured keys.
*/
if (atbm_unlikely(atbmwifi_ieee80211_is_action(fc) && !priv->connect.crypto_igtkgroup &&
atbmwifi_ieee80211_is_robust_mgmt_frame(hdr)
)){
return -ATBM_EACCES;
}
}
return 0;
}
static void atbmwifi_ieee80211_process_sa_query_req(struct atbmwifi_vif *priv,
struct atbmwifi_ieee80211_mgmt *mgmt,
atbm_size_t len)
{
struct sk_buff *skb;
if (atbm_compare_ether_addr(mgmt->da, priv->mac_addr) != 0) {
/* Not to own unicast address */
return;
}
if (atbm_compare_ether_addr(mgmt->sa, priv->bssid) != 0 ||
atbm_compare_ether_addr(mgmt->bssid, priv->bssid) != 0) {
/* Not from the current AP or not associated yet. */
return;
}
if (len < 24 + 1 + sizeof(mgmt->u.action.u.sa_query)) {
/* Too short SA Query request frame */
return;
}
skb = atbmwifi_ieee80211_send_saquery(priv, priv->bssid, priv->bssid, ATBM_WLAN_ACTION_SA_QUERY_RESPONSE, mgmt->u.action.u.sa_query.trans_id);
atbmwifi_tx(priv->hw_priv, skb, priv);
}
#endif //CONFIG_IEEE80211W
atbm_void atbmwifi_rx_actionFrame(struct atbmwifi_vif *priv,struct atbm_buff *skb)
{
struct atbmwifi_ieee80211_mgmt *mgmt = (struct atbmwifi_ieee80211_mgmt *) ATBM_OS_SKB_DATA(skb);
atbm_uint8 *tmp_ie;
struct atbmwifi_ieee80211_channel_sw_packed_ie sw_packed_ie;
sw_packed_ie.chan_sw_ie = ATBM_NULL;
sw_packed_ie.ex_chan_sw_ie = ATBM_NULL;
sw_packed_ie.sec_chan_offs_ie = ATBM_NULL;
switch (mgmt->u.action.category) {
#if ATBM_PKG_REORDER
case ATBM_WLAN_CATEGORY_BACK:
{
#if ATBM_DRIVER_PROCESS_BA
if(priv->hw_priv->driver_setup_ba){
struct atbmwifi_ieee80211_rx_status *hdr = ATBM_IEEE80211_SKB_RXCB(skb);
struct atbmwifi_sta_priv *sta_priv;
sta_priv = atbmwifi_sta_find(priv,mgmt->sa);
wifi_printk(WIFI_BASETUP, "RX BA action %d\n", mgmt->u.action.u.addba_req.action_code);
if(!sta_priv || !sta_priv->ampdu_mlme.init){
wifi_printk(WIFI_DBG_ERROR, "Rx unexpected BA setup Actions\n");
return;
}
switch (mgmt->u.action.u.addba_req.action_code) {
case ATBM_WLAN_ACTION_ADDBA_REQ:
ieee80211_process_addba_request(priv->hw_priv,
sta_priv, mgmt, ATBM_OS_SKB_LEN(skb));
break;
case ATBM_WLAN_ACTION_DELBA:
ieee80211_process_delba(priv->hw_priv, sta_priv, mgmt, ATBM_OS_SKB_LEN(skb));
break;
case ATBM_WLAN_ACTION_ADDBA_RESP:
ieee80211_process_addba_resp(priv->hw_priv, sta_priv, mgmt, ATBM_OS_SKB_LEN(skb));
break;
default:
break;
}
}else
#endif
{
struct atbmwifi_ieee80211_rx_status *hdr = ATBM_IEEE80211_SKB_RXCB(skb);
struct atbm_ba_params ba_params;
ba_params.link_id = hdr->link_id;
switch (mgmt->u.action.u.addba_req.action_code) {
case ATBM_WLAN_ACTION_ADDBA_REQ:
{
atbm_uint16 capab;
ba_params.action = ATBM_BA__ACTION_RX_ADDBR;
ba_params.timeout = atbm_le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
capab = atbm_le16_to_cpu(mgmt->u.action.u.addba_req.capab);
ba_params.tid = (capab & ATBM_IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
// ba_params.win_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
ba_params.win_size = BUFF_STORED_LEN;
ba_params.ssn = atbm_le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
wifi_printk(WIFI_ALWAYS,"rx ADDBA_REQ:ssn(%x),tid(%d),link_id(%d),win_size(%d)\n",ba_params.ssn,ba_params.tid,ba_params.link_id,ba_params.win_size);
atbm_updata_ba_tid_params(priv,&ba_params);
break;
}
case ATBM_WLAN_ACTION_DELBA:
{
atbm_uint16 params;
params = atbm_le16_to_cpu(mgmt->u.action.u.delba.params);
ba_params.tid = (params & ATBM_IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
ba_params.action = ATBM_BA__ACTION_RX_DELBA;
atbm_updata_ba_tid_params(priv,&ba_params);
break;
}
default:
break;
}
}
}
break;
#endif
case ATBM_WLAN_CATEGORY_SPECTRUM_MGMT:
// add 8.5.2.6 Channel Switch Announcement frame format
if(ATBM_WLAN_ACTION_SPCT_CHL_SWITCH == mgmt->u.action.u.chan_switch.action_code)
{
sw_packed_ie.chan_sw_ie = &mgmt->u.action.u.chan_switch.sw_elem;
tmp_ie = ((atbm_uint8 *)sw_packed_ie.chan_sw_ie) + 3;
if((tmp_ie[0] == ATBM_WLAN_EID_SECONDARY_CH_OFFSET)&&(tmp_ie[1]==1))
{
sw_packed_ie.sec_chan_offs_ie = (struct atbmwifi_ieee80211_sec_chan_offs_ie *)(tmp_ie+2);
}
atbm_ieee80211_sta_process_chanswitch(priv,&priv->bss,&sw_packed_ie,0);
}
break;
case ATBM_WLAN_CATEGORY_PUBLIC:
//add 8.5.8.7 Extended Channel Switch Announcement frame format
if(ATBM_WLAN_PUB_ACTION_EX_CHL_SW_ANNOUNCE == mgmt->u.action.u.ext_chan_switch.action_code)
{
sw_packed_ie.ex_chan_sw_ie = &mgmt->u.action.u.ext_chan_switch.ext_sw_elem;
atbm_ieee80211_sta_process_chanswitch(priv,&priv->bss,&sw_packed_ie,0);
break;
}
#if CONFIG_P2P
case ATBM_WLAN_CATEGORY_VENDOR_SPECIFIC:
{
struct atbmwifi_ieee80211_mgmt *mgmt = (struct atbmwifi_ieee80211_mgmt *)ATBM_OS_SKB_DATA(skb);
struct atbmwifi_ieee80211_rx_status *hw_hdr = ATBM_IEEE80211_SKB_RXCB(skb);
atbm_uint8 *data = (atbm_uint8 *)ATBM_OS_SKB_DATA(skb) + offsetof(struct atbmwifi_ieee80211_mgmt, u.probe_req.variable) + 1;
int len = ATBM_OS_SKB_LEN(skb) - offsetof(struct atbmwifi_ieee80211_mgmt, u.probe_req.variable) - 1;
atbm_p2p_rx_action(priv, mgmt->da, mgmt->sa, mgmt->bssid,
mgmt->u.action.category, data, len, hw_hdr->freq);
}
#endif
break;
case ATBM_WLAN_CATEGORY_HT:
{
//add 8.5.12.2 Notify Channel Width frame format
if(ATBM_WLAN_HT_ACTION_NOTIFY_CHANWIDTH == mgmt->u.action.u.notify_chan_width.action_code)
{
atbm_uint8 prev_lock = priv->bss.ht_40M;
atbm_uint8 new_lock = 0;
if(mgmt->u.action.u.notify_chan_width.chan_width)
{
/*
*if not surport ht40, we should not receive this frame.
*/
if(priv->bss.channel_type<=ATBM_NL80211_CHAN_HT20){
wifi_printk(WIFI_DBG_ERROR, "%s:in 20M mode,we can not recive this frame,what happend",__func__);
priv->bss.ht_40M=0;
}
}
else
{
if(priv->bss.channel_type>=ATBM_NL80211_CHAN_HT40MINUS){
priv->bss.ht_40M=1;
}
}
new_lock =priv->bss.ht_40M;
if(prev_lock^new_lock)
{
atbm_queue_work(priv->hw_priv,priv->chantype_switch_work);
}
}
}
break;
#if CONFIG_IEEE80211W
case ATBM_WLAN_CATEGORY_SA_QUERY:
{
switch (mgmt->u.action.u.sa_query.action){
case ATBM_WLAN_ACTION_SA_QUERY_REQUEST:
if (priv->iftype != ATBM_NL80211_IFTYPE_STATION)
break;
atbmwifi_ieee80211_process_sa_query_req(priv, mgmt, ATBM_OS_SKB_LEN(skb));
}
}
break;
#endif
default:
break;
}
}
/*
is bssid in the scan result(hw_priv->scan_ret.info),
if in return 0;
not return 1;
*/
ATBM_BOOL atbmwifi_rx_scan_is_valid(struct atbmwifi_vif *priv,
struct atbmwifi_ieee80211_mgmt *mgmt/*atbm_uint8 * ie*/)
{
int i;
for(i=0;i<priv->scan_ret.len;i++ ){
if(!atbm_memcmp(mgmt->bssid, priv->scan_ret.info[i].BSSID,6)){
return ATBM_FALSE;
}
}
return ATBM_TRUE;
}
static ATBM_BOOL is_uapsd_supported(struct atbmwifi_ieee802_11_elems *elems)
{
atbm_uint8 qos_info;
if (elems->wmm_info && elems->wmm_info_len == 7
&& elems->wmm_info[5] == 1)
qos_info = elems->wmm_info[6];
else if (elems->wmm_param && elems->wmm_param_len == 24
&& elems->wmm_param[5] == 1)
qos_info = elems->wmm_param[6];
else
/* no valid wmm information or parameter element found */
return ATBM_FALSE;
return qos_info & ATBM_IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK;
}
atbm_void atbmwifi_ap_rx_probe_resp(struct atbmwifi_vif *priv,struct atbm_buff *skb)
{
atbm_uint8 * data = (atbm_uint8 *)ATBM_OS_SKB_DATA(skb)+offsetof(struct atbmwifi_ieee80211_mgmt, u.probe_resp.variable);
int len = ATBM_OS_SKB_LEN(skb)-offsetof(struct atbmwifi_ieee80211_mgmt, u.probe_resp.variable);
struct atbmwifi_ieee80211_mgmt *mgmt = (struct atbmwifi_ieee80211_mgmt *) ATBM_OS_SKB_DATA(skb);
atbm_uint8 *ie ;
// ATBM_BOOL privacy = 0;
struct atbmwifi_ieee802_11_elems * pelems;
struct atbmwifi_ieee80211_rx_status *hwhdr = ATBM_IEEE80211_SKB_RXCB(skb);
int ret = -1;
pelems = (struct atbmwifi_ieee802_11_elems *)atbm_kmalloc(sizeof(struct atbmwifi_ieee802_11_elems),GFP_KERNEL);
if(pelems==ATBM_NULL){
ret = -101;
goto __error;
}
ie = atbmwifi_find_ie(ATBM_WLAN_EID_SSID,data,len);
if(ie==ATBM_NULL){
ret = -100;
goto __error;
}
if(priv->scan.ApScan_in_process){
if((priv->scan_ret.info)
&&(priv->scan_no_connect)
&&(priv->scan_ret.len < MAX_SCAN_INFO_NUM)){
if(atbmwifi_rx_scan_is_valid(priv,mgmt)){
struct atbmwifi_scan_result_info *info = priv->scan_ret.info + priv->scan_ret.len;
atbm_ieee802_11_parse_elems(data,len,pelems);
if(pelems->ssid_len){
atbm_memcpy(info->ssid ,pelems->ssid,pelems->ssid_len);
}
atbm_memcpy(info->BSSID,mgmt->bssid,6);
info->ssid[pelems->ssid_len] = 0;
info->ssidlen = pelems->ssid_len;
if(pelems->ds_params)
info->channel = pelems->ds_params[0];
if(pelems->tim)
info->dtim_period = pelems->tim->dtim_period;
info->beacon_interval = mgmt->u.probe_resp.beacon_int;
info->capability = mgmt->u.probe_resp.capab_info;
info->ht = pelems->ht_cap_elem?1:(pelems->ht_info_elem?1:0);
info->wpa= pelems->wpa ?1:0;
info->rsn= pelems->rsn?1:0;
info->encrypt = (mgmt->u.probe_resp.capab_info& ATBM_WLAN_CAPABILITY_PRIVACY)?1:0;
info->rssi = hwhdr->signal;
//info->b40M= ?1:0;
priv->scan_ret.len++;
if(priv->scan_ret.len==1){
wifi_printk(WIFI_ALWAYS,"scan_no_connect: %d\n",priv->scan_no_connect);
}
wifi_printk(WIFI_ALWAYS,"SSID: %s\n",info->ssid);
wifi_printk(WIFI_ALWAYS," channel %d\n",info->channel);
wifi_printk(WIFI_ALWAYS," ht[%d] wpa[%d] rsn[%d] enc[%d]\n",info->ht,info->wpa,info->rsn,info->encrypt);
}
}
}
atbm_kfree(pelems);
return;
__error:
wifi_printk(WIFI_DBG_MSG,"%s++ ret %d\n",__FUNCTION__,ret);
atbm_kfree(pelems);
return;
}
atbm_int8 atbmwifi_get_security_mode(atbm_int32 protect, struct atbmwifi_ieee802_11_elems *elems){
//struct atbmwifi_wpa_ie_data ie;
if(!protect){
return ATBM_KEY_NONE;
}
if(elems->wpa){
if(elems->rsn){
return ATBM_KEY_MIX;
}
return ATBM_KEY_WPA;
}
if(elems->rsn){
return ATBM_KEY_WPA2;
}
return ATBM_KEY_WEP;
}
atbm_void atbmwifi_rx_probe_resp(struct atbmwifi_vif *priv,struct atbm_buff *skb)
{
//struct atbmwifi_common *hw_priv = _atbmwifi_vifpriv_to_hwpriv(priv);
atbm_uint8 * data = (atbm_uint8 *)ATBM_OS_SKB_DATA(skb)+offsetof(struct atbmwifi_ieee80211_mgmt, u.probe_resp.variable);
int len = ATBM_OS_SKB_LEN(skb)-offsetof(struct atbmwifi_ieee80211_mgmt, u.probe_resp.variable);
struct atbmwifi_ieee80211_mgmt *mgmt = (struct atbmwifi_ieee80211_mgmt *) ATBM_OS_SKB_DATA(skb);
#if CONFIG_WPS
struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)priv->appdata;
struct wps_parse_attr *attr = NULL;
#endif
atbm_uint8 *ie ;
ATBM_BOOL privacy = 0;
struct atbmwifi_ieee802_11_elems * pelems;
struct atbmwifi_ieee80211_rx_status *hwhdr = ATBM_IEEE80211_SKB_RXCB(skb);
int ret = -1;
pelems = (struct atbmwifi_ieee802_11_elems *)atbm_kmalloc(sizeof(struct atbmwifi_ieee802_11_elems),GFP_KERNEL);
if(pelems==ATBM_NULL){
ret = -101;
goto __error;
}
ie = atbmwifi_find_ie(ATBM_WLAN_EID_SSID,data,len);
if(ie==ATBM_NULL){
ret = -100;
goto __error;
}
//in scan process we get scan info
//in no scan process we check info
if(priv->scan.in_progress||priv->scan.ApScan_in_process){
#if CONFIG_P2P
if(priv->p2p_scan){
atbm_p2p_prash_ie(priv, mgmt->bssid, hwhdr->freq, hwhdr->signal, data, len);
}else
#endif
#if CONFIG_WPS
if(wpa_s->wps_mode != WPS_MODE_UNKNOWN){
attr = (struct wps_parse_attr *)atbm_kmalloc(sizeof(*attr),GFP_KERNEL);
if(attr == ATBM_NULL){
ret = -200;
goto __error;
}
atbm_ieee802_11_parse_elems(data, len, pelems);
if(wps_parse_msg_attr(pelems->wps_ie, pelems->wps_ie_len, attr)){
wifi_printk(WIFI_DBG_ERROR, "wps parse failed.\n");
}
#if CONFIG_P2P
if(priv->p2p_join){
if(priv->ssid_length != pelems->ssid_len ||
atbm_memcmp(priv->ssid, pelems->ssid, priv->ssid_length)){
ret = -200;
goto __error;
}
}
#endif
if(check_valid_wps_ap(priv, attr, wpa_s->own_addr)){
// if((attr->selected_registrar) &&
// (*(attr->selected_registrar) == 1) &&
// (attr->primary_dev_type != ATBM_NULL)){
priv->bss.sta_priv.capability = mgmt->u.probe_resp.capab_info;
priv->bss.sta_priv.beacon_interval = mgmt->u.probe_resp.beacon_int;
if(pelems->tim){
priv->bss.dtim_period = pelems->tim->dtim_period;
}else{
priv->bss.dtim_period = 0;
}
if(pelems->erp_info){
priv->bss.sta_priv.short_preamble = (pelems->erp_info[0] & ATBM_WLAN_ERP_BARKER_PREAMBLE) == 0;
}
priv->bss.sta_priv.wpa = (pelems->rsn_len || pelems->wpa_len) ? 1 : 0;
priv->bss.sta_priv.ht = (pelems->ht_info_elem || pelems->ht_cap_elem) ? 1 : 0;
priv->bss.sta_priv.rate.ht = priv->bss.sta_priv.ht;
if(pelems->ht_cap_elem){
atbmwifi_ieee80211_ht_cap_ie_to_sta_ht_cap(&atbmwifi_band_2ghz, pelems->ht_cap_elem, &priv->bss.sta_priv.rate.ht_cap);
}
priv->bss.sta_priv.rate.basic_rates = 0;
priv->bss.sta_priv.rate.support_rates = 0;
atbmwifi_ieee80211_get_sta_rateinfo(&priv->bss.sta_priv.rate, &atbmwifi_band_2ghz,
pelems->supp_rates, pelems->supp_rates_len);
atbmwifi_ieee80211_get_sta_rateinfo(&priv->bss.sta_priv.rate, &atbmwifi_band_2ghz,
pelems->ext_supp_rates, pelems->ext_supp_rates_len);
wifi_printk(WIFI_WPS, "priv->bss.sta_priv.rate support_rates(%x) %x \n", priv->bss.sta_priv.rate.support_rates, priv->bss.sta_priv.rate.basic_rates);
wifi_printk(WIFI_WPS, "probe_resp wpa_len(%d), wpa(%d) \n", pelems->wpa_len, priv->bss.sta_priv.wpa);
//free the element ie
if(priv->bss.information_elements &&
(priv->bss.len_information_elements < len)){
atbm_kfree(priv->bss.information_elements);
priv->bss.information_elements = ATBM_NULL;
}
if(priv->bss.information_elements == ATBM_NULL){
priv->bss.information_elements = (atbm_uint8 *)atbm_kmalloc(len, GFP_KERNEL);
if(priv->bss.information_elements == ATBM_NULL){
ret = -205;
goto __error;
}
}
atbm_memcpy(priv->bss.information_elements, data, len);
priv->bss.len_information_elements = len;
if((atbm_memcmp(priv->bssid, mgmt->bssid, ATBM_ETH_ALEN) != 0)
|| (wpa_s->wps_ap_cnt == 0)){
wpa_s->wps_ap_cnt++;
}
atbm_memcpy(priv->daddr, mgmt->bssid, 6);
atbm_memcpy(priv->bssid, mgmt->bssid, 6);
atbm_memcpy(priv->ssid, pelems->ssid, pelems->ssid_len);
priv->ssid[pelems->ssid_len] = '\0';
priv->ssid_length = pelems->ssid_len;
atbm_memcpy(priv->config.ssid, pelems->ssid, pelems->ssid_len);
priv->config.ssid_len = pelems->ssid_len;
priv->scan.status = 1;
wifi_printk(WIFI_WPS, "Found wps AP ssid=%s "MACSTR"<===\n", (char*)priv->ssid, MAC2STR(priv->bssid));
}
if(attr != ATBM_NULL){
atbm_kfree(attr);
}
//goto out;
}
#endif
if((priv->scan_ret.info)
&&(priv->scan_no_connect)
&&(priv->scan_ret.len < MAX_SCAN_INFO_NUM)){
if(atbmwifi_rx_scan_is_valid(priv,mgmt)){
struct atbmwifi_scan_result_info *info = priv->scan_ret.info + priv->scan_ret.len;
atbm_ieee802_11_parse_elems(data,len,pelems);
atbm_memcpy(info->ssid ,pelems->ssid,pelems->ssid_len);
atbm_memcpy(info->BSSID,mgmt->bssid,6);
info->ssid[pelems->ssid_len] = 0;
info->ssidlen = pelems->ssid_len;
if( pelems->ds_params!=ATBM_NULL){
priv->bss.channel_num = pelems->ds_params[0];
}else{
priv->bss.channel_num = atbmwifi_ieee80211_frequency_to_channel(hwhdr->freq);
}
#if CONFIG_5G_SUPPORT
if(priv->scan.cur_scan_req && priv->scan.cur_scan_req->req_type == ATBM_SCAN_5G_PASSAVE_DFS){
atbm_set_bit(info->channel, priv->scan.dfs_map);
}
#endif
if(pelems->tim)
info->dtim_period = pelems->tim->dtim_period;
info->beacon_interval = mgmt->u.probe_resp.beacon_int;
info->capability = mgmt->u.probe_resp.capab_info;
info->ht = pelems->ht_cap_elem?1:(pelems->ht_info_elem?1:0);
info->wpa= pelems->wpa ?1:0;
info->rsn= pelems->rsn?1:0;
info->encrypt = (mgmt->u.probe_resp.capab_info& ATBM_WLAN_CAPABILITY_PRIVACY)?1:0;
info->rssi = hwhdr->signal;
info->channel = priv->bss.channel_num;
info->security = atbmwifi_get_security_mode(info->encrypt, pelems);
//info->b40M= ?1:0;
priv->scan_ret.len++;
if(priv->scan_ret.len==1){
wifi_printk(WIFI_ALWAYS,"scan_no_connect: %d\n",priv->scan_no_connect);
}
//wifi_printk(WIFI_ALWAYS,"SSID: %s\n",info->ssid);
//wifi_printk(WIFI_ALWAYS," channel %d\n",info->channel);
//wifi_printk(WIFI_ALWAYS," ht[%d] wpa[%d] rsn[%d] enc[%d] security[%d]\n",info->ht,info->wpa,info->rsn,info->encrypt,info->security);
}
goto out;
}
if(!priv->scan_no_connect
&&(priv->config.ssid_len != 0)
&&(ie[1] == priv->config.ssid_len)
&&(atbm_memcmp(&ie[2],priv->config.ssid,priv->config.ssid_len)==0)){
/*||
(!priv->connect_ok
&&(priv->config.ssid_len)
&&(ie[1] == priv->config.ssid_len)
&&(atbm_memcmp(&ie[2],priv->config.ssid,priv->config.ssid_len)==0))){*/
if(atbm_is_valid_ether_addr(priv->config.bssid)
&& atbm_memcmp(mgmt->bssid,priv->config.bssid,6)){
goto out;
}
ret = 0;
atbm_ieee802_11_parse_elems(data,len,pelems);
atbm_memcpy(priv->daddr,mgmt->bssid,6);
atbm_memcpy(priv->bssid,mgmt->bssid,6);
priv->bss.sta_priv.capability = mgmt->u.probe_resp.capab_info;
privacy = !!(priv->bss.sta_priv.capability & ATBM_WLAN_CAPABILITY_PRIVACY);
#ifdef STA_KEY_TYPE_SET
if(privacy != config->privacy){
ret = -2;
wifi_printk(WIFI_ALWAYS,"privacy miss:\n");
goto __error;
}
if(((config->wpa == ATBM_WPA_PROTO_RSN) ||(config->wpa == ATBM_WPA_PROTO_WPA))
&&(pelems->rsn_len + pelems->wpa_len ==0)){
ret = -3;
wifi_printk(WIFI_DBG_ERROR,"%s key_mgmt %d,rsn_len %d,wpa_len %d\n",__FUNCTION__,config->wpa,pelems->rsn_len
,pelems->wpa_len);
goto __error;
}
#endif
priv->bss.sta_priv.beacon_interval = mgmt->u.probe_resp.beacon_int;
//ie = atbmwifi_find_ie(ATBM_WLAN_EID_DS_PARAMS,data,len);
if( pelems->ds_params!=ATBM_NULL){
priv->bss.channel_num = pelems->ds_params[0];
}else{
priv->bss.channel_num = atbmwifi_ieee80211_frequency_to_channel(hwhdr->freq);
}
#if CONFIG_5G_SUPPORT
if(priv->bss.channel_num >= 36)
priv->bss.sta_priv.band = ATBM_IEEE80211_BAND_5GHZ;
else
#endif
priv->bss.sta_priv.band = ATBM_IEEE80211_BAND_2GHZ;
atbm_memcpy(priv->bss.bssid, mgmt->bssid,6);
if(pelems->tim)
priv->bss.dtim_period = pelems->tim->dtim_period;
else
priv->bss.dtim_period = 0;
if(pelems->erp_info)
priv->bss.sta_priv.short_preamble = (pelems->erp_info[0]& ATBM_WLAN_ERP_BARKER_PREAMBLE) == 0;
priv->bss.rssi = hwhdr->signal;
/*
if (erp_valid) {
use_protection = (erp & WLAN_ERP_USE_PROTECTION) != 0;
use_short_preamble = (erp & ATBM_WLAN_ERP_BARKER_PREAMBLE) == 0;
} else {
use_protection = ATBM_FALSE;
use_short_preamble = !!(capab & ATBM_WLAN_CAPABILITY_SHORT_PREAMBLE);
}
*/
priv->bss.sta_priv.wpa = !!(pelems->rsn_len || pelems->wpa_len);
#if CONFIG_WPS
priv->bss.sta_priv.wps = pelems->wps_ie_len != 0;
#endif
priv->bss.privacy = privacy;
//priv->bss.sta_priv.wps = pelems->wps_ie_len ? 1:0;
//priv->bss.sta_priv.p2p = pelems->p2p_ie_len ? 1:0;
//priv->bss.sta_priv.bcm_ap = elems->bcm_ie_len ? 1:0;
priv->bss.sta_priv.ht = (pelems->ht_info_elem || pelems->ht_cap_elem)? 1:0;
priv->bss.sta_priv.rate.ht = priv->bss.sta_priv.ht;
priv->bss.sta_priv.wmm_used = (pelems->wmm_param || pelems->wmm_info) ? 1 : 0;
priv->bss.sta_priv.uapsd_supported = is_uapsd_supported(pelems);
if(pelems->ht_cap_elem){
atbmwifi_ieee80211_ht_cap_ie_to_sta_ht_cap(priv->hw_priv->bands[priv->bss.sta_priv.band],
pelems->ht_cap_elem,
&priv->bss.sta_priv.rate.ht_cap);
}
atbmwifi_ieee80211_get_sta_rateinfo(&priv->bss.sta_priv.rate,priv->hw_priv->bands[priv->bss.sta_priv.band],pelems->supp_rates, pelems->supp_rates_len);
atbmwifi_ieee80211_get_sta_rateinfo(&priv->bss.sta_priv.rate,priv->hw_priv->bands[priv->bss.sta_priv.band],pelems->ext_supp_rates, pelems->ext_supp_rates_len);
//wifi_printk(WIFI_SCAN,"probe_resp wpa_len(%d),wpa(%d) \n",pelems->wpa_len,priv->bss.sta_priv.wpa);
//free the element ie
if(priv->bss.information_elements &&
(priv->bss.len_information_elements < len)){
atbm_kfree(priv->bss.information_elements);
priv->bss.information_elements = ATBM_NULL;
}
if(priv->bss.information_elements == ATBM_NULL){
priv->bss.information_elements = (atbm_uint8 *)atbm_kmalloc(len,GFP_KERNEL);
if(priv->bss.information_elements==ATBM_NULL)
{
ret = -5;
wifi_printk(WIFI_ALWAYS,"information_elements miss:\n");
goto __error;
}
}
atbm_memcpy(priv->bss.information_elements,data,len);
priv->bss.len_information_elements = len;
priv->scan.status = ATBMWIFI_SCAN_CONNECT_AP_SUCCESS;
wifi_printk(WIFI_ALWAYS,"[atbm_wifi] connect AP have been Scanned\n");
//wifi_printk(WIFI_RATE,"support_rates %x,basic_rates %x\n",priv->bss.support_rates,priv->bss.basic_rates);
}
}
else {
//TODO add to check beacon info code,if ap beacon info change we need disconnect it
}
#if CONFIG_5G_SUPPORT
if(priv->scan.cur_scan_req && priv->scan.cur_scan_req->req_type == ATBM_SCAN_5G_PASSAVE_DFS){
ie = atbmwifi_find_ie(ATBM_WLAN_EID_DS_PARAMS,data,len);
if(ie && ie[2])
atbm_set_bit(ie[2], priv->scan.dfs_map);
else
atbm_set_bit(atbmwifi_ieee80211_frequency_to_channel(hwhdr->freq), priv->scan.dfs_map);
}
#endif
atbm_kfree(pelems);
return;
__error:
#if CONFIG_WPS
if(attr != ATBM_NULL)
atbm_kfree(attr);
#endif
wifi_printk(WIFI_DBG_MSG,"%s++ ret %d\n",__FUNCTION__,ret);
out:
atbm_kfree(pelems);
return;
}
atbm_void atbmwifi_switch_channletpye(struct atbmwifi_vif *priv,struct atbmwifi_ieee802_11_elems *elems)
{
struct atbmwifi_ieee80211_channel_sw_packed_ie sw_packed_ie;
if(elems->ch_switch_elem)
{
sw_packed_ie.chan_sw_ie = (struct atbmwifi_ieee80211_channel_sw_ie *)elems->ch_switch_elem;
atbm_ieee80211_sta_process_chanswitch(priv,
&priv->bss,
&sw_packed_ie,
0);
}
if(elems->secondary_ch_elem){
sw_packed_ie.sec_chan_offs_ie= (struct atbmwifi_ieee80211_sec_chan_offs_ie *)elems->secondary_ch_elem;
atbm_ieee80211_sta_process_chanswitch(priv,
&priv->bss,
&sw_packed_ie,
0);
}
if(elems->extended_ch_switch_elem)
{
sw_packed_ie.ex_chan_sw_ie= (struct atbmwifi_ieee80211_ext_chansw_ie *)elems->extended_ch_switch_elem;
atbm_ieee80211_sta_process_chanswitch(priv,
&priv->bss,
&sw_packed_ie,
0);
}
}
#if SUPPORT_LIGHT_SLEEP
//Probe response not indicate DTIM period, so it should be updated after connected..
atbm_void atbmwifi_rx_beacon(struct atbmwifi_vif *priv,struct atbm_buff *skb)
{
int baselen, len;
struct atbmwifi_ieee80211_mgmt *mgmt;
struct atbmwifi_ieee802_11_elems elems;
if(priv->assoc_ok ==0)
return;
elems.tim = ATBM_NULL;
if(!priv->bss.dtim_period){
len = ATBM_OS_SKB_LEN(skb)-offsetof(struct atbmwifi_ieee80211_mgmt, u.probe_resp.variable);
mgmt = (struct atbmwifi_ieee80211_mgmt *) ATBM_OS_SKB_DATA(skb);
baselen = (atbm_uint8 *) mgmt->u.beacon.variable - (atbm_uint8 *) mgmt;
atbm_ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
if(elems.tim){
wifi_printk(WIFI_DBG_ERROR, "beacon dtim_period:%d beacon_interval:%d\n", priv->bss.dtim_period, priv->bss.sta_priv.beacon_interval);
wsm_set_beacon_wakeup_period(_atbmwifi_vifpriv_to_hwpriv(priv),
priv->bss.sta_priv.beacon_interval * priv->bss.dtim_period >
MAX_BEACON_SKIP_TIME_MS ? 1 :
priv->bss.dtim_period, priv->bss.sta_priv.beacon_interval, priv->if_id);
}
}
}
#else
atbm_void atbmwifi_rx_beacon(struct atbmwifi_vif *priv,struct atbm_buff *skb)
{
// struct atbmwifi_common *hw_priv = _atbmwifi_vifpriv_to_hwpriv(priv);
struct atbmwifi_cfg *config = atbmwifi_get_config(priv);
struct atbmwifi_ieee802_11_elems elems;
int erp_valid =ATBM_FALSE;
atbm_uint8 erp_value = 0;
int baselen;
int changed = 0;
int len = ATBM_OS_SKB_LEN(skb)-offsetof(struct atbmwifi_ieee80211_mgmt, u.probe_resp.variable);
struct atbmwifi_ieee80211_mgmt *mgmt = (struct atbmwifi_ieee80211_mgmt *) ATBM_OS_SKB_DATA(skb);
/* Process beacon from the current BSS */
baselen = (atbm_uint8 *) mgmt->u.beacon.variable - (atbm_uint8 *) mgmt;
if(priv->assoc_ok == 0){
return ;
}else{
atbm_ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
/*parse 40M ies*/
atbmwifi_switch_channletpye(priv,&elems);
/*parse wmm param*/
if (elems.wmm_param){
atbmwifi_ieee80211_sta_wmm_params(priv,elems.wmm_param,elems.wmm_param_len);
}
/*parse ps mode */
//
if (elems.erp_info && elems.erp_info_len >= 1) {
erp_valid = ATBM_TRUE;
erp_value = elems.erp_info[0];
} else {
erp_valid = ATBM_FALSE;
}
changed |= atbm_ieee80211_handle_bss_capability(priv,atbm_le16_to_cpu(mgmt->u.beacon.capab_info),erp_valid, erp_value);
if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
!(config->flags & ATBM_IEEE80211_STA_DISABLE_11N)) {
struct atbmwifi_ieee80211_supported_band *sband;
atbm_uint16 ap_ht_cap_flags;
sband = priv->hw_priv->bands[priv->bss.sta_priv.band];
atbmwifi_ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
elems.ht_cap_elem, &priv->bss.sta_priv.rate.ht_cap);
ap_ht_cap_flags = priv->bss.sta_priv.rate.ht_cap.cap;
changed |= atbmwifi_ieee80211_enable_ht(elems.ht_info_elem,
priv, ap_ht_cap_flags, ATBM_TRUE);
}
/* Note: country IE parsing is done for us by cfg80211 */
if (elems.country_elem) {
///TODO;;
}
atbmwifi_ieee80211_bss_info_change_notify(priv, changed);
}
return;
}
#endif
atbm_void atbmwifi_rx_sta_mgmtframe(struct atbmwifi_vif *priv,struct atbm_buff *skb)
{
struct atbmwifi_ieee80211_hdr * hdr = (struct atbmwifi_ieee80211_hdr *) ATBM_OS_SKB_DATA(skb);
atbm_uint16 stype = hdr->frame_control & atbm_cpu_to_le16(ATBM_IEEE80211_FCTL_STYPE);
int ret= 0;
wifi_printk(WIFI_DBG_MSG,"atbmwifi_rx_sta_mgmtframe++ stype %x\n",stype);
switch(stype){
case ATBM_IEEE80211_STYPE_BEACON:
#if SUPPORT_LIGHT_SLEEP
atbmwifi_rx_beacon(priv,skb);
#else
//atbmwifi_rx_beacon(priv,skb);
#endif
case ATBM_IEEE80211_STYPE_PROBE_RESP:
atbmwifi_rx_probe_resp(priv,skb);
break;
case ATBM_IEEE80211_STYPE_AUTH:
{
int res;
res = atbmwifi_rx_authen(priv,skb);
if(res == ATBM_WLAN_STATUS_SUCCESS_NEXTSETP){
//send assoc req
atbmwifi_event_uplayer(priv,ATBM_WIFI_AUTH_EVENT,(atbm_uint8*)0);
}
else if(res>0)
{
wifi_printk(WIFI_CONNECT,"[sta]:rx_sta_mgm AUTH fail just DEAUTH\n");
atbmwifi_event_uplayer(priv,ATBM_WIFI_DEAUTH_EVENT,(atbm_uint8*)&res);
}
else {
//drop
}
}
break;
case ATBM_IEEE80211_STYPE_ASSOC_RESP:
case ATBM_IEEE80211_STYPE_REASSOC_RESP:
ret= atbmwifi_rx_assoc_rsp(priv,skb);
if(!ret)
{
atbmwifi_assoc_success(priv,skb);
}
else
{
priv->assoc_ok = 0;
priv->connect_ok = 0;
atbmwifi_event_uplayer(priv,ATBM_WIFI_DEASSOC_EVENT,0);
if(priv->auto_connect_when_lost){
atbmwifi_autoconnect(priv, 0);
}
}
break;
case ATBM_IEEE80211_STYPE_DEAUTH:
case ATBM_IEEE80211_STYPE_DISASSOC:
if(priv->assoc_ok || priv->join_status == ATBMWIFI__JOIN_STATUS_STA){
wifi_printk(WIFI_CONNECT,"[sta]:rx_sta_mgm DEAUTH\n");
wifi_printk(WIFI_ALWAYS,"atbmwifi_rx_sta_mgmtframe() ---deauth\n");
#if FAST_CONNECT_MODE
if(priv->fast_channel){
priv->fast_connect = 1;
}
#endif
#if FAST_CONNECT_NO_SCAN
if(priv->auth_retry && !priv->assoc_ok){
priv->auth_retry = 0;
atbmwifi_wpa_event_queue((atbm_void*)priv,ATBM_NULL,ATBM_NULL,WPA_EVENT__SUPPLICANT_AUTHEN,ATBM_WPA_EVENT_NOACK);
break;
}
#endif
sta_deauth(priv);
}
//atbmwifi_event_uplayer(priv,ATBM_WIFI_DEAUTH_EVENT,0);
break;
#if CONFIG_P2P
case ATBM_IEEE80211_STYPE_PROBE_REQ:
{
struct atbmwifi_ieee80211_mgmt *mgmt = (struct atbmwifi_ieee80211_mgmt *)ATBM_OS_SKB_DATA(skb);
struct atbmwifi_ieee80211_rx_status *hw_hdr = ATBM_IEEE80211_SKB_RXCB(skb);
atbm_uint8 *data = (atbm_uint8 *)ATBM_OS_SKB_DATA(skb) + offsetof(struct atbmwifi_ieee80211_mgmt, u.probe_req.variable);
int len = ATBM_OS_SKB_LEN(skb) - offsetof(struct atbmwifi_ieee80211_mgmt, u.probe_req.variable);
atbm_p2p_probe_req_rx(priv, mgmt->sa, mgmt->da, mgmt->bssid,
data, len, hw_hdr->freq, (int)hw_hdr->signal);
}
break;
#endif
default:
break;
}
}
#if CONFIG_SAE
#define WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER \
"CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER "
static int sme_sae_auth(struct wpa_supplicant *wpa_s, atbm_uint16 auth_transaction,
atbm_uint16 status_code, const atbm_uint8 *data, atbm_size_t len,
const atbm_uint8 *sa)
{
int *groups;
wpa_printf(MSG_DEBUG, "SME: SAE authentication transaction %u "
"status code %u", auth_transaction, status_code);
if (auth_transaction == 1 &&
status_code == ATBM_WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
wpa_s->sae.state == SAE_COMMITTED){
int default_groups[] = { 19, 20, 21, 0 };
atbm_uint16 group;
groups = wpa_s->sae_groups;
if (!groups || groups[0] <= 0)
groups = default_groups;
if (len < sizeof(atbm_uint16)) {
wpa_printf(MSG_DEBUG,
"SME: Too short SAE anti-clogging token request");
return -1;
}
group = ATBM_WPA_GET_LE16(data);
wpa_printf(MSG_DEBUG,
"SME: SAE anti-clogging token requested (group %u)",
group);
if (sae_group_allowed(&wpa_s->sae, groups, group) !=
ATBM_WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_ERROR,
"SME: SAE group %u of anti-clogging request is invalid",
group);
return -1;
}
wpabuf_free(wpa_s->sae_token);
wpa_s->sae_token = wpabuf_alloc_copy(data + sizeof(atbm_uint16),
len - sizeof(atbm_uint16));
// sme_send_authentication(wpa_s, wpa_s->current_bss,
// wpa_s->current_ssid, 2);
wpa_s->sae_start = 2;
wpa_prepare_auth(wpa_s->priv);
}
if (auth_transaction == 1 &&
status_code == ATBM_WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
wpa_s->sae.state == SAE_COMMITTED) {
wpa_printf(MSG_DEBUG, "SME: SAE group not supported");
wpa_s->sae_group_index++;
if (sme_set_sae_group(wpa_s) < 0)
return -1; /* no other groups enabled */
wpa_printf(MSG_DEBUG, "SME: Try next enabled SAE group");
// sme_send_authentication(wpa_s, wpa_s->current_bss,
// wpa_s->current_ssid, 1);
wpa_s->sae_start = 1;
wpa_prepare_auth(wpa_s->priv);
}
if (auth_transaction == 1 &&
status_code == ATBM_WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
const atbm_uint8 *bssid = sa ? sa : wpa_s->priv->bss.bssid;
wpa_printf(MSG_INFO,
WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER MACSTR,
MAC2STR(bssid));
return -1;
}
if (status_code != ATBM_WLAN_STATUS_SUCCESS)
return -1;
if (auth_transaction == 1) {
atbm_uint16 res;
int default_groups[] = { 19, 20, 21, 0 };
groups = wpa_s->sae_groups;
if (!groups || groups[0] <= 0)
groups = default_groups;
wpa_printf(MSG_DEBUG, "SME SAE commit");
// if (wpa_s->current_bss == NULL ||
// wpa_s->current_ssid == NULL)
// return -1;
if (wpa_s->sae.state != SAE_COMMITTED)
return -1;
if (groups && groups[0] <= 0)
groups = NULL;
res = sae_parse_commit(&wpa_s->sae, data, len, NULL, NULL,
groups);
if (res == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message due to reflection attack");
return 0;
}
if (res != ATBM_WLAN_STATUS_SUCCESS)
return -1;
if (sae_process_commit(&wpa_s->sae) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Failed to process peer "
"commit");
return -1;
}
wpabuf_free(wpa_s->sae_token);
wpa_s->sae_token = NULL;
wpa_s->sae_start = 0;
// sme_send_authentication(wpa_s, wpa_s->current_bss,
// wpa_s->current_ssid, 0);
wpa_prepare_auth(wpa_s->priv);
return 0;
} else if (auth_transaction == 2) {
wpa_printf(MSG_DEBUG, "SME SAE confirm");
if (wpa_s->sae.state != SAE_CONFIRMED)
return -1;
if (sae_check_confirm(&wpa_s->sae, data, len) < 0)
return -1;
wpa_s->sae.state = SAE_ACCEPTED;
sae_clear_temp_data(&wpa_s->sae);
return 1;
}
return -1;
}
#endif
int atbmwifi_rx_authen(struct atbmwifi_vif *priv,struct atbm_buff *skb)
{
atbm_uint16 auth_alg, auth_transaction, status_code=-1;
atbm_uint16 fc;
struct atbmwifi_common *hw_priv = _atbmwifi_vifpriv_to_hwpriv(priv);
// atbm_uint8 * data = (atbm_uint8 *)OS_SKB_DATA(skb)+offsetof(struct atbmwifi_ieee80211_mgmt, u.probe_resp.variable);
int len = ATBM_OS_SKB_LEN(skb)-offsetof(struct atbmwifi_ieee80211_mgmt, u.auth.variable);
struct atbmwifi_ieee80211_mgmt *mgmt = (struct atbmwifi_ieee80211_mgmt *) ATBM_OS_SKB_DATA(skb);
// atbm_uint16 resp = ATBM_WLAN_STATUS_SUCCESS;
struct atbmwifi_cfg *config = atbmwifi_get_config(priv);
atbm_uint8 *resp_ies = ATBM_NULL;
atbm_size_t resp_ies_len = 0;
struct atbm_buff *skb_tx = ATBM_NULL;
#if CONFIG_SAE
struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)priv->appdata;
#endif
auth_alg = mgmt->u.auth.auth_alg;
auth_transaction = mgmt->u.auth.auth_transaction;
status_code = mgmt->u.auth.status_code;
fc = mgmt->frame_control;
if(status_code != ATBM_WLAN_STATUS_SUCCESS)
{
return status_code;
}
if(auth_alg != config->auth_alg)
{
return ATBM_WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
}
if(auth_alg == ATBM_WLAN_AUTH_OPEN)
{
return ATBM_WLAN_STATUS_SUCCESS_NEXTSETP;
}
else if((auth_alg == ATBM_WLAN_AUTH_SHARED_KEY))
{
switch(auth_transaction)
{
case 1:
return -2;
case 2:
//if(priv->connect_state != WAIT_AUTH_4)
{
wifi_printk(WIFI_DBG_MSG,"atbmwifi_rx_sta_mgmtframe++:authen len(%d) \n",len);
if ((len >= 2 + ATBM_WLAN_AUTH_CHALLENGE_LEN) &&
(mgmt->u.auth.variable[0] == ATBM_WLAN_EID_CHALLENGE) &&
(mgmt->u.auth.variable[1] == ATBM_WLAN_AUTH_CHALLENGE_LEN))
{
resp_ies = (atbm_uint8 *)atbm_kmalloc(2 + ATBM_WLAN_AUTH_CHALLENGE_LEN,GFP_KERNEL);
if(resp_ies == ATBM_NULL)
{
status_code = ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE;
return status_code;
}
resp_ies[0] = ATBM_WLAN_EID_CHALLENGE;
resp_ies[1] = ATBM_WLAN_AUTH_CHALLENGE_LEN;
atbm_memcpy(resp_ies + 2, &mgmt->u.auth.variable[2],
ATBM_WLAN_AUTH_CHALLENGE_LEN);
resp_ies_len = 2 + ATBM_WLAN_AUTH_CHALLENGE_LEN;
wifi_printk(WIFI_DBG_MSG,"atbmwifi_rx_sta_mgmtframe++:challenge \n");
priv->connect_state = WAIT_AUTH_4;
}
break;
}
case 4:
if(priv->connect_state == WAIT_AUTH_4)
return ATBM_WLAN_STATUS_SUCCESS_NEXTSETP;
else
return ATBM_WLAN_STATUS_JUST_DROP;
}
}
#if CONFIG_SAE
else if((auth_alg == ATBM_WLAN_AUTH_SAE)){
int res;
res = sme_sae_auth(wpa_s, mgmt->u.auth.auth_transaction,
mgmt->u.auth.status_code, mgmt->u.auth.variable,
len, ATBM_NULL);
if (res < 0) {
wpa_deauthen(priv);
//fixme:reconnect here
if(priv->auto_connect_when_lost){
atbmwifi_autoconnect(priv, priv->scan_expire);
}
}
if (res != 1)
return ATBM_WLAN_STATUS_JUST_DROP;
wpa_printf(MSG_DEBUG, "SME: SAE completed - setting PMK for "
"4-way handshake");
wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sae.pmk, ATBM_PMK_LEN,
wpa_s->sae.pmkid, wpa_s->priv->bss.bssid);
wpa_s->sae_pmk_set = 1;
return ATBM_WLAN_STATUS_SUCCESS_NEXTSETP;
}
#endif
else {
return ATBM_WLAN_STATUS_JUST_DROP;
}
if(priv->extra_ie){
atbm_kfree(priv->extra_ie );
}
priv->extra_ie = resp_ies;
priv->extra_ie_len = resp_ies_len;
skb_tx = atbmwifi_ieee80211_send_auth(priv,auth_transaction+1,auth_alg,mgmt->sa,priv->bssid,0);
atbmwifi_tx(hw_priv,skb_tx,priv);
priv->extra_ie = ATBM_NULL;
priv->extra_ie_len = 0;
atbm_kfree(resp_ies);
return status_code;
}
int atbmwifi_ieee80211_build_preq_ies(struct atbmwifi_vif *priv,atbm_uint8 *buffer,
const atbm_uint8 *ie, atbm_size_t ie_len,atbm_uint8 channel)
{
atbm_uint8 *pos;
atbm_uint8 band;
pos = buffer;
#if CONFIG_5G_SUPPORT
if(priv->scan.cur_scan_req && priv->scan.cur_scan_req->scan.band == WSM_PHY_BAND_5G)
band = WSM_PHY_BAND_5G;
else
#endif
band = WSM_PHY_BAND_2_4G;
/* SSID */
*pos++ = ATBM_WLAN_EID_SSID;
*pos++ = 0;
//*pos++ = priv->ssid_length;
//atbm_memcpy(pos,priv->ssid, priv->ssid_length);
//pos += priv->ssid_length;
/* Supported rates */
/* Extended supported rates */
pos = atbmwifi_ieee80211_add_rate_ie(pos ,(band==WSM_PHY_BAND_5G),~0);
if (channel ) {
*pos++ = ATBM_WLAN_EID_DS_PARAMS;
*pos++ = 1;
*pos++ = channel;
}
pos = atbmwifi_ieee80211_add_ht_ie(priv,priv->hw_priv->bands[band],pos);
#if CONFIG_WPS
pos = atbmwifi_ieee80211_add_preq_wps_ie(priv, pos);
#endif
#if CONFIG_P2P
if(priv->p2p_scan){
pos = atbm_p2p_add_scan_ie(priv, pos);
}else if(priv->p2p_join){
if(priv->p2p_assoc_req_ie && priv->p2p_assoc_req_ie_len){
atbm_memcpy(pos, priv->p2p_assoc_req_ie, priv->p2p_assoc_req_ie_len);
pos += priv->p2p_assoc_req_ie_len;
}
}
#endif
/* add any remaining custom IEs */
if (ie && ie_len) {
atbm_memcpy(pos, ie ,ie_len);
pos += ie_len;
}
return pos - buffer;
}
struct atbm_buff *atbmwifi_ieee80211_build_probe_req(struct atbmwifi_vif *priv,
atbm_uint8 *dst, const atbm_uint8 *ie, atbm_size_t ie_len)
{
struct atbm_buff *skb=ATBM_NULL;
struct atbmwifi_ieee80211_mgmt *mgmt;
atbm_size_t buf_len;
atbm_uint8 *buf;
struct atbmwifi_ieee80211_hdr_3addr *hdr;
skb = atbm_dev_alloc_skb(1024);
if (!skb)
return ATBM_NULL;
hdr = (struct atbmwifi_ieee80211_hdr_3addr *) atbm_skb_put(skb, sizeof(*hdr));
atbm_memset(hdr, 0, sizeof(*hdr));
hdr->frame_control = atbm_cpu_to_le16(ATBM_IEEE80211_FTYPE_MGMT |
ATBM_IEEE80211_STYPE_PROBE_REQ);
atbm_memcpy(hdr->addr2, priv->mac_addr, ATBM_ETH_ALEN);
hdr->seq_ctrl = 0;
hdr->duration_id = 0;
if (dst) {
mgmt = (struct atbmwifi_ieee80211_mgmt *) hdr;
atbm_memcpy(mgmt->da, dst, ATBM_ETH_ALEN);
atbm_memcpy(mgmt->bssid, dst, ATBM_ETH_ALEN);
}
else {
atbm_memset(hdr->addr1, 0xff, ATBM_ETH_ALEN);
atbm_memset(hdr->addr3, 0xff, ATBM_ETH_ALEN);
}
buf = (atbm_uint8 *)(hdr + 1);
buf_len = atbmwifi_ieee80211_build_preq_ies(priv, buf, ie, ie_len,
priv->bss.channel_num);
atbm_skb_put(skb, buf_len);
ATBM_IEEE80211_SKB_TXCB(skb)->flags = ATBM_IEEE80211_TX_INTFL_DONT_ENCRYPT;
return skb;
}
struct atbm_buff * atbmwifi_ieee80211_send_probe_req(struct atbmwifi_vif *priv, atbm_uint8 *dst,
const atbm_uint8 *ie, atbm_size_t ie_len, ATBM_BOOL no_cck)
{
struct atbm_buff *skb;
skb = atbmwifi_ieee80211_build_probe_req(priv, dst,ie, ie_len);
if (skb) {
if (no_cck)
ATBM_IEEE80211_SKB_TXCB(skb)->flags |=
ATBM_IEEE80211_TX_CTL_NO_CCK_RATE;
}
#if CONFIG_P2P
if(priv->p2pdata){
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_CTL_NO_CCK_RATE;
}
#endif
return skb;
}
struct atbm_buff * atbmwifi_ieee80211_send_assoc_req(struct atbmwifi_vif *priv)
{
//struct atbmwifi_common * hw_priv = priv->hw_priv;
struct atbm_buff *skb;
struct atbmwifi_ieee80211_mgmt *mgmt;
struct atbmwifi_cfg *config = atbmwifi_get_config(priv);
atbm_uint8 *pos;
//atbm_size_t offset = 0, noffset;
atbm_uint16 capab;
atbm_uint32 rates = 0,rates_len;
#ifdef CONFIG_WPS
struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)priv->appdata;
#endif
/*
* In case AP not provide any supported rates information
* before association, we send information element(s) with
* all rates that we support.
*/
rates = priv->bss.sta_priv.rate.support_rates;
if(rates < 0xf)
rates = 0xffffffff;
rates_len = atbmwifi_g_rates_size;
skb = atbm_dev_alloc_skb(
sizeof(*mgmt) + /* bit too much but doesn't matter */
2 + priv->ssid_length+ /* SSID */
4 + rates_len + /* (extended) rates */
4 + /* power capability */
2 + /* supported channels */
2 + sizeof(struct atbmwifi_ieee80211_ht_cap) + /* HT */
500 + /* wps IE*/
priv->extra_ie_len+ /* extra IEs */
9);/* WMM */
if (!skb)
return ATBM_NULL;
capab = ATBM_WLAN_CAPABILITY_ESS;
capab |= ATBM_WLAN_CAPABILITY_SHORT_SLOT_TIME;
capab |= ATBM_WLAN_CAPABILITY_SHORT_PREAMBLE;
if (config->privacy)
capab |= ATBM_WLAN_CAPABILITY_PRIVACY;
mgmt = (struct atbmwifi_ieee80211_mgmt *) ATBM_OS_SKB_DATA(skb);
atbm_memset(mgmt, 0, 24);
atbm_memcpy(mgmt->sa, priv->mac_addr, ATBM_ETH_ALEN);
atbm_memcpy(mgmt->da, priv->daddr, ATBM_ETH_ALEN);
atbm_memcpy(mgmt->bssid, priv->bssid, ATBM_ETH_ALEN);
mgmt->frame_control = atbm_cpu_to_le16(ATBM_IEEE80211_FTYPE_MGMT |
ATBM_IEEE80211_STYPE_ASSOC_REQ);
mgmt->u.assoc_req.capab_info = atbm_cpu_to_le16(capab);
mgmt->u.assoc_req.listen_interval =
atbm_cpu_to_le16(priv->bss.sta_priv.beacon_interval);
pos= mgmt->u.assoc_req.variable;
/* SSID */
*pos++ = ATBM_WLAN_EID_SSID;
*pos++ = priv->ssid_length;
atbm_memcpy(pos,priv->ssid, priv->ssid_length);
pos += priv->ssid_length;
/* add all rates which were marked to be used above */
pos = atbmwifi_ieee80211_add_rate_ie_from_ap(pos,(priv->bss.sta_priv.band==ATBM_IEEE80211_BAND_5GHZ),rates,priv->bss.sta_priv.rate.basic_rates);
/*
if (priv->bss.channel_num) {
*pos++ = ATBM_WLAN_EID_DS_PARAMS;
*pos++ = 1;
*pos++ = priv->bss.channel_num;
}*/
pos = atbmwifi_ieee80211_add_ht_ie(priv,priv->hw_priv->bands[priv->bss.sta_priv.band], pos);
#if CONFIG_P2P
if(priv->p2p_join){
if(priv->p2p_assoc_req_ie && priv->p2p_assoc_req_ie_len){
atbm_memcpy(pos, priv->p2p_assoc_req_ie, priv->p2p_assoc_req_ie_len);
pos += priv->p2p_assoc_req_ie_len;
}
}
#endif
if (priv->bss.sta_priv.wmm_used){
pos = (atbm_uint8*)atbmwifi_ieee80211_add_wme(priv,pos);
}
#if CONFIG_WPS
if(wpa_s->wps_mode != WPS_MODE_UNKNOWN)
pos = atbmwifi_ieee80211_add_assocreq_wps_ie(priv, pos);
else
#endif
/* if present, add any custom IEs that go before HT */
if (priv->extra_ie && priv->extra_ie_len) {
atbm_memcpy(pos, priv->extra_ie, priv->extra_ie_len);
pos += priv->extra_ie_len;
wifi_printk(WIFI_DBG_MSG,"assciating:ie(%d)\n", priv->extra_ie_len);
}
atbm_skb_put(skb, pos-(atbm_uint8 *)mgmt);
#if CONFIG_P2P
if(priv->p2pdata){
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_CTL_NO_CCK_RATE;
}else
#endif
{
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_CTL_USE_MINRATE;
}
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_INTFL_DONT_ENCRYPT;
return skb;
}
atbm_void atbmwifi_tx_sta_mgmtframe(struct atbmwifi_vif *priv,atbm_uint16 stype,atbm_uint16 transaction )
{
//struct atbmwifi_ieee80211_hdr *hdr;
struct atbmwifi_common * hw_priv = priv->hw_priv;
struct atbm_buff *skb = ATBM_NULL;
struct atbmwifi_cfg *config = atbmwifi_get_config(priv);
wifi_printk(WIFI_TX,"atbmwifi_tx_sta_mgmtframe bssid=%x %x:%x\n",(atbm_uint32)priv->bssid[0],(atbm_uint32)priv->bssid[4],(atbm_uint32)priv->bssid[5]);
//
///build mgmt frame
//
switch(stype){
case ATBM_IEEE80211_STYPE_PROBE_REQ:
//atbmwifi_ieee80211_send_probe_req(priv,NULL,priv->ssid,priv->ssid_length,priv->extra_ie,priv->extra_ie_len,-1,0);
break;
case ATBM_IEEE80211_STYPE_AUTH:
wifi_printk((WIFI_TX|WIFI_CONNECT),"[sta]:send STYPE_AUTH \n");
skb = atbmwifi_ieee80211_send_auth(priv,transaction,config->auth_alg,priv->daddr,priv->bssid,0);
break;
case ATBM_IEEE80211_STYPE_ASSOC_REQ:
case ATBM_IEEE80211_STYPE_REASSOC_REQ:
wifi_printk((WIFI_TX|WIFI_CONNECT),"[sta]:send ASSOC_REQ \n");
skb = atbmwifi_ieee80211_send_assoc_req(priv);
break;
default:
break;
}
if(skb == ATBM_NULL){
wifi_printk((WIFI_DBG_ERROR|WIFI_TX),"atbmwifi_tx_sta_mgmtframe %x error!! \n",stype);
return;
}
//
//send mgmt frame
//
atbmwifi_tx(hw_priv,skb,priv);
}
#if CONFIG_SAE
static int atbmwifi_send_auth_reply(struct atbmwifi_vif *priv,
atbm_uint16 transaction, atbm_uint16 auth_alg, const atbm_uint8 *da,const atbm_uint8 *bssid,atbm_uint16 resp)
{
struct atbmwifi_common *hw_priv = _atbmwifi_vifpriv_to_hwpriv(priv);
struct hostapd_sta_info *sta = ap_get_sta((struct hostapd_data *)priv->appdata, da);
//struct atbmwifi_ieee80211_tx_info * tx_info = ATBM_IEEE80211_SKB_TXCB(skb);
struct atbm_buff *skb_tx = atbmwifi_ieee80211_send_auth(priv,transaction,auth_alg,da,priv->bssid,resp);
atbmwifi_tx(hw_priv,skb_tx,priv);
if(resp == ATBM_WLAN_STATUS_SUCCESS) {
if(sta)
priv->connect_timer_linkid = sta->aid;
wifi_printk(WIFI_WPA,"atbm: atbmwifi_send_auth_reply(), ms=%lu\n", (long unsigned int)atbm_GetOsTimeMs());
atbmwifi_eloop_register_timeout(0,ATBM_WIFI_AUTH_TIMEOUT,atbmwifi_ap_join_timeout,(atbm_void *)priv,ATBM_NULL);
}
return resp;
}
static void sae_set_state(struct hostapd_sta_info *sta, enum sae_state state,
const char *reason)
{
wpa_printf(MSG_DEBUG, "SAE: State %s -> %s for peer " MACSTR " (%s)",
sae_state_txt(sta->sae.state), sae_state_txt(state),
MAC2STR(sta->addr), reason);
sta->sae.state = state;
}
static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
struct hostapd_sta_info *sta, int update)
{
struct wpabuf *buf;
const char *password = NULL;
struct sae_password_entry *pw;
const char *rx_id = NULL;
if (sta->sae.tmp)
rx_id = sta->sae.tmp->pw_id;
for (pw = hapd->sae_passwords; pw; pw = pw->next) {
if (!atbm_is_broadcast_ether_addr(pw->peer_addr) &&
atbm_memcmp(pw->peer_addr, sta->addr, ATBM_ETH_ALEN) != 0)
continue;
if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
continue;
if (rx_id && pw->identifier &&
strcmp(rx_id, pw->identifier) != 0)
continue;
password = pw->password;
break;
}
if (!password)
password = hapd->wpa_passphrase;
if (!password) {
wpa_printf(MSG_DEBUG, "SAE: No password available");
return NULL;
}
if (update &&
sae_prepare_commit(hapd->own_addr, sta->addr,
(atbm_uint8 *) password, strlen(password), rx_id,
&sta->sae) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
return NULL;
}
if (pw && pw->vlan_id) {
if (!sta->sae.tmp) {
wpa_printf(MSG_INFO,
"SAE: No temporary data allocated - cannot store VLAN ID");
return NULL;
}
sta->sae.tmp->vlan_id = pw->vlan_id;
}
buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
(rx_id ? 3 + strlen(rx_id) : 0));
if (buf == NULL)
return NULL;
sae_write_commit(&sta->sae, buf, sta->sae.tmp ?
sta->sae.tmp->anti_clogging_token : ATBM_NULL, rx_id);
return buf;
}
static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
struct hostapd_sta_info *sta)
{
struct wpabuf *buf;
buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
if (buf == NULL)
return NULL;
sae_write_confirm(&sta->sae, buf);
return buf;
}
static int auth_sae_send_commit(struct hostapd_data *hapd,
struct hostapd_sta_info *sta,
const atbm_uint8 *bssid, int update)
{
//struct wpabuf *data;
int reply_res;
wpabuf_free(hapd->sae_data);
hapd->sae_data = auth_build_sae_commit(hapd, sta, update);
if (!hapd->sae_data && sta->sae.tmp && sta->sae.tmp->pw_id)
return ATBM_WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
if (hapd->sae_data == NULL)
return ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE;
/*
reply_res = send_auth_reply(hapd, sta->addr, bssid, ATBM_WLAN_AUTH_SAE, 1,
ATBM_WLAN_STATUS_SUCCESS, wpabuf_head(data),
wpabuf_len(data), "sae-send-commit");
*/
reply_res = atbmwifi_send_auth_reply(hapd->priv,1,ATBM_WLAN_AUTH_SAE,sta->addr,bssid,ATBM_WLAN_STATUS_SUCCESS);
wpabuf_free(hapd->sae_data);
hapd->sae_data = ATBM_NULL;
return reply_res;
}
static int auth_sae_send_confirm(struct hostapd_data *hapd,
struct hostapd_sta_info *sta,
const atbm_uint8 *bssid)
{
//struct wpabuf *data;
int reply_res;
wpabuf_free(hapd->sae_data);
hapd->sae_data = auth_build_sae_confirm(hapd, sta);
if (hapd->sae_data == NULL)
return ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE;
/*
reply_res = send_auth_reply(hapd, sta->addr, bssid, ATBM_WLAN_AUTH_SAE, 2,
ATBM_WLAN_STATUS_SUCCESS, wpabuf_head(data),
wpabuf_len(data), "sae-send-confirm");
*/
reply_res = atbmwifi_send_auth_reply(hapd->priv,2,ATBM_WLAN_AUTH_SAE,sta->addr,bssid,ATBM_WLAN_STATUS_SUCCESS);
wpabuf_free(hapd->sae_data);
hapd->sae_data = ATBM_NULL;
return reply_res;
}
static int use_sae_anti_clogging(struct hostapd_data *hapd)
{
struct hostapd_sta_info *sta;
unsigned int open = 0;
int i;
if (hapd->sae_anti_clogging_threshold == 0)
return 1;
for(i=0;i<ATBMWIFI__MAX_STA_IN_AP_MODE;i++){
sta = hapd->sta_list[i];
if(sta==ATBM_NULL) {
continue;
}
if (sta->sae.state != SAE_COMMITTED &&
sta->sae.state != SAE_CONFIRMED)
continue;
open++;
if (open >= hapd->sae_anti_clogging_threshold)
return 1;
}
/* In addition to already existing open SAE sessions, check whether
* there are enough pending commit messages in the processing queue to
* potentially result in too many open sessions. */
if (open >= //open + dl_list_len(&hapd->sae_commit_queue) >=
hapd->sae_anti_clogging_threshold)
return 1;
return 0;
}
static atbm_uint8 sae_token_hash(struct hostapd_data *hapd, const atbm_uint8 *addr)
{
atbm_uint8 hash[SHA256_MAC_LEN];
atbmwifi_hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
addr, ATBM_ETH_ALEN, hash);
return hash[0];
}
static int check_sae_token(struct hostapd_data *hapd, const atbm_uint8 *addr,
const atbm_uint8 *token, atbm_size_t token_len)
{
atbm_uint8 mac[SHA256_MAC_LEN];
const atbm_uint8 *addrs[2];
atbm_size_t len[2];
atbm_uint16 token_idx;
atbm_uint8 idx;
if (token_len != SHA256_MAC_LEN)
return -1;
idx = sae_token_hash(hapd, addr);
token_idx = hapd->sae_pending_token_idx[idx];
if (token_idx == 0 || token_idx != ATBM_WPA_GET_BE16(token)) {
wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from "
MACSTR " - token_idx 0x%04x, expected 0x%04x",
MAC2STR(addr), ATBM_WPA_GET_BE16(token), token_idx);
return -1;
}
addrs[0] = addr;
len[0] = ATBM_ETH_ALEN;
addrs[1] = token;
len[1] = 2;
if (atbmwifi_hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
2, addrs, len, mac) < 0 ||
atbm_memcmp(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0)
return -1;
hapd->sae_pending_token_idx[idx] = 0; /* invalidate used token */
return 0;
}
static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
int group, const atbm_uint8 *addr)
{
struct wpabuf *buf;
atbm_uint8 *token;
atbm_uint32 now;
atbm_uint8 idx[2];
const atbm_uint8 *addrs[2];
atbm_size_t len[2];
atbm_uint8 p_idx;
atbm_uint16 token_idx;
now = atbm_GetOsTime();
if (!(hapd->last_sae_token_key_update) ||
((now - hapd->last_sae_token_key_update) > 60 * 1000) ||
hapd->sae_token_idx == 0xffff) {
if (random_get_bytes(hapd->sae_token_key,
sizeof(hapd->sae_token_key)) < 0)
return NULL;
wpa_hexdump(MSG_DEBUG, "SAE: Updated token key",
hapd->sae_token_key, sizeof(hapd->sae_token_key));
hapd->last_sae_token_key_update = now;
hapd->sae_token_idx = 0;
atbm_memset(hapd->sae_pending_token_idx, 0,
sizeof(hapd->sae_pending_token_idx));
}
buf = wpabuf_alloc(sizeof(atbm_uint16) + SHA256_MAC_LEN);
if (buf == NULL)
return NULL;
wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
p_idx = sae_token_hash(hapd, addr);
token_idx = hapd->sae_pending_token_idx[p_idx];
if (!token_idx) {
hapd->sae_token_idx++;
token_idx = hapd->sae_token_idx;
hapd->sae_pending_token_idx[p_idx] = token_idx;
}
ATBM_WPA_PUT_BE16(idx, token_idx);
token = wpabuf_put(buf, SHA256_MAC_LEN);
addrs[0] = addr;
len[0] = ATBM_ETH_ALEN;
addrs[1] = idx;
len[1] = sizeof(idx);
if (atbmwifi_hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
2, addrs, len, token) < 0) {
wpabuf_free(buf);
return NULL;
}
ATBM_WPA_PUT_BE16(token, token_idx);
return buf;
}
static int sae_check_big_sync(struct hostapd_data *hapd, struct hostapd_sta_info *sta)
{
if (sta->sae.sync > hapd->sae_sync) {
sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync");
sta->sae.sync = 0;
return -1;
}
return 0;
}
void sae_accept_sta(struct hostapd_data *hapd, struct hostapd_sta_info *sta)
{
#define CONFIG_NO_VLAN
#ifndef CONFIG_NO_VLAN
struct vlan_description vlan_desc;
if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) {
wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR
" to VLAN ID %d",
MAC2STR(sta->addr), sta->sae->tmp->vlan_id);
os_memset(&vlan_desc, 0, sizeof(vlan_desc));
vlan_desc.notempty = 1;
vlan_desc.untagged = sta->sae->tmp->vlan_id;
if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
wpa_printf(MSG_INFO,
"Invalid VLAN ID %d in sae_password",
sta->sae->tmp->vlan_id);
return;
}
if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 ||
ap_sta_bind_vlan(hapd, sta) < 0) {
wpa_printf(MSG_INFO,
"Failed to assign VLAN ID %d from sae_password to "
MACSTR, sta->sae->tmp->vlan_id,
MAC2STR(sta->addr));
return;
}
}
#endif /* CONFIG_NO_VLAN */
sta->flags |= WLAN_STA_AUTH;
sta->auth_alg = ATBM_WLAN_AUTH_SAE;
//mlme_authenticate_indication(hapd, sta);
//wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
extern int wpa_auth_pmksa_add_sae(struct hostapd_data *hapd, const atbm_uint8 *addr, const atbm_uint8 *pmk, const atbm_uint8 *pmkid);
wpa_auth_pmksa_add_sae(hapd, sta->addr,
sta->sae.pmk, sta->sae.pmkid);
//sae_sme_send_external_auth_status(hapd, sta, ATBM_WLAN_STATUS_SUCCESS);
}
static int sae_sm_step(struct hostapd_data *hapd, struct hostapd_sta_info *sta,
const atbm_uint8 *bssid, atbm_uint8 auth_transaction, int allow_reuse,
int *sta_removed)
{
int ret;
*sta_removed = 0;
if (auth_transaction != 1 && auth_transaction != 2)
return ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE;
wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u",
MAC2STR(sta->addr), sae_state_txt(sta->sae.state),
auth_transaction);
switch (sta->sae.state) {
case SAE_NOTHING:
if (auth_transaction == 1) {
ret = auth_sae_send_commit(hapd, sta, bssid,
!allow_reuse);
if (ret)
return ret;
sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
if (sae_process_commit(&sta->sae) < 0)
return ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE;
sta->sae.sync = 0;
//sae_set_retransmit_timer(hapd, sta);
} else {
/*
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"SAE confirm before commit");
*/
}
break;
case SAE_COMMITTED:
//sae_clear_retransmit_timer(hapd, sta);
if (auth_transaction == 1) {
if (sae_process_commit(&sta->sae) < 0)
return ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE;
ret = auth_sae_send_confirm(hapd, sta, bssid);
if (ret)
return ret;
sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
sta->sae.sync = 0;
//sae_set_retransmit_timer(hapd, sta);
} else {
/*
* For instructure BSS, send the postponed Confirm from
* Nothing -> Confirmed transition that was reduced to
* Nothing -> Committed above.
*/
ret = auth_sae_send_confirm(hapd, sta, bssid);
if (ret)
return ret;
sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
/*
* Since this was triggered on Confirm RX, run another
* step to get to Accepted without waiting for
* additional events.
*/
return sae_sm_step(hapd, sta, bssid, auth_transaction,
0, sta_removed);
}
break;
case SAE_CONFIRMED:
//sae_clear_retransmit_timer(hapd, sta);
if (auth_transaction == 1) {
if (sae_check_big_sync(hapd, sta))
return ATBM_WLAN_STATUS_SUCCESS;
sta->sae.sync++;
ret = auth_sae_send_commit(hapd, sta, bssid, 1);
if (ret)
return ret;
if (sae_process_commit(&sta->sae) < 0)
return ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE;
ret = auth_sae_send_confirm(hapd, sta, bssid);
if (ret)
return ret;
//sae_set_retransmit_timer(hapd, sta);
} else {
sta->sae.send_confirm = 0xffff;
sae_accept_sta(hapd, sta);
}
break;
case SAE_ACCEPTED:
if (auth_transaction == 1) {
wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
ret = auth_sae_send_commit(hapd, sta, bssid, 1);
if (ret)
return ret;
sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
if (sae_process_commit(&sta->sae) < 0)
return ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE;
sta->sae.sync = 0;
//sae_set_retransmit_timer(hapd, sta);
} else {
if (sae_check_big_sync(hapd, sta))
return ATBM_WLAN_STATUS_SUCCESS;
sta->sae.sync++;
ret = auth_sae_send_confirm(hapd, sta, bssid);
sae_clear_temp_data(&sta->sae);
if (ret)
return ret;
}
break;
default:
wpa_printf(MSG_ERROR, "SAE: invalid state %d",
sta->sae.state);
return ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE;
}
return ATBM_WLAN_STATUS_SUCCESS;
}
static void sae_pick_next_group(struct hostapd_data *hapd, struct hostapd_sta_info *sta)
{
struct sae_data *sae = &sta->sae;
int i, *groups = hapd->sae_groups;
int default_groups[] = { 19, 0 };
if (sae->state != SAE_COMMITTED)
return;
wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
if (!groups)
groups = default_groups;
for (i = 0; groups[i] > 0; i++) {
if (sae->group == groups[i])
break;
}
if (groups[i] <= 0) {
wpa_printf(MSG_DEBUG,
"SAE: Previously selected group not found from the current configuration");
return;
}
for (;;) {
i++;
if (groups[i] <= 0) {
wpa_printf(MSG_DEBUG,
"SAE: No alternative group enabled");
return;
}
if (sae_set_group(sae, groups[i]) < 0)
continue;
break;
}
wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]);
}
static void handle_auth_sae(struct hostapd_data *hapd, struct hostapd_sta_info *sta,
const struct atbmwifi_ieee80211_mgmt *mgmt, atbm_size_t len,
atbm_uint16 auth_transaction, atbm_uint16 status_code)
{
int resp = ATBM_WLAN_STATUS_SUCCESS;
//struct wpabuf *data = NULL;
int *groups = hapd->sae_groups;
int default_groups[] = { 19, 0 };
const atbm_uint8 *pos, *end;
int sta_removed = 0;
if (!groups)
groups = default_groups;
if (status_code != ATBM_WLAN_STATUS_SUCCESS) {
resp = -1;
goto remove_sta;
}
if (auth_transaction == 1) {
const atbm_uint8 *token = NULL;
atbm_size_t token_len = 0;
int allow_reuse = 0;
sae_set_state(sta, SAE_NOTHING, "Init");
sta->sae.sync = 0;
/*
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"start SAE authentication (RX commit, status=%u (%s))",
status_code, status2str(status_code));
*/
if (sta->sae.state == SAE_COMMITTED) {
/* This is needed in the infrastructure BSS case to
* address a sequence where a STA entry may remain in
* hostapd across two attempts to do SAE authentication
* by the same STA. The second attempt may end up trying
* to use a different group and that would not be
* allowed if we remain in Committed state with the
* previously set parameters. */
pos = mgmt->u.auth.variable;
end = ((const atbm_uint8 *) mgmt) + len;
if (end - pos >= (int) sizeof(atbm_uint16) &&
sae_group_allowed(&sta->sae, groups,
ATBM_WPA_GET_LE16(pos)) ==
ATBM_WLAN_STATUS_SUCCESS) {
/* Do not waste resources deriving the same PWE
* again since the same group is reused. */
sae_set_state(sta, SAE_NOTHING,
"Allow previous PWE to be reused");
allow_reuse = 1;
} else {
sae_set_state(sta, SAE_NOTHING,
"Clear existing state to allow restart");
sae_clear_data(&sta->sae);
}
}
resp = sae_parse_commit(&sta->sae, mgmt->u.auth.variable,
((const atbm_uint8 *) mgmt) + len -
mgmt->u.auth.variable, &token,
&token_len, groups);
if (resp == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message from " MACSTR " due to reflection attack",
MAC2STR(sta->addr));
goto remove_sta;
}
if (resp == ATBM_WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
/*
wpa_msg(hapd->msg_ctx, MSG_INFO,
WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER
MACSTR, MAC2STR(sta->addr));
*/
//sae_clear_retransmit_timer(hapd, sta);
sae_set_state(sta, SAE_NOTHING,
"Unknown Password Identifier");
goto remove_sta;
}
if (token && check_sae_token(hapd, sta->addr, token, token_len)
< 0) {
wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
"incorrect token from " MACSTR,
MAC2STR(sta->addr));
resp = ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE;
goto remove_sta;
}
if (resp != ATBM_WLAN_STATUS_SUCCESS)
goto reply;
if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
wpa_printf(MSG_INFO,
"SAE: Request anti-clogging token from "
MACSTR, MAC2STR(sta->addr));
wpabuf_free(hapd->sae_data);
hapd->sae_data = auth_build_token_req(hapd, sta->sae.group,
sta->addr);
resp = ATBM_WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
goto reply;
}
resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
allow_reuse, &sta_removed);
} else if (auth_transaction == 2) {
/*
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"SAE authentication (RX confirm, status=%u (%s))",
status_code, status2str(status_code));
*/
if (status_code != ATBM_WLAN_STATUS_SUCCESS)
goto remove_sta;
if (sta->sae.state >= SAE_CONFIRMED) {
const atbm_uint8 *var;
atbm_size_t var_len;
atbm_uint16 peer_send_confirm;
var = mgmt->u.auth.variable;
var_len = ((atbm_uint8 *) mgmt) + len - mgmt->u.auth.variable;
if (var_len < 2) {
resp = ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE;
goto reply;
}
peer_send_confirm = ATBM_WPA_GET_LE16(var);
if (sta->sae.state == SAE_ACCEPTED &&
(peer_send_confirm <= sta->sae.rc ||
peer_send_confirm == 0xffff)) {
wpa_printf(MSG_DEBUG,
"SAE: Silently ignore unexpected Confirm from peer "
MACSTR
" (peer-send-confirm=%u Rc=%u)",
MAC2STR(sta->addr),
peer_send_confirm, sta->sae.rc);
return;
}
if (sae_check_confirm(&sta->sae, var, var_len) < 0) {
resp = ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE;
goto reply;
}
sta->sae.rc = peer_send_confirm;
}
resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, 0,
&sta_removed);
} else {
/*
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"unexpected SAE authentication transaction %u (status=%u (%s))",
auth_transaction, status_code,
status2str(status_code));
*/
if (status_code != ATBM_WLAN_STATUS_SUCCESS)
goto remove_sta;
resp = ATBM_WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
}
reply:
if (!sta_removed && resp != ATBM_WLAN_STATUS_SUCCESS) {
pos = mgmt->u.auth.variable;
end = ((const atbm_uint8 *) mgmt) + len;
/* Copy the Finite Cyclic Group field from the request if we
* rejected it as unsupported group. */
if (resp == ATBM_WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
!hapd->sae_data && end - pos >= 2)
hapd->sae_data = wpabuf_alloc_copy(pos, 2);
//sae_sme_send_external_auth_status(hapd, sta, resp);
atbmwifi_send_auth_reply(hapd->priv,auth_transaction,ATBM_WLAN_AUTH_SAE,mgmt->sa,mgmt->bssid,resp);
/*
send_auth_reply(hapd, mgmt->sa, mgmt->bssid, ATBM_WLAN_AUTH_SAE,
auth_transaction, resp,
data ? wpabuf_head(data) : (atbm_uint8 *) "",
data ? wpabuf_len(data) : 0, "auth-sae");
*/
}
remove_sta:
if (!sta_removed &&
(resp != ATBM_WLAN_STATUS_SUCCESS ||
status_code != ATBM_WLAN_STATUS_SUCCESS)) {
atbmwifi_sta_del(hapd->priv, sta->addr);
}
wpabuf_free(hapd->sae_data);
hapd->sae_data = ATBM_NULL;
}
#endif
static atbm_uint8 sta_chllenge[ATBM_WLAN_AUTH_CHALLENGE_LEN];
atbm_void atbmwifi_rx_ap_auth(struct atbmwifi_vif *priv,struct atbm_buff *skb)
{
atbm_uint16 auth_alg, auth_transaction, status_code;
atbm_uint16 fc;
struct atbmwifi_common *hw_priv = _atbmwifi_vifpriv_to_hwpriv(priv);
int len = ATBM_OS_SKB_LEN(skb);
struct atbmwifi_ieee80211_mgmt *mgmt = (struct atbmwifi_ieee80211_mgmt *) ATBM_OS_SKB_DATA(skb);
atbm_uint16 resp = ATBM_WLAN_STATUS_SUCCESS;
struct atbmwifi_ieee80211_tx_info * tx_info = ATBM_IEEE80211_SKB_TXCB(skb);
atbm_uint8 *resp_ies = ATBM_NULL;
atbm_size_t resp_ies_len = 0;
struct atbm_buff *skb_tx = ATBM_NULL;
struct atbmwifi_cfg *config = atbmwifi_get_config(priv);
#if CONFIG_SAE
struct hostapd_sta_info *sta;
struct hostapd_data *hapd = (struct hostapd_data *)priv->appdata;
#endif /* CONFIG_SAE */
auth_alg = mgmt->u.auth.auth_alg;
auth_transaction = mgmt->u.auth.auth_transaction;
status_code = mgmt->u.auth.status_code;
fc = mgmt->frame_control;
wifi_printk(WIFI_WPA,"ap:rx_auth:alg(%d),tran(%d),status(%d),fc(%x)\n",
auth_alg,auth_transaction,status_code,fc);
if (!(((config->auth_alg & ATBM_WPA_AUTH_ALG_OPEN) &&
auth_alg == ATBM_WLAN_AUTH_OPEN) ||
#if CONFIG_SAE
(config->auth_alg & ATBM_WPA_AUTH_ALG_SAE &&
auth_alg == ATBM_WLAN_AUTH_SAE) ||
#endif
((config->auth_alg & ATBM_WPA_AUTH_ALG_SHARED) &&
auth_alg == ATBM_WLAN_AUTH_SHARED_KEY) )) {
wifi_printk(WIFI_WPA,"ap:rx_auth:Unsupport rxalg(%d!=%d)\n",auth_alg,config->auth_alg);
dump_mem(mgmt,32);
resp = ATBM_WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
goto fail;
}
if (!(auth_transaction == 1 ||
#if CONFIG_SAE
auth_alg == ATBM_WLAN_AUTH_SAE ||
#endif
(auth_alg == ATBM_WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
#ifdef WPA_HOST_DEBUG
wifi_printk(WIFI_DBG_INIT,"ap:Unknown auth transnum (%d)\n",
auth_transaction);
#endif
resp = ATBM_WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
goto fail;
}
if (atbm_memcmp(mgmt->sa, priv->mac_addr, ATBM_ETH_ALEN) == 0)
{
wifi_printk(WIFI_DBG_INIT,"Sta " MACSTR " not allow to auth\n",
MAC2STR(mgmt->sa));
resp = ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
if(auth_alg == ATBM_WLAN_AUTH_SHARED_KEY)
{
if(auth_transaction == 1)
{
atbm_uint8 key[8]= {0,1,2,3,4,5,6,7};
resp_ies = (atbm_uint8 *)atbm_kmalloc(2 + ATBM_WLAN_AUTH_CHALLENGE_LEN,GFP_KERNEL);
if(resp_ies == ATBM_NULL)
{
resp = ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
atbmwifi_rc4_skip(key, sizeof(key), 0,
sta_chllenge, ATBM_WLAN_AUTH_CHALLENGE_LEN);
resp_ies[0] = ATBM_WLAN_EID_CHALLENGE;
resp_ies[1] = ATBM_WLAN_AUTH_CHALLENGE_LEN;
atbm_memcpy(resp_ies + 2, sta_chllenge,
ATBM_WLAN_AUTH_CHALLENGE_LEN);
resp_ies_len = 2 + ATBM_WLAN_AUTH_CHALLENGE_LEN;
}
else if(auth_transaction == 3)
{
const atbm_uint8 *challenge = ATBM_NULL;
if ((len >=2 + ATBM_WLAN_AUTH_CHALLENGE_LEN )&&
(mgmt->u.auth.variable[0] == ATBM_WLAN_EID_CHALLENGE) &&
(mgmt->u.auth.variable[1] == ATBM_WLAN_AUTH_CHALLENGE_LEN))
{
challenge = &mgmt->u.auth.variable[2];
}
if ( !challenge ||
atbm_memcmp(sta_chllenge, challenge, ATBM_WLAN_AUTH_CHALLENGE_LEN))
{
wifi_printk(WIFI_WPA,"ap_rx_auth challenge ATBM_FALSE\n\r");
resp = ATBM_WLAN_STATUS_CHALLENGE_FAIL;
}
}
}
#if CONFIG_SAE
if(auth_alg == ATBM_WLAN_AUTH_SAE){
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;
}
handle_auth_sae(hapd, sta, mgmt, len, auth_transaction,
status_code);
return;
}
#endif
if(priv->extra_ie){
atbm_kfree(priv->extra_ie);
}
priv->extra_ie = resp_ies;
priv->extra_ie_len = resp_ies_len;
skb_tx = atbmwifi_ieee80211_send_auth(priv,auth_transaction+1,auth_alg,mgmt->sa,priv->bssid,resp);
atbmwifi_tx(hw_priv,skb_tx,priv);
if(resp == ATBM_WLAN_STATUS_SUCCESS) {
priv->connect_timer_linkid = tx_info->link_id;
wifi_printk(WIFI_WPA,"atbm: atbmwifi_rx_ap_auth(), ms=%lu\n", (long unsigned int)atbm_GetOsTimeMs());
atbmwifi_eloop_register_timeout(0,ATBM_WIFI_AUTH_TIMEOUT,atbmwifi_ap_join_timeout,(atbm_void *)priv,ATBM_NULL);
}
fail:
if(resp_ies)
atbm_kfree(resp_ies);
priv->extra_ie_len = 0;
priv->extra_ie = ATBM_NULL;
}
int atbmwifi_rx_assoc_req(struct atbmwifi_vif *priv, struct atbm_buff *skb, struct atbmwifi_ieee80211_tx_info * tx_info)
{
struct atbmwifi_ieee80211_mgmt *mgmt = ATBM_OS_SKB_DATA(skb);
int len = ATBM_OS_SKB_LEN(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;
const atbm_uint8 *wpa_ie=ATBM_NULL;
atbm_size_t wpa_ie_len=0;
atbm_uint8 * data=ATBM_NULL;
int ret =0;
atbm_uint16 ap_ht_cap_flags;
atbm_uint8 atbm_is_40m = 0;
atbm_uint8 sta_supp_40m = 0;
struct atbmwifi_cfg *config = atbmwifi_get_config(priv);
struct atbmwifi_sta_priv *sta_priv = atbmwifi_sta_find_form_linkid(priv,tx_info->link_id);
#if CONFIG_WPS
const atbm_uint8 *wps_ie = ATBM_NULL;
atbm_size_t wps_ie_len = 0;
struct wpabuf *wpaBuff = ATBM_NULL;
#endif
if(sta_priv == ATBM_NULL){
wifi_printk(WIFI_CONNECT, "<ERROR>atbmwifi_rx_assoc_req sta_priv ATBM_NULL just drop \n");
resp = ATBM_WLAN_STATUS_AUTH_TIMEOUT;
goto fail;
}
wifi_printk(WIFI_WPA,"ATBM_IEEE80211_STYPE_ASSOC_REQ 1\n");
if(type == ATBM_IEEE80211_STYPE_ASSOC_REQ)
{
wifi_printk(WIFI_WPA,"ATBM_IEEE80211_STYPE_ASSOC_REQ 2\n");
data = mgmt->u.assoc_req.variable;
len = len-offsetof(struct atbmwifi_ieee80211_mgmt, u.assoc_req.variable);
}
else if(type == ATBM_IEEE80211_STYPE_REASSOC_REQ)
{
data = mgmt->u.reassoc_req.variable;
len = len-offsetof(struct atbmwifi_ieee80211_mgmt, u.reassoc_req.variable);
}
else {
return -1;
}
atbm_ieee802_11_parse_elems(data,len,&elems);
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;
}
resp = check_ssid(config, elems.ssid, elems.ssid_len);
if (resp != ATBM_WLAN_STATUS_SUCCESS)
goto fail;
if (!elems.supp_rates) {
resp = ATBM_WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
#if CONFIG_WPS
if((priv->pbc || priv->pin) && elems.wps_ie)
{
wpaBuff = wps_build_assoc_resp_ie();
if(!wpaBuff){
resp = ATBM_WLAN_REASON_UNSPECIFIED;
goto fail;
}
wps_ie = wpaBuff->buf;
wps_ie_len = wpaBuff->used;
}else
#endif
if (config->wpa && wpa_ie == ATBM_NULL) {
resp = ATBM_WLAN_STATUS_INVALID_IE;
goto fail;
}
else if ((config->wpa==0) && wpa_ie ) {
resp = ATBM_WLAN_STATUS_INVALID_IE;
goto fail;
}
if (elems.wmm_param || elems.wmm_info){
sta_priv->uapsd_support_queues=is_uapsd_supported(&elems);
if(elems.wmm_info){
sta_priv->max_sp=(*(elems.wmm_info+8)>>5&0x3);
}else if(elems.wmm_param){
sta_priv->max_sp=(*(elems.wmm_param+8)>>5&0x3);
}
sta_priv->wmm_used = 1;
wifi_printk(WIFI_CONNECT,"uapsd_support_queues=%x,max_sp=%d\n",sta_priv->uapsd_support_queues,sta_priv->max_sp);
}else{
sta_priv->wmm_used = 0;
}
sta_priv->beacon_interval = mgmt->u.assoc_req.listen_interval;
if(elems.erp_info)
sta_priv->short_preamble = (elems.erp_info[0]& ATBM_WLAN_ERP_BARKER_PREAMBLE) == 0;
sta_priv->wpa = (elems.rsn_len || elems.wpa_len) ? 1:0;
sta_priv->ht = elems.ht_cap_elem? 1:0;
sta_priv->rate.ht = sta_priv->ht;
sta_priv->band = priv->bss.sta_priv.band;
if(elems.ht_cap_elem){
atbmwifi_ieee80211_ht_cap_ie_to_sta_ht_cap(priv->hw_priv->bands[priv->bss.sta_priv.band],
elems.ht_cap_elem,
&sta_priv->rate.ht_cap);
}
ap_ht_cap_flags = sta_priv->rate.ht_cap.cap;
atbm_is_40m = !!atbmwifi_chtype_is_40M(priv->hw_priv->channel_type);
sta_supp_40m = !!(sta_priv->rate.ht_cap.cap&ATBM_IEEE80211_HT_CAP_SUP_WIDTH_20_40);
if(atbm_is_40m^sta_supp_40m){
sta_priv->rate.channel_type = sta_priv->ht ? ATBM_NL80211_CHAN_HT20 : ATBM_NL80211_CHAN_NO_HT;
}else {
sta_priv->rate.channel_type = sta_priv->ht ? priv->hw_priv->channel_type : ATBM_NL80211_CHAN_NO_HT;
}
if(sta_priv->ht&&(ap_ht_cap_flags&(ATBM_IEEE80211_HT_CAP_SGI_20|ATBM_IEEE80211_HT_CAP_SGI_40))){
sta_priv->sgi = 1;
}else {
sta_priv->sgi = 0;
}
wifi_printk(WIFI_WPA,"atbm_is_40m [%x],sta_supp_40m [%x],sta_chtype[%x]\n",atbm_is_40m,sta_supp_40m,sta_priv->rate.channel_type);
atbmwifi_ieee80211_get_sta_rateinfo(&sta_priv->rate,priv->hw_priv->bands[priv->bss.sta_priv.band],elems.supp_rates, elems.supp_rates_len);
atbmwifi_ieee80211_get_sta_rateinfo(&sta_priv->rate,priv->hw_priv->bands[priv->bss.sta_priv.band],elems.ext_supp_rates, elems.ext_supp_rates_len);
wifi_printk(WIFI_RATE,"support_rates %x,basic_rates %x\n",sta_priv->rate.support_rates,sta_priv->rate.basic_rates);
ret = atbmwifi_sta_add(priv,mgmt->sa);
if(ret){
resp = ATBM_WLAN_STATUS_AUTH_TIMEOUT;
goto fail;
}
priv->assoc_ok = 1;
atbmwifi_eloop_cancel_timeout(atbmwifi_ap_join_timeout, (atbm_void *)priv, ATBM_NULL);
resp = atbmwifi_event_uplayer(priv,ATBM_WIFI_ASSOC_EVENT,(atbm_uint8*)skb);
fail:
{
struct atbm_buff *skb = ATBM_NULL;
atbm_memcpy(priv->daddr,mgmt->sa,6);
#if CONFIG_WPS
skb = atbmwifi_ieee80211_send_assoc_resp(priv,resp,type == ATBM_IEEE80211_STYPE_REASSOC_REQ ? 1:0,wps_ie,wps_ie_len,tx_info->link_id);
wpabuf_free(wpaBuff);
#else
skb = atbmwifi_ieee80211_send_assoc_resp(priv,resp,type == ATBM_IEEE80211_STYPE_REASSOC_REQ ? 1:0,wpa_ie,wpa_ie_len,tx_info->link_id);
#endif
atbmwifi_tx(priv->hw_priv,skb,priv);
//atbm_spin_unlock(mgm_tx);
}
return resp;
}
atbm_void atbmwifi_rx_ap_mgmtframe(struct atbmwifi_vif *priv,struct atbm_buff *skb)
{
struct atbmwifi_ieee80211_hdr * hdr = (struct atbmwifi_ieee80211_hdr *) ATBM_OS_SKB_DATA(skb);
atbm_uint16 stype = hdr->frame_control & atbm_cpu_to_le16(ATBM_IEEE80211_FCTL_STYPE);
struct atbmwifi_ieee80211_tx_info * tx_info = ATBM_IEEE80211_SKB_TXCB(skb);
switch(stype){
#if CONFIG_P2P
case ATBM_IEEE80211_STYPE_PROBE_REQ:
{
struct atbmwifi_ieee80211_mgmt *mgmt = (struct atbmwifi_ieee80211_mgmt *)ATBM_OS_SKB_DATA(skb);
struct atbmwifi_ieee80211_rx_status *hw_hdr = ATBM_IEEE80211_SKB_RXCB(skb);
atbm_uint8 *data = (atbm_uint8 *)ATBM_OS_SKB_DATA(skb) + offsetof(struct atbmwifi_ieee80211_mgmt, u.probe_req.variable);
int len = ATBM_OS_SKB_LEN(skb) - offsetof(struct atbmwifi_ieee80211_mgmt, u.probe_req.variable);
atbm_p2p_probe_req_rx(priv, mgmt->sa, mgmt->da, mgmt->bssid,
data, len, hw_hdr->freq, (int)hw_hdr->signal);
}
break;
#endif
case ATBM_IEEE80211_STYPE_BEACON:
case ATBM_IEEE80211_STYPE_PROBE_RESP:
atbmwifi_ap_rx_probe_resp(priv,skb);
break;
case ATBM_IEEE80211_STYPE_AUTH:
{
int linkid = atbmwifi_sta_alloc(priv,hdr->addr2);
if(linkid < 0){
break;
}
tx_info->link_id = linkid;
atbmwifi_rx_ap_auth(priv,skb);
atbmwifi_event_uplayer(priv,ATBM_WIFI_AUTH_EVENT,(atbm_uint8*)skb);
}
break;
case ATBM_IEEE80211_STYPE_ASSOC_REQ:
case ATBM_IEEE80211_STYPE_REASSOC_REQ:
/*check linking station LinkId,if the link id is already alloced,do further,otherwise drop*/
tx_info->link_id = atbmwifi_find_link_id(priv,hdr->addr2);
if(tx_info->link_id == 0){
//drop
atbmwifi_ieee80211_tx_mgmt_deauth(priv,hdr->addr2,priv->bssid,ATBM_WLAN_REASON_PREV_AUTH_NOT_VALID);
break;
}
if((stype == ATBM_IEEE80211_STYPE_ASSOC_REQ)
&& (priv->link_id_db[tx_info->link_id-1].status != ATBMWIFI__LINK_RESERVE)){
break;
}
//rx_info->link_id
if(!atbmwifi_rx_assoc_req(priv, skb, tx_info) == ATBM_WLAN_STATUS_SUCCESS)
atbmwifi_event_uplayer(priv,ATBM_WIFI_DEASSOC_EVENT,0);
break;
case ATBM_IEEE80211_STYPE_DEAUTH:
case ATBM_IEEE80211_STYPE_DISASSOC:
tx_info->link_id = atbmwifi_find_link_id(priv,hdr->addr2);
wifi_printk(WIFI_WPA,"[ap]:rx DEAUTH \n");
if((tx_info->link_id > ATBMWIFI__MAX_STA_IN_AP_MODE) || ( tx_info->link_id<=0)){
break;
}
if(priv->link_id_db[tx_info->link_id-1].status != ATBMWIFI__LINK_SOFT) {
priv->link_id_db[tx_info->link_id-1].status = ATBMWIFI__LINK_SOFT;
atbmwifi_wpa_event_queue((atbm_void*)priv,(atbm_void*)&tx_info->link_id,ATBM_NULL,WPA_EVENT__SUPPLICANT_DEAUTHEN,ATBM_WPA_EVENT_NOACK);
//atbmwifi_ap_deauth(priv,atbmwifi_ieee80211_get_SA(hdr));
}
break;
default:
break;
}
}
atbm_void atbmwifi_tx_ap_mgmtframe(struct atbmwifi_vif *priv,atbm_uint16 stype,atbm_uint16 transaction )
{
struct atbmwifi_common * hw_priv = priv->hw_priv;
struct atbm_buff *skb = ATBM_NULL;
switch(stype){
case ATBM_IEEE80211_STYPE_PROBE_RESP:
/*probe resp is send by lmac*/
skb = atbmwifi_ieee80211_send_proberesp(priv,priv->extra_ie,priv->extra_ie_len);
break;
case ATBM_IEEE80211_STYPE_AUTH:
wifi_printk(WIFI_CONNECT, "[ap]:tx AUTH \n");
skb = atbmwifi_ieee80211_send_auth(priv,transaction,ATBM_WLAN_AUTH_OPEN,priv->daddr,priv->bssid,0);
break;
case ATBM_IEEE80211_STYPE_ASSOC_RESP:
wifi_printk(WIFI_CONNECT, "[ap]:tx ASSOC\n");
skb = atbmwifi_ieee80211_send_assoc_resp(priv,0,0,ATBM_NULL,0,0);
break;
default:
break;
}
if(skb == ATBM_NULL){
wifi_printk(WIFI_DBG_ERROR, "atbmwifi_tx_ap_mgmtframe %x error!! \n",stype);
return;
}
//
//send mgmt frame
//
atbmwifi_tx(hw_priv,skb,priv);
}
struct atbm_buff * atbmwifi_ieee80211_send_assoc_resp(struct atbmwifi_vif *priv,
atbm_uint16 status_code, int reassoc, const atbm_uint8 *ies,
atbm_size_t ies_len,atbm_uint16 aid)
{
int send_len;
struct atbm_buff *skb=ATBM_NULL;
struct atbmwifi_ieee80211_mgmt *reply;
atbm_uint8 *p = ATBM_NULL;
atbm_uint16 capab=0;
struct atbmwifi_cfg *config = atbmwifi_get_config(priv);
skb = atbm_dev_alloc_skb(
sizeof(struct atbmwifi_ieee80211_mgmt) +1024+500);/* WMM */
if (!skb){
return ATBM_NULL;
}
p = ATBM_OS_SKB_DATA(skb);
reply = (struct atbmwifi_ieee80211_mgmt *) p;
atbm_memset(p, 0, sizeof(struct atbmwifi_ieee80211_mgmt));
reply->frame_control = atbm_cpu_to_le16(ATBM_IEEE80211_FTYPE_MGMT |
ATBM_IEEE80211_STYPE_ASSOC_RESP);
atbm_memcpy(reply->da, priv->daddr, ATBM_ETH_ALEN);
atbm_memcpy(reply->sa, priv->mac_addr, ATBM_ETH_ALEN);
atbm_memcpy(reply->bssid, priv->bssid, ATBM_ETH_ALEN);
send_len = ATBM_IEEE80211_HDRLEN;
send_len += sizeof(reply->u.assoc_resp);
if(config->privacy)
capab |= ATBM_WLAN_CAPABILITY_PRIVACY;
capab |= ATBM_WLAN_CAPABILITY_SHORT_SLOT_TIME;
capab |= ATBM_WLAN_CAPABILITY_ESS|ATBM_WLAN_CAPABILITY_SHORT_PREAMBLE;
reply->u.assoc_resp.capab_info = capab;
reply->u.assoc_resp.status_code = atbm_cpu_to_le16(status_code);
reply->u.assoc_resp.aid = atbm_cpu_to_le16(aid/*aid=1*/ | BIT(14) | BIT(15));
/* Supported rates */
p = reply->u.assoc_resp.variable;
/* Supported rates */
/* Extended supported rates */
p = atbmwifi_ieee80211_add_rate_ie(p ,(config->band==WSM_PHY_BAND_5G),~0);
p = atbmwifi_ieee80211_add_wmm_param(priv,p);
#if CONFIG_IEEE80211N
p = atbmwifi_ieee80211_add_ht_ie(priv,priv->hw_priv->bands[priv->bss.sta_priv.band],p);
p = atbmwifi_ieee80211_add_ht_operation(priv,p);
#endif /* CONFIG_IEEE80211N */
//p = atbmwifi_ieee80211_add_wpa_ie(priv,p);
#if CONFIG_WPS
if(ies_len > 0){
atbm_memcpy(p, ies, ies_len);
p += ies_len;
}
#endif
#if CONFIG_P2P
if(priv->p2p_ap){
p = atbm_p2p_add_ap_assoc_resp_ie(priv, p);
}
#endif
send_len += p - reply->u.assoc_resp.variable;
atbm_skb_put(skb,send_len);
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_INTFL_DONT_ENCRYPT;
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_CTL_USE_MINRATE;
wifi_printk(WIFI_DBG_MSG,"atbm: atbmwifi_ieee80211_send_assoc_resp() <===\n");
return skb;
}
struct atbm_buff *atbmwifi_ieee80211_send_proberesp(struct atbmwifi_vif *priv,
const atbm_uint8 *ies,
atbm_size_t ies_len)
{
int send_len;
struct atbm_buff *skb=ATBM_NULL;
struct atbmwifi_ieee80211_mgmt *reply;
atbm_uint8 *p=ATBM_NULL;
atbm_uint16 capab =0;
struct atbmwifi_cfg *config = atbmwifi_get_config(priv);
skb = atbm_dev_alloc_skb(
sizeof(struct atbmwifi_ieee80211_mgmt) +1024+500);/* WMM */
if (!skb){
wifi_printk(WIFI_DBG_ERROR,"alloc_skb ATBM_NULL\n");
return ATBM_NULL;
}
p = ATBM_OS_SKB_DATA(skb);
atbm_memset(p, 0, ATBM_OS_SKB_LEN(skb));
reply = (struct atbmwifi_ieee80211_mgmt *) p;
reply->frame_control = atbm_cpu_to_le16(ATBM_IEEE80211_FTYPE_MGMT |
ATBM_IEEE80211_STYPE_PROBE_RESP);
atbm_memcpy(reply->da, priv->daddr, ATBM_ETH_ALEN);
atbm_memcpy(reply->sa, priv->mac_addr, ATBM_ETH_ALEN);
atbm_memcpy(reply->bssid, priv->bssid, ATBM_ETH_ALEN);
send_len = ATBM_IEEE80211_HDRLEN;
send_len += sizeof(reply->u.probe_resp);
if (config->privacy)
capab |= ATBM_WLAN_CAPABILITY_PRIVACY;
capab |= ATBM_WLAN_CAPABILITY_SHORT_SLOT_TIME;
capab |= ATBM_WLAN_CAPABILITY_ESS|ATBM_WLAN_CAPABILITY_SHORT_PREAMBLE;
reply->u.probe_resp.beacon_int = config->beaconInterval;
reply->u.probe_resp.capab_info = capab;
p = reply->u.probe_resp.variable;
/*If hide ssid,probeResponse need to add ssid in ies*/
/* SSID */
*p++ = ATBM_WLAN_EID_SSID;
*p++ = priv->ssid_length;
atbm_memcpy(p,priv->ssid, priv->ssid_length);
p+= priv->ssid_length;
/* Supported rates */
/* Extended supported rates */
p = atbmwifi_ieee80211_add_rate_ie(p ,(config->band==WSM_PHY_BAND_5G),~0);
*p++ = ATBM_WLAN_EID_DS_PARAMS;
*p++ = 1;
*p++ = priv->config.channel_index;
p = atbmwifi_ieee80211_add_wmm_param(priv,p);
#if CONFIG_IEEE80211N
p = atbmwifi_ieee80211_add_ht_ie(priv,priv->hw_priv->bands[priv->config.band],p);
p = atbmwifi_ieee80211_add_ht_operation(priv,p);
#endif /* CONFIG_IEEE80211N */
if (ies_len > 0) {
atbm_memcpy(p,ies, ies_len);
p += ies_len;
}
#if CONFIG_WPS
if(priv->wps_probe_resp_ie){
atbm_memcpy(p, priv->wps_probe_resp_ie, priv->wps_probe_resp_ie_len);
p += priv->wps_probe_resp_ie_len;
}
#endif
#if CONFIG_P2P
if(priv->p2p_ap){
p = atbm_p2p_add_ap_pbresp_ie(priv, p);
}
#endif
send_len += p - reply->u.probe_resp.variable;
atbm_skb_put(skb,send_len);
return skb;
}
/*
* Indicate whether there are frames queued for a station in power-save mode.
*/
int atbmwifi_set_tim(struct atbmwifi_vif *priv, atbm_uint16 aid, ATBM_BOOL set)
{
if ((aid == 0) || (aid > ATBMWIFI__MAX_STA_IN_AP_MODE))
return 0;
if (set != (atbm_test_bit(aid,(atbm_uint32 *)priv->tim_vbitmap) != 0)) {
if (set) {
atbm_set_bit(aid,(atbm_uint32 *)priv->tim_vbitmap);
wifi_printk(WIFI_PS,"updata tim info %x\n",(unsigned int)priv->tim_vbitmap);
priv->pspending_sta_num++;
}
else {
wifi_printk(WIFI_PS,"clear tim info %x\n",(unsigned int)priv->tim_vbitmap);
atbm_clear_bit(aid,(atbm_uint32 *)priv->tim_vbitmap);
priv->pspending_sta_num--;
}
return 1;
}
return 0;
}
atbm_uint8 * atbmwifi_add_tim(atbm_uint8 *frm,
struct atbmwifi_vif *priv,
atbm_uint8 mcast)
{
struct atbmwifi_ieee80211_tim_ie *tim_ie = (struct atbmwifi_ieee80211_tim_ie *)frm;
atbm_uint8 timoff;
atbm_uint8 timlen=0;
atbm_uint8 i;
if (priv->pspending_sta_num != 0) {
timoff = WIFI_TIMBITMAP_LEN; /* impossibly large */
for (i = 0; i < WIFI_TIMBITMAP_LEN; i++) {
if (priv->tim_vbitmap[i]) {
timoff = i & ATBM_TIM_BITCTL_UCAST_MASK;
break;
}
}
for (i = WIFI_TIMBITMAP_LEN-1; i >= timoff; i--) {
if (priv->tim_vbitmap[i])
break;
}
timlen = 1 + (i - timoff);
}
else {
timoff = 0;
timlen = 1;
}
/* update information element */
tim_ie->tim_ie= ATBM_WLAN_EID_TIM;
tim_ie->tim_len = 3 + timlen;
tim_ie->dtim_count = 0;
tim_ie->dtim_period= priv->config.DTIMPeriod;
tim_ie->tim_bitmapctl = timoff;
if (mcast && (tim_ie->dtim_count == 0))
tim_ie->tim_bitmapctl |= ATBM_TIM_BITCTL_MCAST;
else
tim_ie->tim_bitmapctl &= ~ATBM_TIM_BITCTL_MCAST;
atbm_memcpy(tim_ie->tim_vbitmap, priv->tim_vbitmap + timoff,
timlen);
return ((atbm_uint8 *)frm+tim_ie->tim_len+2);
}
struct atbm_buff *atbmwifi_ieee80211_send_beacon(struct atbmwifi_vif *priv,const atbm_uint8 *ies, atbm_size_t ies_len)
{
int send_len;
struct atbm_buff *skb=ATBM_NULL;
struct atbmwifi_ieee80211_mgmt *beacon;
atbm_uint8 *p=ATBM_NULL;
atbm_uint16 capab =0;
struct atbmwifi_cfg *config = atbmwifi_get_config(priv);
skb = atbm_dev_alloc_skb(
sizeof(struct atbmwifi_ieee80211_mgmt) +1024+ies_len);/* WMM */
if (!skb){
wifi_printk(WIFI_DBG_ERROR,"alloc_skb ATBM_NULL \n");
return ATBM_NULL;
}
p = ATBM_OS_SKB_DATA(skb);
atbm_memset(p, 0, ATBM_OS_SKB_LEN(skb));
beacon = (struct atbmwifi_ieee80211_mgmt *) p;
beacon->frame_control = atbm_cpu_to_le16(ATBM_IEEE80211_FTYPE_MGMT |
ATBM_IEEE80211_STYPE_BEACON);
//atbm_memcpy(beacon->da, priv->daddr, ATBM_ETH_ALEN);
atbm_memset(beacon->da, 0xff, ATBM_ETH_ALEN);
atbm_memcpy(beacon->sa, priv->mac_addr, ATBM_ETH_ALEN);
atbm_memcpy(beacon->bssid, priv->bssid, ATBM_ETH_ALEN);
send_len = ATBM_IEEE80211_HDRLEN;
send_len += sizeof(beacon->u.beacon);
if (config->privacy)
capab |= ATBM_WLAN_CAPABILITY_PRIVACY;
capab |= ATBM_WLAN_CAPABILITY_SHORT_SLOT_TIME;
capab |= ATBM_WLAN_CAPABILITY_ESS|ATBM_WLAN_CAPABILITY_SHORT_PREAMBLE;
beacon->u.beacon.beacon_int = config->beaconInterval;
beacon->u.beacon.capab_info = capab;
p = beacon->u.beacon.variable;
if(!config->hide_ssid/*hide_ssid*/){
/* ssid*/
*p++ = ATBM_WLAN_EID_SSID;
*p++ = priv->ssid_length;
atbm_memcpy(p,priv->ssid, priv->ssid_length);
p += priv->ssid_length;
}else{
/*hide ssid need set ssidLen=0 or set ssidLen=1&&ssid=0*/
*p++ = ATBM_WLAN_EID_SSID;
*p++ = 0;
}
/* Supported rates */
/* Extended supported rates */
p = atbmwifi_ieee80211_add_rate_ie(p ,(config->band==WSM_PHY_BAND_5G),~0);
*p++ = ATBM_WLAN_EID_DS_PARAMS;
*p++ = 1;
*p++ = priv->config.channel_index;
/* Supported ERP */
*p++ = ATBM_WLAN_EID_ERP_INFO;
*p++ = 1;
*p++ =BIT(2);
p = atbmwifi_ieee80211_add_wmm_param(priv,p);
p = atbmwifi_add_tim(p,priv,0);
#if CONFIG_IEEE80211N
p = atbmwifi_ieee80211_add_ht_ie(priv,priv->hw_priv->bands[config->band], p);
p = atbmwifi_ieee80211_add_ht_operation(priv,p);
#endif /* CONFIG_IEEE80211N */
if (ies_len > 0) {
atbm_memcpy(p,ies, ies_len);
p += ies_len;
}
#if CONFIG_WPS
if(priv->wps_beacon_ie != ATBM_NULL){
wifi_printk(WIFI_DBG_ERROR, "set wps_beacon_ie \n");
atbm_memcpy(p, priv->wps_beacon_ie, priv->wps_beacon_ie_len);
p += priv->wps_beacon_ie_len;
}
#endif
#if CONFIG_P2P
if(priv->p2p_ap){
p = atbm_p2p_add_ap_beacon_ie(priv, p);
}
#endif
send_len += p - beacon->u.beacon.variable;
atbm_skb_put(skb,send_len);
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_INTFL_DONT_ENCRYPT;
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_CTL_USE_MINRATE;
return skb;
}
struct atbm_buff * atbmwifi_ieee80211_send_auth(struct atbmwifi_vif *priv,
atbm_uint16 transaction, atbm_uint16 auth_alg, const atbm_uint8 *da,const atbm_uint8 *bssid,atbm_uint16 resp)
{
struct atbm_buff *skb;
struct atbmwifi_ieee80211_mgmt *mgmt;
int err=1;
int alloc_len = sizeof(*mgmt) + 6 + priv->extra_ie_len;
int extra_sae_len = 0;
#if CONFIG_SAE
struct wpa_supplicant *wpa_s = ATBM_NULL;
struct hostapd_data *hapd = ATBM_NULL;
if(atbmwifi_is_sta_mode(priv->iftype)){
wpa_s = (struct wpa_supplicant *)priv->appdata;
if(wpa_s && wpa_s->sae_data){
extra_sae_len = wpabuf_len(wpa_s->sae_data) - 4;
}
}else{
hapd = (struct hostapd_data *)priv->appdata;
if(hapd && hapd->sae_data){
extra_sae_len = wpabuf_len(hapd->sae_data);
}
}
#endif
skb = atbm_dev_alloc_skb(alloc_len + extra_sae_len);
if (!skb)
{
wifi_printk(WIFI_TX,"<ERROR> send_auth alloc skb \n");
return ATBM_NULL;
}
wifi_printk(WIFI_WPA,"send_auth alg(%d),transaction(%d),ielen(%d)\n",auth_alg,transaction,priv->extra_ie_len);
mgmt = (struct atbmwifi_ieee80211_mgmt *) atbm_skb_put(skb, 24 + 6);
atbm_memset(mgmt, 0, 24 + 6);
mgmt->frame_control = atbm_cpu_to_le16(ATBM_IEEE80211_FTYPE_MGMT|
ATBM_IEEE80211_STYPE_AUTH);
atbm_memcpy(mgmt->da, da, ATBM_ETH_ALEN);
atbm_memcpy(mgmt->sa, priv->mac_addr, ATBM_ETH_ALEN);
atbm_memcpy(mgmt->bssid, bssid, ATBM_ETH_ALEN);
mgmt->u.auth.auth_alg = atbm_cpu_to_le16(auth_alg);
mgmt->u.auth.auth_transaction = atbm_cpu_to_le16(transaction);
mgmt->u.auth.status_code = atbm_cpu_to_le16(resp);
#if CONFIG_SAE
if(extra_sae_len){
if(atbmwifi_is_sta_mode(priv->iftype)){
atbm_memcpy(atbm_skb_put(skb, extra_sae_len), wpabuf_head(wpa_s->sae_data) + 4, extra_sae_len);
}else{
atbm_memcpy(atbm_skb_put(skb, extra_sae_len), wpabuf_head(hapd->sae_data), extra_sae_len);
}
}
#endif
if (priv->extra_ie && priv->extra_ie_len) {
atbm_memcpy(atbm_skb_put(skb, priv->extra_ie_len), priv->extra_ie, priv->extra_ie_len);
}
if (auth_alg == ATBM_WLAN_AUTH_SHARED_KEY && transaction == 3) {
// mgmt->frame_control |= atbm_cpu_to_le16(ATBM_IEEE80211_FCTL_PROTECTED);
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_INTFL_DONT_ENCRYPT;
ATBM_WARN_ON_FUNC(err);
return skb;
}
#if CONFIG_P2P
if(priv->p2pdata){
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_CTL_NO_CCK_RATE;
}else
#endif
{
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_CTL_USE_MINRATE;
}
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_INTFL_DONT_ENCRYPT;
return skb;
}
struct atbm_buff * atbmwifi_ieee80211_send_deauth(struct atbmwifi_vif *priv,const atbm_uint8 *da,const atbm_uint8 *bssid,atbm_uint16 reason)
{
// struct atbmwifi_common * hw_priv = priv->hw_priv;
struct atbm_buff *skb;
struct atbmwifi_ieee80211_mgmt *mgmt;
// int err=1;
skb = atbm_dev_alloc_skb(sizeof(*mgmt) + 2);
if (!skb)
{
wifi_printk(WIFI_TX,"<ERROR> send_auth alloc skb \n");
return ATBM_NULL;
}
wifi_printk(WIFI_TX,"send_deauth reason(%d)\n",reason);
mgmt = (struct atbmwifi_ieee80211_mgmt *) atbm_skb_put(skb, 24 + 2);
atbm_memset(mgmt, 0, 24 + 2);
mgmt->frame_control = atbm_cpu_to_le16(ATBM_IEEE80211_FTYPE_MGMT|
ATBM_IEEE80211_STYPE_DEAUTH);
atbm_memcpy(mgmt->da, da, ATBM_ETH_ALEN);
atbm_memcpy(mgmt->sa, priv->mac_addr, ATBM_ETH_ALEN);
atbm_memcpy(mgmt->bssid, bssid, ATBM_ETH_ALEN);
mgmt->u.deauth.reason_code = atbm_cpu_to_le16(reason);
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_INTFL_DONT_ENCRYPT;
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_CTL_USE_MINRATE;
return skb;
}
int atbmwifi_ieee80211_tx_mgmt_deauth(struct atbmwifi_vif *priv,const atbm_uint8 *da,const atbm_uint8 *bssid,atbm_uint16 reason)
{
struct atbm_buff *skb;
skb = atbmwifi_ieee80211_send_deauth(priv,da,bssid,reason);
if(skb == ATBM_NULL)
return -1;
atbmwifi_tx(priv->hw_priv,skb,priv);
return 0;
}
#ifdef CONFIG_IEEE80211W
struct atbm_buff *atbmwifi_ieee80211_send_saquery(struct atbmwifi_vif *priv,const atbm_uint8 *da,const atbm_uint8 *bssid, int dir, const atbm_uint8 *trans_id)
{
struct atbm_buff *skb;
struct atbmwifi_ieee80211_mgmt *mgmt;
struct wsm_protected_mgmt_policy mgmt_policy;
skb = atbm_dev_alloc_skb(100);
if (!skb)
{
wifi_printk(WIFI_TX,"<ERROR> send_auth alloc skb \n");
return ATBM_NULL;
}
mgmt = (struct atbmwifi_ieee80211_mgmt *) atbm_skb_put(skb, 24);
atbm_memset(mgmt, 0, 24 + 6);
mgmt->frame_control = atbm_cpu_to_le16(ATBM_IEEE80211_FTYPE_MGMT|
ATBM_IEEE80211_STYPE_ACTION);
atbm_memcpy(mgmt->da, da, ATBM_ETH_ALEN);
atbm_memcpy(mgmt->sa, priv->mac_addr, ATBM_ETH_ALEN);
atbm_memcpy(mgmt->bssid, bssid, ATBM_ETH_ALEN);
atbm_skb_put(skb, 1 + sizeof(mgmt->u.action.u.sa_query));
mgmt->u.action.category = ATBM_WLAN_CATEGORY_SA_QUERY;
mgmt->u.action.u.sa_query.action = dir;
atbm_memcpy(mgmt->u.action.u.sa_query.trans_id, trans_id, WLAN_SA_QUERY_TR_ID_LEN);
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_CTL_USE_MINRATE;
return skb;
}
#endif
void atbmwifi_ieee80211_send_addba_request(struct atbmwifi_vif *priv,
const atbm_uint8 *da, atbm_uint16 tid,
atbm_uint8 dialog_token, atbm_uint16 start_seq_num,
atbm_uint16 agg_size, atbm_uint16 timeout)
{
struct atbm_buff *skb;
struct atbmwifi_ieee80211_mgmt *mgmt;
atbm_uint16 capab;
skb = atbm_dev_alloc_skb(sizeof(*mgmt));
if (!skb)
return;
//skb_reserve(skb, local->hw.extra_tx_headroom);
mgmt = (struct atbmwifi_ieee80211_mgmt *) atbm_skb_put(skb, 24);
atbm_memset(mgmt, 0, 24 + 10);
atbm_memcpy(mgmt->da, da, ATBM_ETH_ALEN);
atbm_memcpy(mgmt->sa, priv->mac_addr, ATBM_ETH_ALEN);
if (priv->iftype == ATBM_NL80211_IFTYPE_AP)
atbm_memcpy(mgmt->bssid, priv->mac_addr, ATBM_ETH_ALEN);
else if (priv->iftype == ATBM_NL80211_IFTYPE_STATION)
atbm_memcpy(mgmt->bssid, priv->bss.bssid, ATBM_ETH_ALEN);
mgmt->frame_control = atbm_cpu_to_le16(ATBM_IEEE80211_FTYPE_MGMT |
ATBM_IEEE80211_STYPE_ACTION);
atbm_skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
mgmt->u.action.category = ATBM_WLAN_CATEGORY_BACK;
mgmt->u.action.u.addba_req.action_code = ATBM_WLAN_ACTION_ADDBA_REQ;
mgmt->u.action.u.addba_req.dialog_token = dialog_token;
capab = (atbm_uint32)(1 << 0); /* bit 0 A-MSDU support */
capab |= (atbm_uint32)(1 << 1); /* bit 1 aggregation policy */
capab |= (atbm_uint32)(tid << 2); /* bit 5:2 TID number */
capab |= (atbm_uint32)(agg_size << 6); /* bit 15:6 max size of aggergation */
mgmt->u.action.u.addba_req.capab = atbm_cpu_to_le16(capab);
mgmt->u.action.u.addba_req.timeout = atbm_cpu_to_le16(timeout);
mgmt->u.action.u.addba_req.start_seq_num =
atbm_cpu_to_le16(start_seq_num << 4);
atbmwifi_tx(priv->hw_priv,skb,priv);
}
void ieee80211_send_delba(struct atbmwifi_vif *priv,
const atbm_uint8 *da, atbm_uint16 tid,
atbm_uint16 initiator, atbm_uint16 reason_code)
{
struct atbm_buff *skb;
struct atbmwifi_ieee80211_mgmt *mgmt;
atbm_uint16 params;
skb = atbm_dev_alloc_skb(sizeof(*mgmt));
if (!skb)
return;
mgmt = (struct atbmwifi_ieee80211_mgmt *) atbm_skb_put(skb, 24);
atbm_memset(mgmt, 0, 24 + 5);
atbm_memcpy(mgmt->da, da, ATBM_ETH_ALEN);
atbm_memcpy(mgmt->sa, priv->mac_addr, ATBM_ETH_ALEN);
if (priv->iftype == ATBM_NL80211_IFTYPE_AP)
atbm_memcpy(mgmt->bssid, priv->mac_addr, ATBM_ETH_ALEN);
else if (priv->iftype == ATBM_NL80211_IFTYPE_STATION)
atbm_memcpy(mgmt->bssid, priv->bss.bssid, ATBM_ETH_ALEN);
mgmt->frame_control = atbm_cpu_to_le16(ATBM_IEEE80211_FTYPE_MGMT |
ATBM_IEEE80211_STYPE_ACTION);
atbm_skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba));
mgmt->u.action.category = ATBM_WLAN_CATEGORY_BACK;
mgmt->u.action.u.delba.action_code = ATBM_WLAN_ACTION_DELBA;
params = (atbm_uint16)(initiator << 11); /* bit 11 initiator */
params |= (atbm_uint16)(tid << 12); /* bit 15:12 TID number */
mgmt->u.action.u.delba.params = atbm_cpu_to_le16(params);
mgmt->u.action.u.delba.reason_code = atbm_cpu_to_le16(reason_code);
atbmwifi_tx(priv->hw_priv,skb,priv);
}
void ieee80211_send_addba_resp(struct atbmwifi_vif *priv, atbm_uint8 *da, atbm_uint16 tid,
atbm_uint8 dialog_token, atbm_uint16 status, atbm_uint16 policy,
atbm_uint16 buf_size, atbm_uint16 timeout)
{
//struct ieee80211_local *local = sdata->local;
struct atbm_buff *skb;
struct atbmwifi_ieee80211_mgmt *mgmt;
atbm_uint16 capab;
skb = atbm_dev_alloc_skb(sizeof(*mgmt));
if (!skb)
return;
//atbm_skb_reserve(skb, local->hw.extra_tx_headroom);
mgmt = (struct atbmwifi_ieee80211_mgmt *) atbm_skb_put(skb, 24);
atbm_memset(mgmt, 0, 24 + 8);
atbm_memcpy(mgmt->da, da, ATBM_ETH_ALEN);
atbm_memcpy(mgmt->sa, priv->mac_addr, ATBM_ETH_ALEN);
if (priv->iftype == ATBM_NL80211_IFTYPE_AP)
atbm_memcpy(mgmt->bssid, priv->mac_addr, ATBM_ETH_ALEN);
else if (priv->iftype == ATBM_NL80211_IFTYPE_STATION)
atbm_memcpy(mgmt->bssid, priv->bss.bssid, ATBM_ETH_ALEN);
mgmt->frame_control = atbm_cpu_to_le16(ATBM_IEEE80211_FTYPE_MGMT |
ATBM_IEEE80211_STYPE_ACTION);
atbm_skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
mgmt->u.action.category = ATBM_WLAN_CATEGORY_BACK;
mgmt->u.action.u.addba_resp.action_code = ATBM_WLAN_ACTION_ADDBA_RESP;
mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
capab = (atbm_uint16)(policy << 1); /* bit 1 aggregation policy */
capab |= (atbm_uint16)(tid << 2); /* bit 5:2 TID number */
capab |= (atbm_uint16)(buf_size << 6); /* bit 15:6 max size of aggregation */
mgmt->u.action.u.addba_resp.capab = atbm_cpu_to_le16(capab);
mgmt->u.action.u.addba_resp.timeout = atbm_cpu_to_le16(timeout);
mgmt->u.action.u.addba_resp.status = atbm_cpu_to_le16(status);
atbmwifi_tx(priv->hw_priv,skb,priv);
}
#if NEW_SUPPORT_PS
struct atbm_buff * atbmwifi_ieee80211_NullData(struct atbmwifi_vif *priv,const atbm_uint8 *da,const atbm_uint8 *bssid)
{
//struct atbmwifi_common * hw_priv = priv->hw_priv;
struct atbm_buff *skb;
struct atbmwifi_ieee80211_hdr *nulldata;
skb = atbm_dev_alloc_skb(sizeof(struct atbmwifi_ieee80211_hdr));
if (!skb)
{
wifi_printk(WIFI_TX,"<ERROR> send_auth alloc skb \n");
return ATBM_NULL;
}
nulldata = (struct atbmwifi_ieee80211_hdr *) atbm_skb_put(skb, 24);
atbm_memset(nulldata, 0, 24);
nulldata->frame_control = atbm_cpu_to_le16(ATBM_IEEE80211_FTYPE_DATA|
ATBM_IEEE80211_STYPE_NULLFUNC);
atbm_memcpy(nulldata->addr1, da, ATBM_ETH_ALEN);
atbm_memcpy(nulldata->addr2, priv->mac_addr, ATBM_ETH_ALEN);
atbm_memcpy(nulldata->addr3, bssid, ATBM_ETH_ALEN);
ATBM_IEEE80211_SKB_TXCB(skb)->flags |=ATBM_IEEE80211_TX_INTFL_DONT_ENCRYPT|
ATBM_IEEE80211_TX_CTL_POLL_RESPONSE;
return skb;
}
struct atbm_buff * atbmwifi_ieee80211_QosNullData(struct atbmwifi_vif *priv,const atbm_uint8 *da,const atbm_uint8 *bssid,atbm_uint8 tid)
{
//struct atbmwifi_common * hw_priv = priv->hw_priv;
struct atbm_buff *skb;
struct atbmwifi_ieee80211_qos_hdr *QosNulldata;
skb = atbm_dev_alloc_skb(sizeof(struct atbmwifi_ieee80211_qos_hdr));
if (!skb)
{
wifi_printk(WIFI_TX,"<ERROR> send_auth alloc skb \n");
return ATBM_NULL;
}
QosNulldata = (struct atbmwifi_ieee80211_qos_hdr *) atbm_skb_put(skb, 26);
atbm_memset(QosNulldata, 0, 26);
QosNulldata->frame_control = atbm_cpu_to_le16(ATBM_IEEE80211_FTYPE_DATA|
ATBM_IEEE80211_STYPE_QOS_NULLFUNC);
atbm_memcpy(QosNulldata->addr1, da, ATBM_ETH_ALEN);
atbm_memcpy(QosNulldata->addr2, priv->mac_addr, ATBM_ETH_ALEN);
atbm_memcpy(QosNulldata->addr3, bssid, ATBM_ETH_ALEN);
QosNulldata->qos_ctrl = tid;
QosNulldata->qos_ctrl |=
atbm_cpu_to_le16(ATBM_IEEE80211_QOS_CTL_EOSP);
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_INTFL_DONT_ENCRYPT|
ATBM_IEEE80211_TX_STATUS_EOSP;
return skb;
}
#endif