/******************************************************************************
*
* Copyright(c) 2007 - 2019 Realtek Corporation.
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*****************************************************************************/
#define _RTW_MLME_EXT_C_
#include <drv_types.h>
#include <hal_data.h>
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},
{WIFI_BEACON, "OnBeacon", &OnBeacon},
{WIFI_ATIM, "OnATIM", &OnAtim},
{WIFI_DISASSOC, "OnDisassoc", &OnDisassoc},
{WIFI_AUTH, "OnAuth", &OnAuthClient},
{WIFI_DEAUTH, "OnDeAuth", &OnDeAuth},
{WIFI_ACTION, "OnAction", &OnAction},
{WIFI_ACTION_NOACK, "OnActionNoAck", &OnAction},
};
#ifdef _CONFIG_NATIVEAP_MLME_
struct mlme_handler mlme_ap_tbl[] = {
{WIFI_AUTH, "OnAuth", &OnAuth},
#endif
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_MEAS, "ACTION_RADIO_MEAS", &on_action_rm},
{RTW_WLAN_CATEGORY_FT, "ACTION_FT", &OnAction_ft},
{RTW_WLAN_CATEGORY_HT, "ACTION_HT", &OnAction_ht},
#ifdef CONFIG_IEEE80211W
{RTW_WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &OnAction_sa_query},
#else
{RTW_WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &DoReserved},
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_RTW_WNM
{RTW_WLAN_CATEGORY_WNM, "ACTION_WNM", &on_action_wnm},
{RTW_WLAN_CATEGORY_UNPROTECTED_WNM, "ACTION_UNPROTECTED_WNM", &DoReserved},
#ifdef CONFIG_RTW_MESH
{RTW_WLAN_CATEGORY_MESH, "ACTION_MESH", &on_action_mesh},
{RTW_WLAN_CATEGORY_SELF_PROTECTED, "ACTION_SELF_PROTECTED", &on_action_self_protected},
{RTW_WLAN_CATEGORY_WMM, "ACTION_WMM", &OnAction_wmm},
{RTW_WLAN_CATEGORY_VHT, "ACTION_VHT", &OnAction_vht},
{RTW_WLAN_CATEGORY_P2P, "ACTION_P2P", &OnAction_p2p},
#ifdef CONFIG_RTW_TOKEN_BASED_XMIT
{RTW_WLAN_CATEGORY_TBTX, "ACTION_TBTX_TOKEN", &OnAction_tbtx_token}
u8 null_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
/**************************************************
OUI definitions for the vendor specific IE
***************************************************/
unsigned char RTW_WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01};
unsigned char WMM_OUI[] = {0x00, 0x50, 0xf2, 0x02};
unsigned char WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04};
unsigned char P2P_OUI[] = {0x50, 0x6F, 0x9A, 0x09};
unsigned char WFD_OUI[] = {0x50, 0x6F, 0x9A, 0x0A};
unsigned char DPP_OUI[] = {0x50, 0x6F, 0x9A, 0x1A};
unsigned char MULTI_AP_OUI[] = {0x50, 0x6F, 0x9A, 0x1B};
unsigned char WMM_INFO_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01};
unsigned char WMM_PARA_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
unsigned char WPA_TKIP_CIPHER[4] = {0x00, 0x50, 0xf2, 0x02};
unsigned char RSN_TKIP_CIPHER[4] = {0x00, 0x0f, 0xac, 0x02};
unsigned char REALTEK_TBTX_IE[] = {0x00, 0xe0, 0x4c, 0x01, 0x00, 0x00, 0x00, 0x00};
extern unsigned char REALTEK_96B_IE[];
static void init_channel_list(_adapter *padapter, RT_CHANNEL_INFO *channel_set
, struct p2p_channels *channel_list)
{
struct registry_priv *regsty = adapter_to_regsty(padapter);
struct p2p_oper_class_map op_class[] = {
{ IEEE80211G, 81, 1, 13, 1, BW20 },
{ IEEE80211G, 82, 14, 14, 1, BW20 },
#if 0 /* Do not enable HT40 on 2 GHz */
{ IEEE80211G, 83, 1, 9, 1, BW40PLUS },
{ IEEE80211G, 84, 5, 13, 1, BW40MINUS },
{ IEEE80211A, 115, 36, 48, 4, BW20 },
{ IEEE80211A, 116, 36, 44, 8, BW40PLUS },
{ IEEE80211A, 117, 40, 48, 8, BW40MINUS },
{ IEEE80211A, 124, 149, 161, 4, BW20 },
{ IEEE80211A, 125, 149, 169, 4, BW20 },
{ IEEE80211A, 126, 149, 157, 8, BW40PLUS },
{ IEEE80211A, 127, 153, 161, 8, BW40MINUS },
{ -1, 0, 0, 0, 0, BW20 }
int cla, op;
cla = 0;
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;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
if (rtw_chset_search_ch(channel_set, ch) == -1)
continue;
#if defined(CONFIG_80211N_HT) || defined(CONFIG_80211AC_VHT)
if ((padapter->registrypriv.ht_enable == 0) && (o->inc == 8))
if ((REGSTY_IS_BW_5G_SUPPORT(regsty, CHANNEL_WIDTH_40)) &&
((o->bw == BW40MINUS) || (o->bw == BW40PLUS)))
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;
#if CONFIG_TXPWR_LIMIT
void rtw_txpwr_init_regd(struct rf_ctl_t *rfctl)
u8 regd;
struct regd_exc_ent *exc;
struct txpwr_lmt_ent *ent;
_irqL irqL;
_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
rfctl->regd_name = NULL;
if (rfctl->txpwr_regd_num == 0) {
RTW_PRINT("there is no any txpwr_regd\n");
goto release_lock;
/* search from exception mapping */
exc = _rtw_regd_exc_search(rfctl
, rfctl->country_ent ? rfctl->country_ent->alpha2 : NULL
, rfctl->ChannelPlan);
if (exc) {
u8 has_country = (exc->country[0] == '\0' && exc->country[1] == '\0') ? 0 : 1;
if (strcmp(exc->regd_name, regd_str(TXPWR_LMT_NONE)) == 0)
rfctl->regd_name = regd_str(TXPWR_LMT_NONE);
else if (strcmp(exc->regd_name, regd_str(TXPWR_LMT_WW)) == 0)
rfctl->regd_name = regd_str(TXPWR_LMT_WW);
else {
ent = _rtw_txpwr_lmt_get_by_name(rfctl, exc->regd_name);
if (ent)
rfctl->regd_name = ent->regd_name;
RTW_PRINT("exception mapping country:%c%c domain:0x%02x to%s regd_name:%s\n"
, has_country ? exc->country[0] : '0'
, has_country ? exc->country[1] : '0'
, exc->domain
, rfctl->regd_name ? "" : " unknown"
, exc->regd_name
);
if (rfctl->regd_name)
#ifdef CONFIG_REGD_SRC_FROM_OS
if (rfctl->regd_src == REGD_SRC_OS) {
if (IS_ALPHA2_WORLDWIDE(rfctl->country_ent->alpha2))
char alpha2[3] = {
rfctl->country_ent->alpha2[0], rfctl->country_ent->alpha2[1], 0};
ent = _rtw_txpwr_lmt_get_by_name(rfctl, alpha2);
if (rfctl->regd_name) {
RTW_PRINT("mapping country:%c%c to regd_name:%s\n"
, rfctl->country_ent->alpha2[0]
, rfctl->country_ent->alpha2[1]
, rfctl->regd_name
if (rfctl->ChannelPlan == RTW_CHPLAN_UNSPECIFIED) {
RTW_PRINT("mapping unsupported country:%c%c to regd_name:%s\n"
/* follow default channel plan mapping */
regd = rtw_chplan_get_default_regd(rfctl->ChannelPlan);
if (regd == TXPWR_LMT_NONE)
else if (regd == TXPWR_LMT_WW)
ent = _rtw_txpwr_lmt_get_by_name(rfctl, regd_str(regd));
RTW_PRINT("default mapping domain:0x%02x to%s regd_name:%s\n"
, rfctl->ChannelPlan
, regd_str(regd)
switch (regd) {
/*
* To support older chips without new predefined regd:
* - use FCC if IC or CHILE or MEXICO not found
* - use ETSI if KCC or ACMA not found
*/
case TXPWR_LMT_IC:
case TXPWR_LMT_KCC:
case TXPWR_LMT_NCC:
case TXPWR_LMT_ACMA:
case TXPWR_LMT_CHILE:
case TXPWR_LMT_MEXICO:
if (regd == TXPWR_LMT_IC || regd == TXPWR_LMT_NCC || regd == TXPWR_LMT_CHILE || regd == TXPWR_LMT_MEXICO)
regd = TXPWR_LMT_FCC;
else if (regd == TXPWR_LMT_KCC || regd == TXPWR_LMT_ACMA)
regd = TXPWR_LMT_ETSI;
RTW_PRINT("alternate regd_name:%s %s\n"
, rfctl->regd_name ? "is used" : "not found"
break;
/* fall through */
default:
RTW_PRINT("assign %s for default case\n", regd_str(TXPWR_LMT_WW));
release_lock:
_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);
#endif /* CONFIG_TXPWR_LIMIT */
int rtw_rfctl_init(_adapter *adapter)
struct registry_priv *regsty = adapter_to_regsty(adapter);
struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
int ret;
_rtw_mutex_init(&rfctl->offch_mutex);
_rtw_mutex_init(&rfctl->txpwr_lmt_mutex);
_rtw_init_listhead(&rfctl->reg_exc_list);
_rtw_init_listhead(&rfctl->txpwr_lmt_list);
rfctl->ch_sel_within_same_band = 1;
#ifdef CONFIG_DFS_MASTER
rfctl->dfs_region_domain = regsty->dfs_region_domain;
rfctl->cac_start_time = rfctl->cac_end_time = RTW_CAC_STOPPED;
rtw_init_timer(&(rfctl->radar_detect_timer), adapter, rtw_dfs_rd_timer_hdl, rfctl);
#if CONFIG_DFS_SLAVE_WITH_RADAR_DETECT
rfctl->dfs_slave_with_rd = 1;
if (regsty->antenna_gain != UNSPECIFIED_MBM)
rfctl->antenna_gain = regsty->antenna_gain;
ret = op_class_pref_init(adapter);
if (ret != _SUCCESS)
op_class_pref_deinit(adapter);
return ret;
void rtw_rfctl_deinit(_adapter *adapter)
_rtw_mutex_free(&rfctl->offch_mutex);
rtw_regd_exc_list_free(rfctl);
rtw_txpwr_lmt_list_free(rfctl);
_rtw_mutex_free(&rfctl->txpwr_lmt_mutex);
if (rfctl->regd_src == REGD_SRC_OS)
rtw_mfree((void *)rfctl->country_ent, sizeof(struct country_chplan));
void rtw_rfctl_chplan_init(_adapter *adapter)
rfctl->max_chan_nums = init_channel_set(adapter);
op_class_pref_apply_regulatory(adapter, REG_CHANGE);
init_channel_list(adapter, rfctl->channel_set, &rfctl->channel_list);
void rtw_rfctl_update_op_mode(struct rf_ctl_t *rfctl, u8 ifbmp_mod, u8 if_op)
struct dvobj_priv *dvobj = rfctl_to_dvobj(rfctl);
_adapter *iface;
struct mlme_ext_priv *mlmeext;
u8 op_class = 0;
u8 op_ch = 0;
s16 op_txpwr_max;
u8 if_op_class[CONFIG_IFACE_NUMBER] = {0};
u8 if_op_ch[CONFIG_IFACE_NUMBER] = {0};
u8 ch, bw, offset;
u8 u_ch = 0, u_bw, u_offset;
bool notify = 0;
int i;
for (i = 0; i < dvobj->iface_nums; i++) {
iface = dvobj->padapters[i];
if (!iface)
mlmeext = &iface->mlmeextpriv;
if (ifbmp_mod & BIT(i)) {
if (!if_op)
} else if (!MLME_IS_ASOC(iface) || MLME_IS_OPCH_SW(iface))
ch = mlmeext->cur_channel;
bw = mlmeext->cur_bwmode;
offset = mlmeext->cur_ch_offset;
if_op_class[i] = rtw_get_op_class_by_chbw(ch, bw, offset);
if_op_ch[i] = if_op_class[i] ? ch : 0;
if (!u_ch) {
u_ch = ch;
u_bw = bw;
u_offset = offset;
} else {
rtw_warn_on(!rtw_is_chbw_grouped(u_ch, u_bw, u_offset, ch, bw, offset));
rtw_sync_chbw(&ch, &bw, &offset, &u_ch, &u_bw, &u_offset);
op_class = rtw_get_op_class_by_chbw(u_ch, u_bw, u_offset);
op_ch = op_class ? u_ch : 0;
op_txpwr_max = rtw_rfctl_get_oper_txpwr_max_mbm(rfctl, u_ch, u_bw, u_offset, ifbmp_mod, if_op, 1);
if (op_class != rfctl->op_class
|| op_ch != rfctl->op_ch
|| op_txpwr_max != rfctl->op_txpwr_max
|| _rtw_memcmp(if_op_class, rfctl->if_op_class, sizeof(u8) * CONFIG_IFACE_NUMBER) == _FALSE
|| _rtw_memcmp(if_op_ch, rfctl->if_op_ch, sizeof(u8) * CONFIG_IFACE_NUMBER) == _FALSE)
notify = 1;
rfctl->op_class = op_class;
rfctl->op_ch = op_ch;
rfctl->op_txpwr_max = op_txpwr_max;
_rtw_memcpy(rfctl->if_op_class, if_op_class, sizeof(u8) * CONFIG_IFACE_NUMBER);
_rtw_memcpy(rfctl->if_op_ch, if_op_ch, sizeof(u8) * CONFIG_IFACE_NUMBER);
if (0)
RTW_INFO("radio: %u,%u,%u %d notify:%d\n", u_ch, u_bw, u_offset, op_txpwr_max, notify);
} else if (!MLME_IS_ASOC(iface))
RTW_INFO(ADPT_FMT": %u,%u,%u\n", ADPT_ARG(iface)
, mlmeext->cur_channel, mlmeext->cur_bwmode, mlmeext->cur_ch_offset);
if (notify)
rtw_nlrtw_radio_opmode_notify(rfctl);
#ifdef CONFIG_PLATFORM_CMAP_INTFS
cmap_intfs_nl_bss_status_event(iface, 0);
inline u8 rtw_rfctl_get_dfs_domain(struct rf_ctl_t *rfctl)
return rfctl->dfs_region_domain;
return RTW_DFS_REGD_NONE;
inline u8 rtw_rfctl_dfs_domain_unknown(struct rf_ctl_t *rfctl)
return rtw_rfctl_get_dfs_domain(rfctl) == RTW_DFS_REGD_NONE;
return 1;
* called in rtw_dfs_rd_enable()
* assume the request channel coverage is DFS range
* base on the current status and the request channel coverage to check if need to reset complete CAC time
bool rtw_is_cac_reset_needed(struct rf_ctl_t *rfctl, u8 ch, u8 bw, u8 offset)
bool needed = _FALSE;
u32 cur_hi, cur_lo, hi, lo;
if (rfctl->radar_detected == 1) {
needed = _TRUE;
goto exit;
if (rfctl->radar_detect_ch == 0) {
if (rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo) == _FALSE) {
RTW_ERR("request detection range ch:%u, bw:%u, offset:%u\n", ch, bw, offset);
rtw_warn_on(1);
if (rtw_chbw_to_freq_range(rfctl->radar_detect_ch, rfctl->radar_detect_bw, rfctl->radar_detect_offset, &cur_hi, &cur_lo) == _FALSE) {
RTW_ERR("cur detection range ch:%u, bw:%u, offset:%u\n", rfctl->radar_detect_ch, rfctl->radar_detect_bw, rfctl->radar_detect_offset);
if (hi <= lo || cur_hi <= cur_lo) {
RTW_ERR("hi:%u, lo:%u, cur_hi:%u, cur_lo:%u\n", hi, lo, cur_hi, cur_lo);
if (rtw_is_range_a_in_b(hi, lo, cur_hi, cur_lo)) {
/* request is in current detect range */
/* check if request channel coverage has new range and the new range is in DFS range */
if (!rtw_is_range_overlap(hi, lo, cur_hi, cur_lo)) {
/* request has no overlap with current */
} else if (rtw_is_range_a_in_b(cur_hi, cur_lo, hi, lo)) {
/* request is supper set of current */
if ((hi != cur_hi && rtw_chset_is_dfs_range(rfctl->channel_set, hi, cur_hi))
|| (lo != cur_lo && rtw_chset_is_dfs_range(rfctl->channel_set, cur_lo, lo)))
/* request is not supper set of current, but has overlap */
if ((lo < cur_lo && rtw_chset_is_dfs_range(rfctl->channel_set, cur_lo, lo))
|| (hi > cur_hi && rtw_chset_is_dfs_range(rfctl->channel_set, hi, cur_hi)))
exit:
return needed;
bool _rtw_rfctl_overlap_radar_detect_ch(struct rf_ctl_t *rfctl, u8 ch, u8 bw, u8 offset)
bool ret = _FALSE;
u32 hi = 0, lo = 0;
u32 r_hi = 0, r_lo = 0;
if (rfctl->radar_detect_by_others)
if (rfctl->radar_detect_ch == 0)
if (rtw_chbw_to_freq_range(rfctl->radar_detect_ch
, rfctl->radar_detect_bw, rfctl->radar_detect_offset
, &r_hi, &r_lo) == _FALSE) {
if (rtw_is_range_overlap(hi, lo, r_hi, r_lo))
ret = _TRUE;
bool rtw_rfctl_overlap_radar_detect_ch(struct rf_ctl_t *rfctl)
return _rtw_rfctl_overlap_radar_detect_ch(rfctl
, rfctl_to_dvobj(rfctl)->oper_channel
, rfctl_to_dvobj(rfctl)->oper_bwmode
, rfctl_to_dvobj(rfctl)->oper_ch_offset);
bool rtw_rfctl_is_tx_blocked_by_ch_waiting(struct rf_ctl_t *rfctl)
return rtw_rfctl_overlap_radar_detect_ch(rfctl) && IS_CH_WAITING(rfctl);
bool rtw_chset_is_chbw_non_ocp(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset)
if (rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo) == _FALSE)
for (i = 0; i < MAX_CHANNEL_NUM && ch_set[i].ChannelNum != 0; i++) {
if (!rtw_ch2freq(ch_set[i].ChannelNum)) {
if (!CH_IS_NON_OCP(&ch_set[i]))
if (lo <= rtw_ch2freq(ch_set[i].ChannelNum)
&& rtw_ch2freq(ch_set[i].ChannelNum) <= hi
) {
bool rtw_chset_is_ch_non_ocp(RT_CHANNEL_INFO *ch_set, u8 ch)
return rtw_chset_is_chbw_non_ocp(ch_set, ch, CHANNEL_WIDTH_20, HAL_PRIME_CHNL_OFFSET_DONT_CARE);
u32 rtw_chset_get_ch_non_ocp_ms(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset)
int ms = 0;
systime current_time;
current_time = rtw_get_current_time();
if (rtw_systime_to_ms(ch_set[i].non_ocp_end_time - current_time) > ms)
ms = rtw_systime_to_ms(ch_set[i].non_ocp_end_time - current_time);
return ms;
/**
* rtw_chset_update_non_ocp - update non_ocp_end_time according to the given @ch, @bw, @offset into @ch_set
* @ch_set: the given channel set
* @ch: channel number on which radar is detected
* @bw: bandwidth on which radar is detected
* @offset: bandwidth offset on which radar is detected
* @ms: ms to add from now to update non_ocp_end_time, ms < 0 means use NON_OCP_TIME_MS
static bool _rtw_chset_update_non_ocp(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset, int ms)
bool updated = 0;
if (ms >= 0)
ch_set[i].non_ocp_end_time = rtw_get_current_time() + rtw_ms_to_systime(ms);
else
ch_set[i].non_ocp_end_time = rtw_get_current_time() + rtw_ms_to_systime(NON_OCP_TIME_MS);
ch_set[i].flags |= RTW_CHF_NON_OCP;
updated = 1;
return updated;
inline bool rtw_chset_update_non_ocp(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset)
return _rtw_chset_update_non_ocp(ch_set, ch, bw, offset, -1);
inline bool rtw_chset_update_non_ocp_ms(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset, int ms)
return _rtw_chset_update_non_ocp(ch_set, ch, bw, offset, ms);
static bool rtw_chset_chk_non_ocp_finish_for_chbw(struct rf_ctl_t *rfctl, u8 ch, u8 bw, u8 offset)
RT_CHANNEL_INFO *ch_set = rfctl->channel_set;
u8 cch;
u8 *op_chs;
u8 op_ch_num;
int ch_idx;
bool ret = 0;
cch = rtw_get_center_ch(ch, bw, offset);
if (!rtw_get_op_chs_by_cch_bw(cch, bw, &op_chs, &op_ch_num))
for (i = 0; i < op_ch_num; i++) {
RTW_INFO("%u,%u,%u - cch:%u, bw:%u, op_ch:%u\n", ch, bw, offset, cch, bw, *(op_chs + i));
ch_idx = rtw_chset_search_ch(ch_set, *(op_chs + i));
if (ch_idx == -1)
if (!(ch_set[ch_idx].flags & RTW_CHF_NON_OCP) || CH_IS_NON_OCP(&ch_set[ch_idx]))
if (op_ch_num != 0 && i == op_ch_num) {
ret = 1;
/* clear RTTW_CHF_NON_OCP flag */
ch_set[ch_idx].flags &= ~RTW_CHF_NON_OCP;
rtw_nlrtw_nop_finish_event(dvobj_get_primary_adapter(rfctl_to_dvobj(rfctl)), cch, bw);
/* called by watchdog to clear RTW_CHF_NON_OCP and generate NON_OCP finish event */
void rtw_chset_chk_non_ocp_finish(struct rf_ctl_t *rfctl)
bw = CHANNEL_WIDTH_160;
while (1) {
for (i = 0; i < rfctl->max_chan_nums; i++) {
ch = rfctl->channel_set[i].ChannelNum;
if (!(rfctl->channel_set[i].flags & RTW_CHF_NON_OCP))
if (!rtw_get_offset_by_chbw(ch, bw, &offset))
rtw_chset_chk_non_ocp_finish_for_chbw(rfctl, ch, bw, offset);
if (bw-- == CHANNEL_WIDTH_20)
u32 rtw_get_ch_waiting_ms(struct rf_ctl_t *rfctl, u8 ch, u8 bw, u8 offset, u32 *r_non_ocp_ms, u32 *r_cac_ms)
u32 non_ocp_ms;
u32 cac_ms;
u8 in_rd_range = 0; /* if in current radar detection range*/
if (rtw_chset_is_chbw_non_ocp(rfctl->channel_set, ch, bw, offset))
non_ocp_ms = rtw_chset_get_ch_non_ocp_ms(rfctl->channel_set, ch, bw, offset);
non_ocp_ms = 0;
if (rfctl->radar_detect_enabled) {
RTW_ERR("input range ch:%u, bw:%u, offset:%u\n", ch, bw, offset);
if (rtw_is_range_a_in_b(hi, lo, cur_hi, cur_lo))
in_rd_range = 1;
if (!rtw_chset_is_dfs_chbw(rfctl->channel_set, ch, bw, offset))
cac_ms = 0;
else if (in_rd_range && !non_ocp_ms) {
if (IS_CH_WAITING(rfctl))
cac_ms = rtw_systime_to_ms(rfctl->cac_end_time - rtw_get_current_time());
} else if (rtw_is_long_cac_ch(ch, bw, offset, rtw_rfctl_get_dfs_domain(rfctl)))
cac_ms = CAC_TIME_CE_MS;
cac_ms = CAC_TIME_MS;
if (r_non_ocp_ms)
*r_non_ocp_ms = non_ocp_ms;
if (r_cac_ms)
*r_cac_ms = cac_ms;
return non_ocp_ms + cac_ms;
void rtw_reset_cac(struct rf_ctl_t *rfctl, u8 ch, u8 bw, u8 offset)
rtw_get_ch_waiting_ms(rfctl
, ch
, bw
, offset
, &non_ocp_ms
, &cac_ms
rfctl->cac_start_time = rtw_get_current_time() + rtw_ms_to_systime(non_ocp_ms);
rfctl->cac_end_time = rfctl->cac_start_time + rtw_ms_to_systime(cac_ms);
/* skip special value */
if (rfctl->cac_start_time == RTW_CAC_STOPPED) {
rfctl->cac_start_time++;
rfctl->cac_end_time++;
if (rfctl->cac_end_time == RTW_CAC_STOPPED)
u32 rtw_force_stop_cac(struct rf_ctl_t *rfctl, u32 timeout_ms)
systime start;
u32 pass_ms;
start = rtw_get_current_time();
rfctl->cac_force_stop = 1;
while (rtw_get_passing_time_ms(start) <= timeout_ms
&& IS_UNDER_CAC(rfctl)
if (dev_is_surprise_removed(dvobj) || dev_is_drv_stopped(dvobj))
rtw_msleep_os(20);
if (IS_UNDER_CAC(rfctl)) {
if (!dev_is_surprise_removed(dvobj) && !dev_is_drv_stopped(dvobj))
RTW_INFO("%s waiting for cac stop timeout!\n", __func__);
rfctl->cac_force_stop = 0;
pass_ms = rtw_get_passing_time_ms(start);
return pass_ms;
#endif /* CONFIG_DFS_MASTER */
/* choose channel with shortest waiting (non ocp + cac) time */
bool rtw_choose_shortest_waiting_ch(struct rf_ctl_t *rfctl, u8 sel_ch, u8 max_bw
, u8 *dec_ch, u8 *dec_bw, u8 *dec_offset
, u8 e_flags, u8 d_flags, u8 cur_ch, bool by_int_info, u8 mesh_only)
#ifndef DBG_CHOOSE_SHORTEST_WAITING_CH
#define DBG_CHOOSE_SHORTEST_WAITING_CH 0
#ifdef CONFIG_RTW_ACS
HAL_DATA_TYPE *hal_data = GET_HAL_DATA(dvobj_get_primary_adapter(dvobj));
struct registry_priv *regsty = dvobj_to_regsty(dvobj);
u8 ch_c = 0, bw_c = 0, offset_c = 0;
u32 min_waiting_ms = 0;
u16 int_factor_c = 0;
if (!dec_ch || !dec_bw || !dec_offset) {
return _FALSE;
RTW_INFO("%s: sel_ch:%u max_bw:%u e_flags:0x%02x d_flags:0x%02x cur_ch:%u within_sb:%d%s%s\n"
, __func__, sel_ch, max_bw, e_flags, d_flags, cur_ch, rfctl->ch_sel_within_same_band
, by_int_info ? " int" : "", mesh_only ? " mesh_only" : "");
/* full search and narrow bw judegement first to avoid potetial judegement timing issue */
for (bw = CHANNEL_WIDTH_20; bw <= max_bw; bw++) {
if (!hal_is_bw_support(dvobj_get_primary_adapter(dvobj), bw))
u32 non_ocp_ms = 0;
u32 cac_ms = 0;
u32 waiting_ms = 0;
u16 int_factor = 0;
bool dfs_ch;
bool non_ocp;
bool long_cac;
if (sel_ch) {
if (ch != sel_ch)
} else if (rfctl->ch_sel_within_same_band && !rtw_is_same_band(cur_ch, ch))
if (ch > 14) {
if (bw > REGSTY_BW_5G(regsty))
if (bw > REGSTY_BW_2G(regsty))
if (mesh_only && ch >= 5 && ch <= 9 && bw > CHANNEL_WIDTH_20)
if (!rtw_chset_is_chbw_valid(rfctl->channel_set, ch, bw, offset, 0, 0))
if ((e_flags & RTW_CHF_DFS) || (d_flags & RTW_CHF_DFS)) {
dfs_ch = rtw_chset_is_dfs_chbw(rfctl->channel_set, ch, bw, offset);
if (((e_flags & RTW_CHF_DFS) && !dfs_ch)
|| ((d_flags & RTW_CHF_DFS) && dfs_ch))
if ((e_flags & RTW_CHF_LONG_CAC) || (d_flags & RTW_CHF_LONG_CAC)) {
long_cac = rtw_is_long_cac_ch(ch, bw, offset, rtw_rfctl_get_dfs_domain(rfctl));
if (((e_flags & RTW_CHF_LONG_CAC) && !long_cac)
|| ((d_flags & RTW_CHF_LONG_CAC) && long_cac))
if ((e_flags & RTW_CHF_NON_OCP) || (d_flags & RTW_CHF_NON_OCP)) {
non_ocp = rtw_chset_is_chbw_non_ocp(rfctl->channel_set, ch, bw, offset);
if (((e_flags & RTW_CHF_NON_OCP) && !non_ocp)
|| ((d_flags & RTW_CHF_NON_OCP) && non_ocp))
waiting_ms = rtw_get_ch_waiting_ms(rfctl, ch, bw, offset, &non_ocp_ms, &cac_ms);
if (by_int_info) {
/* for now, consider only primary channel */
int_factor = hal_data->acs.interference_time[i];
if (DBG_CHOOSE_SHORTEST_WAITING_CH)
RTW_INFO("%s:%u,%u,%u %u(non_ocp:%u, cac:%u), int:%u\n"
, __func__, ch, bw, offset, waiting_ms, non_ocp_ms, cac_ms, int_factor);
if (ch_c == 0
/* first: smaller wating time */
|| min_waiting_ms > waiting_ms
/* then: less interference */
|| (min_waiting_ms == waiting_ms && int_factor_c > int_factor)
/* then: wider bw */
|| (min_waiting_ms == waiting_ms && int_factor_c == int_factor && bw > bw_c)
/* if all condition equal, same channel -> same band prefer */
|| (min_waiting_ms == waiting_ms && int_factor_c == int_factor && bw == bw_c
&& ((cur_ch != ch_c && cur_ch == ch)
|| (!rtw_is_same_band(cur_ch, ch_c) && rtw_is_same_band(cur_ch, ch)))
)
ch_c = ch;
bw_c = bw;
offset_c = offset;
min_waiting_ms = waiting_ms;
int_factor_c = int_factor;
if (ch_c != 0) {
RTW_INFO("%s: select %u,%u,%u waiting_ms:%u\n"
, __func__, ch_c, bw_c, offset_c, min_waiting_ms);
*dec_ch = ch_c;
*dec_bw = bw_c;
*dec_offset = offset_c;
return _TRUE;
RTW_INFO("%s: not found\n", __func__);
if (d_flags == 0)
#ifdef CONFIG_PROC_DEBUG
#define RTW_CHF_FMT "%s%s%s%s%s%s"
#define RTW_CHF_ARG_NO_IR(flags) (flags & RTW_CHF_NO_IR) ? " NO_IR" : ""
#define RTW_CHF_ARG_DFS(flags) , (flags & RTW_CHF_DFS) ? " DFS" : ""
#define RTW_CHF_ARG_NO_HT40U(flags) , (flags & RTW_CHF_NO_HT40U) ? " NO_40M+" : ""
#define RTW_CHF_ARG_NO_HT40L(flags) , (flags & RTW_CHF_NO_HT40L) ? " NO_40M-" : ""
#define RTW_CHF_ARG_NO_80MHZ(flags) , (flags & RTW_CHF_NO_80MHZ) ? " NO_80M" : ""
#define RTW_CHF_ARG_NO_160MHZ(flags) , (flags & RTW_CHF_NO_160MHZ) ? " NO_160M" : ""
#define RTW_CHF_ARG(flags) \
RTW_CHF_ARG_NO_IR(flags) \
RTW_CHF_ARG_DFS(flags) \
RTW_CHF_ARG_NO_HT40U(flags) \
RTW_CHF_ARG_NO_HT40L(flags) \
RTW_CHF_ARG_NO_80MHZ(flags) \
RTW_CHF_ARG_NO_160MHZ(flags)
void dump_chset(void *sel, RT_CHANNEL_INFO *ch_set, u8 chset_num)
char buf[8];
u8 i;
RTW_PRINT_SEL(sel, "%-3s %-4s %-4s flags\n", "ch", "freq", "nocp");
for (i = 0; i < MAX_CHANNEL_NUM && i < chset_num && ch_set[i].ChannelNum != 0; i++) {
if ((ch_set[i].flags & RTW_CHF_DFS) && CH_IS_NON_OCP(&ch_set[i]))
snprintf(buf, 8, "%d", rtw_systime_to_ms(ch_set[i].non_ocp_end_time - rtw_get_current_time()) / 1000);
snprintf(buf, 8, "0");
RTW_PRINT_SEL(sel, "%3u %4u %4s"RTW_CHF_FMT"\n"
, ch_set[i].ChannelNum, rtw_ch2freq(ch_set[i].ChannelNum), buf
, RTW_CHF_ARG(ch_set[i].flags)
RTW_PRINT_SEL(sel, "total ch number:%d\n", i);
void dump_cur_chset(void *sel, struct rf_ctl_t *rfctl)
struct get_chplan_resp *chplan;
if (rtw_get_chplan_cmd(dvobj_get_primary_adapter(dvobj), RTW_CMDF_WAIT_ACK, &chplan) == _FAIL)
return;
RTW_PRINT_SEL(sel, "regd_src:%s(%d)\n", regd_src_str(chplan->regd_src), chplan->regd_src);
if (chplan->has_country)
dump_country_chplan(sel, &chplan->country_ent);
RTW_PRINT_SEL(sel, "chplan:0x%02X\n", chplan->channel_plan);
RTW_PRINT_SEL(sel, "PLS regd:%s\n", chplan->regd_name);
RTW_PRINT_SEL(sel, "dfs_domain:%s(%u)\n", rtw_dfs_regd_str(chplan->dfs_domain), chplan->dfs_domain);
for (i = 0; i < MAX_CHANNEL_NUM; i++)
if (regsty->excl_chs[i] != 0)
if (i < MAX_CHANNEL_NUM) {
RTW_PRINT_SEL(sel, "excl_chs:");
for (i = 0; i < MAX_CHANNEL_NUM; i++) {
if (regsty->excl_chs[i] == 0)
_RTW_PRINT_SEL(sel, "%u ", regsty->excl_chs[i]);
_RTW_PRINT_SEL(sel, "\n");
dump_chset(sel, chplan->chset, chplan->chset_num);
rtw_vmfree(chplan, sizeof(struct get_chplan_resp) + sizeof(RT_CHANNEL_INFO) * chplan->chset_num);
* Search the @param ch in given @param ch_set
* @ch: the given channel number
* return the index of channel_num in channel_set, -1 if not found
int rtw_chset_search_ch(RT_CHANNEL_INFO *ch_set, const u32 ch)
if (ch == 0)
return -1;
if (ch == ch_set[i].ChannelNum)
return i;
* Check if the @param ch, bw, offset is valid for the given @param ch_set
* @bw: the given bandwidth
* @offset: the given channel offset
* return valid (1) or not (0)
u8 rtw_chset_is_chbw_valid(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset
, bool allow_primary_passive, bool allow_passive)
u8 valid = 0;
if (ch_set[ch_idx].flags & RTW_CHF_NO_IR) {
if ((!allow_primary_passive && ch_set[ch_idx].ChannelNum == ch)
|| (!allow_passive && ch_set[ch_idx].ChannelNum != ch))
if (bw >= CHANNEL_WIDTH_40) {
if ((ch_set[ch_idx].flags & RTW_CHF_NO_HT40U) && i % 2 == 0)
if ((ch_set[ch_idx].flags & RTW_CHF_NO_HT40L) && i % 2 == 1)
if (bw >= CHANNEL_WIDTH_80 && (ch_set[ch_idx].flags & RTW_CHF_NO_80MHZ))
if (bw >= CHANNEL_WIDTH_160 && (ch_set[ch_idx].flags & RTW_CHF_NO_160MHZ))
if (op_ch_num != 0 && i == op_ch_num)
valid = 1;
return valid;
* rtw_chset_sync_chbw - obey g_ch, adjust g_bw, g_offset, bw, offset to fit in channel plan
* @ch_set: channel plan to check
* @req_ch: pointer of the request ch, may be modified further
* @req_bw: pointer of the request bw, may be modified further
* @req_offset: pointer of the request offset, may be modified further
* @g_ch: pointer of the ongoing group ch
* @g_bw: pointer of the ongoing group bw, may be modified further
* @g_offset: pointer of the ongoing group offset, may be modified further
* @allow_primary_passive: if allow passive primary ch when deciding chbw
* @allow_passive: if allow passive ch (not primary) when deciding chbw
void rtw_chset_sync_chbw(RT_CHANNEL_INFO *ch_set, u8 *req_ch, u8 *req_bw, u8 *req_offset
, u8 *g_ch, u8 *g_bw, u8 *g_offset, bool allow_primary_passive, bool allow_passive)
u8 r_ch, r_bw, r_offset;
u8 u_ch, u_bw, u_offset;
u8 cur_bw = *req_bw;
r_ch = *req_ch;
r_bw = cur_bw;
r_offset = *req_offset;
u_ch = *g_ch;
u_bw = *g_bw;
u_offset = *g_offset;
rtw_sync_chbw(&r_ch, &r_bw, &r_offset, &u_ch, &u_bw, &u_offset);
if (rtw_chset_is_chbw_valid(ch_set, r_ch, r_bw, r_offset, allow_primary_passive, allow_passive))
if (cur_bw == CHANNEL_WIDTH_20) {
cur_bw--;
*req_ch = r_ch;
*req_bw = r_bw;
*req_offset = r_offset;
*g_ch = u_ch;
*g_bw = u_bw;
*g_offset = u_offset;
* Check the @param ch is fit with setband setting of @param adapter
* @adapter: the given adapter
* return _TRUE when check valid, _FALSE not valid
bool rtw_mlme_band_check(_adapter *adapter, const u32 ch)
if (adapter->setband == WIFI_FREQUENCY_BAND_AUTO /* 2.4G and 5G */
|| (adapter->setband == WIFI_FREQUENCY_BAND_2GHZ && ch < 35) /* 2.4G only */
|| (adapter->setband == WIFI_FREQUENCY_BAND_5GHZ && ch > 35) /* 5G only */
inline void RTW_SET_SCAN_BAND_SKIP(_adapter *padapter, int skip_band)
int bs = ATOMIC_READ(&padapter->bandskip);
bs |= skip_band;
ATOMIC_SET(&padapter->bandskip, bs);
inline void RTW_CLR_SCAN_BAND_SKIP(_adapter *padapter, int skip_band)
bs &= ~(skip_band);
inline int RTW_GET_SCAN_BAND_SKIP(_adapter *padapter)
return ATOMIC_READ(&padapter->bandskip);
#define RTW_IS_SCAN_BAND_SKIP(padapter, skip_band) (ATOMIC_READ(&padapter->bandskip) & (skip_band))
bool rtw_mlme_ignore_chan(_adapter *adapter, const u32 ch)
if (RTW_IS_SCAN_BAND_SKIP(adapter, BAND_24G) && ch < 35) /* SKIP 2.4G Band channel */
if (RTW_IS_SCAN_BAND_SKIP(adapter, BAND_5G) && ch > 35) /* SKIP 5G Band channel */
/****************************************************************************
Following are the initialization functions for WiFi MLME
int init_hw_mlme_ext(_adapter *padapter)
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
u8 rx_bar_enble = _TRUE;
* Sync driver status and hardware setting
/* Modify to make sure first time change channel(band) would be done properly */
pHalData->current_channel = 0;
pHalData->current_channel_bw = CHANNEL_WIDTH_MAX;
#if CONFIG_IEEE80211_BAND_5GHZ
pHalData->current_band_type = BAND_MAX;
pHalData->current_band_type = BAND_ON_2_4G;
/* set_opmode_cmd(padapter, infra_client_with_mlme); */ /* removed */
rtw_hal_set_hwreg(padapter, HW_VAR_ENABLE_RX_BAR, &rx_bar_enble);
set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
return _SUCCESS;
void init_mlme_default_rate_set(_adapter *padapter)
unsigned char end_set[1] = {0xff};
u8 offset_datarate = 0;
u8 offset_basicrate = 0;
#ifdef CONFIG_80211N_HT
unsigned char supported_mcs_set[16] = {0xff, 0xff, 0xff, 0xff, 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
if (IsSupportedTxCCK(padapter->registrypriv.wireless_mode)) {
unsigned char datarate_b[B_MODE_RATE_NUM] ={_1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_};
_rtw_memcpy(pmlmeext->datarate, datarate_b, B_MODE_RATE_NUM);
_rtw_memcpy(pmlmeext->basicrate, datarate_b, B_MODE_RATE_NUM);
offset_datarate += B_MODE_RATE_NUM;
offset_basicrate += B_MODE_RATE_NUM;
RTW_INFO("%s: support CCK\n", __func__);
if(IsSupportedTxOFDM(padapter->registrypriv.wireless_mode)) {
unsigned char datarate_g[G_MODE_RATE_NUM] ={_6M_RATE_, _9M_RATE_, _12M_RATE_, _18M_RATE_,_24M_RATE_, _36M_RATE_, _48M_RATE_, _54M_RATE_};
unsigned char basicrate_g[G_MODE_BASIC_RATE_NUM] = {_6M_RATE_, _12M_RATE_, _24M_RATE_};
_rtw_memcpy(pmlmeext->datarate + offset_datarate, datarate_g, G_MODE_RATE_NUM);
_rtw_memcpy(pmlmeext->basicrate + offset_basicrate,basicrate_g, G_MODE_BASIC_RATE_NUM);
offset_datarate += G_MODE_RATE_NUM;
offset_basicrate += G_MODE_BASIC_RATE_NUM;
RTW_INFO("%s: support OFDM\n", __func__);
_rtw_memcpy(pmlmeext->datarate + offset_datarate, end_set, 1);
_rtw_memcpy(pmlmeext->basicrate + offset_basicrate, end_set, 1);
if( padapter->registrypriv.ht_enable && is_supported_ht(padapter->registrypriv.wireless_mode))
_rtw_memcpy(pmlmeext->default_supported_mcs_set, supported_mcs_set, sizeof(pmlmeext->default_supported_mcs_set));
static void init_mlme_ext_priv_value(_adapter *padapter)
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
ATOMIC_SET(&pmlmeext->event_seq, 0);
pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */
pmlmeext->sa_query_seq = 0;
pmlmeext->cur_channel = padapter->registrypriv.channel;
pmlmeext->cur_bwmode = CHANNEL_WIDTH_20;
pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
pmlmeext->retry = 0;
pmlmeext->cur_wireless_mode = padapter->registrypriv.wireless_mode;
init_mlme_default_rate_set(padapter);
if ((pmlmeext->cur_channel > 14) || ((padapter->registrypriv.wireless_mode & WIRELESS_11B) == 0))
pmlmeext->tx_rate = IEEE80211_OFDM_RATE_6MB;
pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB;
mlmeext_set_scan_state(pmlmeext, SCAN_DISABLE);
pmlmeext->sitesurvey_res.channel_idx = 0;
pmlmeext->sitesurvey_res.bss_cnt = 0;
pmlmeext->sitesurvey_res.scan_ch_ms = SURVEY_TO;
pmlmeext->sitesurvey_res.rx_ampdu_accept = RX_AMPDU_ACCEPT_INVALID;
pmlmeext->sitesurvey_res.rx_ampdu_size = RX_AMPDU_SIZE_INVALID;
#ifdef CONFIG_SCAN_BACKOP
mlmeext_assign_scan_backop_flags_sta(pmlmeext, SS_BACKOP_EN | SS_BACKOP_PS_ANNC | SS_BACKOP_TX_RESUME);
#ifdef CONFIG_AP_MODE
#ifdef CONFIG_CUSTOMER_EZVIZ_CHIME2
mlmeext_assign_scan_backop_flags_ap(pmlmeext, SS_BACKOP_EN | SS_BACKOP_PS_ANNC | SS_BACKOP_TX_RESUME | SS_BACKOP_EN_NL);
mlmeext_assign_scan_backop_flags_ap(pmlmeext, SS_BACKOP_EN | SS_BACKOP_PS_ANNC | SS_BACKOP_TX_RESUME);
mlmeext_assign_scan_backop_flags_mesh(pmlmeext, /*SS_BACKOP_EN | */SS_BACKOP_PS_ANNC | SS_BACKOP_TX_RESUME);
pmlmeext->sitesurvey_res.scan_cnt = 0;
pmlmeext->sitesurvey_res.scan_cnt_max = RTW_SCAN_NUM_OF_CH;
pmlmeext->sitesurvey_res.backop_ms = RTW_BACK_OP_CH_MS;
#if defined(CONFIG_ANTENNA_DIVERSITY) || defined(DBG_SCAN_SW_ANTDIV_BL)
pmlmeext->sitesurvey_res.is_sw_antdiv_bl_scan = 0;
pmlmeext->scan_abort = _FALSE;
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;
pmlmeinfo->enc_algo = _NO_PRIVACY_;
pmlmeinfo->authModeToggle = 0;
_rtw_memset(pmlmeinfo->chg_txt, 0, 128);
pmlmeinfo->slotTime = SHORT_SLOT_TIME;
pmlmeinfo->preamble_mode = PREAMBLE_AUTO;
pmlmeinfo->dialogToken = 0;
pmlmeext->action_public_rxseq = 0xffff;
pmlmeext->action_public_dialog_token = 0xff;
#ifdef ROKU_PRIVATE
/*infra mode, used to store AP's info*/
_rtw_memset(pmlmeinfo->SupportedRates_infra_ap, 0, NDIS_802_11_LENGTH_RATES_EX);
pmlmeinfo->ht_vht_received = 0;
#endif /* ROKU_PRIVATE */
#ifdef CONFIG_WRITE_BCN_LEN_TO_FW
pmlmeinfo->last_bcn_len = 0;
void init_mlme_ext_timer(_adapter *padapter)
rtw_init_timer(&pmlmeext->survey_timer, padapter, survey_timer_hdl, padapter);
rtw_init_timer(&pmlmeext->link_timer, padapter, link_timer_hdl, padapter);
#ifdef CONFIG_RTW_80211R
rtw_init_timer(&pmlmeext->ft_link_timer, padapter, rtw_ft_link_timer_hdl, padapter);
rtw_init_timer(&pmlmeext->ft_roam_timer, padapter, rtw_ft_roam_timer_hdl, padapter);
#ifdef CONFIG_RTW_REPEATER_SON
rtw_init_timer(&pmlmeext->rson_scan_timer, padapter, rson_timer_hdl, padapter);
rtw_init_timer(&pmlmeext->tbtx_xmit_timer, padapter, rtw_tbtx_xmit_timer_hdl, padapter);
rtw_init_timer(&pmlmeext->tbtx_token_dispatch_timer, padapter, rtw_tbtx_token_dispatch_timer_hdl, padapter);
#ifdef CONFIG_DFS
rtw_init_timer(&pmlmeext->csa_timer, padapter->pnetdev, csa_timer_hdl, padapter);
int init_mlme_ext_priv(_adapter *padapter)
int res = _SUCCESS;
struct registry_priv *pregistrypriv = &padapter->registrypriv;
/* We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */
/* _rtw_memset((u8 *)pmlmeext, 0, sizeof(struct mlme_ext_priv)); */
pmlmeext->padapter = padapter;
/* fill_fwpriv(padapter, &(pmlmeext->fwpriv)); */
init_mlme_ext_priv_value(padapter);
pmlmeinfo->bAcceptAddbaReq = pregistrypriv->bAcceptAddbaReq;
init_mlme_ext_timer(padapter);
init_mlme_ap_info(padapter);
pmlmeext->last_scan_time = 0;
pmlmeext->mlmeext_init = _TRUE;
#ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK
pmlmeext->active_keep_alive_check = _TRUE;
pmlmeext->active_keep_alive_check = _FALSE;
#ifdef DBG_FIXED_CHAN
pmlmeext->fixed_chan = 0xFF;
pmlmeext->tsf_update_pause_factor = pregistrypriv->tsf_update_pause_factor;
pmlmeext->tsf_update_restore_factor = pregistrypriv->tsf_update_restore_factor;
#ifdef CONFIG_SUPPORT_STATIC_SMPS
pmlmeext->ssmps_en = _FALSE;
pmlmeext->ssmps_tx_tp_th = SSMPS_TX_TP_TH;/*Mbps*/
pmlmeext->ssmps_rx_tp_th = SSMPS_RX_TP_TH;/*Mbps*/
#ifdef DBG_STATIC_SMPS
pmlmeext->ssmps_test = _FALSE;
#ifdef CONFIG_CTRL_TXSS_BY_TP
pmlmeext->txss_ctrl_en = _TRUE;
pmlmeext->txss_tp_th = TXSS_TP_TH;
pmlmeext->txss_tp_chk_cnt = TXSS_TP_CHK_CNT;
return res;
void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext)
_adapter *padapter = pmlmeext->padapter;
if (!padapter)
if (rtw_is_drv_stopped(padapter)) {
_cancel_timer_ex(&pmlmeext->survey_timer);
_cancel_timer_ex(&pmlmeext->link_timer);
_cancel_timer_ex(&pmlmeext->csa_timer);
#endif /* CONFIG_DFS */
#ifdef CONFIG_PATCH_JOIN_WRONG_CHANNEL
static u8 cmp_pkt_chnl_diff(_adapter *padapter, u8 *pframe, uint packet_len)
/* if the channel is same, return 0. else return channel differential */
uint len;
u8 channel;
u8 *p;
p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_, _DSSET_IE_, &len, packet_len - _BEACON_IE_OFFSET_);
if (p) {
channel = *(p + 2);
if (padapter->mlmeextpriv.cur_channel >= channel)
return padapter->mlmeextpriv.cur_channel - channel;
return channel - padapter->mlmeextpriv.cur_channel;
} else
return 0;
#endif /* CONFIG_PATCH_JOIN_WRONG_CHANNEL */
static void _mgt_dispatcher(_adapter *padapter, struct mlme_handler *ptable, union recv_frame *precv_frame)
u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
u8 *pframe = precv_frame->u.hdr.rx_data;
if (ptable->func) {
/* receive the frames that ra(a1) is my address or ra(a1) is bc address. */
if (!_rtw_memcmp(GetAddr1Ptr(pframe), adapter_mac_addr(padapter), ETH_ALEN) &&
!_rtw_memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN))
#if defined(CONFIG_RTW_CFGVENDOR_RANDOM_MAC_OUI) || defined(CONFIG_RTW_SCAN_RAND)
struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(padapter);
if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE) != _TRUE)
if (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE) == _TRUE)
if ( pwdev_priv->pno_mac_addr[0] == 0xFF)
if (!_rtw_memcmp(GetAddr1Ptr(pframe), adapter_pno_mac_addr(padapter), ETH_ALEN))
ptable->func(padapter, precv_frame);
void mgt_dispatcher(_adapter *padapter, union recv_frame *precv_frame)
int index;
struct mlme_handler *ptable;
struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, get_addr2_ptr(pframe));
struct recv_priv *precvpriv = &padapter->recvpriv;
#if 0
u8 *pbuf;
pbuf = GetAddr1Ptr(pframe);
RTW_INFO("A1-%x:%x:%x:%x:%x:%x\n", *pbuf, *(pbuf + 1), *(pbuf + 2), *(pbuf + 3), *(pbuf + 4), *(pbuf + 5));
pbuf = get_addr2_ptr(pframe);
RTW_INFO("A2-%x:%x:%x:%x:%x:%x\n", *pbuf, *(pbuf + 1), *(pbuf + 2), *(pbuf + 3), *(pbuf + 4), *(pbuf + 5));
pbuf = GetAddr3Ptr(pframe);
RTW_INFO("A3-%x:%x:%x:%x:%x:%x\n", *pbuf, *(pbuf + 1), *(pbuf + 2), *(pbuf + 3), *(pbuf + 4), *(pbuf + 5));
if (GetFrameType(pframe) != WIFI_MGT_TYPE) {
ptable = mlme_sta_tbl;
index = get_frame_sub_type(pframe) >> 4;
#ifdef CONFIG_TDLS
if ((index << 4) == WIFI_ACTION) {
/* category==public (4), action==TDLS_DISCOVERY_RESPONSE */
if (*(pframe + 24) == RTW_WLAN_CATEGORY_PUBLIC && *(pframe + 25) == TDLS_DISCOVERY_RESPONSE) {
RTW_INFO("[TDLS] Recv %s from "MAC_FMT"\n", rtw_tdls_action_txt(TDLS_DISCOVERY_RESPONSE), MAC_ARG(get_addr2_ptr(pframe)));
On_TDLS_Dis_Rsp(padapter, precv_frame);
#endif /* CONFIG_TDLS */
if (index >= (sizeof(mlme_sta_tbl) / sizeof(struct mlme_handler))) {
ptable += index;
#if 1
if (psta != NULL) {
if (GetRetry(pframe)) {
if (precv_frame->u.hdr.attrib.seq_num == psta->RxMgmtFrameSeqNum) {
/* drop the duplicate management frame */
precvpriv->dbg_rx_dup_mgt_frame_drop_count++;
RTW_INFO("Drop duplicate management frame with seq_num = %d.\n", precv_frame->u.hdr.attrib.seq_num);
psta->RxMgmtFrameSeqNum = precv_frame->u.hdr.attrib.seq_num;
/* return; */
switch (get_frame_sub_type(pframe)) {
case WIFI_AUTH:
if (MLME_IS_AP(padapter) || MLME_IS_MESH(padapter))
ptable->func = &OnAuth;
ptable->func = &OnAuthClient;
case WIFI_ASSOCREQ:
case WIFI_REASSOCREQ:
_mgt_dispatcher(padapter, ptable, precv_frame);
#ifdef CONFIG_HOSTAPD_MLME
if (MLME_IS_AP(padapter))
rtw_hostapd_mlme_rx(padapter, precv_frame);
case WIFI_PROBEREQ:
case WIFI_BEACON:
case WIFI_ACTION:
#ifdef CONFIG_P2P
u32 p2p_listen_state_process(_adapter *padapter, unsigned char *da)
bool response = _TRUE;
#ifdef CONFIG_IOCTL_CFG80211
if (padapter->wdinfo.driver_interface == DRIVER_CFG80211) {
if (rtw_cfg80211_get_is_roch(padapter) == _FALSE
|| rtw_get_oper_ch(padapter) != padapter->wdinfo.listen_channel
|| adapter_wdev_data(padapter)->p2p_enabled == _FALSE
|| padapter->mlmepriv.wps_probe_resp_ie == NULL
|| padapter->mlmepriv.p2p_probe_resp_ie == NULL
#ifdef CONFIG_DEBUG_CFG80211
RTW_INFO(ADPT_FMT" DON'T issue_probersp_p2p: p2p_enabled:%d, wps_probe_resp_ie:%p, p2p_probe_resp_ie:%p\n"
, ADPT_ARG(padapter)
, adapter_wdev_data(padapter)->p2p_enabled
, padapter->mlmepriv.wps_probe_resp_ie
, padapter->mlmepriv.p2p_probe_resp_ie);
RTW_INFO(ADPT_FMT" DON'T issue_probersp_p2p: is_ro_ch:%d, op_ch:%d, p2p_listen_channel:%d\n"
, rtw_cfg80211_get_is_roch(padapter)
, rtw_get_oper_ch(padapter)
, padapter->wdinfo.listen_channel);
response = _FALSE;
#endif /* CONFIG_IOCTL_CFG80211 */
if (padapter->wdinfo.driver_interface == DRIVER_WEXT) {
/* do nothing if the device name is empty */
if (!padapter->wdinfo.device_name_len)
if (response == _TRUE)
issue_probersp_p2p(padapter, da);
#endif /* CONFIG_P2P */
Following are the callback functions for each subtype of the management frames
unsigned int OnProbeReq(_adapter *padapter, union recv_frame *precv_frame)
unsigned int ielen;
unsigned char *p;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
WLAN_BSSID_EX *cur = &(pmlmeinfo->network);
uint len = precv_frame->u.hdr.len;
u8 is_valid_p2p_probereq = _FALSE;
#ifdef CONFIG_ATMEL_RC_PATCH
u8 *target_ie = NULL, *wps_ie = NULL;
u8 *start;
uint search_len = 0, wps_ielen = 0, target_ielen = 0;
struct sta_info *psta;
struct sta_priv *pstapriv = &padapter->stapriv;
struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
u8 wifi_test_chk_rate = 1;
if ((pwdinfo->driver_interface == DRIVER_CFG80211)
&& !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)
&& (GET_CFG80211_REPORT_MGMT(adapter_wdev_data(padapter), IEEE80211_STYPE_PROBE_REQ) == _TRUE)
rtw_cfg80211_rx_probe_request(padapter, precv_frame);
if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) &&
!rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE) &&
!rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) &&
!rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH) &&
!rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN)
/* Commented by Albert 2011/03/17 */
/* mcs_rate = 0->CCK 1M rate */
/* mcs_rate = 1->CCK 2M rate */
/* mcs_rate = 2->CCK 5.5M rate */
/* mcs_rate = 3->CCK 11M rate */
/* In the P2P mode, the driver should not support the CCK rate */
/* Commented by Kurt 2012/10/16 */
/* IOT issue: Google Nexus7 use 1M rate to send p2p_probe_req after GO nego completed and Nexus7 is client */
if (padapter->registrypriv.wifi_spec == 1) {
if (pattrib->data_rate <= DESC_RATE11M)
wifi_test_chk_rate = 0;
if (wifi_test_chk_rate == 1) {
is_valid_p2p_probereq = process_probe_req_p2p_ie(pwdinfo, pframe, len);
if (is_valid_p2p_probereq == _TRUE) {
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) {
/* FIXME */
if (padapter->wdinfo.driver_interface == DRIVER_WEXT)
report_survey_event(padapter, precv_frame);
p2p_listen_state_process(padapter, get_sa(pframe));
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
goto _continue;
_continue:
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE) == _FALSE &&
check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE | WIFI_AP_STATE | WIFI_MESH_STATE) == _FALSE)
/* RTW_INFO("+OnProbeReq\n"); */
wps_ie = rtw_get_wps_ie(
pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_,
len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_,
NULL, &wps_ielen);
if (wps_ie)
target_ie = rtw_get_wps_attr_content(wps_ie, wps_ielen, WPS_ATTR_MANUFACTURER, NULL, &target_ielen);
if ((target_ie && (target_ielen == 4)) && (_TRUE == _rtw_memcmp((void *)target_ie, "Ozmo", 4))) {
/* psta->flag_atmel_rc = 1; */
unsigned char *sa_addr = get_sa(pframe);
printk("%s: Find Ozmo RC -- %02x:%02x:%02x:%02x:%02x:%02x \n\n",
__func__, *sa_addr, *(sa_addr + 1), *(sa_addr + 2), *(sa_addr + 3), *(sa_addr + 4), *(sa_addr + 5));
_rtw_memcpy(pstapriv->atmel_rc_pattern, get_sa(pframe), ETH_ALEN);
#ifdef CONFIG_AUTO_AP_MODE
if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE) == _TRUE &&
pmlmepriv->cur_network.join_res == _TRUE) {
u8 *mac_addr, *peer_addr;
u8 RC_OUI[4] = {0x00, 0xE0, 0x4C, 0x0A};
/* EID[1] + EID_LEN[1] + RC_OUI[4] + MAC[6] + PairingID[2] + ChannelNum[2] */
p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, (int *)&ielen,
len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_);
if (!p || ielen != 14)
goto _non_rc_device;
if (!_rtw_memcmp(p + 2, RC_OUI, sizeof(RC_OUI)))
if (!_rtw_memcmp(p + 6, get_sa(pframe), ETH_ALEN)) {
RTW_INFO("%s, do rc pairing ("MAC_FMT"), but mac addr mismatch!("MAC_FMT")\n", __FUNCTION__,
MAC_ARG(get_sa(pframe)), MAC_ARG(p + 6));
RTW_INFO("%s, got the pairing device("MAC_FMT")\n", __FUNCTION__, MAC_ARG(get_sa(pframe)));
/* new a station */
psta = rtw_get_stainfo(pstapriv, get_sa(pframe));
if (psta == NULL) {
/* allocate a new one */
RTW_INFO("going to alloc stainfo for rc="MAC_FMT"\n", MAC_ARG(get_sa(pframe)));
psta = rtw_alloc_stainfo(pstapriv, get_sa(pframe));
/* TODO: */
RTW_INFO(" Exceed the upper limit of supported clients...\n");
_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
if (rtw_is_list_empty(&psta->asoc_list)) {
psta->expire_to = pstapriv->expire_to;
rtw_list_insert_tail(&psta->asoc_list, &pstapriv->asoc_list);
pstapriv->asoc_list_cnt++;
if (psta->tbtx_enable)
pstapriv->tbtx_asoc_list_cnt++;
_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
/* generate pairing ID */
mac_addr = adapter_mac_addr(padapter);
peer_addr = psta->cmn.mac_addr;
psta->pid = (u16)(((mac_addr[4] << 8) + mac_addr[5]) + ((peer_addr[4] << 8) + peer_addr[5]));
/* update peer stainfo */
psta->isrc = _TRUE;
/* AID assignment */
if (psta->cmn.aid > 0)
RTW_INFO(FUNC_ADPT_FMT" old AID=%d\n", FUNC_ADPT_ARG(padapter), psta->cmn.aid);
if (!rtw_aid_alloc(padapter, psta)) {
RTW_INFO(FUNC_ADPT_FMT" no room for more AIDs\n", FUNC_ADPT_ARG(padapter));
RTW_INFO(FUNC_ADPT_FMT" allocate new AID=%d\n", FUNC_ADPT_ARG(padapter), psta->cmn.aid);
psta->qos_option = 1;
psta->cmn.bw_mode = CHANNEL_WIDTH_20;
psta->ieee8021x_blocked = _FALSE;
if(padapter->registrypriv.ht_enable &&
is_supported_ht(padapter->registrypriv.wireless_mode)) {
psta->htpriv.ht_option = _TRUE;
psta->htpriv.ampdu_enable = _FALSE;
psta->htpriv.sgi_20m = _FALSE;
psta->htpriv.sgi_40m = _FALSE;
psta->htpriv.ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
psta->htpriv.agg_enable_bitmap = 0x0;/* reset */
psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */
rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, _TRUE);
_rtw_memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
_enter_critical_bh(&psta->lock, &irqL);
psta->state |= WIFI_ASOC_STATE;
_exit_critical_bh(&psta->lock, &irqL);
report_add_sta_event(padapter, psta->cmn.mac_addr);
issue_probersp(padapter, get_sa(pframe), _FALSE);
_non_rc_device:
#endif /* CONFIG_AUTO_AP_MODE */
#ifdef CONFIG_CONCURRENT_MODE
if (((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) &&
rtw_mi_buddy_check_fwstate(padapter, WIFI_UNDER_LINKING | WIFI_UNDER_SURVEY)) {
/* don't process probe req */
p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ielen,
/* check (wildcard) SSID */
if (p != NULL) {
if (is_valid_p2p_probereq == _TRUE)
goto _issue_probersp;
if ((ielen != 0 && _FALSE == _rtw_memcmp((void *)(p + 2), (void *)cur->Ssid.Ssid, cur->Ssid.SsidLength))
|| (ielen == 0 && pmlmeinfo->hidden_ssid_mode))
if (MLME_IS_MESH(padapter)) {
p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, WLAN_EID_MESH_ID, (int *)&ielen,
if (!p)
if (ielen != 0 && _rtw_memcmp((void *)(p + 2), (void *)cur->mesh_id.Ssid, cur->mesh_id.SsidLength) == _FALSE)
_issue_probersp:
if (((check_fwstate(pmlmepriv, WIFI_ASOC_STATE) == _TRUE &&
pmlmepriv->cur_network.join_res == _TRUE)) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
/* RTW_INFO("+issue_probersp during ap mode\n"); */
issue_probersp(padapter, get_sa(pframe), is_valid_p2p_probereq);
unsigned int OnProbeRsp(_adapter *padapter, union recv_frame *precv_frame)
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) {
if (_TRUE == pwdinfo->tx_prov_disc_info.benable) {
if (_rtw_memcmp(pwdinfo->tx_prov_disc_info.peerIFAddr, get_addr2_ptr(pframe), ETH_ALEN)) {
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
pwdinfo->tx_prov_disc_info.benable = _FALSE;
issue_p2p_provision_request(padapter,
pwdinfo->tx_prov_disc_info.ssid.Ssid,
pwdinfo->tx_prov_disc_info.ssid.SsidLength,
pwdinfo->tx_prov_disc_info.peerDevAddr);
} else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
NULL,
0,
} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) {
if (_TRUE == pwdinfo->nego_req_info.benable) {
RTW_INFO("[%s] P2P State is GONEGO ING!\n", __FUNCTION__);
if (_rtw_memcmp(pwdinfo->nego_req_info.peerDevAddr, get_addr2_ptr(pframe), ETH_ALEN)) {
pwdinfo->nego_req_info.benable = _FALSE;
issue_p2p_GO_request(padapter, pwdinfo->nego_req_info.peerDevAddr);
} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) {
if (_TRUE == pwdinfo->invitereq_info.benable) {
RTW_INFO("[%s] P2P_STATE_TX_INVITE_REQ!\n", __FUNCTION__);
if (_rtw_memcmp(pwdinfo->invitereq_info.peer_macaddr, get_addr2_ptr(pframe), ETH_ALEN)) {
pwdinfo->invitereq_info.benable = _FALSE;
issue_p2p_invitation_request(padapter, pwdinfo->invitereq_info.peer_macaddr);
if ((mlmeext_chk_scan_state(pmlmeext, SCAN_PROCESS))
|| (MLME_IS_MESH(padapter) && check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE))
|| (padapter->rtw_rson_scanstage == RSON_SCAN_PROCESS)
if (_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)
&& (pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE && (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)
if (!rtw_check_bcn_info(padapter, pframe, precv_frame->u.hdr.len)) {
RTW_PRINT(FUNC_ADPT_FMT" ap has changed, disconnect now\n", FUNC_ADPT_ARG(padapter));
receive_disconnect(padapter, pmlmeinfo->network.MacAddress , 0, _FALSE);
rtw_mi_report_survey_event(padapter, precv_frame);
#if 0 /* move to validate_recv_mgnt_frame */
if (_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) {
if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) {
psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe));
if (psta != NULL)
psta->sta_stats.rx_mgnt_pkts++;
/* for 11n Logo 4.2.31/4.2.32 */
static void rtw_check_legacy_ap(_adapter *padapter, u8 *pframe, u32 len)
if (!padapter->registrypriv.wifi_spec)
if(!MLME_IS_AP(padapter))
if (pmlmeext->bstart_bss == _TRUE) {
int left;
unsigned char *pos;
struct rtw_ieee802_11_elems elems;
u16 cur_op_mode;
/* checking IEs */
left = len - sizeof(struct rtw_ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_;
pos = pframe + sizeof(struct rtw_ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_;
if (rtw_ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) {
RTW_INFO("%s: parse fail for "MAC_FMT"\n", __func__, MAC_ARG(GetAddr3Ptr(pframe)));
cur_op_mode = pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
/* for legacy ap */
if (elems.ht_capabilities == NULL && elems.ht_capabilities_len == 0) {
RTW_INFO("%s: "MAC_FMT" is legacy ap\n", __func__, MAC_ARG(GetAddr3Ptr(pframe)));
ATOMIC_SET(&pmlmepriv->olbc, _TRUE);
ATOMIC_SET(&pmlmepriv->olbc_ht, _TRUE);
#endif /* CONFIG_AP_MODE */
unsigned int OnBeacon(_adapter *padapter, union recv_frame *precv_frame)
WLAN_BSSID_EX *pbss;
int ret = _SUCCESS;
struct sta_info *ptdls_sta;
struct tdls_info *ptdlsinfo = &padapter->tdlsinfo;
#ifdef CONFIG_TDLS_CH_SW
struct tdls_ch_switch *pchsw_info = &padapter->tdlsinfo.chsw_info;
if (validate_beacon_len(pframe, len) == _FALSE)
if (mlmeext_chk_scan_state(pmlmeext, SCAN_PROCESS)
|| (MLME_IS_MESH(padapter) && check_fwstate(pmlmepriv, WIFI_ASOC_STATE))
if (!rtw_check_bcn_info(padapter, pframe, len)) {
if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE)
&& (_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN))) {
if (pmlmeinfo->last_bcn_len != pattrib->pkt_len) {
pmlmeinfo->last_bcn_len = pattrib->pkt_len;
rtw_write_bcnlen_to_fw_cmd(padapter, pattrib->pkt_len);
if (padapter->rtw_rson_scanstage == RSON_SCAN_PROCESS)
rtw_check_legacy_ap(padapter, pframe, len);
if ((pmlmeinfo->state & WIFI_FW_AUTH_NULL)
&& (rtw_sta_linking_test_wait_done() || pmlmeext->join_abort)
if (rtw_sta_linking_test_force_fail() || pmlmeext->join_abort) {
set_link_timer(pmlmeext, 1);
/* we should update current network before auth, or some IE is wrong */
pbss = (WLAN_BSSID_EX *)rtw_malloc(sizeof(WLAN_BSSID_EX));
if (pbss) {
if (collect_bss_info(padapter, precv_frame, pbss) == _SUCCESS) {
struct beacon_keys recv_beacon;
update_network(&(pmlmepriv->cur_network.network), pbss, padapter, _TRUE);
/* update bcn keys */
if (rtw_get_bcn_keys(padapter, pframe, len, &recv_beacon) == _TRUE) {
RTW_INFO("%s: beacon keys ready\n", __func__);
_rtw_memcpy(&pmlmepriv->cur_beacon_keys,
&recv_beacon, sizeof(recv_beacon));
if (is_hidden_ssid(recv_beacon.ssid, recv_beacon.ssid_len)) {
_rtw_memcpy(pmlmepriv->cur_beacon_keys.ssid, pmlmeinfo->network.Ssid.Ssid, IW_ESSID_MAX_SIZE);
pmlmepriv->cur_beacon_keys.ssid_len = pmlmeinfo->network.Ssid.SsidLength;
RTW_ERR("%s: get beacon keys failed\n", __func__);
_rtw_memset(&pmlmepriv->cur_beacon_keys, 0, sizeof(recv_beacon));
#ifdef CONFIG_BCN_CNT_CONFIRM_HDL
pmlmepriv->new_beacon_cnts = 0;
rtw_mfree((u8 *)pbss, sizeof(WLAN_BSSID_EX));
/* 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));
/* update TSF Value */
update_TSF(pmlmeext, pframe, len);
pmlmeext->bcn_cnt = 0;
pmlmeext->last_bcn_cnt = 0;
#ifdef CONFIG_P2P_PS
/* Comment by YiWei , in wifi p2p spec the "3.3 P2P Power Management" , "These mechanisms are available in a P2P Group in which only P2P Devices are associated." */
/* process_p2p_ps_ie(padapter, (pframe + WLAN_HDR_A3_LEN), (len - WLAN_HDR_A3_LEN)); */
#endif /* CONFIG_P2P_PS */
#if defined(CONFIG_P2P) && defined(CONFIG_CONCURRENT_MODE)
if (padapter->registrypriv.wifi_spec) {
if (process_p2p_cross_connect_ie(padapter, (pframe + WLAN_HDR_A3_LEN), (len - WLAN_HDR_A3_LEN)) == _FALSE) {
if (rtw_mi_buddy_check_mlmeinfo_state(padapter, WIFI_FW_AP_STATE)) {
RTW_PRINT("no issue auth, P2P cross-connect does not permit\n ");
#endif /* CONFIG_P2P CONFIG_P2P and CONFIG_CONCURRENT_MODE */
/* start auth */
start_clnt_auth(padapter);
if (((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) && (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) {
/* Merge from 8712 FW code */
if (cmp_pkt_chnl_diff(padapter, pframe, len) != 0) {
/* join wrong channel, deauth and reconnect */
issue_deauth(padapter, (&(pmlmeinfo->network))->MacAddress, WLAN_REASON_DEAUTH_LEAVING);
report_del_sta_event(padapter, (&(pmlmeinfo->network))->MacAddress, WLAN_REASON_JOIN_WRONG_CHANNEL, _TRUE, _FALSE);
pmlmeinfo->state &= (~WIFI_FW_ASSOC_SUCCESS);
rtw_ft_update_bcn(padapter, precv_frame);
ret = rtw_check_bcn_info(padapter, pframe, len);
if (!ret) {
/* 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) {
/* RTW_INFO("update_bcn_info\n"); */
update_beacon_info(padapter, pframe, len, psta);
pmlmepriv->cur_network_scanned->network.Rssi = precv_frame->u.hdr.attrib.phy_info.recv_signal_power;
pmlmeext->bcn_cnt++;
#ifdef CONFIG_BCN_RECV_TIME
rtw_rx_bcn_time_update(padapter, len, precv_frame->u.hdr.attrib.data_rate);
if (rtw_tdls_is_chsw_allowed(padapter) == _TRUE) {
/* Send TDLS Channel Switch Request when receiving Beacon */
if ((padapter->tdlsinfo.chsw_info.ch_sw_state & TDLS_CH_SW_INITIATOR_STATE) && (ATOMIC_READ(&pchsw_info->chsw_on) == _TRUE)
&& (pmlmeext->cur_channel == rtw_get_oper_ch(padapter))) {
ptdls_sta = rtw_get_stainfo(&padapter->stapriv, padapter->tdlsinfo.chsw_info.addr);
if (ptdls_sta != NULL) {
if (ptdls_sta->tdls_sta_state | TDLS_LINKED_STATE)
_set_timer(&ptdls_sta->stay_on_base_chnl_timer, TDLS_CH_SW_STAY_ON_BASE_CHNL_TIMEOUT);
#if CONFIG_DFS
process_csa_ie(padapter
, pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_
, len - (WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_));
process_p2p_ps_ie(padapter, (pframe + WLAN_HDR_A3_LEN), (len - WLAN_HDR_A3_LEN));
if (pmlmeext->tsf_update_required && pmlmeext->en_hw_update_tsf)
rtw_enable_hw_update_tsf_cmd(padapter);
} else if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) {
u8 rate_set[16];
u8 rate_num = 0;
* 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)
rtw_ies_get_supported_rate(pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_, len - WLAN_HDR_A3_LEN - _BEACON_IE_OFFSET_, rate_set, &rate_num);
if (rate_num == 0) {
RTW_INFO(FUNC_ADPT_FMT" RX beacon with no supported rate\n", FUNC_ADPT_ARG(padapter));
goto _END_ONBEACON_;
psta = rtw_alloc_stainfo(pstapriv, get_addr2_ptr(pframe));
RTW_INFO(FUNC_ADPT_FMT" Exceed the upper limit of supported clients\n", FUNC_ADPT_ARG(padapter));
psta->expire_to = pstapriv->adhoc_expire_to;
_rtw_memcpy(psta->bssrateset, rate_set, rate_num);
psta->bssratelen = rate_num;
/* report sta add event */
report_add_sta_event(padapter, get_addr2_ptr(pframe));
_END_ONBEACON_:
static u32 rtw_get_sta_num_by_state(_adapter *padapter, u32 state)
_list *plist, *phead;
u32 index, sta_num = 0;
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &(padapter->stapriv);
_enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
for (index = 0; index < NUM_STA; index++) {
phead = &(pstapriv->sta_hash[index]);
plist = get_next(phead);
while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
psta = LIST_CONTAINOR(plist, struct sta_info , hash_list);
if ((psta->state & (state)))
sta_num++;
plist = get_next(plist);
_exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
/* RTW_INFO("%s : waiting for %u sta under linking \n", __func__, sta_num); */
return sta_num;
static u8 rtw_defs_attack_chk(_adapter *padapter)
struct mlme_priv *mlme = &(padapter->mlmepriv);
u8 is_reject = _FALSE;
u32 sta_limit = 0;
u32 stime = rtw_systime_to_ms(rtw_get_current_time());
static u32 ptime = 0;
/* RTW_INFO("%s : ptime=%u, stime=%u, diff=%u\n", __func__, ptime, stime, (stime - ptime)); */
if ((ptime > 0) && ((stime - ptime) < mlme->defs_lmt_time)) {
sta_limit = rtw_get_sta_num_by_state(padapter, WIFI_FW_LINKING_STATE);
if (sta_limit >= mlme->defs_lmt_sta)
is_reject = _TRUE;
ptime = stime;
/* RTW_INFO("%s : current linking num=%u\n", __func__, sta_limit); */
return is_reject;
unsigned int OnAuth(_adapter *padapter, union recv_frame *precv_frame)
unsigned int auth_mode, seq, ie_len;
unsigned char *sa, *p;
u16 algorithm;
int status;
static struct sta_info stat;
struct sta_info *pstat = NULL;
struct security_priv *psecuritypriv = &padapter->securitypriv;
u8 offset = 0;
/* don't process auth request; */
#endif /* CONFIG_CONCURRENT_MODE */
if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)
return _FAIL;
if (!MLME_IS_ASOC(padapter))
#if defined(CONFIG_IOCTL_CFG80211) && defined(CONFIG_RTW_MESH)
if (MLME_IS_MESH(padapter))
return rtw_mesh_on_auth(padapter, precv_frame);
RTW_INFO("+OnAuth\n");
sa = get_addr2_ptr(pframe);
auth_mode = psecuritypriv->dot11AuthAlgrthm;
if (GetPrivacy(pframe)) {
u8 *iv;
struct rx_pkt_attrib *prxattrib = &(precv_frame->u.hdr.attrib);
prxattrib->hdrlen = WLAN_HDR_A3_LEN;
prxattrib->encrypt = _WEP40_;
iv = pframe + prxattrib->hdrlen;
prxattrib->key_index = ((iv[3] >> 6) & 0x3);
prxattrib->iv_len = 4;
prxattrib->icv_len = 4;
rtw_wep_decrypt(padapter, (u8 *)precv_frame);
offset = 4;
algorithm = le16_to_cpu(*(u16 *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset));
seq = le16_to_cpu(*(u16 *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 2));
RTW_INFO("auth alg=%x, seq=%X\n", algorithm, seq);
if (rtw_check_invalid_mac_address(sa, _FALSE)){
RTW_INFO("%s : reject invalid AUTH-req "MAC_FMT"\n",
__func__, MAC_ARG(get_addr2_ptr(pframe)));
if(rtw_defs_attack_chk(padapter)) {
struct sta_info *_psta;
_psta = rtw_get_stainfo(pstapriv, sa);
if ((_psta == NULL) || !(_psta->state & WIFI_FW_ASSOC_SUCCESS)) {
status = _STATS_REFUSED_TEMPORARILY_;
RTW_ERR("%s : refused temporarily for sa "MAC_FMT" !\n", __func__, MAC_ARG(sa));
goto auth_fail;
if (rtw_ap_linking_test_force_auth_fail()) {
status = rtw_ap_linking_test_force_auth_fail();
RTW_INFO(FUNC_ADPT_FMT" force auth fail with status:%u\n"
, FUNC_ADPT_ARG(padapter), status);
if ((auth_mode == 2) && (algorithm != WLAN_AUTH_SAE) &&
(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 */
RTW_INFO("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_;
#if CONFIG_RTW_MACADDR_ACL
if (rtw_access_ctrl(padapter, sa) == _FALSE) {
status = _STATS_UNABLE_HANDLE_STA_;
pstat = rtw_get_stainfo(pstapriv, sa);
if (pstat == NULL) {
RTW_INFO("going to alloc stainfo for sa="MAC_FMT"\n", MAC_ARG(sa));
pstat = rtw_alloc_stainfo(pstapriv, sa);
pstat->state = WIFI_FW_AUTH_NULL;
pstat->auth_seq = 0;
/* pstat->flags = 0; */
/* pstat->capability = 0; */
if ((pstat->bpairwise_key_installed != _TRUE && (pstat->flags & WLAN_STA_MFP))
|| !(pstat->flags & WLAN_STA_MFP))
if (rtw_is_list_empty(&pstat->asoc_list) == _FALSE) {
rtw_list_delete(&pstat->asoc_list);
pstapriv->asoc_list_cnt--;
if (pstat->tbtx_enable)
pstapriv->tbtx_asoc_list_cnt--;
if (pstat->expire_to > 0)
;/* TODO: STA re_auth within expire_to */
if (seq == 1)
; /* TODO: STA re_auth and auth timeout */
_enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
if (rtw_is_list_empty(&pstat->auth_list)) {
rtw_list_insert_tail(&pstat->auth_list, &pstapriv->auth_list);
pstapriv->auth_list_cnt++;
_exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
if (pstat->auth_seq == 0)
pstat->expire_to = pstapriv->auth_to;
if (GET_CFG80211_REPORT_MGMT(adapter_wdev_data(padapter), IEEE80211_STYPE_AUTH) == _TRUE) {
if ((algorithm == WLAN_AUTH_SAE) &&
(auth_mode == dot11AuthAlgrthm_8021X)) {
pstat->authalg = algorithm;
rtw_cfg80211_rx_mframe(padapter, precv_frame, NULL);
if ((pstat->auth_seq + 1) != seq) {
RTW_INFO("(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_;
if (algorithm == 0 && (auth_mode == 0 || auth_mode == 2 || auth_mode == 3)) {
if (seq == 1) {
pstat->state &= ~WIFI_FW_AUTH_NULL;
pstat->state |= WIFI_FW_AUTH_SUCCESS;
pstat->expire_to = pstapriv->assoc_to;
RTW_INFO("(2)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n",
} else { /* shared system or auto authentication */
/* prepare for the challenging txt... */
/* get_random_bytes((void *)pstat->chg_txt, 128); */ /* TODO: */
_rtw_memset((void *)pstat->chg_txt, 78, 128);
pstat->state |= WIFI_FW_AUTH_STATE;
pstat->auth_seq = 2;
} else if (seq == 3) {
/* checking for challenging txt... */
RTW_INFO("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)) {
RTW_INFO("auth rejected because challenge failure!(1)\n");
status = _STATS_CHALLENGE_FAIL_;
if (_rtw_memcmp((void *)(p + 2), pstat->chg_txt, 128)) {
pstat->state &= (~WIFI_FW_AUTH_STATE);
/* challenging txt is correct... */
RTW_INFO("auth rejected because challenge failure!\n");
RTW_INFO("(3)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n",
/* Now, we are going to issue_auth... */
pstat->auth_seq = seq + 1;
#ifdef CONFIG_NATIVEAP_MLME
issue_auth(padapter, pstat, (unsigned short)(_STATS_SUCCESSFUL_));
if ((pstat->state & WIFI_FW_AUTH_SUCCESS) || (pstat->state & WIFI_FW_ASSOC_SUCCESS))
auth_fail:
if (pstat)
rtw_free_stainfo(padapter , pstat);
pstat = &stat;
_rtw_memset((char *)pstat, '\0', sizeof(stat));
_rtw_memcpy(pstat->cmn.mac_addr, sa, ETH_ALEN);
issue_auth(padapter, pstat, (unsigned short)status);
unsigned int OnAuthClient(_adapter *padapter, union recv_frame *precv_frame)
unsigned int seq, len, status, algthm, offset;
unsigned int go2asoc = 0;
uint pkt_len = precv_frame->u.hdr.len;
RTW_INFO("%s\n", __FUNCTION__);
if (rtw_sec_chk_auth_type(padapter, MLME_AUTHTYPE_SAE)) {
if (rtw_cached_pmkid(padapter, get_my_bssid(&pmlmeinfo->network)) != -1) {
RTW_INFO("SAE: PMKSA cache entry found\n");
goto normal;
normal:
/* check A1 matches or not */
if (!_rtw_memcmp(adapter_mac_addr(padapter), get_da(pframe), ETH_ALEN))
if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE) || pmlmeext->join_abort)
offset = (GetPrivacy(pframe)) ? 4 : 0;
algthm = le16_to_cpu(*(unsigned short *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset));
seq = le16_to_cpu(*(unsigned short *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 2));
status = le16_to_cpu(*(unsigned short *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 4));
if (status != 0) {
RTW_INFO("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_Shared;
/* pmlmeinfo->reauth_count = 0; */
pmlmeinfo->auth_status = status;
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) {
/* RTW_INFO("marc: no challenge text?\n"); */
_rtw_memcpy((void *)(pmlmeinfo->chg_txt), (void *)(p + 2), len);
pmlmeinfo->auth_seq = 3;
issue_auth(padapter, NULL, 0);
set_link_timer(pmlmeext, REAUTH_TO);
/* open, or 802.11r FTAA system */
go2asoc = 1;
} else if (seq == 4) {
/* this is also illegal */
/* RTW_INFO("marc: clnt auth failed due to illegal seq=%x\n", seq); */
if (go2asoc) {
if (rtw_ft_update_auth_rsp_ies(padapter, pframe, pkt_len))
RTW_PRINT("auth success, start assoc\n");
start_clnt_assoc(padapter);
authclnt_fail:
/* pmlmeinfo->state &= ~(WIFI_FW_AUTH_STATE); */
unsigned int OnAssocReq(_adapter *padapter, union recv_frame *precv_frame)
u16 listen_interval;
struct sta_info *pstat;
unsigned char reassoc, *pos;
unsigned short status = _STATS_SUCCESSFUL_;
unsigned short frame_type, ie_offset = 0;
u8 p2p_status_code = P2P_STATUS_SUCCESS;
u8 *p2pie;
u32 p2pielen = 0;
u8 sta_tbtx_enable = _FALSE;
/* don't process assoc request; */
if (rtw_check_invalid_mac_address(get_addr2_ptr(pframe), _FALSE)) {
RTW_INFO("%s : reject invalid ASSOC-req "MAC_FMT"\n",
frame_type = get_frame_sub_type(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) {
RTW_INFO("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
"\n", reassoc, (unsigned long)pkt_len);
pstat = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe));
if (pstat == (struct sta_info *)NULL) {
status = _RSON_CLS2_;
goto asoc_class2_error;
if (pstat->authalg == WLAN_AUTH_SAE) {
/* WPA3-SAE */
if (((pstat->state) & WIFI_FW_AUTH_NULL)) {
/* TODO:
Queue AssocReq and Proccess
by external auth trigger. */
RTW_INFO("%s: wait external auth trigger\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)) {
pstat->state &= (~WIFI_FW_ASSOC_SUCCESS);
pstat->state |= WIFI_FW_ASSOC_STATE;
pstat->state &= (~WIFI_FW_AUTH_SUCCESS);
#if 0/* todo:tkip_countermeasures */
if (hapd->tkip_countermeasures) {
resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
goto fail;
if (rtw_ap_linking_test_force_asoc_fail()) {
status = rtw_ap_linking_test_force_asoc_fail();
RTW_INFO(FUNC_ADPT_FMT" force asoc fail with status:%u\n"
goto OnAssocReqFail;
/* now parse all ieee802_11 ie to point to elems */
left = pkt_len - (IEEE80211_3ADDR_LEN + ie_offset);
pos = pframe + (IEEE80211_3ADDR_LEN + ie_offset);
RTW_INFO("STA " MAC_FMT " sent invalid association request\n",
MAC_ARG(pstat->cmn.mac_addr));
status = _STATS_FAILURE_;
rtw_ap_parse_sta_capability(padapter, pstat, pframe + WLAN_HDR_A3_LEN);
listen_interval = RTW_GET_LE16(pframe + WLAN_HDR_A3_LEN + 2);
#if 0/* todo: */
/* check listen_interval */
if (listen_interval > hapd->conf->max_listen_interval) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"Too large Listen Interval (%d)",
listen_interval);
resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
pstat->listen_interval = listen_interval;
/* now we should check all the fields... */
/* checking SSID */
if (elems.ssid == NULL
|| elems.ssid_len == 0
|| elems.ssid_len != cur->Ssid.SsidLength
|| _rtw_memcmp(elems.ssid, cur->Ssid.Ssid, cur->Ssid.SsidLength) == _FALSE
/* (Extended) Supported rates */
status = rtw_ap_parse_sta_supported_rates(padapter, pstat
, pframe + WLAN_HDR_A3_LEN + ie_offset, pkt_len - WLAN_HDR_A3_LEN - ie_offset);
if (status != _STATS_SUCCESSFUL_)
/* check RSN/WPA/WPS */
status = rtw_ap_parse_sta_security_ie(padapter, pstat, &elems);
/* check if there is WMM IE & support WWM-PS */
rtw_ap_parse_sta_wmm_ie(padapter, pstat
#ifdef CONFIG_RTS_FULL_BW
/*check vendor IE*/
rtw_parse_sta_vendor_ie_8812(padapter, pstat
#endif/*CONFIG_RTS_FULL_BW*/
if (elems.tbtx_cap && elems.tbtx_cap_len != 0) {
if(rtw_is_tbtx_capabilty(elems.tbtx_cap, elems.tbtx_cap_len)) {
sta_tbtx_enable = _TRUE;
rtw_ap_parse_sta_ht_ie(padapter, pstat, &elems);
rtw_ap_parse_sta_vht_ie(padapter, pstat, &elems);
if (((pstat->flags & WLAN_STA_HT) || (pstat->flags & WLAN_STA_VHT)) &&
((pstat->wpa2_pairwise_cipher & WPA_CIPHER_TKIP) ||
(pstat->wpa_pairwise_cipher & WPA_CIPHER_TKIP))) {
RTW_INFO("(V)HT: " MAC_FMT " tried to use TKIP with (V)HT association\n", MAC_ARG(pstat->cmn.mac_addr));
pstat->flags &= ~WLAN_STA_HT;
pstat->flags &= ~WLAN_STA_VHT;
/*status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
* goto OnAssocReqFail;
pstat->is_p2p_device = _FALSE;
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
p2pie = rtw_get_p2p_ie(pframe + WLAN_HDR_A3_LEN + ie_offset , pkt_len - WLAN_HDR_A3_LEN - ie_offset , NULL, &p2pielen);
if (p2pie) {
pstat->is_p2p_device = _TRUE;
p2p_status_code = (u8)process_assoc_req_p2p_ie(pwdinfo, pframe, pkt_len, pstat);
if (p2p_status_code > 0) {
pstat->p2p_status_code = p2p_status_code;
status = _STATS_CAP_FAIL_;
#ifdef CONFIG_WFD
rtw_process_wfd_ies(padapter, pframe + WLAN_HDR_A3_LEN + ie_offset, pkt_len - WLAN_HDR_A3_LEN - ie_offset, __func__);
rtw_ap_parse_sta_multi_ap_ie(padapter, pstat, pos, left);
if (rtw_rson_ap_check_sta(padapter, pframe, pkt_len, ie_offset))
/* TODO: identify_proprietary_vendor_ie(); */
/* Realtek proprietary IE */
/* identify if this is Broadcom sta */
/* identify if this is ralink sta */
/* Customer proprietary IE */
#ifdef CONFIG_RTW_80211K
rtw_ap_parse_sta_rm_en_cap(padapter, pstat, &elems);
if (pstat->cmn.aid > 0)
RTW_INFO(FUNC_ADPT_FMT" old AID=%d\n", FUNC_ADPT_ARG(padapter), pstat->cmn.aid);
if (!rtw_aid_alloc(padapter, pstat)) {
status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
RTW_INFO(FUNC_ADPT_FMT" allocate new AID=%d\n", FUNC_ADPT_ARG(padapter), pstat->cmn.aid);
pstat->state &= (~WIFI_FW_ASSOC_STATE);
pstat->state |= WIFI_FW_ASSOC_SUCCESS;
/* RTW_INFO("==================%s, %d, (%x), bpairwise_key_installed=%d, MAC:"MAC_FMT"\n"
, __func__, __LINE__, pstat->state, pstat->bpairwise_key_installed, MAC_ARG(pstat->cmn.mac_addr)); */
if (!rtw_is_list_empty(&pstat->auth_list)) {
rtw_list_delete(&pstat->auth_list);
pstapriv->auth_list_cnt--;
if (rtw_is_list_empty(&pstat->asoc_list)) {
pstat->expire_to = pstapriv->expire_to;
rtw_list_insert_tail(&pstat->asoc_list, &pstapriv->asoc_list);
if (sta_tbtx_enable) {
pstat->tbtx_enable = _TRUE;
/* 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);
if (pstat->bpairwise_key_installed == _TRUE && (pstat->flags & WLAN_STA_MFP))
/* .2 issue assoc rsp before notify station join event. */
if (frame_type == WIFI_ASSOCREQ)
issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP);
issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP);
_enter_critical_bh(&pstat->lock, &irqL);
if (pstat->passoc_req) {
rtw_mfree(pstat->passoc_req, pstat->assoc_req_len);
pstat->passoc_req = NULL;
pstat->assoc_req_len = 0;
pstat->passoc_req = rtw_zmalloc(pkt_len);
_rtw_memcpy(pstat->passoc_req, pframe, pkt_len);
pstat->assoc_req_len = pkt_len;
_exit_critical_bh(&pstat->lock, &irqL);
/* .3-(1) report sta add event */
report_add_sta_event(padapter, pstat->cmn.mac_addr);
if (pstat->bpairwise_key_installed == _TRUE && (pstat->flags & WLAN_STA_MFP)) {
RTW_INFO(MAC_FMT"\n", MAC_ARG(pstat->cmn.mac_addr));
issue_action_SA_Query(padapter, pstat->cmn.mac_addr, 0, 0, IEEE80211W_RIGHT_KEY);
#endif /* CONFIG_NATIVEAP_MLME */
asoc_class2_error:
issue_deauth(padapter, (void *)get_addr2_ptr(pframe), status);
OnAssocReqFail:
/* pstat->cmn.aid = 0; */
#if defined(CONFIG_LAYER2_ROAMING) && defined(CONFIG_RTW_80211K)
void rtw_roam_nb_discover(_adapter *padapter, u8 bfroce)
u8 nb_req_issue = _FALSE;
if (!check_fwstate(pmlmepriv, WIFI_ASOC_STATE))
if (!rtw_chk_roam_flags(padapter, RTW_ROAM_ACTIVE))
psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress);
if (!psta)
if (bfroce || (!pmlmepriv->nb_info.nb_rpt_is_same))
nb_req_issue = _TRUE;
if (nb_req_issue && (psta->rm_en_cap[0] & RTW_RRM_NB_RPT_EN))
rm_add_nb_req(padapter, psta);
unsigned int OnAssocRsp(_adapter *padapter, union recv_frame *precv_frame)
uint i;
int res;
unsigned short status;
PNDIS_802_11_VARIABLE_IEs pIE;
/* WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); */
#ifdef CONFIG_WAPI_SUPPORT
PNDIS_802_11_VARIABLE_IEs pWapiIE = NULL;
if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE)) || pmlmeext->join_abort)
if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)
/* status */
status = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN + 2));
if (status > 0) {
RTW_INFO("assoc reject, status code: %d\n", status);
res = -4;
goto report_assoc_result;
/* get capabilities */
pmlmeinfo->capability = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN));
/* set slot time */
pmlmeinfo->slotTime = (pmlmeinfo->capability & BIT(10)) ? 9 : 20;
/* AID */
res = pmlmeinfo->aid = (int)(le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN + 4)) & 0x3fff);
/* check aid value */
if (res < 1 || res > 2007) {
RTW_INFO("assoc reject, aid: %d\n", res);
/* 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 = (PNDIS_802_11_VARIABLE_IEs)(pframe + i);
switch (pIE->ElementID) {
case _VENDOR_SPECIFIC_IE_:
if (_rtw_memcmp(pIE->data, WMM_PARA_OUI, 6)) /* WMM */
WMM_param_handler(padapter, pIE);
#if defined(CONFIG_P2P) && defined(CONFIG_WFD)
else if (_rtw_memcmp(pIE->data, WFD_OUI, 4)) /* WFD */
rtw_process_wfd_ie(padapter, (u8 *)pIE, pIE->Length, __func__);
case _WAPI_IE_:
pWapiIE = pIE;
case _HT_CAPABILITY_IE_: /* HT caps */
HT_caps_handler(padapter, pIE);
HT_caps_handler_infra_ap(padapter, pIE);
case _HT_EXTRA_INFO_IE_: /* HT info */
HT_info_handler(padapter, pIE);
#ifdef CONFIG_80211AC_VHT
case EID_VHTCapability:
VHT_caps_handler(padapter, pIE);
VHT_caps_handler_infra_ap(padapter, pIE);
case EID_VHTOperation:
VHT_operation_handler(padapter, pIE);
case _ERPINFO_IE_:
ERP_IE_handler(padapter, pIE);
case _EXT_CAP_IE_:
if (check_ap_tdls_prohibited(pIE->data, pIE->Length) == _TRUE)
padapter->tdlsinfo.ap_prohibited = _TRUE;
if (check_ap_tdls_ch_switching_prohibited(pIE->data, pIE->Length) == _TRUE)
padapter->tdlsinfo.ch_switch_prohibited = _TRUE;
case _EID_RRM_EN_CAP_IE_:
RM_IE_handler(padapter, pIE);
/* Infra mode, used to store AP's info , Parse the supported rates from AssocRsp */
case _SUPPORTEDRATES_IE_:
Supported_rate_infra_ap(padapter, pIE);
case _EXT_SUPPORTEDRATES_IE_:
Extended_Supported_rate_infra_ap(padapter, pIE);
i += (pIE->Length + 2);
rtw_wapi_on_assoc_ok(padapter, pIE);
pmlmeinfo->state &= (~WIFI_FW_ASSOC_STATE);
pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS;
/* 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);
rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len);
report_join_res(padapter, res, status);
rtw_roam_nb_discover(padapter, _TRUE);
unsigned int OnDeAuth(_adapter *padapter, union recv_frame *precv_frame)
unsigned short reason;
/* check A3 */
if (!(_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)))
RTW_INFO(FUNC_ADPT_FMT" - Start to Disconnect\n", FUNC_ADPT_ARG(padapter));
if (pwdinfo->rx_invitereq_info.scan_op_ch_only) {
_cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey);
_set_timer(&pwdinfo->reset_ch_sitesurvey, 10);
reason = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN));
if (MLME_IS_AP(padapter)) {
/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
/* rtw_free_stainfo(padapter, psta); */
/* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
RTW_PRINT(FUNC_ADPT_FMT" reason=%u, ta=%pM\n"
, FUNC_ADPT_ARG(padapter), reason, get_addr2_ptr(pframe));
if (psta) {
u8 updated = _FALSE;
if (rtw_is_list_empty(&psta->asoc_list) == _FALSE) {
rtw_list_delete(&psta->asoc_list);
updated = ap_free_sta(padapter, psta, _FALSE, reason, _TRUE);
associated_clients_update(padapter, updated, STA_INFO_UPDATE_ALL);
if (!MLME_IS_MESH(padapter)) {
int ignore_received_deauth = 0;
/* Commented by Albert 20130604 */
/* Before sending the auth frame to start the STA/GC mode connection with AP/GO, */
/* we will send the deauth first. */
/* However, the Win8.1 with BRCM Wi-Fi will send the deauth with reason code 6 to us after receieving our deauth. */
/* Added the following code to avoid this case. */
if ((pmlmeinfo->state & WIFI_FW_AUTH_STATE) ||
(pmlmeinfo->state & WIFI_FW_ASSOC_STATE)) {
if (reason == WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA)
ignore_received_deauth = 1;
else if (WLAN_REASON_PREV_AUTH_NOT_VALID == reason) {
/* TODO: 802.11r */
RTW_PRINT(FUNC_ADPT_FMT" reason=%u, ta=%pM, ignore=%d\n"
, FUNC_ADPT_ARG(padapter), reason, get_addr2_ptr(pframe), ignore_received_deauth);
if (0 == ignore_received_deauth)
receive_disconnect(padapter, get_addr2_ptr(pframe), reason, _FALSE);
pmlmepriv->LinkDetectInfo.bBusyTraffic = _FALSE;
unsigned int OnDisassoc(_adapter *padapter, union recv_frame *precv_frame)
if (rtw_wnm_try_btm_roam_imnt(padapter) > 0)
unsigned int OnAtim(_adapter *padapter, union recv_frame *precv_frame)
unsigned int on_action_spct_ch_switch(_adapter *padapter, struct sta_info *psta, u8 *ies, uint ies_len)
unsigned int ret = _FAIL;
struct mlme_ext_priv *mlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(mlmeext->mlmext_info);
if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) {
ret = _SUCCESS;
if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) {
int ch_switch_mode = -1, ch = -1, ch_switch_cnt = -1;
int ch_offset = -1;
u8 bwmode;
struct ieee80211_info_element *ie;
RTW_INFO(FUNC_NDEV_FMT" from "MAC_FMT"\n",
FUNC_NDEV_ARG(padapter->pnetdev), MAC_ARG(psta->cmn.mac_addr));
for_each_ie(ie, ies, ies_len) {
if (ie->id == WLAN_EID_CHANNEL_SWITCH) {
ch_switch_mode = ie->data[0];
ch = ie->data[1];
ch_switch_cnt = ie->data[2];
RTW_INFO("ch_switch_mode:%d, ch:%d, ch_switch_cnt:%d\n",
ch_switch_mode, ch, ch_switch_cnt);
} else if (ie->id == WLAN_EID_SECONDARY_CHANNEL_OFFSET) {
ch_offset = secondary_ch_offset_to_hal_ch_offset(ie->data[0]);
RTW_INFO("ch_offset:%d\n", ch_offset);
if (ch == -1)
if (ch_offset == -1)
bwmode = mlmeext->cur_bwmode;
bwmode = (ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) ?
CHANNEL_WIDTH_20 : CHANNEL_WIDTH_40;
ch_offset = (ch_offset == -1) ? mlmeext->cur_ch_offset : ch_offset;
/* todo:
* 1. the decision of channel switching
* 2. things after channel switching
ret = rtw_set_chbw_cmd(padapter, ch, bwmode, ch_offset, 0);
unsigned int on_action_spct(_adapter *padapter, union recv_frame *precv_frame)
uint frame_len = precv_frame->u.hdr.len;
u8 *frame_body = (u8 *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
u8 category;
u8 action;
category = frame_body[0];
if (category != RTW_WLAN_CATEGORY_SPECTRUM_MGMT)
action = frame_body[1];
RTW_INFO(FUNC_ADPT_FMT" action:%u\n", FUNC_ADPT_ARG(padapter), action);
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:
case RTW_WLAN_ACTION_SPCT_CHL_SWITCH:
#ifdef CONFIG_SPCT_CH_SWITCH
ret = on_action_spct_ch_switch(padapter, psta
, frame_body + 2, frame_len - (frame_body - pframe) - 2);
#elif CONFIG_DFS
if (MLME_IS_STA(padapter) && MLME_IS_ASOC(padapter)) {
unsigned int OnAction_qos(_adapter *padapter, union recv_frame *precv_frame)
unsigned int OnAction_dls(_adapter *padapter, union recv_frame *precv_frame)
unsigned int on_action_wnm(_adapter *adapter, union recv_frame *rframe)
struct sta_info *sta = NULL;
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
struct sta_priv *stapriv = &(adapter->stapriv);
u8 *frame = rframe->u.hdr.rx_data;
u32 frame_len = rframe->u.hdr.len;
u8 *frame_body = (u8 *)(frame + sizeof(struct rtw_ieee80211_hdr_3addr));
u32 frame_body_len = frame_len - sizeof(struct rtw_ieee80211_hdr_3addr);
u8 category, action;
int cnt = 0;
char msg[16];
sta = rtw_get_stainfo(stapriv, get_addr2_ptr(frame));
if (!sta)
if (category != RTW_WLAN_CATEGORY_WNM)
case RTW_WLAN_ACTION_WNM_BTM_REQ:
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) {
RTW_INFO("WNM: BSS Transition Management Request recv.\n");
rtw_wnm_process_btm_req(adapter, frame_body, frame_body_len);
case RTW_WLAN_ACTION_WNM_BTM_RSP:
if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) &&
(pmlmepriv->nb_info.features & RTW_WNM_FEATURE_BTM_REQ_EN)) {
struct btm_rsp_hdr rsp;
u32 sz;
RTW_INFO("WNM: BSS Transition Management Response recv.\n");
sz = rtw_wnm_btm_rsp_candidates_sz_get(adapter,
frame_body, frame_body_len);
_rtw_memset(&rsp, 0, sizeof(rsp));
if (sz > 0)
rsp.pcandidates = rtw_zmalloc(sz);
rtw_wnm_process_btm_rsp(adapter, frame_body, frame_body_len, &rsp);
/* TODO : handle candidates info in rsp.pcandidates for upper-layer services */
cmap_intfs_nl_btm_resp_event(adapter, sta->cmn.mac_addr,
adapter_mac_addr(adapter),
rsp.status, rsp.bssid,
rsp.pcandidates,
rsp.candidates_num);
if (0 && rsp.pcandidates && (rsp.candidates_num > 0))
RTW_INFO_DUMP("pcandidates : ", rsp.pcandidates, sz);
if ((sz > 0) && (rsp.pcandidates != NULL))
rtw_mfree(rsp.pcandidates, sz);
cnt += sprintf((msg + cnt), "ACT_WNM %u", action);
rtw_cfg80211_rx_action(adapter, rframe, msg);
#endif /* CONFIG_RTW_WNM */
* rtw_rx_ampdu_size - Get the target RX AMPDU buffer size for the specific @adapter
* @adapter: the adapter to get target RX AMPDU buffer size
* Returns: the target RX AMPDU buffer size
u8 rtw_rx_ampdu_size(_adapter *adapter)
u8 size;
HT_CAP_AMPDU_FACTOR max_rx_ampdu_factor;
#ifdef CONFIG_BT_COEXIST
if (rtw_btcoex_IsBTCoexCtrlAMPDUSize(adapter) == _TRUE) {
size = rtw_btcoex_GetAMPDUSize(adapter);
/* for scan */
if (!mlmeext_chk_scan_state(&adapter->mlmeextpriv, SCAN_DISABLE)
&& !mlmeext_chk_scan_state(&adapter->mlmeextpriv, SCAN_COMPLETE)
&& adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_size != RX_AMPDU_SIZE_INVALID
size = adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_size;
/* default value based on max_rx_ampdu_factor */
if (adapter->driver_rx_ampdu_factor != 0xFF)
max_rx_ampdu_factor = (HT_CAP_AMPDU_FACTOR)adapter->driver_rx_ampdu_factor;
rtw_hal_get_def_var(adapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor);
/* In Maximum A-MPDU Length Exponent subfield of A-MPDU Parameters field of HT Capabilities element,
the unit of max_rx_ampdu_factor are octets. 8K, 16K, 32K, 64K is right.
But the buffer size subfield of Block Ack Parameter Set field in ADDBA action frame indicates
the number of buffers available for this particular TID. Each buffer is equal to max. size of
MSDU or AMSDU.
The size variable means how many MSDUs or AMSDUs, it's not Kbytes.
if (MAX_AMPDU_FACTOR_64K == max_rx_ampdu_factor)
size = 64;
else if (MAX_AMPDU_FACTOR_32K == max_rx_ampdu_factor)
size = 32;
else if (MAX_AMPDU_FACTOR_16K == max_rx_ampdu_factor)
size = 16;
else if (MAX_AMPDU_FACTOR_8K == max_rx_ampdu_factor)
size = 8;
if (size > 127)
size = 127;
return size;
* rtw_rx_ampdu_is_accept - Get the permission if RX AMPDU should be set up for the specific @adapter
* @adapter: the adapter to get the permission if RX AMPDU should be set up
* Returns: accept or not
bool rtw_rx_ampdu_is_accept(_adapter *adapter)
bool accept;
if (adapter->fix_rx_ampdu_accept != RX_AMPDU_ACCEPT_INVALID) {
accept = adapter->fix_rx_ampdu_accept;
if (rtw_btcoex_IsBTCoexRejectAMPDU(adapter) == _TRUE) {
accept = _FALSE;
&& adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_accept != RX_AMPDU_ACCEPT_INVALID
accept = adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_accept;
/* default value for other cases */
accept = adapter->mlmeextpriv.mlmext_info.bAcceptAddbaReq;
return accept;
* rtw_rx_ampdu_set_size - Set the target RX AMPDU buffer size for the specific @adapter and specific @reason
* @adapter: the adapter to set target RX AMPDU buffer size
* @size: the target RX AMPDU buffer size to set
* @reason: reason for the target RX AMPDU buffer size setting
* Returns: whether the target RX AMPDU buffer size is changed
bool rtw_rx_ampdu_set_size(_adapter *adapter, u8 size, u8 reason)
bool is_adj = _FALSE;
struct mlme_ext_info *mlmeinfo;
mlmeext = &adapter->mlmeextpriv;
mlmeinfo = &mlmeext->mlmext_info;
if (reason == RX_AMPDU_DRV_FIXED) {
if (adapter->fix_rx_ampdu_size != size) {
adapter->fix_rx_ampdu_size = size;
is_adj = _TRUE;
RTW_INFO(FUNC_ADPT_FMT" fix_rx_ampdu_size:%u\n", FUNC_ADPT_ARG(adapter), size);
} else if (reason == RX_AMPDU_DRV_SCAN) {
struct ss_res *ss = &adapter->mlmeextpriv.sitesurvey_res;
if (ss->rx_ampdu_size != size) {
ss->rx_ampdu_size = size;
RTW_INFO(FUNC_ADPT_FMT" ss.rx_ampdu_size:%u\n", FUNC_ADPT_ARG(adapter), size);
return is_adj;
* rtw_rx_ampdu_set_accept - Set the permission if RX AMPDU should be set up for the specific @adapter and specific @reason
* @adapter: the adapter to set if RX AMPDU should be set up
* @accept: if RX AMPDU should be set up
* @reason: reason for the permission if RX AMPDU should be set up
* Returns: whether the permission if RX AMPDU should be set up is changed
bool rtw_rx_ampdu_set_accept(_adapter *adapter, u8 accept, u8 reason)
if (adapter->fix_rx_ampdu_accept != accept) {
adapter->fix_rx_ampdu_accept = accept;
RTW_INFO(FUNC_ADPT_FMT" fix_rx_ampdu_accept:%u\n", FUNC_ADPT_ARG(adapter), accept);
if (adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_accept != accept) {
adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_accept = accept;
RTW_INFO(FUNC_ADPT_FMT" ss.rx_ampdu_accept:%u\n", FUNC_ADPT_ARG(adapter), accept);
* rx_ampdu_apply_sta_tid - Apply RX AMPDU setting to the specific @sta and @tid
* @adapter: the adapter to which @sta belongs
* @sta: the sta to be checked
* @tid: the tid to be checked
* @accept: the target permission if RX AMPDU should be set up
* @size: the target RX AMPDU buffer size
* Returns:
* 0: no canceled
* 1: canceled by no permission
* 2: canceled by different buffer size
* 3: canceled by potential mismatched status
* Blocking function, may sleep
u8 rx_ampdu_apply_sta_tid(_adapter *adapter, struct sta_info *sta, u8 tid, u8 accept, u8 size)
u8 ret = 0;
struct recv_reorder_ctrl *reorder_ctl = &sta->recvreorder_ctrl[tid];
if (reorder_ctl->enable == _FALSE) {
if (reorder_ctl->ampdu_size != RX_AMPDU_SIZE_INVALID) {
send_delba_sta_tid_wait_ack(adapter, 0, sta, tid, 1);
ret = 3;
if (accept == _FALSE) {
send_delba_sta_tid_wait_ack(adapter, 0, sta, tid, 0);
} else if (reorder_ctl->ampdu_size != size) {
ret = 2;
u8 rx_ampdu_size_sta_limit(_adapter *adapter, struct sta_info *sta)
u8 sz_limit = 0xFF;
struct mlme_priv *mlme = &adapter->mlmepriv;
struct mlme_ext_info *mlmeinfo = &adapter->mlmeextpriv.mlmext_info;
s8 nss = -1;
u8 bw = rtw_min(sta->cmn.bw_mode, adapter->mlmeextpriv.cur_bwmode);
if (is_supported_vht(sta->wireless_mode)) {
nss = rtw_min(rtw_vht_mcsmap_to_nss(mlme->vhtpriv.vht_mcs_map)
, rtw_vht_mcsmap_to_nss(sta->vhtpriv.vht_mcs_map));
if (is_supported_ht(sta->wireless_mode)) {
nss = rtw_min(rtw_ht_mcsset_to_nss(mlmeinfo->HT_caps.u.HT_cap_element.MCS_rate)
, rtw_ht_mcsset_to_nss(sta->htpriv.ht_cap.supp_mcs_set));
if (nss >= 1)
sz_limit = regsty->rx_ampdu_sz_limit_by_nss_bw[nss - 1][bw];
#endif /* CONFIG_80211N_HT */
return sz_limit;
* rx_ampdu_apply_sta - Apply RX AMPDU setting to the specific @sta
* Returns: number of the RX AMPDU assciation canceled for applying current target setting
u8 rx_ampdu_apply_sta(_adapter *adapter, struct sta_info *sta, u8 accept, u8 size)
u8 change_cnt = 0;
for (i = 0; i < TID_NUM; i++) {
if (rx_ampdu_apply_sta_tid(adapter, sta, i, accept, size) != 0)
change_cnt++;
return change_cnt;
* rtw_rx_ampdu_apply - Apply the current target RX AMPDU setting for the specific @adapter
* @adapter: the adapter to be applied
u16 rtw_rx_ampdu_apply(_adapter *adapter)
u16 adj_cnt = 0;
struct sta_info *sta;
u8 accept = rtw_rx_ampdu_is_accept(adapter);
if (adapter->fix_rx_ampdu_size != RX_AMPDU_SIZE_INVALID)
size = adapter->fix_rx_ampdu_size;
size = rtw_rx_ampdu_size(adapter);
if (MLME_IS_STA(adapter)) {
sta = rtw_get_stainfo(&adapter->stapriv, get_bssid(&adapter->mlmepriv));
if (sta) {
u8 sta_size = size;
if (adapter->fix_rx_ampdu_size == RX_AMPDU_SIZE_INVALID)
sta_size = rtw_min(size, rx_ampdu_size_sta_limit(adapter, sta));
adj_cnt += rx_ampdu_apply_sta(adapter, sta, accept, sta_size);
/* TODO: TDLS peer */
} else if (MLME_IS_AP(adapter) || MLME_IS_MESH(adapter)) {
_list *phead, *plist;
u8 peer_num = 0;
char peers[NUM_STA];
struct sta_priv *pstapriv = &adapter->stapriv;
phead = &pstapriv->asoc_list;
int stainfo_offset;
sta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
stainfo_offset = rtw_stainfo_offset(pstapriv, sta);
if (stainfo_offset_valid(stainfo_offset))
peers[peer_num++] = stainfo_offset;
for (i = 0; i < peer_num; i++) {
sta = rtw_get_stainfo_by_offset(pstapriv, peers[i]);
/* TODO: ADHOC */
return adj_cnt;
unsigned int OnAction_back(_adapter *padapter, union recv_frame *precv_frame)
u8 *addr;
struct recv_reorder_ctrl *preorder_ctrl;
unsigned char *frame_body;
unsigned char category, action;
unsigned short tid, status, reason_code = 0;
struct registry_priv *pregpriv = &padapter->registrypriv;
/* check RA matches or not */
if (!_rtw_memcmp(adapter_mac_addr(padapter), GetAddr1Ptr(pframe), ETH_ALEN))
if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS))
addr = get_addr2_ptr(pframe);
psta = rtw_get_stainfo(pstapriv, addr);
if (psta == NULL)
frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
if (category == RTW_WLAN_CATEGORY_BACK) { /* representing Block Ack */
if ((psta->tdls_sta_state & TDLS_LINKED_STATE) &&
(psta->htpriv.ht_option == _TRUE) &&
(psta->htpriv.ampdu_enable == _TRUE))
RTW_INFO("Recv [%s] from direc link\n", __FUNCTION__);
if (!pmlmeinfo->HT_enable)
RTW_INFO("%s, action=%d\n", __FUNCTION__, action);
case RTW_WLAN_ACTION_ADDBA_REQ: /* ADDBA request */
_rtw_memcpy(&(pmlmeinfo->ADDBA_req), &(frame_body[2]), sizeof(struct ADDBA_request));
/* process_addba_req(padapter, (u8*)&(pmlmeinfo->ADDBA_req), GetAddr3Ptr(pframe)); */
process_addba_req(padapter, (u8 *)&(pmlmeinfo->ADDBA_req), addr);
case RTW_WLAN_ACTION_ADDBA_RESP: /* ADDBA response */
/* status = frame_body[3] | (frame_body[4] << 8); */ /* endian issue */
status = RTW_GET_LE16(&frame_body[3]);
tid = ((frame_body[5] >> 2) & 0x7);
if (status == 0) {
/* successful */
RTW_INFO("agg_enable for TID=%d\n", tid);
psta->htpriv.agg_enable_bitmap |= 1 << tid;
psta->htpriv.candidate_tid_bitmap &= ~BIT(tid);
/* amsdu in ampdu */
if (pregpriv->tx_ampdu_amsdu == 0)
psta->htpriv.tx_amsdu_enable = _FALSE;
else if (pregpriv->tx_ampdu_amsdu == 1)
psta->htpriv.tx_amsdu_enable = _TRUE;
if (frame_body[5] & 1)
psta->htpriv.agg_enable_bitmap &= ~BIT(tid);
if (psta->state & WIFI_STA_ALIVE_CHK_STATE) {
RTW_INFO("%s alive check - rx ADDBA response\n", __func__);
psta->state ^= WIFI_STA_ALIVE_CHK_STATE;
/* RTW_INFO("marc: ADDBA RSP: %x\n", pmlmeinfo->agg_enable_bitmap); */
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 = frame_body[4] | (frame_body[5] << 8); */
reason_code = RTW_GET_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->ampdu_size = RX_AMPDU_SIZE_INVALID;
RTW_INFO("%s(): DELBA: %x(%x)\n", __FUNCTION__, pmlmeinfo->agg_enable_bitmap, reason_code);
/* todo: how to notify the host while receiving DELETE BA */
#ifdef CONFIG_APPEND_VENDOR_IE_ENABLE
u32 rtw_build_vendor_ie(_adapter *padapter , unsigned char **pframe , u8 mgmt_frame_tyte)
int vendor_ie_num = 0;
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
u32 len = 0;
for (vendor_ie_num = 0 ; vendor_ie_num < WLAN_MAX_VENDOR_IE_NUM ; vendor_ie_num++) {
if (pmlmepriv->vendor_ielen[vendor_ie_num] > 0 && pmlmepriv->vendor_ie_mask[vendor_ie_num] & mgmt_frame_tyte) {
_rtw_memcpy(*pframe , pmlmepriv->vendor_ie[vendor_ie_num] , pmlmepriv->vendor_ielen[vendor_ie_num]);
*pframe += pmlmepriv->vendor_ielen[vendor_ie_num];
len += pmlmepriv->vendor_ielen[vendor_ie_num];
return len;
int get_reg_classes_full_count(struct p2p_channels *channel_list)
for (i = 0; i < channel_list->reg_classes; i++)
cnt += channel_list->reg_class[i].channels;
return cnt;
void issue_p2p_GO_request(_adapter *padapter, u8 *raddr)
struct p2p_channels *ch_list = &(adapter_to_rfctl(padapter)->channel_list);
unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
u8 action = P2P_PUB_ACTION_ACTION;
u32 p2poui = cpu_to_be32(P2POUI);
u8 oui_subtype = P2P_GO_NEGO_REQ;
u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 };
u8 wpsielen = 0, p2pielen = 0;
u16 len_channellist_attr = 0;
u32 wfdielen = 0;
struct xmit_frame *pmgntframe;
struct pkt_attrib *pattrib;
unsigned char *pframe;
struct rtw_ieee80211_hdr *pwlanhdr;
unsigned short *fctrl;
struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
if (pmgntframe == NULL)
RTW_INFO("[%s] In\n", __FUNCTION__);
/* update attribute */
pattrib = &pmgntframe->attrib;
update_mgntframe_attrib(padapter, pattrib);
_rtw_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;
_rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN);
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
set_frame_sub_type(pframe, WIFI_ACTION);
pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
pwdinfo->negotiation_dialog_token = 1; /* Initialize the dialog value */
pframe = rtw_set_fixed_ie(pframe, 1, &pwdinfo->negotiation_dialog_token, &(pattrib->pktlen));
/* WPS Section */
wpsielen = 0;
/* WPS OUI */
*(u32 *)(wpsie) = cpu_to_be32(WPSOUI);
wpsielen += 4;
/* WPS version */
/* Type: */
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
wpsielen += 2;
/* Length: */
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
/* Value: */
wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */
/* Device Password ID */
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID);
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN)
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC);
else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN)
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC);
else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC)
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC);
pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen);
/* P2P IE Section. */
/* P2P OUI */
p2pielen = 0;
p2pie[p2pielen++] = 0x50;
p2pie[p2pielen++] = 0x6F;
p2pie[p2pielen++] = 0x9A;
p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
/* Commented by Albert 20110306 */
/* According to the P2P Specification, the group negoitation request frame should contain 9 P2P attributes */
/* 1. P2P Capability */
/* 2. Group Owner Intent */
/* 3. Configuration Timeout */
/* 4. Listen Channel */
/* 5. Extended Listen Timing */
/* 6. Intended P2P Interface Address */
/* 7. Channel List */
/* 8. P2P Device Info */
/* 9. Operating Channel */
/* P2P Capability */
p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
p2pielen += 2;
/* Device Capability Bitmap, 1 byte */
p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
/* Group Capability Bitmap, 1 byte */
if (pwdinfo->persistent_supported)
p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP;
p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN;
/* Group Owner Intent */
p2pie[p2pielen++] = P2P_ATTR_GO_INTENT;
*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001);
/* Todo the tie breaker bit. */
p2pie[p2pielen++] = ((pwdinfo->intent << 1) & 0xFE);
/* Configuration Timeout */
p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT;
p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */
p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */
/* Listen Channel */
p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH;
*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
/* Country String */
p2pie[p2pielen++] = 'X';
/* The third byte should be set to 0x04. */
/* Described in the "Operating Channel Attribute" section. */
p2pie[p2pielen++] = 0x04;
/* Operating Class */
p2pie[p2pielen++] = 0x51; /* Copy from SD7 */
/* Channel Number */
p2pie[p2pielen++] = pwdinfo->listen_channel; /* listening channel number */
/* Extended Listen Timing ATTR */
p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING;
*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004);
/* Availability Period */
*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
/* Availability Interval */
/* Intended P2P Interface Address */
p2pie[p2pielen++] = P2P_ATTR_INTENDED_IF_ADDR;
*(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
_rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), ETH_ALEN);
p2pielen += ETH_ALEN;
/* Channel List */
p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
/* Country String(3) */
/* + ( Operating Class (1) + Number of Channels(1) ) * Operation Classes (?) */
/* + number of channels in all classes */
len_channellist_attr = 3
+ (1 + 1) * (u16)(ch_list->reg_classes)
+ get_reg_classes_full_count(ch_list);
if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0)
*(u16 *)(p2pie + p2pielen) = cpu_to_le16(5 + 1);
*(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
/* Channel Entry List */
if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0) {
u8 union_ch = rtw_mi_get_union_chan(padapter);
if (union_ch > 14) {
if (union_ch >= 149)
p2pie[p2pielen++] = 0x7c;
p2pie[p2pielen++] = 0x73;
p2pie[p2pielen++] = 0x51;
/* Number of Channels */
/* Just support 1 channel and this channel is AP's channel */
p2pie[p2pielen++] = 1;
p2pie[p2pielen++] = union_ch;
int i, j;
for (j = 0; j < ch_list->reg_classes; j++) {
p2pie[p2pielen++] = ch_list->reg_class[j].reg_class;
p2pie[p2pielen++] = ch_list->reg_class[j].channels;
for (i = 0; i < ch_list->reg_class[j].channels; i++)
p2pie[p2pielen++] = ch_list->reg_class[j].channel[i];
/* Device Info */
p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
/* 21->P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
/* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
*(u16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len);
/* P2P Device Address */
/* Config Method */
/* This field should be big endian. Noted by P2P specification. */
*(u16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm);
/* Primary Device Type */
/* Category ID */
*(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
/* OUI */
*(u32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI);
p2pielen += 4;
/* Sub Category ID */
*(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
/* Number of Secondary Device Types */
p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */
/* Device Name */
*(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
*(u16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len);
_rtw_memcpy(p2pie + p2pielen, pwdinfo->device_name , pwdinfo->device_name_len);
p2pielen += pwdinfo->device_name_len;
/* Operating Channel */
p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
if (pwdinfo->operating_channel <= 14) {
} else if ((pwdinfo->operating_channel >= 36) && (pwdinfo->operating_channel <= 48)) {
p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */
pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen);
wfdielen = build_nego_req_wfd_ie(pwdinfo, pframe);
pframe += wfdielen;
pattrib->pktlen += wfdielen;
pattrib->last_txcmdsz = pattrib->pktlen;
dump_mgntframe(padapter, pmgntframe);
void issue_p2p_GO_response(_adapter *padapter, u8 *raddr, u8 *frame_body, uint len, u8 result)
u8 oui_subtype = P2P_GO_NEGO_RESP;
u8 p2pielen = 0;
uint wpsielen = 0;
u16 wps_devicepassword_id = 0x0000;
uint wps_devicepassword_id_len = 0;
RTW_INFO("[%s] In, result = %d\n", __FUNCTION__, result);
pwdinfo->negotiation_dialog_token = frame_body[7]; /* The Dialog Token of provisioning discovery request frame. */
pframe = rtw_set_fixed_ie(pframe, 1, &(pwdinfo->negotiation_dialog_token), &(pattrib->pktlen));
/* Commented by Albert 20110328 */
/* Try to get the device password ID from the WPS IE of group negotiation request frame */
/* WiFi Direct test plan 5.1.15 */
rtw_get_wps_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, wpsie, &wpsielen);
rtw_get_wps_attr_content(wpsie, wpsielen, WPS_ATTR_DEVICE_PWID, (u8 *) &wps_devicepassword_id, &wps_devicepassword_id_len);
wps_devicepassword_id = be16_to_cpu(wps_devicepassword_id);
_rtw_memset(wpsie, 0x00, 255);
if (wps_devicepassword_id == WPS_DPID_USER_SPEC)
else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC)
/* Commented by Kurt 20120113 */
/* If some device wants to do p2p handshake without sending prov_disc_req */
/* We have to get peer_req_cm from here. */
if (_rtw_memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) {
_rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3);
_rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3);
_rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3);
/* Commented by Albert 20100908 */
/* According to the P2P Specification, the group negoitation response frame should contain 9 P2P attributes */
/* 1. Status */
/* 2. P2P Capability */
/* 3. Group Owner Intent */
/* 4. Configuration Timeout */
/* 5. Operating Channel */
/* 8. Device Info */
/* 9. Group ID ( Only GO ) */
/* ToDo: */
/* P2P Status */
p2pie[p2pielen++] = P2P_ATTR_STATUS;
p2pie[p2pielen++] = result;
/* Commented by Albert 2011/03/08 */
/* According to the P2P specification */
/* if the sending device will be client, the P2P Capability should be reserved of group negotation response frame */
p2pie[p2pielen++] = 0;
/* Be group owner or meet the error case */
if (pwdinfo->peer_intent & 0x01) {
/* Peer's tie breaker bit is 1, our tie breaker bit should be 0 */
p2pie[p2pielen++] = (pwdinfo->intent << 1);
/* Peer's tie breaker bit is 0, our tie breaker bit should be 1 */
p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0));
+ (1 + 1) * (u16)ch_list->reg_classes
u8 union_chan = rtw_mi_get_union_chan(padapter);
/*Operating Class*/
if (union_chan > 14) {
if (union_chan >= 149)
/* Number of Channels
Just support 1 channel and this channel is AP's channel*/
/*Channel List*/
p2pie[p2pielen++] = union_chan;
/* Group ID Attribute */
p2pie[p2pielen++] = P2P_ATTR_GROUP_ID;
*(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen);
/* p2P Device Address */
_rtw_memcpy(p2pie + p2pielen , pwdinfo->device_addr, ETH_ALEN);
/* SSID */
_rtw_memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen);
p2pielen += pwdinfo->nego_ssidlen;
wfdielen = build_nego_resp_wfd_ie(pwdinfo, pframe);
void issue_p2p_GO_confirm(_adapter *padapter, u8 *raddr, u8 result)
u8 oui_subtype = P2P_GO_NEGO_CONF;
u8 p2pie[255] = { 0x00 };
/* According to the P2P Specification, the group negoitation request frame should contain 5 P2P attributes */
/* 3. Operating Channel */
/* 4. Channel List */
/* 5. Group ID ( if this WiFi is GO ) */
if (pwdinfo->peer_operating_ch <= 14) {
} else if ((pwdinfo->peer_operating_ch >= 36) && (pwdinfo->peer_operating_ch <= 48)) {
p2pie[p2pielen++] = pwdinfo->peer_operating_ch;
p2pie[p2pielen++] = pwdinfo->operating_channel; /* Use the listen channel as the operating channel */
*(u16 *)(p2pie + p2pielen) = 6;
wfdielen = build_nego_confirm_wfd_ie(pwdinfo, pframe);
void issue_p2p_invitation_request(_adapter *padapter, u8 *raddr)
u8 oui_subtype = P2P_INVIT_REQ;
u8 dialogToken = 3;
_rtw_memcpy(pwlanhdr->addr3, raddr, ETH_ALEN);
pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
/* Commented by Albert 20101011 */
/* According to the P2P Specification, the P2P Invitation request frame should contain 7 P2P attributes */
/* 1. Configuration Timeout */
/* 2. Invitation Flags */
/* 3. Operating Channel ( Only GO ) */
/* 4. P2P Group BSSID ( Should be included if I am the GO ) */
/* 5. Channel List */
/* 6. P2P Group ID */
/* 7. P2P Device Info */
/* Invitation Flags */
p2pie[p2pielen++] = P2P_ATTR_INVITATION_FLAGS;
p2pie[p2pielen++] = P2P_INVITATION_FLAGS_PERSISTENT;
if (pwdinfo->invitereq_info.operating_ch <= 14)
else if ((pwdinfo->invitereq_info.operating_ch >= 36) && (pwdinfo->invitereq_info.operating_ch <= 48))
p2pie[p2pielen++] = pwdinfo->invitereq_info.operating_ch; /* operating channel number */
if (_rtw_memcmp(adapter_mac_addr(padapter), pwdinfo->invitereq_info.go_bssid, ETH_ALEN)) {
/* P2P Group BSSID */
p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID;
/* P2P Device Address for GO */
_rtw_memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN);
/* P2P Group ID */
*(u16 *)(p2pie + p2pielen) = cpu_to_le16(6 + pwdinfo->invitereq_info.ssidlen);
_rtw_memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_ssid, pwdinfo->invitereq_info.ssidlen);
p2pielen += pwdinfo->invitereq_info.ssidlen;
*(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY);
_rtw_memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len);
wfdielen = build_invitation_req_wfd_ie(pwdinfo, pframe);
void issue_p2p_invitation_response(_adapter *padapter, u8 *raddr, u8 dialogToken, u8 status_code)
u8 oui_subtype = P2P_INVIT_RESP;
/* Commented by Albert 20101005 */
/* According to the P2P Specification, the P2P Invitation response frame should contain 5 P2P attributes */
/* 2. Configuration Timeout */
/* 4. P2P Group BSSID ( Only GO ) */
/* When status code is P2P_STATUS_FAIL_INFO_UNAVAILABLE. */
/* Sent the event receiving the P2P Invitation Req frame to DMP UI. */
/* DMP had to compare the MAC address to find out the profile. */
/* So, the WiFi driver will send the P2P_STATUS_FAIL_INFO_UNAVAILABLE to NB. */
/* If the UI found the corresponding profile, the WiFi driver sends the P2P Invitation Req */
/* to NB to rebuild the persistent group. */
p2pie[p2pielen++] = status_code;
if (status_code == P2P_STATUS_SUCCESS) {
/* The P2P Invitation request frame asks this Wi-Fi device to be the P2P GO */
/* In this case, the P2P Invitation response frame should carry the two more P2P attributes. */
/* First one is operating channel attribute. */
/* Second one is P2P Group BSSID attribute. */
wfdielen = build_invitation_resp_wfd_ie(pwdinfo, pframe);
void issue_p2p_provision_request(_adapter *padapter, u8 *pssid, u8 ussidlen, u8 *pdev_raddr)
u8 dialogToken = 1;
u8 oui_subtype = P2P_PROVISION_DISC_REQ;
u8 wpsie[100] = { 0x00 };
u8 wpsielen = 0;
_rtw_memcpy(pwlanhdr->addr1, pdev_raddr, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr3, pdev_raddr, ETH_ALEN);
p2pielen = build_prov_disc_request_p2p_ie(pwdinfo, pframe, pssid, ussidlen, pdev_raddr);
pframe += p2pielen;
pattrib->pktlen += p2pielen;
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD);
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->tx_prov_disc_info.wps_config_method_request);
wfdielen = build_provdisc_req_wfd_ie(pwdinfo, pframe);
u8 is_matched_in_profilelist(u8 *peermacaddr, struct profile_info *profileinfo)
u8 i, match_result = 0;
RTW_INFO("[%s] peermac = %.2X %.2X %.2X %.2X %.2X %.2X\n", __FUNCTION__,
peermacaddr[0], peermacaddr[1], peermacaddr[2], peermacaddr[3], peermacaddr[4], peermacaddr[5]);
for (i = 0; i < P2P_MAX_PERSISTENT_GROUP_NUM; i++, profileinfo++) {
RTW_INFO("[%s] profileinfo_mac = %.2X %.2X %.2X %.2X %.2X %.2X\n", __FUNCTION__,
profileinfo->peermac[0], profileinfo->peermac[1], profileinfo->peermac[2], profileinfo->peermac[3], profileinfo->peermac[4], profileinfo->peermac[5]);
if (_rtw_memcmp(peermacaddr, profileinfo->peermac, ETH_ALEN)) {
match_result = 1;
RTW_INFO("[%s] Match!\n", __FUNCTION__);
return match_result ;
void issue_probersp_p2p(_adapter *padapter, unsigned char *da)
unsigned char *mac;
u16 beacon_interval = 100;
u16 capInfo = 0;
u8 wpsie[255] = { 0x00 };
u32 wpsielen = 0, p2pielen = 0;
/* RTW_INFO("%s\n", __FUNCTION__); */
if (IS_CCK_RATE(pattrib->rate)) {
/* force OFDM 6M rate */
pattrib->rate = MGN_6M;
pattrib->raid = rtw_get_mgntframe_raid(padapter, WIRELESS_11G);
mac = adapter_mac_addr(padapter);
_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
/* Use the device address for BSSID field. */
_rtw_memcpy(pwlanhdr->addr3, mac, ETH_ALEN);
set_frame_sub_type(fctrl, WIFI_PROBERSP);
pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr);
pattrib->pktlen = pattrib->hdrlen;
pframe += pattrib->hdrlen;
/* timestamp will be inserted by hardware */
pframe += 8;
pattrib->pktlen += 8;
/* beacon interval: 2 bytes */
_rtw_memcpy(pframe, (unsigned char *) &beacon_interval, 2);
pframe += 2;
pattrib->pktlen += 2;
/* capability info: 2 bytes */
/* ESS and IBSS bits must be 0 (defined in the 3.1.2.1.1 of WiFi Direct Spec) */
capInfo |= cap_ShortPremble;
capInfo |= cap_ShortSlot;
_rtw_memcpy(pframe, (unsigned char *) &capInfo, 2);
pframe = rtw_set_ie(pframe, _SSID_IE_, 7, pwdinfo->p2p_wildcard_ssid, &pattrib->pktlen);
/* supported rates... */
/* Use the OFDM rate in the P2P probe response frame. ( 6(B), 9(B), 12, 18, 24, 36, 48, 54 ) */
pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pwdinfo->support_rate, &pattrib->pktlen);
/* DS parameter set */
pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&pwdinfo->listen_channel, &pattrib->pktlen);
if (adapter_wdev_data(padapter)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211) {
if (pmlmepriv->wps_probe_resp_ie != NULL && pmlmepriv->p2p_probe_resp_ie != NULL) {
/* WPS IE */
_rtw_memcpy(pframe, pmlmepriv->wps_probe_resp_ie, pmlmepriv->wps_probe_resp_ie_len);
pattrib->pktlen += pmlmepriv->wps_probe_resp_ie_len;
pframe += pmlmepriv->wps_probe_resp_ie_len;
/* P2P IE */
_rtw_memcpy(pframe, pmlmepriv->p2p_probe_resp_ie, pmlmepriv->p2p_probe_resp_ie_len);
pattrib->pktlen += pmlmepriv->p2p_probe_resp_ie_len;
pframe += pmlmepriv->p2p_probe_resp_ie_len;
/* Todo: WPS IE */
/* Noted by Albert 20100907 */
/* According to the WPS specification, all the WPS attribute is presented by Big Endian. */
/* WiFi Simple Config State */
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SIMPLE_CONF_STATE);
wpsie[wpsielen++] = WPS_WSC_STATE_NOT_CONFIG; /* Not Configured. */
/* Response Type */
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_RESP_TYPE);
wpsie[wpsielen++] = WPS_RESPONSE_TYPE_8021X;
/* UUID-E */
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E);
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0010);
if (pwdinfo->external_uuid == 0) {
_rtw_memset(wpsie + wpsielen, 0x0, 16);
_rtw_memcpy(wpsie + wpsielen, mac, ETH_ALEN);
_rtw_memcpy(wpsie + wpsielen, pwdinfo->uuid, 0x10);
wpsielen += 0x10;
/* Manufacturer */
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MANUFACTURER);
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0007);
_rtw_memcpy(wpsie + wpsielen, "Realtek", 7);
wpsielen += 7;
/* Model Name */
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NAME);
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0006);
_rtw_memcpy(wpsie + wpsielen, "8192CU", 6);
wpsielen += 6;
/* Model Number */
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NUMBER);
wpsie[wpsielen++] = 0x31; /* character 1 */
/* Serial Number */
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SERIAL_NUMBER);
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(ETH_ALEN);
_rtw_memcpy(wpsie + wpsielen, "123456" , ETH_ALEN);
wpsielen += ETH_ALEN;
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE);
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008);
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
*(u32 *)(wpsie + wpsielen) = cpu_to_be32(WPSOUI);
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->device_name_len);
_rtw_memcpy(wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len);
wpsielen += pwdinfo->device_name_len;
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->supported_wps_cm);
p2pielen = build_probe_resp_p2p_ie(pwdinfo, pframe);
wfdielen = rtw_append_probe_resp_wfd_ie(padapter, pframe);
/* Vendor Specific IE */
pattrib->pktlen += rtw_build_vendor_ie(padapter , &pframe , WIFI_P2P_PROBERESP_VENDOR_IE_BIT);
int _issue_probereq_p2p(_adapter *padapter, u8 *da, int wait_ack)
int ret = _FAIL;
u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
u16 wpsielen = 0, p2pielen = 0;
if (da) {
_rtw_memcpy(pwlanhdr->addr3, da, ETH_ALEN);
if ((pwdinfo->p2p_info.scan_op_ch_only) || (pwdinfo->rx_invitereq_info.scan_op_ch_only)) {
/* This two flags will be set when this is only the P2P client mode. */
_rtw_memcpy(pwlanhdr->addr1, pwdinfo->p2p_peer_interface_addr, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr3, pwdinfo->p2p_peer_interface_addr, ETH_ALEN);
/* broadcast probe request frame */
_rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN);
set_frame_sub_type(pframe, WIFI_PROBEREQ);
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ))
pframe = rtw_set_ie(pframe, _SSID_IE_, pwdinfo->tx_prov_disc_info.ssid.SsidLength, pwdinfo->tx_prov_disc_info.ssid.Ssid, &(pattrib->pktlen));
pframe = rtw_set_ie(pframe, _SSID_IE_, P2P_WILDCARD_SSID_LEN, pwdinfo->p2p_wildcard_ssid, &(pattrib->pktlen));
/* Use the OFDM rate in the P2P probe request frame. ( 6(B), 9(B), 12(B), 24(B), 36, 48, 54 ) */
if (pmlmepriv->wps_probe_req_ie != NULL && pmlmepriv->p2p_probe_req_ie != NULL) {
_rtw_memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len);
pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len;
pframe += pmlmepriv->wps_probe_req_ie_len;
_rtw_memcpy(pframe, pmlmepriv->p2p_probe_req_ie, pmlmepriv->p2p_probe_req_ie_len);
pattrib->pktlen += pmlmepriv->p2p_probe_req_ie_len;
pframe += pmlmepriv->p2p_probe_req_ie_len;
/* Noted by Albert 20110221 */
if (pmlmepriv->wps_probe_req_ie == NULL) {
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_RTK_WIDI);
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_RTK_DMP);
*(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); /* Registrar-specified */
/* Commented by Albert 20110221 */
/* According to the P2P Specification, the probe request frame should contain 5 P2P attributes */
/* 2. P2P Device ID if this probe request wants to find the specific P2P device */
/* 3. Listen Channel */
/* 4. Extended Listen Timing */
/* 5. Operating Channel if this WiFi is working as the group owner now */
p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT;
p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT;
p2pie[p2pielen++] = pwdinfo->listen_channel; /* listen channel */
/* Extended Listen Timing */
/* Operating Channel (if this WiFi is working as the group owner now) */
wfdielen = rtw_append_probe_req_wfd_ie(padapter, pframe);
pattrib->pktlen += rtw_build_vendor_ie(padapter , &pframe , WIFI_P2P_PROBEREQ_VENDOR_IE_BIT);
if (wait_ack)
ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe);
inline void issue_probereq_p2p(_adapter *adapter, u8 *da)
_issue_probereq_p2p(adapter, da, _FALSE);
* wait_ms == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT
* wait_ms > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX
* try_cnt means the maximal TX count to try
int issue_probereq_p2p_ex(_adapter *adapter, u8 *da, int try_cnt, int wait_ms)
int i = 0;
systime start = rtw_get_current_time();
do {
ret = _issue_probereq_p2p(adapter, da, wait_ms > 0 ? _TRUE : _FALSE);
i++;
if (RTW_CANNOT_RUN(adapter))
if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
rtw_msleep_os(wait_ms);
} while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
if (ret != _FAIL) {
#ifndef DBG_XMIT_ACK
if (try_cnt && wait_ms) {
if (da)
RTW_INFO(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d in %u ms\n",
FUNC_ADPT_ARG(adapter), MAC_ARG(da), rtw_get_oper_ch(adapter),
ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
RTW_INFO(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
FUNC_ADPT_ARG(adapter), rtw_get_oper_ch(adapter),
s32 rtw_action_public_decache(union recv_frame *rframe, u8 token_offset)
_adapter *adapter = rframe->u.hdr.adapter;
struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv);
u16 seq_ctrl = ((rframe->u.hdr.attrib.seq_num & 0xffff) << 4) | (rframe->u.hdr.attrib.frag_num & 0xf);
u8 token = *(rframe->u.hdr.rx_data + sizeof(struct rtw_ieee80211_hdr_3addr) + token_offset);
if (GetRetry(frame)) {
if ((seq_ctrl == mlmeext->action_public_rxseq)
&& (token == mlmeext->action_public_dialog_token)
RTW_INFO(FUNC_ADPT_FMT" seq_ctrl=0x%x, rxseq=0x%x, token:%d\n",
FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq, token);
/* TODO: per sta seq & token */
mlmeext->action_public_rxseq = seq_ctrl;
mlmeext->action_public_dialog_token = token;
unsigned int on_action_public_p2p(union recv_frame *precv_frame)
_adapter *padapter = precv_frame->u.hdr.adapter;
u8 *frame_body;
u8 *p2p_ie;
u32 p2p_ielen;
u8 result = P2P_STATUS_SUCCESS;
u8 empty_addr[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
u8 *merged_p2pie = NULL;
u32 merged_p2p_ielen = 0;
struct roch_info *prochinfo = &padapter->rochinfo;
if (adapter_wdev_data(padapter)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211)
rtw_cfg80211_rx_p2p_action_public(padapter, precv_frame);
/* Do nothing if the driver doesn't enable the P2P function. */
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE))
len -= sizeof(struct rtw_ieee80211_hdr_3addr);
switch (frame_body[6]) { /* OUI Subtype */
case P2P_GO_NEGO_REQ: {
RTW_INFO("[%s] Got GO Nego Req Frame\n", __FUNCTION__);
_rtw_memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info));
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ))
rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) {
/* Commented by Albert 20110526 */
/* In this case, this means the previous nego fail doesn't be reset yet. */
_cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
/* Restore the previous p2p state */
RTW_INFO("[%s] Restore the previous p2p state to %d\n", __FUNCTION__, rtw_p2p_state(pwdinfo));
if (rtw_mi_buddy_check_fwstate(padapter, WIFI_ASOC_STATE))
_cancel_timer_ex(&prochinfo->ap_roch_ch_switch_timer);
/* Commented by Kurt 20110902 */
/* Add if statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */
if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING))
rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
/* Get peer_dev_addr here if peer doesn't issue prov_disc frame. */
if (_rtw_memcmp(pwdinfo->rx_prov_disc_info.peerDevAddr, empty_addr, ETH_ALEN))
_rtw_memcpy(pwdinfo->rx_prov_disc_info.peerDevAddr, get_addr2_ptr(pframe), ETH_ALEN);
result = process_p2p_group_negotation_req(pwdinfo, frame_body, len);
issue_p2p_GO_response(padapter, get_addr2_ptr(pframe), frame_body, len, result);
/* Commented by Albert 20110718 */
/* No matter negotiating or negotiation failure, the driver should set up the restore P2P state timer. */
/* Commented by Albert 20120107 */
_set_timer(&pwdinfo->restore_p2p_state_timer, 3000);
#else /* CONFIG_CONCURRENT_MODE */
_set_timer(&pwdinfo->restore_p2p_state_timer, 5000);
case P2P_GO_NEGO_RESP: {
RTW_INFO("[%s] Got GO Nego Resp Frame\n", __FUNCTION__);
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) {
/* Commented by Albert 20110425 */
/* The restore timer is enabled when issuing the nego request frame of rtw_p2p_connect function. */
result = process_p2p_group_negotation_resp(pwdinfo, frame_body, len);
issue_p2p_GO_confirm(pwdinfo->padapter, get_addr2_ptr(pframe), result);
if (P2P_STATUS_SUCCESS == result) {
if (rtw_p2p_role(pwdinfo) == P2P_ROLE_CLIENT) {
pwdinfo->p2p_info.operation_ch[0] = pwdinfo->peer_operating_ch;
#ifdef CONFIG_P2P_OP_CHK_SOCIAL_CH
pwdinfo->p2p_info.operation_ch[1] = 1; /* Check whether GO is operating in channel 1; */
pwdinfo->p2p_info.operation_ch[2] = 6; /* Check whether GO is operating in channel 6; */
pwdinfo->p2p_info.operation_ch[3] = 11; /* Check whether GO is operating in channel 11; */
#endif /* CONFIG_P2P_OP_CHK_SOCIAL_CH */
pwdinfo->p2p_info.scan_op_ch_only = 1;
_set_timer(&pwdinfo->reset_ch_sitesurvey2, P2P_RESET_SCAN_CH);
/* Reset the dialog token for group negotiation frames. */
pwdinfo->negotiation_dialog_token = 1;
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL))
RTW_INFO("[%s] Skipped GO Nego Resp Frame (p2p_state != P2P_STATE_GONEGO_ING)\n", __FUNCTION__);
case P2P_GO_NEGO_CONF: {
RTW_INFO("[%s] Got GO Nego Confirm Frame\n", __FUNCTION__);
result = process_p2p_group_negotation_confirm(pwdinfo, frame_body, len);
case P2P_INVIT_REQ: {
/* Added by Albert 2010/10/05 */
/* Received the P2P Invite Request frame. */
RTW_INFO("[%s] Got invite request frame!\n", __FUNCTION__);
p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen);
if (p2p_ie) {
/* Parse the necessary information from the P2P Invitation Request frame. */
/* For example: The MAC address of sending this P2P Invitation Request frame. */
u32 attr_contentlen = 0;
u8 status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
struct group_id_info group_id;
u8 invitation_flag = 0;
merged_p2p_ielen = rtw_get_p2p_merged_ies_len(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_);
merged_p2pie = rtw_zmalloc(merged_p2p_ielen + 2); /* 2 is for EID and Length */
if (merged_p2pie == NULL) {
RTW_INFO("[%s] Malloc p2p ie fail\n", __FUNCTION__);
_rtw_memset(merged_p2pie, 0x00, merged_p2p_ielen);
merged_p2p_ielen = rtw_p2p_merge_ies(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, merged_p2pie);
rtw_get_p2p_attr_content(merged_p2pie, merged_p2p_ielen, P2P_ATTR_INVITATION_FLAGS, &invitation_flag, &attr_contentlen);
if (attr_contentlen) {
rtw_get_p2p_attr_content(merged_p2pie, merged_p2p_ielen, P2P_ATTR_GROUP_BSSID, pwdinfo->p2p_peer_interface_addr, &attr_contentlen);
/* Commented by Albert 20120510 */
/* Copy to the pwdinfo->p2p_peer_interface_addr. */
/* So that the WFD UI ( or Sigma ) can get the peer interface address by using the following command. */
/* #> iwpriv wlan0 p2p_get peer_ifa */
/* After having the peer interface address, the sigma can find the correct conf file for wpa_supplicant. */
RTW_INFO("[%s] GO's BSSID = %.2X %.2X %.2X %.2X %.2X %.2X\n", __FUNCTION__,
pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1],
pwdinfo->p2p_peer_interface_addr[2], pwdinfo->p2p_peer_interface_addr[3],
pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]);
if (invitation_flag & P2P_INVITATION_FLAGS_PERSISTENT) {
/* Re-invoke the persistent group. */
_rtw_memset(&group_id, 0x00, sizeof(struct group_id_info));
rtw_get_p2p_attr_content(merged_p2pie, merged_p2p_ielen, P2P_ATTR_GROUP_ID, (u8 *) &group_id, &attr_contentlen);
if (_rtw_memcmp(group_id.go_device_addr, adapter_mac_addr(padapter), ETH_ALEN)) {
/* The p2p device sending this p2p invitation request wants this Wi-Fi device to be the persistent GO. */
rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_GO);
rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
status_code = P2P_STATUS_SUCCESS;
/* The p2p device sending this p2p invitation request wants to be the persistent GO. */
if (is_matched_in_profilelist(pwdinfo->p2p_peer_interface_addr, &pwdinfo->profileinfo[0])) {
u8 operatingch_info[5] = { 0x00 };
if (rtw_get_p2p_attr_content(merged_p2pie, merged_p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info,
&attr_contentlen)) {
if (rtw_chset_search_ch(adapter_to_chset(padapter), (u32)operatingch_info[4]) >= 0) {
/* The operating channel is acceptable for this device. */
pwdinfo->rx_invitereq_info.operation_ch[0] = operatingch_info[4];
pwdinfo->rx_invitereq_info.operation_ch[1] = 1; /* Check whether GO is operating in channel 1; */
pwdinfo->rx_invitereq_info.operation_ch[2] = 6; /* Check whether GO is operating in channel 6; */
pwdinfo->rx_invitereq_info.operation_ch[3] = 11; /* Check whether GO is operating in channel 11; */
pwdinfo->rx_invitereq_info.scan_op_ch_only = 1;
_set_timer(&pwdinfo->reset_ch_sitesurvey, P2P_RESET_SCAN_CH);
rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH);
rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
/* The operating channel isn't supported by this device. */
rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH);
rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
status_code = P2P_STATUS_FAIL_NO_COMMON_CH;
/* Commented by Albert 20121130 */
/* Intel will use the different P2P IE to store the operating channel information */
/* Workaround for Intel WiDi 3.5 */
status_code = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP;
RTW_INFO("[%s] P2P Group ID Attribute NOT FOUND!\n", __FUNCTION__);
status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
/* Received the invitation to join a P2P group. */
/* In this case, the GO can't be myself. */
/* The p2p device sending this p2p invitation request wants to join an existing P2P group */
/* Commented by Albert 2012/06/28 */
/* In this case, this Wi-Fi device should use the iwpriv command to get the peer device address. */
/* The peer device address should be the destination address for the provisioning discovery request. */
/* Then, this Wi-Fi device should use the iwpriv command to get the peer interface address. */
/* The peer interface address should be the address for WPS mac address */
_rtw_memcpy(pwdinfo->p2p_peer_device_addr, group_id.go_device_addr , ETH_ALEN);
rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_JOIN);
RTW_INFO("[%s] P2P Invitation Flags Attribute NOT FOUND!\n", __FUNCTION__);
RTW_INFO("[%s] status_code = %d\n", __FUNCTION__, status_code);
pwdinfo->inviteresp_info.token = frame_body[7];
issue_p2p_invitation_response(padapter, get_addr2_ptr(pframe), pwdinfo->inviteresp_info.token, status_code);
case P2P_INVIT_RESP: {
u8 attr_content = 0x00;
RTW_INFO("[%s] Got invite response frame!\n", __FUNCTION__);
rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen);
if (attr_contentlen == 1) {
RTW_INFO("[%s] Status = %d\n", __FUNCTION__, attr_content);
if (attr_content == P2P_STATUS_SUCCESS) {
if (_rtw_memcmp(pwdinfo->invitereq_info.go_bssid, adapter_mac_addr(padapter), ETH_ALEN))
rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_OK);
rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL);
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL))
case P2P_DEVDISC_REQ:
process_p2p_devdisc_req(pwdinfo, pframe, len);
case P2P_DEVDISC_RESP:
process_p2p_devdisc_resp(pwdinfo, pframe, len);
case P2P_PROVISION_DISC_REQ:
RTW_INFO("[%s] Got Provisioning Discovery Request Frame\n", __FUNCTION__);
process_p2p_provdisc_req(pwdinfo, pframe, len);
/* 20110902 Kurt */
/* Add the following statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */
if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ))
rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ);
_set_timer(&pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT);
case P2P_PROVISION_DISC_RESP:
/* Commented by Albert 20110707 */
/* Should we check the pwdinfo->tx_prov_disc_info.bsent flag here?? */
RTW_INFO("[%s] Got Provisioning Discovery Response Frame\n", __FUNCTION__);
/* Commented by Albert 20110426 */
/* The restore timer is enabled when issuing the provisioing request frame in rtw_p2p_prov_disc function. */
rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_RSP);
process_p2p_provdisc_resp(pwdinfo, pframe);
if (merged_p2pie)
rtw_mfree(merged_p2pie, merged_p2p_ielen + 2);
unsigned int on_action_public_vendor(union recv_frame *precv_frame)
u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
_adapter *adapter = precv_frame->u.hdr.adapter;
char msg[64];
if (_rtw_memcmp(frame_body + 2, P2P_OUI, 4) == _TRUE) {
if (rtw_action_public_decache(precv_frame, 7) == _FAIL)
if (!hal_chk_wl_func(precv_frame->u.hdr.adapter, WL_FUNC_MIRACAST))
rtw_rframe_del_wfd_ie(precv_frame, 8);
ret = on_action_public_p2p(precv_frame);
} else if (_rtw_memcmp(frame_body + 2, DPP_OUI, 4) == _TRUE) {
u8 dpp_type = frame_body[7];
cnt += sprintf((msg + cnt), "DPP(type:%u)", dpp_type);
rtw_cfg80211_rx_action(adapter, precv_frame, msg);
unsigned int on_action_public_default(union recv_frame *precv_frame, u8 action)
u8 token;
token = frame_body[2];
if (rtw_action_public_decache(precv_frame, 2) == _FAIL)
cnt += sprintf((msg + cnt), "%s(token:%u)", action_public_str(action), token);
unsigned int on_action_public(_adapter *padapter, union recv_frame *precv_frame)
/* check RA matches or broadcast */
if (!(_rtw_memcmp(adapter_mac_addr(padapter), GetAddr1Ptr(pframe), ETH_ALEN) ||
is_broadcast_mac_addr(GetAddr1Ptr(pframe))))
if (category != RTW_WLAN_CATEGORY_PUBLIC)
case ACT_PUBLIC_BSSCOEXIST:
/*20/40 BSS Coexistence Management frame is a Public Action frame*/
if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE)
rtw_process_public_act_bsscoex(padapter, pframe, frame_len);
#endif /*CONFIG_AP_MODE*/
#endif /*CONFIG_80211N_HT*/
case ACT_PUBLIC_VENDOR:
ret = on_action_public_vendor(precv_frame);
ret = on_action_public_default(precv_frame, action);
unsigned int OnAction_ft(_adapter *padapter, union recv_frame *precv_frame)
u32 ret = _FAIL;
u32 frame_len = 0;
u8 action_code = 0;
u8 category = 0;
u8 *pframe = NULL;
u8 *pframe_body = NULL;
u8 tgt_addr[ETH_ALEN];
u8 *pie = NULL;
u32 ft_ie_len = 0;
u32 status_code = 0;
struct mlme_ext_priv *pmlmeext = NULL;
struct mlme_ext_info *pmlmeinfo = NULL;
struct mlme_priv *pmlmepriv = NULL;
struct wlan_network *proam_target = NULL;
struct ft_roam_info *pft_roam = NULL;
pmlmeext = &(padapter->mlmeextpriv);
pmlmeinfo = &(pmlmeext->mlmext_info);
pmlmepriv = &(padapter->mlmepriv);
pft_roam = &(pmlmepriv->ft_roam);
pframe = precv_frame->u.hdr.rx_data;
frame_len = precv_frame->u.hdr.len;
pframe_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
category = pframe_body[0];
if (category != RTW_WLAN_CATEGORY_FT)
action_code = pframe_body[1];
switch (action_code) {
case RTW_WLAN_ACTION_FT_RSP:
RTW_INFO("FT: RTW_WLAN_ACTION_FT_RSP recv.\n");
if (!_rtw_memcmp(adapter_mac_addr(padapter), &pframe_body[2], ETH_ALEN)) {
RTW_ERR("FT: Unmatched STA MAC Address "MAC_FMT"\n", MAC_ARG(&pframe_body[2]));
status_code = le16_to_cpu(*(u16 *)((SIZE_PTR)pframe + sizeof(struct rtw_ieee80211_hdr_3addr) + 14));
if (status_code != 0) {
RTW_ERR("FT: WLAN ACTION FT RESPONSE fail, status: %d\n", status_code);
_rtw_memcpy(tgt_addr, &pframe_body[8], ETH_ALEN);
if (is_zero_mac_addr(tgt_addr) || is_broadcast_mac_addr(tgt_addr)) {
RTW_ERR("FT: Invalid Target MAC Address "MAC_FMT"\n", MAC_ARG(tgt_addr));
pie = rtw_get_ie(pframe_body, _MDIE_, &ft_ie_len, frame_len);
if (pie) {
if (!_rtw_memcmp(&pft_roam->mdid, pie+2, 2)) {
RTW_ERR("FT: Invalid MDID\n");
rtw_ft_set_status(padapter, RTW_FT_REQUESTED_STA);
_cancel_timer_ex(&pmlmeext->ft_link_timer);
/*Disconnect current AP*/
receive_disconnect(padapter, pmlmepriv->cur_network.network.MacAddress, WLAN_REASON_ACTIVE_ROAM, _FALSE);
pft_roam->ft_action_len = frame_len;
_rtw_memcpy(pft_roam->ft_action, pframe, rtw_min(frame_len, RTW_FT_MAX_IE_SZ));
case RTW_WLAN_ACTION_FT_REQ:
case RTW_WLAN_ACTION_FT_CONF:
case RTW_WLAN_ACTION_FT_ACK:
RTW_ERR("FT: Unsupported FT Action!\n");
unsigned int OnAction_ht(_adapter *padapter, union recv_frame *precv_frame)
if (category != RTW_WLAN_CATEGORY_HT)
case RTW_WLAN_ACTION_HT_SM_PS:
rtw_process_ht_action_smps(padapter, get_addr2_ptr(pframe), frame_body[2]);
case RTW_WLAN_ACTION_HT_COMPRESS_BEAMFORMING:
#ifdef CONFIG_BEAMFORMING
/*RTW_INFO("RTW_WLAN_ACTION_HT_COMPRESS_BEAMFORMING\n");*/
rtw_beamforming_get_report_frame(padapter, precv_frame);
#endif /*CONFIG_BEAMFORMING*/
unsigned int OnAction_sa_query(_adapter *padapter, union recv_frame *precv_frame)
u16 tid;
/* Baron */
RTW_INFO("OnAction_sa_query\n");
switch (pframe[WLAN_HDR_A3_LEN + 1]) {
case 0: /* SA Query req */
_rtw_memcpy(&tid, &pframe[WLAN_HDR_A3_LEN + 2], sizeof(u16));
RTW_INFO("OnAction_sa_query request,action=%d, tid=%04x, pframe=%02x-%02x\n"
, pframe[WLAN_HDR_A3_LEN + 1], tid, pframe[WLAN_HDR_A3_LEN + 2], pframe[WLAN_HDR_A3_LEN + 3]);
issue_action_SA_Query(padapter, get_addr2_ptr(pframe), 1, tid, IEEE80211W_RIGHT_KEY);
case 1: /* SA Query rsp */
_cancel_timer_ex(&psta->dot11w_expire_timer);
RTW_INFO("OnAction_sa_query response,action=%d, tid=%04x, cancel timer\n", pframe[WLAN_HDR_A3_LEN + 1], tid);
if (0) {
int pp;
printk("pattrib->pktlen = %d =>", pattrib->pkt_len);
for (pp = 0; pp < pattrib->pkt_len; pp++)
printk(" %02x ", pframe[pp]);
printk("\n");
unsigned int on_action_rm(_adapter *padapter, union recv_frame *precv_frame)
return rm_on_action(padapter, precv_frame);
#endif /* CONFIG_RTW_80211K */
unsigned int OnAction_wmm(_adapter *padapter, union recv_frame *precv_frame)
unsigned int OnAction_vht(_adapter *padapter, union recv_frame *precv_frame)
struct rtw_ieee80211_hdr_3addr *whdr = (struct rtw_ieee80211_hdr_3addr *)pframe;
if (category != RTW_WLAN_CATEGORY_VHT)
case RTW_WLAN_ACTION_VHT_COMPRESSED_BEAMFORMING:
/*RTW_INFO("RTW_WLAN_ACTION_VHT_COMPRESSED_BEAMFORMING\n");*/
case RTW_WLAN_ACTION_VHT_OPMODE_NOTIFICATION:
/* CategoryCode(1) + ActionCode(1) + OpModeNotification(1) */
/* RTW_INFO("RTW_WLAN_ACTION_VHT_OPMODE_NOTIFICATION\n"); */
psta = rtw_get_stainfo(&padapter->stapriv, whdr->addr2);
if (psta)
rtw_process_vht_op_mode_notify(padapter, &frame_body[2], psta);
case RTW_WLAN_ACTION_VHT_GROUPID_MANAGEMENT:
#ifdef RTW_BEAMFORMING_VERSION_2
rtw_beamforming_get_vht_gid_mgnt_frame(padapter, precv_frame);
#endif /* RTW_BEAMFORMING_VERSION_2 */
#endif /* CONFIG_BEAMFORMING */
#endif /* CONFIG_80211AC_VHT */
unsigned int OnAction_p2p(_adapter *padapter, union recv_frame *precv_frame)
u8 category, OUI_Subtype, dialogToken = 0;
if (category != RTW_WLAN_CATEGORY_P2P)
if (cpu_to_be32(*((u32 *)(frame_body + 1))) != P2POUI)
if (adapter_wdev_data(padapter)->p2p_enabled
&& pwdinfo->driver_interface == DRIVER_CFG80211
rtw_cfg80211_rx_action_p2p(padapter, precv_frame);
OUI_Subtype = frame_body[5];
dialogToken = frame_body[6];
switch (OUI_Subtype) {
case P2P_NOTICE_OF_ABSENCE:
case P2P_PRESENCE_REQUEST:
process_p2p_presence_req(pwdinfo, pframe, len);
case P2P_PRESENCE_RESPONSE:
case P2P_GO_DISC_REQUEST:
unsigned int OnAction_tbtx_token(_adapter *padapter, union recv_frame *precv_frame)
#define TOKEN_REQ 0x00
#define TOKEN_REL 0x01
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
u32 xmit_time;
u8 *src=NULL, *pframe = precv_frame->u.hdr.rx_data;
u8 tbtx_action_code;
u8 i, nr_send;
uint tx_duration = 0;
if (padapter->tbtx_capability == _FALSE)
tbtx_action_code = *(pframe + WLAN_HDR_A3_LEN + 1);
switch (tbtx_action_code)
case TOKEN_REQ:
// parse duration
tx_duration = le32_to_cpu(*(uint *)(pframe + WLAN_HDR_A3_LEN + 2));
padapter->tbtx_duration = tx_duration/1000; // Mirocsecond to Millisecond
ATOMIC_SET(&padapter->tbtx_tx_pause, _FALSE);
rtw_tx_control_cmd(padapter);
_set_timer(&pmlmeext->tbtx_xmit_timer, padapter->tbtx_duration);
ATOMIC_SET(&padapter->tbtx_remove_tx_pause, _FALSE);
#if defined(CONFIG_SDIO_HCI) && !defined(CONFIG_SDIO_TX_TASKLET)
_rtw_up_sema(&pxmitpriv->SdioXmitSema);
tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
case TOKEN_REL:
src = get_addr2_ptr(pframe);
if (!src)
psta = rtw_get_stainfo(&padapter->stapriv, src);
if (ATOMIC_READ(&pstapriv->nr_token_keeper) < 1)
for (i=0; i< NR_MAXSTA_INSLOT; i++) {
if (pstapriv->token_holder[i] == psta) {
pstapriv->token_holder[i] = NULL;
//RTW_INFO("macaddr1:" MAC_FMT "\n", MAC_ARG(psta->cmn.mac_addr));
ATOMIC_DEC(&pstapriv->nr_token_keeper);
if (ATOMIC_READ(&pstapriv->nr_token_keeper) == 0)
_set_timer(&pmlmeext->tbtx_token_dispatch_timer, 1);
RTW_INFO("Undefined Action Code\n");
void rtw_issue_action_token_rel(_adapter *padapter)
// Todo:
// gen token
/* Token Release Format
Category code : 1 Byte
Action code : 1 Byte */
//u16 *fctrl;
u8 val = 0x01;
u8 category = RTW_WLAN_CATEGORY_TBTX;
u8 *pframe;
//struct sta_info *psta;
//struct sta_priv *pstapriv = &padapter->stapriv;
//struct registry_priv *pregpriv = &padapter->registrypriv;
if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
/*update attribute */
pattrib->rate = MGN_24M; /* issue action release using OFDM rate? 20190716 Bruce add */
//fctrl = &(pwlanhdr->frame_ctl);
//*(fctrl) = 0;
_rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
// SetSeqNum??
pframe = rtw_set_fixed_ie(pframe, 1, &(val), &(pattrib->pktlen));
//RTW_INFO("%s\n", __func__);
unsigned int OnAction(_adapter *padapter, union recv_frame *precv_frame)
unsigned char category;
struct action_handler *ptable;
for (i = 0; i < sizeof(OnAction_tbl) / sizeof(struct action_handler); i++) {
ptable = &OnAction_tbl[i];
if (category == ptable->num)
unsigned int DoReserved(_adapter *padapter, union recv_frame *precv_frame)
/* RTW_INFO("rcvd mgt frame(%x, %x)\n", (get_frame_sub_type(pframe) >> 4), *(unsigned int *)GetAddr1Ptr(pframe)); */
struct xmit_frame *_alloc_mgtxmitframe(struct xmit_priv *pxmitpriv, bool once)
struct xmit_buf *pxmitbuf;
if (once)
pmgntframe = rtw_alloc_xmitframe_once(pxmitpriv);
pmgntframe = rtw_alloc_xmitframe_ext(pxmitpriv);
if (pmgntframe == NULL) {
RTW_INFO(FUNC_ADPT_FMT" alloc xmitframe fail, once:%d\n", FUNC_ADPT_ARG(pxmitpriv->adapter), once);
pxmitbuf = rtw_alloc_xmitbuf_ext(pxmitpriv);
if (pxmitbuf == NULL) {
RTW_INFO(FUNC_ADPT_FMT" alloc xmitbuf fail\n", FUNC_ADPT_ARG(pxmitpriv->adapter));
rtw_free_xmitframe(pxmitpriv, pmgntframe);
pmgntframe = NULL;
pmgntframe->frame_tag = MGNT_FRAMETAG;
pmgntframe->pxmitbuf = pxmitbuf;
pmgntframe->buf_addr = pxmitbuf->pbuf;
pxmitbuf->priv_data = pmgntframe;
return pmgntframe;
inline struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv)
return _alloc_mgtxmitframe(pxmitpriv, _FALSE);
inline struct xmit_frame *alloc_mgtxmitframe_once(struct xmit_priv *pxmitpriv)
return _alloc_mgtxmitframe(pxmitpriv, _TRUE);
Following are some TX fuctions for WiFi MLME
void update_mgnt_tx_rate(_adapter *padapter, u8 rate)
pmlmeext->tx_rate = rate;
/* RTW_INFO("%s(): rate = %x\n",__FUNCTION__, rate); */
void update_monitor_frame_attrib(_adapter *padapter, struct pkt_attrib *pattrib)
u8 wireless_mode;
psta = rtw_get_stainfo(pstapriv, pattrib->ra);
pattrib->hdrlen = 24;
pattrib->nr_frags = 1;
pattrib->priority = 7;
pattrib->mac_id = RTW_DEFAULT_MGMT_MACID;
pattrib->qsel = QSLT_MGNT;
pattrib->pktlen = 0;
if (pmlmeext->tx_rate == IEEE80211_CCK_RATE_1MB)
wireless_mode = WIRELESS_11B;
wireless_mode = WIRELESS_11G;
pattrib->raid = rtw_get_mgntframe_raid(padapter, wireless_mode);
if (pHalData->rf_type == RF_1T1R)
pattrib->raid = RATEID_IDX_VHT_1SS;
else if (pHalData->rf_type == RF_2T2R || pHalData->rf_type == RF_2T4R)
pattrib->raid = RATEID_IDX_VHT_2SS;
else if (pHalData->rf_type == RF_3T3R)
pattrib->raid = RATEID_IDX_VHT_3SS;
pattrib->raid = RATEID_IDX_BGN_40M_1SS;
pattrib->rate = MGN_VHT1SS_MCS9;
pattrib->rate = MGN_MCS7;
pattrib->encrypt = _NO_PRIVACY_;
pattrib->bswenc = _FALSE;
pattrib->qos_en = _FALSE;
pattrib->ht_en = 1;
pattrib->bwmode = CHANNEL_WIDTH_20;
pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
pattrib->sgi = _FALSE;
pattrib->seqnum = pmlmeext->mgnt_seq;
pattrib->retry_ctrl = _TRUE;
pattrib->mbssid = 0;
pattrib->hw_ssn_sel = pxmitpriv->hw_ssn_seq_no;
#ifdef CONFIG_RTW_MGMT_QUEUE
void update_mgntframe_subtype(_adapter *padapter, struct xmit_frame *pmgntframe)
struct pkt_attrib *pattrib = &pmgntframe->attrib;
u8 subtype, category ,action;
subtype = get_frame_sub_type(pframe); /* bit(7)~bit(2) */
pattrib->subtype = subtype;
rtw_action_frame_parse(pframe, pattrib->pktlen, &category, &action);
if ((subtype == WIFI_ACTION && !(action == ACT_PUBLIC_FTM_REQ || action == ACT_PUBLIC_FTM)) ||
subtype == WIFI_DISASSOC || subtype == WIFI_DEAUTH ||
(subtype == WIFI_PROBERSP && MLME_IS_ADHOC(padapter)))
pattrib->ps_dontq = 0;
pattrib->ps_dontq = 1;
void update_mgntframe_attrib(_adapter *padapter, struct pkt_attrib *pattrib)
#ifdef CONFIG_P2P_PS_NOA_USE_MACID_SLEEP
#endif /* CONFIG_P2P_PS_NOA_USE_MACID_SLEEP */
/* _rtw_memset((u8 *)(pattrib), 0, sizeof(struct pkt_attrib)); */
#ifdef CONFIG_MCC_MODE
update_mcc_mgntframe_attrib(padapter, pattrib);
if (MLME_IS_GC(padapter)) {
if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) {
WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network);
psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress);
/* use macid sleep during NoA, mgmt frame use ac queue & ap macid */
pattrib->mac_id = psta->cmn.mac_id;
pattrib->qsel = QSLT_VO;
if (pwdinfo->p2p_ps_state != P2P_PS_DISABLE)
RTW_ERR("%s , psta was NULL\n", __func__);
if (IS_CCK_RATE(pmlmeext->tx_rate))
pattrib->rate = pmlmeext->tx_rate;
pattrib->ht_en = _FALSE;
void update_mgntframe_attrib_addr(_adapter *padapter, struct xmit_frame *pmgntframe)
#if defined(CONFIG_BEAMFORMING) || defined(CONFIG_ANTENNA_DIVERSITY) || defined(CONFIG_RTW_MGMT_QUEUE)
_rtw_memcpy(pattrib->ra, GetAddr1Ptr(pframe), ETH_ALEN);
_rtw_memcpy(pattrib->ta, get_addr2_ptr(pframe), ETH_ALEN);
sta = pattrib->psta;
if (!sta) {
sta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra);
pattrib->psta = sta;
if (sta)
update_attrib_txbf_info(padapter, pattrib, sta);
#endif /* defined(CONFIG_BEAMFORMING) || defined(CONFIG_ANTENNA_DIVERSITY) || defined(CONFIG_RTW_MGMT_QUEUE) */
void dump_mgntframe(_adapter *padapter, struct xmit_frame *pmgntframe)
if (RTW_CANNOT_RUN(padapter)) {
rtw_free_xmitbuf(&padapter->xmitpriv, pmgntframe->pxmitbuf);
rtw_free_xmitframe(&padapter->xmitpriv, pmgntframe);
rtw_hal_mgnt_xmit(padapter, pmgntframe);
s32 dump_mgntframe_and_wait(_adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms)
s32 ret = _FAIL;
struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf;
struct submit_ctx sctx;
rtw_sctx_init(&sctx, timeout_ms);
pxmitbuf->sctx = &sctx;
ret = rtw_hal_mgnt_xmit(padapter, pmgntframe);
if (ret == _SUCCESS
|| ret == RTW_QUEUE_MGMT
ret = rtw_sctx_wait(&sctx, __func__);
_enter_critical(&pxmitpriv->lock_sctx, &irqL);
pxmitbuf->sctx = NULL;
_exit_critical(&pxmitpriv->lock_sctx, &irqL);
s32 dump_mgntframe_and_wait_ack_timeout(_adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms)
#ifdef CONFIG_XMIT_ACK
static u8 seq_no = 0;
struct xmit_priv *pxmitpriv = &(GET_PRIMARY_ADAPTER(padapter))->xmitpriv;
_enter_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL);
pxmitpriv->ack_tx = _TRUE;
pxmitpriv->seq_no = seq_no++;
pmgntframe->ack_report = 1;
rtw_sctx_init(&(pxmitpriv->ack_tx_ops), timeout_ms);
ret = rtw_sctx_wait(&(pxmitpriv->ack_tx_ops), __func__);
pxmitpriv->ack_tx = _FALSE;
_exit_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL);
#else /* !CONFIG_XMIT_ACK */
rtw_msleep_os(50);
#endif /* !CONFIG_XMIT_ACK */
s32 dump_mgntframe_and_wait_ack(_adapter *padapter, struct xmit_frame *pmgntframe)
/* In this case, use 500 ms as the default wait_ack timeout */
return dump_mgntframe_and_wait_ack_timeout(padapter, pmgntframe, 500);
int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode)
u8 *ssid_ie;
sint ssid_len_ori;
int len_diff = 0;
ssid_ie = rtw_get_ie(ies, WLAN_EID_SSID, &ssid_len_ori, ies_len);
/* RTW_INFO("%s hidden_ssid_mode:%u, ssid_ie:%p, ssid_len_ori:%d\n", __FUNCTION__, hidden_ssid_mode, ssid_ie, ssid_len_ori); */
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;
_rtw_memcpy(ssid_ie + 2, next_ie, remain_len);
len_diff -= ssid_len_ori;
case 2:
_rtw_memset(&ssid_ie[2], 0, ssid_len_ori);
return len_diff;
void issue_beacon(_adapter *padapter, int timeout_ms)
unsigned int rate_len;
#if defined(CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME)
#endif /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */
#ifdef CONFIG_BCN_ICF
pmgntframe = rtw_alloc_bcnxmitframe(pxmitpriv);
RTW_INFO("%s, alloc mgnt frame fail\n", __FUNCTION__);
_enter_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
pattrib->qsel = QSLT_BEACON;
#if defined(CONFIG_CONCURRENT_MODE) && (!defined(CONFIG_SWTIMER_BASED_TXBCN))
if (padapter->hw_port == HW_PORT1)
pattrib->mbssid = 1;
#ifdef CONFIG_FW_HANDLE_TXBCN
if (padapter->vap_id != CONFIG_LIMITED_AP_NUM)
pattrib->mbssid = padapter->vap_id;
_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN);
SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
/* pmlmeext->mgnt_seq++; */
set_frame_sub_type(pframe, WIFI_BEACON);
if (MLME_IS_AP(padapter) || MLME_IS_MESH(padapter)) {
/* RTW_INFO("ie len=%d\n", cur_network->IELength); */
/* for P2P : Primary Device Type & Device Name */
u32 wpsielen = 0, insert_len = 0;
u8 *wpsie = NULL;
wpsie = rtw_get_wps_ie(cur_network->IEs + _FIXED_IE_LENGTH_, cur_network->IELength - _FIXED_IE_LENGTH_, NULL, &wpsielen);
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && wpsie && wpsielen > 0) {
uint wps_offset, remainder_ielen;
u8 *premainder_ie, *pframe_wscie;
wps_offset = (uint)(wpsie - cur_network->IEs);
premainder_ie = wpsie + wpsielen;
remainder_ielen = cur_network->IELength - wps_offset - wpsielen;
if (pmlmepriv->wps_beacon_ie && pmlmepriv->wps_beacon_ie_len > 0) {
_rtw_memcpy(pframe, cur_network->IEs, wps_offset);
pframe += wps_offset;
pattrib->pktlen += wps_offset;
_rtw_memcpy(pframe, pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len);
pframe += pmlmepriv->wps_beacon_ie_len;
pattrib->pktlen += pmlmepriv->wps_beacon_ie_len;
/* copy remainder_ie to pframe */
_rtw_memcpy(pframe, premainder_ie, remainder_ielen);
pframe += remainder_ielen;
pattrib->pktlen += remainder_ielen;
_rtw_memcpy(pframe, cur_network->IEs, cur_network->IELength);
pframe += cur_network->IELength;
pattrib->pktlen += cur_network->IELength;
pframe_wscie = pframe + wps_offset;
_rtw_memcpy(pframe, cur_network->IEs, wps_offset + wpsielen);
pframe += (wps_offset + wpsielen);
pattrib->pktlen += (wps_offset + wpsielen);
/* now pframe is end of wsc ie, insert Primary Device Type & Device Name */
*(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE);
insert_len += 2;
*(u16 *)(pframe + insert_len) = cpu_to_be16(0x0008);
*(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
*(u32 *)(pframe + insert_len) = cpu_to_be32(WPSOUI);
insert_len += 4;
*(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
*(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
*(u16 *)(pframe + insert_len) = cpu_to_be16(pwdinfo->device_name_len);
_rtw_memcpy(pframe + insert_len, pwdinfo->device_name, pwdinfo->device_name_len);
insert_len += pwdinfo->device_name_len;
/* update wsc ie length */
*(pframe_wscie + 1) = (wpsielen - 2) + insert_len;
/* pframe move to end */
pframe += insert_len;
pattrib->pktlen += insert_len;
int len_diff;
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);
u8 *wps_ie;
uint wps_ielen;
u8 sr = 0;
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);
_clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS);
u32 len;
len = pmlmepriv->p2p_beacon_ie_len;
if (pmlmepriv->p2p_beacon_ie && len > 0)
_rtw_memcpy(pframe, pmlmepriv->p2p_beacon_ie, len);
len = build_beacon_p2p_ie(pwdinfo, pframe);
pframe += len;
pattrib->pktlen += len;
pframe = rtw_hal_mcc_append_go_p2p_ie(padapter, pframe, &pattrib->pktlen);
#endif /* CONFIG_MCC_MODE*/
len = rtw_append_beacon_wfd_ie(padapter, pframe);
rtw_rson_append_ie(padapter, pframe, &pattrib->pktlen);
pattrib->pktlen += rtw_build_vendor_ie(padapter , &pframe , WIFI_BEACON_VENDOR_IE_BIT);
#ifdef CONFIG_RTL8812A
pframe = rtw_hal_set_8812a_vendor_ie(padapter, pframe, &pattrib->pktlen );
#endif/*CONFIG_RTL8812A*/
if (padapter->tbtx_capability == _TRUE)
pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 8, REALTEK_TBTX_IE, &pattrib->pktlen);
goto _issue_bcn;
/* below for ad-hoc mode */
_rtw_memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2);
_rtw_memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2);
pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen);
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);
pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen);
/* 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);
/* 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:
pmlmepriv->update_bcn = _FALSE;
_exit_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
if ((pattrib->pktlen + TXDESC_SIZE) > MAX_BEACON_LEN) {
RTW_ERR("beacon frame too large ,len(%d,%d)\n",
(pattrib->pktlen + TXDESC_SIZE), MAX_BEACON_LEN);
/* RTW_INFO("issue bcn_sz=%d\n", pattrib->last_txcmdsz); */
if (timeout_ms > 0)
dump_mgntframe_and_wait(padapter, pmgntframe, timeout_ms);
void issue_probersp(_adapter *padapter, unsigned char *da, u8 is_valid_p2p_probereq)
unsigned char *mac, *bssid;
u8 *pwps_ie;
if (da == NULL)
bssid = cur_network->MacAddress;
_rtw_memcpy(pwlanhdr->addr3, bssid, ETH_ALEN);
if (cur_network->IELength > MAX_IE_SZ)
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);
/* inerset & update wps_probe_resp_ie */
if ((pmlmepriv->wps_probe_resp_ie != NULL) && pwps_ie && (wps_ielen > 0)) {
u8 *premainder_ie;
wps_offset = (uint)(pwps_ie - cur_network->IEs);
premainder_ie = pwps_ie + wps_ielen;
remainder_ielen = cur_network->IELength - wps_offset - wps_ielen;
wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1];/* to get ie data len */
if ((wps_offset + wps_ielen + 2) <= MAX_IE_SZ) {
_rtw_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) {
/* retrieve SSID IE from cur_network->Ssid */
sint ssid_ielen;
sint ssid_ielen_diff;
u8 buf[MAX_IE_SZ];
u8 *ies = pmgntframe->buf_addr + TXDESC_OFFSET + sizeof(struct rtw_ieee80211_hdr_3addr);
ssid_ie = rtw_get_ie(ies + _FIXED_IE_LENGTH_, _SSID_IE_, &ssid_ielen,
(pframe - ies) - _FIXED_IE_LENGTH_);
ssid_ielen_diff = cur_network->Ssid.SsidLength - ssid_ielen;
if (ssid_ie && cur_network->Ssid.SsidLength) {
uint remainder_ielen;
u8 *remainder_ie;
remainder_ie = ssid_ie + 2;
remainder_ielen = (pframe - remainder_ie);
if (remainder_ielen > MAX_IE_SZ) {
RTW_WARN(FUNC_ADPT_FMT" remainder_ielen > MAX_IE_SZ\n", FUNC_ADPT_ARG(padapter));
remainder_ielen = MAX_IE_SZ;
_rtw_memcpy(buf, remainder_ie, remainder_ielen);
_rtw_memcpy(remainder_ie + ssid_ielen_diff, buf, remainder_ielen);
*(ssid_ie + 1) = cur_network->Ssid.SsidLength;
_rtw_memcpy(ssid_ie + 2, cur_network->Ssid.Ssid, cur_network->Ssid.SsidLength);
pframe += ssid_ielen_diff;
pattrib->pktlen += ssid_ielen_diff;
pattrib->pktlen += rtw_build_vendor_ie(padapter , &pframe , WIFI_PROBERESP_VENDOR_IE_BIT);
if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) {
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)
/* IOT issue, When wifi_spec is not set, send probe_resp with P2P IE even if probe_req has no P2P IE */
&& (is_valid_p2p_probereq || !padapter->registrypriv.wifi_spec)) {
/* if pwdinfo->role == P2P_ROLE_DEVICE will call issue_probersp_p2p() */
len = pmlmepriv->p2p_go_probe_resp_ie_len;
if (pmlmepriv->p2p_go_probe_resp_ie && len > 0)
_rtw_memcpy(pframe, pmlmepriv->p2p_go_probe_resp_ie, len);
len = build_probe_resp_p2p_ie(pwdinfo, pframe);
len = rtw_append_probe_resp_wfd_ie(padapter, pframe);
RTW_INFO("(%s)\n", __FUNCTION__);
/* check rc station */
psta = rtw_get_stainfo(pstapriv, da);
if (psta && psta->isrc && psta->pid > 0) {
u8 RC_INFO[14] = {0};
u16 cu_ch = (u16)cur_network->Configuration.DSConfig;
RTW_INFO("%s, reply rc(pid=0x%x) device "MAC_FMT" in ch=%d\n", __FUNCTION__,
psta->pid, MAC_ARG(psta->cmn.mac_addr), cu_ch);
/* append vendor specific ie */
_rtw_memcpy(RC_INFO, RC_OUI, sizeof(RC_OUI));
_rtw_memcpy(&RC_INFO[4], mac, ETH_ALEN);
_rtw_memcpy(&RC_INFO[10], (u8 *)&psta->pid, 2);
_rtw_memcpy(&RC_INFO[12], (u8 *)&cu_ch, 2);
pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, sizeof(RC_INFO), RC_INFO, &pattrib->pktlen);
pframe = rtw_hal_set_8812a_vendor_ie(padapter, pframe, &pattrib->pktlen);
int _issue_probereq(_adapter *padapter, const NDIS_802_11_SSID *pssid, const u8 *da, u8 ch, bool append_wps, int wait_ack)
unsigned char bssrate[NumRates];
int bssrate_len = 0;
if ((pwdev_priv->pno_mac_addr[0] != 0xFF)
&& (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE) == _TRUE)
&& (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE) == _FALSE))
mac = pwdev_priv->pno_mac_addr;
/* unicast probe request frame */
&& (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE) == _FALSE)) {
#ifdef CONFIG_RTW_DEBUG
RTW_DBG("%s pno_scan_seq_num: %d\n", __func__,
pwdev_priv->pno_scan_seq_num);
SetSeqNum(pwlanhdr, pwdev_priv->pno_scan_seq_num);
pattrib->seqnum = pwdev_priv->pno_scan_seq_num;
pattrib->qos_en = 1;
pwdev_priv->pno_scan_seq_num++;
if (pssid && !MLME_IS_MESH(padapter))
pframe = rtw_set_ie(pframe, _SSID_IE_, pssid->SsidLength, pssid->Ssid, &(pattrib->pktlen));
pframe = rtw_set_ie(pframe, _SSID_IE_, 0, NULL, &(pattrib->pktlen));
get_rate_set(padapter, bssrate, &bssrate_len);
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));
pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen));
if (ch)
pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, &ch, &pattrib->pktlen);
if (pssid)
pframe = rtw_set_ie_mesh_id(pframe, &pattrib->pktlen, pssid->Ssid, pssid->SsidLength);
pframe = rtw_set_ie_mesh_id(pframe, &pattrib->pktlen, NULL, 0);
if (append_wps) {
/* add wps_ie for wps2.0 */
if (pmlmepriv->wps_probe_req_ie_len > 0 && pmlmepriv->wps_probe_req_ie) {
/* pmlmepriv->wps_probe_req_ie_len = 0 ; */ /* reset to zero */
pattrib->pktlen += rtw_build_vendor_ie(padapter , &pframe , WIFI_PROBEREQ_VENDOR_IE_BIT);
#ifdef CONFIG_RTW_MBO
rtw_mbo_build_probe_req_ies( padapter, &pframe, pattrib);
inline void issue_probereq(_adapter *padapter, const NDIS_802_11_SSID *pssid, const u8 *da)
_issue_probereq(padapter, pssid, da, 0, 1, _FALSE);
int issue_probereq_ex(_adapter *padapter, const NDIS_802_11_SSID *pssid, const u8 *da, u8 ch, bool append_wps,
int try_cnt, int wait_ms)
ret = _issue_probereq(padapter, pssid, da, ch, append_wps, wait_ms > 0 ? _TRUE : _FALSE);
if (RTW_CANNOT_RUN(padapter))
FUNC_ADPT_ARG(padapter), MAC_ARG(da), rtw_get_oper_ch(padapter),
FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
/* if psta == NULL, indiate we are station(client) now... */
void issue_auth(_adapter *padapter, struct sta_info *psta, unsigned short status)
unsigned int val32;
unsigned short val16;
int use_shared_key = 0;
set_frame_sub_type(pframe, WIFI_AUTH);
if (psta) { /* for AP mode */
_rtw_memcpy(pwlanhdr->addr1, psta->cmn.mac_addr, ETH_ALEN);
/* setting auth algo number */
val16 = (u16)psta->authalg;
val16 = 0;
if (val16) {
val16 = cpu_to_le16(val16);
use_shared_key = 1;
pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&val16, &(pattrib->pktlen));
/* setting auth seq number */
val16 = (u16)psta->auth_seq;
pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&val16, &(pattrib->pktlen));
/* setting status code... */
val16 = status;
pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&val16, &(pattrib->pktlen));
/* 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));
_rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
if (rtw_ft_roam(padapter)) {
/* 2: 802.11R FTAA */
val16 = cpu_to_le16(2);
val16 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ? 1 : 0; /* 0:OPEN System, 1:Shared key */
/* RTW_INFO("%s auth_algo= %s auth_seq=%d\n",__FUNCTION__,(pmlmeinfo->auth_algo==0)?"OPEN":"SHARED",pmlmeinfo->auth_seq); */
/* setting IV for auth seq #3 */
if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) {
/* RTW_INFO("==> iv(%d),key_index(%d)\n",pmlmeinfo->iv,pmlmeinfo->key_index); */
val32 = ((pmlmeinfo->iv++) | (pmlmeinfo->key_index << 30));
val32 = cpu_to_le32(val32);
pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&val32, &(pattrib->pktlen));
pattrib->iv_len = 4;
val16 = pmlmeinfo->auth_seq;
rtw_ft_build_auth_req_ies(padapter, pattrib, &pframe);
/* then checking to see if sending challenging text... */
pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, pmlmeinfo->chg_txt, &(pattrib->pktlen));
SetPrivacy(fctrl);
pattrib->encrypt = _WEP40_;
pattrib->icv_len = 4;
pattrib->pktlen += pattrib->icv_len;
rtw_wep_encrypt(padapter, (u8 *)pmgntframe);
void issue_asocrsp(_adapter *padapter, unsigned short status, struct sta_info *pstat, int pkt_type)
unsigned char *pbuf, *pframe;
unsigned short val, ie_status;
WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network);
u8 *ie = pnetwork->IEs, cap[5], i;
_rtw_memcpy((void *)GetAddr1Ptr(pwlanhdr), pstat->cmn.mac_addr, ETH_ALEN);
_rtw_memcpy((void *)get_addr2_ptr(pwlanhdr), adapter_mac_addr(padapter), ETH_ALEN);
_rtw_memcpy((void *)GetAddr3Ptr(pwlanhdr), get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP))
set_frame_sub_type(pwlanhdr, pkt_type);
pattrib->pktlen += pattrib->hdrlen;
/* capability */
val = *(unsigned short *)rtw_get_capability_from_ie(ie);
val |= cap_RM;
pframe = rtw_set_fixed_ie(pframe, _CAPABILITY_ , (unsigned char *)&val, &(pattrib->pktlen));
ie_status = cpu_to_le16(status);
pframe = rtw_set_fixed_ie(pframe , _STATUS_CODE_ , (unsigned char *)&ie_status, &(pattrib->pktlen));
val = cpu_to_le16(pstat->cmn.aid | BIT(14) | BIT(15));
pframe = rtw_set_fixed_ie(pframe, _ASOC_ID_ , (unsigned char *)&val, &(pattrib->pktlen));
if (pstat->bssratelen <= 8)
pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, pstat->bssratelen, pstat->bssrateset, &(pattrib->pktlen));
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 (status == _STATS_REFUSED_TEMPORARILY_) {
u8 timeout_itvl[5];
u32 timeout_interval = 3000;
/* Association Comeback time */
timeout_itvl[0] = 0x03;
timeout_interval = cpu_to_le32(timeout_interval);
_rtw_memcpy(timeout_itvl + 1, &timeout_interval, 4);
pframe = rtw_set_ie(pframe, _TIMEOUT_ITVL_IE_, 5, timeout_itvl, &(pattrib->pktlen));
if ((pstat->flags & WLAN_STA_HT) && (pmlmepriv->htpriv.ht_option)) {
uint ie_len = 0;
/* FILL HT CAP INFO IE */
/* p = hostapd_eid_ht_capabilities_info(hapd, p); */
pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
if (pbuf && ie_len > 0) {
_rtw_memcpy(pframe, pbuf, ie_len + 2);
pframe += (ie_len + 2);
pattrib->pktlen += (ie_len + 2);
/* FILL HT ADD INFO IE */
/* p = hostapd_eid_ht_operation(hapd, p); */
pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
/*adding EXT_CAPAB_IE */
if (pmlmepriv->ext_capab_ie_len > 0) {
pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_CAP_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
if ((pstat->flags & WLAN_STA_VHT) && (pmlmepriv->vhtpriv.vht_option)
&& (pstat->wpa_pairwise_cipher != WPA_CIPHER_TKIP)
&& (pstat->wpa2_pairwise_cipher != WPA_CIPHER_TKIP)) {
u32 ie_len = 0;
/* FILL VHT CAP IE */
pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, EID_VHTCapability, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
/* FILL VHT OPERATION IE */
pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, EID_VHTOperation, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
/* FILL RM Enabled Capabilities with joint capabilities */
for (i = 0; i < 5; i++) {
cap[i] = padapter->rmpriv.rm_en_cap_def[i]
& pstat->rm_en_cap[i];
if (pstat->capability & cap_RM)
pframe = rtw_set_ie(pframe, _EID_RRM_EN_CAP_IE_, 5,
(u8 *)cap, &(pattrib->pktlen));
/* FILL WMM IE */
if ((pstat->flags & WLAN_STA_WME) && (pmlmepriv->qospriv.qos_option)) {
unsigned char WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
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 && _rtw_memcmp(pbuf + 2, WMM_PARA_IE, 6)) {
if ((pbuf == NULL) || (ie_len == 0))
if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK)
pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen));
/* add WPS IE ie for wps 2.0 */
if (pmlmepriv->wps_assoc_resp_ie && pmlmepriv->wps_assoc_resp_ie_len > 0) {
_rtw_memcpy(pframe, pmlmepriv->wps_assoc_resp_ie, pmlmepriv->wps_assoc_resp_ie_len);
pframe += pmlmepriv->wps_assoc_resp_ie_len;
pattrib->pktlen += pmlmepriv->wps_assoc_resp_ie_len;
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && (pstat->is_p2p_device == _TRUE)) {
len = 0;
if (pmlmepriv->p2p_assoc_resp_ie && pmlmepriv->p2p_assoc_resp_ie_len > 0) {
len = pmlmepriv->p2p_assoc_resp_ie_len;
_rtw_memcpy(pframe, pmlmepriv->p2p_assoc_resp_ie, len);
len = build_assoc_resp_p2p_ie(pwdinfo, pframe, pstat->p2p_status_code);
wfdielen = rtw_append_assoc_resp_wfd_ie(padapter, pframe);
#ifdef CONFIG_RTW_MULTI_AP
if (padapter->multi_ap && (pstat->flags & WLAN_STA_MULTI_AP))
pframe = rtw_set_multi_ap_ie_ext(pframe, &pattrib->pktlen, padapter->multi_ap);
pattrib->pktlen += rtw_build_vendor_ie(padapter , &pframe , WIFI_ASSOCRESP_VENDOR_IE_BIT);
static u32 rtw_append_assoc_req_owe_ie(_adapter *adapter, u8 *pbuf)
struct security_priv *sec = &adapter->securitypriv;
if (sec == NULL)
if (sec->owe_ie_len > 0) {
len = sec->owe_ie_len;
_rtw_memcpy(pbuf, sec->owe_ie, len);
void _issue_assocreq(_adapter *padapter, u8 is_reassoc)
unsigned int i, j, index = 0;
unsigned char bssrate[NumRates], sta_bssrate[NumRates];
int bssrate_len = 0, sta_bssrate_len = 0;
u8 vs_ie_length = 0;
u16 p2pielen = 0;
u16 cap;
if (is_reassoc == _TRUE)
set_frame_sub_type(pframe, WIFI_REASSOCREQ);
set_frame_sub_type(pframe, WIFI_ASSOCREQ);
/* caps */
_rtw_memcpy(&cap, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2);
cap |= cap_SpecMgmt;
cap |= cap_RM;
_rtw_memcpy(pframe, &cap, 2);
_rtw_memcpy(pframe, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2);
/* listen interval */
/* todo: listen interval for power saving */
val16 = cpu_to_le16(3);
_rtw_memcpy(pframe , (unsigned char *)&val16, 2);
/*Construct Current AP Field for Reassoc-Req only*/
if (is_reassoc == _TRUE) {
_rtw_memcpy(pframe, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
pframe += ETH_ALEN;
pattrib->pktlen += ETH_ALEN;
pframe = rtw_set_ie(pframe, _SSID_IE_, pmlmeinfo->network.Ssid.SsidLength, pmlmeinfo->network.Ssid.Ssid, &(pattrib->pktlen));
#if CONFIG_IEEE80211_BAND_5GHZ && CONFIG_DFS
/* Dot H */
if (pmlmeext->cur_channel > 14) {
struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter);
u8 pow_cap_ele[2] = { 0x00 };
u8 sup_ch[30 * 2] = {0x00 }, sup_ch_idx = 0, idx_5g = 2; /* For supported channel */
pow_cap_ele[0] = 13; /* Minimum transmit power capability */
pow_cap_ele[1] = 21; /* Maximum transmit power capability */
pframe = rtw_set_ie(pframe, EID_PowerCap, 2, pow_cap_ele, &(pattrib->pktlen));
/* supported channels */
while (sup_ch_idx < rfctl->max_chan_nums && rfctl->channel_set[sup_ch_idx].ChannelNum != 0) {
if (rfctl->channel_set[sup_ch_idx].ChannelNum <= 14) {
/* TODO: fix 2.4G supported channel when channel doesn't start from 1 and continuous */
sup_ch[0] = 1; /* First channel number */
sup_ch[1] = rfctl->channel_set[sup_ch_idx].ChannelNum; /* Number of channel */
sup_ch[idx_5g++] = rfctl->channel_set[sup_ch_idx].ChannelNum;
sup_ch[idx_5g++] = 1;
sup_ch_idx++;
pframe = rtw_set_ie(pframe, EID_SupportedChannels, idx_5g, sup_ch, &(pattrib->pktlen));
#endif /* CONFIG_IEEE80211_BAND_5GHZ && CONFIG_DFS */
/* supported rate & extended supported rate */
#if 1 /* Check if the AP's supported rates are also supported by STA. */
get_rate_set(padapter, sta_bssrate, &sta_bssrate_len);
/* RTW_INFO("sta_bssrate_len=%d\n", sta_bssrate_len); */
if (pmlmeext->cur_channel == 14) /* for JAPAN, channel 14 can only uses B Mode(CCK) */
sta_bssrate_len = 4;
/* for (i = 0; i < sta_bssrate_len; i++) { */
/* RTW_INFO("sta_bssrate[%d]=%02X\n", i, sta_bssrate[i]); */
/* } */
for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
if (pmlmeinfo->network.SupportedRates[i] == 0)
RTW_INFO("network.SupportedRates[%d]=%02X\n", i, pmlmeinfo->network.SupportedRates[i]);
/* 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)) {
/* RTW_INFO("match i = %d, j=%d\n", i, j); */
/* RTW_INFO("not match: %02X != %02X\n", (pmlmeinfo->network.SupportedRates[i]|IEEE80211_BASIC_RATE_MASK), (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK)); */
if (j == sta_bssrate_len) {
/* the rate is not supported by STA */
RTW_INFO("%s(): the rate[%d]=%02X is not supported by STA!\n", __FUNCTION__, i, pmlmeinfo->network.SupportedRates[i]);
/* the rate is supported by STA */
bssrate[index++] = pmlmeinfo->network.SupportedRates[i];
bssrate_len = index;
RTW_INFO("bssrate_len = %d\n", bssrate_len);
#else /* Check if the AP's supported rates are also supported by STA. */
for (bssrate_len = 0; bssrate_len < NumRates; bssrate_len++) {
if (pmlmeinfo->network.SupportedRates[bssrate_len] == 0)
if (pmlmeinfo->network.SupportedRates[bssrate_len] == 0x2C) /* Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP */
bssrate[bssrate_len] = pmlmeinfo->network.SupportedRates[bssrate_len];
#endif /* Check if the AP's supported rates are also supported by STA. */
if ((bssrate_len == 0) && (pmlmeinfo->network.SupportedRates[0] != 0)) {
rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf);
goto exit; /* don't connect to AP if no joint supported rate */
} else if (bssrate_len > 0)
RTW_INFO("%s: Connect to AP without 11b and 11g data rate!\n", __FUNCTION__);
rtw_mbo_build_assoc_req_ies(padapter, &pframe, pattrib);
rtw_ft_build_assoc_req_ies(padapter, is_reassoc, pattrib, &pframe);
(u8 *)padapter->rmpriv.rm_en_cap_def,
&(pattrib->pktlen));
/* vendor specific IE, such as WPA, WMM, WPS */
for (i = sizeof(NDIS_802_11_FIXED_IEs); i < pmlmeinfo->network.IELength;) {
pIE = (PNDIS_802_11_VARIABLE_IEs)(pmlmeinfo->network.IEs + i);
if ((_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4)) ||
(_rtw_memcmp(pIE->data, WMM_OUI, 4)) ||
(_rtw_memcmp(pIE->data, WPS_OUI, 4))) {
vs_ie_length = pIE->Length;
if ((!padapter->registrypriv.wifi_spec) && (_rtw_memcmp(pIE->data, WPS_OUI, 4))) {
/* Commented by Kurt 20110629 */
/* In some older APs, WPS handshake */
/* would be fail if we append vender extensions informations to AP */
vs_ie_length = 14;
pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, vs_ie_length, pIE->data, &(pattrib->pktlen));
case EID_WPA2:
if ((is_reassoc) && (rtw_ft_roam(padapter))) {
rtw_ft_update_rsnie(padapter, _TRUE, pattrib, &pframe);
if (rtw_sec_chk_auth_alg(padapter, WLAN_AUTH_OPEN) &&
rtw_sec_chk_auth_type(padapter, MLME_AUTHTYPE_SAE)) {
s32 entry = rtw_cached_pmkid(padapter, pmlmepriv->assoc_bssid);
rtw_rsn_sync_pmkid(padapter, (u8 *)pIE, (pIE->Length + 2), entry);
pframe = rtw_set_ie(pframe, EID_WPA2, pIE->Length, pIE->data, &(pattrib->pktlen));
/* tmp: update rsn's spp related opt. */
/*rtw_set_spp_amsdu_mode(padapter->registrypriv.amsdu_mode, pframe - (pIE->Length + 2), pIE->Length +2);*/
case EID_HTCapability:
if (padapter->mlmepriv.htpriv.ht_option == _TRUE) {
if (!(is_ap_in_tkip(padapter))) {
_rtw_memcpy(&(pmlmeinfo->HT_caps), pIE->data, sizeof(struct HT_caps_element));
pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info = cpu_to_le16(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info);
pframe = rtw_set_ie(pframe, EID_HTCapability, pIE->Length , (u8 *)(&(pmlmeinfo->HT_caps)), &(pattrib->pktlen));
case EID_EXTCapability:
if (padapter->mlmepriv.htpriv.ht_option == _TRUE)
pframe = rtw_set_ie(pframe, EID_EXTCapability, pIE->Length, pIE->data, &(pattrib->pktlen));
if (padapter->mlmepriv.vhtpriv.vht_option == _TRUE)
pframe = rtw_set_ie(pframe, EID_VHTCapability, pIE->Length, pIE->data, &(pattrib->pktlen));
case EID_OpModeNotification:
pframe = rtw_set_ie(pframe, EID_OpModeNotification, pIE->Length, pIE->data, &(pattrib->pktlen));
pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 8 , REALTEK_TBTX_IE, &(pattrib->pktlen));
rtw_build_assoc_req_wapi_ie(padapter, pframe, pattrib);
if (pmlmepriv->p2p_assoc_req_ie && pmlmepriv->p2p_assoc_req_ie_len > 0) {
_rtw_memcpy(pframe, pmlmepriv->p2p_assoc_req_ie, pmlmepriv->p2p_assoc_req_ie_len);
pframe += pmlmepriv->p2p_assoc_req_ie_len;
pattrib->pktlen += pmlmepriv->p2p_assoc_req_ie_len;
if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) {
/* Should add the P2P IE in the association request frame. */
/* Commented by Albert 20101109 */
/* According to the P2P Specification, the association request frame should contain 3 P2P attributes */
/* 2. Extended Listen Timing */
/* 3. Device Info */
/* Commented by Albert 20110516 */
/* 4. P2P Interface */
if ((pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN) ||
(pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN))
*(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_PBC);
/* P2P Interface */
p2pie[p2pielen++] = P2P_ATTR_INTERFACE;
*(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x000D);
_rtw_memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); /* P2P Device Address */
p2pie[p2pielen++] = 1; /* P2P Interface Address Count */
_rtw_memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); /* P2P Interface Address List */
wfdielen = rtw_append_assoc_req_wfd_ie(padapter, pframe);
if (padapter->multi_ap)
/* OWE */
u32 owe_ie_len;
owe_ie_len = rtw_append_assoc_req_owe_ie(padapter, pframe);
pframe += owe_ie_len;
pattrib->pktlen += owe_ie_len;
pattrib->pktlen += rtw_build_vendor_ie(padapter , &pframe , WIFI_ASSOCREQ_VENDOR_IE_BIT);
if (ret == _SUCCESS) {
rtw_buf_update(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len, (u8 *)pwlanhdr, pattrib->pktlen);
rtw_wnm_update_reassoc_req_ie(padapter);
rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len);
void issue_assocreq(_adapter *padapter)
_issue_assocreq(padapter, _FALSE);
void issue_reassocreq(_adapter *padapter)
_issue_assocreq(padapter, _TRUE);
/* when wait_ack is ture, this function shoule be called at process context */
static int _issue_nulldata(_adapter *padapter, unsigned char *da, unsigned int power_mode, int wait_ack)
struct xmit_priv *pxmitpriv;
struct mlme_ext_priv *pmlmeext;
struct mlme_ext_info *pmlmeinfo;
u8 a4_shift;
/* RTW_INFO("%s:%d\n", __FUNCTION__, power_mode); */
pxmitpriv = &(padapter->xmitpriv);
pattrib->retry_ctrl = _FALSE;
SetFrDs(fctrl);
else if (MLME_IS_STA(padapter))
SetToDs(fctrl);
else if (MLME_IS_MESH(padapter)) {
if (power_mode)
SetPwrMgt(fctrl);
if (get_tofr_ds(fctrl) == 3) {
_rtw_memcpy(pwlanhdr->addr4, adapter_mac_addr(padapter), ETH_ALEN);
a4_shift = ETH_ALEN;
pattrib->hdrlen += ETH_ALEN;
a4_shift = 0;
set_frame_sub_type(pframe, WIFI_DATA_NULL);
pframe += sizeof(struct rtw_ieee80211_hdr_3addr) + a4_shift;
pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr) + a4_shift;
* When wait_ms > 0, this function should be called at process context
* da == NULL for station mode
int issue_nulldata(_adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms)
/* da == NULL, assum it's null data for sta to ap */
da = get_my_bssid(&(pmlmeinfo->network));
ret = _issue_nulldata(padapter, da, power_mode, wait_ms > 0 ? _TRUE : _FALSE);
static int _issue_qos_nulldata(_adapter *padapter, unsigned char *da, u16 tid, u8 ps, int wait_ack)
unsigned short *fctrl, *qc;
pattrib->hdrlen += 2;
pattrib->qos_en = _TRUE;
pattrib->eosp = 1;
pattrib->ack_policy = 0;
pattrib->mdata = 0;
if (ps)
if (pattrib->mdata)
SetMData(fctrl);
qc = (unsigned short *)(pframe + pattrib->hdrlen - 2);
SetPriority(qc, tid);
SetEOSP(qc, pattrib->eosp);
SetAckpolicy(qc, pattrib->ack_policy);
set_frame_sub_type(pframe, WIFI_QOS_DATA_NULL);
pframe += sizeof(struct rtw_ieee80211_hdr_3addr_qos) + a4_shift;
pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos) + a4_shift;
* when wait_ms >0 , this function should be called at process context
int issue_qos_nulldata(_adapter *padapter, unsigned char *da, u16 tid, u8 ps, int try_cnt, int wait_ms)
/* da == NULL, assum it's null data for sta to ap*/
ret = _issue_qos_nulldata(padapter, da, tid, ps, wait_ms > 0 ? _TRUE : _FALSE);
static int _issue_deauth(_adapter *padapter, unsigned char *da, unsigned short reason, u8 wait_ack, u8 key_type)
/* RTW_INFO("%s to "MAC_FMT"\n", __func__, MAC_ARG(da)); */
if (!(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) && (pwdinfo->rx_invitereq_info.scan_op_ch_only)) {
pattrib->key_type = key_type;
set_frame_sub_type(pframe, WIFI_DEAUTH);
reason = cpu_to_le16(reason);
pframe = rtw_set_fixed_ie(pframe, _RSON_CODE_ , (unsigned char *)&reason, &(pattrib->pktlen));
int issue_deauth(_adapter *padapter, unsigned char *da, unsigned short reason)
RTW_INFO("%s reason(%u) to "MAC_FMT"\n", __func__, reason, MAC_ARG(da));
return _issue_deauth(padapter, da, reason, _FALSE, IEEE80211W_RIGHT_KEY);
int issue_deauth_11w(_adapter *padapter, unsigned char *da, unsigned short reason, u8 key_type)
RTW_INFO("%s to "MAC_FMT"\n", __func__, MAC_ARG(da));
return _issue_deauth(padapter, da, reason, _FALSE, key_type);
int issue_deauth_ex(_adapter *padapter, u8 *da, unsigned short reason, int try_cnt,
int wait_ms)
ret = _issue_deauth(padapter, da, reason, wait_ms > 0 ? _TRUE : _FALSE, IEEE80211W_RIGHT_KEY);
void issue_action_spct_ch_switch(_adapter *padapter, u8 *ra, u8 new_ch, u8 ch_offset)
RTW_INFO(FUNC_NDEV_FMT" ra="MAC_FMT", ch:%u, offset:%u\n",
FUNC_NDEV_ARG(padapter->pnetdev), MAC_ARG(ra), new_ch, ch_offset);
_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); /* RA */
_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); /* TA */
_rtw_memcpy(pwlanhdr->addr3, ra, ETH_ALEN); /* DA = RA */
/* category, action */
category = RTW_WLAN_CATEGORY_SPECTRUM_MGMT;
action = RTW_WLAN_ACTION_SPCT_CHL_SWITCH;
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));
void issue_action_SA_Query(_adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short tid, u8 key_type)
u8 category = RTW_WLAN_CATEGORY_SA_QUERY;
u16 reason_code;
u16 *fctrl;
RTW_INFO("%s, %04x\n", __FUNCTION__, tid);
RTW_INFO("%s: alloc_mgtxmitframe fail\n", __FUNCTION__);
if (raddr)
pframe = rtw_set_fixed_ie(pframe, 1, &category, &pattrib->pktlen);
pframe = rtw_set_fixed_ie(pframe, 1, &action, &pattrib->pktlen);
pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&pmlmeext->sa_query_seq, &pattrib->pktlen);
pmlmeext->sa_query_seq++;
/* send sa query request to AP, AP should reply sa query response in 1 second */
if (pattrib->key_type == IEEE80211W_RIGHT_KEY) {
psta = rtw_get_stainfo(pstapriv, pwlanhdr->addr1);
/* RTW_INFO("%s, %d, set dot11w_expire_timer\n", __func__, __LINE__); */
_set_timer(&psta->dot11w_expire_timer, 1000);
tid = cpu_to_le16(tid);
/* RTW_INFO("rtw_set_fixed_ie, %04x\n", tid); */
pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&tid, &pattrib->pktlen);
* issue_action_ba - internal function to TX Block Ack action frame
* @padapter: the adapter to TX
* @raddr: receiver address
* @action: Block Ack Action
* @tid: tid
* @size: the announced AMPDU buffer size. used by ADDBA_RESP
* @status: status/reason code. used by ADDBA_RESP, DELBA
* @initiator: if we are the initiator of AMPDU association. used by DELBA
* @wait_ack: used xmit ack
* _SUCCESS: No xmit ack is used or acked
* _FAIL: not acked when using xmit ack
static int issue_action_ba(_adapter *padapter, unsigned char *raddr, unsigned char action
, u8 tid, u8 size, u16 status, u8 initiator, int wait_ack)
u8 category = RTW_WLAN_CATEGORY_BACK;
u16 start_seq;
u16 BA_para_set;
u16 BA_timeout_value;
u16 BA_starting_seqctrl;
/* _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); */
if (category == 3) {
case RTW_WLAN_ACTION_ADDBA_REQ:
pmlmeinfo->dialogToken++;
} while (pmlmeinfo->dialogToken == 0);
pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->dialogToken), &(pattrib->pktlen));
#if defined(CONFIG_RTL8188E) && defined(CONFIG_SDIO_HCI)
BA_para_set = (0x0802 | ((tid & 0xf) << 2)); /* immediate ack & 16 buffer size */
BA_para_set = (0x1002 | ((tid & 0xf) << 2)); /* immediate ack & 64 buffer size */
#ifdef CONFIG_TX_AMSDU
if (padapter->tx_amsdu >= 1) /* TX AMSDU enabled */
BA_para_set |= BIT(0);
else /* TX AMSDU disabled */
BA_para_set &= ~BIT(0);
psta = rtw_get_stainfo(pstapriv, raddr);
if (psta->flags & WLAN_STA_AMSDU_DISABLE)
BA_para_set = cpu_to_le16(BA_para_set);
pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_para_set)), &(pattrib->pktlen));
/* BA_timeout_value = 0xffff; */ /* max: 65535 TUs(~ 65 ms) */
BA_timeout_value = 5000;/* ~ 5ms */
BA_timeout_value = cpu_to_le16(BA_timeout_value);
pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_timeout_value)), &(pattrib->pktlen));
/* if ((psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress)) != NULL) */
start_seq = (psta->sta_xmitpriv.txseq_tid[tid & 0x07] & 0xfff) + 1;
RTW_INFO("BA_starting_seqctrl = %d for TID=%d\n", start_seq, tid & 0x07);
psta->BA_starting_seqctrl[tid & 0x07] = start_seq;
BA_starting_seqctrl = start_seq << 4;
BA_starting_seqctrl = cpu_to_le16(BA_starting_seqctrl);
pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_starting_seqctrl)), &(pattrib->pktlen));
case RTW_WLAN_ACTION_ADDBA_RESP:
pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->ADDBA_req.dialog_token), &(pattrib->pktlen));
status = cpu_to_le16(status);
pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&status), &(pattrib->pktlen));
BA_para_set = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set);
BA_para_set &= ~IEEE80211_ADDBA_PARAM_TID_MASK;
BA_para_set |= (tid << 2) & IEEE80211_ADDBA_PARAM_TID_MASK;
BA_para_set &= ~RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
BA_para_set |= (size << 6) & RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
if (!padapter->registrypriv.wifi_spec) {
if (pregpriv->rx_ampdu_amsdu == 0) /* disabled */
else if (pregpriv->rx_ampdu_amsdu == 1) /* enabled */
pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(pmlmeinfo->ADDBA_req.BA_timeout_value)), &(pattrib->pktlen));
case RTW_WLAN_ACTION_DELBA:
BA_para_set = 0;
BA_para_set |= (tid << 12) & IEEE80211_DELBA_PARAM_TID_MASK;
BA_para_set |= (initiator << 11) & IEEE80211_DELBA_PARAM_INITIATOR_MASK;
pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(status)), &(pattrib->pktlen));
* issue_addba_req - TX ADDBA_REQ
* @adapter: the adapter to TX
* @ra: receiver address
inline void issue_addba_req(_adapter *adapter, unsigned char *ra, u8 tid)
issue_action_ba(adapter, ra, RTW_WLAN_ACTION_ADDBA_REQ
, tid
, 0 /* unused */
, _FALSE
RTW_INFO(FUNC_ADPT_FMT" ra="MAC_FMT" tid=%u\n"
, FUNC_ADPT_ARG(adapter), MAC_ARG(ra), tid);
* issue_addba_rsp - TX ADDBA_RESP
* @status: status code
* @size: the announced AMPDU buffer size
inline void issue_addba_rsp(_adapter *adapter, unsigned char *ra, u8 tid, u16 status, u8 size)
issue_action_ba(adapter, ra, RTW_WLAN_ACTION_ADDBA_RESP
, size
, status
RTW_INFO(FUNC_ADPT_FMT" ra="MAC_FMT" status=%u, tid=%u, size=%u\n"
, FUNC_ADPT_ARG(adapter), MAC_ARG(ra), status, tid, size);
* issue_addba_rsp_wait_ack - TX ADDBA_RESP and wait ack
* @try_cnt: the maximal TX count to try
* @wait_ms: == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT
* > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX
inline u8 issue_addba_rsp_wait_ack(_adapter *adapter, unsigned char *ra, u8 tid, u16 status, u8 size, int try_cnt, int wait_ms)
if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(adapter)))
ret = issue_action_ba(adapter, ra, RTW_WLAN_ACTION_ADDBA_RESP
, _TRUE
/* goto exit; */
RTW_INFO(FUNC_ADPT_FMT" ra="MAC_FMT" status:=%u tid=%u size:%u%s, %d/%d in %u ms\n"
, FUNC_ADPT_ARG(adapter), MAC_ARG(ra), status, tid, size
, ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
* issue_del_ba - TX DELBA
* @reason: reason code
inline void issue_del_ba(_adapter *adapter, unsigned char *ra, u8 tid, u16 reason, u8 initiator)
issue_action_ba(adapter, ra, RTW_WLAN_ACTION_DELBA
, reason
, initiator
RTW_INFO(FUNC_ADPT_FMT" ra="MAC_FMT" reason=%u, tid=%u, initiator=%u\n"
, FUNC_ADPT_ARG(adapter), MAC_ARG(ra), reason, tid, initiator);
* issue_del_ba_ex - TX DELBA with xmit ack options
int issue_del_ba_ex(_adapter *adapter, unsigned char *ra, u8 tid, u16 reason, u8 initiator
, int try_cnt, int wait_ms)
ret = issue_action_ba(adapter, ra, RTW_WLAN_ACTION_DELBA
, wait_ms > 0 ? _TRUE : _FALSE
RTW_INFO(FUNC_ADPT_FMT" ra="MAC_FMT" reason=%u, tid=%u, initiator=%u%s, %d/%d in %u ms\n"
, FUNC_ADPT_ARG(adapter), MAC_ARG(ra), reason, tid, initiator
void issue_action_BSSCoexistPacket(_adapter *padapter)
struct wlan_network *pnetwork = NULL;
_queue *queue = &(pmlmepriv->scanned_queue);
u8 InfoContent[16] = {0};
u8 ICS[8][15];
if ((pmlmepriv->num_FortyMHzIntolerant == 0) && (pmlmepriv->num_sta_no_ht == 0))
if (_TRUE == pmlmeinfo->bwmode_updated)
category = RTW_WLAN_CATEGORY_PUBLIC;
action = ACT_PUBLIC_BSSCOEXIST;
/* TODO calculate 40Mhz intolerant via ch and ch offset */
/* if (pmlmepriv->num_FortyMHzIntolerant > 0) */
u8 iedata = 0;
iedata |= BIT(2);/* 20 MHz BSS Width Request */
pframe = rtw_set_ie(pframe, EID_BSSCoexistence, 1, &iedata, &(pattrib->pktlen));
/* */
_rtw_memset(ICS, 0, sizeof(ICS));
if (pmlmepriv->num_sta_no_ht > 0) {
_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
phead = get_list_head(queue);
int len;
WLAN_BSSID_EX *pbss_network;
if (rtw_end_of_queue_search(phead, plist) == _TRUE)
pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
pbss_network = (WLAN_BSSID_EX *)&pnetwork->network;
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))
ICS[0][pbss_network->Configuration.DSConfig] = 1;
if (ICS[0][0] == 0)
ICS[0][0] = 1;
_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
for (i = 0; i < 8; i++) {
if (ICS[i][0] == 1) {
int j, k = 0;
InfoContent[k] = i;
/* SET_BSS_INTOLERANT_ELE_REG_CLASS(InfoContent,i); */
k++;
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); */
pframe = rtw_set_ie(pframe, EID_BSSIntolerantChlReport, k, InfoContent, &(pattrib->pktlen));
/* Spatial Multiplexing Powersave (SMPS) action frame */
int _issue_action_SM_PS(_adapter *padapter , unsigned char *raddr , u8 NewMimoPsMode , u8 wait_ack)
unsigned char category = RTW_WLAN_CATEGORY_HT;
u8 action = RTW_WLAN_ACTION_HT_SM_PS;
u8 sm_power_control = 0;
if (NewMimoPsMode == WLAN_HT_CAP_SM_PS_DISABLED) {
sm_power_control = sm_power_control & ~(BIT(0)); /* SM Power Save Enable = 0 SM Power Save Disable */
} else if (NewMimoPsMode == WLAN_HT_CAP_SM_PS_STATIC) {
sm_power_control = sm_power_control | BIT(0); /* SM Power Save Enable = 1 SM Power Save Enable */
sm_power_control = sm_power_control & ~(BIT(1)); /* SM Mode = 0 Static Mode */
} else if (NewMimoPsMode == WLAN_HT_CAP_SM_PS_DYNAMIC) {
sm_power_control = sm_power_control | BIT(1); /* SM Mode = 1 Dynamic Mode */
RTW_INFO("%s, sm_power_control=%u, NewMimoPsMode=%u\n", __FUNCTION__ , sm_power_control , NewMimoPsMode);
_rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); /* RA */
_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); /* DA = RA */
pframe = rtw_set_fixed_ie(pframe, 1, &(sm_power_control), &(pattrib->pktlen));
RTW_INFO("%s, ack to\n", __func__);
int issue_action_SM_PS_wait_ack(_adapter *padapter, unsigned char *raddr, u8 NewMimoPsMode, int try_cnt, int wait_ms)
ret = _issue_action_SM_PS(padapter, raddr, NewMimoPsMode , wait_ms > 0 ? _TRUE : _FALSE);
RTW_INFO(FUNC_ADPT_FMT" to "MAC_FMT", %s , %d/%d in %u ms\n",
FUNC_ADPT_ARG(padapter), MAC_ARG(raddr),
RTW_INFO(FUNC_ADPT_FMT", %s , %d/%d in %u ms\n",
FUNC_ADPT_ARG(padapter),
int issue_action_SM_PS(_adapter *padapter , unsigned char *raddr , u8 NewMimoPsMode)
RTW_INFO("%s to "MAC_FMT"\n", __func__, MAC_ARG(raddr));
return _issue_action_SM_PS(padapter, raddr, NewMimoPsMode , _FALSE);
* _send_delba_sta_tid - Cancel the AMPDU association for the specific @sta, @tid
* @initiator: if we are the initiator of AMPDU association
* @force: cancel and send DELBA even when no AMPDU association is setup
* @wait_ack: send delba with xmit ack (valid when initiator == 0)
* _FAIL if sta is NULL
* when initiator is 1, always _SUCCESS
* when initiator is 0, _SUCCESS if DELBA is acked
static unsigned int _send_delba_sta_tid(_adapter *adapter, u8 initiator, struct sta_info *sta, u8 tid
, u8 force, int wait_ack)
if (sta == NULL) {
ret = _FAIL;
if (initiator == 0) {
/* recipient */
if (force || sta->recvreorder_ctrl[tid].enable == _TRUE) {
u8 ampdu_size_bak = sta->recvreorder_ctrl[tid].ampdu_size;
sta->recvreorder_ctrl[tid].enable = _FALSE;
sta->recvreorder_ctrl[tid].ampdu_size = RX_AMPDU_SIZE_INVALID;
if (rtw_del_rx_ampdu_test_trigger_no_tx_fail())
else if (wait_ack)
ret = issue_del_ba_ex(adapter, sta->cmn.mac_addr, tid, 37, initiator, 3, 1);
issue_del_ba(adapter, sta->cmn.mac_addr, tid, 37, initiator);
if (ret == _FAIL && sta->recvreorder_ctrl[tid].enable == _FALSE)
sta->recvreorder_ctrl[tid].ampdu_size = ampdu_size_bak;
} else if (initiator == 1) {
/* originator */
if (force || sta->htpriv.agg_enable_bitmap & BIT(tid)) {
sta->htpriv.agg_enable_bitmap &= ~BIT(tid);
sta->htpriv.candidate_tid_bitmap &= ~BIT(tid);
inline unsigned int send_delba_sta_tid(_adapter *adapter, u8 initiator, struct sta_info *sta, u8 tid
, u8 force)
return _send_delba_sta_tid(adapter, initiator, sta, tid, force, 0);
inline unsigned int send_delba_sta_tid_wait_ack(_adapter *adapter, u8 initiator, struct sta_info *sta, u8 tid
return _send_delba_sta_tid(adapter, initiator, sta, tid, force, 1);
unsigned int send_delba(_adapter *padapter, u8 initiator, u8 *addr)
RTW_INFO("%s:%s\n", __func__, (initiator == 0) ? "RX_DIR" : "TX_DIR");
if (initiator == 1) /* originator */
RTW_INFO("tx agg_enable_bitmap(0x%08x)\n", psta->htpriv.agg_enable_bitmap);
for (tid = 0; tid < TID_NUM; tid++)
send_delba_sta_tid(padapter, initiator, psta, tid, 0);
unsigned int send_beacon(_adapter *padapter)
#if defined(CONFIG_PCI_HCI) && !defined(CONFIG_PCI_BCN_POLLING)
u8 vap_id = padapter->vap_id;
/* bypass TX BCN because vap_id is invalid*/
if (vap_id == CONFIG_LIMITED_AP_NUM)
/* bypass TX BCN queue because op ch is switching/waiting */
if (check_fwstate(&padapter->mlmepriv, WIFI_OP_CH_SWITCHING)
|| IS_CH_WAITING(adapter_to_rfctl(padapter))
rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL);
/* 8192EE Port select for Beacon DL */
rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL);
rtw_hal_set_hwreg(padapter, HW_VAR_BCN_HEAD_SEL, &vap_id);
issue_beacon(padapter, 0);
vap_id = 0xFF;
#ifdef RTL8814AE_SW_BCN
if (GET_HAL_DATA(padapter)->bCorrectBCN != 0)
RTW_INFO("%s, line%d, Warnning, pHalData->bCorrectBCN != 0\n", __func__, __LINE__);
GET_HAL_DATA(padapter)->bCorrectBCN = 1;
/* CONFIG_PCI_BCN_POLLING is for pci interface beacon polling mode */
#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)|| defined(CONFIG_PCI_BCN_POLLING)
u8 bxmitok = _FALSE;
int issue = 0;
int poll = 0;
#if defined(CONFIG_USB_HCI)
#if defined(CONFIG_RTL8812A)
if (IS_FULL_SPEED_USB(padapter)) {
issue_beacon(padapter, 300);
bxmitok = _TRUE;
#if defined(CONFIG_PCI_BCN_POLLING)
issue_beacon(padapter, 100);
issue++;
rtw_msleep_os(1);
rtw_yield_os();
rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bxmitok));
poll++;
} while ((poll % 10) != 0 && _FALSE == bxmitok && !RTW_CANNOT_RUN(padapter));
rtw_hal_unmap_beacon_icf(padapter);
} while (bxmitok == _FALSE && (issue < 100) && !RTW_CANNOT_RUN(padapter));
if (_FALSE == bxmitok) {
RTW_INFO("%s fail! %u ms\n", __FUNCTION__, rtw_get_passing_time_ms(start));
#ifdef CONFIG_BCN_RECOVERY
GET_HAL_DATA(padapter)->issue_bcn_fail++;
#endif /*CONFIG_BCN_RECOVERY*/
u32 passing_time = rtw_get_passing_time_ms(start);
if (passing_time > 100 || issue > 3)
RTW_INFO("%s success, issue:%d, poll:%d, %u ms\n", __FUNCTION__, issue, poll, rtw_get_passing_time_ms(start));
else if (0)
#ifdef CONFIG_FW_CORRECT_BCN
rtw_hal_fw_correct_bcn(padapter);
#endif /*defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)*/
Following are some utitity fuctions for WiFi MLME
BOOLEAN IsLegal5GChannel(
PADAPTER Adapter,
u8 channel)
u8 Channel_5G[45] = {36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58,
60, 62, 64, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122,
124, 126, 128, 130, 132, 134, 136, 138, 140, 149, 151, 153, 155, 157, 159,
161, 163, 165
for (i = 0; i < sizeof(Channel_5G); i++)
if (channel == Channel_5G[i])
/* collect bss info from Beacon and Probe request/response frames. */
u8 collect_bss_info(_adapter *padapter, union recv_frame *precv_frame, WLAN_BSSID_EX *bssid)
sint len;
u8 rf_path;
u16 val16, subtype;
u32 packet_len = precv_frame->u.hdr.len;
u8 ie_offset;
struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter);
#ifdef CONFIG_LAYER2_ROAMING
u32 *pbuf;
len = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr);
if (len > MAX_IE_SZ) {
/* RTW_INFO("IE too long for survey event\n"); */
_rtw_memset(bssid, 0, sizeof(WLAN_BSSID_EX));
subtype = get_frame_sub_type(pframe);
if (subtype == WIFI_BEACON) {
bssid->Reserved[0] = BSS_TYPE_BCN;
ie_offset = _BEACON_IE_OFFSET_;
/* FIXME : more type */
if (subtype == WIFI_PROBERSP) {
ie_offset = _PROBERSP_IE_OFFSET_;
bssid->Reserved[0] = BSS_TYPE_PROB_RSP;
} else if (subtype == WIFI_PROBEREQ) {
ie_offset = _PROBEREQ_IE_OFFSET_;
bssid->Reserved[0] = BSS_TYPE_PROB_REQ;
bssid->Reserved[0] = BSS_TYPE_UNDEF;
ie_offset = _FIXED_IE_LENGTH_;
bssid->Length = sizeof(WLAN_BSSID_EX) - MAX_IE_SZ + len;
/* below is to copy the information element */
bssid->IELength = len;
_rtw_memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength);
/* get the signal strength */
/* bssid->Rssi = precv_frame->u.hdr.attrib.SignalStrength; */ /* 0-100 index. */
bssid->Rssi = precv_frame->u.hdr.attrib.phy_info.recv_signal_power; /* in dBM.raw data */
bssid->PhyInfo.SignalQuality = precv_frame->u.hdr.attrib.phy_info.signal_quality;/* in percentage */
bssid->PhyInfo.SignalStrength = precv_frame->u.hdr.attrib.phy_info.signal_strength;/* in percentage */
/* get rx_snr */
if (precv_frame->u.hdr.attrib.data_rate >= DESC_RATE11M) {
bssid->PhyInfo.is_cck_rate = 0;
for (rf_path = 0; rf_path < hal_spec->rf_reg_path_num; rf_path++)
bssid->PhyInfo.rx_snr[rf_path] =
precv_frame->u.hdr.attrib.phy_info.rx_snr[rf_path];
bssid->PhyInfo.is_cck_rate = 1;
#ifdef CONFIG_ANTENNA_DIVERSITY
rtw_hal_get_odm_var(padapter, HAL_ODM_ANTDIV_SELECT, &(bssid->PhyInfo.Optimum_antenna), NULL);
p = rtw_get_ie(bssid->IEs + ie_offset, _SSID_IE_, &len, bssid->IELength - ie_offset);
RTW_INFO("marc: cannot find SSID for survey event\n");
if (*(p + 1)) {
if (len > NDIS_802_11_LENGTH_SSID) {
RTW_INFO("%s()-%d: IE too long (%d) for survey event\n", __FUNCTION__, __LINE__, len);
_rtw_memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1));
bssid->Ssid.SsidLength = *(p + 1);
bssid->Ssid.SsidLength = 0;
_rtw_memset(bssid->SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX);
/* checking rate info... */
i = 0;
p = rtw_get_ie(bssid->IEs + ie_offset, _SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset);
if (len > NDIS_802_11_LENGTH_RATES_EX) {
#ifdef CONFIG_CHECK_SPECIFIC_IE_CONTENT
if (rtw_validate_value(_SUPPORTEDRATES_IE_, p+2, len) == _FALSE) {
rtw_absorb_ssid_ifneed(padapter, bssid, pframe);
RTW_DBG_DUMP("Invalidated Support Rate IE --", p, len+2);
#endif /* #ifdef CONFIG_CHECK_SPECIFIC_IE_CONTENT */
_rtw_memcpy(bssid->SupportedRates, (p + 2), len);
i = len;
p = rtw_get_ie(bssid->IEs + ie_offset, _EXT_SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset);
if (len > (NDIS_802_11_LENGTH_RATES_EX - i)) {
if (rtw_validate_value(_EXT_SUPPORTEDRATES_IE_, p+2, len) == _FALSE) {
RTW_DBG_DUMP("Invalidated EXT Support Rate IE --", p, len+2);
_rtw_memcpy(bssid->SupportedRates + i, (p + 2), len);
if (subtype == WIFI_PROBEREQ) {
/* Set Listion Channel */
p2p_ie = rtw_get_p2p_ie(bssid->IEs, bssid->IELength, NULL, &p2p_ielen);
u8 listen_ch[5] = { 0x00 };
rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_LISTEN_CH, listen_ch, &attr_contentlen);
bssid->Configuration.DSConfig = listen_ch[4];
/* use current channel */
bssid->Configuration.DSConfig = padapter->mlmeextpriv.cur_channel;
RTW_INFO("%s()-%d: Cannot get p2p_ie. set DSconfig to op_ch(%d)\n", __FUNCTION__, __LINE__, bssid->Configuration.DSConfig);
bssid->InfrastructureMode = Ndis802_11Infrastructure;
_rtw_memcpy(bssid->MacAddress, get_addr2_ptr(pframe), ETH_ALEN);
bssid->Privacy = 1;
if (bssid->IELength < 12)
/* Checking for DSConfig */
p = rtw_get_ie(bssid->IEs + ie_offset, _DSSET_IE_, &len, bssid->IELength - ie_offset);
bssid->Configuration.DSConfig = 0;
bssid->Configuration.Length = 0;
if (p)
bssid->Configuration.DSConfig = *(p + 2);
/* 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);
struct HT_info_element *HT_info = (struct HT_info_element *)(p + 2);
bssid->Configuration.DSConfig = HT_info->primary_channel;
bssid->Configuration.DSConfig = rtw_get_oper_ch(padapter);
_rtw_memcpy(&bssid->Configuration.BeaconPeriod, rtw_get_beacon_interval_from_ie(bssid->IEs), 2);
bssid->Configuration.BeaconPeriod = le32_to_cpu(bssid->Configuration.BeaconPeriod);
val16 = rtw_get_capability((WLAN_BSSID_EX *)bssid);
if ((val16 & 0x03) == cap_ESS) {
} else if ((val16 & 0x03) == cap_IBSS){
bssid->InfrastructureMode = Ndis802_11IBSS;
_rtw_memcpy(bssid->MacAddress, GetAddr3Ptr(pframe), ETH_ALEN);
} else if ((val16 & 0x03) == 0x00){
u8 *mesh_id_ie, *mesh_conf_ie;
sint mesh_id_ie_len, mesh_conf_ie_len;
mesh_id_ie = rtw_get_ie(bssid->IEs + ie_offset, WLAN_EID_MESH_ID, &mesh_id_ie_len, bssid->IELength - ie_offset);
mesh_conf_ie = rtw_get_ie(bssid->IEs + ie_offset, WLAN_EID_MESH_CONFIG, &mesh_conf_ie_len, bssid->IELength - ie_offset);
if (mesh_id_ie || mesh_conf_ie) {
if (!mesh_id_ie) {
RTW_INFO("cannot find Mesh ID for survey event\n");
if (mesh_id_ie_len) {
if (mesh_id_ie_len > NDIS_802_11_LENGTH_SSID) {
RTW_INFO("Mesh ID too long (%d) for survey event\n", mesh_id_ie_len);
_rtw_memcpy(bssid->mesh_id.Ssid, (mesh_id_ie + 2), mesh_id_ie_len);
bssid->mesh_id.SsidLength = mesh_id_ie_len;
bssid->mesh_id.SsidLength = 0;
if (!mesh_conf_ie) {
RTW_INFO("cannot find Mesh config for survey event\n");
if (mesh_conf_ie_len != 7) {
RTW_INFO("invalid Mesh conf IE len (%d) for survey event\n", mesh_conf_ie_len);
bssid->InfrastructureMode = Ndis802_11_mesh;
/* default cases */
if (val16 & BIT(4))
bssid->Privacy = 0;
bssid->Configuration.ATIMWindow = 0;
/* 20/40 BSS Coexistence check */
if ((pregistrypriv->wifi_spec == 1) && (_FALSE == pmlmeinfo->bwmode_updated)) {
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);
if (pHT_caps->u.HT_cap_element.HT_caps_info & BIT(14))
pmlmepriv->num_FortyMHzIntolerant++;
pmlmepriv->num_sta_no_ht++;
#if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) & 1
if (strcmp(bssid->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) {
RTW_INFO("Receiving %s("MAC_FMT", DSConfig:%u) from ch%u with ss:%3u, sq:%3u, RawRSSI:%3ld\n"
, bssid->Ssid.Ssid, MAC_ARG(bssid->MacAddress), bssid->Configuration.DSConfig
, bssid->PhyInfo.SignalStrength, bssid->PhyInfo.SignalQuality, bssid->Rssi
/* mark bss info receving from nearby channel as SignalQuality 101 */
if (bssid->Configuration.DSConfig != rtw_get_oper_ch(padapter))
bssid->PhyInfo.SignalQuality = 101;
p = rtw_get_ie(bssid->IEs + ie_offset, _EID_RRM_EN_CAP_IE_, &len, bssid->IELength - ie_offset);
_rtw_memcpy(bssid->PhyInfo.rm_en_cap, (p + 2), *(p + 1));
/* save freerun counter */
bssid->PhyInfo.free_cnt = precv_frame->u.hdr.attrib.free_cnt;
pbuf = (u32 *)((u8 *)pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
bssid->tsf = le32_to_cpu(*(pbuf + 1));
bssid->tsf = bssid->tsf << 32;
bssid->tsf |= le32_to_cpu(*pbuf);
void start_create_ibss(_adapter *padapter)
unsigned short caps;
u8 val8;
u8 join_type;
WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network));
u8 doiqk = _FALSE;
pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig;
pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork);
/* update wireless mode */
update_wireless_mode(padapter);
/* udpate capability */
caps = rtw_get_capability((WLAN_BSSID_EX *)pnetwork);
update_capinfo(padapter, caps);
if (caps & cap_IBSS) { /* adhoc master */
/* set_opmode_cmd(padapter, adhoc); */ /* removed */
val8 = 0xcf;
rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
doiqk = _TRUE;
rtw_hal_set_hwreg(padapter , HW_VAR_DO_IQK , &doiqk);
/* switch channel */
set_channel_bwmode(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
doiqk = _FALSE;
beacon_timing_control(padapter);
/* set msr to WIFI_FW_ADHOC_STATE */
pmlmeinfo->state = WIFI_FW_ADHOC_STATE;
Set_MSR(padapter, (pmlmeinfo->state & 0x3));
/* issue beacon */
if (send_beacon(padapter) == _FAIL) {
report_join_res(padapter, -1, WLAN_STATUS_UNSPECIFIED_FAILURE);
rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, padapter->registrypriv.dev_network.MacAddress);
rtw_hal_rcr_set_chk_bssid(padapter, MLME_ADHOC_STARTED);
join_type = 0;
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
rtw_btcoex_connect_notify(padapter, join_type);
report_join_res(padapter, 1, WLAN_STATUS_SUCCESS);
rtw_indicate_connect(padapter);
RTW_INFO("start_create_ibss, invalid cap:%x\n", caps);
/* update bc/mc sta_info */
update_bmc_sta(padapter);
void start_clnt_join(_adapter *padapter)
int beacon_timeout;
u8 ASIX_ID[] = {0x00, 0x0E, 0xC6};
/* check if sta is ASIX peer and fix IOT issue if it is. */
if (_rtw_memcmp(get_my_bssid(&pmlmeinfo->network) , ASIX_ID , 3)) {
u8 iot_flag = _TRUE;
rtw_hal_set_hwreg(padapter, HW_VAR_ASIX_IOT, (u8 *)(&iot_flag));
if (caps & cap_ESS) {
Set_MSR(padapter, WIFI_FW_STATION_STATE);
val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf;
if (padapter->wapiInfo.bWapiEnable && pmlmeinfo->auth_algo == dot11AuthAlgrthm_WAPI) {
/* Disable TxUseDefaultKey, RxUseDefaultKey, RxBroadcastUseDefaultKey. */
val8 = 0x4c;
#ifdef CONFIG_DEAUTH_BEFORE_CONNECT
/* 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. */
_queue *queue = &(padapter->mlmepriv.scanned_queue);
_list *head = get_list_head(queue);
_list *pos = get_next(head);
struct wlan_network *scanned = NULL;
u8 ie_offset = 0;
bool has_p2p_ie = _FALSE;
_enter_critical_bh(&(padapter->mlmepriv.scanned_queue.lock), &irqL);
for (pos = get_next(head); !rtw_end_of_queue_search(head, pos); pos = get_next(pos)) {
scanned = LIST_CONTAINOR(pos, struct wlan_network, list);
if (_rtw_memcmp(&(scanned->network.Ssid), &(pnetwork->Ssid), sizeof(NDIS_802_11_SSID)) == _TRUE
&& _rtw_memcmp(scanned->network.MacAddress, pnetwork->MacAddress, sizeof(NDIS_802_11_MAC_ADDRESS)) == _TRUE
ie_offset = (scanned->network.Reserved[0] == BSS_TYPE_PROB_REQ ? 0 : 12);
if (rtw_get_p2p_ie(scanned->network.IEs + ie_offset, scanned->network.IELength - ie_offset, NULL, NULL))
has_p2p_ie = _TRUE;
_exit_critical_bh(&(padapter->mlmepriv.scanned_queue.lock), &irqL);
if (scanned == NULL || rtw_end_of_queue_search(head, pos) || has_p2p_ie == _FALSE)
/* To avoid connecting to AP fail during resume process, change retry count from 5 to 1 */
issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, 1, 100);
#endif /* CONFIG_DEAUTH_BEFORE_CONNECT */
/* 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);
_set_timer(&padapter->mlmepriv.assoc_timer,
(REAUTH_TO * REAUTH_LIMIT) + (REASSOC_TO * REASSOC_LIMIT) + beacon_timeout);
rtw_ft_start_clnt_join(padapter);
rtw_sta_linking_test_set_start();
pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE;
} else if (caps & cap_IBSS) { /* adhoc client */
Set_MSR(padapter, WIFI_FW_ADHOC_STATE);
/* RTW_INFO("marc: invalid cap:%x\n", caps); */
void start_clnt_auth(_adapter *padapter)
pmlmeinfo->state &= (~WIFI_FW_AUTH_NULL);
pmlmeinfo->state |= WIFI_FW_AUTH_STATE;
pmlmeinfo->auth_seq = 1;
rtw_ft_set_status(padapter, RTW_FT_AUTHENTICATING_STA);
RTW_PRINT("start ft auth\n");
RTW_PRINT("start auth\n");
padapter->securitypriv.auth_alg = WLAN_AUTH_OPEN;
goto no_external_auth;
RTW_PRINT("SAE: start external auth\n");
rtw_cfg80211_external_auth_request(padapter, NULL);
no_external_auth:
void start_clnt_assoc(_adapter *padapter)
pmlmeinfo->state &= (~(WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE));
pmlmeinfo->state |= (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE);
if (rtw_ft_roam(padapter)
|| rtw_wnm_btm_reassoc_req(padapter)
issue_reassocreq(padapter);
issue_assocreq(padapter);
set_link_timer(pmlmeext, REASSOC_TO);
unsigned int receive_disconnect(_adapter *padapter, unsigned char *MacAddr, unsigned short reason, u8 locally_generated)
if (!(_rtw_memcmp(MacAddr, get_my_bssid(&pmlmeinfo->network), ETH_ALEN)))
rtw_rson_do_disconnect(padapter);
if (report_del_sta_event(padapter, MacAddr, reason, _TRUE, locally_generated) != _FAIL)
} else if (pmlmeinfo->state & WIFI_FW_LINKING_STATE) {
if (report_join_res(padapter, -2, reason) != _FAIL)
RTW_INFO(FUNC_ADPT_FMT" - End to Disconnect\n", FUNC_ADPT_ARG(padapter));
rtw_ft_roam_status_reset(padapter);
rtw_wnm_reset_btm_state(padapter);
static void rtw_hidden_ssid_bss_count(_adapter *adapter, WLAN_BSSID_EX *bss)
RT_CHANNEL_INFO *chset = rfctl->channel_set;
int chset_idx;
if (bss->InfrastructureMode != Ndis802_11Infrastructure)
if (!hidden_ssid_ap(bss))
chset_idx = rtw_chset_search_ch(chset, bss->Configuration.DSConfig);
if (chset_idx < 0)
chset[chset_idx].hidden_bss_cnt++;
Following are the functions to report events
void report_survey_event(_adapter *padapter, union recv_frame *precv_frame)
struct cmd_obj *pcmd_obj;
u8 *pevtcmd;
u32 cmdsz;
struct survey_event *psurvey_evt;
struct rtw_evt_header *evt_hdr;
struct cmd_priv *pcmdpriv;
/* u8 *pframe = precv_frame->u.hdr.rx_data; */
/* uint len = precv_frame->u.hdr.len; */
pmlmeext = &padapter->mlmeextpriv;
pcmdpriv = &padapter->cmdpriv;
pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (pcmd_obj == NULL)
cmdsz = (sizeof(struct survey_event) + sizeof(struct rtw_evt_header));
pevtcmd = (u8 *)rtw_zmalloc(cmdsz);
if (pevtcmd == NULL) {
rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj));
_rtw_init_listhead(&pcmd_obj->list);
pcmd_obj->cmdcode = CMD_SET_MLME_EVT;
pcmd_obj->cmdsz = cmdsz;
pcmd_obj->parmbuf = pevtcmd;
pcmd_obj->rsp = NULL;
pcmd_obj->rspsz = 0;
evt_hdr = (struct rtw_evt_header *)(pevtcmd);
evt_hdr->len = sizeof(struct survey_event);
evt_hdr->id = EVT_SURVEY;
evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq);
psurvey_evt = (struct survey_event *)(pevtcmd + sizeof(struct rtw_evt_header));
if (collect_bss_info(padapter, precv_frame, (WLAN_BSSID_EX *)&psurvey_evt->bss) == _FAIL) {
rtw_mfree((u8 *)pevtcmd, cmdsz);
rtw_hidden_ssid_bss_count(padapter, &psurvey_evt->bss);
rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
pmlmeext->sitesurvey_res.bss_cnt++;
* @acs: aim to trigger channel selection
void report_surveydone_event(_adapter *padapter, bool acs)
struct surveydone_event *psurveydone_evt;
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
cmdsz = (sizeof(struct surveydone_event) + sizeof(struct rtw_evt_header));
evt_hdr->len = sizeof(struct surveydone_event);
evt_hdr->id = EVT_SURVEY_DONE;
psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct rtw_evt_header));
psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt;
psurveydone_evt->activate_ch_cnt = pmlmeext->sitesurvey_res.activate_ch_cnt;
psurveydone_evt->acs = acs;
RTW_INFO("survey done event(%x) band:%d for "ADPT_FMT"\n", psurveydone_evt->bss_cnt, padapter->setband, ADPT_ARG(padapter));
u32 report_join_res(_adapter *padapter, int aid_res, u16 status)
struct joinbss_event *pjoinbss_evt;
cmdsz = (sizeof(struct joinbss_event) + sizeof(struct rtw_evt_header));
evt_hdr->len = sizeof(struct joinbss_event);
evt_hdr->id = EVT_JOINBSS;
pjoinbss_evt = (struct joinbss_event *)(pevtcmd + sizeof(struct rtw_evt_header));
_rtw_memcpy((unsigned char *)(&(pjoinbss_evt->network.network)), &(pmlmeinfo->network), sizeof(WLAN_BSSID_EX));
pjoinbss_evt->network.join_res = pjoinbss_evt->network.aid = aid_res;
RTW_INFO("report_join_res(%d, %u)\n", aid_res, status);
rtw_joinbss_event_prehandle(padapter, (u8 *)&pjoinbss_evt->network, status);
ret = rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
void report_wmm_edca_update(_adapter *padapter)
struct wmm_event *pwmm_event;
cmdsz = (sizeof(struct wmm_event) + sizeof(struct rtw_evt_header));
evt_hdr->len = sizeof(struct wmm_event);
evt_hdr->id = EVT_WMM_UPDATE;
pwmm_event = (struct wmm_event *)(pevtcmd + sizeof(struct rtw_evt_header));
pwmm_event->wmm = 0;
u32 report_del_sta_event(_adapter *padapter, unsigned char *MacAddr, unsigned short reason, bool enqueue, u8 locally_generated)
int mac_id = -1;
struct stadel_event *pdel_sta_evt;
u8 res = _SUCCESS;
/* prepare cmd parameter */
cmdsz = (sizeof(struct stadel_event) + sizeof(struct rtw_evt_header));
res = _FAIL;
evt_hdr->len = sizeof(struct stadel_event);
evt_hdr->id = EVT_DEL_STA;
pdel_sta_evt = (struct stadel_event *)(pevtcmd + sizeof(struct rtw_evt_header));
_rtw_memcpy((unsigned char *)(&(pdel_sta_evt->macaddr)), MacAddr, ETH_ALEN);
_rtw_memcpy((unsigned char *)(pdel_sta_evt->rsvd), (unsigned char *)(&reason), 2);
psta = rtw_get_stainfo(&padapter->stapriv, MacAddr);
mac_id = (int)psta->cmn.mac_id;
mac_id = (-1);
pdel_sta_evt->mac_id = mac_id;
pdel_sta_evt->locally_generated = locally_generated;
if (!enqueue) {
/* do directly */
rtw_stadel_event_callback(padapter, (u8 *)pdel_sta_evt);
rtw_mfree(pevtcmd, cmdsz);
if (pcmd_obj == NULL) {
res = rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
RTW_INFO(FUNC_ADPT_FMT" "MAC_FMT" mac_id=%d, enqueue:%d, res:%u\n"
, FUNC_ADPT_ARG(padapter), MAC_ARG(MacAddr), mac_id, enqueue, res);
void report_add_sta_event(_adapter *padapter, unsigned char *MacAddr)
struct stassoc_event *padd_sta_evt;
cmdsz = (sizeof(struct stassoc_event) + sizeof(struct rtw_evt_header));
evt_hdr->len = sizeof(struct stassoc_event);
evt_hdr->id = EVT_ADD_STA;
padd_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct rtw_evt_header));
_rtw_memcpy((unsigned char *)(&(padd_sta_evt->macaddr)), MacAddr, ETH_ALEN);
RTW_INFO("report_add_sta_event: add STA\n");
bool rtw_port_switch_chk(_adapter *adapter)
bool switch_needed = _FALSE;
#ifdef CONFIG_RUNTIME_PORT_SWITCH
struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(dvobj);
_adapter *if_port0 = NULL;
_adapter *if_port1 = NULL;
struct mlme_ext_info *if_port0_mlmeinfo = NULL;
struct mlme_ext_info *if_port1_mlmeinfo = NULL;
if (get_hw_port(dvobj->padapters[i]) == HW_PORT0) {
if_port0 = dvobj->padapters[i];
if_port0_mlmeinfo = &(if_port0->mlmeextpriv.mlmext_info);
} else if (get_hw_port(dvobj->padapters[i]) == HW_PORT1) {
if_port1 = dvobj->padapters[i];
if_port1_mlmeinfo = &(if_port1->mlmeextpriv.mlmext_info);
if (if_port0 == NULL) {
if (if_port1 == NULL) {
#ifdef DBG_RUNTIME_PORT_SWITCH
RTW_INFO(FUNC_ADPT_FMT" wowlan_mode:%u\n"
ADPT_FMT", port0, mlmeinfo->state:0x%08x, p2p_state:%d, %d\n"
ADPT_FMT", port1, mlmeinfo->state:0x%08x, p2p_state:%d, %d\n",
FUNC_ADPT_ARG(adapter), pwrctl->wowlan_mode,
ADPT_ARG(if_port0), if_port0_mlmeinfo->state, rtw_p2p_state(&if_port0->wdinfo), rtw_p2p_chk_state(&if_port0->wdinfo, P2P_STATE_NONE),
ADPT_ARG(if_port1), if_port1_mlmeinfo->state, rtw_p2p_state(&if_port1->wdinfo), rtw_p2p_chk_state(&if_port1->wdinfo, P2P_STATE_NONE));
#endif /* DBG_RUNTIME_PORT_SWITCH */
#ifdef CONFIG_WOWLAN
/* WOWLAN interface(primary, for now) should be port0 */
if (pwrctl->wowlan_mode == _TRUE) {
if (!is_primary_adapter(if_port0)) {
RTW_INFO("%s "ADPT_FMT" enable WOWLAN\n", __func__, ADPT_ARG(if_port1));
switch_needed = _TRUE;
#endif /* CONFIG_WOWLAN */
/* AP/Mesh should use port0 for ctl frame's ack */
if ((if_port1_mlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) {
RTW_INFO("%s "ADPT_FMT" is AP/GO/Mesh\n", __func__, ADPT_ARG(if_port1));
/* GC should use port0 for p2p ps */
if (((if_port1_mlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE)
&& (if_port1_mlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)
&& !rtw_p2p_chk_state(&if_port1->wdinfo, P2P_STATE_NONE)
&& !check_fwstate(&if_port1->mlmepriv, WIFI_UNDER_WPS)
RTW_INFO("%s "ADPT_FMT" is GC\n", __func__, ADPT_ARG(if_port1));
/* port1 linked, but port0 not linked */
if ((if_port1_mlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)
&& !(if_port0_mlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)
&& ((if_port0_mlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)
RTW_INFO("%s "ADPT_FMT" is SINGLE_LINK\n", __func__, ADPT_ARG(if_port1));
RTW_INFO(FUNC_ADPT_FMT" ret:%d\n", FUNC_ADPT_ARG(adapter), switch_needed);
#endif /* CONFIG_RUNTIME_PORT_SWITCH */
return switch_needed;
Following are the event callback functions
/* for sta/adhoc mode */
void update_sta_info(_adapter *padapter, struct sta_info *psta)
/* ERP */
VCS_update(padapter, psta);
/* HT */
if (pmlmepriv->htpriv.ht_option) {
psta->htpriv.ampdu_enable = pmlmepriv->htpriv.ampdu_enable;
psta->htpriv.rx_ampdu_min_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2;
if (support_short_GI(padapter, &(pmlmeinfo->HT_caps), CHANNEL_WIDTH_20))
psta->htpriv.sgi_20m = _TRUE;
if (support_short_GI(padapter, &(pmlmeinfo->HT_caps), CHANNEL_WIDTH_40))
psta->htpriv.sgi_40m = _TRUE;
psta->qos_option = _TRUE;
psta->htpriv.ldpc_cap = pmlmepriv->htpriv.ldpc_cap;
psta->htpriv.stbc_cap = pmlmepriv->htpriv.stbc_cap;
psta->htpriv.beamform_cap = pmlmepriv->htpriv.beamform_cap;
_rtw_memcpy(&psta->htpriv.ht_cap, &pmlmeinfo->HT_caps, sizeof(struct rtw_ieee80211_ht_cap));
psta->cmn.bf_info.ht_beamform_cap = pmlmepriv->htpriv.beamform_cap;
psta->htpriv.ht_option = _FALSE;
psta->qos_option = _FALSE;
psta->htpriv.ch_offset = pmlmeext->cur_ch_offset;
psta->cmn.bw_mode = pmlmeext->cur_bwmode;
/* QoS */
if (pmlmepriv->qospriv.qos_option)
_rtw_memcpy(&psta->vhtpriv, &pmlmepriv->vhtpriv, sizeof(struct vht_priv));
if (psta->vhtpriv.vht_option) {
psta->cmn.ra_info.is_vht_enable = _TRUE;
psta->vhtpriv.beamform_cap = pmlmepriv->vhtpriv.beamform_cap;
psta->cmn.bf_info.vht_beamform_cap = pmlmepriv->vhtpriv.beamform_cap;
psta->cmn.ra_info.is_support_sgi = query_ra_short_GI(psta, rtw_get_tx_bw_mode(padapter, psta));
update_ldpc_stbc_cap(psta);
psta->state = WIFI_ASOC_STATE;
static void rtw_mlmeext_disconnect(_adapter *padapter)
u8 self_action = MLME_ACTION_UNKNOWN;
u8 state_backup = (pmlmeinfo->state & 0x03);
self_action = MLME_AP_STOPPED;
else if (MLME_IS_MESH(padapter))
self_action = MLME_MESH_STOPPED;
self_action = MLME_STA_DISCONNECTED;
else if (MLME_IS_ADHOC(padapter) || MLME_IS_ADHOC_MASTER(padapter))
self_action = MLME_ADHOC_STOPPED;
// nrm
#ifdef CONFIG_WIFI_MONITOR
else if (MLME_IS_MONITOR(padapter))
self_action = MLME_ACTION_NONE;
RTW_INFO("state:0x%x\n", MLME_STATE(padapter));
/* set_opmode_cmd(padapter, infra_client_with_mlme); */
#ifdef CONFIG_HW_P0_TSF_SYNC
if (self_action == MLME_STA_DISCONNECTED)
correct_TSF(padapter, self_action);
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, 0);
rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr);
rtw_hal_rcr_set_chk_bssid(padapter, self_action);
/* set MSR to no link state->infra. mode */
Set_MSR(padapter, _HW_STATE_STATION_);
u8 iot_flag = _FALSE;
/* mcc disconnect setting before download LPS rsvd page */
rtw_hal_set_mcc_setting_disconnect(padapter);
#endif /* CONFIG_MCC_MODE */
if (state_backup == WIFI_FW_STATION_STATE) {
if (rtw_port_switch_chk(padapter) == _TRUE) {
rtw_hal_set_hwreg(padapter, HW_VAR_PORT_SWITCH, NULL);
#ifdef CONFIG_LPS
_adapter *port0_iface = dvobj_get_port0_adapter(adapter_to_dvobj(padapter));
if (port0_iface)
rtw_lps_ctrl_wk_cmd(port0_iface, LPS_CTRL_CONNECT, RTW_CMDF_DIRECTLY);
/* switch to the 20M Hz mode after disconnect */
pmlmeext->txss_1ss = _FALSE;
#ifdef CONFIG_FCS_MODE
if (EN_FCS(padapter))
rtw_hal_set_hwreg(padapter, HW_VAR_STOP_FCS_MODE, NULL);
if (!(MLME_IS_STA(padapter) && MLME_IS_OPCH_SW(padapter))) {
/* DFS and channel status no need to check here for STA under OPCH_SW */
rtw_dfs_rd_en_decision(padapter, self_action, 0);
if (rtw_mi_get_ch_setting_union_no_self(padapter, &ch, &bw, &offset) != 0)
set_channel_bwmode(padapter, ch, offset, bw);
rtw_mi_update_union_chan_inf(padapter, ch, offset, bw);
rtw_rfctl_update_op_mode(adapter_to_rfctl(padapter), BIT(padapter->iface_id), 0);
flush_all_cam_entry(padapter);
/* pmlmepriv->LinkDetectInfo.TrafficBusyState = _FALSE; */
pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0;
pmlmepriv->LinkDetectInfo.LowPowerTransitionCount = 0;
padapter->tdlsinfo.ap_prohibited = _FALSE;
/* For TDLS channel switch, currently we only allow it to work in wifi logo test mode */
if (padapter->registrypriv.wifi_spec == 1)
padapter->tdlsinfo.ch_switch_prohibited = _FALSE;
#ifdef CONFIG_WMMPS_STA
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
/* reset currently related uapsd setting when the connection has broken */
pmlmepriv->qospriv.uapsd_max_sp_len = 0;
pmlmepriv->qospriv.uapsd_tid = 0;
pmlmepriv->qospriv.uapsd_tid_delivery_enabled = 0;
pmlmepriv->qospriv.uapsd_tid_trigger_enabled = 0;
pmlmepriv->qospriv.uapsd_ap_supported = 0;
#endif /* CONFIG_WMMPS_STA */
rtw_set_rts_bw(padapter);
void mlmeext_joinbss_event_callback(_adapter *padapter, int join_res)
#if (!defined(CONFIG_IOCTL_CFG80211)) || defined(CONFIG_LAYER2_ROAMING)
if (pmlmepriv->wpa_phase == _TRUE)
pmlmepriv->wpa_phase = _FALSE;
if (join_res < 0) {
join_type = 1;
if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE)
rtw_hal_rcr_set_chk_bssid(padapter, MLME_STA_DISCONNECTED);
goto exit_mlmeext_joinbss_event_callback;
#ifdef CONFIG_ARP_KEEP_ALIVE
pmlmepriv->bGetGateway = 1;
pmlmepriv->GetGatewayTryCnt = 0;
/* turn on dynamic functions */
/* Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, _TRUE); */
/* update IOT-releated issue */
update_IOT_info(padapter);
rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, cur_network->SupportedRates);
/* BCN interval */
rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pmlmeinfo->bcn_interval));
update_capinfo(padapter, pmlmeinfo->capability);
/* WMM, Update EDCA param */
WMMOnAssocRsp(padapter);
HTOnAssocRsp(padapter);
/* VHT */
VHTOnAssocRsp(padapter);
if (psta) { /* only for infra. mode */
psta->wireless_mode = pmlmeext->cur_wireless_mode;
/* set per sta rate after updating HT cap. */
set_sta_rate(padapter, psta);
rtw_sta_media_status_rpt(padapter, psta, 1);
/* wakeup macid after join bss successfully to ensure
the subsequent data frames can be sent out normally */
rtw_hal_macid_wakeup(padapter, psta->cmn.mac_id);
rtw_xmit_queue_clear(psta);
#ifndef CONFIG_IOCTL_CFG80211
if (is_wep_enc(psecuritypriv->dot11PrivacyAlgrthm))
rtw_sec_restore_wep_key(padapter);
if (rtw_port_switch_chk(padapter) == _TRUE)
join_type = 2;
rtw_hal_rcr_set_chk_bssid(padapter, MLME_STA_CONNECTED);
/* correcting TSF */
correct_TSF(padapter, MLME_STA_CONNECTED);
/* set_link_timer(pmlmeext, DISCONNECT_TO); */
#ifndef CONFIG_FW_MULTI_PORT_SUPPORT
if (get_hw_port(padapter) == HW_PORT0)
rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_CONNECT, RTW_CMDF_DIRECTLY);
beamforming_wk_cmd(padapter, BEAMFORMING_CTRL_ENTER, (u8 *)psta, sizeof(struct sta_info), 0);
#endif/*CONFIG_BEAMFORMING*/
exit_mlmeext_joinbss_event_callback:
rtw_join_done_chk_ch(padapter, join_res);
rtw_rson_join_done(padapter);
if ((psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_) &&
(pmlmepriv->roam_network)) {
struct xmit_frame *rframe;
_pkt *pkt;
padapter->mlmepriv.roam_network = NULL;
_enter_critical_bh(&pxmitpriv->rpkt_queue.lock, &irqL);
phead = get_list_head(&pxmitpriv->rpkt_queue);
rframe = LIST_CONTAINOR(plist, struct xmit_frame, list);
rtw_list_delete(&rframe->list);
pkt = rframe->pkt;
rframe->pkt = NULL;
rtw_xmit_posthandle(padapter, rframe, pkt);
_exit_critical_bh(&pxmitpriv->rpkt_queue.lock, &irqL);
RTW_INFO("=>%s - End to Connection without 4-way\n", __FUNCTION__);
/* currently only adhoc mode will go here */
void mlmeext_sta_add_event_callback(_adapter *padapter, struct sta_info *psta)
if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { /* adhoc master or sta_count>1 */
/* nothing to do */
} else { /* adhoc client */
/* update_TSF(pmlmeext, pframe, len); */
correct_TSF(padapter, MLME_ADHOC_STARTED);
/* start beacon */
if (send_beacon(padapter) == _FAIL)
/* update adhoc sta_info */
update_sta_info(padapter, psta);
rtw_hal_update_sta_ra_info(padapter, psta);
/* ToDo: HT for Ad-hoc */
psta->wireless_mode = rtw_check_network_type(psta->bssrateset, psta->bssratelen, pmlmeext->cur_channel);
/* rate radaptive */
Update_RA_Entry(padapter, psta);
void mlmeext_sta_del_event_callback(_adapter *padapter)
if (is_client_associated_to_ap(padapter) || is_IBSS_empty(padapter))
rtw_mlmeext_disconnect(padapter);
Following are the functions for the timer handlers
void _linked_info_dump(_adapter *padapter)
if (padapter->bLinkInfoDump) {
rtw_hal_get_def_var(padapter, HW_DEF_RA_INFO_DUMP, RTW_DBGDUMP);
rtw_hal_set_odm_var(padapter, HAL_ODM_RX_INFO_DUMP, RTW_DBGDUMP, _FALSE);
/********************************************************************
When station does not receive any packet in MAX_CONTINUAL_NORXPACKET_COUNT*2 seconds,
recipient station will teardown the block ack by issuing DELBA frame.
*********************************************************************/
void rtw_delba_check(_adapter *padapter, struct sta_info *psta, u8 from_timer)
IOT issue,occur Broadcom ap(Buffalo WZR-D1800H,Netgear R6300).
AP is originator.AP does not transmit unicast packets when STA response its BAR.
This case probably occur ap issue BAR after AP builds BA.
Follow 802.11 spec, STA shall maintain an inactivity timer for every negotiated Block Ack setup.
The inactivity timer is not reset when MPDUs corresponding to other TIDs are received.
if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_BROADCOM) {
for (i = 0; i < TID_NUM ; i++) {
if ((psta->recvreorder_ctrl[i].enable) &&
(sta_rx_data_qos_pkts(psta, i) == sta_last_rx_data_qos_pkts(psta, i)) ) {
if (_TRUE == rtw_inc_and_chk_continual_no_rx_packet(psta, i)) {
/* send a DELBA frame to the peer STA with the Reason Code field set to TIMEOUT */
if (!from_timer)
ret = issue_del_ba_ex(padapter, psta->cmn.mac_addr, i, 39, 0, 3, 1);
issue_del_ba(padapter, psta->cmn.mac_addr, i, 39, 0);
psta->recvreorder_ctrl[i].enable = _FALSE;
if (ret != _FAIL)
psta->recvreorder_ctrl[i].ampdu_size = RX_AMPDU_SIZE_INVALID;
rtw_reset_continual_no_rx_packet(psta, i);
/* The inactivity timer is reset when MPDUs to the TID is received. */
u8 chk_ap_is_alive(_adapter *padapter, struct sta_info *psta)
u8 ret = _FALSE;
#ifdef DBG_EXPIRATION_CHK
RTW_INFO(FUNC_ADPT_FMT" rx:"STA_PKTS_FMT", beacon:%llu, probersp_to_self:%llu"
/*", probersp_bm:%llu, probersp_uo:%llu, probereq:%llu, BI:%u"*/
", retry:%u\n"
, FUNC_ADPT_ARG(padapter)
, STA_RX_PKTS_DIFF_ARG(psta)
, psta->sta_stats.rx_beacon_pkts - psta->sta_stats.last_rx_beacon_pkts
, psta->sta_stats.rx_probersp_pkts - psta->sta_stats.last_rx_probersp_pkts
/*, psta->sta_stats.rx_probersp_bm_pkts - psta->sta_stats.last_rx_probersp_bm_pkts
, psta->sta_stats.rx_probersp_uo_pkts - psta->sta_stats.last_rx_probersp_uo_pkts
, psta->sta_stats.rx_probereq_pkts - psta->sta_stats.last_rx_probereq_pkts
, pmlmeinfo->bcn_interval*/
, pmlmeext->retry
RTW_INFO(FUNC_ADPT_FMT" tx_pkts:%llu, link_count:%u\n", FUNC_ADPT_ARG(padapter)
, sta_tx_pkts(psta)
, pmlmeinfo->link_count
if ((sta_rx_data_pkts(psta) == sta_last_rx_data_pkts(psta))
&& sta_rx_beacon_pkts(psta) == sta_last_rx_beacon_pkts(psta)
&& sta_rx_probersp_pkts(psta) == sta_last_rx_probersp_pkts(psta)
ret = _FALSE;
sta_update_last_rx_pkts(psta);
u8 chk_adhoc_peer_is_alive(struct sta_info *psta)
u8 ret = _TRUE;
RTW_INFO("sta:"MAC_FMT", rssi:%d, rx:"STA_PKTS_FMT", beacon:%llu, probersp_to_self:%llu"
", expire_to:%u\n"
, MAC_ARG(psta->cmn.mac_addr)
, psta->cmn.rssi_stat.rssi
, psta->expire_to
if (sta_rx_data_pkts(psta) == sta_last_rx_data_pkts(psta)
&& sta_rx_probersp_pkts(psta) == sta_last_rx_probersp_pkts(psta))
u8 chk_tdls_peer_sta_is_alive(_adapter *padapter, struct sta_info *psta)
if ((psta->sta_stats.rx_data_pkts == psta->sta_stats.last_rx_data_pkts)
&& (psta->sta_stats.rx_tdls_disc_rsp_pkts == psta->sta_stats.last_rx_tdls_disc_rsp_pkts))
void linked_status_chk_tdls(_adapter *padapter)
struct candidate_pool {
u8 addr[ETH_ALEN];
u8 ack_chk;
int i, num_teardown = 0, num_checkalive = 0;
struct tdls_txmgmt txmgmt;
struct candidate_pool checkalive[MAX_ALLOWED_TDLS_STA_NUM];
struct candidate_pool teardown[MAX_ALLOWED_TDLS_STA_NUM];
u8 tdls_sta_max = _FALSE;
#define ALIVE_MIN 2
#define ALIVE_MAX 5
_rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt));
_rtw_memset(checkalive, 0x00, sizeof(checkalive));
_rtw_memset(teardown, 0x00, sizeof(teardown));
if ((padapter->tdlsinfo.link_established == _TRUE)) {
for (i = 0; i < NUM_STA; i++) {
phead = &(pstapriv->sta_hash[i]);
psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
if (psta->tdls_sta_state & TDLS_LINKED_STATE) {
psta->alive_count++;
if (psta->alive_count >= ALIVE_MIN) {
if (chk_tdls_peer_sta_is_alive(padapter, psta) == _FALSE) {
if (psta->alive_count < ALIVE_MAX) {
_rtw_memcpy(checkalive[num_checkalive].addr, psta->cmn.mac_addr, ETH_ALEN);
checkalive[num_checkalive].psta = psta;
num_checkalive++;
_rtw_memcpy(teardown[num_teardown].addr, psta->cmn.mac_addr, ETH_ALEN);
teardown[num_teardown].psta = psta;
num_teardown++;
psta->alive_count = 0;
psta->sta_stats.last_rx_data_pkts = psta->sta_stats.rx_data_pkts;
psta->sta_stats.last_rx_tdls_disc_rsp_pkts = psta->sta_stats.rx_tdls_disc_rsp_pkts;
if ((num_checkalive >= MAX_ALLOWED_TDLS_STA_NUM) || (num_teardown >= MAX_ALLOWED_TDLS_STA_NUM)) {
tdls_sta_max = _TRUE;
if (tdls_sta_max == _TRUE)
if (num_checkalive > 0) {
for (i = 0; i < num_checkalive; i++) {
_rtw_memcpy(txmgmt.peer, checkalive[i].addr, ETH_ALEN);
issue_tdls_dis_req(padapter, &txmgmt);
if (num_teardown > 0) {
for (i = 0; i < num_teardown; i++) {
RTW_INFO("[%s %d] Send teardown to "MAC_FMT"\n", __FUNCTION__, __LINE__, MAC_ARG(teardown[i].addr));
txmgmt.status_code = _RSON_TDLS_TEAR_TOOFAR_;
_rtw_memcpy(txmgmt.peer, teardown[i].addr, ETH_ALEN);
issue_tdls_teardown(padapter, &txmgmt, _FALSE);
inline int rtw_get_rx_chk_limit(_adapter *adapter)
return adapter->stapriv.rx_chk_limit;
inline void rtw_set_rx_chk_limit(_adapter *adapter, int limit)
adapter->stapriv.rx_chk_limit = limit;
/* from_timer == 1 means driver is in LPS */
void linked_status_chk(_adapter *padapter, u8 from_timer)
u32 i;
#ifdef CONFIG_RTW_WDS
rtw_wds_gptr_expire(padapter);
if (padapter->registrypriv.mp_mode == _TRUE)
if (check_fwstate(pmlmepriv, WIFI_CSA_UPDATE_BEACON))
if (is_client_associated_to_ap(padapter)) {
/* linked infrastructure client mode */
int tx_chk = _SUCCESS, rx_chk = _SUCCESS;
int rx_chk_limit;
int link_count_limit;
#if defined(CONFIG_RTW_REPEATER_SON)
rtw_rson_scan_wk_cmd(padapter, RSON_SCAN_PROCESS);
#elif defined(CONFIG_LAYER2_ROAMING)
if (rtw_chk_roam_flags(padapter, RTW_ROAM_ACTIVE)) {
RTW_INFO("signal_strength_data.avg_val = %d\n", precvpriv->signal_strength_data.avg_val);
if ((precvpriv->signal_strength_data.avg_val < pmlmepriv->roam_rssi_threshold)
&& (rtw_get_passing_time_ms(pmlmepriv->last_roaming) >= pmlmepriv->roam_scan_int*2000)) {
rtw_roam_nb_discover(padapter, _FALSE);
pmlmepriv->need_to_roam = _TRUE;
rtw_drv_scan_by_self(padapter, RTW_AUTO_SCAN_REASON_ROAM);
pmlmepriv->last_roaming = rtw_get_current_time();
pmlmepriv->need_to_roam = _FALSE;
* due to tx ps null date to ao, so ap doest not tx pkt to driver
* we may check chk_ap_is_alive fail, and may issue_probereq to wrong channel under sitesurvey
* don't keep alive check under MCC
if (rtw_hal_mcc_link_status_chk(padapter, __func__) == _FALSE)
rx_chk_limit = rtw_get_rx_chk_limit(padapter);
if (!from_timer && pmlmepriv->bGetGateway == 1 && pmlmepriv->GetGatewayTryCnt < 3) {
RTW_INFO("do rtw_gw_addr_query() : %d\n", pmlmepriv->GetGatewayTryCnt);
pmlmepriv->GetGatewayTryCnt++;
if (rtw_gw_addr_query(padapter) == 0)
pmlmepriv->bGetGateway = 0;
_rtw_memset(pmlmepriv->gw_ip, 0, 4);
_rtw_memset(pmlmepriv->gw_mac_addr, 0, ETH_ALEN);
if (!rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE)) {
link_count_limit = 3; /* 8 sec */
link_count_limit = 15; /* 32 sec */
link_count_limit = 7; /* 16 sec */
link_count_limit = 29; /* 60 sec */
if (ATOMIC_READ(&padapter->tdlsinfo.chsw_info.chsw_on) == _TRUE)
#endif /* CONFIG_TDLS_CH_SW */
#ifdef CONFIG_TDLS_AUTOCHECKALIVE
linked_status_chk_tdls(padapter);
#endif /* CONFIG_TDLS_AUTOCHECKALIVE */
bool is_p2p_enable = _FALSE;
is_p2p_enable = !rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE);
#ifdef CONFIG_ISSUE_DELBA_WHEN_NO_TRAFFIC
/*issue delba when ap does not tx data packet that is Broadcom ap */
rtw_delba_check(padapter, psta, from_timer);
if (chk_ap_is_alive(padapter, psta) == _FALSE)
rx_chk = _FAIL;
if (sta_last_tx_pkts(psta) == sta_tx_pkts(psta))
tx_chk = _FAIL;
if (!from_timer && pmlmeext->active_keep_alive_check && (rx_chk == _FAIL || tx_chk == _FAIL)
u8 backup_ch = 0, backup_bw = 0, backup_offset = 0;
u8 union_ch = 0, union_bw = 0, union_offset = 0;
u8 switch_channel_by_drv = _TRUE;
if (MCC_EN(padapter)) {
/* driver doesn't switch channel under MCC */
if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC))
switch_channel_by_drv = _FALSE;
if (switch_channel_by_drv) {
if (!rtw_mi_get_ch_setting_union(padapter, &union_ch, &union_bw, &union_offset)
|| pmlmeext->cur_channel != union_ch)
goto bypass_active_keep_alive;
/* switch to correct channel of current network before issue keep-alive frames */
if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) {
backup_ch = rtw_get_oper_ch(padapter);
backup_bw = rtw_get_oper_bw(padapter);
backup_offset = rtw_get_oper_choffset(padapter);
set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
if (rx_chk != _SUCCESS)
issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, psta->cmn.mac_addr, 0, 0, 3, 1);
if ((tx_chk != _SUCCESS && pmlmeinfo->link_count++ == link_count_limit) || rx_chk != _SUCCESS) {
if (rtw_mi_check_fwstate(padapter, WIFI_UNDER_SURVEY))
tx_chk = issue_nulldata(padapter, psta->cmn.mac_addr, 1, 3, 1);
tx_chk = issue_nulldata(padapter, psta->cmn.mac_addr, 0, 3, 1);
/* if tx acked and p2p disabled, set rx_chk _SUCCESS to reset retry count */
if (tx_chk == _SUCCESS && !is_p2p_enable)
rx_chk = _SUCCESS;
/* back to the original operation channel */
if (backup_ch > 0 && switch_channel_by_drv)
set_channel_bwmode(padapter, backup_ch, backup_offset, backup_bw);
bypass_active_keep_alive:
;
#endif /* CONFIG_ACTIVE_KEEP_ALIVE_CHECK */
if (rx_chk != _SUCCESS) {
if (pmlmeext->retry == 0) {
RTW_INFO("issue_probereq to trigger probersp, retry=%d\n", pmlmeext->retry);
issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress, 0, 0, 0, (from_timer ? 0 : 1));
if (tx_chk != _SUCCESS && pmlmeinfo->link_count++ == link_count_limit
/* FW tx nulldata under MCC mode, we just check ap is alive */
&& (!rtw_hal_check_mcc_status(padapter, MCC_STATUS_NEED_MCC))
RTW_INFO("%s issue_nulldata(%d)\n", __FUNCTION__, from_timer ? 1 : 0);
if (from_timer || rtw_mi_check_fwstate(padapter, WIFI_UNDER_SURVEY))
tx_chk = issue_nulldata(padapter, NULL, 1, 0, 0);
tx_chk = issue_nulldata(padapter, NULL, 0, 1, 1);
if (rx_chk == _FAIL) {
pmlmeext->retry++;
if (pmlmeext->retry > rx_chk_limit) {
RTW_PRINT(FUNC_ADPT_FMT" disconnect or roaming\n",
FUNC_ADPT_ARG(padapter));
receive_disconnect(padapter, pmlmeinfo->network.MacAddress
, WLAN_REASON_EXPIRATION_CHK, _FALSE);
if (tx_chk == _FAIL)
pmlmeinfo->link_count %= (link_count_limit + 1);
psta->sta_stats.last_tx_pkts = psta->sta_stats.tx_pkts;
} /* end of if ((psta = rtw_get_stainfo(pstapriv, passoc_res->network.MacAddress)) != NULL) */
} else if (is_client_associated_to_ibss(padapter)) {
_list *phead, *plist, dlist;
_rtw_init_listhead(&dlist);
if (is_broadcast_mac_addr(psta->cmn.mac_addr))
if (chk_adhoc_peer_is_alive(psta) || !psta->expire_to)
psta->expire_to--;
if (psta->expire_to <= 0) {
rtw_list_delete(&psta->list);
rtw_list_insert_tail(&psta->list, &dlist);
plist = get_next(&dlist);
while (rtw_end_of_queue_search(&dlist, plist) == _FALSE) {
psta = LIST_CONTAINOR(plist, struct sta_info, list);
RTW_INFO(FUNC_ADPT_FMT" ibss expire "MAC_FMT"\n"
, FUNC_ADPT_ARG(padapter), MAC_ARG(psta->cmn.mac_addr));
report_del_sta_event(padapter, psta->cmn.mac_addr, WLAN_REASON_EXPIRATION_CHK, from_timer ? _TRUE : _FALSE, _FALSE);
void survey_timer_hdl(void *ctx)
_adapter *padapter = (_adapter *)ctx;
struct cmd_obj *cmd;
struct sitesurvey_parm *psurveyPara;
if (mlmeext_scan_state(pmlmeext) > SCAN_DISABLE) {
cmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (cmd == NULL) {
psurveyPara = (struct sitesurvey_parm *)rtw_zmalloc(sizeof(struct sitesurvey_parm));
if (psurveyPara == NULL) {
rtw_mfree((unsigned char *)cmd, sizeof(struct cmd_obj));
init_h2fwcmd_w_parm_no_rsp(cmd, psurveyPara, CMD_SITE_SURVEY);
rtw_enqueue_cmd(pcmdpriv, cmd);
/* 100ms pass, stop rson_scan */
void rson_timer_hdl(void *ctx)
rtw_rson_scan_wk_cmd(padapter, RSON_SCAN_DISABLE);
void rtw_tbtx_xmit_timer_hdl(void *ctx)
if (ATOMIC_READ(&padapter->tbtx_remove_tx_pause) == _TRUE){
}else {
rtw_issue_action_token_rel(padapter);
ATOMIC_SET(&padapter->tbtx_tx_pause, _TRUE);
_set_timer(&pmlmeext->tbtx_xmit_timer, MAX_TXPAUSE_DURATION);
ATOMIC_SET(&padapter->tbtx_remove_tx_pause, _TRUE);
void rtw_tbtx_token_dispatch_timer_hdl(void *ctx)
int i, found = _FALSE;
u8 nr_send, th_idx = 0;
RTW_DBG("%s:asoc_cnt: %d\n",__func__, pstapriv->tbtx_asoc_list_cnt);
// check number of TBTX sta
if (padapter->stapriv.tbtx_asoc_list_cnt < 2)
// dispatch token
nr_send = RTW_DIV_ROUND_UP(pstapriv->tbtx_asoc_list_cnt, NR_TBTX_SLOT);
psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
/* psta is supporting TBTX */
if ((!psta) || (!psta->tbtx_enable))
RTW_DBG("sta tbtx_enable is false\n");
for (i = 0; i < nr_send; i++) {
if (pstapriv->last_token_holder == psta) {
found = _TRUE;
goto outof_loop;
outof_loop:
RTW_DBG("rtw_tbtx_token_dispatch_timer_hdl() th_idx=%d, nr_send=%d, phead=%p, plist=%p, found=%d\n ", th_idx , nr_send, phead, plist, found);
if (!found) {
while(rtw_end_of_queue_search(phead, plist) == _FALSE) {
pstapriv->token_holder[th_idx] = psta;
rtw_issue_action_token_req(padapter, pstapriv->token_holder[th_idx++]);
for (i=th_idx; i<nr_send;) {
if (plist == phead)
ATOMIC_SET(&pstapriv->nr_token_keeper, nr_send);
// set_timer
_set_timer(&pmlmeext->tbtx_token_dispatch_timer, TBTX_TX_DURATION);
#endif /* CONFIG_RTW_TOKEN_BASED_XMIT */
void link_timer_hdl(void *ctx)
/* static unsigned int rx_pkt = 0; */
/* static u64 tx_cnt = 0; */
/* struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); */
/* struct sta_priv *pstapriv = &padapter->stapriv; */
if (rtw_sta_linking_test_force_fail())
RTW_INFO("rtw_sta_linking_test_force_fail\n");
if (pmlmeext->join_abort && pmlmeinfo->state != WIFI_FW_NULL_STATE) {
RTW_INFO(FUNC_ADPT_FMT" join abort\n", FUNC_ADPT_ARG(padapter));
report_join_res(padapter, -4, WLAN_STATUS_UNSPECIFIED_FAILURE);
if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) {
RTW_INFO("link_timer_hdl:no beacon while connecting\n");
report_join_res(padapter, -3, WLAN_STATUS_UNSPECIFIED_FAILURE);
} else if (pmlmeinfo->state & WIFI_FW_AUTH_STATE) {
if (rtw_sec_chk_auth_type(padapter, MLME_AUTHTYPE_SAE))
/* re-auth timer */
if (++pmlmeinfo->reauth_count > REAUTH_LIMIT) {
/* if (pmlmeinfo->auth_algo != dot11AuthAlgrthm_Auto) */
/* { */
pmlmeinfo->state = 0;
if (pmlmeinfo->auth_status) {
report_join_res(padapter, -1, pmlmeinfo->auth_status);
pmlmeinfo->auth_status = 0; /* reset */
/* else */
/* pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; */
RTW_INFO("link_timer_hdl: auth timeout and try again\n");
} else if (pmlmeinfo->state & WIFI_FW_ASSOC_STATE) {
/* re-assoc timer */
if (++pmlmeinfo->reassoc_count > REASSOC_LIMIT) {
rtw_free_stainfo(padapter, psta);
report_join_res(padapter, -2, WLAN_STATUS_UNSPECIFIED_FAILURE);
RTW_INFO("link_timer_hdl: reassoc timeout and try again\n");
RTW_INFO("link_timer_hdl: assoc timeout and try again\n");
void addba_timer_hdl(void *ctx)
struct sta_info *psta = (struct sta_info *)ctx;
struct ht_priv *phtpriv;
phtpriv = &psta->htpriv;
if ((phtpriv->ht_option == _TRUE) && (phtpriv->ampdu_enable == _TRUE)) {
if (phtpriv->candidate_tid_bitmap)
phtpriv->candidate_tid_bitmap = 0x0;
void report_sta_timeout_event(_adapter *padapter, u8 *MacAddr, unsigned short reason)
int mac_id;
evt_hdr->id = EVT_TIMEOUT_STA;
RTW_INFO("report_del_sta_event: delete STA, mac_id=%d\n", mac_id);
void clnt_sa_query_timeout(_adapter *padapter)
struct mlme_ext_priv *mlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *mlmeinfo = &(mlmeext->mlmext_info);
RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
receive_disconnect(padapter, get_my_bssid(&(mlmeinfo->network)), WLAN_REASON_SA_QUERY_TIMEOUT, _FALSE);
void sa_query_timer_hdl(void *ctx)
_adapter *padapter = psta->padapter;
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE &&
check_fwstate(pmlmepriv, WIFI_ASOC_STATE) == _TRUE)
clnt_sa_query_timeout(padapter);
else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE)
report_sta_timeout_event(padapter, psta->cmn.mac_addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
void rtw_auto_ap_rx_msg_dump(_adapter *padapter, union recv_frame *precv_frame, u8 *ehdr_pos)
struct sta_info *psta = precv_frame->u.hdr.psta;
struct ethhdr *ehdr = (struct ethhdr *)ehdr_pos;
RTW_INFO("eth rx: got eth_type=0x%x\n", ntohs(ehdr->h_proto));
u16 rx_pid;
rx_pid = *(u16 *)(ehdr_pos + ETH_HLEN);
RTW_INFO("eth rx(pid=0x%x): sta("MAC_FMT") pid=0x%x\n",
rx_pid, MAC_ARG(psta->cmn.mac_addr), psta->pid);
if (rx_pid == psta->pid) {
u16 len = *(u16 *)(ehdr_pos + ETH_HLEN + 2);
/* u16 ctrl_type = *(u16 *)(ehdr_pos + ETH_HLEN + 4); */
/* RTW_INFO("eth, RC: len=0x%x, ctrl_type=0x%x\n", len, ctrl_type); */
RTW_INFO("eth, RC: len=0x%x\n", len);
for (i = 0; i < len; i++)
RTW_INFO("0x%x\n", *(ehdr_pos + ETH_HLEN + 4 + i));
/* RTW_INFO("0x%x\n", *(ehdr_pos + ETH_HLEN + 6 + i)); */
RTW_INFO("eth, RC-end\n");
void rtw_start_auto_ap(_adapter *adapter)
rtw_set_802_11_infrastructure_mode(adapter, Ndis802_11APMode, 0);
rtw_setopmode_cmd(adapter, Ndis802_11APMode, RTW_CMDF_WAIT_ACK);
static int rtw_auto_ap_start_beacon(_adapter *adapter)
int ret = 0;
u8 *pbuf = NULL;
u8 supportRate[16];
int sz = 0, rateLen;
u8 *ie;
u8 wireless_mode, oper_channel;
u8 ssid[3] = {0}; /* hidden ssid */
u32 ssid_len = sizeof(ssid);
if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE)
return -EINVAL;
len = 128;
pbuf = rtw_zmalloc(len);
if (!pbuf)
return -ENOMEM;
/* generate beacon */
ie = pbuf;
sz += 8;
ie += sz;
/* beacon interval : 2bytes */
*(u16 *)ie = cpu_to_le16((u16)100); /* BCN_INTERVAL=100; */
sz += 2;
ie += 2;
/* capability info */
*(u16 *)ie = 0;
*(u16 *)ie |= cpu_to_le16(cap_ESS);
*(u16 *)ie |= cpu_to_le16(cap_ShortPremble);
/* *(u16*)ie |= cpu_to_le16(cap_Privacy); */
ie = rtw_set_ie(ie, _SSID_IE_, ssid_len, ssid, &sz);
/* supported rates */
wireless_mode = (WIRELESS_11BG_24N & padapter->registrypriv.wireless_mode);
rtw_set_supported_rate(supportRate, wireless_mode);
rateLen = rtw_get_rateset_len(supportRate);
if (rateLen > 8)
ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, 8, supportRate, &sz);
ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, rateLen, supportRate, &sz);
if (rtw_mi_check_status(adapter, MI_LINKED))
oper_channel = rtw_mi_get_union_chan(adapter);
oper_channel = adapter_to_dvobj(adapter)->oper_channel;
ie = rtw_set_ie(ie, _DSSET_IE_, 1, &oper_channel, &sz);
/* ext supported rates */
ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (supportRate + 8), &sz);
RTW_INFO("%s, start auto ap beacon sz=%d\n", __FUNCTION__, sz);
/* lunch ap mode & start to issue beacon */
if (rtw_check_beacon_data(adapter, pbuf, sz) == _SUCCESS) {
ret = -EINVAL;
rtw_mfree(pbuf, len);
#endif/* CONFIG_AUTO_AP_MODE */
u8 tx_control_hdl(_adapter *adapter)
u8 val;
if(ATOMIC_READ(&adapter->tbtx_tx_pause))
val = 0xff;
val = 0x00;
rtw_hal_set_hwreg(adapter, HW_VAR_TXPAUSE, &val);
return H2C_SUCCESS;
u8 stop_ap_hdl(_adapter *adapter)
RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter));
rtw_set_802_11_infrastructure_mode(adapter, Ndis802_11Infrastructure, RTW_CMDF_DIRECTLY);
rtw_setopmode_cmd(adapter, Ndis802_11Infrastructure, RTW_CMDF_DIRECTLY);
u8 setopmode_hdl(_adapter *padapter, u8 *pbuf)
u8 type;
struct setopmode_parm *psetop = (struct setopmode_parm *)pbuf;
if (psetop->mode == Ndis802_11APMode
|| psetop->mode == Ndis802_11_mesh
pmlmeinfo->state = WIFI_FW_AP_STATE;
type = _HW_STATE_AP_;
} else if (psetop->mode == Ndis802_11Infrastructure) {
pmlmeinfo->state &= ~(BIT(0) | BIT(1)); /* clear state */
pmlmeinfo->state |= WIFI_FW_STATION_STATE;/* set to STATION_STATE */
type = _HW_STATE_STATION_;
} else if (psetop->mode == Ndis802_11IBSS)
type = _HW_STATE_ADHOC_;
else if (psetop->mode == Ndis802_11Monitor)
type = _HW_STATE_MONITOR_;
type = _HW_STATE_NOLINK_;
#ifdef CONFIG_AP_PORT_SWAP
rtw_hal_set_hwreg(padapter, HW_VAR_PORT_SWITCH, (u8 *)(&type));
rtw_hal_set_hwreg(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type));
if (psetop->mode == Ndis802_11APMode)
rtw_auto_ap_start_beacon(padapter);
adapter_to_pwrctl(padapter)->fw_psmode_iface_id = 0xff; /* ap mode won't dowload rsvd pages */
else if (psetop->mode == Ndis802_11Infrastructure) {
|| psetop->mode == Ndis802_11Monitor
/* Do this after port switch to */
/* prevent from downloading rsvd page to wrong port */
rtw_btcoex_MediaStatusNotify(padapter, 1); /* connect */
#endif /* CONFIG_BT_COEXIST */
u8 createbss_hdl(_adapter *padapter, u8 *pbuf)
WLAN_BSSID_EX *pdev_network = &padapter->registrypriv.dev_network;
struct createbss_parm *parm = (struct createbss_parm *)pbuf;
u8 ret = H2C_SUCCESS;
/* u8 initialgain; */
if ((parm->req_ch == 0 && pmlmeinfo->state == WIFI_FW_AP_STATE)
|| parm->req_ch != 0
start_bss_network(padapter, parm);
/* below is for ad-hoc master */
if (parm->adhoc) {
rtw_warn_on(pdev_network->InfrastructureMode != Ndis802_11IBSS);
rtw_joinbss_reset(padapter);
pmlmeinfo->ERP_enable = 0;
pmlmeinfo->WMM_enable = 0;
pmlmeinfo->HT_enable = 0;
pmlmeinfo->HT_caps_enable = 0;
pmlmeinfo->HT_info_enable = 0;
pmlmeinfo->agg_enable_bitmap = 0;
pmlmeinfo->candidate_tid_bitmap = 0;
/* cancel link timer */
/* clear CAM */
pdev_network->Length = get_WLAN_BSSID_EX_sz(pdev_network);
_rtw_memcpy(pnetwork, pdev_network, FIELD_OFFSET(WLAN_BSSID_EX, IELength));
pnetwork->IELength = pdev_network->IELength;
if (pnetwork->IELength > MAX_IE_SZ) {
ret = H2C_PARAMETERS_ERROR;
goto ibss_post_hdl;
_rtw_memcpy(pnetwork->IEs, pdev_network->IEs, pnetwork->IELength);
start_create_ibss(padapter);
ibss_post_hdl:
rtw_create_ibss_post_hdl(padapter, ret);
u8 join_cmd_hdl(_adapter *padapter, u8 *pbuf)
struct joinbss_parm *pparm = (struct joinbss_parm *)pbuf;
#endif /* CONFIG_ANTENNA_DIVERSITY */
struct wlan_network *rnetwork = pmlmepriv->roam_network;
struct beacon_keys bcn_keys;
u32 roam_ielen;
/* u32 acparm; */
/* check already connecting to AP or not */
if (pmlmeinfo->state & WIFI_FW_STATION_STATE)
/* set MSR to nolink->infra. mode */
/* Set_MSR(padapter, _HW_STATE_NOLINK_); */
rtw_antenna_select_cmd(padapter, pparm->network.PhyInfo.Optimum_antenna, _FALSE);
rtw_wapi_clear_all_cam_entry(padapter);
pmlmeinfo->bwmode_updated = _FALSE;
/* pmlmeinfo->assoc_AP_vendor = HT_IOT_PEER_MAX; */
pmlmeinfo->VHT_enable = 0;
_rtw_memcpy(pnetwork, pbuf, FIELD_OFFSET(WLAN_BSSID_EX, IELength));
pnetwork->IELength = ((WLAN_BSSID_EX *)pbuf)->IELength;
if (pnetwork->IELength > MAX_IE_SZ) /* Check pbuf->IELength */
return H2C_PARAMETERS_ERROR;
if (pnetwork->IELength < 2) {
report_join_res(padapter, (-4), WLAN_STATUS_UNSPECIFIED_FAILURE);
_rtw_memcpy(pnetwork->IEs, ((WLAN_BSSID_EX *)pbuf)->IEs, pnetwork->IELength);
/* Check AP vendor to move rtw_joinbss_cmd() */
/* pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->IEs, pnetwork->IELength); */
/* sizeof(NDIS_802_11_FIXED_IEs) */
for (i = _FIXED_IE_LENGTH_ ; i < pnetwork->IELength - 2 ;) {
pIE = (PNDIS_802_11_VARIABLE_IEs)(pnetwork->IEs + i);
case _VENDOR_SPECIFIC_IE_: /* Get WMM IE. */
if (_rtw_memcmp(pIE->data, WMM_OUI, 4))
case _HT_CAPABILITY_IE_: /* Get HT Cap IE. */
pmlmeinfo->HT_caps_enable = 1;
case _HT_EXTRA_INFO_IE_: /* Get HT Info IE. */
pmlmeinfo->HT_info_enable = 1;
case EID_VHTCapability: /* Get VHT Cap IE. */
pmlmeinfo->VHT_enable = 1;
case EID_VHTOperation: /* Get VHT Operation IE. */
rtw_bss_get_chbw(pnetwork
, &pmlmeext->cur_channel, &pmlmeext->cur_bwmode, &pmlmeext->cur_ch_offset, 1, 1);
rtw_adjust_chbw(padapter, pmlmeext->cur_channel, &pmlmeext->cur_bwmode, &pmlmeext->cur_ch_offset);
/* for WiFi test, follow WMM test plan spec */
acparm = 0x002F431C; /* VO */
rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm));
acparm = 0x005E541C; /* VI */
rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm));
acparm = 0x0000A525; /* BE */
rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm));
acparm = 0x0000A549; /* BK */
rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm));
/* for WiFi test, mixed mode with intel STA under bg mode throughput issue */
if (padapter->mlmepriv.htpriv.ht_option == _FALSE) {
acparm = 0x00004320;
acparm = 0x002F3217; /* VO */
acparm = 0x005E4317; /* VI */
acparm = 0x00105320; /* BE */
acparm = 0x0000A444; /* BK */
/* check channel, bandwidth, offset and switch */
if (rtw_chk_start_clnt_join(padapter, &u_ch, &u_bw, &u_offset) == _FAIL) {
/* disable dynamic functions, such as high power, DIG */
/*rtw_phydm_func_disable_all(padapter);*/
/* config the initial gain under linking, need to write the BB registers */
/* initialgain = 0x1E; */
/*rtw_hal_set_odm_var(padapter, HAL_ODM_INITIAL_GAIN, &initialgain, _FALSE);*/
rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pmlmeinfo->network.MacAddress);
if (MLME_IS_STA(padapter))
rtw_hal_rcr_set_chk_bssid(padapter, MLME_STA_CONNECTING);
set_channel_bwmode(padapter, u_ch, u_offset, u_bw);
start_clnt_join(padapter);
rtw_msleep_os(2);
if (rnetwork && (pmlmeinfo->state & (WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE))) {
if (!rnetwork) {
RTW_INFO("%s: pmlmepriv->roam_network is NULL. roaming fail!!\n", __func__);
roam_ielen = rnetwork->network.IELength;
update_network(&(pmlmepriv->cur_network.network), &(rnetwork->network), padapter, _TRUE);
if (rtw_get_bcn_keys_from_bss(&rnetwork->network, &bcn_keys) == _TRUE) {
_rtw_memcpy(&pmlmepriv->cur_beacon_keys, &bcn_keys, sizeof(bcn_keys));
if (is_hidden_ssid(bcn_keys.ssid, bcn_keys.ssid_len)) {
_rtw_memset(&pmlmepriv->cur_beacon_keys, 0, sizeof(bcn_keys));
pmlmeinfo->assoc_AP_vendor = check_assoc_AP(rnetwork->network.IEs, rnetwork->network.IELength);
pmlmeext->TSFValue = rnetwork->network.tsf + rtw_get_passing_time_ms(rnetwork->last_scanned)*1000;
u8 disconnect_hdl(_adapter *padapter, unsigned char *pbuf)
struct disconnect_parm *param = (struct disconnect_parm *)pbuf;
if (is_client_associated_to_ap(padapter)
&& !IS_RADAR_DETECTED(rfctl) && !rfctl->csa_ch
#ifdef CONFIG_PLATFORM_ROCKCHIPS
issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, param->deauth_timeout_ms / 100, 100);
#endif /* CONFIG_PLATFORM_ROCKCHIPS */
#ifndef CONFIG_SUPPORT_MULTI_BCN
if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) {
/* Stop BCN */
val8 = 0;
rtw_hal_set_hwreg(padapter, HW_VAR_BCN_FUNC, (u8 *)(&val8));
rtw_sta_mstatus_report(padapter);
rtw_free_uc_swdec_pending_queue(padapter);
static const char *const _scan_state_str[] = {
"SCAN_DISABLE",
"SCAN_START",
"SCAN_PS_ANNC_WAIT",
"SCAN_ENTER",
"SCAN_PROCESS",
"SCAN_BACKING_OP",
"SCAN_BACK_OP",
"SCAN_LEAVING_OP",
"SCAN_LEAVE_OP",
"SCAN_SW_ANTDIV_BL",
"SCAN_TO_P2P_LISTEN",
"SCAN_P2P_LISTEN",
"SCAN_COMPLETE",
"SCAN_STATE_MAX",
const char *scan_state_str(u8 state)
state = (state >= SCAN_STATE_MAX) ? SCAN_STATE_MAX : state;
return _scan_state_str[state];
static bool scan_abort_hdl(_adapter *adapter)
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
struct ss_res *ss = &pmlmeext->sitesurvey_res;
struct wifidirect_info *pwdinfo = &adapter->wdinfo;
if (pmlmeext->scan_abort == _TRUE) {
if (!rtw_p2p_chk_state(&adapter->wdinfo, P2P_STATE_NONE)) {
rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX);
ss->channel_idx = 3;
RTW_INFO("%s idx:%d, cnt:%u\n", __FUNCTION__
, ss->channel_idx
, pwdinfo->find_phase_state_exchange_cnt
ss->channel_idx = ss->ch_num;
RTW_INFO("%s idx:%d\n", __FUNCTION__
u8 rtw_scan_sparse(_adapter *adapter, struct rtw_ieee80211_channel *ch, u8 ch_num)
/* interval larger than this is treated as backgroud scan */
#ifndef RTW_SCAN_SPARSE_BG_INTERVAL_MS
#define RTW_SCAN_SPARSE_BG_INTERVAL_MS 12000
#ifndef RTW_SCAN_SPARSE_CH_NUM_MIRACAST
#define RTW_SCAN_SPARSE_CH_NUM_MIRACAST 1
#ifndef RTW_SCAN_SPARSE_CH_NUM_BG
#define RTW_SCAN_SPARSE_CH_NUM_BG 4
#define SCAN_SPARSE_CH_NUM_INVALID 255
static u8 token = 255;
u32 interval;
bool busy_traffic = _FALSE;
bool miracast_enabled = _FALSE;
bool bg_scan = _FALSE;
u8 max_allow_ch = SCAN_SPARSE_CH_NUM_INVALID;
u8 scan_division_num;
u8 ret_num = ch_num;
struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
if (mlmeext->last_scan_time == 0)
mlmeext->last_scan_time = rtw_get_current_time();
interval = rtw_get_passing_time_ms(mlmeext->last_scan_time);
if (rtw_mi_busy_traffic_check(adapter))
busy_traffic = _TRUE;
if (rtw_mi_check_miracast_enabled(adapter))
miracast_enabled = _TRUE;
if (interval > RTW_SCAN_SPARSE_BG_INTERVAL_MS)
bg_scan = _TRUE;
/* max_allow_ch by conditions*/
#if RTW_SCAN_SPARSE_MIRACAST
if (miracast_enabled == _TRUE && busy_traffic == _TRUE)
max_allow_ch = rtw_min(max_allow_ch, RTW_SCAN_SPARSE_CH_NUM_MIRACAST);
#if RTW_SCAN_SPARSE_BG
if (bg_scan == _TRUE)
max_allow_ch = rtw_min(max_allow_ch, RTW_SCAN_SPARSE_CH_NUM_BG);
if (max_allow_ch != SCAN_SPARSE_CH_NUM_INVALID) {
int k = 0;
scan_division_num = (ch_num / max_allow_ch) + ((ch_num % max_allow_ch) ? 1 : 0);
token = (token + 1) % scan_division_num;
RTW_INFO("scan_division_num:%u, token:%u\n", scan_division_num, token);
for (i = 0; i < ch_num; i++) {
if (ch[i].hw_value && (i % scan_division_num) == token
if (i != k)
_rtw_memcpy(&ch[k], &ch[i], sizeof(struct rtw_ieee80211_channel));
_rtw_memset(&ch[k], 0, sizeof(struct rtw_ieee80211_channel));
ret_num = k;
return ret_num;
u8 rtw_scan_backop_decision(_adapter *adapter)
struct mi_state mstate;
u8 backop_flags = 0;
rtw_mi_status(adapter, &mstate);
if ((MSTATE_STA_LD_NUM(&mstate) && mlmeext_chk_scan_backop_flags_sta(mlmeext, SS_BACKOP_EN))
|| (MSTATE_STA_NUM(&mstate) && mlmeext_chk_scan_backop_flags_sta(mlmeext, SS_BACKOP_EN_NL)))
backop_flags |= mlmeext_scan_backop_flags_sta(mlmeext);
if ((MSTATE_AP_LD_NUM(&mstate) && mlmeext_chk_scan_backop_flags_ap(mlmeext, SS_BACKOP_EN))
|| (MSTATE_AP_NUM(&mstate) && mlmeext_chk_scan_backop_flags_ap(mlmeext, SS_BACKOP_EN_NL)))
backop_flags |= mlmeext_scan_backop_flags_ap(mlmeext);
if ((MSTATE_MESH_LD_NUM(&mstate) && mlmeext_chk_scan_backop_flags_mesh(mlmeext, SS_BACKOP_EN))
|| (MSTATE_MESH_NUM(&mstate) && mlmeext_chk_scan_backop_flags_mesh(mlmeext, SS_BACKOP_EN_NL)))
backop_flags |= mlmeext_scan_backop_flags_mesh(mlmeext);
return backop_flags;
#define SCANNING_TIMEOUT_EX 2000
u32 rtw_scan_timeout_decision(_adapter *padapter)
u32 back_op_times= 0;
u8 max_chan_num;
u16 scan_ms;
if (is_supported_5g(padapter->registrypriv.wireless_mode)
&& IsSupported24G(padapter->registrypriv.wireless_mode))
max_chan_num = MAX_CHANNEL_NUM;/* dual band */
max_chan_num = MAX_CHANNEL_NUM_2G;/*single band*/
if (rtw_scan_backop_decision(padapter))
back_op_times = (max_chan_num / ss->scan_cnt_max) * ss->backop_ms;
if (ss->duration)
scan_ms = ss->duration;
#if defined(CONFIG_RTW_ACS) && defined(CONFIG_RTW_ACS_DBG)
if (IS_ACS_ENABLE(padapter) && rtw_is_acs_st_valid(padapter))
scan_ms = rtw_acs_get_adv_st(padapter);
#endif /*CONFIG_RTW_ACS*/
scan_ms = ss->scan_ch_ms;
ss->scan_timeout_ms = (scan_ms * max_chan_num) + back_op_times + SCANNING_TIMEOUT_EX;
#ifdef DBG_SITESURVEY
RTW_INFO("%s , scan_timeout_ms = %d (ms)\n", __func__, ss->scan_timeout_ms);
#endif /*DBG_SITESURVEY*/
return ss->scan_timeout_ms;
static int rtw_scan_ch_decision(_adapter *padapter, struct rtw_ieee80211_channel *out,
u32 out_num, struct rtw_ieee80211_channel *in, u32 in_num, bool no_sparse, int reason)
int set_idx;
u8 chan;
struct registry_priv *regsty = dvobj_to_regsty(adapter_to_dvobj(padapter));
#ifdef CONFIG_RTW_ROAM_QUICKSCAN
/* clear first */
_rtw_memset(out, 0, sizeof(struct rtw_ieee80211_channel) * out_num);
if ((reason == RTW_AUTO_SCAN_REASON_ROAM) && (pmlmeext->quickscan_next)) {
pmlmeext->quickscan_next = _FALSE;
_rtw_memcpy(out, pmlmeext->roam_ch, sizeof(struct rtw_ieee80211_channel)*RTW_CHANNEL_SCAN_AMOUNT);
return pmlmeext->roam_ch_num;
/* acquire channels from in */
j = 0;
for (i = 0; i < in_num; i++) {
RTW_INFO(FUNC_ADPT_FMT" "CHAN_FMT"\n", FUNC_ADPT_ARG(padapter), CHAN_ARG(&in[i]));
if (!in[i].hw_value || (in[i].flags & RTW_IEEE80211_CHAN_DISABLED))
if (rtw_mlme_band_check(padapter, in[i].hw_value) == _FALSE)
set_idx = rtw_chset_search_ch(rfctl->channel_set, in[i].hw_value);
if (set_idx >= 0) {
if (j >= out_num) {
RTW_PRINT(FUNC_ADPT_FMT" out_num:%u not enough\n",
FUNC_ADPT_ARG(padapter), out_num);
_rtw_memcpy(&out[j], &in[i], sizeof(struct rtw_ieee80211_channel));
if (rfctl->channel_set[set_idx].flags & (RTW_CHF_NO_IR | RTW_CHF_DFS))
out[j].flags |= RTW_IEEE80211_CHAN_PASSIVE_SCAN;
j++;
if (j >= out_num)
/* if out is empty, use channel_set as default */
if (j == 0) {
chan = rfctl->channel_set[i].ChannelNum;
if (rtw_mlme_band_check(padapter, chan) == _TRUE) {
if (rtw_mlme_ignore_chan(padapter, chan) == _TRUE)
RTW_INFO(FUNC_ADPT_FMT" ch:%u\n", FUNC_ADPT_ARG(padapter), chan);
out[j].hw_value = chan;
if (rfctl->channel_set[i].flags & (RTW_CHF_NO_IR | RTW_CHF_DFS))
if (!no_sparse
&& !regsty->wifi_spec
&& j > 6 /* assume ch_num > 6 is normal scan */
/* scan_sparse */
j = rtw_scan_sparse(padapter, out, j);
return j;
static void sitesurvey_res_reset(_adapter *adapter, struct sitesurvey_parm *parm)
RT_CHANNEL_INFO *chset = adapter_to_chset(adapter);
int i, reason = 0;
ss->bss_cnt = 0;
ss->activate_ch_cnt = 0;
ss->channel_idx = 0;
ss->force_ssid_scan = 0;
ss->igi_scan = 0;
ss->igi_before_scan = 0;
ss->scan_cnt = 0;
ss->is_sw_antdiv_bl_scan = 0;
ss->ssid_num = 0;
for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) {
if (parm->ssid[i].SsidLength) {
_rtw_memcpy(ss->ssid[i].Ssid, parm->ssid[i].Ssid, IW_ESSID_MAX_SIZE);
ss->ssid[i].SsidLength = parm->ssid[i].SsidLength;
ss->ssid_num++;
ss->ssid[i].SsidLength = 0;
reason = parm->reason;
ss->ch_num = rtw_scan_ch_decision(adapter
, ss->ch, RTW_CHANNEL_SCAN_AMOUNT
, parm->ch, parm->ch_num
, parm->acs
chset[i].hidden_bss_cnt = 0;
ss->bw = parm->bw;
ss->igi = parm->igi;
ss->token = parm->token;
ss->duration = parm->duration;
ss->scan_mode = parm->scan_mode;
ss->acs = parm->acs;
static u8 sitesurvey_pick_ch_behavior(_adapter *padapter, u8 *ch, RT_SCAN_TYPE *type)
u8 next_state;
u8 scan_ch = 0;
RT_SCAN_TYPE scan_type = SCAN_PASSIVE;
int ch_set_idx;
/* handle scan abort request */
scan_abort_hdl(padapter);
if (pwdinfo->rx_invitereq_info.scan_op_ch_only || pwdinfo->p2p_info.scan_op_ch_only) {
if (pwdinfo->rx_invitereq_info.scan_op_ch_only)
scan_ch = pwdinfo->rx_invitereq_info.operation_ch[ss->channel_idx];
scan_ch = pwdinfo->p2p_info.operation_ch[ss->channel_idx];
scan_type = SCAN_ACTIVE;
} else if (rtw_p2p_findphase_ex_is_social(pwdinfo)) {
* Commented by Albert 2011/06/03
* The driver is in the find phase, it should go through the social channel.
scan_ch = pwdinfo->social_chan[ss->channel_idx];
ch_set_idx = rtw_chset_search_ch(rfctl->channel_set, scan_ch);
if (ch_set_idx >= 0)
scan_type = rfctl->channel_set[ch_set_idx].flags & RTW_CHF_NO_IR ? SCAN_PASSIVE : SCAN_ACTIVE;
struct rtw_ieee80211_channel *ch;
backop_flags = rtw_scan_backop_decision(padapter);
if (!(backop_flags && ss->scan_cnt >= ss->scan_cnt_max))
#ifdef CONFIG_RTW_WIFI_HAL
if (adapter_to_dvobj(padapter)->nodfs) {
while (ss->channel_idx < ss->ch_num && rtw_chset_is_dfs_ch(rfctl->channel_set, ss->ch[ss->channel_idx].hw_value))
ss->channel_idx++;
if (ss->channel_idx != 0 && ss->force_ssid_scan == 0
&& pmlmeext->sitesurvey_res.ssid_num
&& (ss->ch[ss->channel_idx - 1].flags & RTW_IEEE80211_CHAN_PASSIVE_SCAN)
ch_set_idx = rtw_chset_search_ch(rfctl->channel_set, ss->ch[ss->channel_idx - 1].hw_value);
if (ch_set_idx != -1 && rfctl->channel_set[ch_set_idx].hidden_bss_cnt
&& (!IS_DFS_SLAVE_WITH_RD(rfctl)
|| rtw_rfctl_dfs_domain_unknown(rfctl)
|| !CH_IS_NON_OCP(&rfctl->channel_set[ch_set_idx]))
ss->channel_idx--;
ss->force_ssid_scan = 1;
if (ss->channel_idx < ss->ch_num) {
ch = &ss->ch[ss->channel_idx];
scan_ch = ch->hw_value;
if (IS_ACS_ENABLE(padapter) && rtw_is_acs_passiv_scan(padapter))
scan_type = SCAN_PASSIVE;
scan_type = (ch->flags & RTW_IEEE80211_CHAN_PASSIVE_SCAN) ? SCAN_PASSIVE : SCAN_ACTIVE;
if (scan_ch != 0) {
next_state = SCAN_PROCESS;
if (backop_flags) {
if (ss->scan_cnt < ss->scan_cnt_max)
ss->scan_cnt++;
mlmeext_assign_scan_backop_flags(pmlmeext, backop_flags);
next_state = SCAN_BACKING_OP;
} else if (rtw_p2p_findphase_ex_is_needed(pwdinfo)) {
/* go p2p listen */
next_state = SCAN_TO_P2P_LISTEN;
} else if (rtw_hal_antdiv_before_linked(padapter)) {
/* go sw antdiv before link */
next_state = SCAN_SW_ANTDIV_BL;
next_state = SCAN_COMPLETE;
#if defined(DBG_SCAN_SW_ANTDIV_BL)
/* for SCAN_SW_ANTDIV_BL state testing */
struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
bool is_linked = _FALSE;
if (rtw_linked_check(dvobj->padapters[i]))
is_linked = _TRUE;
if (!is_linked) {
static bool fake_sw_antdiv_bl_state = 0;
if (fake_sw_antdiv_bl_state == 0) {
fake_sw_antdiv_bl_state = 1;
fake_sw_antdiv_bl_state = 0;
#endif /* defined(DBG_SCAN_SW_ANTDIV_BL) */
if (next_state != SCAN_PROCESS)
if (pmlmeext->fixed_chan != 0xff && next_state == SCAN_PROCESS)
scan_ch = pmlmeext->fixed_chan;
*ch = scan_ch;
if (type)
*type = scan_type;
return next_state;
void site_survey(_adapter *padapter, u8 survey_channel, RT_SCAN_TYPE ScanType)
u8 ssid_scan = 0;
if (survey_channel != 0) {
set_channel_bwmode(padapter, survey_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
if (ScanType == SCAN_PASSIVE && ss->force_ssid_scan)
ssid_scan = 1;
else if (ScanType == SCAN_ACTIVE) {
if (rtw_cfg80211_is_p2p_scan(padapter))
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN)
|| rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH))
issue_probereq_p2p(padapter, NULL);
if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) {
/* IOT issue, When wifi_spec is not set, send one probe req without WPS IE. */
if (padapter->registrypriv.wifi_spec)
issue_probereq(padapter, NULL, NULL);
issue_probereq_ex(padapter, NULL, NULL, 0, 0, 0, 0);
if (ssid_scan) {
if (pmlmeext->sitesurvey_res.ssid[i].SsidLength) {
issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL);
issue_probereq_ex(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL, 0, 0, 0, 0);
/* channel number is 0 or this channel is not valid. */
void survey_done_set_ch_bw(_adapter *padapter)
u8 cur_channel = 0;
u8 cur_bwmode;
u8 cur_ch_offset;
if (!rtw_hal_mcc_change_scan_flag(padapter, &cur_channel, &cur_bwmode, &cur_ch_offset)) {
RTW_INFO(FUNC_ADPT_FMT" back to AP channel - ch:%u, bw:%u, offset:%u\n",
FUNC_ADPT_ARG(padapter), cur_channel, cur_bwmode, cur_ch_offset);
if (rtw_mi_get_ch_setting_union(padapter, &cur_channel, &cur_bwmode, &cur_ch_offset) != 0) {
RTW_INFO(FUNC_ADPT_FMT" back to linked/linking union - ch:%u, bw:%u, offset:%u\n",
if (iface->wdinfo.driver_interface == DRIVER_CFG80211 && !adapter_wdev_data(iface)->p2p_enabled)
if (rtw_p2p_chk_state(&iface->wdinfo, P2P_STATE_LISTEN)) {
cur_channel = iface->wdinfo.listen_channel;
cur_bwmode = CHANNEL_WIDTH_20;
cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
RTW_INFO(FUNC_ADPT_FMT" back to "ADPT_FMT"'s listen ch - ch:%u, bw:%u, offset:%u\n",
FUNC_ADPT_ARG(padapter), ADPT_ARG(iface), cur_channel, cur_bwmode, cur_ch_offset);
if (cur_channel == 0) {
cur_channel = pmlmeext->cur_channel;
cur_bwmode = pmlmeext->cur_bwmode;
cur_ch_offset = pmlmeext->cur_ch_offset;
RTW_INFO(FUNC_ADPT_FMT" back to ch:%u, bw:%u, offset:%u\n",
set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode);
* rtw_ps_annc - check and doing ps announcement for all the adapters
* @adapter: the requesting adapter
* @ps: power saving or not
* Returns: 0: no ps announcement is doing. 1: ps announcement is doing
u8 rtw_ps_annc(_adapter *adapter, bool ps)
u8 ps_anc = 0;
if (MLME_IS_STA(iface)) {
if (is_client_associated_to_ap(iface) == _TRUE) {
/* TODO: TDLS peers */
/* for two station case */
if (MCC_EN(adapter) && rtw_hal_check_mcc_status(adapter, MCC_STATUS_NEED_MCC)) {
u8 ch = iface->mlmeextpriv.cur_channel;
u8 offset = iface->mlmeextpriv.cur_ch_offset;
u8 bw = iface->mlmeextpriv.cur_bwmode;
set_channel_bwmode(iface, ch, offset, bw);
issue_nulldata(iface, NULL, ps, 3, 500);
ps_anc = 1;
} else if (MLME_IS_MESH(iface)) {
if (rtw_mesh_ps_annc(iface, ps))
return ps_anc;
void rtw_leave_opch(_adapter *adapter)
if (MCC_EN(adapter) && rtw_hal_check_mcc_status(adapter, MCC_STATUS_DOING_MCC))
_enter_critical_mutex(&rfctl->offch_mutex, NULL);
if (rfctl->offch_state == OFFCHS_NONE) {
/* prepare to leave operating channel */
rfctl->offch_state = OFFCHS_LEAVING_OP;
/* clear HW TX queue */
rtw_hal_set_hwreg(adapter, HW_VAR_CHECK_TXBUF, 0);
rtw_hal_macid_sleep_all_used(adapter);
rtw_ps_annc(adapter, 1);
rfctl->offch_state = OFFCHS_LEAVE_OP;
_exit_critical_mutex(&rfctl->offch_mutex, NULL);
void rtw_back_opch(_adapter *adapter)
if (rfctl->offch_state != OFFCHS_NONE) {
rfctl->offch_state = OFFCHS_BACKING_OP;
rtw_hal_macid_wakeup_all_used(adapter);
rtw_ps_annc(adapter, 0);
rfctl->offch_state = OFFCHS_NONE;
rtw_mi_os_xmit_schedule(adapter);
void sitesurvey_set_igi(_adapter *adapter)
struct ss_res *ss = &mlmeext->sitesurvey_res;
u8 igi;
switch (mlmeext_scan_state(mlmeext)) {
case SCAN_ENTER:
if (pwdinfo->driver_interface == DRIVER_CFG80211 && rtw_cfg80211_is_p2p_scan(adapter))
igi = 0x30;
if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
igi = 0x28;
if (ss->igi)
igi = ss->igi;
if (IS_ACS_ENABLE(adapter) && rtw_is_acs_igi_valid(adapter))
igi = rtw_acs_get_adv_igi(adapter);
igi = 0x1e;
/* record IGI status */
ss->igi_scan = igi;
rtw_hal_get_odm_var(adapter, HAL_ODM_INITIAL_GAIN, &ss->igi_before_scan, NULL);
/* disable DIG and set IGI for scan */
rtw_hal_set_odm_var(adapter, HAL_ODM_INITIAL_GAIN, &igi, _FALSE);
case SCAN_COMPLETE:
case SCAN_TO_P2P_LISTEN:
/* enable DIG and restore IGI */
igi = 0xff;
case SCAN_BACKING_OP:
/* write IGI for op channel when DIG is not enabled */
odm_write_dig(adapter_to_phydm(adapter), ss->igi_before_scan);
case SCAN_LEAVE_OP:
/* write IGI for scan when DIG is not enabled */
odm_write_dig(adapter_to_phydm(adapter), ss->igi_scan);
#endif /* CONFIG_SCAN_BACKOP */
void sitesurvey_set_msr(_adapter *adapter, bool enter)
u8 network_type;
if (enter) {
#ifdef CONFIG_MI_WITH_MBSSID_CAM
rtw_hal_get_hwreg(adapter, HW_VAR_MEDIA_STATUS, (u8 *)(&pmlmeinfo->hw_media_state));
/* set MSR to no link state */
network_type = _HW_STATE_NOLINK_;
network_type = pmlmeinfo->hw_media_state;
network_type = pmlmeinfo->state & 0x3;
Set_MSR(adapter, network_type);
void sitesurvey_set_offch_state(_adapter *adapter, u8 scan_state)
switch (scan_state) {
case SCAN_DISABLE:
case SCAN_BACK_OP:
case SCAN_START:
case SCAN_LEAVING_OP:
extern inline int is_same_ess(WLAN_BSSID_EX *a, WLAN_BSSID_EX *b);
extern int rtw_is_desired_network(_adapter *adapter, struct wlan_network *pnetwork);
void generate_quickss(_adapter *padapter)
struct rtw_ieee80211_channel *roam_ch = pmlmeext->roam_ch;
int chan;
u8 *target_ssid=NULL, *ssid=NULL, ds_cfg, j, ch_num;
u32 target_ssid_len=0, ssid_len=0;
u8 mark[166];
target_ssid = pmlmepriv->cur_network.network.Ssid.Ssid;
target_ssid_len = pmlmepriv->cur_network.network.Ssid.SsidLength;
_rtw_memset(mark, 0, sizeof(u8)*166);
phead = get_list_head(&(pmlmepriv->scanned_queue));
if (!phead) {
if (!plist) {
if (!pnetwork)
ds_cfg = pnetwork->network.Configuration.DSConfig;
if (is_same_ess(&pnetwork->network, &pmlmepriv->cur_network.network) &&
rtw_is_desired_network(padapter, pnetwork))
mark[ds_cfg] = 1;
/* ex: assume roaming channel=1/6/40/165, then mark[1]/[6]/[40]/[165] are 1. */
ch_num = 0;
for (j = 0; j < rfctl->max_chan_nums; j++) {
chan = rfctl->channel_set[j].ChannelNum;
if (mark[chan]) {
roam_ch[ch_num].hw_value = chan;
roam_ch[ch_num++].flags = rfctl->channel_set[j].flags;
pmlmeext->roam_ch_num = ch_num;
u8 sitesurvey_cmd_hdl(_adapter *padapter, u8 *pbuf)
struct sitesurvey_parm *pparm = (struct sitesurvey_parm *)pbuf;
#ifdef DBG_CHECK_FW_PS_STATE
struct dvobj_priv *dvobj = padapter->dvobj;
struct debug_priv *pdbgpriv = &dvobj->drv_dbg;
if (rtw_fw_ps_state(padapter) == _FAIL) {
RTW_INFO("scan without leave 32k\n");
pdbgpriv->dbg_scan_pwr_state_cnt++;
#endif /* DBG_CHECK_FW_PS_STATE */
/* increase channel idx */
if (mlmeext_chk_scan_state(pmlmeext, SCAN_PROCESS))
/* update scan state to next state (assigned by previous cmd hdl) */
if (mlmeext_scan_state(pmlmeext) != mlmeext_scan_next_state(pmlmeext))
mlmeext_set_scan_state(pmlmeext, mlmeext_scan_next_state(pmlmeext));
operation_by_state:
switch (mlmeext_scan_state(pmlmeext)) {
* SW parameter initialization
sitesurvey_res_reset(padapter, pparm);
mlmeext_set_scan_state(pmlmeext, SCAN_START);
goto operation_by_state;
u16 seq_num;
#ifdef CONFIG_RTW_CFGVENDOR_RANDOM_MAC_OUI
rtw_hal_pno_random_gen_mac_addr(padapter);
rtw_hal_set_hw_mac_addr(padapter, pwdev_priv->pno_mac_addr);
get_random_bytes(&seq_num, 2);
pwdev_priv->pno_scan_seq_num = seq_num & 0xFFF;
RTW_INFO("%s pno_scan_seq_num %d\n", __func__,
* prepare to leave operating channel
rtw_hal_set_mcc_setting_scan_start(padapter);
/* apply rx ampdu setting */
if (ss->rx_ampdu_accept != RX_AMPDU_ACCEPT_INVALID
|| ss->rx_ampdu_size != RX_AMPDU_SIZE_INVALID)
rtw_rx_ampdu_apply(padapter);
/* clear HW TX queue before scan */
rtw_hal_set_hwreg(padapter, HW_VAR_CHECK_TXBUF, 0);
rtw_hal_macid_sleep_all_used(padapter);
/* power save state announcement */
if (rtw_ps_annc(padapter, 1)) {
mlmeext_set_scan_state(pmlmeext, SCAN_PS_ANNC_WAIT);
mlmeext_set_scan_next_state(pmlmeext, SCAN_ENTER);
set_survey_timer(pmlmeext, 50); /* delay 50ms to protect nulldata(1) */
mlmeext_set_scan_state(pmlmeext, SCAN_ENTER);
* HW register and DM setting for enter scan
rtw_phydm_ability_backup(padapter);
sitesurvey_set_igi(padapter);
/* config dynamic functions for off channel */
rtw_phydm_func_for_offchannel(padapter);
sitesurvey_set_msr(padapter, _TRUE);
val8 = 1; /* under site survey */
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
mlmeext_set_scan_state(pmlmeext, SCAN_PROCESS);
case SCAN_PROCESS: {
u8 scan_ch;
RT_SCAN_TYPE scan_type;
u32 scan_ms;
if (IS_ACS_ENABLE(padapter))
rtw_acs_get_rst(padapter);
next_state = sitesurvey_pick_ch_behavior(padapter, &scan_ch, &scan_type);
if (next_state != SCAN_PROCESS) {
mlmeext_set_scan_state(pmlmeext, next_state);
/* still SCAN_PROCESS state */
RTW_INFO(FUNC_ADPT_FMT" %s ch:%u (cnt:%u,idx:%d) at %dms, %c%c%c%c\n"
, mlmeext_scan_state_str(pmlmeext)
, scan_ch
, pwdinfo->find_phase_state_exchange_cnt, ss->channel_idx
, rtw_get_passing_time_ms(padapter->mlmepriv.scan_start_time)
, scan_type ? 'A' : 'P', ss->scan_mode ? 'A' : 'P'
, ss->ssid[0].SsidLength ? 'S' : ' '
, ss->force_ssid_scan ? 'F' : ' '
RTW_INFO(FUNC_ADPT_FMT" %s ch:%u (idx:%d) at %dms, %c%c%c%c\n"
if (pmlmeext->fixed_chan != 0xff)
RTW_INFO(FUNC_ADPT_FMT" fixed_chan:%u\n", pmlmeext->fixed_chan);
site_survey(padapter, scan_ch, scan_type);
#if defined(CONFIG_ATMEL_RC_PATCH)
if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE) == _TRUE)
scan_ms = 20;
scan_ms = 40;
if (ss->is_sw_antdiv_bl_scan)
scan_ms = scan_ms / 2;
if (IS_ACS_ENABLE(padapter)) {
if (pparm->token)
rtw_acs_trigger(padapter, scan_ms, scan_ch, NHM_PID_IEEE_11K_HIGH);
rtw_acs_trigger(padapter, scan_ms, scan_ch, NHM_PID_ACS);
#ifdef CONFIG_BACKGROUND_NOISE_MONITOR
if (IS_NM_ENABLE(padapter))
rtw_noise_measure(padapter, scan_ch, _FALSE, 0, scan_ms / 2);
set_survey_timer(pmlmeext, scan_ms);
case SCAN_BACKING_OP: {
u8 back_ch, back_bw, back_ch_offset;
u8 need_ch_setting_union = _TRUE;
need_ch_setting_union = rtw_hal_mcc_change_scan_flag(padapter,
&back_ch, &back_bw, &back_ch_offset);
if (need_ch_setting_union) {
if (rtw_mi_get_ch_setting_union(padapter, &back_ch, &back_bw, &back_ch_offset) == 0) {
back_ch = pmlmeext->cur_channel;
back_bw = pmlmeext->cur_bwmode;
back_ch_offset = pmlmeext->cur_ch_offset;
RTW_INFO(FUNC_ADPT_FMT" %s ch:%u, bw:%u, offset:%u at %dms\n"
, back_ch, back_bw, back_ch_offset
set_channel_bwmode(padapter, back_ch, back_ch_offset, back_bw);
sitesurvey_set_msr(padapter, _FALSE);
val8 = 0; /* survey done */
if (mlmeext_chk_scan_backop_flags(pmlmeext, SS_BACKOP_PS_ANNC)) {
rtw_hal_macid_wakeup_all_used(padapter);
rtw_ps_annc(padapter, 0);
mlmeext_set_scan_state(pmlmeext, SCAN_BACK_OP);
ss->backop_time = rtw_get_current_time();
if (mlmeext_chk_scan_backop_flags(pmlmeext, SS_BACKOP_TX_RESUME))
rtw_mi_os_xmit_schedule(padapter);
if (rtw_get_passing_time_ms(ss->backop_time) >= ss->backop_ms
|| pmlmeext->scan_abort
mlmeext_set_scan_state(pmlmeext, SCAN_LEAVING_OP);
set_survey_timer(pmlmeext, 50);
if (mlmeext_chk_scan_backop_flags(pmlmeext, SS_BACKOP_PS_ANNC)
&& rtw_ps_annc(padapter, 1)
mlmeext_set_scan_next_state(pmlmeext, SCAN_LEAVE_OP);
mlmeext_set_scan_state(pmlmeext, SCAN_LEAVE_OP);
if (mlmeext_chk_scan_backop_flags(pmlmeext, SS_BACKOP_PS_ANNC))
case SCAN_SW_ANTDIV_BL:
* 20100721
* 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.
ss->is_sw_antdiv_bl_scan = 1;
mlmeext_set_scan_next_state(pmlmeext, SCAN_PROCESS);
set_survey_timer(pmlmeext, ss->scan_ch_ms);
* Set the P2P State to the listen state of find phase
* and set the current channel to the listen channel
set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_LISTEN);
/* turn on phy-dynamic functions */
rtw_phydm_ability_restore(padapter);
mlmeext_set_scan_state(pmlmeext, SCAN_P2P_LISTEN);
_set_timer(&pwdinfo->find_phase_timer, (u32)((u32)pwdinfo->listen_dwell * 100));
case SCAN_P2P_LISTEN:
rtw_hal_set_hw_mac_addr(padapter, adapter_mac_addr(padapter));
|| rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)
if (pwdinfo->driver_interface == DRIVER_WEXT) {
if (rtw_mi_check_status(padapter, MI_LINKED))
_set_timer(&prochinfo->ap_roch_ch_switch_timer, 500);
rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE);
survey_done_set_ch_bw(padapter);
/* start MCC fail, then tx null data */
if (!rtw_hal_set_mcc_setting_scan_complete(padapter))
report_surveydone_event(padapter, ss->acs);
rtw_acs_select_best_chan(padapter);
#if defined(CONFIG_BACKGROUND_NOISE_MONITOR) && defined(DBG_NOISE_MONITOR)
rtw_noise_info_dump(RTW_DBGDUMP, padapter);
issue_action_BSSCoexistPacket(padapter);
if (ss->token)
rm_post_event(padapter, ss->token, RM_EV_survey_done);
if (padapter->mlmepriv.need_to_roam == _TRUE)
generate_quickss(padapter);
u8 setauth_hdl(_adapter *padapter, unsigned char *pbuf)
struct setauth_parm *pparm = (struct setauth_parm *)pbuf;
if (pparm->mode < 4)
pmlmeinfo->auth_algo = pparm->mode;
static u8 amsdu_spp_enable(_adapter *pdapter, enum security_type type)
if (pdapter->registrypriv.amsdu_mode == RTW_AMSDU_MODE_SPP) {
if ( type == _AES_ || type == _CCMP_256_
|| type == _GCMP_ || type == _GCMP_256_ )
SEC CAM Entry format (32 bytes)
DW0 - MAC_ADDR[15:0] | Valid[15] | MFB[14:8] | RSVD[7] | GK[6] | MIC_KEY[5] | SEC_TYPE[4:2] | KID[1:0]
DW0 - MAC_ADDR[15:0] | Valid[15] |RSVD[14:9] | RPT_MODE[8] | SPP_MODE[7] | GK[6] | MIC_KEY[5] | SEC_TYPE[4:2] | KID[1:0] (92E/8812A/8814A)
DW1 - MAC_ADDR[47:16]
DW2 - KEY[31:0]
DW3 - KEY[63:32]
DW4 - KEY[95:64]
DW5 - KEY[127:96]
DW6 - RSVD
DW7 - RSVD
/*Set WEP key or Group Key*/
u8 setkey_hdl(_adapter *padapter, u8 *pbuf)
u16 ctrl = 0;
s16 cam_id = 0;
struct setkey_parm *pparm = (struct setkey_parm *)pbuf;
unsigned char null_addr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
bool used = _FALSE;
/* main tx key for wep. */
if (pparm->set_tx)
pmlmeinfo->key_index = pparm->keyid;
#ifndef SEC_DEFAULT_KEY_SEARCH
if (((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE))
cam_id = rtw_iface_bcmc_id_get(padapter);
cam_id = rtw_camid_alloc(padapter, NULL, pparm->keyid, 1,
!!(pparm->algorithm & _SEC_TYPE_256_), &used);
if (cam_id < 0)
goto enable_mc;
#ifdef SEC_DEFAULT_KEY_SEARCH
if (cam_id >= 0 && cam_id <= 3) {
/* default key camid */
addr = null_addr;
/* not default key camid */
if (((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE)) {
/* group TX, force sec cam entry_id */
addr = adapter_mac_addr(padapter);
/* group RX, searched by A2 (TA) */
addr = get_bssid(&padapter->mlmepriv);
#ifdef CONFIG_LPS_PG
if (adapter_to_pwrctl(padapter)->lps_level == LPS_PG)
LPS_Leave(padapter, "SET_KEY");
/* cam entry searched is pairwise key */
if (used == _TRUE && rtw_camid_is_gk(padapter, cam_id) == _FALSE) {
s16 camid_clr;
RTW_PRINT(FUNC_ADPT_FMT" group key with "MAC_FMT" id:%u the same key id as pairwise key\n"
, FUNC_ADPT_ARG(padapter), MAC_ARG(addr), pparm->keyid);
/* HW has problem to distinguish this group key with existing pairwise key, stop HW enc and dec for BMC */
rtw_camctl_set_flags(padapter, SEC_STATUS_STA_PK_GK_CONFLICT_DIS_BMC_SEARCH);
rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, NULL);
/* clear group key */
while ((camid_clr = rtw_camid_search(padapter, addr, -1, 1)) >= 0) {
RTW_PRINT("clear group key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(addr), camid_clr);
clear_cam_entry(padapter, camid_clr);
rtw_camid_free(padapter, camid_clr);
ctrl = BIT(15) | BIT(6) | ((pparm->algorithm & 0x07) << 2) | pparm->keyid;
RTW_PRINT("set group key camid:%d, addr:"MAC_FMT", kid:%d, type:%s\n"
, cam_id, MAC_ARG(addr), pparm->keyid, security_type_str(pparm->algorithm));
if (pparm->algorithm & _SEC_TYPE_256_) {
RTW_INFO_DUMP("GTK : ", pparm->key, sizeof(pparm->key));
ctrl |= BIT(9);
if (amsdu_spp_enable(padapter, pparm->algorithm) == _SUCCESS)
ctrl |= BIT(7);
write_cam(padapter, cam_id, ctrl, addr, pparm->key);
/* if ((cam_id > 3) && (((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)))*/
if (is_wep_enc(pparm->algorithm)) {
padapter->securitypriv.dot11Def_camid[pparm->keyid] = cam_id;
padapter->securitypriv.dot118021x_bmc_cam_id =
padapter->securitypriv.dot11Def_camid[padapter->securitypriv.dot11PrivacyKeyIndex];
RTW_PRINT("wep group key - force camid:%d\n", padapter->securitypriv.dot118021x_bmc_cam_id);
/*u8 org_cam_id = padapter->securitypriv.dot118021x_bmc_cam_id;*/
/*force GK's cam id*/
padapter->securitypriv.dot118021x_bmc_cam_id = cam_id;
/* for GTK rekey
if ((org_cam_id != INVALID_SEC_MAC_CAM_ID) &&
(org_cam_id != cam_id)) {
RTW_PRINT("clear group key for addr:"MAC_FMT", org_camid:%d new_camid:%d\n", MAC_ARG(addr), org_cam_id, cam_id);
clear_cam_entry(padapter, org_cam_id);
rtw_camid_free(padapter, org_cam_id);
}*/
if (cam_id >= 0 && cam_id <= 3)
rtw_hal_set_hwreg(padapter, HW_VAR_SEC_DK_CFG, (u8 *)_TRUE);
/* 8814au should set both broadcast and unicast CAM entry for WEP key in STA mode */
if (is_wep_enc(pparm->algorithm) && check_mlmeinfo_state(pmlmeext, WIFI_FW_STATION_STATE) &&
_rtw_camctl_chk_cap(padapter, SEC_CAP_CHK_BMC)) {
struct set_stakey_parm sta_pparm;
_rtw_memset(&sta_pparm, 0, sizeof(struct set_stakey_parm));
sta_pparm.algorithm = pparm->algorithm;
sta_pparm.keyid = pparm->keyid;
_rtw_memcpy(sta_pparm.key, pparm->key, 16);
_rtw_memcpy(sta_pparm.addr, get_bssid(&padapter->mlmepriv), ETH_ALEN);
set_stakey_hdl(padapter, (u8 *)&sta_pparm);
enable_mc:
/* allow multicast packets to driver */
rtw_hal_set_hwreg(padapter, HW_VAR_ON_RCR_AM, null_addr);
if (padapter->mlmepriv.roam_network) {
void rtw_ap_wep_pk_setting(_adapter *adapter, struct sta_info *psta)
struct security_priv *psecuritypriv = &(adapter->securitypriv);
sint keyid;
if (!is_wep_enc(psecuritypriv->dot11PrivacyAlgrthm))
for (keyid = 0; keyid < 4; keyid++) {
if ((psecuritypriv->key_mask & BIT(keyid)) && (keyid == psecuritypriv->dot11PrivacyKeyIndex)) {
sta_pparm.algorithm = psecuritypriv->dot11PrivacyAlgrthm;
sta_pparm.keyid = keyid;
sta_pparm.gk = 0;
_rtw_memcpy(sta_pparm.key, &(psecuritypriv->dot11DefKey[keyid].skey[0]), 16);
_rtw_memcpy(sta_pparm.addr, psta->cmn.mac_addr, ETH_ALEN);
RTW_PRINT(FUNC_ADPT_FMT"set WEP - PK with "MAC_FMT" keyid:%u\n"
, FUNC_ADPT_ARG(adapter), MAC_ARG(psta->cmn.mac_addr), keyid);
set_stakey_hdl(adapter, (u8 *)&sta_pparm);
u8 set_stakey_hdl(_adapter *padapter, u8 *pbuf)
bool used;
struct set_stakey_parm *pparm = (struct set_stakey_parm *)pbuf;
if (pparm->algorithm == _NO_PRIVACY_)
goto write_to_cam;
psta = rtw_get_stainfo(pstapriv, pparm->addr);
if (!psta) {
RTW_PRINT("%s sta:"MAC_FMT" not found\n", __func__, MAC_ARG(pparm->addr));
ret = H2C_REJECTED;
pmlmeinfo->enc_algo = pparm->algorithm;
cam_id = rtw_camid_alloc(padapter, psta, pparm->keyid, pparm->gk,
/* cam entry searched is group key when setting pariwise key */
if (!pparm->gk && used == _TRUE && rtw_camid_is_gk(padapter, cam_id) == _TRUE) {
RTW_PRINT(FUNC_ADPT_FMT" pairwise key with "MAC_FMT" id:%u the same key id as group key\n"
, FUNC_ADPT_ARG(padapter), MAC_ARG(pparm->addr), pparm->keyid);
/* HW has problem to distinguish this pairwise key with existing group key, stop HW enc and dec for BMC */
while ((camid_clr = rtw_camid_search(padapter, pparm->addr, -1, 1)) >= 0) {
RTW_PRINT("clear group key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(pparm->addr), camid_clr);
write_to_cam:
if (pparm->algorithm == _NO_PRIVACY_) {
while ((cam_id = rtw_camid_search(padapter, pparm->addr, -1, -1)) >= 0) {
RTW_PRINT("clear key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(pparm->addr), cam_id);
clear_cam_entry(padapter, cam_id);
rtw_camid_free(padapter, cam_id);
RTW_PRINT("set %s key camid:%d, addr:"MAC_FMT", kid:%d, type:%s\n"
, pparm->gk ? "group" : "pairwise"
, cam_id, MAC_ARG(pparm->addr), pparm->keyid, security_type_str(pparm->algorithm));
ctrl = BIT(15) | ((pparm->algorithm & 0x07) << 2) | pparm->keyid;
if (pparm->gk)
ctrl |= BIT(6);
RTW_INFO_DUMP("PTK : ", pparm->key, sizeof(pparm->key));
write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key);
if (!(pparm->gk))
ATOMIC_INC(&psta->keytrack); /*CVE-2020-24587*/
ret = H2C_SUCCESS_RSP;
u8 add_ba_hdl(_adapter *padapter, unsigned char *pbuf)
struct addBaReq_parm *pparm = (struct addBaReq_parm *)pbuf;
struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, pparm->addr);
if (((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && (pmlmeinfo->HT_enable)) ||
((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) {
/* pmlmeinfo->ADDBA_retry_count = 0; */
/* pmlmeinfo->candidate_tid_bitmap |= (0x1 << pparm->tid); */
/* psta->htpriv.candidate_tid_bitmap |= BIT(pparm->tid); */
issue_addba_req(padapter, pparm->addr, (u8)pparm->tid);
_set_timer(&psta->addba_retry_timer, ADDBA_TO);
else if ((psta->tdls_sta_state & TDLS_LINKED_STATE) &&
(psta->htpriv.ampdu_enable == _TRUE)) {
#endif /* CONFIG */
psta->htpriv.candidate_tid_bitmap &= ~BIT(pparm->tid);
u8 add_ba_rsp_hdl(_adapter *padapter, unsigned char *pbuf)
struct addBaRsp_parm *pparm = (struct addBaRsp_parm *)pbuf;
preorder_ctrl = &psta->recvreorder_ctrl[pparm->tid];
ret = issue_addba_rsp_wait_ack(padapter, pparm->addr, pparm->tid, pparm->status, pparm->size, 3, 50);
#ifdef CONFIG_UPDATE_INDICATE_SEQ_WHILE_PROCESS_ADDBA_REQ
/* status = 0 means accept this addba req, so update indicate seq = start_seq under this compile flag */
if (pparm->status == 0) {
preorder_ctrl->indicate_seq = pparm->start_seq;
#ifdef DBG_RX_SEQ
RTW_INFO("DBG_RX_SEQ "FUNC_ADPT_FMT" tid:%u SN_UPDATE indicate_seq:%d, start_seq:%d\n"
, FUNC_ADPT_ARG(padapter), preorder_ctrl->tid, preorder_ctrl->indicate_seq, pparm->start_seq);
rtw_set_bit(RTW_RECV_ACK_OR_TIMEOUT, &preorder_ctrl->rec_abba_rsp_ack);
RTW_INFO("DBG_RX_SEQ "FUNC_ADPT_FMT" tid:%u SN_CLEAR indicate_seq:%d, start_seq:%d preorder_ctrl->rec_abba_rsp_ack =%lu \n"
, preorder_ctrl->tid
, preorder_ctrl->indicate_seq
, pparm->start_seq
,preorder_ctrl->rec_abba_rsp_ack
* status = 0 means accept this addba req
* status = 37 means reject this addba req
preorder_ctrl->enable = _TRUE;
preorder_ctrl->ampdu_size = pparm->size;
} else if (pparm->status == 37)
u8 chk_bmc_sleepq_cmd(_adapter *padapter)
struct cmd_obj *ph2c;
struct cmd_priv *pcmdpriv = &(padapter->cmdpriv);
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
init_h2fwcmd_w_parm_no_parm_rsp(ph2c, CMD_CHK_BMCSLEEPQ);
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
u8 set_tx_beacon_cmd(_adapter *padapter, u8 flags)
struct Tx_Beacon_param *ptxBeacon_parm;
/*prepare cmd parameter*/
ptxBeacon_parm = (struct Tx_Beacon_param *)rtw_zmalloc(sizeof(struct Tx_Beacon_param));
if (ptxBeacon_parm == NULL) {
_rtw_memcpy(&(ptxBeacon_parm->network), &(pmlmeinfo->network), sizeof(WLAN_BSSID_EX));
ptxBeacon_parm->network.IEs + _BEACON_IE_OFFSET_
, ptxBeacon_parm->network.IELength - _BEACON_IE_OFFSET_
ptxBeacon_parm->network.IELength += len_diff;
/* need enqueue, prepare cmd_obj and enqueue */
rtw_mfree((u8 *)ptxBeacon_parm, sizeof(*ptxBeacon_parm));
init_h2fwcmd_w_parm_no_rsp(ph2c, ptxBeacon_parm, CMD_TX_BEACON);
if (flags & RTW_CMDF_WAIT_ACK) {
ph2c->sctx = &sctx;
rtw_sctx_init(&sctx, 10 * 1000);
if (res == _SUCCESS && (flags & RTW_CMDF_WAIT_ACK)) {
rtw_sctx_wait(&sctx, __func__);
_enter_critical_mutex(&pcmdpriv->sctx_mutex, NULL);
if (sctx.status == RTW_SCTX_SUBMITTED)
ph2c->sctx = NULL;
_exit_critical_mutex(&pcmdpriv->sctx_mutex, NULL);
u8 mlme_evt_hdl(_adapter *padapter, unsigned char *pbuf)
u8 *peventbuf;
void (*event_callback)(_adapter *dev, u8 *pbuf);
struct evt_priv *pevt_priv = &(padapter->evtpriv);
if (pbuf == NULL)
goto _abort_event_;
evt_hdr = (struct rtw_evt_header *)pbuf;
peventbuf = pbuf + sizeof(struct rtw_evt_header);
#ifdef CHECK_EVENT_SEQ
/* checking event sequence... */
if (evt_hdr->seq != (ATOMIC_READ(&pevt_priv->event_seq) & 0x7f)) {
pevt_priv->event_seq = (evt_hdr->seq + 1) & 0x7f;
/* checking if event code is valid */
if (evt_hdr->id >= EVT_ID_MAX) {
/* checking if event size match the event parm size */
if ((wlanevents[evt_hdr->id].parmsize != 0) &&
(wlanevents[evt_hdr->id].parmsize != evt_hdr->len)) {
ATOMIC_INC(&pevt_priv->event_seq);
if (peventbuf) {
event_callback = wlanevents[evt_hdr->id].event_callback;
event_callback(padapter, (u8 *)peventbuf);
pevt_priv->evt_done_cnt++;
_abort_event_:
u8 chk_bmc_sleepq_hdl(_adapter *padapter, unsigned char *pbuf)
struct sta_info *psta_bmc;
_list *xmitframe_plist, *xmitframe_phead;
struct xmit_frame *pxmitframe = NULL;
/* for BC/MC Frames */
psta_bmc = rtw_get_bcmc_stainfo(padapter);
if (!psta_bmc)
if ((rtw_tim_map_is_set(padapter, pstapriv->tim_bitmap, 0)) && (psta_bmc->sleepq_len > 0)) {
#ifndef CONFIG_PCI_HCI
rtw_msleep_os(10);/* 10ms, ATIM(HIQ) Windows */
/* _enter_critical_bh(&psta_bmc->sleep_q.lock, &irqL); */
_enter_critical_bh(&pxmitpriv->lock, &irqL);
xmitframe_phead = get_list_head(&psta_bmc->sleep_q);
xmitframe_plist = get_next(xmitframe_phead);
while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) {
pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
xmitframe_plist = get_next(xmitframe_plist);
rtw_list_delete(&pxmitframe->list);
psta_bmc->sleepq_len--;
if (psta_bmc->sleepq_len > 0)
pxmitframe->attrib.mdata = 1;
pxmitframe->attrib.mdata = 0;
pxmitframe->attrib.triggered = 1;
if (xmitframe_hiq_filter(pxmitframe) == _TRUE)
pxmitframe->attrib.qsel = QSLT_HIGH;/* HIQ */
_exit_critical_bh(&psta_bmc->sleep_q.lock, &irqL);
if (rtw_hal_xmit(padapter, pxmitframe) == _TRUE)
rtw_os_xmit_complete(padapter, pxmitframe);
_enter_critical_bh(&psta_bmc->sleep_q.lock, &irqL);
rtw_hal_xmitframe_enqueue(padapter, pxmitframe);
/* _exit_critical_bh(&psta_bmc->sleep_q.lock, &irqL); */
_exit_critical_bh(&pxmitpriv->lock, &irqL);
if (rtw_get_intf_type(padapter) != RTW_PCIE) {
/* check hi queue and bmc_sleepq */
rtw_chk_hi_queue_cmd(padapter);
u8 tx_beacon_hdl(_adapter *padapter, unsigned char *pbuf)
/*RTW_INFO(FUNC_ADPT_FMT, FUNC_ADPT_ARG(padapter));*/
#ifdef CONFIG_SWTIMER_BASED_TXBCN
tx_beacon_handlder(padapter->dvobj);
RTW_INFO("issue_beacon, fail!\n");
/* tx bc/mc frames after update TIM */
chk_bmc_sleepq_hdl(padapter, NULL);
* according to channel
* add/remove WLAN_BSSID_EX.IEs's ERP ie
* set WLAN_BSSID_EX.SupportedRates
* update WLAN_BSSID_EX.IEs's Supported Rate and Extended Supported Rate ie
void change_band_update_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 ch)
u8 network_type, rate_len, total_rate_len, remainder_rate_len;
u8 erpinfo = 0x4;
if (ch >= 36) {
network_type = WIRELESS_11A;
total_rate_len = IEEE80211_NUM_OFDM_RATESLEN;
rtw_remove_bcn_ie(padapter, pnetwork, _ERPINFO_IE_);
/* if channel in 5G band, then add vht ie . */
if ((pmlmepriv->htpriv.ht_option == _TRUE)
&& REGSTY_IS_11AC_ENABLE(&padapter->registrypriv)
&& is_supported_vht(padapter->registrypriv.wireless_mode)
&& (!rfctl->country_ent || COUNTRY_CHPLAN_EN_11AC(rfctl->country_ent))
if (REGSTY_IS_11AC_AUTO(&padapter->registrypriv)
|| pmlmepriv->ori_vht_en)
rtw_vht_ies_attach(padapter, pnetwork);
network_type = 0;
total_rate_len = 0;
if (padapter->registrypriv.wireless_mode & WIRELESS_11B) {
network_type |= WIRELESS_11B;
total_rate_len += IEEE80211_CCK_RATE_LEN;
if (padapter->registrypriv.wireless_mode & WIRELESS_11G) {
network_type |= WIRELESS_11G;
total_rate_len += IEEE80211_NUM_OFDM_RATESLEN;
rtw_add_bcn_ie(padapter, pnetwork, _ERPINFO_IE_, &erpinfo, 1);
rtw_vht_ies_detach(padapter, pnetwork);
rtw_set_supported_rate(pnetwork->SupportedRates, network_type);
UpdateBrateTbl(padapter, pnetwork->SupportedRates);
if (total_rate_len > 8) {
rate_len = 8;
remainder_rate_len = total_rate_len - 8;
rate_len = total_rate_len;
remainder_rate_len = 0;
rtw_add_bcn_ie(padapter, pnetwork, _SUPPORTEDRATES_IE_, pnetwork->SupportedRates, rate_len);
if (remainder_rate_len)
rtw_add_bcn_ie(padapter, pnetwork, _EXT_SUPPORTEDRATES_IE_, (pnetwork->SupportedRates + 8), remainder_rate_len);
rtw_remove_bcn_ie(padapter, pnetwork, _EXT_SUPPORTEDRATES_IE_);
pnetwork->Length = get_WLAN_BSSID_EX_sz(pnetwork);
void rtw_join_done_chk_ch(_adapter *adapter, int join_res)
#define DUMP_ADAPTERS_STATUS 0
struct dvobj_priv *dvobj;
struct mlme_priv *mlme;
u8 u_ch, u_offset, u_bw;
int i, ret;
dvobj = adapter_to_dvobj(adapter);
if (DUMP_ADAPTERS_STATUS) {
RTW_INFO(FUNC_ADPT_FMT" enter\n", FUNC_ADPT_ARG(adapter));
dump_adapters_status(RTW_DBGDUMP , dvobj);
ret = rtw_mi_get_ch_setting_union(adapter, &u_ch, &u_bw, &u_offset);
if (join_res >= 0 && ret <= 0) {
join_res = -1;
if (join_res >= 0) {
/* MCC setting success, don't go to ch union process */
if (rtw_hal_set_mcc_setting_join_done_chk_ch(adapter))
mlme = &iface->mlmepriv;
if (!iface || iface == adapter)
if ((MLME_IS_AP(iface) || MLME_IS_MESH(iface))
&& check_fwstate(mlme, WIFI_ASOC_STATE)
u8 ori_ch, ori_bw, ori_offset;
bool is_grouped = rtw_is_chbw_grouped(u_ch, u_bw, u_offset
if (is_grouped == _FALSE) {
/* handle AP which need to switch ch setting */
ori_ch = mlmeext->cur_channel;
ori_bw = mlmeext->cur_bwmode;
ori_offset = mlmeext->cur_ch_offset;
/* restore original bw, adjust bw by registry setting on target ch */
mlmeext->cur_bwmode = mlme->ori_bw;
mlmeext->cur_channel = u_ch;
rtw_adjust_chbw(iface, mlmeext->cur_channel, &mlmeext->cur_bwmode, &mlmeext->cur_ch_offset);
if (MLME_IS_MESH(iface))
rtw_mesh_adjust_chbw(mlmeext->cur_channel, &mlmeext->cur_bwmode, &mlmeext->cur_ch_offset);
rtw_chset_sync_chbw(adapter_to_chset(adapter)
, &mlmeext->cur_channel, &mlmeext->cur_bwmode, &mlmeext->cur_ch_offset
, &u_ch, &u_bw, &u_offset, 1, 0);
RTW_INFO(FUNC_ADPT_FMT" %u,%u,%u => %u,%u,%u\n", FUNC_ADPT_ARG(iface)
, ori_ch, ori_bw, ori_offset
rtw_ap_update_bss_chbw(iface, &(mlmeext->mlmext_info.network)
_rtw_memcpy(&(mlme->cur_network.network), &(mlmeext->mlmext_info.network), sizeof(WLAN_BSSID_EX));
rtw_start_bss_hdl_after_chbw_decided(iface);
#if defined(CONFIG_IOCTL_CFG80211) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
u8 ht_option = 0;
ht_option = mlme->htpriv.ht_option;
rtw_cfg80211_ch_switch_notify(iface
, mlmeext->cur_channel, mlmeext->cur_bwmode, mlmeext->cur_ch_offset
, ht_option, 0);
clr_fwstate(mlme, WIFI_OP_CH_SWITCHING);
update_beacon(iface, 0xFF, NULL, _TRUE, 0);
rtw_dfs_rd_en_decision(adapter, MLME_STA_CONNECTED, 0);
rtw_dfs_rd_en_decision(adapter, MLME_STA_DISCONNECTED, 0);
if (rtw_mi_get_ch_setting_union(adapter, &u_ch, &u_bw, &u_offset)) {
RTW_INFO(FUNC_ADPT_FMT" union:%u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset);
set_channel_bwmode(adapter, u_ch, u_offset, u_bw);
rtw_mi_update_union_chan_inf(adapter, u_ch, u_offset, u_bw);
if (join_res >= 0)
rtw_rfctl_update_op_mode(adapter_to_rfctl(adapter), BIT(adapter->iface_id), 1);
RTW_INFO(FUNC_ADPT_FMT" exit\n", FUNC_ADPT_ARG(adapter));
int rtw_chk_start_clnt_join(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset)
bool chbw_allow = _TRUE;
bool connect_allow = _TRUE;
u8 cur_ch, cur_bw, cur_ch_offset;
u_ch = cur_ch = pmlmeext->cur_channel;
u_bw = cur_bw = pmlmeext->cur_bwmode;
u_offset = cur_ch_offset = pmlmeext->cur_ch_offset;
if (!ch || !bw || !offset) {
connect_allow = _FALSE;
if (cur_ch == 0) {
RTW_ERR(FUNC_ADPT_FMT" cur_ch:%u\n"
, FUNC_ADPT_ARG(adapter), cur_ch);
RTW_INFO(FUNC_ADPT_FMT" req: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset);
rtw_mi_status_no_self(adapter, &mstate);
RTW_INFO(FUNC_ADPT_FMT" others ld_sta_num:%u, ap_num:%u, mesh_num:%u\n"
, FUNC_ADPT_ARG(adapter), MSTATE_STA_LD_NUM(&mstate)
, MSTATE_AP_NUM(&mstate), MSTATE_MESH_NUM(&mstate));
if (!MSTATE_STA_LD_NUM(&mstate) && !MSTATE_AP_NUM(&mstate) && !MSTATE_MESH_NUM(&mstate)) {
/* consider linking STA? */
goto connect_allow_hdl;
if (rtw_mi_get_ch_setting_union_no_self(adapter, &u_ch, &u_bw, &u_offset) <= 0) {
RTW_INFO(FUNC_ADPT_FMT" others union:%u,%u,%u\n"
, FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset);
/* chbw_allow? */
chbw_allow = rtw_is_chbw_grouped(pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset
, u_ch, u_bw, u_offset);
RTW_INFO(FUNC_ADPT_FMT" chbw_allow:%d\n"
, FUNC_ADPT_ARG(adapter), chbw_allow);
/* check setting success, don't go to ch union process */
if (rtw_hal_set_mcc_setting_chk_start_clnt_join(adapter, &u_ch, &u_bw, &u_offset, chbw_allow))
if (chbw_allow == _TRUE) {
rtw_sync_chbw(&cur_ch, &cur_bw, &cur_ch_offset, &u_ch, &u_bw, &u_offset);
rtw_warn_on(cur_ch != pmlmeext->cur_channel);
rtw_warn_on(cur_bw != pmlmeext->cur_bwmode);
rtw_warn_on(cur_ch_offset != pmlmeext->cur_ch_offset);
#ifdef CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT
/* chbw_allow is _FALSE, connect allow? */
if (check_fwstate(mlme, WIFI_STATION_STATE)
#if defined(CONFIG_P2P)
&& rtw_p2p_chk_state(&(iface->wdinfo), P2P_STATE_NONE)
#endif /* CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT */
if (MSTATE_STA_LD_NUM(&mstate) + MSTATE_AP_LD_NUM(&mstate) + MSTATE_MESH_LD_NUM(&mstate) >= 4)
RTW_INFO(FUNC_ADPT_FMT" connect_allow:%d\n"
, FUNC_ADPT_ARG(adapter), connect_allow);
if (connect_allow == _FALSE)
connect_allow_hdl:
/* connect_allow == _TRUE */
if (chbw_allow == _FALSE) {
u_ch = cur_ch;
u_bw = cur_bw;
u_offset = cur_ch_offset;
if (1)
rtw_ap_inform_ch_switch(iface, pmlmeext->cur_channel , pmlmeext->cur_ch_offset);
rtw_sta_flush(iface, _FALSE);
rtw_hal_set_hwreg(iface, HW_VAR_CHECK_TXBUF, 0);
set_fwstate(mlme, WIFI_OP_CH_SWITCHING);
rtw_disassoc_cmd(iface, 500, RTW_CMDF_DIRECTLY);
rtw_indicate_disconnect(iface, 0, _FALSE);
rtw_free_assoc_resources(iface, _TRUE);
rtw_dfs_rd_en_decision(adapter, MLME_STA_CONNECTING, 0);
if (connect_allow == _TRUE) {
RTW_INFO(FUNC_ADPT_FMT" union: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset);
*ch = u_ch;
*bw = u_bw;
*offset = u_offset;
ht_option = adapter->mlmepriv.htpriv.ht_option;
when supplicant send the mlme frame,
the bss freq is updated by channel switch event.
rtw_cfg80211_ch_switch_notify(adapter,
cur_ch, cur_bw, cur_ch_offset, ht_option, 1);
return connect_allow == _TRUE ? _SUCCESS : _FAIL;
void rtw_set_external_auth_status(_adapter *padapter,
const void *data, int len)
struct net_device *dev = padapter->pnetdev;
struct wiphy *wiphy = adapter_to_wiphy(padapter);
struct rtw_external_auth_params params;
/* convert data to external_auth_params */
params.action = RTW_GET_BE32((u8 *)data);
_rtw_memcpy(¶ms.bssid, (u8 *)data + 4, ETH_ALEN);
_rtw_memcpy(¶ms.ssid.ssid, (u8 *)data + 10, WLAN_SSID_MAXLEN);
params.ssid.ssid_len = RTW_GET_BE64((u8 *)data + 42);
params.key_mgmt_suite = RTW_GET_BE32((u8 *)data + 58);
params.status = RTW_GET_BE16((u8 *)data + 62);
_rtw_memcpy(¶ms.pmkid, (u8 *)data + 64, PMKID_LEN);
rtw_cfg80211_external_auth_status(wiphy, dev, ¶ms);
u8 rtw_iqk_hdl(_adapter *padapter, unsigned char *pbuf)
rtw_hal_phydm_cal_trigger(padapter);
u8 rtw_set_chbw_hdl(_adapter *padapter, u8 *pbuf)
struct set_ch_parm *set_ch_parm;
u8 ifbmp_s = rtw_mi_get_ld_sta_ifbmp(padapter);
set_ch_parm = (struct set_ch_parm *)pbuf;
RTW_INFO(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n",
FUNC_NDEV_ARG(padapter->pnetdev),
set_ch_parm->ch, set_ch_parm->bw, set_ch_parm->ch_offset);
/* update ch, bw, offset for all asoc STA ifaces */
if (ifbmp_s) {
if (!iface || !(ifbmp_s & BIT(iface->iface_id)))
/* update STA mode ch/bw/offset */
iface->mlmeextpriv.cur_channel = set_ch_parm->ch;
iface->mlmeextpriv.cur_bwmode = set_ch_parm->bw;
iface->mlmeextpriv.cur_ch_offset = set_ch_parm->ch_offset;
/* updaet STA mode DSConfig , ap mode will update in rtw_change_bss_chbw_cmd */
iface->mlmepriv.cur_network.network.Configuration.DSConfig = set_ch_parm->ch;
LeaveAllPowerSaveModeDirect(padapter);
#ifdef CONFIG_MONITOR_MODE_XMIT
pmlmeext->cur_channel = set_ch_parm->ch;
pmlmeext->cur_ch_offset = set_ch_parm->ch_offset;
pmlmeext->cur_bwmode = set_ch_parm->bw;
#endif /* CONFIG_MONITOR_MODE_XMIT */
set_channel_bwmode(padapter, set_ch_parm->ch, set_ch_parm->ch_offset, set_ch_parm->bw);
rtw_mi_get_ch_setting_union(padapter, &u_ch, &u_bw, &u_offset);
rtw_mi_update_union_chan_inf(padapter, u_ch, u_offset, u_bw);
rtw_rfctl_update_op_mode(dvobj_to_rfctl(dvobj), 0, 0);
u8 rtw_set_chplan_hdl(_adapter *padapter, unsigned char *pbuf)
struct SetChannelPlan_param *param;
param = (struct SetChannelPlan_param *)pbuf;
if (param->regd_src == REGD_SRC_RTK_PRIV
&& !rtw_is_channel_plan_valid(param->channel_plan))
rfctl->regd_src = param->regd_src;
rfctl->country_ent = param->country_ent;
rfctl->ChannelPlan = param->channel_plan;
rtw_txpwr_init_regd(rfctl);
rtw_rfctl_chplan_init(padapter);
rtw_hal_set_odm_var(padapter, HAL_ODM_REGULATION, NULL, _TRUE);
rtw_regd_apply_flags(adapter_to_wiphy(padapter));
rtw_nlrtw_reg_change_event(padapter);
if (GET_HAL_DATA(padapter)->txpwr_limit_loaded
&& rtw_get_hw_init_completed(padapter))
rtw_hal_update_txpwr_level(padapter);
u8 rtw_get_chplan_hdl(_adapter *padapter, unsigned char *pbuf)
struct get_channel_plan_param *param;
struct get_chplan_resp *resp;
struct rf_ctl_t *rfctl;
rfctl = adapter_to_rfctl(padapter);
param = (struct get_channel_plan_param *)pbuf;
resp = rtw_vmalloc(sizeof(struct get_chplan_resp) + sizeof(RT_CHANNEL_INFO) * rfctl->max_chan_nums);
if (!resp)
return H2C_CMD_FAIL;
resp->regd_src = rfctl->regd_src;
if (rfctl->country_ent) {
_rtw_memcpy(&resp->country_ent, rfctl->country_ent, sizeof(struct country_chplan));
resp->has_country = 1;
resp->has_country = 0;
resp->channel_plan = rfctl->ChannelPlan;
resp->regd_name = rfctl->regd_name;
resp->dfs_domain = rtw_rfctl_get_dfs_domain(rfctl);
resp->chset_num = rfctl->max_chan_nums;
_rtw_memcpy(resp->chset, rfctl->channel_set, sizeof(RT_CHANNEL_INFO) * rfctl->max_chan_nums);
*param->resp = resp;
u8 led_blink_hdl(_adapter *padapter, unsigned char *pbuf)
struct LedBlink_param *ledBlink_param;
ledBlink_param = (struct LedBlink_param *)pbuf;
#ifdef CONFIG_RTW_LED_HANDLED_BY_CMD_THREAD
BlinkHandler((PLED_DATA)ledBlink_param->pLed);
void csa_timer_hdl(void *FunctionContext)
_adapter *padapter = (_adapter *)FunctionContext;
struct rf_ctl_t *rfctl = dvobj_to_rfctl(dvobj);
u8 i, update_beacon = _FALSE;
if (check_fwstate(pmlmepriv, WIFI_CSA_UPDATE_BEACON)) {
clr_fwstate(pmlmepriv, WIFI_CSA_UPDATE_BEACON);
update_beacon = _TRUE;
/* wait beacons more than 70 seconds */
if(update_beacon == _TRUE) {
RTW_INFO("wait beacons more than 70 seconds\n");
return ;
if(rfctl->csa_ch == 0) {
RTW_INFO("channel switch done\n");
/* channel switch */
if (rtw_set_csa_cmd(padapter) != _SUCCESS) {
rfctl->csa_ch = 0;
rfctl->csa_switch_cnt = 0;
rfctl->csa_ch_offset = 0;
rfctl->csa_ch_width = 0;
rfctl->csa_ch_freq_seg0 = 0;
rfctl->csa_ch_freq_seg1 = 0;
u8 set_csa_hdl(_adapter *adapter, unsigned char *pbuf)
if (rfctl->csa_ch)
rtw_dfs_ch_switch_hdl(adapter_to_dvobj(adapter));
u8 tdls_hdl(_adapter *padapter, unsigned char *pbuf)
struct tdls_ch_switch *pchsw_info = &ptdlsinfo->chsw_info;
struct TDLSoption_param *TDLSoption;
struct sta_info *ptdls_sta = NULL;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
struct sta_info *ap_sta = rtw_get_stainfo(&padapter->stapriv, get_my_bssid(&(pmlmeinfo->network)));
u8 survey_channel, i, min, option;
u32 setchtime, resp_sleep = 0, wait_time;
u8 zaddr[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
u8 ret;
u8 doiqk;
u64 tx_ra_bitmap = 0;
TDLSoption = (struct TDLSoption_param *)pbuf;
option = TDLSoption->option;
if (!_rtw_memcmp(TDLSoption->addr, zaddr, ETH_ALEN)) {
ptdls_sta = rtw_get_stainfo(&(padapter->stapriv), TDLSoption->addr);
if (ptdls_sta == NULL)
return H2C_REJECTED;
if (!(option == TDLS_RS_RCR))
/* _enter_critical_bh(&(ptdlsinfo->hdl_lock), &irqL); */
/* RTW_INFO("[%s] option:%d\n", __FUNCTION__, option); */
switch (option) {
case TDLS_ESTABLISHED: {
/* As long as TDLS handshake success, we should set RCR_CBSSID_DATA bit to 0 */
/* So we can receive all kinds of data frames. */
u8 sta_band = 0;
/* leave ALL PS when TDLS is established */
rtw_pwr_wakeup(padapter);
rtw_hal_rcr_set_chk_bssid(padapter, MLME_TDLS_LINKED);
RTW_INFO("Created Direct Link with "MAC_FMT"\n", MAC_ARG(ptdls_sta->cmn.mac_addr));
/* Set TDLS sta rate. */
/* Update station supportRate */
rtw_hal_update_sta_ra_info(padapter, ptdls_sta);
tx_ra_bitmap = ptdls_sta->cmn.ra_info.ramask;
if (tx_ra_bitmap & 0xffff000)
sta_band |= WIRELESS_11_5N ;
if (tx_ra_bitmap & 0xff0)
sta_band |= WIRELESS_11A;
/* 5G band */
if (ptdls_sta->vhtpriv.vht_option)
sta_band = WIRELESS_11_5AC;
sta_band |= WIRELESS_11_24N;
sta_band |= WIRELESS_11G;
if (tx_ra_bitmap & 0x0f)
sta_band |= WIRELESS_11B;
ptdls_sta->wireless_mode = sta_band;
rtw_hal_update_sta_wset(padapter, ptdls_sta);
/* Sta mode */
rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, ptdls_sta, _TRUE);
set_sta_rate(padapter, ptdls_sta);
rtw_sta_media_status_rpt(padapter, ptdls_sta, 1);
case TDLS_ISSUE_PTI:
ptdls_sta->tdls_sta_state |= TDLS_WAIT_PTR_STATE;
issue_tdls_peer_traffic_indication(padapter, ptdls_sta);
_set_timer(&ptdls_sta->pti_timer, TDLS_PTI_TIME);
case TDLS_CH_SW_RESP:
txmgmt.status_code = 0;
_rtw_memcpy(txmgmt.peer, ptdls_sta->cmn.mac_addr, ETH_ALEN);
if (ap_sta)
rtw_hal_macid_sleep(padapter, ap_sta->cmn.mac_id);
issue_nulldata(padapter, NULL, 1, 3, 3);
RTW_INFO("[TDLS ] issue tdls channel switch response\n");
ret = issue_tdls_ch_switch_rsp(padapter, &txmgmt, _TRUE);
/* If we receive TDLS_CH_SW_REQ at off channel which it's target is AP's channel */
/* then we just switch to AP's channel*/
if (padapter->mlmeextpriv.cur_channel == pchsw_info->off_ch_num) {
rtw_tdls_cmd(padapter, ptdls_sta->cmn.mac_addr, TDLS_CH_SW_END_TO_BASE_CHNL);
if (ret == _SUCCESS)
rtw_tdls_cmd(padapter, ptdls_sta->cmn.mac_addr, TDLS_CH_SW_TO_OFF_CHNL);
RTW_INFO("[TDLS] issue_tdls_ch_switch_rsp wait ack fail !!!!!!!!!!\n");
case TDLS_CH_SW_PREPARE:
pchsw_info->ch_sw_state |= TDLS_CH_SWITCH_PREPARE_STATE;
/* to collect IQK info of off-chnl */
rtw_hal_set_hwreg(padapter, HW_VAR_DO_IQK, &doiqk);
set_channel_bwmode(padapter, pchsw_info->off_ch_num, pchsw_info->ch_offset, (pchsw_info->ch_offset) ? CHANNEL_WIDTH_40 : CHANNEL_WIDTH_20);
/* switch back to base-chnl */
rtw_tdls_cmd(padapter, ptdls_sta->cmn.mac_addr, TDLS_CH_SW_START);
pchsw_info->ch_sw_state &= ~(TDLS_CH_SWITCH_PREPARE_STATE);
case TDLS_CH_SW_START:
rtw_tdls_set_ch_sw_oper_control(padapter, _TRUE);
case TDLS_CH_SW_TO_OFF_CHNL:
if (padapter->registrypriv.wifi_spec == 0) {
if (!(pchsw_info->ch_sw_state & TDLS_CH_SW_INITIATOR_STATE))
_set_timer(&ptdls_sta->ch_sw_timer, (u32)(ptdls_sta->ch_switch_timeout) / 1000);
if (rtw_tdls_do_ch_sw(padapter, ptdls_sta, TDLS_CH_SW_OFF_CHNL, pchsw_info->off_ch_num,
pchsw_info->ch_offset, (pchsw_info->ch_offset) ? CHANNEL_WIDTH_40 : CHANNEL_WIDTH_20, ptdls_sta->ch_switch_time) == _SUCCESS) {
pchsw_info->ch_sw_state &= ~(TDLS_PEER_AT_OFF_STATE);
if (pchsw_info->ch_sw_state & TDLS_CH_SW_INITIATOR_STATE) {
if (issue_nulldata_to_TDLS_peer_STA(ptdls_sta->padapter, ptdls_sta->cmn.mac_addr, 0, 1,
(padapter->registrypriv.wifi_spec == 0) ? 3 : 0) == _FAIL)
rtw_tdls_cmd(padapter, ptdls_sta->cmn.mac_addr, TDLS_CH_SW_TO_BASE_CHNL);
_cancel_timer_ex(&ptdls_sta->ch_sw_timer);
case TDLS_CH_SW_END:
case TDLS_CH_SW_END_TO_BASE_CHNL:
rtw_tdls_set_ch_sw_oper_control(padapter, _FALSE);
_cancel_timer_ex(&ptdls_sta->stay_on_base_chnl_timer);
_cancel_timer_ex(&ptdls_sta->ch_sw_monitor_timer);
_rtw_memset(pHalData->tdls_ch_sw_iqk_info_base_chnl, 0x00, sizeof(pHalData->tdls_ch_sw_iqk_info_base_chnl));
_rtw_memset(pHalData->tdls_ch_sw_iqk_info_off_chnl, 0x00, sizeof(pHalData->tdls_ch_sw_iqk_info_off_chnl));
if (option == TDLS_CH_SW_END_TO_BASE_CHNL)
case TDLS_CH_SW_TO_BASE_CHNL_UNSOLICITED:
case TDLS_CH_SW_TO_BASE_CHNL:
pchsw_info->ch_sw_state &= ~(TDLS_PEER_AT_OFF_STATE | TDLS_WAIT_CH_RSP_STATE);
if (option == TDLS_CH_SW_TO_BASE_CHNL_UNSOLICITED) {
/* Send unsolicited channel switch rsp. to peer */
issue_tdls_ch_switch_rsp(padapter, &txmgmt, _FALSE);
if (rtw_tdls_do_ch_sw(padapter, ptdls_sta, TDLS_CH_SW_BASE_CHNL, pmlmeext->cur_channel,
pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode, ptdls_sta->ch_switch_time) == _SUCCESS) {
rtw_hal_macid_wakeup(padapter, ap_sta->cmn.mac_id);
issue_nulldata(padapter, NULL, 0, 3, 3);
/* set ch sw monitor timer for responder */
_set_timer(&ptdls_sta->ch_sw_monitor_timer, TDLS_CH_SW_MONITOR_TIMEOUT);
case TDLS_RS_RCR:
rtw_hal_rcr_set_chk_bssid(padapter, MLME_TDLS_NOLINK);
case TDLS_TEARDOWN_STA:
case TDLS_TEARDOWN_STA_NO_WAIT:
txmgmt.status_code = _RSON_TDLS_TEAR_UN_RSN_;
issue_tdls_teardown(padapter, &txmgmt, (option == TDLS_TEARDOWN_STA) ? _TRUE : _FALSE);
case TDLS_TEARDOWN_STA_LOCALLY:
case TDLS_TEARDOWN_STA_LOCALLY_POST:
if (_rtw_memcmp(TDLSoption->addr, pchsw_info->addr, ETH_ALEN) == _TRUE) {
pchsw_info->ch_sw_state &= ~(TDLS_CH_SW_INITIATOR_STATE |
TDLS_CH_SWITCH_ON_STATE |
TDLS_PEER_AT_OFF_STATE);
_rtw_memset(pchsw_info->addr, 0x00, ETH_ALEN);
if (option == TDLS_TEARDOWN_STA_LOCALLY)
rtw_tdls_teardown_pre_hdl(padapter, ptdls_sta);
rtw_tdls_teardown_post_hdl(padapter, ptdls_sta, _FALSE);
if (ptdlsinfo->tdls_sctx != NULL)
rtw_sctx_done(&(ptdlsinfo->tdls_sctx));
/* _exit_critical_bh(&(ptdlsinfo->hdl_lock), &irqL); */
u8 run_in_thread_hdl(_adapter *padapter, u8 *pbuf)
struct RunInThread_param *p;
if (NULL == pbuf)
p = (struct RunInThread_param *)pbuf;
if (p->func)
p->func(p->context);
int rtw_sae_preprocess(_adapter *adapter, const u8 *buf, u32 len, u8 tx)
const u8 *frame_body = buf + sizeof(struct rtw_ieee80211_hdr_3addr);
u16 alg;
u16 seq;
u16 status;
alg = RTW_GET_LE16(frame_body);
if (alg != WLAN_AUTH_SAE)
seq = RTW_GET_LE16(frame_body + 2);
status = RTW_GET_LE16(frame_body + 4);
RTW_INFO("RTW_%s:AUTH alg:0x%04x, seq:0x%04x, status:0x%04x, mesg:%s\n",
(tx == _TRUE) ? "Tx" : "Rx", alg, seq, status,
(seq == 1) ? "Commit" : "Confirm");
if (MLME_IS_MESH(adapter)) {
rtw_mesh_sae_check_frames(adapter, buf, len, tx, alg, seq, status);
if (tx && (seq == 2) && (status == 0)) {
/* quere commit frame until external auth statue update */
psta = rtw_get_stainfo(pstapriv, GetAddr1Ptr(buf));
if (psta->pauth_frame) {
rtw_mfree(psta->pauth_frame, psta->auth_len);
psta->pauth_frame = NULL;
psta->auth_len = 0;
psta->pauth_frame = rtw_zmalloc(len);
_rtw_memcpy(psta->pauth_frame, buf, len);
psta->auth_len = len;
/* Needs to confirm with FW the value of REG_RX_BEACON_LENGTH */
u8 rtw_write_bcnlen_hdl(_adapter *padapter, u8 *pbuf)
struct write_bcnlen_param *parm = (struct write_bcnlen_param *)pbuf;
u16 bcn_len = parm->bcn_len;
rtw_write16(padapter, REG_RX_BEACON_LENGTH + 2, bcn_len);