mirror of
https://gitee.com/Vancouver2017/luban-lite.git
synced 2025-12-24 21:18:54 +00:00
3285 lines
101 KiB
C
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
|
|
|