From 4e1023445343541731f45debf718090310cff632 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Fri, 12 Jun 2015 00:20:43 +0200 Subject: [PATCH] staging: rtl8188eu: rtw_mlme_ext.c: reorder message callbacks and tables The message handling stored in mlme_sta_tbl and OnAction_tbl are internal and will be declared static, and their declaration removed from rtw_mlme_ext.h, in a later commit. This would break compilation, since they are are referenced before their definition. Reorder these functions and the structures that hold them so that symbols are defined before they are referenced, without the need for forward declarations. This commit only reorders code, there is no content change. Signed-off-by: Luca Ceresoli Cc: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_mlme_ext.c | 6311 ++++++++--------- 1 file changed, 3155 insertions(+), 3156 deletions(-) diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c index 052d0f456956..0d1d4bfc6474 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c @@ -29,42 +29,6 @@ #include #include -static struct mlme_handler mlme_sta_tbl[] = { - {WIFI_ASSOCREQ, "OnAssocReq", &OnAssocReq}, - {WIFI_ASSOCRSP, "OnAssocRsp", &OnAssocRsp}, - {WIFI_REASSOCREQ, "OnReAssocReq", &OnAssocReq}, - {WIFI_REASSOCRSP, "OnReAssocRsp", &OnAssocRsp}, - {WIFI_PROBEREQ, "OnProbeReq", &OnProbeReq}, - {WIFI_PROBERSP, "OnProbeRsp", &OnProbeRsp}, - - /*---------------------------------------------------------- - below 2 are reserved - -----------------------------------------------------------*/ - {0, "DoReserved", &DoReserved}, - {0, "DoReserved", &DoReserved}, - {WIFI_BEACON, "OnBeacon", &OnBeacon}, - {WIFI_ATIM, "OnATIM", &OnAtim}, - {WIFI_DISASSOC, "OnDisassoc", &OnDisassoc}, - {WIFI_AUTH, "OnAuth", &OnAuthClient}, - {WIFI_DEAUTH, "OnDeAuth", &OnDeAuth}, - {WIFI_ACTION, "OnAction", &OnAction}, -}; - -static struct action_handler OnAction_tbl[] = { - {RTW_WLAN_CATEGORY_SPECTRUM_MGMT, "ACTION_SPECTRUM_MGMT", on_action_spct}, - {RTW_WLAN_CATEGORY_QOS, "ACTION_QOS", &OnAction_qos}, - {RTW_WLAN_CATEGORY_DLS, "ACTION_DLS", &OnAction_dls}, - {RTW_WLAN_CATEGORY_BACK, "ACTION_BACK", &OnAction_back}, - {RTW_WLAN_CATEGORY_PUBLIC, "ACTION_PUBLIC", on_action_public}, - {RTW_WLAN_CATEGORY_RADIO_MEASUREMENT, "ACTION_RADIO_MEASUREMENT", &DoReserved}, - {RTW_WLAN_CATEGORY_FT, "ACTION_FT", &DoReserved}, - {RTW_WLAN_CATEGORY_HT, "ACTION_HT", &OnAction_ht}, - {RTW_WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &DoReserved}, - {RTW_WLAN_CATEGORY_WMM, "ACTION_WMM", &OnAction_wmm}, - {RTW_WLAN_CATEGORY_P2P, "ACTION_P2P", &OnAction_p2p}, -}; - - static u8 null_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; /************************************************** @@ -195,1936 +159,1630 @@ int rtw_ch_set_search_ch(struct rt_channel_info *ch_set, const u32 ch) return i; } +struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv) +{ + struct xmit_frame *pmgntframe; + struct xmit_buf *pxmitbuf; + + pmgntframe = rtw_alloc_xmitframe(pxmitpriv); + if (pmgntframe == NULL) { + DBG_88E("%s, alloc xmitframe fail\n", __func__); + return NULL; + } + + pxmitbuf = rtw_alloc_xmitbuf_ext(pxmitpriv); + if (pxmitbuf == NULL) { + DBG_88E("%s, alloc xmitbuf fail\n", __func__); + rtw_free_xmitframe(pxmitpriv, pmgntframe); + return NULL; + } + pmgntframe->frame_tag = MGNT_FRAMETAG; + pmgntframe->pxmitbuf = pxmitbuf; + pmgntframe->buf_addr = pxmitbuf->pbuf; + pxmitbuf->priv_data = pmgntframe; + return pmgntframe; +} + /**************************************************************************** -Following are the initialization functions for WiFi MLME +Following are some TX functions for WiFi MLME *****************************************************************************/ -int init_hw_mlme_ext(struct adapter *padapter) +void update_mgnt_tx_rate(struct adapter *padapter, u8 rate) { - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); - set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); - return _SUCCESS; + pmlmeext->tx_rate = rate; + DBG_88E("%s(): rate = %x\n", __func__, rate); } -static void init_mlme_ext_priv_value(struct adapter *padapter) +void update_mgntframe_attrib(struct adapter *padapter, struct pkt_attrib *pattrib) { - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - unsigned char mixed_datarate[NumRates] = { - _1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, - _9M_RATE_, _12M_RATE_, _18M_RATE_, _24M_RATE_, _36M_RATE_, - _48M_RATE_, _54M_RATE_, 0xff - }; - unsigned char mixed_basicrate[NumRates] = { - _1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, - _12M_RATE_, _24M_RATE_, 0xff, - }; - - atomic_set(&pmlmeext->event_seq, 0); - pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */ - - pmlmeext->cur_channel = padapter->registrypriv.channel; - pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; - pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; - pmlmeext->oper_channel = pmlmeext->cur_channel; - pmlmeext->oper_bwmode = pmlmeext->cur_bwmode; - pmlmeext->oper_ch_offset = pmlmeext->cur_ch_offset; - pmlmeext->retry = 0; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); - pmlmeext->cur_wireless_mode = padapter->registrypriv.wireless_mode; + memset((u8 *)(pattrib), 0, sizeof(struct pkt_attrib)); - memcpy(pmlmeext->datarate, mixed_datarate, NumRates); - memcpy(pmlmeext->basicrate, mixed_basicrate, NumRates); + pattrib->hdrlen = 24; + pattrib->nr_frags = 1; + pattrib->priority = 7; + pattrib->mac_id = 0; + pattrib->qsel = 0x12; - pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB; + pattrib->pktlen = 0; - pmlmeext->sitesurvey_res.state = SCAN_DISABLE; - pmlmeext->sitesurvey_res.channel_idx = 0; - pmlmeext->sitesurvey_res.bss_cnt = 0; - pmlmeext->scan_abort = false; + if (pmlmeext->cur_wireless_mode & WIRELESS_11B) + pattrib->raid = 6;/* b mode */ + else + pattrib->raid = 5;/* a/g mode */ - pmlmeinfo->state = WIFI_FW_NULL_STATE; - pmlmeinfo->reauth_count = 0; - pmlmeinfo->reassoc_count = 0; - pmlmeinfo->link_count = 0; - pmlmeinfo->auth_seq = 0; - pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; - pmlmeinfo->key_index = 0; - pmlmeinfo->iv = 0; + pattrib->encrypt = _NO_PRIVACY_; + pattrib->bswenc = false; - pmlmeinfo->enc_algo = _NO_PRIVACY_; - pmlmeinfo->authModeToggle = 0; + pattrib->qos_en = false; + pattrib->ht_en = false; + pattrib->bwmode = HT_CHANNEL_WIDTH_20; + pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + pattrib->sgi = false; - memset(pmlmeinfo->chg_txt, 0, 128); + pattrib->seqnum = pmlmeext->mgnt_seq; - pmlmeinfo->slotTime = SHORT_SLOT_TIME; - pmlmeinfo->preamble_mode = PREAMBLE_AUTO; + pattrib->retry_ctrl = true; +} - pmlmeinfo->dialogToken = 0; +void dump_mgntframe(struct adapter *padapter, struct xmit_frame *pmgntframe) +{ + if (padapter->bSurpriseRemoved || padapter->bDriverStopped) + return; - pmlmeext->action_public_rxseq = 0xffff; - pmlmeext->action_public_dialog_token = 0xff; + rtw_hal_mgnt_xmit(padapter, pmgntframe); } -static int has_channel(struct rt_channel_info *channel_set, - u8 chanset_size, - u8 chan) { - int i; +s32 dump_mgntframe_and_wait(struct adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms) +{ + s32 ret = _FAIL; + struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf; + struct submit_ctx sctx; - for (i = 0; i < chanset_size; i++) { - if (channel_set[i].ChannelNum == chan) - return 1; - } - return 0; -} + if (padapter->bSurpriseRemoved || padapter->bDriverStopped) + return ret; -static void init_channel_list(struct adapter *padapter, struct rt_channel_info *channel_set, - u8 chanset_size, - struct p2p_channels *channel_list) { - struct p2p_oper_class_map op_class[] = { - { IEEE80211G, 81, 1, 13, 1, BW20 }, - { IEEE80211G, 82, 14, 14, 1, BW20 }, - { -1, 0, 0, 0, 0, BW20 } - }; + rtw_sctx_init(&sctx, timeout_ms); + pxmitbuf->sctx = &sctx; - int cla, op; + ret = rtw_hal_mgnt_xmit(padapter, pmgntframe); - cla = 0; + if (ret == _SUCCESS) + ret = rtw_sctx_wait(&sctx); - for (op = 0; op_class[op].op_class; op++) { - u8 ch; - struct p2p_oper_class_map *o = &op_class[op]; - struct p2p_reg_class *reg = NULL; + return ret; +} - for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { - if (!has_channel(channel_set, chanset_size, ch)) { - continue; - } +s32 dump_mgntframe_and_wait_ack(struct adapter *padapter, struct xmit_frame *pmgntframe) +{ + s32 ret = _FAIL; + u32 timeout_ms = 500;/* 500ms */ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - if ((0 == padapter->registrypriv.ht_enable) && (8 == o->inc)) - continue; + if (padapter->bSurpriseRemoved || padapter->bDriverStopped) + return -1; - if ((0 == (padapter->registrypriv.cbw40_enable & BIT(1))) && - ((BW40MINUS == o->bw) || (BW40PLUS == o->bw))) - continue; + _enter_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL); + pxmitpriv->ack_tx = true; - if (reg == NULL) { - reg = &channel_list->reg_class[cla]; - cla++; - reg->reg_class = o->op_class; - reg->channels = 0; - } - reg->channel[reg->channels] = ch; - reg->channels++; - } + pmgntframe->ack_report = 1; + if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS) { + ret = rtw_ack_tx_wait(pxmitpriv, timeout_ms); } - channel_list->reg_classes = cla; + + pxmitpriv->ack_tx = false; + mutex_unlock(&pxmitpriv->ack_tx_mutex); + + return ret; } -static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan, struct rt_channel_info *channel_set) +static int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode) { - u8 index, chanset_size = 0; - u8 b2_4GBand = false; - u8 Index2G = 0; + u8 *ssid_ie; + int ssid_len_ori; + int len_diff = 0; - memset(channel_set, 0, sizeof(struct rt_channel_info) * MAX_CHANNEL_NUM); + ssid_ie = rtw_get_ie(ies, WLAN_EID_SSID, &ssid_len_ori, ies_len); - if (ChannelPlan >= RT_CHANNEL_DOMAIN_MAX && ChannelPlan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) { - DBG_88E("ChannelPlan ID %x error !!!!!\n", ChannelPlan); - return chanset_size; - } + if (ssid_ie && ssid_len_ori > 0) { + switch (hidden_ssid_mode) { + case 1: { + u8 *next_ie = ssid_ie + 2 + ssid_len_ori; + u32 remain_len = 0; - if (padapter->registrypriv.wireless_mode & WIRELESS_11G) { - b2_4GBand = true; - if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == ChannelPlan) - Index2G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index2G; - else - Index2G = RTW_ChannelPlanMap[ChannelPlan].Index2G; - } + remain_len = ies_len - (next_ie - ies); - if (b2_4GBand) { - for (index = 0; index < RTW_ChannelPlan2G[Index2G].Len; index++) { - channel_set[chanset_size].ChannelNum = RTW_ChannelPlan2G[Index2G].Channel[index]; + ssid_ie[1] = 0; + memcpy(ssid_ie+2, next_ie, remain_len); + len_diff -= ssid_len_ori; - if ((RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN == ChannelPlan) ||/* Channel 1~11 is active, and 12~14 is passive */ - (RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G == ChannelPlan)) { - if (channel_set[chanset_size].ChannelNum >= 1 && channel_set[chanset_size].ChannelNum <= 11) - channel_set[chanset_size].ScanType = SCAN_ACTIVE; - else if ((channel_set[chanset_size].ChannelNum >= 12 && channel_set[chanset_size].ChannelNum <= 14)) - channel_set[chanset_size].ScanType = SCAN_PASSIVE; - } else if (RT_CHANNEL_DOMAIN_WORLD_WIDE_13 == ChannelPlan || - RT_CHANNEL_DOMAIN_2G_WORLD == Index2G) {/* channel 12~13, passive scan */ - if (channel_set[chanset_size].ChannelNum <= 11) - channel_set[chanset_size].ScanType = SCAN_ACTIVE; - else - channel_set[chanset_size].ScanType = SCAN_PASSIVE; - } else { - channel_set[chanset_size].ScanType = SCAN_ACTIVE; - } - - chanset_size++; + break; + } + case 2: + memset(&ssid_ie[2], 0, ssid_len_ori); + break; + default: + break; } } - return chanset_size; + + return len_diff; } -int init_mlme_ext_priv(struct adapter *padapter) +void issue_beacon(struct adapter *padapter, int timeout_ms) { - struct registry_priv *pregistrypriv = &padapter->registrypriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + __le16 *fctrl; + unsigned int rate_len; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); + u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - pmlmeext->padapter = padapter; - - init_mlme_ext_priv_value(padapter); - pmlmeinfo->bAcceptAddbaReq = pregistrypriv->bAcceptAddbaReq; + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) { + DBG_88E("%s, alloc mgnt frame fail\n", __func__); + return; + } +#if defined(CONFIG_88EU_AP_MODE) + spin_lock_bh(&pmlmepriv->bcn_update_lock); +#endif /* if defined (CONFIG_88EU_AP_MODE) */ - init_mlme_ext_timer(padapter); + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + pattrib->qsel = 0x10; -#ifdef CONFIG_88EU_AP_MODE - init_mlme_ap_info(padapter); -#endif + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - pmlmeext->max_chan_nums = init_channel_set(padapter, pmlmepriv->ChannelPlan, pmlmeext->channel_set); - init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list); + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; - pmlmeext->chan_scan_time = SURVEY_TO; - pmlmeext->mlmeext_init = true; + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; - pmlmeext->active_keep_alive_check = true; + memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); + memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); + memcpy(pwlanhdr->addr3, cur_network->MacAddress, ETH_ALEN); - return _SUCCESS; -} + SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); + /* pmlmeext->mgnt_seq++; */ + SetFrameSubType(pframe, WIFI_BEACON); -void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext) -{ - struct adapter *padapter = pmlmeext->padapter; + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); - if (!padapter) - return; + if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { + int len_diff; + u8 *wps_ie; + uint wps_ielen; + u8 sr = 0; + memcpy(pframe, cur_network->IEs, cur_network->IELength); + len_diff = update_hidden_ssid( + pframe+_BEACON_IE_OFFSET_ + , cur_network->IELength-_BEACON_IE_OFFSET_ + , pmlmeinfo->hidden_ssid_mode + ); + pframe += (cur_network->IELength+len_diff); + pattrib->pktlen += (cur_network->IELength+len_diff); + wps_ie = rtw_get_wps_ie(pmgntframe->buf_addr+TXDESC_OFFSET+sizeof(struct rtw_ieee80211_hdr_3addr)+_BEACON_IE_OFFSET_, + pattrib->pktlen-sizeof(struct rtw_ieee80211_hdr_3addr)-_BEACON_IE_OFFSET_, NULL, &wps_ielen); + if (wps_ie && wps_ielen > 0) + rtw_get_wps_attr_content(wps_ie, wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL); + if (sr != 0) + set_fwstate(pmlmepriv, WIFI_UNDER_WPS); + else + _clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS); - if (padapter->bDriverStopped) { - del_timer_sync(&pmlmeext->survey_timer); - del_timer_sync(&pmlmeext->link_timer); + goto _issue_bcn; } -} -static void _mgt_dispatcher(struct adapter *padapter, struct mlme_handler *ptable, struct recv_frame *precv_frame) -{ - u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - u8 *pframe = precv_frame->rx_data; + /* below for ad-hoc mode */ - if (ptable->func) { - /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ - if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) && - memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN)) - return; - ptable->func(padapter, precv_frame); - } -} + /* timestamp will be inserted by hardware */ + pframe += 8; + pattrib->pktlen += 8; -void mgt_dispatcher(struct adapter *padapter, struct recv_frame *precv_frame) -{ - int index; - struct mlme_handler *ptable; -#ifdef CONFIG_88EU_AP_MODE - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -#endif /* CONFIG_88EU_AP_MODE */ - u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - u8 *pframe = precv_frame->rx_data; - struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(pframe)); + /* beacon interval: 2 bytes */ - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, - ("+mgt_dispatcher: type(0x%x) subtype(0x%x)\n", - GetFrameType(pframe), GetFrameSubType(pframe))); + memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); - if (GetFrameType(pframe) != WIFI_MGT_TYPE) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("mgt_dispatcher: type(0x%x) error!\n", GetFrameType(pframe))); - return; - } + pframe += 2; + pattrib->pktlen += 2; - /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ - if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) && - memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN)) - return; + /* capability info: 2 bytes */ - ptable = mlme_sta_tbl; + memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); - index = GetFrameSubType(pframe) >> 4; + pframe += 2; + pattrib->pktlen += 2; - if (index > 13) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Currently we do not support reserved sub-fr-type=%d\n", index)); - return; - } - ptable += index; + /* SSID */ + pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen); - if (psta != NULL) { - if (GetRetry(pframe)) { - if (precv_frame->attrib.seq_num == - psta->RxMgmtFrameSeqNum) { - /* drop the duplicate management frame */ - DBG_88E("Drop duplicate management frame with seq_num=%d.\n", - precv_frame->attrib.seq_num); - return; - } - } - psta->RxMgmtFrameSeqNum = precv_frame->attrib.seq_num; - } + /* supported rates... */ + rate_len = rtw_get_rateset_len(cur_network->SupportedRates); + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pattrib->pktlen); -#ifdef CONFIG_88EU_AP_MODE - switch (GetFrameSubType(pframe)) { - case WIFI_AUTH: - if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) - ptable->func = &OnAuth; - else - ptable->func = &OnAuthClient; - /* fall through */ - case WIFI_ASSOCREQ: - case WIFI_REASSOCREQ: - case WIFI_PROBEREQ: - case WIFI_BEACON: - case WIFI_ACTION: - _mgt_dispatcher(padapter, ptable, precv_frame); - break; - default: - _mgt_dispatcher(padapter, ptable, precv_frame); - break; - } -#else - _mgt_dispatcher(padapter, ptable, precv_frame); -#endif -} + /* DS parameter set */ + pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen); -/**************************************************************************** + { + u8 erpinfo = 0; + u32 ATIMWindow; + /* IBSS Parameter Set... */ + ATIMWindow = 0; + pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen); -Following are the callback functions for each subtype of the management frames + /* ERP IE */ + pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen); + } -*****************************************************************************/ + /* EXTERNDED SUPPORTED RATE */ + if (rate_len > 8) + pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen); + /* todo:HT for adhoc */ +_issue_bcn: -unsigned int OnProbeReq(struct adapter *padapter, struct recv_frame *precv_frame) -{ - unsigned int ielen; - unsigned char *p; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct wlan_bssid_ex *cur = &(pmlmeinfo->network); - u8 *pframe = precv_frame->rx_data; - uint len = precv_frame->len; - u8 is_valid_p2p_probereq = false; +#if defined(CONFIG_88EU_AP_MODE) + pmlmepriv->update_bcn = false; - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) - return _SUCCESS; + spin_unlock_bh(&pmlmepriv->bcn_update_lock); +#endif /* if defined (CONFIG_88EU_AP_MODE) */ - if (!check_fwstate(pmlmepriv, _FW_LINKED) && - !check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE)) - return _SUCCESS; + if ((pattrib->pktlen + TXDESC_SIZE) > 512) { + DBG_88E("beacon frame too large\n"); + return; + } - p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ielen, - len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); + pattrib->last_txcmdsz = pattrib->pktlen; - /* check (wildcard) SSID */ - if (p != NULL) { - if (is_valid_p2p_probereq) - goto _issue_probersp; + /* DBG_88E("issue bcn_sz=%d\n", pattrib->last_txcmdsz); */ + if (timeout_ms > 0) + dump_mgntframe_and_wait(padapter, pmgntframe, timeout_ms); + else + dump_mgntframe(padapter, pmgntframe); +} - if ((ielen != 0 && memcmp((void *)(p+2), (void *)cur->Ssid.Ssid, cur->Ssid.SsidLength)) || - (ielen == 0 && pmlmeinfo->hidden_ssid_mode)) - return _SUCCESS; - -_issue_probersp: +void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p_probereq) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + __le16 *fctrl; + unsigned char *mac, *bssid; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); +#if defined(CONFIG_88EU_AP_MODE) + u8 *pwps_ie; + uint wps_ielen; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; +#endif /* if defined (CONFIG_88EU_AP_MODE) */ + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); + unsigned int rate_len; - if (check_fwstate(pmlmepriv, _FW_LINKED) && - pmlmepriv->cur_network.join_res) - issue_probersp(padapter, get_sa(pframe), is_valid_p2p_probereq); + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) { + DBG_88E("%s, alloc mgnt frame fail\n", __func__); + return; } - return _SUCCESS; -} -unsigned int OnProbeRsp(struct adapter *padapter, struct recv_frame *precv_frame) -{ - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); - if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { - report_survey_event(padapter, precv_frame); - return _SUCCESS; - } + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - return _SUCCESS; -} + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -unsigned int OnBeacon(struct adapter *padapter, struct recv_frame *precv_frame) -{ - int cam_idx; - struct sta_info *psta; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct sta_priv *pstapriv = &padapter->stapriv; - u8 *pframe = precv_frame->rx_data; - uint len = precv_frame->len; - struct wlan_bssid_ex *pbss; - int ret = _SUCCESS; - struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); + mac = myid(&(padapter->eeprompriv)); + bssid = cur_network->MacAddress; - if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { - report_survey_event(padapter, precv_frame); - return _SUCCESS; - } + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + memcpy(pwlanhdr->addr1, da, ETH_ALEN); + memcpy(pwlanhdr->addr2, mac, ETH_ALEN); + memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); - if (!memcmp(GetAddr3Ptr(pframe), pnetwork->MacAddress, ETH_ALEN)) { - if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) { - /* we should update current network before auth, or some IE is wrong */ - pbss = (struct wlan_bssid_ex *)rtw_malloc(sizeof(struct wlan_bssid_ex)); - if (pbss) { - if (collect_bss_info(padapter, precv_frame, pbss) == _SUCCESS) { - update_network(&(pmlmepriv->cur_network.network), pbss, padapter, true); - rtw_get_bcn_info(&(pmlmepriv->cur_network)); - } - kfree(pbss); - } + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(fctrl, WIFI_PROBERSP); - /* check the vendor of the assoc AP */ - pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pframe+sizeof(struct rtw_ieee80211_hdr_3addr), len-sizeof(struct rtw_ieee80211_hdr_3addr)); + pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = pattrib->hdrlen; + pframe += pattrib->hdrlen; - /* update TSF Value */ - update_TSF(pmlmeext, pframe, len); + if (cur_network->IELength > MAX_IE_SZ) + return; - /* start auth */ - start_clnt_auth(padapter); +#if defined(CONFIG_88EU_AP_MODE) + if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { + pwps_ie = rtw_get_wps_ie(cur_network->IEs+_FIXED_IE_LENGTH_, cur_network->IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen); - return _SUCCESS; - } + /* inerset & update wps_probe_resp_ie */ + if ((pmlmepriv->wps_probe_resp_ie != NULL) && pwps_ie && (wps_ielen > 0)) { + uint wps_offset, remainder_ielen; + u8 *premainder_ie; - if (((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) && (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) { - psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); - if (psta != NULL) { - ret = rtw_check_bcn_info(padapter, pframe, len); - if (!ret) { - DBG_88E_LEVEL(_drv_info_, "ap has changed, disconnect now\n "); - receive_disconnect(padapter, pmlmeinfo->network.MacAddress , 65535); - return _SUCCESS; - } - /* update WMM, ERP in the beacon */ - /* todo: the timer is used instead of the number of the beacon received */ - if ((sta_rx_pkts(psta) & 0xf) == 0) - update_beacon_info(padapter, pframe, len, psta); - } - } else if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { - psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); - if (psta != NULL) { - /* update WMM, ERP in the beacon */ - /* todo: the timer is used instead of the number of the beacon received */ - if ((sta_rx_pkts(psta) & 0xf) == 0) - update_beacon_info(padapter, pframe, len, psta); - } else { - /* allocate a new CAM entry for IBSS station */ - cam_idx = allocate_fw_sta_entry(padapter); - if (cam_idx == NUM_STA) - goto _END_ONBEACON_; + wps_offset = (uint)(pwps_ie - cur_network->IEs); - /* get supported rate */ - if (update_sta_support_rate(padapter, (pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_), (len - WLAN_HDR_A3_LEN - _BEACON_IE_OFFSET_), cam_idx) == _FAIL) { - pmlmeinfo->FW_sta_info[cam_idx].status = 0; - goto _END_ONBEACON_; - } + premainder_ie = pwps_ie + wps_ielen; - /* update TSF Value */ - update_TSF(pmlmeext, pframe, len); + remainder_ielen = cur_network->IELength - wps_offset - wps_ielen; - /* report sta add event */ - report_add_sta_event(padapter, GetAddr2Ptr(pframe), cam_idx); + memcpy(pframe, cur_network->IEs, wps_offset); + pframe += wps_offset; + pattrib->pktlen += wps_offset; + + wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1];/* to get ie data len */ + if ((wps_offset+wps_ielen+2) <= MAX_IE_SZ) { + memcpy(pframe, pmlmepriv->wps_probe_resp_ie, wps_ielen+2); + pframe += wps_ielen+2; + pattrib->pktlen += wps_ielen+2; } + + if ((wps_offset+wps_ielen+2+remainder_ielen) <= MAX_IE_SZ) { + memcpy(pframe, premainder_ie, remainder_ielen); + pframe += remainder_ielen; + pattrib->pktlen += remainder_ielen; + } + } else { + memcpy(pframe, cur_network->IEs, cur_network->IELength); + pframe += cur_network->IELength; + pattrib->pktlen += cur_network->IELength; } - } + } else +#endif + { + /* timestamp will be inserted by hardware */ + pframe += 8; + pattrib->pktlen += 8; -_END_ONBEACON_: + /* beacon interval: 2 bytes */ - return _SUCCESS; -} + memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); -unsigned int OnAuth(struct adapter *padapter, struct recv_frame *precv_frame) -{ -#ifdef CONFIG_88EU_AP_MODE - unsigned int auth_mode, ie_len; - u16 seq; - unsigned char *sa, *p; - u16 algorithm; - int status; - static struct sta_info stat; - struct sta_info *pstat = NULL; - struct sta_priv *pstapriv = &padapter->stapriv; - struct security_priv *psecuritypriv = &padapter->securitypriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - u8 *pframe = precv_frame->rx_data; - uint len = precv_frame->len; + pframe += 2; + pattrib->pktlen += 2; - if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) - return _FAIL; + /* capability info: 2 bytes */ - DBG_88E("+OnAuth\n"); + memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); - sa = GetAddr2Ptr(pframe); + pframe += 2; + pattrib->pktlen += 2; - auth_mode = psecuritypriv->dot11AuthAlgrthm; - seq = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + 2)); - algorithm = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN)); + /* below for ad-hoc mode */ - DBG_88E("auth alg=%x, seq=%X\n", algorithm, seq); + /* SSID */ + pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen); - if (auth_mode == 2 && psecuritypriv->dot11PrivacyAlgrthm != _WEP40_ && - psecuritypriv->dot11PrivacyAlgrthm != _WEP104_) - auth_mode = 0; + /* supported rates... */ + rate_len = rtw_get_rateset_len(cur_network->SupportedRates); + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pattrib->pktlen); - if ((algorithm > 0 && auth_mode == 0) || /* rx a shared-key auth but shared not enabled */ - (algorithm == 0 && auth_mode == 1)) { /* rx a open-system auth but shared-key is enabled */ - DBG_88E("auth rejected due to bad alg [alg=%d, auth_mib=%d] %02X%02X%02X%02X%02X%02X\n", - algorithm, auth_mode, sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]); + /* DS parameter set */ + pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen); - status = _STATS_NO_SUPP_ALG_; + if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { + u8 erpinfo = 0; + u32 ATIMWindow; + /* IBSS Parameter Set... */ + /* ATIMWindow = cur->Configuration.ATIMWindow; */ + ATIMWindow = 0; + pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen); - goto auth_fail; - } + /* ERP IE */ + pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen); + } - if (!rtw_access_ctrl(padapter, sa)) { - status = _STATS_UNABLE_HANDLE_STA_; - goto auth_fail; + + /* EXTERNDED SUPPORTED RATE */ + if (rate_len > 8) + pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen); + /* todo:HT for adhoc */ } - pstat = rtw_get_stainfo(pstapriv, sa); - if (pstat == NULL) { - /* allocate a new one */ - DBG_88E("going to alloc stainfo for sa=%pM\n", sa); - pstat = rtw_alloc_stainfo(pstapriv, sa); - if (pstat == NULL) { - DBG_88E(" Exceed the upper limit of supported clients...\n"); - status = _STATS_UNABLE_HANDLE_STA_; - goto auth_fail; - } + pattrib->last_txcmdsz = pattrib->pktlen; - pstat->state = WIFI_FW_AUTH_NULL; - pstat->auth_seq = 0; - } else { - spin_lock_bh(&pstapriv->asoc_list_lock); - if (!list_empty(&pstat->asoc_list)) { - list_del_init(&pstat->asoc_list); - pstapriv->asoc_list_cnt--; - } - spin_unlock_bh(&pstapriv->asoc_list_lock); + dump_mgntframe(padapter, pmgntframe); - if (seq == 1) { - /* TODO: STA re_auth and auth timeout */ - } - } + return; +} - spin_lock_bh(&pstapriv->auth_list_lock); - if (list_empty(&pstat->auth_list)) { - list_add_tail(&pstat->auth_list, &pstapriv->auth_list); - pstapriv->auth_list_cnt++; - } - spin_unlock_bh(&pstapriv->auth_list_lock); +static int _issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da, int wait_ack) +{ + int ret = _FAIL; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + __le16 *fctrl; + unsigned char *mac; + unsigned char bssrate[NumRates]; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + int bssrate_len = 0; + u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - if (pstat->auth_seq == 0) - pstat->expire_to = pstapriv->auth_to; + RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+issue_probereq\n")); - if ((pstat->auth_seq + 1) != seq) { - DBG_88E("(1)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", - seq, pstat->auth_seq+1); - status = _STATS_OUT_OF_AUTH_SEQ_; - goto auth_fail; - } + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; - if (algorithm == 0 && (auth_mode == 0 || auth_mode == 2)) { - if (seq == 1) { - pstat->state &= ~WIFI_FW_AUTH_NULL; - pstat->state |= WIFI_FW_AUTH_SUCCESS; - pstat->expire_to = pstapriv->assoc_to; - pstat->authalg = algorithm; - } else { - DBG_88E("(2)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", - seq, pstat->auth_seq+1); - status = _STATS_OUT_OF_AUTH_SEQ_; - goto auth_fail; - } - } else { /* shared system or auto authentication */ - if (seq == 1) { - /* prepare for the challenging txt... */ + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); - pstat->state &= ~WIFI_FW_AUTH_NULL; - pstat->state |= WIFI_FW_AUTH_STATE; - pstat->authalg = algorithm; - pstat->auth_seq = 2; - } else if (seq == 3) { - /* checking for challenging txt... */ - DBG_88E("checking for challenging txt...\n"); - p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + 4 + _AUTH_IE_OFFSET_ , _CHLGETXT_IE_, (int *)&ie_len, - len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_ - 4); + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - if ((p == NULL) || (ie_len <= 0)) { - DBG_88E("auth rejected because challenge failure!(1)\n"); - status = _STATS_CHALLENGE_FAIL_; - goto auth_fail; - } + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; - if (!memcmp((void *)(p + 2), pstat->chg_txt, 128)) { - pstat->state &= (~WIFI_FW_AUTH_STATE); - pstat->state |= WIFI_FW_AUTH_SUCCESS; - /* challenging txt is correct... */ - pstat->expire_to = pstapriv->assoc_to; - } else { - DBG_88E("auth rejected because challenge failure!\n"); - status = _STATS_CHALLENGE_FAIL_; - goto auth_fail; - } - } else { - DBG_88E("(3)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", - seq, pstat->auth_seq+1); - status = _STATS_OUT_OF_AUTH_SEQ_; - goto auth_fail; - } - } + mac = myid(&(padapter->eeprompriv)); - /* Now, we are going to issue_auth... */ - pstat->auth_seq = seq + 1; + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; - issue_auth(padapter, pstat, (unsigned short)(_STATS_SUCCESSFUL_)); + if (da) { + /* unicast probe request frame */ + memcpy(pwlanhdr->addr1, da, ETH_ALEN); + memcpy(pwlanhdr->addr3, da, ETH_ALEN); + } else { + /* broadcast probe request frame */ + memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); + memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN); + } - if (pstat->state & WIFI_FW_AUTH_SUCCESS) - pstat->auth_seq = 0; + memcpy(pwlanhdr->addr2, mac, ETH_ALEN); - return _SUCCESS; + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_PROBEREQ); -auth_fail: + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); - if (pstat) - rtw_free_stainfo(padapter, pstat); + if (pssid) + pframe = rtw_set_ie(pframe, _SSID_IE_, pssid->SsidLength, pssid->Ssid, &(pattrib->pktlen)); + else + pframe = rtw_set_ie(pframe, _SSID_IE_, 0, NULL, &(pattrib->pktlen)); - pstat = &stat; - memset((char *)pstat, '\0', sizeof(stat)); - pstat->auth_seq = 2; - memcpy(pstat->hwaddr, sa, 6); + get_rate_set(padapter, bssrate, &bssrate_len); - issue_auth(padapter, pstat, (unsigned short)status); + if (bssrate_len > 8) { + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen)); + pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen)); + } else { + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen)); + } -#endif /* CONFIG_88EU_AP_MODE */ - return _FAIL; -} + /* add wps_ie for wps2.0 */ + if (pmlmepriv->wps_probe_req_ie_len > 0 && pmlmepriv->wps_probe_req_ie) { + memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len); + pframe += pmlmepriv->wps_probe_req_ie_len; + pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; + } -unsigned int OnAuthClient(struct adapter *padapter, struct recv_frame *precv_frame) -{ - unsigned int seq, len, status, offset; - unsigned char *p; - unsigned int go2asoc = 0; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - u8 *pframe = precv_frame->rx_data; - uint pkt_len = precv_frame->len; + pattrib->last_txcmdsz = pattrib->pktlen; - DBG_88E("%s\n", __func__); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, + ("issuing probe_req, tx_len=%d\n", pattrib->last_txcmdsz)); - /* check A1 matches or not */ - if (memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN)) - return _SUCCESS; + if (wait_ack) { + ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); + } else { + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; + } - if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE)) - return _SUCCESS; +exit: + return ret; +} - offset = (GetPrivacy(pframe)) ? 4 : 0; +inline void issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da) +{ + _issue_probereq(padapter, pssid, da, false); +} - seq = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + offset + 2)); - status = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + offset + 4)); +int issue_probereq_ex(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da, + int try_cnt, int wait_ms) +{ + int ret; + int i = 0; + u32 start = jiffies; - if (status != 0) { - DBG_88E("clnt auth fail, status: %d\n", status); - if (status == 13) { /* pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) */ - if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) - pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; - else - pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; - } + do { + ret = _issue_probereq(padapter, pssid, da, wait_ms > 0 ? true : false); - set_link_timer(pmlmeext, 1); - goto authclnt_fail; - } + i++; - if (seq == 2) { - if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) { - /* legendary shared system */ - p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _AUTH_IE_OFFSET_, _CHLGETXT_IE_, (int *)&len, - pkt_len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_); + if (padapter->bDriverStopped || padapter->bSurpriseRemoved) + break; - if (p == NULL) - goto authclnt_fail; + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + msleep(wait_ms); - memcpy((void *)(pmlmeinfo->chg_txt), (void *)(p + 2), len); - pmlmeinfo->auth_seq = 3; - issue_auth(padapter, NULL, 0); - set_link_timer(pmlmeext, REAUTH_TO); + } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); - return _SUCCESS; - } else { - /* open system */ - go2asoc = 1; - } - } else if (seq == 4) { - if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) - go2asoc = 1; - else - goto authclnt_fail; - } else { - /* this is also illegal */ - goto authclnt_fail; + if (ret != _FAIL) { + ret = _SUCCESS; + goto exit; } - if (go2asoc) { - DBG_88E_LEVEL(_drv_info_, "auth success, start assoc\n"); - start_clnt_assoc(padapter); - return _SUCCESS; + if (try_cnt && wait_ms) { + if (da) + DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + else + DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); } -authclnt_fail: - return _FAIL; +exit: + return ret; } -unsigned int OnAssocReq(struct adapter *padapter, struct recv_frame *precv_frame) +/* if psta == NULL, indicate we are station(client) now... */ +void issue_auth(struct adapter *padapter, struct sta_info *psta, unsigned short status) { -#ifdef CONFIG_88EU_AP_MODE - u16 capab_info; - struct rtw_ieee802_11_elems elems; - struct sta_info *pstat; - unsigned char reassoc, *p, *pos, *wpa_ie; - unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; - int i, ie_len, wpa_ie_len, left; - unsigned char supportRate[16]; - int supportRateNum; - unsigned short status = _STATS_SUCCESSFUL_; - unsigned short frame_type, ie_offset = 0; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct security_priv *psecuritypriv = &padapter->securitypriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + __le16 *fctrl; + unsigned int val32; + u16 val16; +#ifdef CONFIG_88EU_AP_MODE + __le16 le_val16; +#endif + int use_shared_key = 0; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct wlan_bssid_ex *cur = &(pmlmeinfo->network); - struct sta_priv *pstapriv = &padapter->stapriv; - u8 *pframe = precv_frame->rx_data; - uint pkt_len = precv_frame->len; + struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); - if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) - return _FAIL; + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; - frame_type = GetFrameSubType(pframe); - if (frame_type == WIFI_ASSOCREQ) { - reassoc = 0; - ie_offset = _ASOCREQ_IE_OFFSET_; - } else { /* WIFI_REASSOCREQ */ - reassoc = 1; - ie_offset = _REASOCREQ_IE_OFFSET_; - } + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - if (pkt_len < IEEE80211_3ADDR_LEN + ie_offset) { - DBG_88E("handle_assoc(reassoc=%d) - too short payload (len=%lu)" - "\n", reassoc, (unsigned long)pkt_len); - return _FAIL; - } + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; - pstat = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); - if (pstat == NULL) { - status = _RSON_CLS2_; - goto asoc_class2_error; - } + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; - capab_info = get_unaligned_le16(pframe + WLAN_HDR_A3_LEN); + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_AUTH); - left = pkt_len - (IEEE80211_3ADDR_LEN + ie_offset); - pos = pframe + (IEEE80211_3ADDR_LEN + ie_offset); + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); - DBG_88E("%s\n", __func__); + if (psta) {/* for AP mode */ +#ifdef CONFIG_88EU_AP_MODE - /* check if this stat has been successfully authenticated/assocated */ - if (!((pstat->state) & WIFI_FW_AUTH_SUCCESS)) { - if (!((pstat->state) & WIFI_FW_ASSOC_SUCCESS)) { - status = _RSON_CLS2_; - goto asoc_class2_error; - } else { - pstat->state &= (~WIFI_FW_ASSOC_SUCCESS); - pstat->state |= WIFI_FW_ASSOC_STATE; - } - } else { - pstat->state &= (~WIFI_FW_AUTH_SUCCESS); - pstat->state |= WIFI_FW_ASSOC_STATE; - } - pstat->capability = capab_info; - /* now parse all ieee802_11 ie to point to elems */ - if (rtw_ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed || - !elems.ssid) { - DBG_88E("STA %pM sent invalid association request\n", - pstat->hwaddr); - status = _STATS_FAILURE_; - goto OnAssocReqFail; - } + memcpy(pwlanhdr->addr1, psta->hwaddr, ETH_ALEN); + memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); + memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); - /* now we should check all the fields... */ - /* checking SSID */ - p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SSID_IE_, &ie_len, - pkt_len - WLAN_HDR_A3_LEN - ie_offset); - if (p == NULL) - status = _STATS_FAILURE_; + /* setting auth algo number */ + val16 = (u16)psta->authalg; - if (ie_len == 0) { /* broadcast ssid, however it is not allowed in assocreq */ - status = _STATS_FAILURE_; - } else { - /* check if ssid match */ - if (memcmp((void *)(p+2), cur->Ssid.Ssid, cur->Ssid.SsidLength)) - status = _STATS_FAILURE_; + if (status != _STATS_SUCCESSFUL_) + val16 = 0; - if (ie_len != cur->Ssid.SsidLength) - status = _STATS_FAILURE_; - } + if (val16) { + le_val16 = cpu_to_le16(val16); + use_shared_key = 1; + } else { + le_val16 = 0; + } - if (_STATS_SUCCESSFUL_ != status) - goto OnAssocReqFail; + pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&le_val16, &(pattrib->pktlen)); - /* check if the supported rate is ok */ - p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SUPPORTEDRATES_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset); - if (p == NULL) { - DBG_88E("Rx a sta assoc-req which supported rate is empty!\n"); - /* use our own rate set as statoin used */ - /* memcpy(supportRate, AP_BSSRATE, AP_BSSRATE_LEN); */ - /* supportRateNum = AP_BSSRATE_LEN; */ + /* setting auth seq number */ + val16 = (u16)psta->auth_seq; + le_val16 = cpu_to_le16(val16); + pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&le_val16, &(pattrib->pktlen)); - status = _STATS_FAILURE_; - goto OnAssocReqFail; - } else { - memcpy(supportRate, p+2, ie_len); - supportRateNum = ie_len; + /* setting status code... */ + val16 = status; + le_val16 = cpu_to_le16(val16); + pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&le_val16, &(pattrib->pktlen)); - p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _EXT_SUPPORTEDRATES_IE_ , &ie_len, - pkt_len - WLAN_HDR_A3_LEN - ie_offset); - if (p != NULL) { - if (supportRateNum <= sizeof(supportRate)) { - memcpy(supportRate+supportRateNum, p+2, ie_len); - supportRateNum += ie_len; - } - } - } + /* added challenging text... */ + if ((psta->auth_seq == 2) && (psta->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) + pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, psta->chg_txt, &(pattrib->pktlen)); +#endif + } else { + __le32 le_tmp32; + __le16 le_tmp16; + memcpy(pwlanhdr->addr1, pnetwork->MacAddress, ETH_ALEN); + memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); + memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN); - /* todo: mask supportRate between AP & STA -> move to update raid */ - /* get_matched_rate(pmlmeext, supportRate, &supportRateNum, 0); */ + /* setting auth algo number */ + val16 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ? 1 : 0;/* 0:OPEN System, 1:Shared key */ + if (val16) + use_shared_key = 1; - /* update station supportRate */ - pstat->bssratelen = supportRateNum; - memcpy(pstat->bssrateset, supportRate, supportRateNum); - UpdateBrateTblForSoftAP(pstat->bssrateset, pstat->bssratelen); + /* setting IV for auth seq #3 */ + if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) { + val32 = (pmlmeinfo->iv++) | (pmlmeinfo->key_index << 30); + le_tmp32 = cpu_to_le32(val32); + pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&le_tmp32, &(pattrib->pktlen)); - /* check RSN/WPA/WPS */ - pstat->dot8021xalg = 0; - pstat->wpa_psk = 0; - pstat->wpa_group_cipher = 0; - pstat->wpa2_group_cipher = 0; - pstat->wpa_pairwise_cipher = 0; - pstat->wpa2_pairwise_cipher = 0; - memset(pstat->wpa_ie, 0, sizeof(pstat->wpa_ie)); - if ((psecuritypriv->wpa_psk & BIT(1)) && elems.rsn_ie) { - int group_cipher = 0, pairwise_cipher = 0; + pattrib->iv_len = 4; + } - wpa_ie = elems.rsn_ie; - wpa_ie_len = elems.rsn_ie_len; + le_tmp16 = cpu_to_le16(val16); + pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&le_tmp16, &(pattrib->pktlen)); - if (rtw_parse_wpa2_ie(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { - pstat->dot8021xalg = 1;/* psk, todo:802.1x */ - pstat->wpa_psk |= BIT(1); + /* setting auth seq number */ + val16 = pmlmeinfo->auth_seq; + le_tmp16 = cpu_to_le16(val16); + pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&le_tmp16, &(pattrib->pktlen)); - pstat->wpa2_group_cipher = group_cipher&psecuritypriv->wpa2_group_cipher; - pstat->wpa2_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa2_pairwise_cipher; - if (!pstat->wpa2_group_cipher) - status = WLAN_STATUS_INVALID_GROUP_CIPHER; + /* setting status code... */ + le_tmp16 = cpu_to_le16(status); + pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&le_tmp16, &(pattrib->pktlen)); - if (!pstat->wpa2_pairwise_cipher) - status = WLAN_STATUS_INVALID_PAIRWISE_CIPHER; - } else { - status = WLAN_STATUS_INVALID_IE; - } - } else if ((psecuritypriv->wpa_psk & BIT(0)) && elems.wpa_ie) { - int group_cipher = 0, pairwise_cipher = 0; + /* then checking to see if sending challenging text... */ + if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) { + pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, pmlmeinfo->chg_txt, &(pattrib->pktlen)); - wpa_ie = elems.wpa_ie; - wpa_ie_len = elems.wpa_ie_len; + SetPrivacy(fctrl); - if (rtw_parse_wpa_ie(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { - pstat->dot8021xalg = 1;/* psk, todo:802.1x */ - pstat->wpa_psk |= BIT(0); + pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); - pstat->wpa_group_cipher = group_cipher&psecuritypriv->wpa_group_cipher; - pstat->wpa_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa_pairwise_cipher; + pattrib->encrypt = _WEP40_; - if (!pstat->wpa_group_cipher) - status = WLAN_STATUS_INVALID_GROUP_CIPHER; + pattrib->icv_len = 4; - if (!pstat->wpa_pairwise_cipher) - status = WLAN_STATUS_INVALID_PAIRWISE_CIPHER; - } else { - status = WLAN_STATUS_INVALID_IE; + pattrib->pktlen += pattrib->icv_len; } - } else { - wpa_ie = NULL; - wpa_ie_len = 0; } - if (_STATS_SUCCESSFUL_ != status) - goto OnAssocReqFail; - - pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); - if (wpa_ie == NULL) { - if (elems.wps_ie) { - DBG_88E("STA included WPS IE in " - "(Re)Association Request - assume WPS is " - "used\n"); - pstat->flags |= WLAN_STA_WPS; - /* wpabuf_free(sta->wps_ie); */ - /* sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4, */ - /* elems.wps_ie_len - 4); */ - } else { - DBG_88E("STA did not include WPA/RSN IE " - "in (Re)Association Request - possible WPS " - "use\n"); - pstat->flags |= WLAN_STA_MAYBE_WPS; - } + pattrib->last_txcmdsz = pattrib->pktlen; + rtw_wep_encrypt(padapter, (u8 *)pmgntframe); + DBG_88E("%s\n", __func__); + dump_mgntframe(padapter, pmgntframe); - /* AP support WPA/RSN, and sta is going to do WPS, but AP is not ready */ - /* that the selected registrar of AP is _FLASE */ - if ((psecuritypriv->wpa_psk > 0) && (pstat->flags & (WLAN_STA_WPS|WLAN_STA_MAYBE_WPS))) { - if (pmlmepriv->wps_beacon_ie) { - u8 selected_registrar = 0; + return; +} - rtw_get_wps_attr_content(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len, WPS_ATTR_SELECTED_REGISTRAR , &selected_registrar, NULL); - if (!selected_registrar) { - DBG_88E("selected_registrar is false , or AP is not ready to do WPS\n"); +void issue_asocrsp(struct adapter *padapter, unsigned short status, struct sta_info *pstat, int pkt_type) +{ +#ifdef CONFIG_88EU_AP_MODE + struct xmit_frame *pmgntframe; + struct rtw_ieee80211_hdr *pwlanhdr; + struct pkt_attrib *pattrib; + unsigned char *pbuf, *pframe; + unsigned short val; + __le16 *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); + u8 *ie = pnetwork->IEs; + __le16 lestatus, leval; - status = _STATS_UNABLE_HANDLE_STA_; + DBG_88E("%s\n", __func__); - goto OnAssocReqFail; - } - } - } - } else { - int copy_len; + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; - if (psecuritypriv->wpa_psk == 0) { - DBG_88E("STA %pM: WPA/RSN IE in association " - "request, but AP don't support WPA/RSN\n", pstat->hwaddr); + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); - status = WLAN_STATUS_INVALID_IE; - goto OnAssocReqFail; - } + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - if (elems.wps_ie) { - DBG_88E("STA included WPS IE in " - "(Re)Association Request - WPS is " - "used\n"); - pstat->flags |= WLAN_STA_WPS; - copy_len = 0; - } else { - copy_len = ((wpa_ie_len+2) > sizeof(pstat->wpa_ie)) ? (sizeof(pstat->wpa_ie)) : (wpa_ie_len+2); - } - if (copy_len > 0) - memcpy(pstat->wpa_ie, wpa_ie-2, copy_len); - } - /* check if there is WMM IE & support WWM-PS */ - pstat->flags &= ~WLAN_STA_WME; - pstat->qos_option = 0; - pstat->qos_info = 0; - pstat->has_legacy_ac = true; - pstat->uapsd_vo = 0; - pstat->uapsd_vi = 0; - pstat->uapsd_be = 0; - pstat->uapsd_bk = 0; - if (pmlmepriv->qospriv.qos_option) { - p = pframe + WLAN_HDR_A3_LEN + ie_offset; ie_len = 0; - for (;;) { - p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset); - if (p != NULL) { - if (!memcmp(p+2, WMM_IE, 6)) { - pstat->flags |= WLAN_STA_WME; + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; - pstat->qos_option = 1; - pstat->qos_info = *(p+8); + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; - pstat->max_sp_len = (pstat->qos_info>>5)&0x3; + memcpy((void *)GetAddr1Ptr(pwlanhdr), pstat->hwaddr, ETH_ALEN); + memcpy((void *)GetAddr2Ptr(pwlanhdr), myid(&(padapter->eeprompriv)), ETH_ALEN); + memcpy((void *)GetAddr3Ptr(pwlanhdr), pnetwork->MacAddress, ETH_ALEN); - if ((pstat->qos_info&0xf) != 0xf) - pstat->has_legacy_ac = true; - else - pstat->has_legacy_ac = false; - if (pstat->qos_info&0xf) { - if (pstat->qos_info&BIT(0)) - pstat->uapsd_vo = BIT(0)|BIT(1); - else - pstat->uapsd_vo = 0; + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP)) + SetFrameSubType(pwlanhdr, pkt_type); + else + return; - if (pstat->qos_info&BIT(1)) - pstat->uapsd_vi = BIT(0)|BIT(1); - else - pstat->uapsd_vi = 0; + pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen += pattrib->hdrlen; + pframe += pattrib->hdrlen; - if (pstat->qos_info&BIT(2)) - pstat->uapsd_bk = BIT(0)|BIT(1); - else - pstat->uapsd_bk = 0; + /* capability */ + val = *(unsigned short *)rtw_get_capability_from_ie(ie); - if (pstat->qos_info&BIT(3)) - pstat->uapsd_be = BIT(0)|BIT(1); - else - pstat->uapsd_be = 0; - } - break; - } - } else { - break; - } - p = p + ie_len + 2; - } - } + pframe = rtw_set_fixed_ie(pframe, _CAPABILITY_ , (unsigned char *)&val, &(pattrib->pktlen)); - /* save HT capabilities in the sta object */ - memset(&pstat->htpriv.ht_cap, 0, sizeof(struct rtw_ieee80211_ht_cap)); - if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct rtw_ieee80211_ht_cap)) { - pstat->flags |= WLAN_STA_HT; + lestatus = cpu_to_le16(status); + pframe = rtw_set_fixed_ie(pframe , _STATUS_CODE_ , (unsigned char *)&lestatus, &(pattrib->pktlen)); - pstat->flags |= WLAN_STA_WME; + leval = cpu_to_le16(pstat->aid | BIT(14) | BIT(15)); + pframe = rtw_set_fixed_ie(pframe, _ASOC_ID_ , (unsigned char *)&leval, &(pattrib->pktlen)); - memcpy(&pstat->htpriv.ht_cap, elems.ht_capabilities, sizeof(struct rtw_ieee80211_ht_cap)); + if (pstat->bssratelen <= 8) { + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, pstat->bssratelen, pstat->bssrateset, &(pattrib->pktlen)); } else { - pstat->flags &= ~WLAN_STA_HT; - } - if ((!pmlmepriv->htpriv.ht_option) && (pstat->flags&WLAN_STA_HT)) { - status = _STATS_FAILURE_; - goto OnAssocReqFail; + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pstat->bssrateset, &(pattrib->pktlen)); + pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (pstat->bssratelen-8), pstat->bssrateset+8, &(pattrib->pktlen)); } - if ((pstat->flags & WLAN_STA_HT) && - ((pstat->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) || - (pstat->wpa_pairwise_cipher&WPA_CIPHER_TKIP))) { - DBG_88E("HT: %pM tried to " - "use TKIP with HT association\n", pstat->hwaddr); + if ((pstat->flags & WLAN_STA_HT) && (pmlmepriv->htpriv.ht_option)) { + uint ie_len = 0; - /* status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; */ - /* goto OnAssocReqFail; */ - } + /* FILL HT CAP INFO IE */ + pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); + if (pbuf && ie_len > 0) { + memcpy(pframe, pbuf, ie_len+2); + pframe += (ie_len+2); + pattrib->pktlen += (ie_len+2); + } - pstat->flags |= WLAN_STA_NONERP; - for (i = 0; i < pstat->bssratelen; i++) { - if ((pstat->bssrateset[i] & 0x7f) > 22) { - pstat->flags &= ~WLAN_STA_NONERP; - break; + /* FILL HT ADD INFO IE */ + pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); + if (pbuf && ie_len > 0) { + memcpy(pframe, pbuf, ie_len+2); + pframe += (ie_len+2); + pattrib->pktlen += (ie_len+2); } } - if (pstat->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) - pstat->flags |= WLAN_STA_SHORT_PREAMBLE; - else - pstat->flags &= ~WLAN_STA_SHORT_PREAMBLE; - - - - if (status != _STATS_SUCCESSFUL_) - goto OnAssocReqFail; - - /* TODO: identify_proprietary_vendor_ie(); */ - /* Realtek proprietary IE */ - /* identify if this is Broadcom sta */ - /* identify if this is ralink sta */ - /* Customer proprietary IE */ + /* FILL WMM IE */ + if ((pstat->flags & WLAN_STA_WME) && (pmlmepriv->qospriv.qos_option)) { + uint ie_len = 0; + unsigned char WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; - /* get a unique AID */ - if (pstat->aid > 0) { - DBG_88E(" old AID %d\n", pstat->aid); - } else { - for (pstat->aid = 1; pstat->aid <= NUM_STA; pstat->aid++) - if (pstapriv->sta_aid[pstat->aid - 1] == NULL) + for (pbuf = ie + _BEACON_IE_OFFSET_;; pbuf += (ie_len + 2)) { + pbuf = rtw_get_ie(pbuf, _VENDOR_SPECIFIC_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); + if (pbuf && !memcmp(pbuf+2, WMM_PARA_IE, 6)) { + memcpy(pframe, pbuf, ie_len+2); + pframe += (ie_len+2); + pattrib->pktlen += (ie_len+2); break; + } - /* if (pstat->aid > NUM_STA) { */ - if (pstat->aid > pstapriv->max_num_sta) { - pstat->aid = 0; - - DBG_88E(" no room for more AIDs\n"); - - status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; - - goto OnAssocReqFail; - } else { - pstapriv->sta_aid[pstat->aid - 1] = pstat; - DBG_88E("allocate new AID=(%d)\n", pstat->aid); + if ((pbuf == NULL) || (ie_len == 0)) + break; } } - pstat->state &= (~WIFI_FW_ASSOC_STATE); - pstat->state |= WIFI_FW_ASSOC_SUCCESS; + if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen)); - spin_lock_bh(&pstapriv->auth_list_lock); - if (!list_empty(&pstat->auth_list)) { - list_del_init(&pstat->auth_list); - pstapriv->auth_list_cnt--; - } - spin_unlock_bh(&pstapriv->auth_list_lock); + /* add WPS IE ie for wps 2.0 */ + if (pmlmepriv->wps_assoc_resp_ie && pmlmepriv->wps_assoc_resp_ie_len > 0) { + memcpy(pframe, pmlmepriv->wps_assoc_resp_ie, pmlmepriv->wps_assoc_resp_ie_len); - spin_lock_bh(&pstapriv->asoc_list_lock); - if (list_empty(&pstat->asoc_list)) { - pstat->expire_to = pstapriv->expire_to; - list_add_tail(&pstat->asoc_list, &pstapriv->asoc_list); - pstapriv->asoc_list_cnt++; + pframe += pmlmepriv->wps_assoc_resp_ie_len; + pattrib->pktlen += pmlmepriv->wps_assoc_resp_ie_len; } - spin_unlock_bh(&pstapriv->asoc_list_lock); - /* now the station is qualified to join our BSS... */ - if (pstat && (pstat->state & WIFI_FW_ASSOC_SUCCESS) && (_STATS_SUCCESSFUL_ == status)) { - /* 1 bss_cap_update & sta_info_update */ - bss_cap_update_on_sta_join(padapter, pstat); - sta_info_update(padapter, pstat); - - /* issue assoc rsp before notify station join event. */ - if (frame_type == WIFI_ASSOCREQ) - issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP); - else - issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP); + pattrib->last_txcmdsz = pattrib->pktlen; + dump_mgntframe(padapter, pmgntframe); +#endif +} - /* 2 - report to upper layer */ - DBG_88E("indicate_sta_join_event to upper layer - hostapd\n"); - rtw_indicate_sta_assoc_event(padapter, pstat); +void issue_assocreq(struct adapter *padapter) +{ + int ret = _FAIL; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe, *p; + struct rtw_ieee80211_hdr *pwlanhdr; + __le16 *fctrl; + __le16 le_tmp; + unsigned int i, j, ie_len, index = 0; + unsigned char rf_type, bssrate[NumRates], sta_bssrate[NumRates]; + struct ndis_802_11_var_ie *pIE; + struct registry_priv *pregpriv = &padapter->registrypriv; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + int bssrate_len = 0, sta_bssrate_len = 0; + struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); - /* 3-(1) report sta add event */ - report_add_sta_event(padapter, pstat->hwaddr, pstat->aid); - } + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; - return _SUCCESS; + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); -asoc_class2_error: + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; - issue_deauth(padapter, (void *)GetAddr2Ptr(pframe), status); + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + memcpy(pwlanhdr->addr1, pnetwork->MacAddress, ETH_ALEN); + memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); + memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN); - return _FAIL; + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ASSOCREQ); -OnAssocReqFail: + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); - pstat->aid = 0; - if (frame_type == WIFI_ASSOCREQ) - issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP); - else - issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP); + /* caps */ -#endif /* CONFIG_88EU_AP_MODE */ + memcpy(pframe, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2); - return _FAIL; -} + pframe += 2; + pattrib->pktlen += 2; -unsigned int OnAssocRsp(struct adapter *padapter, struct recv_frame *precv_frame) -{ - uint i; - int res; - unsigned short status; - struct ndis_802_11_var_ie *pIE; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - /* struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); */ - u8 *pframe = precv_frame->rx_data; - uint pkt_len = precv_frame->len; + /* listen interval */ + /* todo: listen interval for power saving */ + le_tmp = cpu_to_le16(3); + memcpy(pframe , (unsigned char *)&le_tmp, 2); + pframe += 2; + pattrib->pktlen += 2; - DBG_88E("%s\n", __func__); + /* SSID */ + pframe = rtw_set_ie(pframe, _SSID_IE_, pmlmeinfo->network.Ssid.SsidLength, pmlmeinfo->network.Ssid.Ssid, &(pattrib->pktlen)); - /* check A1 matches or not */ - if (memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN)) - return _SUCCESS; + /* supported rate & extended supported rate */ - if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE))) - return _SUCCESS; + /* Check if the AP's supported rates are also supported by STA. */ + get_rate_set(padapter, sta_bssrate, &sta_bssrate_len); - if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) - return _SUCCESS; + if (pmlmeext->cur_channel == 14)/* for JAPAN, channel 14 can only uses B Mode(CCK) */ + sta_bssrate_len = 4; - del_timer_sync(&pmlmeext->link_timer); + for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { + if (pmlmeinfo->network.SupportedRates[i] == 0) + break; + DBG_88E("network.SupportedRates[%d]=%02X\n", i, pmlmeinfo->network.SupportedRates[i]); + } - /* status */ - status = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 2)); - if (status > 0) { - DBG_88E("assoc reject, status code: %d\n", status); - pmlmeinfo->state = WIFI_FW_NULL_STATE; - res = -4; - goto report_assoc_result; + for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { + if (pmlmeinfo->network.SupportedRates[i] == 0) + break; + + /* Check if the AP's supported rates are also supported by STA. */ + for (j = 0; j < sta_bssrate_len; j++) { + /* Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP */ + if ((pmlmeinfo->network.SupportedRates[i]|IEEE80211_BASIC_RATE_MASK) + == (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK)) + break; + } + + if (j == sta_bssrate_len) { + /* the rate is not supported by STA */ + DBG_88E("%s(): the rate[%d]=%02X is not supported by STA!\n", __func__, i, pmlmeinfo->network.SupportedRates[i]); + } else { + /* the rate is supported by STA */ + bssrate[index++] = pmlmeinfo->network.SupportedRates[i]; + } } - /* get capabilities */ - pmlmeinfo->capability = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); + bssrate_len = index; + DBG_88E("bssrate_len=%d\n", bssrate_len); - /* set slot time */ - pmlmeinfo->slotTime = (pmlmeinfo->capability & BIT(10)) ? 9 : 20; + if (bssrate_len == 0) { + rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(pxmitpriv, pmgntframe); + goto exit; /* don't connect to AP if no joint supported rate */ + } - /* AID */ - pmlmeinfo->aid = (int)(le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 4))&0x3fff); - res = pmlmeinfo->aid; - /* following are moved to join event callback function */ - /* to handle HT, WMM, rate adaptive, update MAC reg */ - /* for not to handle the synchronous IO in the tasklet */ - for (i = (6 + WLAN_HDR_A3_LEN); i < pkt_len;) { - pIE = (struct ndis_802_11_var_ie *)(pframe + i); + if (bssrate_len > 8) { + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen)); + pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen)); + } else { + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen)); + } + + /* RSN */ + p = rtw_get_ie((pmlmeinfo->network.IEs + sizeof(struct ndis_802_11_fixed_ie)), _RSN_IE_2_, &ie_len, (pmlmeinfo->network.IELength - sizeof(struct ndis_802_11_fixed_ie))); + if (p != NULL) + pframe = rtw_set_ie(pframe, _RSN_IE_2_, ie_len, (p + 2), &(pattrib->pktlen)); + + /* HT caps */ + if (padapter->mlmepriv.htpriv.ht_option) { + p = rtw_get_ie((pmlmeinfo->network.IEs + sizeof(struct ndis_802_11_fixed_ie)), _HT_CAPABILITY_IE_, &ie_len, (pmlmeinfo->network.IELength - sizeof(struct ndis_802_11_fixed_ie))); + if ((p != NULL) && (!(is_ap_in_tkip(padapter)))) { + memcpy(&(pmlmeinfo->HT_caps), (p + 2), sizeof(struct HT_caps_element)); + + /* to disable 40M Hz support while gd_bw_40MHz_en = 0 */ + if (pregpriv->cbw40_enable == 0) + pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info &= cpu_to_le16(~(BIT(6) | BIT(1))); + else + pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(BIT(1)); + + /* todo: disable SM power save mode */ + pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x000c); + + rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + switch (rf_type) { + case RF_1T1R: + if (pregpriv->rx_stbc) + pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0100);/* RX STBC One spatial stream */ + memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_1R, 16); + break; + case RF_2T2R: + case RF_1T2R: + default: + if ((pregpriv->rx_stbc == 0x3) ||/* enable for 2.4/5 GHz */ + ((pmlmeext->cur_wireless_mode & WIRELESS_11_24N) && (pregpriv->rx_stbc == 0x1)) || /* enable for 2.4GHz */ + (pregpriv->wifi_spec == 1)) { + DBG_88E("declare supporting RX STBC\n"); + pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0200);/* RX STBC two spatial stream */ + } + memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_2R, 16); + break; + } + pframe = rtw_set_ie(pframe, _HT_CAPABILITY_IE_, ie_len , (u8 *)(&(pmlmeinfo->HT_caps)), &(pattrib->pktlen)); + } + } + + /* vendor specific IE, such as WPA, WMM, WPS */ + for (i = sizeof(struct ndis_802_11_fixed_ie); i < pmlmeinfo->network.IELength;) { + pIE = (struct ndis_802_11_var_ie *)(pmlmeinfo->network.IEs + i); switch (pIE->ElementID) { case _VENDOR_SPECIFIC_IE_: - if (!memcmp(pIE->data, WMM_PARA_OUI, 6)) /* WMM */ - WMM_param_handler(padapter, pIE); - break; - case _HT_CAPABILITY_IE_: /* HT caps */ - HT_caps_handler(padapter, pIE); - break; - case _HT_EXTRA_INFO_IE_: /* HT info */ - HT_info_handler(padapter, pIE); + if ((!memcmp(pIE->data, RTW_WPA_OUI, 4)) || + (!memcmp(pIE->data, WMM_OUI, 4)) || + (!memcmp(pIE->data, WPS_OUI, 4))) { + if (!padapter->registrypriv.wifi_spec) { + /* Commented by Kurt 20110629 */ + /* In some older APs, WPS handshake */ + /* would be fail if we append vender extensions informations to AP */ + if (!memcmp(pIE->data, WPS_OUI, 4)) + pIE->Length = 14; + } + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, pIE->Length, pIE->data, &(pattrib->pktlen)); + } break; - case _ERPINFO_IE_: - ERP_IE_handler(padapter, pIE); default: break; } - i += (pIE->Length + 2); } - pmlmeinfo->state &= (~WIFI_FW_ASSOC_STATE); - pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; + if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen)); - /* Update Basic Rate Table for spec, 2010-12-28 , by thomas */ - UpdateBrateTbl(padapter, pmlmeinfo->network.SupportedRates); + pattrib->last_txcmdsz = pattrib->pktlen; + dump_mgntframe(padapter, pmgntframe); -report_assoc_result: - if (res > 0) { - rtw_buf_update(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len, pframe, pkt_len); - } else { - rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len); - } + ret = _SUCCESS; - report_join_res(padapter, res); +exit: + if (ret == _SUCCESS) + rtw_buf_update(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len, (u8 *)pwlanhdr, pattrib->pktlen); + else + rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len); - return _SUCCESS; + return; } -unsigned int OnDeAuth(struct adapter *padapter, struct recv_frame *precv_frame) +/* when wait_ack is true, this function should be called at process context */ +static int _issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int wait_ack) { - unsigned short reason; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - u8 *pframe = precv_frame->rx_data; - struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); + int ret = _FAIL; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + __le16 *fctrl; + struct xmit_priv *pxmitpriv; + struct mlme_ext_priv *pmlmeext; + struct mlme_ext_info *pmlmeinfo; + struct wlan_bssid_ex *pnetwork; - /* check A3 */ - if (memcmp(GetAddr3Ptr(pframe), pnetwork->MacAddress, ETH_ALEN)) - return _SUCCESS; + if (!padapter) + goto exit; - reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); + pxmitpriv = &(padapter->xmitpriv); + pmlmeext = &(padapter->mlmeextpriv); + pmlmeinfo = &(pmlmeext->mlmext_info); + pnetwork = &(pmlmeinfo->network); - DBG_88E("%s Reason code(%d)\n", __func__, reason); + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; -#ifdef CONFIG_88EU_AP_MODE - if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { - struct sta_info *psta; - struct sta_priv *pstapriv = &padapter->stapriv; + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + pattrib->retry_ctrl = false; - DBG_88E_LEVEL(_drv_always_, "ap recv deauth reason code(%d) sta:%pM\n", - reason, GetAddr2Ptr(pframe)); + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); - if (psta) { - u8 updated = 0; + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; - spin_lock_bh(&pstapriv->asoc_list_lock); - if (!list_empty(&psta->asoc_list)) { - list_del_init(&psta->asoc_list); - pstapriv->asoc_list_cnt--; - updated = ap_free_sta(padapter, psta, false, reason); - } - spin_unlock_bh(&pstapriv->asoc_list_lock); + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; - associated_clients_update(padapter, updated); - } + if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) + SetFrDs(fctrl); + else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) + SetToDs(fctrl); + if (power_mode) + SetPwrMgt(fctrl); - return _SUCCESS; - } else -#endif - { - DBG_88E_LEVEL(_drv_always_, "sta recv deauth reason code(%d) sta:%pM\n", - reason, GetAddr3Ptr(pframe)); + memcpy(pwlanhdr->addr1, da, ETH_ALEN); + memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); + memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN); - receive_disconnect(padapter, GetAddr3Ptr(pframe) , reason); + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_DATA_NULL); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + pattrib->last_txcmdsz = pattrib->pktlen; + + if (wait_ack) { + ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); + } else { + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; } - pmlmepriv->LinkDetectInfo.bBusyTraffic = false; - return _SUCCESS; + +exit: + return ret; } -unsigned int OnDisassoc(struct adapter *padapter, struct recv_frame *precv_frame) + +/* when wait_ms > 0 , this function should be called at process context */ +/* da == NULL for station mode */ +int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms) { - u16 reason; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + int ret; + int i = 0; + u32 start = jiffies; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - u8 *pframe = precv_frame->rx_data; - struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); - - /* check A3 */ - if (memcmp(GetAddr3Ptr(pframe), pnetwork->MacAddress, ETH_ALEN)) - return _SUCCESS; - - reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); - - DBG_88E("%s Reason code(%d)\n", __func__, reason); + struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); -#ifdef CONFIG_88EU_AP_MODE - if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { - struct sta_info *psta; - struct sta_priv *pstapriv = &padapter->stapriv; + /* da == NULL, assume it's null data for sta to ap*/ + if (da == NULL) + da = pnetwork->MacAddress; - DBG_88E_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n", - reason, GetAddr2Ptr(pframe)); + do { + ret = _issue_nulldata(padapter, da, power_mode, wait_ms > 0 ? true : false); - psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); - if (psta) { - u8 updated = 0; + i++; - spin_lock_bh(&pstapriv->asoc_list_lock); - if (!list_empty(&psta->asoc_list)) { - list_del_init(&psta->asoc_list); - pstapriv->asoc_list_cnt--; - updated = ap_free_sta(padapter, psta, false, reason); - } - spin_unlock_bh(&pstapriv->asoc_list_lock); + if (padapter->bDriverStopped || padapter->bSurpriseRemoved) + break; - associated_clients_update(padapter, updated); - } + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + msleep(wait_ms); + } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); - return _SUCCESS; - } else -#endif - { - DBG_88E_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n", - reason, GetAddr3Ptr(pframe)); + if (ret != _FAIL) { + ret = _SUCCESS; + goto exit; + } - receive_disconnect(padapter, GetAddr3Ptr(pframe), reason); + if (try_cnt && wait_ms) { + if (da) + DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + else + DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); } - pmlmepriv->LinkDetectInfo.bBusyTraffic = false; - return _SUCCESS; +exit: + return ret; } -unsigned int OnAtim(struct adapter *padapter, struct recv_frame *precv_frame) +/* when wait_ack is true, this function should be called at process context */ +static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int wait_ack) { + int ret = _FAIL; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + __le16 *fctrl; + unsigned short *qc; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); + DBG_88E("%s\n", __func__); - return _SUCCESS; -} -unsigned int on_action_spct(struct adapter *padapter, struct recv_frame *precv_frame) -{ - struct sta_info *psta = NULL; - struct sta_priv *pstapriv = &padapter->stapriv; - u8 *pframe = precv_frame->rx_data; - u8 *frame_body = (u8 *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); - u8 category; - u8 action; + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; - DBG_88E(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev)); + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); - psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); + pattrib->hdrlen += 2; + pattrib->qos_en = true; + pattrib->eosp = 1; + pattrib->ack_policy = 0; + pattrib->mdata = 0; - if (!psta) - goto exit; + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - category = frame_body[0]; - if (category != RTW_WLAN_CATEGORY_SPECTRUM_MGMT) - goto exit; + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; - action = frame_body[1]; - switch (action) { - case RTW_WLAN_ACTION_SPCT_MSR_REQ: - case RTW_WLAN_ACTION_SPCT_MSR_RPRT: - case RTW_WLAN_ACTION_SPCT_TPC_REQ: - case RTW_WLAN_ACTION_SPCT_TPC_RPRT: - break; - case RTW_WLAN_ACTION_SPCT_CHL_SWITCH: - break; - default: - break; - } + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; -exit: - return _FAIL; -} + if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) + SetFrDs(fctrl); + else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) + SetToDs(fctrl); -unsigned int OnAction_qos(struct adapter *padapter, struct recv_frame *precv_frame) -{ - return _SUCCESS; -} + if (pattrib->mdata) + SetMData(fctrl); -unsigned int OnAction_dls(struct adapter *padapter, struct recv_frame *precv_frame) -{ - return _SUCCESS; -} + qc = (unsigned short *)(pframe + pattrib->hdrlen - 2); -unsigned int OnAction_back(struct adapter *padapter, struct recv_frame *precv_frame) -{ - u8 *addr; - struct sta_info *psta = NULL; - struct recv_reorder_ctrl *preorder_ctrl; - unsigned char *frame_body; - unsigned char category, action; - unsigned short tid, status, reason_code = 0; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - u8 *pframe = precv_frame->rx_data; - struct sta_priv *pstapriv = &padapter->stapriv; - /* check RA matches or not */ - if (memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), - ETH_ALEN))/* for if1, sta/ap mode */ - return _SUCCESS; + SetPriority(qc, tid); - DBG_88E("%s\n", __func__); + SetEOSP(qc, pattrib->eosp); - if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) - if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) - return _SUCCESS; + SetAckpolicy(qc, pattrib->ack_policy); - addr = GetAddr2Ptr(pframe); - psta = rtw_get_stainfo(pstapriv, addr); + memcpy(pwlanhdr->addr1, da, ETH_ALEN); + memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); + memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN); - if (psta == NULL) - return _SUCCESS; + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); - frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); + pframe += sizeof(struct rtw_ieee80211_hdr_3addr_qos); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos); - category = frame_body[0]; - if (category == RTW_WLAN_CATEGORY_BACK) { /* representing Block Ack */ - if (!pmlmeinfo->HT_enable) - return _SUCCESS; - action = frame_body[1]; - DBG_88E("%s, action=%d\n", __func__, action); - switch (action) { - case RTW_WLAN_ACTION_ADDBA_REQ: /* ADDBA request */ - memcpy(&(pmlmeinfo->ADDBA_req), &(frame_body[2]), sizeof(struct ADDBA_request)); - process_addba_req(padapter, (u8 *)&(pmlmeinfo->ADDBA_req), addr); + pattrib->last_txcmdsz = pattrib->pktlen; - if (pmlmeinfo->bAcceptAddbaReq) - issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 0); - else - issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 37);/* reject ADDBA Req */ - break; - case RTW_WLAN_ACTION_ADDBA_RESP: /* ADDBA response */ - status = get_unaligned_le16(&frame_body[3]); - tid = (frame_body[5] >> 2) & 0x7; - if (status == 0) { /* successful */ - DBG_88E("agg_enable for TID=%d\n", tid); - psta->htpriv.agg_enable_bitmap |= 1 << tid; - psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); - } else { - psta->htpriv.agg_enable_bitmap &= ~BIT(tid); - } - break; - case RTW_WLAN_ACTION_DELBA: /* DELBA */ - if ((frame_body[3] & BIT(3)) == 0) { - psta->htpriv.agg_enable_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf)); - psta->htpriv.candidate_tid_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf)); - reason_code = get_unaligned_le16(&frame_body[4]); - } else if ((frame_body[3] & BIT(3)) == BIT(3)) { - tid = (frame_body[3] >> 4) & 0x0F; - preorder_ctrl = &psta->recvreorder_ctrl[tid]; - preorder_ctrl->enable = false; - preorder_ctrl->indicate_seq = 0xffff; - } - DBG_88E("%s(): DELBA: %x(%x)\n", __func__, pmlmeinfo->agg_enable_bitmap, reason_code); - /* todo: how to notify the host while receiving DELETE BA */ - break; - default: - break; - } + if (wait_ack) { + ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); + } else { + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; } - return _SUCCESS; + +exit: + return ret; } -static s32 rtw_action_public_decache(struct recv_frame *recv_frame, s32 token) +/* when wait_ms > 0 , this function should be called at process context */ +/* da == NULL for station mode */ +int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int try_cnt, int wait_ms) { - struct adapter *adapter = recv_frame->adapter; - struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv); - u8 *frame = recv_frame->rx_data; - u16 seq_ctrl = ((recv_frame->attrib.seq_num&0xffff) << 4) | - (recv_frame->attrib.frag_num & 0xf); - - if (GetRetry(frame)) { - if (token >= 0) { - if ((seq_ctrl == mlmeext->action_public_rxseq) && (token == mlmeext->action_public_dialog_token)) { - DBG_88E(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x, token:%d\n", - FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq, token); - return _FAIL; - } - } else { - if (seq_ctrl == mlmeext->action_public_rxseq) { - DBG_88E(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x\n", - FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq); - return _FAIL; - } - } - } + int ret; + int i = 0; + u32 start = jiffies; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); - mlmeext->action_public_rxseq = seq_ctrl; + /* da == NULL, assume it's null data for sta to ap*/ + if (da == NULL) + da = pnetwork->MacAddress; - if (token >= 0) - mlmeext->action_public_dialog_token = token; + do { + ret = _issue_qos_nulldata(padapter, da, tid, wait_ms > 0 ? true : false); - return _SUCCESS; -} + i++; -static unsigned int on_action_public_p2p(struct recv_frame *precv_frame) -{ - u8 *pframe = precv_frame->rx_data; - u8 *frame_body; - u8 dialogToken = 0; - frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); + if (padapter->bDriverStopped || padapter->bSurpriseRemoved) + break; - dialogToken = frame_body[7]; + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + msleep(wait_ms); + } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); - if (rtw_action_public_decache(precv_frame, dialogToken) == _FAIL) - return _FAIL; + if (ret != _FAIL) { + ret = _SUCCESS; + goto exit; + } - return _SUCCESS; + if (try_cnt && wait_ms) { + if (da) + DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + else + DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + } +exit: + return ret; } -static unsigned int on_action_public_vendor(struct recv_frame *precv_frame) +static int _issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason, u8 wait_ack) { - unsigned int ret = _FAIL; - u8 *pframe = precv_frame->rx_data; - u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + __le16 *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); + int ret = _FAIL; + __le16 le_tmp; - if (!memcmp(frame_body + 2, P2P_OUI, 4)) - ret = on_action_public_p2p(precv_frame); + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; - return ret; -} + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + pattrib->retry_ctrl = false; -static unsigned int on_action_public_default(struct recv_frame *precv_frame, u8 action) -{ - unsigned int ret = _FAIL; - u8 *pframe = precv_frame->rx_data; - u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); - u8 token; + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - token = frame_body[2]; + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; - if (rtw_action_public_decache(precv_frame, token) == _FAIL) - goto exit; + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; - ret = _SUCCESS; + memcpy(pwlanhdr->addr1, da, ETH_ALEN); + memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); + memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN); -exit: - return ret; -} + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_DEAUTH); -unsigned int on_action_public(struct adapter *padapter, struct recv_frame *precv_frame) -{ - unsigned int ret = _FAIL; - u8 *pframe = precv_frame->rx_data; - u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); - u8 category, action; + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); - /* check RA matches or not */ - if (memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN)) - goto exit; + le_tmp = cpu_to_le16(reason); + pframe = rtw_set_fixed_ie(pframe, _RSON_CODE_ , (unsigned char *)&le_tmp, &(pattrib->pktlen)); - category = frame_body[0]; - if (category != RTW_WLAN_CATEGORY_PUBLIC) - goto exit; + pattrib->last_txcmdsz = pattrib->pktlen; - action = frame_body[1]; - switch (action) { - case ACT_PUBLIC_VENDOR: - ret = on_action_public_vendor(precv_frame); - break; - default: - ret = on_action_public_default(precv_frame, action); - break; + + if (wait_ack) { + ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); + } else { + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; } exit: return ret; } -unsigned int OnAction_ht(struct adapter *padapter, struct recv_frame *precv_frame) +int issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason) { - return _SUCCESS; + DBG_88E("%s to %pM\n", __func__, da); + return _issue_deauth(padapter, da, reason, false); } -unsigned int OnAction_wmm(struct adapter *padapter, struct recv_frame *precv_frame) +int issue_deauth_ex(struct adapter *padapter, u8 *da, unsigned short reason, int try_cnt, + int wait_ms) { - return _SUCCESS; -} + int ret; + int i = 0; + u32 start = jiffies; -unsigned int OnAction_p2p(struct adapter *padapter, struct recv_frame *precv_frame) -{ - return _SUCCESS; -} + do { + ret = _issue_deauth(padapter, da, reason, wait_ms > 0 ? true : false); -unsigned int OnAction(struct adapter *padapter, struct recv_frame *precv_frame) -{ - int i; - unsigned char category; - struct action_handler *ptable; - unsigned char *frame_body; - u8 *pframe = precv_frame->rx_data; - - frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); - - category = frame_body[0]; - - for (i = 0; i < sizeof(OnAction_tbl)/sizeof(struct action_handler); i++) { - ptable = &OnAction_tbl[i]; - if (category == ptable->num) - ptable->func(padapter, precv_frame); - } - return _SUCCESS; -} + i++; -unsigned int DoReserved(struct adapter *padapter, struct recv_frame *precv_frame) -{ - return _SUCCESS; -} + if (padapter->bDriverStopped || padapter->bSurpriseRemoved) + break; -struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv) -{ - struct xmit_frame *pmgntframe; - struct xmit_buf *pxmitbuf; + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + msleep(wait_ms); + } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); - pmgntframe = rtw_alloc_xmitframe(pxmitpriv); - if (pmgntframe == NULL) { - DBG_88E("%s, alloc xmitframe fail\n", __func__); - return NULL; + if (ret != _FAIL) { + ret = _SUCCESS; + goto exit; } - pxmitbuf = rtw_alloc_xmitbuf_ext(pxmitpriv); - if (pxmitbuf == NULL) { - DBG_88E("%s, alloc xmitbuf fail\n", __func__); - rtw_free_xmitframe(pxmitpriv, pmgntframe); - return NULL; + if (try_cnt && wait_ms) { + if (da) + DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + else + DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); } - pmgntframe->frame_tag = MGNT_FRAMETAG; - pmgntframe->pxmitbuf = pxmitbuf; - pmgntframe->buf_addr = pxmitbuf->pbuf; - pxmitbuf->priv_data = pmgntframe; - return pmgntframe; -} - -/**************************************************************************** - -Following are some TX functions for WiFi MLME - -*****************************************************************************/ - -void update_mgnt_tx_rate(struct adapter *padapter, u8 rate) -{ - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); - - pmlmeext->tx_rate = rate; - DBG_88E("%s(): rate = %x\n", __func__, rate); +exit: + return ret; } -void update_mgntframe_attrib(struct adapter *padapter, struct pkt_attrib *pattrib) +void issue_action_spct_ch_switch(struct adapter *padapter, u8 *ra, u8 new_ch, u8 ch_offset) { + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + __le16 *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); - memset((u8 *)(pattrib), 0, sizeof(struct pkt_attrib)); - - pattrib->hdrlen = 24; - pattrib->nr_frags = 1; - pattrib->priority = 7; - pattrib->mac_id = 0; - pattrib->qsel = 0x12; - - pattrib->pktlen = 0; - - if (pmlmeext->cur_wireless_mode & WIRELESS_11B) - pattrib->raid = 6;/* b mode */ - else - pattrib->raid = 5;/* a/g mode */ - - pattrib->encrypt = _NO_PRIVACY_; - pattrib->bswenc = false; - - pattrib->qos_en = false; - pattrib->ht_en = false; - pattrib->bwmode = HT_CHANNEL_WIDTH_20; - pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; - pattrib->sgi = false; - - pattrib->seqnum = pmlmeext->mgnt_seq; - pattrib->retry_ctrl = true; -} + DBG_88E(FUNC_NDEV_FMT" ra =%pM, ch:%u, offset:%u\n", + FUNC_NDEV_ARG(padapter->pnetdev), ra, new_ch, ch_offset); -void dump_mgntframe(struct adapter *padapter, struct xmit_frame *pmgntframe) -{ - if (padapter->bSurpriseRemoved || padapter->bDriverStopped) + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) return; - rtw_hal_mgnt_xmit(padapter, pmgntframe); -} - -s32 dump_mgntframe_and_wait(struct adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms) -{ - s32 ret = _FAIL; - struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf; - struct submit_ctx sctx; - - if (padapter->bSurpriseRemoved || padapter->bDriverStopped) - return ret; + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); - rtw_sctx_init(&sctx, timeout_ms); - pxmitbuf->sctx = &sctx; + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - ret = rtw_hal_mgnt_xmit(padapter, pmgntframe); + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; - if (ret == _SUCCESS) - ret = rtw_sctx_wait(&sctx); + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; - return ret; -} + memcpy(pwlanhdr->addr1, ra, ETH_ALEN); /* RA */ + memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); /* TA */ + memcpy(pwlanhdr->addr3, ra, ETH_ALEN); /* DA = RA */ -s32 dump_mgntframe_and_wait_ack(struct adapter *padapter, struct xmit_frame *pmgntframe) -{ - s32 ret = _FAIL; - u32 timeout_ms = 500;/* 500ms */ - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ACTION); - if (padapter->bSurpriseRemoved || padapter->bDriverStopped) - return -1; + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); - _enter_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL); - pxmitpriv->ack_tx = true; + /* category, action */ + { + u8 category, action; + category = RTW_WLAN_CATEGORY_SPECTRUM_MGMT; + action = RTW_WLAN_ACTION_SPCT_CHL_SWITCH; - pmgntframe->ack_report = 1; - if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS) { - ret = rtw_ack_tx_wait(pxmitpriv, timeout_ms); + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); } - pxmitpriv->ack_tx = false; - mutex_unlock(&pxmitpriv->ack_tx_mutex); - - return ret; -} - -static int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode) -{ - u8 *ssid_ie; - int ssid_len_ori; - int len_diff = 0; - - ssid_ie = rtw_get_ie(ies, WLAN_EID_SSID, &ssid_len_ori, ies_len); - - if (ssid_ie && ssid_len_ori > 0) { - switch (hidden_ssid_mode) { - case 1: { - u8 *next_ie = ssid_ie + 2 + ssid_len_ori; - u32 remain_len = 0; - - remain_len = ies_len - (next_ie - ies); - - ssid_ie[1] = 0; - memcpy(ssid_ie+2, next_ie, remain_len); - len_diff -= ssid_len_ori; + pframe = rtw_set_ie_ch_switch(pframe, &(pattrib->pktlen), 0, new_ch, 0); + pframe = rtw_set_ie_secondary_ch_offset(pframe, &(pattrib->pktlen), + hal_ch_offset_to_secondary_ch_offset(ch_offset)); - break; - } - case 2: - memset(&ssid_ie[2], 0, ssid_len_ori); - break; - default: - break; - } - } + pattrib->last_txcmdsz = pattrib->pktlen; - return len_diff; + dump_mgntframe(padapter, pmgntframe); } -void issue_beacon(struct adapter *padapter, int timeout_ms) +void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short status) { - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; + u8 category = RTW_WLAN_CATEGORY_BACK; + u16 start_seq; + u16 BA_para_set; + u16 reason_code; + u16 BA_timeout_value; + __le16 le_tmp; + u16 BA_starting_seqctrl = 0; + enum ht_cap_ampdu_factor max_rx_ampdu_factor; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + u8 *pframe; struct rtw_ieee80211_hdr *pwlanhdr; __le16 *fctrl; - unsigned int rate_len; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); - u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + struct registry_priv *pregpriv = &padapter->registrypriv; + struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); + + DBG_88E("%s, category=%d, action=%d, status=%d\n", __func__, category, action, status); pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) { - DBG_88E("%s, alloc mgnt frame fail\n", __func__); + if (pmgntframe == NULL) return; - } -#if defined(CONFIG_88EU_AP_MODE) - spin_lock_bh(&pmlmepriv->bcn_update_lock); -#endif /* if defined (CONFIG_88EU_AP_MODE) */ /* update attribute */ pattrib = &pmgntframe->attrib; update_mgntframe_attrib(padapter, pattrib); - pattrib->qsel = 0x10; memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; - fctrl = &(pwlanhdr->frame_ctl); *(fctrl) = 0; - memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); + /* memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); */ + memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); - memcpy(pwlanhdr->addr3, cur_network->MacAddress, ETH_ALEN); - - SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); - /* pmlmeext->mgnt_seq++; */ - SetFrameSubType(pframe, WIFI_BEACON); + memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN); - pframe += sizeof(struct rtw_ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); - - if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { - int len_diff; - u8 *wps_ie; - uint wps_ielen; - u8 sr = 0; - memcpy(pframe, cur_network->IEs, cur_network->IELength); - len_diff = update_hidden_ssid( - pframe+_BEACON_IE_OFFSET_ - , cur_network->IELength-_BEACON_IE_OFFSET_ - , pmlmeinfo->hidden_ssid_mode - ); - pframe += (cur_network->IELength+len_diff); - pattrib->pktlen += (cur_network->IELength+len_diff); - wps_ie = rtw_get_wps_ie(pmgntframe->buf_addr+TXDESC_OFFSET+sizeof(struct rtw_ieee80211_hdr_3addr)+_BEACON_IE_OFFSET_, - pattrib->pktlen-sizeof(struct rtw_ieee80211_hdr_3addr)-_BEACON_IE_OFFSET_, NULL, &wps_ielen); - if (wps_ie && wps_ielen > 0) - rtw_get_wps_attr_content(wps_ie, wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL); - if (sr != 0) - set_fwstate(pmlmepriv, WIFI_UNDER_WPS); - else - _clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS); - - goto _issue_bcn; - } - - /* below for ad-hoc mode */ - - /* timestamp will be inserted by hardware */ - pframe += 8; - pattrib->pktlen += 8; - - /* beacon interval: 2 bytes */ - - memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ACTION); - pframe += 2; - pattrib->pktlen += 2; + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); - /* capability info: 2 bytes */ + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); - memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); + if (category == 3) { + switch (action) { + case 0: /* ADDBA req */ + do { + pmlmeinfo->dialogToken++; + } while (pmlmeinfo->dialogToken == 0); + pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->dialogToken), &(pattrib->pktlen)); - pframe += 2; - pattrib->pktlen += 2; + BA_para_set = 0x1002 | ((status & 0xf) << 2); /* immediate ack & 64 buffer size */ + le_tmp = cpu_to_le16(BA_para_set); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); - /* SSID */ - pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen); + BA_timeout_value = 5000;/* 5ms */ + le_tmp = cpu_to_le16(BA_timeout_value); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); - /* supported rates... */ - rate_len = rtw_get_rateset_len(cur_network->SupportedRates); - pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pattrib->pktlen); + psta = rtw_get_stainfo(pstapriv, raddr); + if (psta != NULL) { + start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07]&0xfff) + 1; - /* DS parameter set */ - pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen); + DBG_88E("BA_starting_seqctrl=%d for TID=%d\n", start_seq, status & 0x07); - { - u8 erpinfo = 0; - u32 ATIMWindow; - /* IBSS Parameter Set... */ - ATIMWindow = 0; - pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen); + psta->BA_starting_seqctrl[status & 0x07] = start_seq; - /* ERP IE */ - pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen); - } + BA_starting_seqctrl = start_seq << 4; + } + le_tmp = cpu_to_le16(BA_starting_seqctrl); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); + break; + case 1: /* ADDBA rsp */ + pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->ADDBA_req.dialog_token), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&status), &(pattrib->pktlen)); - /* EXTERNDED SUPPORTED RATE */ - if (rate_len > 8) - pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen); - /* todo:HT for adhoc */ -_issue_bcn: + BA_para_set = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f; + rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); + switch (max_rx_ampdu_factor) { + case MAX_AMPDU_FACTOR_64K: + BA_para_set |= 0x1000; /* 64 buffer size */ + break; + case MAX_AMPDU_FACTOR_32K: + BA_para_set |= 0x0800; /* 32 buffer size */ + break; + case MAX_AMPDU_FACTOR_16K: + BA_para_set |= 0x0400; /* 16 buffer size */ + break; + case MAX_AMPDU_FACTOR_8K: + BA_para_set |= 0x0200; /* 8 buffer size */ + break; + default: + BA_para_set |= 0x1000; /* 64 buffer size */ + break; + } -#if defined(CONFIG_88EU_AP_MODE) - pmlmepriv->update_bcn = false; + if (pregpriv->ampdu_amsdu == 0)/* disabled */ + BA_para_set = BA_para_set & ~BIT(0); + else if (pregpriv->ampdu_amsdu == 1)/* enabled */ + BA_para_set = BA_para_set | BIT(0); + le_tmp = cpu_to_le16(BA_para_set); - spin_unlock_bh(&pmlmepriv->bcn_update_lock); -#endif /* if defined (CONFIG_88EU_AP_MODE) */ + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(pmlmeinfo->ADDBA_req.BA_timeout_value)), &(pattrib->pktlen)); + break; + case 2:/* DELBA */ + BA_para_set = (status & 0x1F) << 3; + le_tmp = cpu_to_le16(BA_para_set); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); - if ((pattrib->pktlen + TXDESC_SIZE) > 512) { - DBG_88E("beacon frame too large\n"); - return; + reason_code = 37;/* Requested from peer STA as it does not want to use the mechanism */ + le_tmp = cpu_to_le16(reason_code); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); + break; + default: + break; + } } pattrib->last_txcmdsz = pattrib->pktlen; - /* DBG_88E("issue bcn_sz=%d\n", pattrib->last_txcmdsz); */ - if (timeout_ms > 0) - dump_mgntframe_and_wait(padapter, pmgntframe, timeout_ms); - else - dump_mgntframe(padapter, pmgntframe); + dump_mgntframe(padapter, pmgntframe); } -void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p_probereq) +static void issue_action_BSSCoexistPacket(struct adapter *padapter) { + struct list_head *plist, *phead; + unsigned char category, action; struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; - unsigned char *pframe; + unsigned char *pframe; struct rtw_ieee80211_hdr *pwlanhdr; __le16 *fctrl; - unsigned char *mac, *bssid; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -#if defined(CONFIG_88EU_AP_MODE) - u8 *pwps_ie; - uint wps_ielen; + struct wlan_network *pnetwork = NULL; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -#endif /* if defined (CONFIG_88EU_AP_MODE) */ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); - unsigned int rate_len; + struct __queue *queue = &(pmlmepriv->scanned_queue); + u8 InfoContent[16] = {0}; + u8 ICS[8][15]; + struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); + + if ((pmlmepriv->num_FortyMHzIntolerant == 0) || (pmlmepriv->num_sta_no_ht == 0)) + return; + + if (pmlmeinfo->bwmode_updated) + return; + + + DBG_88E("%s\n", __func__); + + + category = RTW_WLAN_CATEGORY_PUBLIC; + action = ACT_PUBLIC_BSSCOEXIST; pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) { - DBG_88E("%s, alloc mgnt frame fail\n", __func__); + if (pmgntframe == NULL) return; - } /* update attribute */ pattrib = &pmgntframe->attrib; @@ -2135,2078 +1793,2419 @@ void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; - mac = myid(&(padapter->eeprompriv)); - bssid = cur_network->MacAddress; - fctrl = &(pwlanhdr->frame_ctl); *(fctrl) = 0; - memcpy(pwlanhdr->addr1, da, ETH_ALEN); - memcpy(pwlanhdr->addr2, mac, ETH_ALEN); - memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); + + memcpy(pwlanhdr->addr1, cur_network->MacAddress, ETH_ALEN); + memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); + memcpy(pwlanhdr->addr3, cur_network->MacAddress, ETH_ALEN); SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); pmlmeext->mgnt_seq++; - SetFrameSubType(fctrl, WIFI_PROBERSP); - - pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); - pattrib->pktlen = pattrib->hdrlen; - pframe += pattrib->hdrlen; + SetFrameSubType(pframe, WIFI_ACTION); - if (cur_network->IELength > MAX_IE_SZ) - return; + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -#if defined(CONFIG_88EU_AP_MODE) - if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { - pwps_ie = rtw_get_wps_ie(cur_network->IEs+_FIXED_IE_LENGTH_, cur_network->IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen); + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); - /* inerset & update wps_probe_resp_ie */ - if ((pmlmepriv->wps_probe_resp_ie != NULL) && pwps_ie && (wps_ielen > 0)) { - uint wps_offset, remainder_ielen; - u8 *premainder_ie; - wps_offset = (uint)(pwps_ie - cur_network->IEs); + /* */ + if (pmlmepriv->num_FortyMHzIntolerant > 0) { + u8 iedata = 0; - premainder_ie = pwps_ie + wps_ielen; + iedata |= BIT(2);/* 20 MHz BSS Width Request */ - remainder_ielen = cur_network->IELength - wps_offset - wps_ielen; + pframe = rtw_set_ie(pframe, EID_BSSCoexistence, 1, &iedata, &(pattrib->pktlen)); + } - memcpy(pframe, cur_network->IEs, wps_offset); - pframe += wps_offset; - pattrib->pktlen += wps_offset; - wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1];/* to get ie data len */ - if ((wps_offset+wps_ielen+2) <= MAX_IE_SZ) { - memcpy(pframe, pmlmepriv->wps_probe_resp_ie, wps_ielen+2); - pframe += wps_ielen+2; - pattrib->pktlen += wps_ielen+2; - } + /* */ + memset(ICS, 0, sizeof(ICS)); + if (pmlmepriv->num_sta_no_ht > 0) { + int i; - if ((wps_offset+wps_ielen+2+remainder_ielen) <= MAX_IE_SZ) { - memcpy(pframe, premainder_ie, remainder_ielen); - pframe += remainder_ielen; - pattrib->pktlen += remainder_ielen; - } - } else { - memcpy(pframe, cur_network->IEs, cur_network->IELength); - pframe += cur_network->IELength; - pattrib->pktlen += cur_network->IELength; - } - } else -#endif - { - /* timestamp will be inserted by hardware */ - pframe += 8; - pattrib->pktlen += 8; + spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); - /* beacon interval: 2 bytes */ + phead = get_list_head(queue); + plist = phead->next; - memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); + while (phead != plist) { + int len; + u8 *p; + struct wlan_bssid_ex *pbss_network; - pframe += 2; - pattrib->pktlen += 2; + pnetwork = container_of(plist, struct wlan_network, list); - /* capability info: 2 bytes */ + plist = plist->next; - memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); + pbss_network = (struct wlan_bssid_ex *)&pnetwork->network; - pframe += 2; - pattrib->pktlen += 2; + p = rtw_get_ie(pbss_network->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pbss_network->IELength - _FIXED_IE_LENGTH_); + if ((p == NULL) || (len == 0)) { /* non-HT */ + if ((pbss_network->Configuration.DSConfig <= 0) || (pbss_network->Configuration.DSConfig > 14)) + continue; - /* below for ad-hoc mode */ + ICS[0][pbss_network->Configuration.DSConfig] = 1; - /* SSID */ - pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen); + if (ICS[0][0] == 0) + ICS[0][0] = 1; + } + } + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); - /* supported rates... */ - rate_len = rtw_get_rateset_len(cur_network->SupportedRates); - pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pattrib->pktlen); + for (i = 0; i < 8; i++) { + if (ICS[i][0] == 1) { + int j, k = 0; - /* DS parameter set */ - pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen); + InfoContent[k] = i; + /* SET_BSS_INTOLERANT_ELE_REG_CLASS(InfoContent, i); */ + k++; - if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { - u8 erpinfo = 0; - u32 ATIMWindow; - /* IBSS Parameter Set... */ - /* ATIMWindow = cur->Configuration.ATIMWindow; */ - ATIMWindow = 0; - pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen); + for (j = 1; j <= 14; j++) { + if (ICS[i][j] == 1) { + if (k < 16) { + InfoContent[k] = j; /* channel number */ + /* SET_BSS_INTOLERANT_ELE_CHANNEL(InfoContent+k, j); */ + k++; + } + } + } - /* ERP IE */ - pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen); + pframe = rtw_set_ie(pframe, EID_BSSIntolerantChlReport, k, InfoContent, &(pattrib->pktlen)); + } } - - - /* EXTERNDED SUPPORTED RATE */ - if (rate_len > 8) - pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen); - /* todo:HT for adhoc */ } + pattrib->last_txcmdsz = pattrib->pktlen; dump_mgntframe(padapter, pmgntframe); - - return; } -static int _issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da, int wait_ack) +unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr) { - int ret = _FAIL; - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct rtw_ieee80211_hdr *pwlanhdr; - __le16 *fctrl; - unsigned char *mac; - unsigned char bssrate[NumRates]; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); - int bssrate_len = 0; - u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - - RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+issue_probereq\n")); + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta = NULL; + /* struct recv_reorder_ctrl *preorder_ctrl; */ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u16 tid; - pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) - goto exit; + if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) + if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) + return _SUCCESS; - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib(padapter, pattrib); + psta = rtw_get_stainfo(pstapriv, addr); + if (psta == NULL) + return _SUCCESS; + if (initiator == 0) { /* recipient */ + for (tid = 0; tid < MAXTID; tid++) { + if (psta->recvreorder_ctrl[tid].enable) { + DBG_88E("rx agg disable tid(%d)\n", tid); + issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator)&0x1F)); + psta->recvreorder_ctrl[tid].enable = false; + psta->recvreorder_ctrl[tid].indicate_seq = 0xffff; + } + } + } else if (initiator == 1) { /* originator */ + for (tid = 0; tid < MAXTID; tid++) { + if (psta->htpriv.agg_enable_bitmap & BIT(tid)) { + DBG_88E("tx agg disable tid(%d)\n", tid); + issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator)&0x1F)); + psta->htpriv.agg_enable_bitmap &= ~BIT(tid); + psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); + } + } + } - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + return _SUCCESS; +} - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; +unsigned int send_beacon(struct adapter *padapter) +{ + u8 bxmitok = false; + int issue = 0; + int poll = 0; - mac = myid(&(padapter->eeprompriv)); + u32 start = jiffies; - fctrl = &(pwlanhdr->frame_ctl); - *(fctrl) = 0; + rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); + do { + issue_beacon(padapter, 100); + issue++; + do { + yield(); + rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bxmitok)); + poll++; + } while ((poll%10) != 0 && !bxmitok && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); + } while (!bxmitok && issue < 100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); - if (da) { - /* unicast probe request frame */ - memcpy(pwlanhdr->addr1, da, ETH_ALEN); - memcpy(pwlanhdr->addr3, da, ETH_ALEN); + if (padapter->bSurpriseRemoved || padapter->bDriverStopped) + return _FAIL; + if (!bxmitok) { + DBG_88E("%s fail! %u ms\n", __func__, rtw_get_passing_time_ms(start)); + return _FAIL; } else { - /* broadcast probe request frame */ - memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); - memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN); - } + u32 passing_time = rtw_get_passing_time_ms(start); - memcpy(pwlanhdr->addr2, mac, ETH_ALEN); + if (passing_time > 100 || issue > 3) + DBG_88E("%s success, issue:%d, poll:%d, %u ms\n", __func__, issue, poll, rtw_get_passing_time_ms(start)); + return _SUCCESS; + } +} - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_PROBEREQ); +/**************************************************************************** - pframe += sizeof(struct rtw_ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); +Following are some utility functions for WiFi MLME - if (pssid) - pframe = rtw_set_ie(pframe, _SSID_IE_, pssid->SsidLength, pssid->Ssid, &(pattrib->pktlen)); - else - pframe = rtw_set_ie(pframe, _SSID_IE_, 0, NULL, &(pattrib->pktlen)); +*****************************************************************************/ - get_rate_set(padapter, bssrate, &bssrate_len); +void site_survey(struct adapter *padapter) +{ + unsigned char survey_channel = 0, val8; + enum rt_scan_type ScanType = SCAN_PASSIVE; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u32 initialgain = 0; + struct rtw_ieee80211_channel *ch; - if (bssrate_len > 8) { - pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen)); - pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen)); - } else { - pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen)); + if (pmlmeext->sitesurvey_res.channel_idx < pmlmeext->sitesurvey_res.ch_num) { + ch = &pmlmeext->sitesurvey_res.ch[pmlmeext->sitesurvey_res.channel_idx]; + survey_channel = ch->hw_value; + ScanType = (ch->flags & RTW_IEEE80211_CHAN_PASSIVE_SCAN) ? SCAN_PASSIVE : SCAN_ACTIVE; } - /* add wps_ie for wps2.0 */ - if (pmlmepriv->wps_probe_req_ie_len > 0 && pmlmepriv->wps_probe_req_ie) { - memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len); - pframe += pmlmepriv->wps_probe_req_ie_len; - pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; - } - pattrib->last_txcmdsz = pattrib->pktlen; + if (survey_channel != 0) { + /* PAUSE 4-AC Queue when site_survey */ + /* rtw_hal_get_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ + /* val8 |= 0x0f; */ + /* rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ + if (pmlmeext->sitesurvey_res.channel_idx == 0) + set_channel_bwmode(padapter, survey_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); + else + SelectChannel(padapter, survey_channel); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, - ("issuing probe_req, tx_len=%d\n", pattrib->last_txcmdsz)); + if (ScanType == SCAN_ACTIVE) { /* obey the channel plan setting... */ + int i; + for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) { + if (pmlmeext->sitesurvey_res.ssid[i].SsidLength) { + /* todo: to issue two probe req??? */ + issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL); + /* msleep(SURVEY_TO>>1); */ + issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL); + } + } - if (wait_ack) { - ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); - } else { - dump_mgntframe(padapter, pmgntframe); - ret = _SUCCESS; - } + if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) { + /* todo: to issue two probe req??? */ + issue_probereq(padapter, NULL, NULL); + /* msleep(SURVEY_TO>>1); */ + issue_probereq(padapter, NULL, NULL); + } -exit: - return ret; -} + if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) { + /* todo: to issue two probe req??? */ + issue_probereq(padapter, NULL, NULL); + /* msleep(SURVEY_TO>>1); */ + issue_probereq(padapter, NULL, NULL); + } + } -inline void issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da) -{ - _issue_probereq(padapter, pssid, da, false); -} + set_survey_timer(pmlmeext, pmlmeext->chan_scan_time); + } else { -int issue_probereq_ex(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da, - int try_cnt, int wait_ms) -{ - int ret; - int i = 0; - u32 start = jiffies; + /* 20100721:Interrupt scan operation here. */ + /* For SW antenna diversity before link, it needs to switch to another antenna and scan again. */ + /* It compares the scan result and select better one to do connection. */ + if (rtw_hal_antdiv_before_linked(padapter)) { + pmlmeext->sitesurvey_res.bss_cnt = 0; + pmlmeext->sitesurvey_res.channel_idx = -1; + pmlmeext->chan_scan_time = SURVEY_TO / 2; + set_survey_timer(pmlmeext, pmlmeext->chan_scan_time); + return; + } - do { - ret = _issue_probereq(padapter, pssid, da, wait_ms > 0 ? true : false); + pmlmeext->sitesurvey_res.state = SCAN_COMPLETE; - i++; + /* switch back to the original channel */ - if (padapter->bDriverStopped || padapter->bSurpriseRemoved) - break; + set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); - if (i < try_cnt && wait_ms > 0 && ret == _FAIL) - msleep(wait_ms); + /* flush 4-AC Queue after site_survey */ + /* val8 = 0; */ + /* rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ - } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); + /* config MSR */ + Set_MSR(padapter, (pmlmeinfo->state & 0x3)); - if (ret != _FAIL) { - ret = _SUCCESS; - goto exit; - } + initialgain = 0xff; /* restore RX GAIN */ + rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); + /* turn on dynamic functions */ + Restore_DM_Func_Flag(padapter); + /* Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); */ - if (try_cnt && wait_ms) { - if (da) - DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter), - ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); - else - DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), - ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + if (is_client_associated_to_ap(padapter)) + issue_nulldata(padapter, NULL, 0, 3, 500); + + val8 = 0; /* survey done */ + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + + report_surveydone_event(padapter); + + pmlmeext->chan_scan_time = SURVEY_TO; + pmlmeext->sitesurvey_res.state = SCAN_DISABLE; + + issue_action_BSSCoexistPacket(padapter); + issue_action_BSSCoexistPacket(padapter); + issue_action_BSSCoexistPacket(padapter); } -exit: - return ret; + return; } -/* if psta == NULL, indicate we are station(client) now... */ -void issue_auth(struct adapter *padapter, struct sta_info *psta, unsigned short status) +/* collect bss info from Beacon and Probe request/response frames. */ +u8 collect_bss_info(struct adapter *padapter, struct recv_frame *precv_frame, struct wlan_bssid_ex *bssid) { - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct rtw_ieee80211_hdr *pwlanhdr; - __le16 *fctrl; - unsigned int val32; - u16 val16; -#ifdef CONFIG_88EU_AP_MODE - __le16 le_val16; -#endif - int use_shared_key = 0; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + int i; + u32 len; + u8 *p; + u16 val16, subtype; + u8 *pframe = precv_frame->rx_data; + u32 packet_len = precv_frame->len; + u8 ie_offset; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); - - pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) - return; - - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib(padapter, pattrib); - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + len = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr); - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + if (len > MAX_IE_SZ) + return _FAIL; - fctrl = &(pwlanhdr->frame_ctl); - *(fctrl) = 0; + memset(bssid, 0, sizeof(struct wlan_bssid_ex)); - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_AUTH); + subtype = GetFrameSubType(pframe); - pframe += sizeof(struct rtw_ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + if (subtype == WIFI_BEACON) { + bssid->Reserved[0] = 1; + ie_offset = _BEACON_IE_OFFSET_; + } else { + /* FIXME : more type */ + if (subtype == WIFI_PROBEREQ) { + ie_offset = _PROBEREQ_IE_OFFSET_; + bssid->Reserved[0] = 2; + } else if (subtype == WIFI_PROBERSP) { + ie_offset = _PROBERSP_IE_OFFSET_; + bssid->Reserved[0] = 3; + } else { + bssid->Reserved[0] = 0; + ie_offset = _FIXED_IE_LENGTH_; + } + } + bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len; - if (psta) {/* for AP mode */ -#ifdef CONFIG_88EU_AP_MODE + /* below is to copy the information element */ + bssid->IELength = len; + memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength); - memcpy(pwlanhdr->addr1, psta->hwaddr, ETH_ALEN); - memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); - memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); + /* get the signal strength in dBM.raw data */ + bssid->Rssi = precv_frame->attrib.phy_info.recvpower; + bssid->PhyInfo.SignalQuality = precv_frame->attrib.phy_info.SignalQuality;/* in percentage */ + bssid->PhyInfo.SignalStrength = precv_frame->attrib.phy_info.SignalStrength;/* in percentage */ + rtw_hal_get_def_var(padapter, HAL_DEF_CURRENT_ANTENNA, &bssid->PhyInfo.Optimum_antenna); + /* checking SSID */ + p = rtw_get_ie(bssid->IEs + ie_offset, _SSID_IE_, &len, bssid->IELength - ie_offset); + if (p == NULL) { + DBG_88E("marc: cannot find SSID for survey event\n"); + return _FAIL; + } - /* setting auth algo number */ - val16 = (u16)psta->authalg; + if (len) { + if (len > NDIS_802_11_LENGTH_SSID) { + DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); + return _FAIL; + } + memcpy(bssid->Ssid.Ssid, (p + 2), len); + bssid->Ssid.SsidLength = len; + } else { + bssid->Ssid.SsidLength = 0; + } - if (status != _STATS_SUCCESSFUL_) - val16 = 0; + memset(bssid->SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX); - if (val16) { - le_val16 = cpu_to_le16(val16); - use_shared_key = 1; - } else { - le_val16 = 0; + /* checking rate info... */ + i = 0; + p = rtw_get_ie(bssid->IEs + ie_offset, _SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); + if (p != NULL) { + if (len > NDIS_802_11_LENGTH_RATES_EX) { + DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); + return _FAIL; } + memcpy(bssid->SupportedRates, (p + 2), len); + i = len; + } - pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&le_val16, &(pattrib->pktlen)); - - /* setting auth seq number */ - val16 = (u16)psta->auth_seq; - le_val16 = cpu_to_le16(val16); - pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&le_val16, &(pattrib->pktlen)); + p = rtw_get_ie(bssid->IEs + ie_offset, _EXT_SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); + if (p != NULL) { + if (len > (NDIS_802_11_LENGTH_RATES_EX-i)) { + DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); + return _FAIL; + } + memcpy(bssid->SupportedRates + i, (p + 2), len); + } - /* setting status code... */ - val16 = status; - le_val16 = cpu_to_le16(val16); - pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&le_val16, &(pattrib->pktlen)); + /* todo: */ + bssid->NetworkTypeInUse = Ndis802_11OFDM24; - /* added challenging text... */ - if ((psta->auth_seq == 2) && (psta->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) - pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, psta->chg_txt, &(pattrib->pktlen)); -#endif - } else { - __le32 le_tmp32; - __le16 le_tmp16; - memcpy(pwlanhdr->addr1, pnetwork->MacAddress, ETH_ALEN); - memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); - memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN); + if (bssid->IELength < 12) + return _FAIL; - /* setting auth algo number */ - val16 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ? 1 : 0;/* 0:OPEN System, 1:Shared key */ - if (val16) - use_shared_key = 1; + /* Checking for DSConfig */ + p = rtw_get_ie(bssid->IEs + ie_offset, _DSSET_IE_, &len, bssid->IELength - ie_offset); - /* setting IV for auth seq #3 */ - if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) { - val32 = (pmlmeinfo->iv++) | (pmlmeinfo->key_index << 30); - le_tmp32 = cpu_to_le32(val32); - pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&le_tmp32, &(pattrib->pktlen)); + bssid->Configuration.DSConfig = 0; + bssid->Configuration.Length = 0; - pattrib->iv_len = 4; + if (p) { + bssid->Configuration.DSConfig = *(p + 2); + } else {/* In 5G, some ap do not have DSSET IE */ + /* checking HT info for channel */ + p = rtw_get_ie(bssid->IEs + ie_offset, _HT_ADD_INFO_IE_, &len, bssid->IELength - ie_offset); + if (p) { + struct HT_info_element *HT_info = (struct HT_info_element *)(p + 2); + bssid->Configuration.DSConfig = HT_info->primary_channel; + } else { /* use current channel */ + bssid->Configuration.DSConfig = rtw_get_oper_ch(padapter); } + } - le_tmp16 = cpu_to_le16(val16); - pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&le_tmp16, &(pattrib->pktlen)); - - /* setting auth seq number */ - val16 = pmlmeinfo->auth_seq; - le_tmp16 = cpu_to_le16(val16); - pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&le_tmp16, &(pattrib->pktlen)); + if (subtype == WIFI_PROBEREQ) { + /* FIXME */ + bssid->InfrastructureMode = Ndis802_11Infrastructure; + memcpy(bssid->MacAddress, GetAddr2Ptr(pframe), ETH_ALEN); + bssid->Privacy = 1; + return _SUCCESS; + } + bssid->Configuration.BeaconPeriod = + get_unaligned_le16(rtw_get_beacon_interval_from_ie(bssid->IEs)); - /* setting status code... */ - le_tmp16 = cpu_to_le16(status); - pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&le_tmp16, &(pattrib->pktlen)); + val16 = rtw_get_capability((struct wlan_bssid_ex *)bssid); - /* then checking to see if sending challenging text... */ - if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) { - pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, pmlmeinfo->chg_txt, &(pattrib->pktlen)); - - SetPrivacy(fctrl); + if (val16 & BIT(0)) { + bssid->InfrastructureMode = Ndis802_11Infrastructure; + memcpy(bssid->MacAddress, GetAddr2Ptr(pframe), ETH_ALEN); + } else { + bssid->InfrastructureMode = Ndis802_11IBSS; + memcpy(bssid->MacAddress, GetAddr3Ptr(pframe), ETH_ALEN); + } - pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); + if (val16 & BIT(4)) + bssid->Privacy = 1; + else + bssid->Privacy = 0; - pattrib->encrypt = _WEP40_; + bssid->Configuration.ATIMWindow = 0; - pattrib->icv_len = 4; + /* 20/40 BSS Coexistence check */ + if ((pregistrypriv->wifi_spec == 1) && (!pmlmeinfo->bwmode_updated)) { + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + p = rtw_get_ie(bssid->IEs + ie_offset, _HT_CAPABILITY_IE_, &len, bssid->IELength - ie_offset); + if (p && len > 0) { + struct HT_caps_element *pHT_caps; + pHT_caps = (struct HT_caps_element *)(p + 2); - pattrib->pktlen += pattrib->icv_len; + if (le16_to_cpu(pHT_caps->u.HT_cap_element.HT_caps_info)&BIT(14)) + pmlmepriv->num_FortyMHzIntolerant++; + } else { + pmlmepriv->num_sta_no_ht++; } } - pattrib->last_txcmdsz = pattrib->pktlen; - - rtw_wep_encrypt(padapter, (u8 *)pmgntframe); - DBG_88E("%s\n", __func__); - dump_mgntframe(padapter, pmgntframe); - - return; + /* mark bss info receiving from nearby channel as SignalQuality 101 */ + if (bssid->Configuration.DSConfig != rtw_get_oper_ch(padapter)) + bssid->PhyInfo.SignalQuality = 101; + return _SUCCESS; } - -void issue_asocrsp(struct adapter *padapter, unsigned short status, struct sta_info *pstat, int pkt_type) +void start_create_ibss(struct adapter *padapter) { -#ifdef CONFIG_88EU_AP_MODE - struct xmit_frame *pmgntframe; - struct rtw_ieee80211_hdr *pwlanhdr; - struct pkt_attrib *pattrib; - unsigned char *pbuf, *pframe; - unsigned short val; - __le16 *fctrl; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + unsigned short caps; + u8 val8; + u8 join_type; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); - u8 *ie = pnetwork->IEs; - __le16 lestatus, leval; - - DBG_88E("%s\n", __func__); - - pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) - return; + struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network)); + pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig; + pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork); - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib(padapter, pattrib); + /* update wireless mode */ + update_wireless_mode(padapter); + /* update capability */ + caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork); + update_capinfo(padapter, caps); + if (caps&cap_IBSS) {/* adhoc master */ + val8 = 0xcf; + rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + /* switch channel */ + /* SelectChannel(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE); */ + set_channel_bwmode(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + beacon_timing_control(padapter); - fctrl = &(pwlanhdr->frame_ctl); - *(fctrl) = 0; + /* set msr to WIFI_FW_ADHOC_STATE */ + pmlmeinfo->state = WIFI_FW_ADHOC_STATE; + Set_MSR(padapter, (pmlmeinfo->state & 0x3)); - memcpy((void *)GetAddr1Ptr(pwlanhdr), pstat->hwaddr, ETH_ALEN); - memcpy((void *)GetAddr2Ptr(pwlanhdr), myid(&(padapter->eeprompriv)), ETH_ALEN); - memcpy((void *)GetAddr3Ptr(pwlanhdr), pnetwork->MacAddress, ETH_ALEN); + /* issue beacon */ + if (send_beacon(padapter) == _FAIL) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("issuing beacon frame fail....\n")); + report_join_res(padapter, -1); + pmlmeinfo->state = WIFI_FW_NULL_STATE; + } else { + rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, padapter->registrypriv.dev_network.MacAddress); + join_type = 0; + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP)) - SetFrameSubType(pwlanhdr, pkt_type); - else + report_join_res(padapter, 1); + pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; + } + } else { + DBG_88E("start_create_ibss, invalid cap:%x\n", caps); return; + } +} - pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); - pattrib->pktlen += pattrib->hdrlen; - pframe += pattrib->hdrlen; - - /* capability */ - val = *(unsigned short *)rtw_get_capability_from_ie(ie); +void start_clnt_join(struct adapter *padapter) +{ + unsigned short caps; + u8 val8; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network)); + int beacon_timeout; - pframe = rtw_set_fixed_ie(pframe, _CAPABILITY_ , (unsigned char *)&val, &(pattrib->pktlen)); + pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig; + pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork); - lestatus = cpu_to_le16(status); - pframe = rtw_set_fixed_ie(pframe , _STATUS_CODE_ , (unsigned char *)&lestatus, &(pattrib->pktlen)); + /* update wireless mode */ + update_wireless_mode(padapter); - leval = cpu_to_le16(pstat->aid | BIT(14) | BIT(15)); - pframe = rtw_set_fixed_ie(pframe, _ASOC_ID_ , (unsigned char *)&leval, &(pattrib->pktlen)); + /* update capability */ + caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork); + update_capinfo(padapter, caps); + if (caps&cap_ESS) { + Set_MSR(padapter, WIFI_FW_STATION_STATE); - if (pstat->bssratelen <= 8) { - pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, pstat->bssratelen, pstat->bssrateset, &(pattrib->pktlen)); - } else { - pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pstat->bssrateset, &(pattrib->pktlen)); - pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (pstat->bssratelen-8), pstat->bssrateset+8, &(pattrib->pktlen)); - } + val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf; - if ((pstat->flags & WLAN_STA_HT) && (pmlmepriv->htpriv.ht_option)) { - uint ie_len = 0; + rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); - /* FILL HT CAP INFO IE */ - pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); - if (pbuf && ie_len > 0) { - memcpy(pframe, pbuf, ie_len+2); - pframe += (ie_len+2); - pattrib->pktlen += (ie_len+2); - } + /* switch channel */ + set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); - /* FILL HT ADD INFO IE */ - pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); - if (pbuf && ie_len > 0) { - memcpy(pframe, pbuf, ie_len+2); - pframe += (ie_len+2); - pattrib->pktlen += (ie_len+2); - } - } + /* here wait for receiving the beacon to start auth */ + /* and enable a timer */ + beacon_timeout = decide_wait_for_beacon_timeout(pmlmeinfo->bcn_interval); + set_link_timer(pmlmeext, beacon_timeout); + mod_timer(&padapter->mlmepriv.assoc_timer, jiffies + + msecs_to_jiffies((REAUTH_TO * REAUTH_LIMIT) + (REASSOC_TO * REASSOC_LIMIT) + beacon_timeout)); - /* FILL WMM IE */ - if ((pstat->flags & WLAN_STA_WME) && (pmlmepriv->qospriv.qos_option)) { - uint ie_len = 0; - unsigned char WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; + pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE; + } else if (caps&cap_IBSS) { /* adhoc client */ + Set_MSR(padapter, WIFI_FW_ADHOC_STATE); - for (pbuf = ie + _BEACON_IE_OFFSET_;; pbuf += (ie_len + 2)) { - pbuf = rtw_get_ie(pbuf, _VENDOR_SPECIFIC_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); - if (pbuf && !memcmp(pbuf+2, WMM_PARA_IE, 6)) { - memcpy(pframe, pbuf, ie_len+2); - pframe += (ie_len+2); - pattrib->pktlen += (ie_len+2); - break; - } + val8 = 0xcf; + rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); - if ((pbuf == NULL) || (ie_len == 0)) - break; - } - } + /* switch channel */ + set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); - if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) - pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen)); + beacon_timing_control(padapter); - /* add WPS IE ie for wps 2.0 */ - if (pmlmepriv->wps_assoc_resp_ie && pmlmepriv->wps_assoc_resp_ie_len > 0) { - memcpy(pframe, pmlmepriv->wps_assoc_resp_ie, pmlmepriv->wps_assoc_resp_ie_len); + pmlmeinfo->state = WIFI_FW_ADHOC_STATE; - pframe += pmlmepriv->wps_assoc_resp_ie_len; - pattrib->pktlen += pmlmepriv->wps_assoc_resp_ie_len; + report_join_res(padapter, 1); + } else { + return; } - - pattrib->last_txcmdsz = pattrib->pktlen; - dump_mgntframe(padapter, pmgntframe); -#endif } -void issue_assocreq(struct adapter *padapter) +void start_clnt_auth(struct adapter *padapter) { - int ret = _FAIL; - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe, *p; - struct rtw_ieee80211_hdr *pwlanhdr; - __le16 *fctrl; - __le16 le_tmp; - unsigned int i, j, ie_len, index = 0; - unsigned char rf_type, bssrate[NumRates], sta_bssrate[NumRates]; - struct ndis_802_11_var_ie *pIE; - struct registry_priv *pregpriv = &padapter->registrypriv; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - int bssrate_len = 0, sta_bssrate_len = 0; - struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); - pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) - goto exit; + del_timer_sync(&pmlmeext->link_timer); - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib(padapter, pattrib); + pmlmeinfo->state &= (~WIFI_FW_AUTH_NULL); + pmlmeinfo->state |= WIFI_FW_AUTH_STATE; - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + pmlmeinfo->auth_seq = 1; + pmlmeinfo->reauth_count = 0; + pmlmeinfo->reassoc_count = 0; + pmlmeinfo->link_count = 0; + pmlmeext->retry = 0; - fctrl = &(pwlanhdr->frame_ctl); - *(fctrl) = 0; - memcpy(pwlanhdr->addr1, pnetwork->MacAddress, ETH_ALEN); - memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); - memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN); - - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_ASSOCREQ); - pframe += sizeof(struct rtw_ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + /* Because of AP's not receiving deauth before */ + /* AP may: 1)not response auth or 2)deauth us after link is complete */ + /* issue deauth before issuing auth to deal with the situation */ + /* Commented by Albert 2012/07/21 */ + /* For the Win8 P2P connection, it will be hard to have a successful connection if this Wi-Fi doesn't connect to it. */ + issue_deauth(padapter, (&(pmlmeinfo->network))->MacAddress, WLAN_REASON_DEAUTH_LEAVING); - /* caps */ + DBG_88E_LEVEL(_drv_info_, "start auth\n"); + issue_auth(padapter, NULL, 0); - memcpy(pframe, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2); + set_link_timer(pmlmeext, REAUTH_TO); +} - pframe += 2; - pattrib->pktlen += 2; - /* listen interval */ - /* todo: listen interval for power saving */ - le_tmp = cpu_to_le16(3); - memcpy(pframe , (unsigned char *)&le_tmp, 2); - pframe += 2; - pattrib->pktlen += 2; +void start_clnt_assoc(struct adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - /* SSID */ - pframe = rtw_set_ie(pframe, _SSID_IE_, pmlmeinfo->network.Ssid.SsidLength, pmlmeinfo->network.Ssid.Ssid, &(pattrib->pktlen)); + del_timer_sync(&pmlmeext->link_timer); - /* supported rate & extended supported rate */ + pmlmeinfo->state &= (~(WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE)); + pmlmeinfo->state |= (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE); - /* Check if the AP's supported rates are also supported by STA. */ - get_rate_set(padapter, sta_bssrate, &sta_bssrate_len); + issue_assocreq(padapter); - if (pmlmeext->cur_channel == 14)/* for JAPAN, channel 14 can only uses B Mode(CCK) */ - sta_bssrate_len = 4; + set_link_timer(pmlmeext, REASSOC_TO); +} - for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { - if (pmlmeinfo->network.SupportedRates[i] == 0) - break; - DBG_88E("network.SupportedRates[%d]=%02X\n", i, pmlmeinfo->network.SupportedRates[i]); - } +unsigned int receive_disconnect(struct adapter *padapter, unsigned char *MacAddr, unsigned short reason) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); - for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { - if (pmlmeinfo->network.SupportedRates[i] == 0) - break; + /* check A3 */ + if (memcmp(MacAddr, pnetwork->MacAddress, ETH_ALEN)) + return _SUCCESS; - /* Check if the AP's supported rates are also supported by STA. */ - for (j = 0; j < sta_bssrate_len; j++) { - /* Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP */ - if ((pmlmeinfo->network.SupportedRates[i]|IEEE80211_BASIC_RATE_MASK) - == (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK)) - break; - } + DBG_88E("%s\n", __func__); - if (j == sta_bssrate_len) { - /* the rate is not supported by STA */ - DBG_88E("%s(): the rate[%d]=%02X is not supported by STA!\n", __func__, i, pmlmeinfo->network.SupportedRates[i]); - } else { - /* the rate is supported by STA */ - bssrate[index++] = pmlmeinfo->network.SupportedRates[i]; + if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) { + if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { + pmlmeinfo->state = WIFI_FW_NULL_STATE; + report_del_sta_event(padapter, MacAddr, reason); + } else if (pmlmeinfo->state & WIFI_FW_LINKING_STATE) { + pmlmeinfo->state = WIFI_FW_NULL_STATE; + report_join_res(padapter, -2); } } + return _SUCCESS; +} - bssrate_len = index; - DBG_88E("bssrate_len=%d\n", bssrate_len); - - if (bssrate_len == 0) { - rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); - rtw_free_xmitframe(pxmitpriv, pmgntframe); - goto exit; /* don't connect to AP if no joint supported rate */ - } +static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid) +{ + struct registry_priv *pregistrypriv; + struct mlme_ext_priv *pmlmeext; + struct rt_channel_info *chplan_new; + u8 channel; + u8 i; + pregistrypriv = &padapter->registrypriv; + pmlmeext = &padapter->mlmeextpriv; - if (bssrate_len > 8) { - pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen)); - pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen)); - } else { - pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen)); - } + /* Adjust channel plan by AP Country IE */ + if (pregistrypriv->enable80211d && + (!pmlmeext->update_channel_plan_by_ap_done)) { + u8 *ie, *p; + u32 len; + struct rt_channel_plan chplan_ap; + struct rt_channel_info chplan_sta[MAX_CHANNEL_NUM]; + u8 country[4]; + u8 fcn; /* first channel number */ + u8 noc; /* number of channel */ + u8 j, k; - /* RSN */ - p = rtw_get_ie((pmlmeinfo->network.IEs + sizeof(struct ndis_802_11_fixed_ie)), _RSN_IE_2_, &ie_len, (pmlmeinfo->network.IELength - sizeof(struct ndis_802_11_fixed_ie))); - if (p != NULL) - pframe = rtw_set_ie(pframe, _RSN_IE_2_, ie_len, (p + 2), &(pattrib->pktlen)); + ie = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _COUNTRY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); + if (!ie) + return; + if (len < 6) + return; + ie += 2; + p = ie; + ie += len; - /* HT caps */ - if (padapter->mlmepriv.htpriv.ht_option) { - p = rtw_get_ie((pmlmeinfo->network.IEs + sizeof(struct ndis_802_11_fixed_ie)), _HT_CAPABILITY_IE_, &ie_len, (pmlmeinfo->network.IELength - sizeof(struct ndis_802_11_fixed_ie))); - if ((p != NULL) && (!(is_ap_in_tkip(padapter)))) { - memcpy(&(pmlmeinfo->HT_caps), (p + 2), sizeof(struct HT_caps_element)); + memset(country, 0, 4); + memcpy(country, p, 3); + p += 3; + RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, + ("%s: 802.11d country =%s\n", __func__, country)); - /* to disable 40M Hz support while gd_bw_40MHz_en = 0 */ - if (pregpriv->cbw40_enable == 0) - pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info &= cpu_to_le16(~(BIT(6) | BIT(1))); - else - pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(BIT(1)); + i = 0; + while ((ie - p) >= 3) { + fcn = *(p++); + noc = *(p++); + p++; - /* todo: disable SM power save mode */ - pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x000c); + for (j = 0; j < noc; j++) { + if (fcn <= 14) + channel = fcn + j; /* 2.4 GHz */ + else + channel = fcn + j*4; /* 5 GHz */ - rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); - switch (rf_type) { - case RF_1T1R: - if (pregpriv->rx_stbc) - pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0100);/* RX STBC One spatial stream */ - memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_1R, 16); - break; - case RF_2T2R: - case RF_1T2R: - default: - if ((pregpriv->rx_stbc == 0x3) ||/* enable for 2.4/5 GHz */ - ((pmlmeext->cur_wireless_mode & WIRELESS_11_24N) && (pregpriv->rx_stbc == 0x1)) || /* enable for 2.4GHz */ - (pregpriv->wifi_spec == 1)) { - DBG_88E("declare supporting RX STBC\n"); - pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0200);/* RX STBC two spatial stream */ - } - memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_2R, 16); - break; + chplan_ap.Channel[i++] = channel; } - pframe = rtw_set_ie(pframe, _HT_CAPABILITY_IE_, ie_len , (u8 *)(&(pmlmeinfo->HT_caps)), &(pattrib->pktlen)); } - } - - /* vendor specific IE, such as WPA, WMM, WPS */ - for (i = sizeof(struct ndis_802_11_fixed_ie); i < pmlmeinfo->network.IELength;) { - pIE = (struct ndis_802_11_var_ie *)(pmlmeinfo->network.IEs + i); + chplan_ap.Len = i; - switch (pIE->ElementID) { - case _VENDOR_SPECIFIC_IE_: - if ((!memcmp(pIE->data, RTW_WPA_OUI, 4)) || - (!memcmp(pIE->data, WMM_OUI, 4)) || - (!memcmp(pIE->data, WPS_OUI, 4))) { - if (!padapter->registrypriv.wifi_spec) { - /* Commented by Kurt 20110629 */ - /* In some older APs, WPS handshake */ - /* would be fail if we append vender extensions informations to AP */ - if (!memcmp(pIE->data, WPS_OUI, 4)) - pIE->Length = 14; - } - pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, pIE->Length, pIE->data, &(pattrib->pktlen)); - } - break; - default: - break; - } - i += (pIE->Length + 2); - } + memcpy(chplan_sta, pmlmeext->channel_set, sizeof(chplan_sta)); - if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) - pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen)); + memset(pmlmeext->channel_set, 0, sizeof(pmlmeext->channel_set)); + chplan_new = pmlmeext->channel_set; - pattrib->last_txcmdsz = pattrib->pktlen; - dump_mgntframe(padapter, pmgntframe); + i = 0; + j = 0; + k = 0; + if (pregistrypriv->wireless_mode & WIRELESS_11G) { + do { + if ((i == MAX_CHANNEL_NUM) || + (chplan_sta[i].ChannelNum == 0) || + (chplan_sta[i].ChannelNum > 14)) + break; - ret = _SUCCESS; + if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] > 14)) + break; -exit: - if (ret == _SUCCESS) - rtw_buf_update(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len, (u8 *)pwlanhdr, pattrib->pktlen); - else - rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len); + if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + chplan_new[k].ScanType = SCAN_ACTIVE; + i++; + j++; + k++; + } else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; + chplan_new[k].ScanType = SCAN_PASSIVE; + i++; + k++; + } else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + chplan_new[k].ScanType = SCAN_ACTIVE; + j++; + k++; + } + } while (1); - return; -} + /* change AP not support channel to Passive scan */ + while ((i < MAX_CHANNEL_NUM) && + (chplan_sta[i].ChannelNum != 0) && + (chplan_sta[i].ChannelNum <= 14)) { + chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; + chplan_new[k].ScanType = SCAN_PASSIVE; + i++; + k++; + } -/* when wait_ack is true, this function should be called at process context */ -static int _issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int wait_ack) -{ - int ret = _FAIL; - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct rtw_ieee80211_hdr *pwlanhdr; - __le16 *fctrl; - struct xmit_priv *pxmitpriv; - struct mlme_ext_priv *pmlmeext; - struct mlme_ext_info *pmlmeinfo; - struct wlan_bssid_ex *pnetwork; + /* add channel AP supported */ + while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) { + chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + chplan_new[k].ScanType = SCAN_ACTIVE; + j++; + k++; + } + } else { + /* keep original STA 2.4G channel plan */ + while ((i < MAX_CHANNEL_NUM) && + (chplan_sta[i].ChannelNum != 0) && + (chplan_sta[i].ChannelNum <= 14)) { + chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; + chplan_new[k].ScanType = chplan_sta[i].ScanType; + i++; + k++; + } - if (!padapter) - goto exit; + /* skip AP 2.4G channel plan */ + while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) + j++; + } - pxmitpriv = &(padapter->xmitpriv); - pmlmeext = &(padapter->mlmeextpriv); - pmlmeinfo = &(pmlmeext->mlmext_info); - pnetwork = &(pmlmeinfo->network); + /* keep original STA 5G channel plan */ + while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) { + chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; + chplan_new[k].ScanType = chplan_sta[i].ScanType; + i++; + k++; + } - pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) - goto exit; + pmlmeext->update_channel_plan_by_ap_done = 1; + } - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib(padapter, pattrib); - pattrib->retry_ctrl = false; + /* If channel is used by AP, set channel scan type to active */ + channel = bssid->Configuration.DSConfig; + chplan_new = pmlmeext->channel_set; + i = 0; + while ((i < MAX_CHANNEL_NUM) && (chplan_new[i].ChannelNum != 0)) { + if (chplan_new[i].ChannelNum == channel) { + if (chplan_new[i].ScanType == SCAN_PASSIVE) { + chplan_new[i].ScanType = SCAN_ACTIVE; + RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, + ("%s: change channel %d scan type from passive to active\n", + __func__, channel)); + } + break; + } + i++; + } +} - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); +/**************************************************************************** - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; +Following are the callback functions for each subtype of the management frames - fctrl = &(pwlanhdr->frame_ctl); - *(fctrl) = 0; +*****************************************************************************/ - if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) - SetFrDs(fctrl); - else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) - SetToDs(fctrl); +unsigned int OnProbeReq(struct adapter *padapter, struct recv_frame *precv_frame) +{ + unsigned int ielen; + unsigned char *p; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wlan_bssid_ex *cur = &(pmlmeinfo->network); + u8 *pframe = precv_frame->rx_data; + uint len = precv_frame->len; + u8 is_valid_p2p_probereq = false; - if (power_mode) - SetPwrMgt(fctrl); + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) + return _SUCCESS; - memcpy(pwlanhdr->addr1, da, ETH_ALEN); - memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); - memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN); + if (!check_fwstate(pmlmepriv, _FW_LINKED) && + !check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE)) + return _SUCCESS; - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_DATA_NULL); + p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ielen, + len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); - pframe += sizeof(struct rtw_ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + /* check (wildcard) SSID */ + if (p != NULL) { + if (is_valid_p2p_probereq) + goto _issue_probersp; - pattrib->last_txcmdsz = pattrib->pktlen; + if ((ielen != 0 && memcmp((void *)(p+2), (void *)cur->Ssid.Ssid, cur->Ssid.SsidLength)) || + (ielen == 0 && pmlmeinfo->hidden_ssid_mode)) + return _SUCCESS; - if (wait_ack) { - ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); - } else { - dump_mgntframe(padapter, pmgntframe); - ret = _SUCCESS; - } +_issue_probersp: -exit: - return ret; + if (check_fwstate(pmlmepriv, _FW_LINKED) && + pmlmepriv->cur_network.join_res) + issue_probersp(padapter, get_sa(pframe), is_valid_p2p_probereq); + } + return _SUCCESS; } - -/* when wait_ms > 0 , this function should be called at process context */ -/* da == NULL for station mode */ -int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms) +unsigned int OnProbeRsp(struct adapter *padapter, struct recv_frame *precv_frame) { - int ret; - int i = 0; - u32 start = jiffies; - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); - - /* da == NULL, assume it's null data for sta to ap*/ - if (da == NULL) - da = pnetwork->MacAddress; - - do { - ret = _issue_nulldata(padapter, da, power_mode, wait_ms > 0 ? true : false); - - i++; - - if (padapter->bDriverStopped || padapter->bSurpriseRemoved) - break; - - if (i < try_cnt && wait_ms > 0 && ret == _FAIL) - msleep(wait_ms); - } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - if (ret != _FAIL) { - ret = _SUCCESS; - goto exit; + if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { + report_survey_event(padapter, precv_frame); + return _SUCCESS; } - if (try_cnt && wait_ms) { - if (da) - DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter), - ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); - else - DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), - ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); - } -exit: - return ret; + return _SUCCESS; } -/* when wait_ack is true, this function should be called at process context */ -static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int wait_ack) +unsigned int OnBeacon(struct adapter *padapter, struct recv_frame *precv_frame) { - int ret = _FAIL; - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct rtw_ieee80211_hdr *pwlanhdr; - __le16 *fctrl; - unsigned short *qc; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + int cam_idx; + struct sta_info *psta; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); - - DBG_88E("%s\n", __func__); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *pframe = precv_frame->rx_data; + uint len = precv_frame->len; + struct wlan_bssid_ex *pbss; + int ret = _SUCCESS; + struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); - pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) - goto exit; + if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { + report_survey_event(padapter, precv_frame); + return _SUCCESS; + } - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib(padapter, pattrib); + if (!memcmp(GetAddr3Ptr(pframe), pnetwork->MacAddress, ETH_ALEN)) { + if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) { + /* we should update current network before auth, or some IE is wrong */ + pbss = (struct wlan_bssid_ex *)rtw_malloc(sizeof(struct wlan_bssid_ex)); + if (pbss) { + if (collect_bss_info(padapter, precv_frame, pbss) == _SUCCESS) { + update_network(&(pmlmepriv->cur_network.network), pbss, padapter, true); + rtw_get_bcn_info(&(pmlmepriv->cur_network)); + } + kfree(pbss); + } - pattrib->hdrlen += 2; - pattrib->qos_en = true; - pattrib->eosp = 1; - pattrib->ack_policy = 0; - pattrib->mdata = 0; + /* check the vendor of the assoc AP */ + pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pframe+sizeof(struct rtw_ieee80211_hdr_3addr), len-sizeof(struct rtw_ieee80211_hdr_3addr)); - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + /* update TSF Value */ + update_TSF(pmlmeext, pframe, len); - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + /* start auth */ + start_clnt_auth(padapter); - fctrl = &(pwlanhdr->frame_ctl); - *(fctrl) = 0; + return _SUCCESS; + } - if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) - SetFrDs(fctrl); - else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) - SetToDs(fctrl); + if (((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) && (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) { + psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); + if (psta != NULL) { + ret = rtw_check_bcn_info(padapter, pframe, len); + if (!ret) { + DBG_88E_LEVEL(_drv_info_, "ap has changed, disconnect now\n "); + receive_disconnect(padapter, pmlmeinfo->network.MacAddress , 65535); + return _SUCCESS; + } + /* update WMM, ERP in the beacon */ + /* todo: the timer is used instead of the number of the beacon received */ + if ((sta_rx_pkts(psta) & 0xf) == 0) + update_beacon_info(padapter, pframe, len, psta); + } + } else if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { + psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); + if (psta != NULL) { + /* update WMM, ERP in the beacon */ + /* todo: the timer is used instead of the number of the beacon received */ + if ((sta_rx_pkts(psta) & 0xf) == 0) + update_beacon_info(padapter, pframe, len, psta); + } else { + /* allocate a new CAM entry for IBSS station */ + cam_idx = allocate_fw_sta_entry(padapter); + if (cam_idx == NUM_STA) + goto _END_ONBEACON_; + + /* get supported rate */ + if (update_sta_support_rate(padapter, (pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_), (len - WLAN_HDR_A3_LEN - _BEACON_IE_OFFSET_), cam_idx) == _FAIL) { + pmlmeinfo->FW_sta_info[cam_idx].status = 0; + goto _END_ONBEACON_; + } + + /* update TSF Value */ + update_TSF(pmlmeext, pframe, len); + + /* report sta add event */ + report_add_sta_event(padapter, GetAddr2Ptr(pframe), cam_idx); + } + } + } + +_END_ONBEACON_: + + return _SUCCESS; +} + +unsigned int OnAuth(struct adapter *padapter, struct recv_frame *precv_frame) +{ +#ifdef CONFIG_88EU_AP_MODE + unsigned int auth_mode, ie_len; + u16 seq; + unsigned char *sa, *p; + u16 algorithm; + int status; + static struct sta_info stat; + struct sta_info *pstat = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 *pframe = precv_frame->rx_data; + uint len = precv_frame->len; + + if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) + return _FAIL; + + DBG_88E("+OnAuth\n"); + + sa = GetAddr2Ptr(pframe); + + auth_mode = psecuritypriv->dot11AuthAlgrthm; + seq = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + 2)); + algorithm = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN)); + + DBG_88E("auth alg=%x, seq=%X\n", algorithm, seq); + + if (auth_mode == 2 && psecuritypriv->dot11PrivacyAlgrthm != _WEP40_ && + psecuritypriv->dot11PrivacyAlgrthm != _WEP104_) + auth_mode = 0; + + if ((algorithm > 0 && auth_mode == 0) || /* rx a shared-key auth but shared not enabled */ + (algorithm == 0 && auth_mode == 1)) { /* rx a open-system auth but shared-key is enabled */ + DBG_88E("auth rejected due to bad alg [alg=%d, auth_mib=%d] %02X%02X%02X%02X%02X%02X\n", + algorithm, auth_mode, sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]); + + status = _STATS_NO_SUPP_ALG_; + + goto auth_fail; + } + + if (!rtw_access_ctrl(padapter, sa)) { + status = _STATS_UNABLE_HANDLE_STA_; + goto auth_fail; + } + + pstat = rtw_get_stainfo(pstapriv, sa); + if (pstat == NULL) { + /* allocate a new one */ + DBG_88E("going to alloc stainfo for sa=%pM\n", sa); + pstat = rtw_alloc_stainfo(pstapriv, sa); + if (pstat == NULL) { + DBG_88E(" Exceed the upper limit of supported clients...\n"); + status = _STATS_UNABLE_HANDLE_STA_; + goto auth_fail; + } + + pstat->state = WIFI_FW_AUTH_NULL; + pstat->auth_seq = 0; + } else { + spin_lock_bh(&pstapriv->asoc_list_lock); + if (!list_empty(&pstat->asoc_list)) { + list_del_init(&pstat->asoc_list); + pstapriv->asoc_list_cnt--; + } + spin_unlock_bh(&pstapriv->asoc_list_lock); + + if (seq == 1) { + /* TODO: STA re_auth and auth timeout */ + } + } + + spin_lock_bh(&pstapriv->auth_list_lock); + if (list_empty(&pstat->auth_list)) { + list_add_tail(&pstat->auth_list, &pstapriv->auth_list); + pstapriv->auth_list_cnt++; + } + spin_unlock_bh(&pstapriv->auth_list_lock); + + if (pstat->auth_seq == 0) + pstat->expire_to = pstapriv->auth_to; + + if ((pstat->auth_seq + 1) != seq) { + DBG_88E("(1)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", + seq, pstat->auth_seq+1); + status = _STATS_OUT_OF_AUTH_SEQ_; + goto auth_fail; + } + + if (algorithm == 0 && (auth_mode == 0 || auth_mode == 2)) { + if (seq == 1) { + pstat->state &= ~WIFI_FW_AUTH_NULL; + pstat->state |= WIFI_FW_AUTH_SUCCESS; + pstat->expire_to = pstapriv->assoc_to; + pstat->authalg = algorithm; + } else { + DBG_88E("(2)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", + seq, pstat->auth_seq+1); + status = _STATS_OUT_OF_AUTH_SEQ_; + goto auth_fail; + } + } else { /* shared system or auto authentication */ + if (seq == 1) { + /* prepare for the challenging txt... */ + + pstat->state &= ~WIFI_FW_AUTH_NULL; + pstat->state |= WIFI_FW_AUTH_STATE; + pstat->authalg = algorithm; + pstat->auth_seq = 2; + } else if (seq == 3) { + /* checking for challenging txt... */ + DBG_88E("checking for challenging txt...\n"); + + p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + 4 + _AUTH_IE_OFFSET_ , _CHLGETXT_IE_, (int *)&ie_len, + len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_ - 4); + + if ((p == NULL) || (ie_len <= 0)) { + DBG_88E("auth rejected because challenge failure!(1)\n"); + status = _STATS_CHALLENGE_FAIL_; + goto auth_fail; + } + + if (!memcmp((void *)(p + 2), pstat->chg_txt, 128)) { + pstat->state &= (~WIFI_FW_AUTH_STATE); + pstat->state |= WIFI_FW_AUTH_SUCCESS; + /* challenging txt is correct... */ + pstat->expire_to = pstapriv->assoc_to; + } else { + DBG_88E("auth rejected because challenge failure!\n"); + status = _STATS_CHALLENGE_FAIL_; + goto auth_fail; + } + } else { + DBG_88E("(3)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", + seq, pstat->auth_seq+1); + status = _STATS_OUT_OF_AUTH_SEQ_; + goto auth_fail; + } + } + + /* Now, we are going to issue_auth... */ + pstat->auth_seq = seq + 1; + + issue_auth(padapter, pstat, (unsigned short)(_STATS_SUCCESSFUL_)); + + if (pstat->state & WIFI_FW_AUTH_SUCCESS) + pstat->auth_seq = 0; + + return _SUCCESS; + +auth_fail: + + if (pstat) + rtw_free_stainfo(padapter, pstat); + + pstat = &stat; + memset((char *)pstat, '\0', sizeof(stat)); + pstat->auth_seq = 2; + memcpy(pstat->hwaddr, sa, 6); + + issue_auth(padapter, pstat, (unsigned short)status); + +#endif /* CONFIG_88EU_AP_MODE */ + return _FAIL; +} + +unsigned int OnAuthClient(struct adapter *padapter, struct recv_frame *precv_frame) +{ + unsigned int seq, len, status, offset; + unsigned char *p; + unsigned int go2asoc = 0; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 *pframe = precv_frame->rx_data; + uint pkt_len = precv_frame->len; + + DBG_88E("%s\n", __func__); + + /* check A1 matches or not */ + if (memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN)) + return _SUCCESS; + + if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE)) + return _SUCCESS; + + offset = (GetPrivacy(pframe)) ? 4 : 0; + + seq = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + offset + 2)); + status = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + offset + 4)); + + if (status != 0) { + DBG_88E("clnt auth fail, status: %d\n", status); + if (status == 13) { /* pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) */ + if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) + pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; + else + pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; + } + + set_link_timer(pmlmeext, 1); + goto authclnt_fail; + } + + if (seq == 2) { + if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) { + /* legendary shared system */ + p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _AUTH_IE_OFFSET_, _CHLGETXT_IE_, (int *)&len, + pkt_len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_); + + if (p == NULL) + goto authclnt_fail; + + memcpy((void *)(pmlmeinfo->chg_txt), (void *)(p + 2), len); + pmlmeinfo->auth_seq = 3; + issue_auth(padapter, NULL, 0); + set_link_timer(pmlmeext, REAUTH_TO); + + return _SUCCESS; + } else { + /* open system */ + go2asoc = 1; + } + } else if (seq == 4) { + if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) + go2asoc = 1; + else + goto authclnt_fail; + } else { + /* this is also illegal */ + goto authclnt_fail; + } + + if (go2asoc) { + DBG_88E_LEVEL(_drv_info_, "auth success, start assoc\n"); + start_clnt_assoc(padapter); + return _SUCCESS; + } +authclnt_fail: + return _FAIL; +} + +unsigned int OnAssocReq(struct adapter *padapter, struct recv_frame *precv_frame) +{ +#ifdef CONFIG_88EU_AP_MODE + u16 capab_info; + struct rtw_ieee802_11_elems elems; + struct sta_info *pstat; + unsigned char reassoc, *p, *pos, *wpa_ie; + unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; + int i, ie_len, wpa_ie_len, left; + unsigned char supportRate[16]; + int supportRateNum; + unsigned short status = _STATS_SUCCESSFUL_; + unsigned short frame_type, ie_offset = 0; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wlan_bssid_ex *cur = &(pmlmeinfo->network); + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *pframe = precv_frame->rx_data; + uint pkt_len = precv_frame->len; + + if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) + return _FAIL; + + frame_type = GetFrameSubType(pframe); + if (frame_type == WIFI_ASSOCREQ) { + reassoc = 0; + ie_offset = _ASOCREQ_IE_OFFSET_; + } else { /* WIFI_REASSOCREQ */ + reassoc = 1; + ie_offset = _REASOCREQ_IE_OFFSET_; + } + + + if (pkt_len < IEEE80211_3ADDR_LEN + ie_offset) { + DBG_88E("handle_assoc(reassoc=%d) - too short payload (len=%lu)" + "\n", reassoc, (unsigned long)pkt_len); + return _FAIL; + } + + pstat = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); + if (pstat == NULL) { + status = _RSON_CLS2_; + goto asoc_class2_error; + } + + capab_info = get_unaligned_le16(pframe + WLAN_HDR_A3_LEN); + + left = pkt_len - (IEEE80211_3ADDR_LEN + ie_offset); + pos = pframe + (IEEE80211_3ADDR_LEN + ie_offset); + + + DBG_88E("%s\n", __func__); + + /* check if this stat has been successfully authenticated/assocated */ + if (!((pstat->state) & WIFI_FW_AUTH_SUCCESS)) { + if (!((pstat->state) & WIFI_FW_ASSOC_SUCCESS)) { + status = _RSON_CLS2_; + goto asoc_class2_error; + } else { + pstat->state &= (~WIFI_FW_ASSOC_SUCCESS); + pstat->state |= WIFI_FW_ASSOC_STATE; + } + } else { + pstat->state &= (~WIFI_FW_AUTH_SUCCESS); + pstat->state |= WIFI_FW_ASSOC_STATE; + } + pstat->capability = capab_info; + /* now parse all ieee802_11 ie to point to elems */ + if (rtw_ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed || + !elems.ssid) { + DBG_88E("STA %pM sent invalid association request\n", + pstat->hwaddr); + status = _STATS_FAILURE_; + goto OnAssocReqFail; + } + + + /* now we should check all the fields... */ + /* checking SSID */ + p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SSID_IE_, &ie_len, + pkt_len - WLAN_HDR_A3_LEN - ie_offset); + if (p == NULL) + status = _STATS_FAILURE_; + + if (ie_len == 0) { /* broadcast ssid, however it is not allowed in assocreq */ + status = _STATS_FAILURE_; + } else { + /* check if ssid match */ + if (memcmp((void *)(p+2), cur->Ssid.Ssid, cur->Ssid.SsidLength)) + status = _STATS_FAILURE_; + + if (ie_len != cur->Ssid.SsidLength) + status = _STATS_FAILURE_; + } + + if (_STATS_SUCCESSFUL_ != status) + goto OnAssocReqFail; + + /* check if the supported rate is ok */ + p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SUPPORTEDRATES_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset); + if (p == NULL) { + DBG_88E("Rx a sta assoc-req which supported rate is empty!\n"); + /* use our own rate set as statoin used */ + /* memcpy(supportRate, AP_BSSRATE, AP_BSSRATE_LEN); */ + /* supportRateNum = AP_BSSRATE_LEN; */ + + status = _STATS_FAILURE_; + goto OnAssocReqFail; + } else { + memcpy(supportRate, p+2, ie_len); + supportRateNum = ie_len; + + p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _EXT_SUPPORTEDRATES_IE_ , &ie_len, + pkt_len - WLAN_HDR_A3_LEN - ie_offset); + if (p != NULL) { + if (supportRateNum <= sizeof(supportRate)) { + memcpy(supportRate+supportRateNum, p+2, ie_len); + supportRateNum += ie_len; + } + } + } + + /* todo: mask supportRate between AP & STA -> move to update raid */ + /* get_matched_rate(pmlmeext, supportRate, &supportRateNum, 0); */ + + /* update station supportRate */ + pstat->bssratelen = supportRateNum; + memcpy(pstat->bssrateset, supportRate, supportRateNum); + UpdateBrateTblForSoftAP(pstat->bssrateset, pstat->bssratelen); + + /* check RSN/WPA/WPS */ + pstat->dot8021xalg = 0; + pstat->wpa_psk = 0; + pstat->wpa_group_cipher = 0; + pstat->wpa2_group_cipher = 0; + pstat->wpa_pairwise_cipher = 0; + pstat->wpa2_pairwise_cipher = 0; + memset(pstat->wpa_ie, 0, sizeof(pstat->wpa_ie)); + if ((psecuritypriv->wpa_psk & BIT(1)) && elems.rsn_ie) { + int group_cipher = 0, pairwise_cipher = 0; - if (pattrib->mdata) - SetMData(fctrl); + wpa_ie = elems.rsn_ie; + wpa_ie_len = elems.rsn_ie_len; - qc = (unsigned short *)(pframe + pattrib->hdrlen - 2); + if (rtw_parse_wpa2_ie(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { + pstat->dot8021xalg = 1;/* psk, todo:802.1x */ + pstat->wpa_psk |= BIT(1); - SetPriority(qc, tid); + pstat->wpa2_group_cipher = group_cipher&psecuritypriv->wpa2_group_cipher; + pstat->wpa2_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa2_pairwise_cipher; - SetEOSP(qc, pattrib->eosp); + if (!pstat->wpa2_group_cipher) + status = WLAN_STATUS_INVALID_GROUP_CIPHER; - SetAckpolicy(qc, pattrib->ack_policy); + if (!pstat->wpa2_pairwise_cipher) + status = WLAN_STATUS_INVALID_PAIRWISE_CIPHER; + } else { + status = WLAN_STATUS_INVALID_IE; + } + } else if ((psecuritypriv->wpa_psk & BIT(0)) && elems.wpa_ie) { + int group_cipher = 0, pairwise_cipher = 0; - memcpy(pwlanhdr->addr1, da, ETH_ALEN); - memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); - memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN); + wpa_ie = elems.wpa_ie; + wpa_ie_len = elems.wpa_ie_len; - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); + if (rtw_parse_wpa_ie(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { + pstat->dot8021xalg = 1;/* psk, todo:802.1x */ + pstat->wpa_psk |= BIT(0); - pframe += sizeof(struct rtw_ieee80211_hdr_3addr_qos); - pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos); + pstat->wpa_group_cipher = group_cipher&psecuritypriv->wpa_group_cipher; + pstat->wpa_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa_pairwise_cipher; - pattrib->last_txcmdsz = pattrib->pktlen; + if (!pstat->wpa_group_cipher) + status = WLAN_STATUS_INVALID_GROUP_CIPHER; - if (wait_ack) { - ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); + if (!pstat->wpa_pairwise_cipher) + status = WLAN_STATUS_INVALID_PAIRWISE_CIPHER; + } else { + status = WLAN_STATUS_INVALID_IE; + } } else { - dump_mgntframe(padapter, pmgntframe); - ret = _SUCCESS; + wpa_ie = NULL; + wpa_ie_len = 0; } -exit: - return ret; -} - -/* when wait_ms > 0 , this function should be called at process context */ -/* da == NULL for station mode */ -int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int try_cnt, int wait_ms) -{ - int ret; - int i = 0; - u32 start = jiffies; - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); - - /* da == NULL, assume it's null data for sta to ap*/ - if (da == NULL) - da = pnetwork->MacAddress; - - do { - ret = _issue_qos_nulldata(padapter, da, tid, wait_ms > 0 ? true : false); + if (_STATS_SUCCESSFUL_ != status) + goto OnAssocReqFail; - i++; + pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); + if (wpa_ie == NULL) { + if (elems.wps_ie) { + DBG_88E("STA included WPS IE in " + "(Re)Association Request - assume WPS is " + "used\n"); + pstat->flags |= WLAN_STA_WPS; + /* wpabuf_free(sta->wps_ie); */ + /* sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4, */ + /* elems.wps_ie_len - 4); */ + } else { + DBG_88E("STA did not include WPA/RSN IE " + "in (Re)Association Request - possible WPS " + "use\n"); + pstat->flags |= WLAN_STA_MAYBE_WPS; + } - if (padapter->bDriverStopped || padapter->bSurpriseRemoved) - break; - if (i < try_cnt && wait_ms > 0 && ret == _FAIL) - msleep(wait_ms); - } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); + /* AP support WPA/RSN, and sta is going to do WPS, but AP is not ready */ + /* that the selected registrar of AP is _FLASE */ + if ((psecuritypriv->wpa_psk > 0) && (pstat->flags & (WLAN_STA_WPS|WLAN_STA_MAYBE_WPS))) { + if (pmlmepriv->wps_beacon_ie) { + u8 selected_registrar = 0; - if (ret != _FAIL) { - ret = _SUCCESS; - goto exit; - } + rtw_get_wps_attr_content(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len, WPS_ATTR_SELECTED_REGISTRAR , &selected_registrar, NULL); - if (try_cnt && wait_ms) { - if (da) - DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter), - ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); - else - DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), - ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); - } -exit: - return ret; -} + if (!selected_registrar) { + DBG_88E("selected_registrar is false , or AP is not ready to do WPS\n"); -static int _issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason, u8 wait_ack) -{ - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct rtw_ieee80211_hdr *pwlanhdr; - __le16 *fctrl; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); - int ret = _FAIL; - __le16 le_tmp; + status = _STATS_UNABLE_HANDLE_STA_; - pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) - goto exit; + goto OnAssocReqFail; + } + } + } + } else { + int copy_len; - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib(padapter, pattrib); - pattrib->retry_ctrl = false; + if (psecuritypriv->wpa_psk == 0) { + DBG_88E("STA %pM: WPA/RSN IE in association " + "request, but AP don't support WPA/RSN\n", pstat->hwaddr); - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + status = WLAN_STATUS_INVALID_IE; - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + goto OnAssocReqFail; + } - fctrl = &(pwlanhdr->frame_ctl); - *(fctrl) = 0; + if (elems.wps_ie) { + DBG_88E("STA included WPS IE in " + "(Re)Association Request - WPS is " + "used\n"); + pstat->flags |= WLAN_STA_WPS; + copy_len = 0; + } else { + copy_len = ((wpa_ie_len+2) > sizeof(pstat->wpa_ie)) ? (sizeof(pstat->wpa_ie)) : (wpa_ie_len+2); + } + if (copy_len > 0) + memcpy(pstat->wpa_ie, wpa_ie-2, copy_len); + } + /* check if there is WMM IE & support WWM-PS */ + pstat->flags &= ~WLAN_STA_WME; + pstat->qos_option = 0; + pstat->qos_info = 0; + pstat->has_legacy_ac = true; + pstat->uapsd_vo = 0; + pstat->uapsd_vi = 0; + pstat->uapsd_be = 0; + pstat->uapsd_bk = 0; + if (pmlmepriv->qospriv.qos_option) { + p = pframe + WLAN_HDR_A3_LEN + ie_offset; ie_len = 0; + for (;;) { + p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset); + if (p != NULL) { + if (!memcmp(p+2, WMM_IE, 6)) { + pstat->flags |= WLAN_STA_WME; - memcpy(pwlanhdr->addr1, da, ETH_ALEN); - memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); - memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN); + pstat->qos_option = 1; + pstat->qos_info = *(p+8); - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_DEAUTH); + pstat->max_sp_len = (pstat->qos_info>>5)&0x3; - pframe += sizeof(struct rtw_ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + if ((pstat->qos_info&0xf) != 0xf) + pstat->has_legacy_ac = true; + else + pstat->has_legacy_ac = false; - le_tmp = cpu_to_le16(reason); - pframe = rtw_set_fixed_ie(pframe, _RSON_CODE_ , (unsigned char *)&le_tmp, &(pattrib->pktlen)); + if (pstat->qos_info&0xf) { + if (pstat->qos_info&BIT(0)) + pstat->uapsd_vo = BIT(0)|BIT(1); + else + pstat->uapsd_vo = 0; - pattrib->last_txcmdsz = pattrib->pktlen; + if (pstat->qos_info&BIT(1)) + pstat->uapsd_vi = BIT(0)|BIT(1); + else + pstat->uapsd_vi = 0; + if (pstat->qos_info&BIT(2)) + pstat->uapsd_bk = BIT(0)|BIT(1); + else + pstat->uapsd_bk = 0; - if (wait_ack) { - ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); - } else { - dump_mgntframe(padapter, pmgntframe); - ret = _SUCCESS; + if (pstat->qos_info&BIT(3)) + pstat->uapsd_be = BIT(0)|BIT(1); + else + pstat->uapsd_be = 0; + } + break; + } + } else { + break; + } + p = p + ie_len + 2; + } } -exit: - return ret; -} - -int issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason) -{ - DBG_88E("%s to %pM\n", __func__, da); - return _issue_deauth(padapter, da, reason, false); -} - -int issue_deauth_ex(struct adapter *padapter, u8 *da, unsigned short reason, int try_cnt, - int wait_ms) -{ - int ret; - int i = 0; - u32 start = jiffies; - - do { - ret = _issue_deauth(padapter, da, reason, wait_ms > 0 ? true : false); + /* save HT capabilities in the sta object */ + memset(&pstat->htpriv.ht_cap, 0, sizeof(struct rtw_ieee80211_ht_cap)); + if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct rtw_ieee80211_ht_cap)) { + pstat->flags |= WLAN_STA_HT; - i++; + pstat->flags |= WLAN_STA_WME; - if (padapter->bDriverStopped || padapter->bSurpriseRemoved) - break; + memcpy(&pstat->htpriv.ht_cap, elems.ht_capabilities, sizeof(struct rtw_ieee80211_ht_cap)); + } else { + pstat->flags &= ~WLAN_STA_HT; + } + if ((!pmlmepriv->htpriv.ht_option) && (pstat->flags&WLAN_STA_HT)) { + status = _STATS_FAILURE_; + goto OnAssocReqFail; + } - if (i < try_cnt && wait_ms > 0 && ret == _FAIL) - msleep(wait_ms); - } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); + if ((pstat->flags & WLAN_STA_HT) && + ((pstat->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) || + (pstat->wpa_pairwise_cipher&WPA_CIPHER_TKIP))) { + DBG_88E("HT: %pM tried to " + "use TKIP with HT association\n", pstat->hwaddr); - if (ret != _FAIL) { - ret = _SUCCESS; - goto exit; + /* status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; */ + /* goto OnAssocReqFail; */ } - if (try_cnt && wait_ms) { - if (da) - DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter), - ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); - else - DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", - FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), - ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + pstat->flags |= WLAN_STA_NONERP; + for (i = 0; i < pstat->bssratelen; i++) { + if ((pstat->bssrateset[i] & 0x7f) > 22) { + pstat->flags &= ~WLAN_STA_NONERP; + break; + } } -exit: - return ret; -} -void issue_action_spct_ch_switch(struct adapter *padapter, u8 *ra, u8 new_ch, u8 ch_offset) -{ - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct rtw_ieee80211_hdr *pwlanhdr; - __le16 *fctrl; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + if (pstat->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + pstat->flags |= WLAN_STA_SHORT_PREAMBLE; + else + pstat->flags &= ~WLAN_STA_SHORT_PREAMBLE; - DBG_88E(FUNC_NDEV_FMT" ra =%pM, ch:%u, offset:%u\n", - FUNC_NDEV_ARG(padapter->pnetdev), ra, new_ch, ch_offset); - pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) - return; + if (status != _STATS_SUCCESSFUL_) + goto OnAssocReqFail; - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib(padapter, pattrib); + /* TODO: identify_proprietary_vendor_ie(); */ + /* Realtek proprietary IE */ + /* identify if this is Broadcom sta */ + /* identify if this is ralink sta */ + /* Customer proprietary IE */ - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + /* get a unique AID */ + if (pstat->aid > 0) { + DBG_88E(" old AID %d\n", pstat->aid); + } else { + for (pstat->aid = 1; pstat->aid <= NUM_STA; pstat->aid++) + if (pstapriv->sta_aid[pstat->aid - 1] == NULL) + break; - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + /* if (pstat->aid > NUM_STA) { */ + if (pstat->aid > pstapriv->max_num_sta) { + pstat->aid = 0; - fctrl = &(pwlanhdr->frame_ctl); - *(fctrl) = 0; + DBG_88E(" no room for more AIDs\n"); - memcpy(pwlanhdr->addr1, ra, ETH_ALEN); /* RA */ - memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); /* TA */ - memcpy(pwlanhdr->addr3, ra, ETH_ALEN); /* DA = RA */ + status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_ACTION); + goto OnAssocReqFail; + } else { + pstapriv->sta_aid[pstat->aid - 1] = pstat; + DBG_88E("allocate new AID=(%d)\n", pstat->aid); + } + } - pframe += sizeof(struct rtw_ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + pstat->state &= (~WIFI_FW_ASSOC_STATE); + pstat->state |= WIFI_FW_ASSOC_SUCCESS; - /* category, action */ - { - u8 category, action; - category = RTW_WLAN_CATEGORY_SPECTRUM_MGMT; - action = RTW_WLAN_ACTION_SPCT_CHL_SWITCH; + spin_lock_bh(&pstapriv->auth_list_lock); + if (!list_empty(&pstat->auth_list)) { + list_del_init(&pstat->auth_list); + pstapriv->auth_list_cnt--; + } + spin_unlock_bh(&pstapriv->auth_list_lock); - pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); - pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); + spin_lock_bh(&pstapriv->asoc_list_lock); + if (list_empty(&pstat->asoc_list)) { + pstat->expire_to = pstapriv->expire_to; + list_add_tail(&pstat->asoc_list, &pstapriv->asoc_list); + pstapriv->asoc_list_cnt++; } + spin_unlock_bh(&pstapriv->asoc_list_lock); - pframe = rtw_set_ie_ch_switch(pframe, &(pattrib->pktlen), 0, new_ch, 0); - pframe = rtw_set_ie_secondary_ch_offset(pframe, &(pattrib->pktlen), - hal_ch_offset_to_secondary_ch_offset(ch_offset)); + /* now the station is qualified to join our BSS... */ + if (pstat && (pstat->state & WIFI_FW_ASSOC_SUCCESS) && (_STATS_SUCCESSFUL_ == status)) { + /* 1 bss_cap_update & sta_info_update */ + bss_cap_update_on_sta_join(padapter, pstat); + sta_info_update(padapter, pstat); - pattrib->last_txcmdsz = pattrib->pktlen; + /* issue assoc rsp before notify station join event. */ + if (frame_type == WIFI_ASSOCREQ) + issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP); + else + issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP); - dump_mgntframe(padapter, pmgntframe); -} + /* 2 - report to upper layer */ + DBG_88E("indicate_sta_join_event to upper layer - hostapd\n"); + rtw_indicate_sta_assoc_event(padapter, pstat); -void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short status) -{ - u8 category = RTW_WLAN_CATEGORY_BACK; - u16 start_seq; - u16 BA_para_set; - u16 reason_code; - u16 BA_timeout_value; - __le16 le_tmp; - u16 BA_starting_seqctrl = 0; - enum ht_cap_ampdu_factor max_rx_ampdu_factor; - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - u8 *pframe; - struct rtw_ieee80211_hdr *pwlanhdr; - __le16 *fctrl; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct sta_info *psta; - struct sta_priv *pstapriv = &padapter->stapriv; - struct registry_priv *pregpriv = &padapter->registrypriv; - struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); + /* 3-(1) report sta add event */ + report_add_sta_event(padapter, pstat->hwaddr, pstat->aid); + } - DBG_88E("%s, category=%d, action=%d, status=%d\n", __func__, category, action, status); + return _SUCCESS; - pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) - return; +asoc_class2_error: - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib(padapter, pattrib); + issue_deauth(padapter, (void *)GetAddr2Ptr(pframe), status); - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + return _FAIL; - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; +OnAssocReqFail: - fctrl = &(pwlanhdr->frame_ctl); - *(fctrl) = 0; + pstat->aid = 0; + if (frame_type == WIFI_ASSOCREQ) + issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP); + else + issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP); - /* memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); */ - memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); - memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); - memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN); +#endif /* CONFIG_88EU_AP_MODE */ - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_ACTION); + return _FAIL; +} - pframe += sizeof(struct rtw_ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); +unsigned int OnAssocRsp(struct adapter *padapter, struct recv_frame *precv_frame) +{ + uint i; + int res; + unsigned short status; + struct ndis_802_11_var_ie *pIE; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + /* struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); */ + u8 *pframe = precv_frame->rx_data; + uint pkt_len = precv_frame->len; - pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); - pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); + DBG_88E("%s\n", __func__); - if (category == 3) { - switch (action) { - case 0: /* ADDBA req */ - do { - pmlmeinfo->dialogToken++; - } while (pmlmeinfo->dialogToken == 0); - pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->dialogToken), &(pattrib->pktlen)); + /* check A1 matches or not */ + if (memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN)) + return _SUCCESS; - BA_para_set = 0x1002 | ((status & 0xf) << 2); /* immediate ack & 64 buffer size */ - le_tmp = cpu_to_le16(BA_para_set); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); + if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE))) + return _SUCCESS; - BA_timeout_value = 5000;/* 5ms */ - le_tmp = cpu_to_le16(BA_timeout_value); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); + if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) + return _SUCCESS; - psta = rtw_get_stainfo(pstapriv, raddr); - if (psta != NULL) { - start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07]&0xfff) + 1; + del_timer_sync(&pmlmeext->link_timer); - DBG_88E("BA_starting_seqctrl=%d for TID=%d\n", start_seq, status & 0x07); + /* status */ + status = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 2)); + if (status > 0) { + DBG_88E("assoc reject, status code: %d\n", status); + pmlmeinfo->state = WIFI_FW_NULL_STATE; + res = -4; + goto report_assoc_result; + } - psta->BA_starting_seqctrl[status & 0x07] = start_seq; + /* get capabilities */ + pmlmeinfo->capability = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); - BA_starting_seqctrl = start_seq << 4; - } - le_tmp = cpu_to_le16(BA_starting_seqctrl); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); - break; - case 1: /* ADDBA rsp */ - pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->ADDBA_req.dialog_token), &(pattrib->pktlen)); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&status), &(pattrib->pktlen)); + /* set slot time */ + pmlmeinfo->slotTime = (pmlmeinfo->capability & BIT(10)) ? 9 : 20; - BA_para_set = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f; - rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); - switch (max_rx_ampdu_factor) { - case MAX_AMPDU_FACTOR_64K: - BA_para_set |= 0x1000; /* 64 buffer size */ - break; - case MAX_AMPDU_FACTOR_32K: - BA_para_set |= 0x0800; /* 32 buffer size */ - break; - case MAX_AMPDU_FACTOR_16K: - BA_para_set |= 0x0400; /* 16 buffer size */ - break; - case MAX_AMPDU_FACTOR_8K: - BA_para_set |= 0x0200; /* 8 buffer size */ - break; - default: - BA_para_set |= 0x1000; /* 64 buffer size */ - break; - } + /* AID */ + pmlmeinfo->aid = (int)(le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 4))&0x3fff); + res = pmlmeinfo->aid; - if (pregpriv->ampdu_amsdu == 0)/* disabled */ - BA_para_set = BA_para_set & ~BIT(0); - else if (pregpriv->ampdu_amsdu == 1)/* enabled */ - BA_para_set = BA_para_set | BIT(0); - le_tmp = cpu_to_le16(BA_para_set); + /* following are moved to join event callback function */ + /* to handle HT, WMM, rate adaptive, update MAC reg */ + /* for not to handle the synchronous IO in the tasklet */ + for (i = (6 + WLAN_HDR_A3_LEN); i < pkt_len;) { + pIE = (struct ndis_802_11_var_ie *)(pframe + i); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(pmlmeinfo->ADDBA_req.BA_timeout_value)), &(pattrib->pktlen)); + switch (pIE->ElementID) { + case _VENDOR_SPECIFIC_IE_: + if (!memcmp(pIE->data, WMM_PARA_OUI, 6)) /* WMM */ + WMM_param_handler(padapter, pIE); break; - case 2:/* DELBA */ - BA_para_set = (status & 0x1F) << 3; - le_tmp = cpu_to_le16(BA_para_set); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); - - reason_code = 37;/* Requested from peer STA as it does not want to use the mechanism */ - le_tmp = cpu_to_le16(reason_code); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); + case _HT_CAPABILITY_IE_: /* HT caps */ + HT_caps_handler(padapter, pIE); break; + case _HT_EXTRA_INFO_IE_: /* HT info */ + HT_info_handler(padapter, pIE); + break; + case _ERPINFO_IE_: + ERP_IE_handler(padapter, pIE); default: break; } + + i += (pIE->Length + 2); } - pattrib->last_txcmdsz = pattrib->pktlen; + pmlmeinfo->state &= (~WIFI_FW_ASSOC_STATE); + pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; - dump_mgntframe(padapter, pmgntframe); + /* Update Basic Rate Table for spec, 2010-12-28 , by thomas */ + UpdateBrateTbl(padapter, pmlmeinfo->network.SupportedRates); + +report_assoc_result: + if (res > 0) { + rtw_buf_update(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len, pframe, pkt_len); + } else { + rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len); + } + + report_join_res(padapter, res); + + return _SUCCESS; } -static void issue_action_BSSCoexistPacket(struct adapter *padapter) +unsigned int OnDeAuth(struct adapter *padapter, struct recv_frame *precv_frame) { - struct list_head *plist, *phead; - unsigned char category, action; - struct xmit_frame *pmgntframe; - struct pkt_attrib *pattrib; - unsigned char *pframe; - struct rtw_ieee80211_hdr *pwlanhdr; - __le16 *fctrl; - struct wlan_network *pnetwork = NULL; - struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + unsigned short reason; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct __queue *queue = &(pmlmepriv->scanned_queue); - u8 InfoContent[16] = {0}; - u8 ICS[8][15]; - struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); - - if ((pmlmepriv->num_FortyMHzIntolerant == 0) || (pmlmepriv->num_sta_no_ht == 0)) - return; - - if (pmlmeinfo->bwmode_updated) - return; - - - DBG_88E("%s\n", __func__); - - - category = RTW_WLAN_CATEGORY_PUBLIC; - action = ACT_PUBLIC_BSSCOEXIST; + u8 *pframe = precv_frame->rx_data; + struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); - pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) - return; + /* check A3 */ + if (memcmp(GetAddr3Ptr(pframe), pnetwork->MacAddress, ETH_ALEN)) + return _SUCCESS; - /* update attribute */ - pattrib = &pmgntframe->attrib; - update_mgntframe_attrib(padapter, pattrib); + reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); - memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + DBG_88E("%s Reason code(%d)\n", __func__, reason); - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; +#ifdef CONFIG_88EU_AP_MODE + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; - fctrl = &(pwlanhdr->frame_ctl); - *(fctrl) = 0; + DBG_88E_LEVEL(_drv_always_, "ap recv deauth reason code(%d) sta:%pM\n", + reason, GetAddr2Ptr(pframe)); - memcpy(pwlanhdr->addr1, cur_network->MacAddress, ETH_ALEN); - memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); - memcpy(pwlanhdr->addr3, cur_network->MacAddress, ETH_ALEN); + psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); + if (psta) { + u8 updated = 0; - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); - pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_ACTION); + spin_lock_bh(&pstapriv->asoc_list_lock); + if (!list_empty(&psta->asoc_list)) { + list_del_init(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + updated = ap_free_sta(padapter, psta, false, reason); + } + spin_unlock_bh(&pstapriv->asoc_list_lock); - pframe += sizeof(struct rtw_ieee80211_hdr_3addr); - pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + associated_clients_update(padapter, updated); + } - pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); - pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); + return _SUCCESS; + } else +#endif + { + DBG_88E_LEVEL(_drv_always_, "sta recv deauth reason code(%d) sta:%pM\n", + reason, GetAddr3Ptr(pframe)); - /* */ - if (pmlmepriv->num_FortyMHzIntolerant > 0) { - u8 iedata = 0; + receive_disconnect(padapter, GetAddr3Ptr(pframe) , reason); + } + pmlmepriv->LinkDetectInfo.bBusyTraffic = false; + return _SUCCESS; +} - iedata |= BIT(2);/* 20 MHz BSS Width Request */ +unsigned int OnDisassoc(struct adapter *padapter, struct recv_frame *precv_frame) +{ + u16 reason; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 *pframe = precv_frame->rx_data; + struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); - pframe = rtw_set_ie(pframe, EID_BSSCoexistence, 1, &iedata, &(pattrib->pktlen)); - } + /* check A3 */ + if (memcmp(GetAddr3Ptr(pframe), pnetwork->MacAddress, ETH_ALEN)) + return _SUCCESS; + reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); - /* */ - memset(ICS, 0, sizeof(ICS)); - if (pmlmepriv->num_sta_no_ht > 0) { - int i; + DBG_88E("%s Reason code(%d)\n", __func__, reason); - spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); +#ifdef CONFIG_88EU_AP_MODE + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; - phead = get_list_head(queue); - plist = phead->next; + DBG_88E_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n", + reason, GetAddr2Ptr(pframe)); - while (phead != plist) { - int len; - u8 *p; - struct wlan_bssid_ex *pbss_network; + psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); + if (psta) { + u8 updated = 0; - pnetwork = container_of(plist, struct wlan_network, list); + spin_lock_bh(&pstapriv->asoc_list_lock); + if (!list_empty(&psta->asoc_list)) { + list_del_init(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + updated = ap_free_sta(padapter, psta, false, reason); + } + spin_unlock_bh(&pstapriv->asoc_list_lock); - plist = plist->next; + associated_clients_update(padapter, updated); + } - pbss_network = (struct wlan_bssid_ex *)&pnetwork->network; + return _SUCCESS; + } else +#endif + { + DBG_88E_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n", + reason, GetAddr3Ptr(pframe)); - p = rtw_get_ie(pbss_network->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pbss_network->IELength - _FIXED_IE_LENGTH_); - if ((p == NULL) || (len == 0)) { /* non-HT */ - if ((pbss_network->Configuration.DSConfig <= 0) || (pbss_network->Configuration.DSConfig > 14)) - continue; + receive_disconnect(padapter, GetAddr3Ptr(pframe), reason); + } + pmlmepriv->LinkDetectInfo.bBusyTraffic = false; + return _SUCCESS; +} - ICS[0][pbss_network->Configuration.DSConfig] = 1; +unsigned int OnAtim(struct adapter *padapter, struct recv_frame *precv_frame) +{ + DBG_88E("%s\n", __func__); + return _SUCCESS; +} - if (ICS[0][0] == 0) - ICS[0][0] = 1; - } - } - spin_unlock_bh(&pmlmepriv->scanned_queue.lock); +unsigned int on_action_spct(struct adapter *padapter, struct recv_frame *precv_frame) +{ + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *pframe = precv_frame->rx_data; + u8 *frame_body = (u8 *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); + u8 category; + u8 action; - for (i = 0; i < 8; i++) { - if (ICS[i][0] == 1) { - int j, k = 0; + DBG_88E(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev)); - InfoContent[k] = i; - /* SET_BSS_INTOLERANT_ELE_REG_CLASS(InfoContent, i); */ - k++; + psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); - for (j = 1; j <= 14; j++) { - if (ICS[i][j] == 1) { - if (k < 16) { - InfoContent[k] = j; /* channel number */ - /* SET_BSS_INTOLERANT_ELE_CHANNEL(InfoContent+k, j); */ - k++; - } - } - } + if (!psta) + goto exit; - pframe = rtw_set_ie(pframe, EID_BSSIntolerantChlReport, k, InfoContent, &(pattrib->pktlen)); - } - } + category = frame_body[0]; + if (category != RTW_WLAN_CATEGORY_SPECTRUM_MGMT) + goto exit; + + action = frame_body[1]; + switch (action) { + case RTW_WLAN_ACTION_SPCT_MSR_REQ: + case RTW_WLAN_ACTION_SPCT_MSR_RPRT: + case RTW_WLAN_ACTION_SPCT_TPC_REQ: + case RTW_WLAN_ACTION_SPCT_TPC_RPRT: + break; + case RTW_WLAN_ACTION_SPCT_CHL_SWITCH: + break; + default: + break; } +exit: + return _FAIL; +} - pattrib->last_txcmdsz = pattrib->pktlen; +unsigned int OnAction_qos(struct adapter *padapter, struct recv_frame *precv_frame) +{ + return _SUCCESS; +} - dump_mgntframe(padapter, pmgntframe); +unsigned int OnAction_dls(struct adapter *padapter, struct recv_frame *precv_frame) +{ + return _SUCCESS; } -unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr) +unsigned int OnAction_back(struct adapter *padapter, struct recv_frame *precv_frame) { - struct sta_priv *pstapriv = &padapter->stapriv; + u8 *addr; struct sta_info *psta = NULL; - /* struct recv_reorder_ctrl *preorder_ctrl; */ + struct recv_reorder_ctrl *preorder_ctrl; + unsigned char *frame_body; + unsigned char category, action; + unsigned short tid, status, reason_code = 0; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - u16 tid; + u8 *pframe = precv_frame->rx_data; + struct sta_priv *pstapriv = &padapter->stapriv; + /* check RA matches or not */ + if (memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), + ETH_ALEN))/* for if1, sta/ap mode */ + return _SUCCESS; + + DBG_88E("%s\n", __func__); if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) return _SUCCESS; + addr = GetAddr2Ptr(pframe); psta = rtw_get_stainfo(pstapriv, addr); + if (psta == NULL) return _SUCCESS; - if (initiator == 0) { /* recipient */ - for (tid = 0; tid < MAXTID; tid++) { - if (psta->recvreorder_ctrl[tid].enable) { - DBG_88E("rx agg disable tid(%d)\n", tid); - issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator)&0x1F)); - psta->recvreorder_ctrl[tid].enable = false; - psta->recvreorder_ctrl[tid].indicate_seq = 0xffff; - } - } - } else if (initiator == 1) { /* originator */ - for (tid = 0; tid < MAXTID; tid++) { - if (psta->htpriv.agg_enable_bitmap & BIT(tid)) { - DBG_88E("tx agg disable tid(%d)\n", tid); - issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator)&0x1F)); - psta->htpriv.agg_enable_bitmap &= ~BIT(tid); + frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); + + category = frame_body[0]; + if (category == RTW_WLAN_CATEGORY_BACK) { /* representing Block Ack */ + if (!pmlmeinfo->HT_enable) + return _SUCCESS; + action = frame_body[1]; + DBG_88E("%s, action=%d\n", __func__, action); + switch (action) { + case RTW_WLAN_ACTION_ADDBA_REQ: /* ADDBA request */ + memcpy(&(pmlmeinfo->ADDBA_req), &(frame_body[2]), sizeof(struct ADDBA_request)); + process_addba_req(padapter, (u8 *)&(pmlmeinfo->ADDBA_req), addr); + + if (pmlmeinfo->bAcceptAddbaReq) + issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 0); + else + issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 37);/* reject ADDBA Req */ + break; + case RTW_WLAN_ACTION_ADDBA_RESP: /* ADDBA response */ + status = get_unaligned_le16(&frame_body[3]); + tid = (frame_body[5] >> 2) & 0x7; + if (status == 0) { /* successful */ + DBG_88E("agg_enable for TID=%d\n", tid); + psta->htpriv.agg_enable_bitmap |= 1 << tid; psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); + } else { + psta->htpriv.agg_enable_bitmap &= ~BIT(tid); + } + break; + case RTW_WLAN_ACTION_DELBA: /* DELBA */ + if ((frame_body[3] & BIT(3)) == 0) { + psta->htpriv.agg_enable_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf)); + psta->htpriv.candidate_tid_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf)); + reason_code = get_unaligned_le16(&frame_body[4]); + } else if ((frame_body[3] & BIT(3)) == BIT(3)) { + tid = (frame_body[3] >> 4) & 0x0F; + preorder_ctrl = &psta->recvreorder_ctrl[tid]; + preorder_ctrl->enable = false; + preorder_ctrl->indicate_seq = 0xffff; } + DBG_88E("%s(): DELBA: %x(%x)\n", __func__, pmlmeinfo->agg_enable_bitmap, reason_code); + /* todo: how to notify the host while receiving DELETE BA */ + break; + default: + break; } } - return _SUCCESS; } -unsigned int send_beacon(struct adapter *padapter) -{ - u8 bxmitok = false; - int issue = 0; - int poll = 0; - - u32 start = jiffies; - - rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); - do { - issue_beacon(padapter, 100); - issue++; - do { - yield(); - rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bxmitok)); - poll++; - } while ((poll%10) != 0 && !bxmitok && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); - } while (!bxmitok && issue < 100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); - - if (padapter->bSurpriseRemoved || padapter->bDriverStopped) - return _FAIL; - if (!bxmitok) { - DBG_88E("%s fail! %u ms\n", __func__, rtw_get_passing_time_ms(start)); - return _FAIL; - } else { - u32 passing_time = rtw_get_passing_time_ms(start); - - if (passing_time > 100 || issue > 3) - DBG_88E("%s success, issue:%d, poll:%d, %u ms\n", __func__, issue, poll, rtw_get_passing_time_ms(start)); - return _SUCCESS; - } -} - -/**************************************************************************** - -Following are some utility functions for WiFi MLME - -*****************************************************************************/ - -void site_survey(struct adapter *padapter) +static s32 rtw_action_public_decache(struct recv_frame *recv_frame, s32 token) { - unsigned char survey_channel = 0, val8; - enum rt_scan_type ScanType = SCAN_PASSIVE; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - u32 initialgain = 0; - struct rtw_ieee80211_channel *ch; - - if (pmlmeext->sitesurvey_res.channel_idx < pmlmeext->sitesurvey_res.ch_num) { - ch = &pmlmeext->sitesurvey_res.ch[pmlmeext->sitesurvey_res.channel_idx]; - survey_channel = ch->hw_value; - ScanType = (ch->flags & RTW_IEEE80211_CHAN_PASSIVE_SCAN) ? SCAN_PASSIVE : SCAN_ACTIVE; - } - - - if (survey_channel != 0) { - /* PAUSE 4-AC Queue when site_survey */ - /* rtw_hal_get_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ - /* val8 |= 0x0f; */ - /* rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ - if (pmlmeext->sitesurvey_res.channel_idx == 0) - set_channel_bwmode(padapter, survey_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); - else - SelectChannel(padapter, survey_channel); - - if (ScanType == SCAN_ACTIVE) { /* obey the channel plan setting... */ - int i; - for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) { - if (pmlmeext->sitesurvey_res.ssid[i].SsidLength) { - /* todo: to issue two probe req??? */ - issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL); - /* msleep(SURVEY_TO>>1); */ - issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL); - } - } - - if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) { - /* todo: to issue two probe req??? */ - issue_probereq(padapter, NULL, NULL); - /* msleep(SURVEY_TO>>1); */ - issue_probereq(padapter, NULL, NULL); - } + struct adapter *adapter = recv_frame->adapter; + struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv); + u8 *frame = recv_frame->rx_data; + u16 seq_ctrl = ((recv_frame->attrib.seq_num&0xffff) << 4) | + (recv_frame->attrib.frag_num & 0xf); - if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) { - /* todo: to issue two probe req??? */ - issue_probereq(padapter, NULL, NULL); - /* msleep(SURVEY_TO>>1); */ - issue_probereq(padapter, NULL, NULL); + if (GetRetry(frame)) { + if (token >= 0) { + if ((seq_ctrl == mlmeext->action_public_rxseq) && (token == mlmeext->action_public_dialog_token)) { + DBG_88E(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x, token:%d\n", + FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq, token); + return _FAIL; } - } - - set_survey_timer(pmlmeext, pmlmeext->chan_scan_time); - } else { - - /* 20100721:Interrupt scan operation here. */ - /* For SW antenna diversity before link, it needs to switch to another antenna and scan again. */ - /* It compares the scan result and select better one to do connection. */ - if (rtw_hal_antdiv_before_linked(padapter)) { - pmlmeext->sitesurvey_res.bss_cnt = 0; - pmlmeext->sitesurvey_res.channel_idx = -1; - pmlmeext->chan_scan_time = SURVEY_TO / 2; - set_survey_timer(pmlmeext, pmlmeext->chan_scan_time); - return; - } - - pmlmeext->sitesurvey_res.state = SCAN_COMPLETE; - - /* switch back to the original channel */ - - set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); - - /* flush 4-AC Queue after site_survey */ - /* val8 = 0; */ - /* rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ + } else { + if (seq_ctrl == mlmeext->action_public_rxseq) { + DBG_88E(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x\n", + FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq); + return _FAIL; + } + } + } - /* config MSR */ - Set_MSR(padapter, (pmlmeinfo->state & 0x3)); + mlmeext->action_public_rxseq = seq_ctrl; - initialgain = 0xff; /* restore RX GAIN */ - rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); - /* turn on dynamic functions */ - Restore_DM_Func_Flag(padapter); - /* Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); */ + if (token >= 0) + mlmeext->action_public_dialog_token = token; - if (is_client_associated_to_ap(padapter)) - issue_nulldata(padapter, NULL, 0, 3, 500); + return _SUCCESS; +} - val8 = 0; /* survey done */ - rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); +static unsigned int on_action_public_p2p(struct recv_frame *precv_frame) +{ + u8 *pframe = precv_frame->rx_data; + u8 *frame_body; + u8 dialogToken = 0; + frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); - report_surveydone_event(padapter); + dialogToken = frame_body[7]; - pmlmeext->chan_scan_time = SURVEY_TO; - pmlmeext->sitesurvey_res.state = SCAN_DISABLE; + if (rtw_action_public_decache(precv_frame, dialogToken) == _FAIL) + return _FAIL; - issue_action_BSSCoexistPacket(padapter); - issue_action_BSSCoexistPacket(padapter); - issue_action_BSSCoexistPacket(padapter); - } - return; + return _SUCCESS; } -/* collect bss info from Beacon and Probe request/response frames. */ -u8 collect_bss_info(struct adapter *padapter, struct recv_frame *precv_frame, struct wlan_bssid_ex *bssid) +static unsigned int on_action_public_vendor(struct recv_frame *precv_frame) { - int i; - u32 len; - u8 *p; - u16 val16, subtype; + unsigned int ret = _FAIL; u8 *pframe = precv_frame->rx_data; - u32 packet_len = precv_frame->len; - u8 ie_offset; - struct registry_priv *pregistrypriv = &padapter->registrypriv; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - - len = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr); + u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); - if (len > MAX_IE_SZ) - return _FAIL; + if (!memcmp(frame_body + 2, P2P_OUI, 4)) + ret = on_action_public_p2p(precv_frame); - memset(bssid, 0, sizeof(struct wlan_bssid_ex)); + return ret; +} - subtype = GetFrameSubType(pframe); +static unsigned int on_action_public_default(struct recv_frame *precv_frame, u8 action) +{ + unsigned int ret = _FAIL; + u8 *pframe = precv_frame->rx_data; + u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); + u8 token; - if (subtype == WIFI_BEACON) { - bssid->Reserved[0] = 1; - ie_offset = _BEACON_IE_OFFSET_; - } else { - /* FIXME : more type */ - if (subtype == WIFI_PROBEREQ) { - ie_offset = _PROBEREQ_IE_OFFSET_; - bssid->Reserved[0] = 2; - } else if (subtype == WIFI_PROBERSP) { - ie_offset = _PROBERSP_IE_OFFSET_; - bssid->Reserved[0] = 3; - } else { - bssid->Reserved[0] = 0; - ie_offset = _FIXED_IE_LENGTH_; - } - } + token = frame_body[2]; - bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len; + if (rtw_action_public_decache(precv_frame, token) == _FAIL) + goto exit; - /* below is to copy the information element */ - bssid->IELength = len; - memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength); + ret = _SUCCESS; - /* get the signal strength in dBM.raw data */ - bssid->Rssi = precv_frame->attrib.phy_info.recvpower; - bssid->PhyInfo.SignalQuality = precv_frame->attrib.phy_info.SignalQuality;/* in percentage */ - bssid->PhyInfo.SignalStrength = precv_frame->attrib.phy_info.SignalStrength;/* in percentage */ - rtw_hal_get_def_var(padapter, HAL_DEF_CURRENT_ANTENNA, &bssid->PhyInfo.Optimum_antenna); +exit: + return ret; +} - /* checking SSID */ - p = rtw_get_ie(bssid->IEs + ie_offset, _SSID_IE_, &len, bssid->IELength - ie_offset); - if (p == NULL) { - DBG_88E("marc: cannot find SSID for survey event\n"); - return _FAIL; - } +unsigned int on_action_public(struct adapter *padapter, struct recv_frame *precv_frame) +{ + unsigned int ret = _FAIL; + u8 *pframe = precv_frame->rx_data; + u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); + u8 category, action; - if (len) { - if (len > NDIS_802_11_LENGTH_SSID) { - DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); - return _FAIL; - } - memcpy(bssid->Ssid.Ssid, (p + 2), len); - bssid->Ssid.SsidLength = len; - } else { - bssid->Ssid.SsidLength = 0; - } + /* check RA matches or not */ + if (memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN)) + goto exit; - memset(bssid->SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX); + category = frame_body[0]; + if (category != RTW_WLAN_CATEGORY_PUBLIC) + goto exit; - /* checking rate info... */ - i = 0; - p = rtw_get_ie(bssid->IEs + ie_offset, _SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); - if (p != NULL) { - if (len > NDIS_802_11_LENGTH_RATES_EX) { - DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); - return _FAIL; - } - memcpy(bssid->SupportedRates, (p + 2), len); - i = len; + action = frame_body[1]; + switch (action) { + case ACT_PUBLIC_VENDOR: + ret = on_action_public_vendor(precv_frame); + break; + default: + ret = on_action_public_default(precv_frame, action); + break; } - p = rtw_get_ie(bssid->IEs + ie_offset, _EXT_SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); - if (p != NULL) { - if (len > (NDIS_802_11_LENGTH_RATES_EX-i)) { - DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); - return _FAIL; - } - memcpy(bssid->SupportedRates + i, (p + 2), len); - } +exit: + return ret; +} - /* todo: */ - bssid->NetworkTypeInUse = Ndis802_11OFDM24; +unsigned int OnAction_ht(struct adapter *padapter, struct recv_frame *precv_frame) +{ + return _SUCCESS; +} - if (bssid->IELength < 12) - return _FAIL; +unsigned int OnAction_wmm(struct adapter *padapter, struct recv_frame *precv_frame) +{ + return _SUCCESS; +} - /* Checking for DSConfig */ - p = rtw_get_ie(bssid->IEs + ie_offset, _DSSET_IE_, &len, bssid->IELength - ie_offset); +unsigned int OnAction_p2p(struct adapter *padapter, struct recv_frame *precv_frame) +{ + return _SUCCESS; +} - bssid->Configuration.DSConfig = 0; - bssid->Configuration.Length = 0; +unsigned int DoReserved(struct adapter *padapter, struct recv_frame *precv_frame) +{ + return _SUCCESS; +} - if (p) { - bssid->Configuration.DSConfig = *(p + 2); - } else {/* In 5G, some ap do not have DSSET IE */ - /* checking HT info for channel */ - p = rtw_get_ie(bssid->IEs + ie_offset, _HT_ADD_INFO_IE_, &len, bssid->IELength - ie_offset); - if (p) { - struct HT_info_element *HT_info = (struct HT_info_element *)(p + 2); - bssid->Configuration.DSConfig = HT_info->primary_channel; - } else { /* use current channel */ - bssid->Configuration.DSConfig = rtw_get_oper_ch(padapter); - } - } +static struct action_handler OnAction_tbl[] = { + {RTW_WLAN_CATEGORY_SPECTRUM_MGMT, "ACTION_SPECTRUM_MGMT", on_action_spct}, + {RTW_WLAN_CATEGORY_QOS, "ACTION_QOS", &OnAction_qos}, + {RTW_WLAN_CATEGORY_DLS, "ACTION_DLS", &OnAction_dls}, + {RTW_WLAN_CATEGORY_BACK, "ACTION_BACK", &OnAction_back}, + {RTW_WLAN_CATEGORY_PUBLIC, "ACTION_PUBLIC", on_action_public}, + {RTW_WLAN_CATEGORY_RADIO_MEASUREMENT, "ACTION_RADIO_MEASUREMENT", &DoReserved}, + {RTW_WLAN_CATEGORY_FT, "ACTION_FT", &DoReserved}, + {RTW_WLAN_CATEGORY_HT, "ACTION_HT", &OnAction_ht}, + {RTW_WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &DoReserved}, + {RTW_WLAN_CATEGORY_WMM, "ACTION_WMM", &OnAction_wmm}, + {RTW_WLAN_CATEGORY_P2P, "ACTION_P2P", &OnAction_p2p}, +}; - if (subtype == WIFI_PROBEREQ) { - /* FIXME */ - bssid->InfrastructureMode = Ndis802_11Infrastructure; - memcpy(bssid->MacAddress, GetAddr2Ptr(pframe), ETH_ALEN); - bssid->Privacy = 1; - return _SUCCESS; - } +unsigned int OnAction(struct adapter *padapter, struct recv_frame *precv_frame) +{ + int i; + unsigned char category; + struct action_handler *ptable; + unsigned char *frame_body; + u8 *pframe = precv_frame->rx_data; - bssid->Configuration.BeaconPeriod = - get_unaligned_le16(rtw_get_beacon_interval_from_ie(bssid->IEs)); + frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); - val16 = rtw_get_capability((struct wlan_bssid_ex *)bssid); + category = frame_body[0]; - if (val16 & BIT(0)) { - bssid->InfrastructureMode = Ndis802_11Infrastructure; - memcpy(bssid->MacAddress, GetAddr2Ptr(pframe), ETH_ALEN); - } else { - bssid->InfrastructureMode = Ndis802_11IBSS; - memcpy(bssid->MacAddress, GetAddr3Ptr(pframe), ETH_ALEN); + for (i = 0; i < sizeof(OnAction_tbl)/sizeof(struct action_handler); i++) { + ptable = &OnAction_tbl[i]; + if (category == ptable->num) + ptable->func(padapter, precv_frame); } + return _SUCCESS; +} - if (val16 & BIT(4)) - bssid->Privacy = 1; - else - bssid->Privacy = 0; +/**************************************************************************** - bssid->Configuration.ATIMWindow = 0; +Following are the initialization functions for WiFi MLME - /* 20/40 BSS Coexistence check */ - if ((pregistrypriv->wifi_spec == 1) && (!pmlmeinfo->bwmode_updated)) { - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - p = rtw_get_ie(bssid->IEs + ie_offset, _HT_CAPABILITY_IE_, &len, bssid->IELength - ie_offset); - if (p && len > 0) { - struct HT_caps_element *pHT_caps; - pHT_caps = (struct HT_caps_element *)(p + 2); +*****************************************************************************/ + +static struct mlme_handler mlme_sta_tbl[] = { + {WIFI_ASSOCREQ, "OnAssocReq", &OnAssocReq}, + {WIFI_ASSOCRSP, "OnAssocRsp", &OnAssocRsp}, + {WIFI_REASSOCREQ, "OnReAssocReq", &OnAssocReq}, + {WIFI_REASSOCRSP, "OnReAssocRsp", &OnAssocRsp}, + {WIFI_PROBEREQ, "OnProbeReq", &OnProbeReq}, + {WIFI_PROBERSP, "OnProbeRsp", &OnProbeRsp}, - if (le16_to_cpu(pHT_caps->u.HT_cap_element.HT_caps_info)&BIT(14)) - pmlmepriv->num_FortyMHzIntolerant++; - } else { - pmlmepriv->num_sta_no_ht++; - } - } + /*---------------------------------------------------------- + below 2 are reserved + -----------------------------------------------------------*/ + {0, "DoReserved", &DoReserved}, + {0, "DoReserved", &DoReserved}, + {WIFI_BEACON, "OnBeacon", &OnBeacon}, + {WIFI_ATIM, "OnATIM", &OnAtim}, + {WIFI_DISASSOC, "OnDisassoc", &OnDisassoc}, + {WIFI_AUTH, "OnAuth", &OnAuthClient}, + {WIFI_DEAUTH, "OnDeAuth", &OnDeAuth}, + {WIFI_ACTION, "OnAction", &OnAction}, +}; - /* mark bss info receiving from nearby channel as SignalQuality 101 */ - if (bssid->Configuration.DSConfig != rtw_get_oper_ch(padapter)) - bssid->PhyInfo.SignalQuality = 101; +int init_hw_mlme_ext(struct adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); return _SUCCESS; } -void start_create_ibss(struct adapter *padapter) +static void init_mlme_ext_priv_value(struct adapter *padapter) { - unsigned short caps; - u8 val8; - u8 join_type; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network)); - pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig; - pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork); + unsigned char mixed_datarate[NumRates] = { + _1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, + _9M_RATE_, _12M_RATE_, _18M_RATE_, _24M_RATE_, _36M_RATE_, + _48M_RATE_, _54M_RATE_, 0xff + }; + unsigned char mixed_basicrate[NumRates] = { + _1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, + _12M_RATE_, _24M_RATE_, 0xff, + }; - /* update wireless mode */ - update_wireless_mode(padapter); + atomic_set(&pmlmeext->event_seq, 0); + pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */ - /* update capability */ - caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork); - update_capinfo(padapter, caps); - if (caps&cap_IBSS) {/* adhoc master */ - val8 = 0xcf; - rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + pmlmeext->cur_channel = padapter->registrypriv.channel; + pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + pmlmeext->oper_channel = pmlmeext->cur_channel; + pmlmeext->oper_bwmode = pmlmeext->cur_bwmode; + pmlmeext->oper_ch_offset = pmlmeext->cur_ch_offset; + pmlmeext->retry = 0; - /* switch channel */ - /* SelectChannel(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE); */ - set_channel_bwmode(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); + pmlmeext->cur_wireless_mode = padapter->registrypriv.wireless_mode; - beacon_timing_control(padapter); + memcpy(pmlmeext->datarate, mixed_datarate, NumRates); + memcpy(pmlmeext->basicrate, mixed_basicrate, NumRates); - /* set msr to WIFI_FW_ADHOC_STATE */ - pmlmeinfo->state = WIFI_FW_ADHOC_STATE; - Set_MSR(padapter, (pmlmeinfo->state & 0x3)); + pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB; - /* issue beacon */ - if (send_beacon(padapter) == _FAIL) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("issuing beacon frame fail....\n")); + pmlmeext->sitesurvey_res.state = SCAN_DISABLE; + pmlmeext->sitesurvey_res.channel_idx = 0; + pmlmeext->sitesurvey_res.bss_cnt = 0; + pmlmeext->scan_abort = false; - report_join_res(padapter, -1); - pmlmeinfo->state = WIFI_FW_NULL_STATE; - } else { - rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, padapter->registrypriv.dev_network.MacAddress); - join_type = 0; - rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + pmlmeinfo->state = WIFI_FW_NULL_STATE; + pmlmeinfo->reauth_count = 0; + pmlmeinfo->reassoc_count = 0; + pmlmeinfo->link_count = 0; + pmlmeinfo->auth_seq = 0; + pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; + pmlmeinfo->key_index = 0; + pmlmeinfo->iv = 0; - report_join_res(padapter, 1); - pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; - } - } else { - DBG_88E("start_create_ibss, invalid cap:%x\n", caps); - return; - } -} + pmlmeinfo->enc_algo = _NO_PRIVACY_; + pmlmeinfo->authModeToggle = 0; -void start_clnt_join(struct adapter *padapter) -{ - unsigned short caps; - u8 val8; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network)); - int beacon_timeout; + memset(pmlmeinfo->chg_txt, 0, 128); - pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig; - pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork); + pmlmeinfo->slotTime = SHORT_SLOT_TIME; + pmlmeinfo->preamble_mode = PREAMBLE_AUTO; - /* update wireless mode */ - update_wireless_mode(padapter); + pmlmeinfo->dialogToken = 0; - /* update capability */ - caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork); - update_capinfo(padapter, caps); - if (caps&cap_ESS) { - Set_MSR(padapter, WIFI_FW_STATION_STATE); + pmlmeext->action_public_rxseq = 0xffff; + pmlmeext->action_public_dialog_token = 0xff; +} - val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf; +static int has_channel(struct rt_channel_info *channel_set, + u8 chanset_size, + u8 chan) { + int i; - rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + for (i = 0; i < chanset_size; i++) { + if (channel_set[i].ChannelNum == chan) + return 1; + } + return 0; +} - /* switch channel */ - set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); +static void init_channel_list(struct adapter *padapter, struct rt_channel_info *channel_set, + u8 chanset_size, + struct p2p_channels *channel_list) { + struct p2p_oper_class_map op_class[] = { + { IEEE80211G, 81, 1, 13, 1, BW20 }, + { IEEE80211G, 82, 14, 14, 1, BW20 }, + { -1, 0, 0, 0, 0, BW20 } + }; - /* here wait for receiving the beacon to start auth */ - /* and enable a timer */ - beacon_timeout = decide_wait_for_beacon_timeout(pmlmeinfo->bcn_interval); - set_link_timer(pmlmeext, beacon_timeout); - mod_timer(&padapter->mlmepriv.assoc_timer, jiffies + - msecs_to_jiffies((REAUTH_TO * REAUTH_LIMIT) + (REASSOC_TO * REASSOC_LIMIT) + beacon_timeout)); + int cla, op; - pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE; - } else if (caps&cap_IBSS) { /* adhoc client */ - Set_MSR(padapter, WIFI_FW_ADHOC_STATE); + cla = 0; - val8 = 0xcf; - rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + for (op = 0; op_class[op].op_class; op++) { + u8 ch; + struct p2p_oper_class_map *o = &op_class[op]; + struct p2p_reg_class *reg = NULL; - /* switch channel */ - set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { + if (!has_channel(channel_set, chanset_size, ch)) { + continue; + } - beacon_timing_control(padapter); + if ((0 == padapter->registrypriv.ht_enable) && (8 == o->inc)) + continue; - pmlmeinfo->state = WIFI_FW_ADHOC_STATE; + if ((0 == (padapter->registrypriv.cbw40_enable & BIT(1))) && + ((BW40MINUS == o->bw) || (BW40PLUS == o->bw))) + continue; - report_join_res(padapter, 1); - } else { - return; + if (reg == NULL) { + reg = &channel_list->reg_class[cla]; + cla++; + reg->reg_class = o->op_class; + reg->channels = 0; + } + reg->channel[reg->channels] = ch; + reg->channels++; + } } + channel_list->reg_classes = cla; } -void start_clnt_auth(struct adapter *padapter) +static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan, struct rt_channel_info *channel_set) { - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - - del_timer_sync(&pmlmeext->link_timer); + u8 index, chanset_size = 0; + u8 b2_4GBand = false; + u8 Index2G = 0; - pmlmeinfo->state &= (~WIFI_FW_AUTH_NULL); - pmlmeinfo->state |= WIFI_FW_AUTH_STATE; + memset(channel_set, 0, sizeof(struct rt_channel_info) * MAX_CHANNEL_NUM); - pmlmeinfo->auth_seq = 1; - pmlmeinfo->reauth_count = 0; - pmlmeinfo->reassoc_count = 0; - pmlmeinfo->link_count = 0; - pmlmeext->retry = 0; + if (ChannelPlan >= RT_CHANNEL_DOMAIN_MAX && ChannelPlan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) { + DBG_88E("ChannelPlan ID %x error !!!!!\n", ChannelPlan); + return chanset_size; + } + if (padapter->registrypriv.wireless_mode & WIRELESS_11G) { + b2_4GBand = true; + if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == ChannelPlan) + Index2G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index2G; + else + Index2G = RTW_ChannelPlanMap[ChannelPlan].Index2G; + } - /* Because of AP's not receiving deauth before */ - /* AP may: 1)not response auth or 2)deauth us after link is complete */ - /* issue deauth before issuing auth to deal with the situation */ - /* Commented by Albert 2012/07/21 */ - /* For the Win8 P2P connection, it will be hard to have a successful connection if this Wi-Fi doesn't connect to it. */ - issue_deauth(padapter, (&(pmlmeinfo->network))->MacAddress, WLAN_REASON_DEAUTH_LEAVING); + if (b2_4GBand) { + for (index = 0; index < RTW_ChannelPlan2G[Index2G].Len; index++) { + channel_set[chanset_size].ChannelNum = RTW_ChannelPlan2G[Index2G].Channel[index]; - DBG_88E_LEVEL(_drv_info_, "start auth\n"); - issue_auth(padapter, NULL, 0); + if ((RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN == ChannelPlan) ||/* Channel 1~11 is active, and 12~14 is passive */ + (RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G == ChannelPlan)) { + if (channel_set[chanset_size].ChannelNum >= 1 && channel_set[chanset_size].ChannelNum <= 11) + channel_set[chanset_size].ScanType = SCAN_ACTIVE; + else if ((channel_set[chanset_size].ChannelNum >= 12 && channel_set[chanset_size].ChannelNum <= 14)) + channel_set[chanset_size].ScanType = SCAN_PASSIVE; + } else if (RT_CHANNEL_DOMAIN_WORLD_WIDE_13 == ChannelPlan || + RT_CHANNEL_DOMAIN_2G_WORLD == Index2G) {/* channel 12~13, passive scan */ + if (channel_set[chanset_size].ChannelNum <= 11) + channel_set[chanset_size].ScanType = SCAN_ACTIVE; + else + channel_set[chanset_size].ScanType = SCAN_PASSIVE; + } else { + channel_set[chanset_size].ScanType = SCAN_ACTIVE; + } - set_link_timer(pmlmeext, REAUTH_TO); + chanset_size++; + } + } + return chanset_size; } - -void start_clnt_assoc(struct adapter *padapter) +int init_mlme_ext_priv(struct adapter *padapter) { - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - del_timer_sync(&pmlmeext->link_timer); + pmlmeext->padapter = padapter; - pmlmeinfo->state &= (~(WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE)); - pmlmeinfo->state |= (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE); + init_mlme_ext_priv_value(padapter); + pmlmeinfo->bAcceptAddbaReq = pregistrypriv->bAcceptAddbaReq; - issue_assocreq(padapter); + init_mlme_ext_timer(padapter); - set_link_timer(pmlmeext, REASSOC_TO); -} +#ifdef CONFIG_88EU_AP_MODE + init_mlme_ap_info(padapter); +#endif -unsigned int receive_disconnect(struct adapter *padapter, unsigned char *MacAddr, unsigned short reason) -{ - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); + pmlmeext->max_chan_nums = init_channel_set(padapter, pmlmepriv->ChannelPlan, pmlmeext->channel_set); + init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list); - /* check A3 */ - if (memcmp(MacAddr, pnetwork->MacAddress, ETH_ALEN)) - return _SUCCESS; + pmlmeext->chan_scan_time = SURVEY_TO; + pmlmeext->mlmeext_init = true; - DBG_88E("%s\n", __func__); - if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) { - if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { - pmlmeinfo->state = WIFI_FW_NULL_STATE; - report_del_sta_event(padapter, MacAddr, reason); - } else if (pmlmeinfo->state & WIFI_FW_LINKING_STATE) { - pmlmeinfo->state = WIFI_FW_NULL_STATE; - report_join_res(padapter, -2); - } - } + pmlmeext->active_keep_alive_check = true; + return _SUCCESS; } -static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid) +void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext) { - struct registry_priv *pregistrypriv; - struct mlme_ext_priv *pmlmeext; - struct rt_channel_info *chplan_new; - u8 channel; - u8 i; - - pregistrypriv = &padapter->registrypriv; - pmlmeext = &padapter->mlmeextpriv; - - /* Adjust channel plan by AP Country IE */ - if (pregistrypriv->enable80211d && - (!pmlmeext->update_channel_plan_by_ap_done)) { - u8 *ie, *p; - u32 len; - struct rt_channel_plan chplan_ap; - struct rt_channel_info chplan_sta[MAX_CHANNEL_NUM]; - u8 country[4]; - u8 fcn; /* first channel number */ - u8 noc; /* number of channel */ - u8 j, k; + struct adapter *padapter = pmlmeext->padapter; - ie = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _COUNTRY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); - if (!ie) - return; - if (len < 6) - return; - ie += 2; - p = ie; - ie += len; + if (!padapter) + return; - memset(country, 0, 4); - memcpy(country, p, 3); - p += 3; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, - ("%s: 802.11d country =%s\n", __func__, country)); + if (padapter->bDriverStopped) { + del_timer_sync(&pmlmeext->survey_timer); + del_timer_sync(&pmlmeext->link_timer); + } +} - i = 0; - while ((ie - p) >= 3) { - fcn = *(p++); - noc = *(p++); - p++; +static void _mgt_dispatcher(struct adapter *padapter, struct mlme_handler *ptable, struct recv_frame *precv_frame) +{ + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 *pframe = precv_frame->rx_data; - for (j = 0; j < noc; j++) { - if (fcn <= 14) - channel = fcn + j; /* 2.4 GHz */ - else - channel = fcn + j*4; /* 5 GHz */ + if (ptable->func) { + /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ + if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) && + memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN)) + return; + ptable->func(padapter, precv_frame); + } +} - chplan_ap.Channel[i++] = channel; - } - } - chplan_ap.Len = i; +void mgt_dispatcher(struct adapter *padapter, struct recv_frame *precv_frame) +{ + int index; + struct mlme_handler *ptable; +#ifdef CONFIG_88EU_AP_MODE + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; +#endif /* CONFIG_88EU_AP_MODE */ + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 *pframe = precv_frame->rx_data; + struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(pframe)); - memcpy(chplan_sta, pmlmeext->channel_set, sizeof(chplan_sta)); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("+mgt_dispatcher: type(0x%x) subtype(0x%x)\n", + GetFrameType(pframe), GetFrameSubType(pframe))); - memset(pmlmeext->channel_set, 0, sizeof(pmlmeext->channel_set)); - chplan_new = pmlmeext->channel_set; + if (GetFrameType(pframe) != WIFI_MGT_TYPE) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("mgt_dispatcher: type(0x%x) error!\n", GetFrameType(pframe))); + return; + } - i = 0; - j = 0; - k = 0; - if (pregistrypriv->wireless_mode & WIRELESS_11G) { - do { - if ((i == MAX_CHANNEL_NUM) || - (chplan_sta[i].ChannelNum == 0) || - (chplan_sta[i].ChannelNum > 14)) - break; + /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ + if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) && + memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN)) + return; - if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] > 14)) - break; + ptable = mlme_sta_tbl; - if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) { - chplan_new[k].ChannelNum = chplan_ap.Channel[j]; - chplan_new[k].ScanType = SCAN_ACTIVE; - i++; - j++; - k++; - } else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) { - chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; - chplan_new[k].ScanType = SCAN_PASSIVE; - i++; - k++; - } else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) { - chplan_new[k].ChannelNum = chplan_ap.Channel[j]; - chplan_new[k].ScanType = SCAN_ACTIVE; - j++; - k++; - } - } while (1); + index = GetFrameSubType(pframe) >> 4; - /* change AP not support channel to Passive scan */ - while ((i < MAX_CHANNEL_NUM) && - (chplan_sta[i].ChannelNum != 0) && - (chplan_sta[i].ChannelNum <= 14)) { - chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; - chplan_new[k].ScanType = SCAN_PASSIVE; - i++; - k++; - } + if (index > 13) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Currently we do not support reserved sub-fr-type=%d\n", index)); + return; + } + ptable += index; - /* add channel AP supported */ - while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) { - chplan_new[k].ChannelNum = chplan_ap.Channel[j]; - chplan_new[k].ScanType = SCAN_ACTIVE; - j++; - k++; - } - } else { - /* keep original STA 2.4G channel plan */ - while ((i < MAX_CHANNEL_NUM) && - (chplan_sta[i].ChannelNum != 0) && - (chplan_sta[i].ChannelNum <= 14)) { - chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; - chplan_new[k].ScanType = chplan_sta[i].ScanType; - i++; - k++; + if (psta != NULL) { + if (GetRetry(pframe)) { + if (precv_frame->attrib.seq_num == + psta->RxMgmtFrameSeqNum) { + /* drop the duplicate management frame */ + DBG_88E("Drop duplicate management frame with seq_num=%d.\n", + precv_frame->attrib.seq_num); + return; } - - /* skip AP 2.4G channel plan */ - while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) - j++; - } - - /* keep original STA 5G channel plan */ - while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) { - chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; - chplan_new[k].ScanType = chplan_sta[i].ScanType; - i++; - k++; } - - pmlmeext->update_channel_plan_by_ap_done = 1; + psta->RxMgmtFrameSeqNum = precv_frame->attrib.seq_num; } - /* If channel is used by AP, set channel scan type to active */ - channel = bssid->Configuration.DSConfig; - chplan_new = pmlmeext->channel_set; - i = 0; - while ((i < MAX_CHANNEL_NUM) && (chplan_new[i].ChannelNum != 0)) { - if (chplan_new[i].ChannelNum == channel) { - if (chplan_new[i].ScanType == SCAN_PASSIVE) { - chplan_new[i].ScanType = SCAN_ACTIVE; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, - ("%s: change channel %d scan type from passive to active\n", - __func__, channel)); - } - break; - } - i++; +#ifdef CONFIG_88EU_AP_MODE + switch (GetFrameSubType(pframe)) { + case WIFI_AUTH: + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) + ptable->func = &OnAuth; + else + ptable->func = &OnAuthClient; + /* fall through */ + case WIFI_ASSOCREQ: + case WIFI_REASSOCREQ: + case WIFI_PROBEREQ: + case WIFI_BEACON: + case WIFI_ACTION: + _mgt_dispatcher(padapter, ptable, precv_frame); + break; + default: + _mgt_dispatcher(padapter, ptable, precv_frame); + break; } +#else + _mgt_dispatcher(padapter, ptable, precv_frame); +#endif } /**************************************************************************** -- GitLab