rtl8192eu-linux-driver/core/rtw_mlme.c
Phillip Potter 2a467a7923 convert all rtw_zvmalloc calls to vzalloc calls
Convert all rtw_zvmalloc calls within the driver to use the existing
kernel vzalloc function, which has the same semantics. Also rewrite the
two places where it is mentioned in comments to say vzalloc, and remove
the redundant cast to struct adapter * in ./os_dep/usb_intf.c as vzalloc
returns void *.

The reason for the conversion is that rtw_zvmalloc is just a
preprocessor definition for _rtw_zvmalloc which itself is just an inline
wrapper around vmalloc which then zeroes the memory out. As vzalloc does
the same thing via usage of __GFP_ZERO, this code is redundant and can
subsequently be removed.

Link: https://lore.kernel.org/r/20210818234853.208448-5-phil@philpotter.co.uk
2021-10-11 15:59:59 +02:00

5352 lines
158 KiB
C

/******************************************************************************
*
* Copyright(c) 2007 - 2017 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_C_
#include <hal_data.h>
extern void indicate_wx_scan_complete_event(_adapter *padapter);
extern u8 rtw_do_join(_adapter *padapter);
void rtw_init_mlme_timer(_adapter *padapter)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
rtw_init_timer(&(pmlmepriv->assoc_timer), padapter, rtw_join_timeout_handler, padapter);
rtw_init_timer(&(pmlmepriv->scan_to_timer), padapter, rtw_scan_timeout_handler, padapter);
#ifdef CONFIG_SET_SCAN_DENY_TIMER
rtw_init_timer(&(pmlmepriv->set_scan_deny_timer), padapter, rtw_set_scan_deny_timer_hdl, padapter);
#endif
#ifdef RTK_DMP_PLATFORM
_init_workitem(&(pmlmepriv->Linkup_workitem), Linkup_workitem_callback, padapter);
_init_workitem(&(pmlmepriv->Linkdown_workitem), Linkdown_workitem_callback, padapter);
#endif
}
sint _rtw_init_mlme_priv(_adapter *padapter)
{
sint i;
u8 *pbuf;
struct wlan_network *pnetwork;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter);
sint res = _SUCCESS;
/* We don't need to memset padapter->XXX to zero, because adapter is allocated by vzalloc(). */
/* memset((u8 *)pmlmepriv, 0, sizeof(struct mlme_priv)); */
/*qos_priv*/
/*pmlmepriv->qospriv.qos_option = pregistrypriv->wmm_enable;*/
/*ht_priv*/
#ifdef CONFIG_80211N_HT
pmlmepriv->htpriv.ampdu_enable = _FALSE;/*set to disabled*/
#endif
pmlmepriv->nic_hdl = (u8 *)padapter;
pmlmepriv->pscanned = NULL;
init_fwstate(pmlmepriv, WIFI_STATION_STATE);
pmlmepriv->cur_network.network.InfrastructureMode = Ndis802_11AutoUnknown;
pmlmepriv->scan_mode = SCAN_ACTIVE; /* 1: active, 0: pasive. Maybe someday we should rename this varable to "active_mode" (Jeff) */
_rtw_spinlock_init(&(pmlmepriv->lock));
_rtw_init_queue(&(pmlmepriv->free_bss_pool));
_rtw_init_queue(&(pmlmepriv->scanned_queue));
set_scanned_network_val(pmlmepriv, 0);
memset(&pmlmepriv->assoc_ssid, 0, sizeof(NDIS_802_11_SSID));
if (padapter->registrypriv.max_bss_cnt != 0)
pmlmepriv->max_bss_cnt = padapter->registrypriv.max_bss_cnt;
else if (rfctl->max_chan_nums <= MAX_CHANNEL_NUM_2G)
pmlmepriv->max_bss_cnt = MAX_BSS_CNT;
else
pmlmepriv->max_bss_cnt = MAX_BSS_CNT + MAX_BSS_CNT;
pbuf = vzalloc(pmlmepriv->max_bss_cnt * (sizeof(struct wlan_network)));
if (pbuf == NULL) {
res = _FAIL;
goto exit;
}
pmlmepriv->free_bss_buf = pbuf;
pnetwork = (struct wlan_network *)pbuf;
for (i = 0; i < pmlmepriv->max_bss_cnt; i++) {
_rtw_init_listhead(&(pnetwork->list));
rtw_list_insert_tail(&(pnetwork->list), &(pmlmepriv->free_bss_pool.queue));
pnetwork++;
}
/* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
rtw_clear_scan_deny(padapter);
#ifdef CONFIG_ARP_KEEP_ALIVE
pmlmepriv->bGetGateway = 0;
pmlmepriv->GetGatewayTryCnt = 0;
#endif
#ifdef CONFIG_LAYER2_ROAMING
#define RTW_ROAM_SCAN_RESULT_EXP_MS (5*1000)
#define RTW_ROAM_RSSI_DIFF_TH 10
#define RTW_ROAM_SCAN_INTERVAL (5) /* 5*(2 second)*/
#define RTW_ROAM_RSSI_THRESHOLD 70
pmlmepriv->roam_flags = 0
| RTW_ROAM_ON_EXPIRED
#ifdef CONFIG_LAYER2_ROAMING_RESUME
| RTW_ROAM_ON_RESUME
#endif
#ifdef CONFIG_LAYER2_ROAMING_ACTIVE
| RTW_ROAM_ACTIVE
#endif
;
pmlmepriv->roam_scanr_exp_ms = RTW_ROAM_SCAN_RESULT_EXP_MS;
pmlmepriv->roam_rssi_diff_th = RTW_ROAM_RSSI_DIFF_TH;
pmlmepriv->roam_scan_int = RTW_ROAM_SCAN_INTERVAL;
pmlmepriv->roam_rssi_threshold = RTW_ROAM_RSSI_THRESHOLD;
pmlmepriv->need_to_roam = _FALSE;
pmlmepriv->last_roaming = rtw_get_current_time();
#endif /* CONFIG_LAYER2_ROAMING */
#ifdef CONFIG_RTW_80211R
rtw_ft_info_init(&pmlmepriv->ft_roam);
#endif
#ifdef CONFIG_LAYER2_ROAMING
#if defined(CONFIG_RTW_WNM) || defined(CONFIG_RTW_80211K)
rtw_roam_nb_info_init(padapter);
pmlmepriv->ch_cnt = 0;
#endif
#endif
rtw_init_mlme_timer(padapter);
exit:
return res;
}
void rtw_mfree_mlme_priv_lock(struct mlme_priv *pmlmepriv);
void rtw_mfree_mlme_priv_lock(struct mlme_priv *pmlmepriv)
{
}
static void rtw_free_mlme_ie_data(u8 **ppie, u32 *plen)
{
if (*ppie) {
rtw_mfree(*ppie, *plen);
*plen = 0;
*ppie = NULL;
}
}
void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv)
{
#if defined(CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME)
rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len);
rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len);
rtw_free_mlme_ie_data(&pmlmepriv->wps_beacon_ie, &pmlmepriv->wps_beacon_ie_len);
rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_req_ie, &pmlmepriv->wps_probe_req_ie_len);
rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_resp_ie, &pmlmepriv->wps_probe_resp_ie_len);
rtw_free_mlme_ie_data(&pmlmepriv->wps_assoc_resp_ie, &pmlmepriv->wps_assoc_resp_ie_len);
rtw_free_mlme_ie_data(&pmlmepriv->p2p_beacon_ie, &pmlmepriv->p2p_beacon_ie_len);
rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_req_ie, &pmlmepriv->p2p_probe_req_ie_len);
rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_resp_ie, &pmlmepriv->p2p_probe_resp_ie_len);
rtw_free_mlme_ie_data(&pmlmepriv->p2p_go_probe_resp_ie, &pmlmepriv->p2p_go_probe_resp_ie_len);
rtw_free_mlme_ie_data(&pmlmepriv->p2p_assoc_req_ie, &pmlmepriv->p2p_assoc_req_ie_len);
rtw_free_mlme_ie_data(&pmlmepriv->p2p_assoc_resp_ie, &pmlmepriv->p2p_assoc_resp_ie_len);
#endif
#if defined(CONFIG_WFD) && defined(CONFIG_IOCTL_CFG80211)
rtw_free_mlme_ie_data(&pmlmepriv->wfd_beacon_ie, &pmlmepriv->wfd_beacon_ie_len);
rtw_free_mlme_ie_data(&pmlmepriv->wfd_probe_req_ie, &pmlmepriv->wfd_probe_req_ie_len);
rtw_free_mlme_ie_data(&pmlmepriv->wfd_probe_resp_ie, &pmlmepriv->wfd_probe_resp_ie_len);
rtw_free_mlme_ie_data(&pmlmepriv->wfd_go_probe_resp_ie, &pmlmepriv->wfd_go_probe_resp_ie_len);
rtw_free_mlme_ie_data(&pmlmepriv->wfd_assoc_req_ie, &pmlmepriv->wfd_assoc_req_ie_len);
rtw_free_mlme_ie_data(&pmlmepriv->wfd_assoc_resp_ie, &pmlmepriv->wfd_assoc_resp_ie_len);
#endif
#ifdef CONFIG_RTW_80211R
rtw_free_mlme_ie_data(&pmlmepriv->auth_rsp, &pmlmepriv->auth_rsp_len);
#endif
}
#if defined(CONFIG_WFD) && defined(CONFIG_IOCTL_CFG80211)
int rtw_mlme_update_wfd_ie_data(struct mlme_priv *mlme, u8 type, u8 *ie, u32 ie_len)
{
_adapter *adapter = mlme_to_adapter(mlme);
struct wifi_display_info *wfd_info = &adapter->wfd_info;
u8 clear = 0;
u8 **t_ie = NULL;
u32 *t_ie_len = NULL;
int ret = _FAIL;
if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST))
goto success;
if (wfd_info->wfd_enable == _TRUE)
goto success; /* WFD IE is build by self */
if (!ie && !ie_len)
clear = 1;
else if (!ie || !ie_len) {
RTW_PRINT(FUNC_ADPT_FMT" type:%u, ie:%p, ie_len:%u"
, FUNC_ADPT_ARG(adapter), type, ie, ie_len);
rtw_warn_on(1);
goto exit;
}
switch (type) {
case MLME_BEACON_IE:
t_ie = &mlme->wfd_beacon_ie;
t_ie_len = &mlme->wfd_beacon_ie_len;
break;
case MLME_PROBE_REQ_IE:
t_ie = &mlme->wfd_probe_req_ie;
t_ie_len = &mlme->wfd_probe_req_ie_len;
break;
case MLME_PROBE_RESP_IE:
t_ie = &mlme->wfd_probe_resp_ie;
t_ie_len = &mlme->wfd_probe_resp_ie_len;
break;
case MLME_GO_PROBE_RESP_IE:
t_ie = &mlme->wfd_go_probe_resp_ie;
t_ie_len = &mlme->wfd_go_probe_resp_ie_len;
break;
case MLME_ASSOC_REQ_IE:
t_ie = &mlme->wfd_assoc_req_ie;
t_ie_len = &mlme->wfd_assoc_req_ie_len;
break;
case MLME_ASSOC_RESP_IE:
t_ie = &mlme->wfd_assoc_resp_ie;
t_ie_len = &mlme->wfd_assoc_resp_ie_len;
break;
default:
RTW_PRINT(FUNC_ADPT_FMT" unsupported type:%u"
, FUNC_ADPT_ARG(adapter), type);
rtw_warn_on(1);
goto exit;
}
if (*t_ie) {
u32 free_len = *t_ie_len;
*t_ie_len = 0;
rtw_mfree(*t_ie, free_len);
*t_ie = NULL;
}
if (!clear) {
*t_ie = rtw_malloc(ie_len);
if (*t_ie == NULL) {
RTW_ERR(FUNC_ADPT_FMT" type:%u, rtw_malloc() fail\n"
, FUNC_ADPT_ARG(adapter), type);
goto exit;
}
_rtw_memcpy(*t_ie, ie, ie_len);
*t_ie_len = ie_len;
}
if (*t_ie && *t_ie_len) {
u8 *attr_content;
u32 attr_contentlen = 0;
attr_content = rtw_get_wfd_attr_content(*t_ie, *t_ie_len, WFD_ATTR_DEVICE_INFO, NULL, &attr_contentlen);
if (attr_content && attr_contentlen) {
if (RTW_GET_BE16(attr_content + 2) != wfd_info->rtsp_ctrlport) {
wfd_info->rtsp_ctrlport = RTW_GET_BE16(attr_content + 2);
RTW_INFO(FUNC_ADPT_FMT" type:%u, RTSP CTRL port = %u\n"
, FUNC_ADPT_ARG(adapter), type, wfd_info->rtsp_ctrlport);
}
}
}
success:
ret = _SUCCESS;
exit:
return ret;
}
#endif /* defined(CONFIG_WFD) && defined(CONFIG_IOCTL_CFG80211) */
void _rtw_free_mlme_priv(struct mlme_priv *pmlmepriv)
{
_adapter *adapter = mlme_to_adapter(pmlmepriv);
if (NULL == pmlmepriv) {
rtw_warn_on(1);
goto exit;
}
rtw_free_mlme_priv_ie_data(pmlmepriv);
if (pmlmepriv) {
rtw_mfree_mlme_priv_lock(pmlmepriv);
vfree(pmlmepriv->free_bss_buf);
}
exit:
return;
}
sint _rtw_enqueue_network(_queue *queue, struct wlan_network *pnetwork)
{
_irqL irqL;
if (pnetwork == NULL)
goto exit;
_enter_critical_bh(&queue->lock, &irqL);
rtw_list_insert_tail(&pnetwork->list, &queue->queue);
_exit_critical_bh(&queue->lock, &irqL);
exit:
return _SUCCESS;
}
/*
struct wlan_network *_rtw_dequeue_network(_queue *queue)
{
_irqL irqL;
struct wlan_network *pnetwork;
_enter_critical_bh(&queue->lock, &irqL);
if (_rtw_queue_empty(queue) == _TRUE)
pnetwork = NULL;
else
{
pnetwork = LIST_CONTAINOR(get_next(&queue->queue), struct wlan_network, list);
rtw_list_delete(&(pnetwork->list));
}
_exit_critical_bh(&queue->lock, &irqL);
return pnetwork;
}
*/
struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv) /* (_queue *free_queue) */
{
_irqL irqL;
struct wlan_network *pnetwork;
_queue *free_queue = &pmlmepriv->free_bss_pool;
_list *plist = NULL;
_enter_critical_bh(&free_queue->lock, &irqL);
if (_rtw_queue_empty(free_queue) == _TRUE) {
pnetwork = NULL;
goto exit;
}
plist = get_next(&(free_queue->queue));
pnetwork = LIST_CONTAINOR(plist , struct wlan_network, list);
rtw_list_delete(&pnetwork->list);
pnetwork->network_type = 0;
pnetwork->fixed = _FALSE;
pnetwork->last_scanned = rtw_get_current_time();
#if defined(CONFIG_RTW_MESH) && CONFIG_RTW_MESH_ACNODE_PREVENT
pnetwork->acnode_stime = 0;
pnetwork->acnode_notify_etime = 0;
#endif
pnetwork->aid = 0;
pnetwork->join_res = 0;
pmlmepriv->num_of_scanned++;
exit:
_exit_critical_bh(&free_queue->lock, &irqL);
return pnetwork;
}
void _rtw_free_network(struct mlme_priv *pmlmepriv , struct wlan_network *pnetwork, u8 isfreeall)
{
u32 delta_time;
u32 lifetime = SCANQUEUE_LIFETIME;
_irqL irqL;
_queue *free_queue = &(pmlmepriv->free_bss_pool);
if (pnetwork == NULL)
goto exit;
if (pnetwork->fixed == _TRUE)
goto exit;
if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) ||
(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE))
lifetime = 1;
if (!isfreeall) {
delta_time = (u32) rtw_get_passing_time_ms(pnetwork->last_scanned);
if (delta_time < lifetime) /* unit:msec */
goto exit;
}
_enter_critical_bh(&free_queue->lock, &irqL);
rtw_list_delete(&(pnetwork->list));
rtw_list_insert_tail(&(pnetwork->list), &(free_queue->queue));
pmlmepriv->num_of_scanned--;
/* RTW_INFO("_rtw_free_network:SSID=%s\n", pnetwork->network.Ssid.Ssid); */
_exit_critical_bh(&free_queue->lock, &irqL);
exit:
return;
}
void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork)
{
_queue *free_queue = &(pmlmepriv->free_bss_pool);
if (pnetwork == NULL)
goto exit;
if (pnetwork->fixed == _TRUE)
goto exit;
/* _enter_critical(&free_queue->lock, &irqL); */
rtw_list_delete(&(pnetwork->list));
rtw_list_insert_tail(&(pnetwork->list), get_list_head(free_queue));
pmlmepriv->num_of_scanned--;
/* _exit_critical(&free_queue->lock, &irqL); */
exit:
return;
}
void _rtw_free_network_queue(_adapter *padapter, u8 isfreeall)
{
_irqL irqL;
_list *phead, *plist;
struct wlan_network *pnetwork;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
_queue *scanned_queue = &pmlmepriv->scanned_queue;
_enter_critical_bh(&scanned_queue->lock, &irqL);
phead = get_list_head(scanned_queue);
plist = get_next(phead);
while (rtw_end_of_queue_search(phead, plist) == _FALSE) {
pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
plist = get_next(plist);
_rtw_free_network(pmlmepriv, pnetwork, isfreeall);
}
_exit_critical_bh(&scanned_queue->lock, &irqL);
}
sint rtw_if_up(_adapter *padapter)
{
sint res;
if (RTW_CANNOT_RUN(padapter) ||
(check_fwstate(&padapter->mlmepriv, _FW_LINKED) == _FALSE)) {
res = _FALSE;
} else
res = _TRUE;
return res;
}
void rtw_generate_random_ibss(u8 *pibss)
{
*((u32 *)(&pibss[2])) = rtw_random32();
pibss[0] = 0x02; /* in ad-hoc mode local bit must set to 1 */
pibss[1] = 0x11;
pibss[2] = 0x87;
}
u8 *rtw_get_capability_from_ie(u8 *ie)
{
return ie + 8 + 2;
}
u16 rtw_get_capability(WLAN_BSSID_EX *bss)
{
u16 val;
_rtw_memcpy((u8 *)&val, rtw_get_capability_from_ie(bss->IEs), 2);
return le16_to_cpu(val);
}
u8 *rtw_get_timestampe_from_ie(u8 *ie)
{
return ie + 0;
}
u8 *rtw_get_beacon_interval_from_ie(u8 *ie)
{
return ie + 8;
}
int rtw_init_mlme_priv(_adapter *padapter) /* (struct mlme_priv *pmlmepriv) */
{
int res;
res = _rtw_init_mlme_priv(padapter);/* (pmlmepriv); */
return res;
}
void rtw_free_mlme_priv(struct mlme_priv *pmlmepriv)
{
_rtw_free_mlme_priv(pmlmepriv);
}
int rtw_enqueue_network(_queue *queue, struct wlan_network *pnetwork);
int rtw_enqueue_network(_queue *queue, struct wlan_network *pnetwork)
{
int res;
res = _rtw_enqueue_network(queue, pnetwork);
return res;
}
/*
static struct wlan_network *rtw_dequeue_network(_queue *queue)
{
struct wlan_network *pnetwork;
pnetwork = _rtw_dequeue_network(queue);
return pnetwork;
}
*/
struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv);
struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv) /* (_queue *free_queue) */
{
struct wlan_network *pnetwork;
pnetwork = _rtw_alloc_network(pmlmepriv);
return pnetwork;
}
void rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork, u8 is_freeall);
void rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork, u8 is_freeall)/* (struct wlan_network *pnetwork, _queue *free_queue) */
{
_rtw_free_network(pmlmepriv, pnetwork, is_freeall);
}
void rtw_free_network_nolock(_adapter *padapter, struct wlan_network *pnetwork);
void rtw_free_network_nolock(_adapter *padapter, struct wlan_network *pnetwork)
{
_rtw_free_network_nolock(&(padapter->mlmepriv), pnetwork);
#ifdef CONFIG_IOCTL_CFG80211
rtw_cfg80211_unlink_bss(padapter, pnetwork);
#endif /* CONFIG_IOCTL_CFG80211 */
}
void rtw_free_network_queue(_adapter *dev, u8 isfreeall)
{
_rtw_free_network_queue(dev, isfreeall);
}
struct wlan_network *_rtw_find_network(_queue *scanned_queue, const u8 *addr)
{
_list *phead, *plist;
struct wlan_network *pnetwork = NULL;
u8 zero_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
if (_rtw_memcmp(zero_addr, addr, ETH_ALEN)) {
pnetwork = NULL;
goto exit;
}
phead = get_list_head(scanned_queue);
plist = get_next(phead);
while (plist != phead) {
pnetwork = LIST_CONTAINOR(plist, struct wlan_network , list);
if (_rtw_memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN) == _TRUE)
break;
plist = get_next(plist);
}
if (plist == phead)
pnetwork = NULL;
exit:
return pnetwork;
}
struct wlan_network *rtw_find_network(_queue *scanned_queue, const u8 *addr)
{
struct wlan_network *pnetwork;
_irqL irqL;
_enter_critical_bh(&scanned_queue->lock, &irqL);
pnetwork = _rtw_find_network(scanned_queue, addr);
_exit_critical_bh(&scanned_queue->lock, &irqL);
return pnetwork;
}
int rtw_is_same_ibss(_adapter *adapter, struct wlan_network *pnetwork)
{
int ret = _TRUE;
struct security_priv *psecuritypriv = &adapter->securitypriv;
if ((psecuritypriv->dot11PrivacyAlgrthm != _NO_PRIVACY_) &&
(pnetwork->network.Privacy == 0))
ret = _FALSE;
else if ((psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_) &&
(pnetwork->network.Privacy == 1))
ret = _FALSE;
else
ret = _TRUE;
return ret;
}
inline int is_same_ess(WLAN_BSSID_EX *a, WLAN_BSSID_EX *b)
{
return (a->Ssid.SsidLength == b->Ssid.SsidLength)
&& _rtw_memcmp(a->Ssid.Ssid, b->Ssid.Ssid, a->Ssid.SsidLength) == _TRUE;
}
int is_same_network(WLAN_BSSID_EX *src, WLAN_BSSID_EX *dst, u8 feature)
{
u16 s_cap, d_cap;
if (rtw_bug_check(dst, src, &s_cap, &d_cap) == _FALSE)
return _FALSE;
_rtw_memcpy((u8 *)&s_cap, rtw_get_capability_from_ie(src->IEs), 2);
_rtw_memcpy((u8 *)&d_cap, rtw_get_capability_from_ie(dst->IEs), 2);
s_cap = le16_to_cpu(s_cap);
d_cap = le16_to_cpu(d_cap);
#ifdef CONFIG_P2P
if ((feature == 1) && /* 1: P2P supported */
(_rtw_memcmp(src->MacAddress, dst->MacAddress, ETH_ALEN) == _TRUE)
)
return _TRUE;
#endif
/* Wi-Fi driver doesn't consider the situation of BCN and ProbRsp sent from the same hidden AP,
* it considers these two packets are sent from different AP.
* Therefore, the scan queue may store two scan results of the same hidden AP, likes below.
*
* index bssid ch RSSI SdBm Noise age flag ssid
* 1 00:e0:4c:55:50:01 153 -73 -73 0 7044 [WPS][ESS] RTK5G
* 3 00:e0:4c:55:50:01 153 -73 -73 0 7044 [WPS][ESS]
*
* Original rules will compare Ssid, SsidLength, MacAddress, s_cap, d_cap at the same time.
* Wi-Fi driver will assume that the BCN and ProbRsp sent from the same hidden AP are the same network
* after we add an additional rule to compare SsidLength and Ssid.
* It means the scan queue will not store two scan results of the same hidden AP, it only store ProbRsp.
* For customer request.
*/
if (((_rtw_memcmp(src->MacAddress, dst->MacAddress, ETH_ALEN)) == _TRUE) &&
((s_cap & WLAN_CAPABILITY_IBSS) == (d_cap & WLAN_CAPABILITY_IBSS)) &&
((s_cap & WLAN_CAPABILITY_BSS) == (d_cap & WLAN_CAPABILITY_BSS))) {
if ((src->Ssid.SsidLength == dst->Ssid.SsidLength) &&
(((_rtw_memcmp(src->Ssid.Ssid, dst->Ssid.Ssid, src->Ssid.SsidLength)) == _TRUE) || //Case of normal AP
(is_all_null(src->Ssid.Ssid, src->Ssid.SsidLength) == _TRUE || is_all_null(dst->Ssid.Ssid, dst->Ssid.SsidLength) == _TRUE))) //Case of hidden AP
return _TRUE;
else if ((src->Ssid.SsidLength == 0 || dst->Ssid.SsidLength == 0)) //Case of hidden AP
return _TRUE;
else
return _FALSE;
} else {
return _FALSE;
}
}
struct wlan_network *_rtw_find_same_network(_queue *scanned_queue, struct wlan_network *network)
{
_list *phead, *plist;
struct wlan_network *found = NULL;
phead = get_list_head(scanned_queue);
plist = get_next(phead);
while (plist != phead) {
found = LIST_CONTAINOR(plist, struct wlan_network , list);
if (is_same_network(&network->network, &found->network, 0))
break;
plist = get_next(plist);
}
if (plist == phead)
found = NULL;
return found;
}
struct wlan_network *rtw_find_same_network(_queue *scanned_queue, struct wlan_network *network)
{
_irqL irqL;
struct wlan_network *found = NULL;
if (scanned_queue == NULL || network == NULL)
goto exit;
_enter_critical_bh(&scanned_queue->lock, &irqL);
found = _rtw_find_same_network(scanned_queue, network);
_exit_critical_bh(&scanned_queue->lock, &irqL);
exit:
return found;
}
struct wlan_network *rtw_get_oldest_wlan_network(_queue *scanned_queue)
{
_list *plist, *phead;
struct wlan_network *pwlan = NULL;
struct wlan_network *oldest = NULL;
phead = get_list_head(scanned_queue);
plist = get_next(phead);
while (1) {
if (rtw_end_of_queue_search(phead, plist) == _TRUE)
break;
pwlan = LIST_CONTAINOR(plist, struct wlan_network, list);
if (pwlan->fixed != _TRUE) {
if (oldest == NULL || rtw_time_after(oldest->last_scanned, pwlan->last_scanned))
oldest = pwlan;
}
plist = get_next(plist);
}
return oldest;
}
void update_network(WLAN_BSSID_EX *dst, WLAN_BSSID_EX *src,
_adapter *padapter, bool update_ie)
{
#if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) && 1
u8 ss_ori = dst->PhyInfo.SignalStrength;
u8 sq_ori = dst->PhyInfo.SignalQuality;
u8 ss_smp = src->PhyInfo.SignalStrength;
long rssi_smp = src->Rssi;
#endif
long rssi_ori = dst->Rssi;
u8 sq_smp = src->PhyInfo.SignalQuality;
u8 ss_final;
u8 sq_final;
long rssi_final;
#ifdef CONFIG_ANTENNA_DIVERSITY
rtw_hal_antdiv_rssi_compared(padapter, dst, src); /* this will update src.Rssi, need consider again */
#endif
#if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) && 1
if (strcmp(dst->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) {
RTW_INFO(FUNC_ADPT_FMT" %s("MAC_FMT", ch%u) ss_ori:%3u, sq_ori:%3u, rssi_ori:%3ld, ss_smp:%3u, sq_smp:%3u, rssi_smp:%3ld\n"
, FUNC_ADPT_ARG(padapter)
, src->Ssid.Ssid, MAC_ARG(src->MacAddress), src->Configuration.DSConfig
, ss_ori, sq_ori, rssi_ori
, ss_smp, sq_smp, rssi_smp
);
}
#endif
/* The rule below is 1/5 for sample value, 4/5 for history value */
if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network(&(padapter->mlmepriv.cur_network.network), src, 0)) {
/* Take the recvpriv's value for the connected AP*/
ss_final = padapter->recvpriv.signal_strength;
sq_final = padapter->recvpriv.signal_qual;
/* the rssi value here is undecorated, and will be used for antenna diversity */
if (sq_smp != 101) /* from the right channel */
rssi_final = (src->Rssi + dst->Rssi * 4) / 5;
else
rssi_final = rssi_ori;
} else {
if (sq_smp != 101) { /* from the right channel */
ss_final = ((u32)(src->PhyInfo.SignalStrength) + (u32)(dst->PhyInfo.SignalStrength) * 4) / 5;
sq_final = ((u32)(src->PhyInfo.SignalQuality) + (u32)(dst->PhyInfo.SignalQuality) * 4) / 5;
rssi_final = (src->Rssi + dst->Rssi * 4) / 5;
} else {
/* bss info not receving from the right channel, use the original RX signal infos */
ss_final = dst->PhyInfo.SignalStrength;
sq_final = dst->PhyInfo.SignalQuality;
rssi_final = dst->Rssi;
}
}
if (update_ie) {
dst->Reserved[0] = src->Reserved[0];
dst->Reserved[1] = src->Reserved[1];
_rtw_memcpy((u8 *)dst, (u8 *)src, get_WLAN_BSSID_EX_sz(src));
}
dst->PhyInfo.SignalStrength = ss_final;
dst->PhyInfo.SignalQuality = sq_final;
dst->Rssi = rssi_final;
#if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) && 1
if (strcmp(dst->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) {
RTW_INFO(FUNC_ADPT_FMT" %s("MAC_FMT"), SignalStrength:%u, SignalQuality:%u, RawRSSI:%ld\n"
, FUNC_ADPT_ARG(padapter)
, dst->Ssid.Ssid, MAC_ARG(dst->MacAddress), dst->PhyInfo.SignalStrength, dst->PhyInfo.SignalQuality, dst->Rssi);
}
#endif
#if 0 /* old codes, may be useful one day...
* RTW_INFO("update_network: rssi=0x%lx dst->Rssi=%d ,dst->Rssi=0x%lx , src->Rssi=0x%lx",(dst->Rssi+src->Rssi)/2,dst->Rssi,dst->Rssi,src->Rssi); */
if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network(&(padapter->mlmepriv.cur_network.network), src)) {
/* RTW_INFO("b:ssid=%s update_network: src->rssi=0x%d padapter->recvpriv.ui_rssi=%d\n",src->Ssid.Ssid,src->Rssi,padapter->recvpriv.signal); */
if (padapter->recvpriv.signal_qual_data.total_num++ >= PHY_LINKQUALITY_SLID_WIN_MAX) {
padapter->recvpriv.signal_qual_data.total_num = PHY_LINKQUALITY_SLID_WIN_MAX;
last_evm = padapter->recvpriv.signal_qual_data.elements[padapter->recvpriv.signal_qual_data.index];
padapter->recvpriv.signal_qual_data.total_val -= last_evm;
}
padapter->recvpriv.signal_qual_data.total_val += query_rx_pwr_percentage(src->Rssi);
padapter->recvpriv.signal_qual_data.elements[padapter->recvpriv.signal_qual_data.index++] = query_rx_pwr_percentage(src->Rssi);
if (padapter->recvpriv.signal_qual_data.index >= PHY_LINKQUALITY_SLID_WIN_MAX)
padapter->recvpriv.signal_qual_data.index = 0;
/* RTW_INFO("Total SQ=%d pattrib->signal_qual= %d\n", padapter->recvpriv.signal_qual_data.total_val, src->Rssi); */
/* <1> Showed on UI for user,in percentage. */
tmpVal = padapter->recvpriv.signal_qual_data.total_val / padapter->recvpriv.signal_qual_data.total_num;
padapter->recvpriv.signal = (u8)tmpVal; /* Link quality */
src->Rssi = translate_percentage_to_dbm(padapter->recvpriv.signal) ;
} else {
/* RTW_INFO("ELSE:ssid=%s update_network: src->rssi=0x%d dst->rssi=%d\n",src->Ssid.Ssid,src->Rssi,dst->Rssi); */
src->Rssi = (src->Rssi + dst->Rssi) / 2; /* dBM */
}
/* RTW_INFO("a:update_network: src->rssi=0x%d padapter->recvpriv.ui_rssi=%d\n",src->Rssi,padapter->recvpriv.signal); */
#endif
}
static void update_current_network(_adapter *adapter, WLAN_BSSID_EX *pnetwork)
{
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
rtw_bug_check(&(pmlmepriv->cur_network.network),
&(pmlmepriv->cur_network.network),
&(pmlmepriv->cur_network.network),
&(pmlmepriv->cur_network.network));
if ((check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) && (is_same_network(&(pmlmepriv->cur_network.network), pnetwork, 0))) {
/* if(pmlmepriv->cur_network.network.IELength<= pnetwork->IELength) */
{
update_network(&(pmlmepriv->cur_network.network), pnetwork, adapter, _TRUE);
rtw_update_protection(adapter, (pmlmepriv->cur_network.network.IEs) + sizeof(NDIS_802_11_FIXED_IEs),
pmlmepriv->cur_network.network.IELength);
}
}
}
/*
Caller must hold pmlmepriv->lock first.
*/
bool rtw_update_scanned_network(_adapter *adapter, WLAN_BSSID_EX *target)
{
_irqL irqL;
_list *plist, *phead;
ULONG bssid_ex_sz;
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
#ifdef CONFIG_P2P
struct wifidirect_info *pwdinfo = &(adapter->wdinfo);
#endif /* CONFIG_P2P */
_queue *queue = &(pmlmepriv->scanned_queue);
struct wlan_network *pnetwork = NULL;
struct wlan_network *choice = NULL;
int target_find = 0;
u8 feature = 0;
bool update_ie = _FALSE;
_enter_critical_bh(&queue->lock, &irqL);
phead = get_list_head(queue);
plist = get_next(phead);
#if 0
RTW_INFO("%s => ssid:%s , rssi:%ld , ss:%d\n",
__func__, target->Ssid.Ssid, target->Rssi, target->PhyInfo.SignalStrength);
#endif
#ifdef CONFIG_P2P
if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
feature = 1; /* p2p enable */
#endif
while (1) {
if (rtw_end_of_queue_search(phead, plist) == _TRUE)
break;
pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
rtw_bug_check(pnetwork, pnetwork, pnetwork, pnetwork);
#ifdef CONFIG_P2P
if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) &&
(_rtw_memcmp(pnetwork->network.MacAddress, target->MacAddress, ETH_ALEN) == _TRUE)) {
target_find = 1;
break;
}
#endif
if (is_same_network(&(pnetwork->network), target, feature)) {
target_find = 1;
break;
}
if (rtw_roam_flags(adapter)) {
/* TODO: don't select netowrk in the same ess as choice if it's new enough*/
}
if (pnetwork->fixed) {
plist = get_next(plist);
continue;
}
#ifdef CONFIG_RSSI_PRIORITY
if ((choice == NULL) || (pnetwork->network.PhyInfo.SignalStrength < choice->network.PhyInfo.SignalStrength))
#ifdef CONFIG_RTW_MESH
if (!MLME_IS_MESH(adapter) || !MLME_IS_ASOC(adapter)
|| !rtw_bss_is_same_mbss(&pmlmepriv->cur_network.network, &pnetwork->network))
#endif
choice = pnetwork;
#else
if (choice == NULL || rtw_time_after(choice->last_scanned, pnetwork->last_scanned))
#ifdef CONFIG_RTW_MESH
if (!MLME_IS_MESH(adapter) || !MLME_IS_ASOC(adapter)
|| !rtw_bss_is_same_mbss(&pmlmepriv->cur_network.network, &pnetwork->network))
#endif
choice = pnetwork;
#endif
plist = get_next(plist);
}
/* If we didn't find a match, then get a new network slot to initialize
* with this beacon's information */
/* if (rtw_end_of_queue_search(phead,plist)== _TRUE) { */
if (!target_find) {
if (_rtw_queue_empty(&(pmlmepriv->free_bss_pool)) == _TRUE) {
/* If there are no more slots, expire the choice */
/* list_del_init(&choice->list); */
pnetwork = choice;
if (pnetwork == NULL)
goto unlock_scan_queue;
#ifdef CONFIG_RSSI_PRIORITY
RTW_DBG("%s => ssid:%s ,bssid:"MAC_FMT" will be deleted from scanned_queue (rssi:%ld , ss:%d)\n",
__func__, pnetwork->network.Ssid.Ssid, MAC_ARG(pnetwork->network.MacAddress), pnetwork->network.Rssi, pnetwork->network.PhyInfo.SignalStrength);
#else
RTW_DBG("%s => ssid:%s ,bssid:"MAC_FMT" will be deleted from scanned_queue\n",
__func__, pnetwork->network.Ssid.Ssid, MAC_ARG(pnetwork->network.MacAddress));
#endif
#ifdef CONFIG_ANTENNA_DIVERSITY
rtw_hal_get_odm_var(adapter, HAL_ODM_ANTDIV_SELECT, &(target->PhyInfo.Optimum_antenna), NULL);
#endif
_rtw_memcpy(&(pnetwork->network), target, get_WLAN_BSSID_EX_sz(target));
/* pnetwork->last_scanned = rtw_get_current_time(); */
/* variable initialize */
pnetwork->fixed = _FALSE;
pnetwork->last_scanned = rtw_get_current_time();
#if defined(CONFIG_RTW_MESH) && CONFIG_RTW_MESH_ACNODE_PREVENT
pnetwork->acnode_stime = 0;
pnetwork->acnode_notify_etime = 0;
#endif
pnetwork->network_type = 0;
pnetwork->aid = 0;
pnetwork->join_res = 0;
/* bss info not receving from the right channel */
if (pnetwork->network.PhyInfo.SignalQuality == 101)
pnetwork->network.PhyInfo.SignalQuality = 0;
} else {
/* Otherwise just pull from the free list */
pnetwork = rtw_alloc_network(pmlmepriv); /* will update scan_time */
if (pnetwork == NULL)
goto unlock_scan_queue;
bssid_ex_sz = get_WLAN_BSSID_EX_sz(target);
target->Length = bssid_ex_sz;
#ifdef CONFIG_ANTENNA_DIVERSITY
rtw_hal_get_odm_var(adapter, HAL_ODM_ANTDIV_SELECT, &(target->PhyInfo.Optimum_antenna), NULL);
#endif
_rtw_memcpy(&(pnetwork->network), target, bssid_ex_sz);
pnetwork->last_scanned = rtw_get_current_time();
/* bss info not receving from the right channel */
if (pnetwork->network.PhyInfo.SignalQuality == 101)
pnetwork->network.PhyInfo.SignalQuality = 0;
rtw_list_insert_tail(&(pnetwork->list), &(queue->queue));
}
} else {
/* we have an entry and we are going to update it. But this entry may
* be already expired. In this case we do the same as we found a new
* net and call the new_net handler
*/
#if defined(CONFIG_RTW_MESH) && CONFIG_RTW_MESH_ACNODE_PREVENT
systime last_scanned = pnetwork->last_scanned;
#endif
pnetwork->last_scanned = rtw_get_current_time();
/* target.Reserved[0]==BSS_TYPE_BCN, means that scanned network is a bcn frame. */
if ((pnetwork->network.IELength > target->IELength) && (target->Reserved[0] == BSS_TYPE_BCN))
update_ie = _FALSE;
if (MLME_IS_MESH(adapter)
/* probe resp(3) > beacon(1) > probe req(2) */
|| (target->Reserved[0] != BSS_TYPE_PROB_REQ
&& target->Reserved[0] >= pnetwork->network.Reserved[0])
)
update_ie = _TRUE;
else
update_ie = _FALSE;
#if defined(CONFIG_RTW_MESH) && CONFIG_RTW_MESH_ACNODE_PREVENT
if (!MLME_IS_MESH(adapter) || !MLME_IS_ASOC(adapter)
|| pnetwork->network.Configuration.DSConfig != target->Configuration.DSConfig
|| rtw_get_passing_time_ms(last_scanned) > adapter->mesh_cfg.peer_sel_policy.scanr_exp_ms
|| !rtw_bss_is_same_mbss(&pnetwork->network, target)
) {
pnetwork->acnode_stime = 0;
pnetwork->acnode_notify_etime = 0;
}
#endif
update_network(&(pnetwork->network), target, adapter, update_ie);
}
#if defined(CONFIG_RTW_MESH) && CONFIG_RTW_MESH_ACNODE_PREVENT
if (MLME_IS_MESH(adapter) && MLME_IS_ASOC(adapter))
rtw_mesh_update_scanned_acnode_status(adapter, pnetwork);
#endif
unlock_scan_queue:
_exit_critical_bh(&queue->lock, &irqL);
#ifdef CONFIG_RTW_MESH
if (pnetwork && MLME_IS_MESH(adapter)
&& check_fwstate(pmlmepriv, WIFI_ASOC_STATE)
&& !check_fwstate(pmlmepriv, WIFI_SITE_MONITOR)
)
rtw_chk_candidate_peer_notify(adapter, pnetwork);
#endif
return update_ie;
}
void rtw_add_network(_adapter *adapter, WLAN_BSSID_EX *pnetwork);
void rtw_add_network(_adapter *adapter, WLAN_BSSID_EX *pnetwork)
{
bool update_ie;
/* _queue *queue = &(pmlmepriv->scanned_queue); */
/* _enter_critical_bh(&queue->lock, &irqL); */
#if defined(CONFIG_P2P) && defined(CONFIG_P2P_REMOVE_GROUP_INFO)
if (adapter->registrypriv.wifi_spec == 0)
rtw_bss_ex_del_p2p_attr(pnetwork, P2P_ATTR_GROUP_INFO);
#endif
if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST))
rtw_bss_ex_del_wfd_ie(pnetwork);
/* Wi-Fi driver will update the current network if the scan result of the connected AP be updated by scan. */
update_ie = rtw_update_scanned_network(adapter, pnetwork);
if (update_ie)
update_current_network(adapter, pnetwork);
/* _exit_critical_bh(&queue->lock, &irqL); */
}
/* select the desired network based on the capability of the (i)bss.
* check items: (1) security
* (2) network_type
* (3) WMM
* (4) HT
* (5) others */
int rtw_is_desired_network(_adapter *adapter, struct wlan_network *pnetwork);
int rtw_is_desired_network(_adapter *adapter, struct wlan_network *pnetwork)
{
struct security_priv *psecuritypriv = &adapter->securitypriv;
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
u32 desired_encmode;
u32 privacy;
/* u8 wps_ie[512]; */
uint wps_ielen;
int bselected = _TRUE;
desired_encmode = psecuritypriv->ndisencryptstatus;
privacy = pnetwork->network.Privacy;
if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
if (rtw_get_wps_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, pnetwork->network.IELength - _FIXED_IE_LENGTH_, NULL, &wps_ielen) != NULL)
return _TRUE;
else
return _FALSE;
}
if (adapter->registrypriv.wifi_spec == 1) { /* for correct flow of 8021X to do.... */
u8 *p = NULL;
uint ie_len = 0;
if ((desired_encmode == Ndis802_11EncryptionDisabled) && (privacy != 0))
bselected = _FALSE;
if (psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPA2PSK) {
p = rtw_get_ie(pnetwork->network.IEs + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pnetwork->network.IELength - _BEACON_IE_OFFSET_));
if (p && ie_len > 0)
bselected = _TRUE;
else
bselected = _FALSE;
}
}
if ((desired_encmode != Ndis802_11EncryptionDisabled) && (privacy == 0)) {
RTW_INFO("desired_encmode: %d, privacy: %d\n", desired_encmode, privacy);
bselected = _FALSE;
}
if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) {
if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode)
bselected = _FALSE;
}
return bselected;
}
/* TODO: Perry : For Power Management */
void rtw_atimdone_event_callback(_adapter *adapter , u8 *pbuf)
{
return;
}
void rtw_survey_event_callback(_adapter *adapter, u8 *pbuf)
{
_irqL irqL;
u32 len;
WLAN_BSSID_EX *pnetwork;
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
pnetwork = (WLAN_BSSID_EX *)pbuf;
#ifdef CONFIG_RTL8712
/* endian_convert */
pnetwork->Length = le32_to_cpu(pnetwork->Length);
pnetwork->Ssid.SsidLength = le32_to_cpu(pnetwork->Ssid.SsidLength);
pnetwork->Privacy = le32_to_cpu(pnetwork->Privacy);
pnetwork->Rssi = le32_to_cpu(pnetwork->Rssi);
pnetwork->NetworkTypeInUse = le32_to_cpu(pnetwork->NetworkTypeInUse);
pnetwork->Configuration.ATIMWindow = le32_to_cpu(pnetwork->Configuration.ATIMWindow);
pnetwork->Configuration.BeaconPeriod = le32_to_cpu(pnetwork->Configuration.BeaconPeriod);
pnetwork->Configuration.DSConfig = le32_to_cpu(pnetwork->Configuration.DSConfig);
pnetwork->Configuration.FHConfig.DwellTime = le32_to_cpu(pnetwork->Configuration.FHConfig.DwellTime);
pnetwork->Configuration.FHConfig.HopPattern = le32_to_cpu(pnetwork->Configuration.FHConfig.HopPattern);
pnetwork->Configuration.FHConfig.HopSet = le32_to_cpu(pnetwork->Configuration.FHConfig.HopSet);
pnetwork->Configuration.FHConfig.Length = le32_to_cpu(pnetwork->Configuration.FHConfig.Length);
pnetwork->Configuration.Length = le32_to_cpu(pnetwork->Configuration.Length);
pnetwork->InfrastructureMode = le32_to_cpu(pnetwork->InfrastructureMode);
pnetwork->IELength = le32_to_cpu(pnetwork->IELength);
#endif
len = get_WLAN_BSSID_EX_sz(pnetwork);
if (len > (sizeof(WLAN_BSSID_EX))) {
return;
}
_enter_critical_bh(&pmlmepriv->lock, &irqL);
/* update IBSS_network 's timestamp */
if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == _TRUE) {
if (_rtw_memcmp(&(pmlmepriv->cur_network.network.MacAddress), pnetwork->MacAddress, ETH_ALEN)) {
struct wlan_network *ibss_wlan = NULL;
_irqL irqL;
_rtw_memcpy(pmlmepriv->cur_network.network.IEs, pnetwork->IEs, 8);
_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
ibss_wlan = _rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->MacAddress);
if (ibss_wlan) {
_rtw_memcpy(ibss_wlan->network.IEs , pnetwork->IEs, 8);
_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
goto exit;
}
_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
}
}
/* lock pmlmepriv->lock when you accessing network_q */
if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == _FALSE) {
if (pnetwork->Ssid.Ssid[0] == 0)
pnetwork->Ssid.SsidLength = 0;
rtw_add_network(adapter, pnetwork);
}
exit:
_exit_critical_bh(&pmlmepriv->lock, &irqL);
return;
}
void rtw_surveydone_event_callback(_adapter *adapter, u8 *pbuf)
{
_irqL irqL;
struct sitesurvey_parm parm;
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
#ifdef CONFIG_RTW_80211R
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
#endif
#ifdef CONFIG_MLME_EXT
mlmeext_surveydone_event_callback(adapter);
#endif
_enter_critical_bh(&pmlmepriv->lock, &irqL);
if (pmlmepriv->wps_probe_req_ie) {
u32 free_len = pmlmepriv->wps_probe_req_ie_len;
pmlmepriv->wps_probe_req_ie_len = 0;
rtw_mfree(pmlmepriv->wps_probe_req_ie, free_len);
pmlmepriv->wps_probe_req_ie = NULL;
}
if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _FALSE) {
RTW_INFO(FUNC_ADPT_FMT" fw_state:0x%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv));
/* rtw_warn_on(1); */
}
_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
_exit_critical_bh(&pmlmepriv->lock, &irqL);
_cancel_timer_ex(&pmlmepriv->scan_to_timer);
_enter_critical_bh(&pmlmepriv->lock, &irqL);
#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS
rtw_set_signal_stat_timer(&adapter->recvpriv);
#endif
if (pmlmepriv->to_join == _TRUE) {
if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE)) {
if (check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE) {
set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
if (rtw_select_and_join_from_scanned_queue(pmlmepriv) == _SUCCESS)
_set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT);
else {
WLAN_BSSID_EX *pdev_network = &(adapter->registrypriv.dev_network);
u8 *pibss = adapter->registrypriv.dev_network.MacAddress;
/* pmlmepriv->fw_state ^= _FW_UNDER_SURVEY; */ /* because don't set assoc_timer */
_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
memset(&pdev_network->Ssid, 0, sizeof(NDIS_802_11_SSID));
_rtw_memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(NDIS_802_11_SSID));
rtw_update_registrypriv_dev_network(adapter);
rtw_generate_random_ibss(pibss);
/*pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;*/
init_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
if (rtw_create_ibss_cmd(adapter, 0) != _SUCCESS)
RTW_ERR("rtw_create_ibss_cmd FAIL\n");
pmlmepriv->to_join = _FALSE;
}
}
} else {
int s_ret;
set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
pmlmepriv->to_join = _FALSE;
s_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv);
if (_SUCCESS == s_ret)
_set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT);
else if (s_ret == 2) { /* there is no need to wait for join */
_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
rtw_indicate_connect(adapter);
} else {
RTW_INFO("try_to_join, but select scanning queue fail, to_roam:%d\n", rtw_to_roam(adapter));
if (rtw_to_roam(adapter) != 0) {
u8 ssc_chk = rtw_sitesurvey_condition_check(adapter, _FALSE);
rtw_init_sitesurvey_parm(adapter, &parm);
_rtw_memcpy(&parm.ssid[0], &pmlmepriv->assoc_ssid, sizeof(NDIS_802_11_SSID));
parm.ssid_num = 1;
if (rtw_dec_to_roam(adapter) == 0
|| (ssc_chk != SS_ALLOW && ssc_chk != SS_DENY_BUSY_TRAFFIC)
|| _SUCCESS != rtw_sitesurvey_cmd(adapter, &parm)
) {
rtw_set_to_roam(adapter, 0);
#ifdef CONFIG_INTEL_WIDI
if (adapter->mlmepriv.widi_state == INTEL_WIDI_STATE_ROAMING) {
memset(pmlmepriv->sa_ext, 0x00, L2SDTA_SERVICE_VE_LEN);
intel_widi_wk_cmd(adapter, INTEL_WIDI_LISTEN_WK, NULL, 0);
RTW_INFO("change to widi listen\n");
}
#endif /* CONFIG_INTEL_WIDI */
rtw_free_assoc_resources(adapter, _TRUE);
rtw_indicate_disconnect(adapter, 0, _FALSE);
} else
pmlmepriv->to_join = _TRUE;
} else
rtw_indicate_disconnect(adapter, 0, _FALSE);
_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
}
}
} else {
if (rtw_chk_roam_flags(adapter, RTW_ROAM_ACTIVE)) {
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)
&& check_fwstate(pmlmepriv, _FW_LINKED)) {
if (rtw_select_roaming_candidate(pmlmepriv) == _SUCCESS) {
#ifdef CONFIG_RTW_80211R
rtw_ft_start_roam(adapter,
(u8 *)pmlmepriv->roam_network->network.MacAddress);
#else
receive_disconnect(adapter, pmlmepriv->cur_network.network.MacAddress
, WLAN_REASON_ACTIVE_ROAM, _FALSE);
#endif
}
}
}
}
/* RTW_INFO("scan complete in %dms\n",rtw_get_passing_time_ms(pmlmepriv->scan_start_time)); */
_exit_critical_bh(&pmlmepriv->lock, &irqL);
#ifdef CONFIG_P2P_PS
if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
p2p_ps_wk_cmd(adapter, P2P_PS_SCAN_DONE, 0);
#endif /* CONFIG_P2P_PS */
rtw_mi_os_xmit_schedule(adapter);
#ifdef CONFIG_DRVEXT_MODULE_WSC
drvext_surveydone_callback(&adapter->drvextpriv);
#endif
#ifdef DBG_CONFIG_ERROR_DETECT
{
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
if (pmlmeext->sitesurvey_res.bss_cnt == 0) {
/* rtw_hal_sreset_reset(adapter); */
}
}
#endif
#ifdef CONFIG_IOCTL_CFG80211
rtw_cfg80211_surveydone_event_callback(adapter);
#endif /* CONFIG_IOCTL_CFG80211 */
rtw_indicate_scan_done(adapter, _FALSE);
#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_IOCTL_CFG80211)
rtw_cfg80211_indicate_scan_done_for_buddy(adapter, _FALSE);
#endif
#ifdef CONFIG_RTW_MESH
#if CONFIG_RTW_MESH_OFFCH_CAND
if (rtw_mesh_offch_candidate_accepted(adapter)) {
u8 ch;
ch = rtw_mesh_select_operating_ch(adapter);
if (ch && pmlmepriv->cur_network.network.Configuration.DSConfig != ch) {
u8 ifbmp = rtw_mi_get_ap_mesh_ifbmp(adapter);
if (ifbmp) {
/* switch to selected channel */
rtw_change_bss_chbw_cmd(adapter, RTW_CMDF_DIRECTLY, ifbmp, 0, ch, REQ_BW_ORI, REQ_OFFSET_NONE);
issue_probereq_ex(adapter, &pmlmepriv->cur_network.network.mesh_id, NULL, 0, 0, 0, 0);
} else
rtw_warn_on(1);
}
}
#endif
#endif /* CONFIG_RTW_MESH */
}
u8 _rtw_sitesurvey_condition_check(const char *caller, _adapter *adapter, bool check_sc_interval)
{
u8 ss_condition = SS_ALLOW;
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
#ifdef DBG_LA_MODE
struct registry_priv *registry_par = &adapter->registrypriv;
#endif
#ifdef CONFIG_MP_INCLUDED
if (rtw_mp_mode_check(adapter)) {
RTW_INFO("%s ("ADPT_FMT") MP mode block Scan request\n", caller, ADPT_ARG(adapter));
ss_condition = SS_DENY_MP_MODE;
goto _exit;
}
#endif
#ifdef DBG_LA_MODE
if(registry_par->la_mode_en == 1 && MLME_IS_ASOC(adapter)) {
RTW_INFO("%s ("ADPT_FMT") LA debug mode block Scan request\n", caller, ADPT_ARG(adapter));
ss_condition = SS_DENY_LA_MODE;
goto _exit;
}
#endif
#ifdef CONFIG_RTW_REPEATER_SON
if (adapter->rtw_rson_scanstage == RSON_SCAN_PROCESS) {
RTW_INFO("%s ("ADPT_FMT") blocking scan for under rson scanning process\n", caller, ADPT_ARG(adapter));
ss_condition = SS_DENY_RSON_SCANING;
goto _exit;
}
#endif
#ifdef CONFIG_IOCTL_CFG80211
if (adapter_wdev_data(adapter)->block_scan == _TRUE) {
RTW_INFO("%s ("ADPT_FMT") wdev_priv.block_scan is set\n", caller, ADPT_ARG(adapter));
ss_condition = SS_DENY_BLOCK_SCAN;
goto _exit;
}
#endif
if (adapter_to_dvobj(adapter)->scan_deny == _TRUE) {
RTW_INFO("%s ("ADPT_FMT") tpt mode, scan deny!\n", caller, ADPT_ARG(adapter));
ss_condition = SS_DENY_BLOCK_SCAN;
goto _exit;
}
if (rtw_is_scan_deny(adapter)) {
RTW_INFO("%s ("ADPT_FMT") : scan deny\n", caller, ADPT_ARG(adapter));
ss_condition = SS_DENY_BY_DRV;
goto _exit;
}
if (check_fwstate(pmlmepriv, WIFI_AP_STATE)){
if(check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
RTW_INFO("%s ("ADPT_FMT") : scan abort!! AP mode process WPS\n", caller, ADPT_ARG(adapter));
ss_condition = SS_DENY_SELF_AP_UNDER_WPS;
goto _exit;
} else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE) {
RTW_INFO("%s ("ADPT_FMT") : scan abort!!AP mode under linking (fwstate=0x%x)\n",
caller, ADPT_ARG(adapter), pmlmepriv->fw_state);
ss_condition = SS_DENY_SELF_AP_UNDER_LINKING;
goto _exit;
} else if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) {
RTW_INFO("%s ("ADPT_FMT") : scan abort!!AP mode under survey (fwstate=0x%x)\n",
caller, ADPT_ARG(adapter), pmlmepriv->fw_state);
ss_condition = SS_DENY_SELF_AP_UNDER_SURVEY;
goto _exit;
}
} else {
if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE) {
RTW_INFO("%s ("ADPT_FMT") : scan abort!!STA mode under linking (fwstate=0x%x)\n",
caller, ADPT_ARG(adapter), pmlmepriv->fw_state);
ss_condition = SS_DENY_SELF_STA_UNDER_LINKING;
goto _exit;
} else if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) {
RTW_INFO("%s ("ADPT_FMT") : scan abort!!STA mode under survey (fwstate=0x%x)\n",
caller, ADPT_ARG(adapter), pmlmepriv->fw_state);
ss_condition = SS_DENY_SELF_STA_UNDER_SURVEY;
goto _exit;
}
}
#ifdef CONFIG_CONCURRENT_MODE
if (rtw_mi_buddy_check_fwstate(adapter, _FW_UNDER_LINKING | WIFI_UNDER_WPS)) {
RTW_INFO("%s ("ADPT_FMT") : scan abort!! buddy_intf under linking or wps\n", caller, ADPT_ARG(adapter));
ss_condition = SS_DENY_BUDDY_UNDER_LINK_WPS;
goto _exit;
} else if (rtw_mi_buddy_check_fwstate(adapter, _FW_UNDER_SURVEY)) {
RTW_INFO("%s ("ADPT_FMT") : scan abort!! buddy_intf under survey\n", caller, ADPT_ARG(adapter));
ss_condition = SS_DENY_BUDDY_UNDER_SURVEY;
goto _exit;
}
#endif /* CONFIG_CONCURRENT_MODE */
if (pmlmepriv->LinkDetectInfo.bBusyTraffic == _TRUE) {
RTW_INFO("%s ("ADPT_FMT") : scan abort!! BusyTraffic\n",
caller, ADPT_ARG(adapter));
ss_condition = SS_DENY_BUSY_TRAFFIC;
goto _exit;
}
/*
* Rule for Android.
* If scan interval > BUSY_TRAFFIC_SCAN_DENY_PERIOD,
* it is a periodical background scan.
* Skip background scan when other interface is busy.
*/
if ((rtw_get_passing_time_ms(pmlmepriv->lastscantime) > BUSY_TRAFFIC_SCAN_DENY_PERIOD)
&& rtw_mi_buddy_busy_traffic_check(adapter, _FALSE)) {
RTW_INFO("%s ("ADPT_FMT") : scan abort!! others BusyTraffic\n",
caller, ADPT_ARG(adapter));
ss_condition = SS_DENY_BUSY_TRAFFIC;
goto _exit;
}
_exit :
return ss_condition;
}
void rtw_dummy_event_callback(_adapter *adapter , u8 *pbuf)
{
}
void rtw_fwdbg_event_callback(_adapter *adapter , u8 *pbuf)
{
}
static void free_scanqueue(struct mlme_priv *pmlmepriv)
{
_irqL irqL, irqL0;
_queue *free_queue = &pmlmepriv->free_bss_pool;
_queue *scan_queue = &pmlmepriv->scanned_queue;
_list *plist, *phead, *ptemp;
_enter_critical_bh(&scan_queue->lock, &irqL0);
_enter_critical_bh(&free_queue->lock, &irqL);
phead = get_list_head(scan_queue);
plist = get_next(phead);
while (plist != phead) {
ptemp = get_next(plist);
rtw_list_delete(plist);
rtw_list_insert_tail(plist, &free_queue->queue);
plist = ptemp;
pmlmepriv->num_of_scanned--;
}
_exit_critical_bh(&free_queue->lock, &irqL);
_exit_critical_bh(&scan_queue->lock, &irqL0);
}
void rtw_reset_rx_info(_adapter *adapter)
{
struct recv_priv *precvpriv = &adapter->recvpriv;
precvpriv->dbg_rx_ampdu_drop_count = 0;
precvpriv->dbg_rx_ampdu_forced_indicate_count = 0;
precvpriv->dbg_rx_ampdu_loss_count = 0;
precvpriv->dbg_rx_dup_mgt_frame_drop_count = 0;
precvpriv->dbg_rx_ampdu_window_shift_cnt = 0;
precvpriv->dbg_rx_drop_count = 0;
precvpriv->dbg_rx_conflic_mac_addr_cnt = 0;
}
/*
*rtw_free_assoc_resources: the caller has to lock pmlmepriv->lock
*/
void rtw_free_assoc_resources(_adapter *adapter, u8 lock_scanned_queue)
{
_irqL irqL;
struct wlan_network *pwlan = NULL;
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
struct wlan_network *tgt_network = &pmlmepriv->cur_network;
#ifdef CONFIG_TDLS
struct tdls_info *ptdlsinfo = &adapter->tdlsinfo;
#endif /* CONFIG_TDLS */
RTW_INFO("%s-"ADPT_FMT" tgt_network MacAddress=" MAC_FMT" ssid=%s\n",
__func__, ADPT_ARG(adapter), MAC_ARG(tgt_network->network.MacAddress), tgt_network->network.Ssid.Ssid);
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
struct sta_info *psta;
psta = rtw_get_stainfo(&adapter->stapriv, tgt_network->network.MacAddress);
#ifdef CONFIG_TDLS
rtw_free_all_tdls_sta(adapter, _TRUE);
rtw_reset_tdls_info(adapter);
if (ptdlsinfo->link_established == _TRUE)
rtw_tdls_cmd(adapter, NULL, TDLS_RS_RCR);
#endif /* CONFIG_TDLS */
/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
rtw_free_stainfo(adapter, psta);
/* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
}
if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) {
struct sta_info *psta;
rtw_free_all_stainfo(adapter);
psta = rtw_get_bcmc_stainfo(adapter);
/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
rtw_free_stainfo(adapter, psta);
/* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
rtw_init_bcmc_stainfo(adapter);
}
if (lock_scanned_queue)
_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS) || (pmlmepriv->wpa_phase == _TRUE)){
RTW_INFO("Dont free disconnecting network of scanned_queue due to uner %s %s phase\n\n",
check_fwstate(pmlmepriv, WIFI_UNDER_WPS) ? "WPS" : "",
(pmlmepriv->wpa_phase == _TRUE) ? "WPA" : "");
} else {
pwlan = _rtw_find_same_network(&pmlmepriv->scanned_queue, tgt_network);
if (pwlan) {
pwlan->fixed = _FALSE;
RTW_INFO("Free disconnecting network of scanned_queue\n");
rtw_free_network_nolock(adapter, pwlan);
#ifdef CONFIG_P2P
if (!rtw_p2p_chk_state(&adapter->wdinfo, P2P_STATE_NONE)) {
rtw_set_scan_deny(adapter, 2000);
/* rtw_clear_scan_deny(adapter); */
}
#endif /* CONFIG_P2P */
} else
RTW_ERR("Free disconnecting network of scanned_queue failed due to pwlan == NULL\n\n");
}
if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && (adapter->stapriv.asoc_sta_count == 1))
/*||check_fwstate(pmlmepriv, WIFI_STATION_STATE)*/) {
if (pwlan)
rtw_free_network_nolock(adapter, pwlan);
}
if (lock_scanned_queue)
_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
adapter->securitypriv.key_mask = 0;
rtw_reset_rx_info(adapter);
}
/*
*rtw_indicate_connect: the caller has to lock pmlmepriv->lock
*/
void rtw_indicate_connect(_adapter *padapter)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
pmlmepriv->to_join = _FALSE;
if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
set_fwstate(pmlmepriv, _FW_LINKED);
rtw_led_control(padapter, LED_CTL_LINK);
rtw_os_indicate_connect(padapter);
}
rtw_set_to_roam(padapter, 0);
#ifdef CONFIG_INTEL_WIDI
if (padapter->mlmepriv.widi_state == INTEL_WIDI_STATE_ROAMING) {
memset(pmlmepriv->sa_ext, 0x00, L2SDTA_SERVICE_VE_LEN);
intel_widi_wk_cmd(padapter, INTEL_WIDI_LISTEN_WK, NULL, 0);
RTW_INFO("change to widi listen\n");
}
#endif /* CONFIG_INTEL_WIDI */
if (!MLME_IS_AP(padapter) && !MLME_IS_MESH(padapter))
rtw_mi_set_scan_deny(padapter, 3000);
}
/*
*rtw_indicate_disconnect: the caller has to lock pmlmepriv->lock
*/
void rtw_indicate_disconnect(_adapter *padapter, u16 reason, u8 locally_generated)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network);
#ifdef CONFIG_WAPI_SUPPORT
struct sta_info *psta;
struct sta_priv *pstapriv = &padapter->stapriv;
#endif
u8 *wps_ie = NULL;
uint wpsie_len = 0;
if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS))
pmlmepriv->wpa_phase = _TRUE;
_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING | WIFI_UNDER_WPS | WIFI_OP_CH_SWITCHING | WIFI_UNDER_KEY_HANDSHAKE);
/* force to clear cur_network_scanned's SELECTED REGISTRAR */
if (pmlmepriv->cur_network_scanned) {
WLAN_BSSID_EX *current_joined_bss = &(pmlmepriv->cur_network_scanned->network);
if (current_joined_bss) {
wps_ie = rtw_get_wps_ie(current_joined_bss->IEs + _FIXED_IE_LENGTH_,
current_joined_bss->IELength - _FIXED_IE_LENGTH_, NULL, &wpsie_len);
if (wps_ie && wpsie_len > 0) {
u8 *attr = NULL;
u32 attr_len;
attr = rtw_get_wps_attr(wps_ie, wpsie_len, WPS_ATTR_SELECTED_REGISTRAR,
NULL, &attr_len);
if (attr)
*(attr + 4) = 0;
}
}
}
/* RTW_INFO("clear wps when %s\n", __func__); */
if (rtw_to_roam(padapter) > 0)
_clr_fwstate_(pmlmepriv, _FW_LINKED);
#ifdef CONFIG_WAPI_SUPPORT
psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress);
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
rtw_wapi_return_one_sta_info(padapter, psta->cmn.mac_addr);
else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))
rtw_wapi_return_all_sta_info(padapter);
#endif
if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)
|| (rtw_to_roam(padapter) <= 0)
) {
rtw_os_indicate_disconnect(padapter, reason, locally_generated);
/* set ips_deny_time to avoid enter IPS before LPS leave */
rtw_set_ips_deny(padapter, 3000);
_clr_fwstate_(pmlmepriv, _FW_LINKED);
rtw_led_control(padapter, LED_CTL_NO_LINK);
rtw_clear_scan_deny(padapter);
}
#ifdef CONFIG_P2P_PS
p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1);
#endif /* CONFIG_P2P_PS */
#ifdef CONFIG_LPS
rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_DISCONNECT, 0);
#endif
#ifdef CONFIG_BEAMFORMING
beamforming_wk_cmd(padapter, BEAMFORMING_CTRL_LEAVE, cur_network->MacAddress, ETH_ALEN, 1);
#endif /*CONFIG_BEAMFORMING*/
}
inline void rtw_indicate_scan_done(_adapter *padapter, bool aborted)
{
RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
rtw_os_indicate_scan_done(padapter, aborted);
#ifdef CONFIG_IPS
if (is_primary_adapter(padapter)
&& (_FALSE == adapter_to_pwrctl(padapter)->bInSuspend)
&& (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE | WIFI_UNDER_LINKING) == _FALSE)) {
struct pwrctrl_priv *pwrpriv;
pwrpriv = adapter_to_pwrctl(padapter);
rtw_set_ips_deny(padapter, 0);
#ifdef CONFIG_IPS_CHECK_IN_WD
_set_timer(&adapter_to_dvobj(padapter)->dynamic_chk_timer, 1);
#else /* !CONFIG_IPS_CHECK_IN_WD */
_rtw_set_pwr_state_check_timer(pwrpriv, 1);
#endif /* !CONFIG_IPS_CHECK_IN_WD */
}
#endif /* CONFIG_IPS */
}
static u32 _rtw_wait_scan_done(_adapter *adapter, u8 abort, u32 timeout_ms)
{
systime start;
u32 pass_ms;
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv);
start = rtw_get_current_time();
pmlmeext->scan_abort = abort;
while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)
&& rtw_get_passing_time_ms(start) <= timeout_ms) {
if (RTW_CANNOT_RUN(adapter))
break;
RTW_INFO(FUNC_NDEV_FMT"fw_state=_FW_UNDER_SURVEY!\n", FUNC_NDEV_ARG(adapter->pnetdev));
msleep(20);
}
if (_TRUE == abort) {
if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
if (!RTW_CANNOT_RUN(adapter))
RTW_INFO(FUNC_NDEV_FMT"waiting for scan_abort time out!\n", FUNC_NDEV_ARG(adapter->pnetdev));
#ifdef CONFIG_PLATFORM_MSTAR
/*_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);*/
set_survey_timer(pmlmeext, 0);
mlme_set_scan_to_timer(pmlmepriv, 50);
#endif
rtw_indicate_scan_done(adapter, _TRUE);
}
}
pmlmeext->scan_abort = _FALSE;
pass_ms = rtw_get_passing_time_ms(start);
return pass_ms;
}
void rtw_scan_wait_completed(_adapter *adapter)
{
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
struct ss_res *ss = &pmlmeext->sitesurvey_res;
_rtw_wait_scan_done(adapter, _FALSE, ss->scan_timeout_ms);
}
u32 rtw_scan_abort_timeout(_adapter *adapter, u32 timeout_ms)
{
return _rtw_wait_scan_done(adapter, _TRUE, timeout_ms);
}
void rtw_scan_abort_no_wait(_adapter *adapter)
{
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv);
if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
pmlmeext->scan_abort = _TRUE;
}
void rtw_scan_abort(_adapter *adapter)
{
rtw_scan_abort_timeout(adapter, 200);
}
static u32 _rtw_wait_join_done(_adapter *adapter, u8 abort, u32 timeout_ms)
{
systime start;
u32 pass_ms;
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv);
start = rtw_get_current_time();
pmlmeext->join_abort = abort;
if (abort)
set_link_timer(pmlmeext, 1);
while (rtw_get_passing_time_ms(start) <= timeout_ms
&& (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)
#ifdef CONFIG_IOCTL_CFG80211
|| rtw_cfg80211_is_connect_requested(adapter)
#endif
)
) {
if (RTW_CANNOT_RUN(adapter))
break;
RTW_INFO(FUNC_ADPT_FMT" linking...\n", FUNC_ADPT_ARG(adapter));
msleep(20);
}
if (abort) {
if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)
#ifdef CONFIG_IOCTL_CFG80211
|| rtw_cfg80211_is_connect_requested(adapter)
#endif
) {
if (!RTW_CANNOT_RUN(adapter))
RTW_INFO(FUNC_ADPT_FMT" waiting for join_abort time out!\n", FUNC_ADPT_ARG(adapter));
}
}
pmlmeext->join_abort = 0;
pass_ms = rtw_get_passing_time_ms(start);
return pass_ms;
}
u32 rtw_join_abort_timeout(_adapter *adapter, u32 timeout_ms)
{
return _rtw_wait_join_done(adapter, _TRUE, timeout_ms);
}
static struct sta_info *rtw_joinbss_update_stainfo(_adapter *padapter, struct wlan_network *pnetwork)
{
int i;
struct sta_info *psta = NULL;
struct recv_reorder_ctrl *preorder_ctrl;
struct sta_priv *pstapriv = &padapter->stapriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
#ifdef CONFIG_RTS_FULL_BW
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
struct wlan_network *cur_network = &(pmlmepriv->cur_network);
#endif/*CONFIG_RTS_FULL_BW*/
psta = rtw_get_stainfo(pstapriv, pnetwork->network.MacAddress);
if (psta == NULL)
psta = rtw_alloc_stainfo(pstapriv, pnetwork->network.MacAddress);
if (psta) { /* update ptarget_sta */
RTW_INFO("%s\n", __FUNCTION__);
psta->cmn.aid = pnetwork->join_res;
update_sta_info(padapter, psta);
/* update station supportRate */
psta->bssratelen = rtw_get_rateset_len(pnetwork->network.SupportedRates);
_rtw_memcpy(psta->bssrateset, pnetwork->network.SupportedRates, psta->bssratelen);
rtw_hal_update_sta_ra_info(padapter, psta);
psta->wireless_mode = pmlmeext->cur_wireless_mode;
rtw_hal_update_sta_wset(padapter, psta);
/* sta mode */
rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, _TRUE);
/* security related */
#ifdef CONFIG_RTW_80211R
if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)
&& (psta->ft_pairwise_key_installed == _FALSE)) {
#else
if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
#endif
u8 *ie;
sint ie_len;
u8 mfp_opt = MFP_NO;
padapter->securitypriv.binstallGrpkey = _FALSE;
padapter->securitypriv.busetkipkey = _FALSE;
padapter->securitypriv.bgrpkey_handshake = _FALSE;
ie = rtw_get_ie(pnetwork->network.IEs + _BEACON_IE_OFFSET_, WLAN_EID_RSN
, &ie_len, (pnetwork->network.IELength - _BEACON_IE_OFFSET_));
if (ie && ie_len > 0
&& rtw_parse_wpa2_ie(ie, ie_len + 2, NULL, NULL, NULL, &mfp_opt) == _SUCCESS
) {
if (padapter->securitypriv.mfp_opt >= MFP_OPTIONAL && mfp_opt >= MFP_OPTIONAL)
psta->flags |= WLAN_STA_MFP;
}
psta->ieee8021x_blocked = _TRUE;
psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
memset((u8 *)&psta->dot118021x_UncstKey, 0, sizeof(union Keytype));
memset((u8 *)&psta->dot11tkiprxmickey, 0, sizeof(union Keytype));
memset((u8 *)&psta->dot11tkiptxmickey, 0, sizeof(union Keytype));
}
/* Commented by Albert 2012/07/21 */
/* When doing the WPS, the wps_ie_len won't equal to 0 */
/* And the Wi-Fi driver shouldn't allow the data packet to be tramsmitted. */
if (padapter->securitypriv.wps_ie_len != 0) {
psta->ieee8021x_blocked = _TRUE;
padapter->securitypriv.wps_ie_len = 0;
}
/* for A-MPDU Rx reordering buffer control for sta_info */
/* if A-MPDU Rx is enabled, reseting rx_ordering_ctrl wstart_b(indicate_seq) to default value=0xffff */
/* todo: check if AP can send A-MPDU packets */
for (i = 0; i < 16 ; i++) {
/* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */
preorder_ctrl = &psta->recvreorder_ctrl[i];
preorder_ctrl->enable = _FALSE;
preorder_ctrl->indicate_seq = 0xffff;
#ifdef DBG_RX_SEQ
RTW_INFO("DBG_RX_SEQ "FUNC_ADPT_FMT" tid:%u SN_CLEAR indicate_seq:%u\n"
, FUNC_ADPT_ARG(padapter), i, preorder_ctrl->indicate_seq);
#endif
preorder_ctrl->wend_b = 0xffff;
preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; */ /* ex. 32(kbytes) -> wsize_b=32 */
preorder_ctrl->ampdu_size = RX_AMPDU_SIZE_INVALID;
}
}
#ifdef CONFIG_RTW_80211K
_rtw_memcpy(&psta->rm_en_cap, pnetwork->network.PhyInfo.rm_en_cap, 5);
#endif
#ifdef CONFIG_RTS_FULL_BW
rtw_parse_sta_vendor_ie_8812(padapter, psta, BSS_EX_TLV_IES(&cur_network->network), BSS_EX_TLV_IES_LEN(&cur_network->network));
#endif
return psta;
}
/* pnetwork : returns from rtw_joinbss_event_callback
* ptarget_wlan: found from scanned_queue */
static void rtw_joinbss_update_network(_adapter *padapter, struct wlan_network *ptarget_wlan, struct wlan_network *pnetwork)
{
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
struct security_priv *psecuritypriv = &padapter->securitypriv;
struct wlan_network *cur_network = &(pmlmepriv->cur_network);
sint tmp_fw_state = 0x0;
RTW_INFO("%s\n", __FUNCTION__);
/* why not use ptarget_wlan?? */
_rtw_memcpy(&cur_network->network, &pnetwork->network, pnetwork->network.Length);
/* some IEs in pnetwork is wrong, so we should use ptarget_wlan IEs */
cur_network->network.IELength = ptarget_wlan->network.IELength;
_rtw_memcpy(&cur_network->network.IEs[0], &ptarget_wlan->network.IEs[0], MAX_IE_SZ);
cur_network->aid = pnetwork->join_res;
#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS
rtw_set_signal_stat_timer(&padapter->recvpriv);
#endif
padapter->recvpriv.signal_strength = ptarget_wlan->network.PhyInfo.SignalStrength;
padapter->recvpriv.signal_qual = ptarget_wlan->network.PhyInfo.SignalQuality;
/* the ptarget_wlan->network.Rssi is raw data, we use ptarget_wlan->network.PhyInfo.SignalStrength instead (has scaled) */
padapter->recvpriv.rssi = translate_percentage_to_dbm(ptarget_wlan->network.PhyInfo.SignalStrength);
#if defined(DBG_RX_SIGNAL_DISPLAY_PROCESSING) && 1
RTW_INFO(FUNC_ADPT_FMT" signal_strength:%3u, rssi:%3d, signal_qual:%3u"
"\n"
, FUNC_ADPT_ARG(padapter)
, padapter->recvpriv.signal_strength
, padapter->recvpriv.rssi
, padapter->recvpriv.signal_qual
);
#endif
#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS
rtw_set_signal_stat_timer(&padapter->recvpriv);
#endif
/* update fw_state */ /* will clr _FW_UNDER_LINKING here indirectly */
switch (pnetwork->network.InfrastructureMode) {
case Ndis802_11Infrastructure:
/* Check encryption */
if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)
tmp_fw_state = tmp_fw_state | WIFI_UNDER_KEY_HANDSHAKE;
if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS))
tmp_fw_state = tmp_fw_state | WIFI_UNDER_WPS;
init_fwstate(pmlmepriv, WIFI_STATION_STATE | tmp_fw_state);
break;
case Ndis802_11IBSS:
/*pmlmepriv->fw_state = WIFI_ADHOC_STATE;*/
init_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
break;
default:
/*pmlmepriv->fw_state = WIFI_NULL_STATE;*/
init_fwstate(pmlmepriv, WIFI_NULL_STATE);
break;
}
rtw_update_protection(padapter, (cur_network->network.IEs) + sizeof(NDIS_802_11_FIXED_IEs),
(cur_network->network.IELength));
#ifdef CONFIG_80211N_HT
rtw_update_ht_cap(padapter, cur_network->network.IEs, cur_network->network.IELength, (u8) cur_network->network.Configuration.DSConfig);
#endif
}
/* Notes: the fucntion could be > passive_level (the same context as Rx tasklet)
* pnetwork : returns from rtw_joinbss_event_callback
* ptarget_wlan: found from scanned_queue
* if join_res > 0, for (fw_state==WIFI_STATION_STATE), we check if "ptarget_sta" & "ptarget_wlan" exist.
* if join_res > 0, for (fw_state==WIFI_ADHOC_STATE), we only check if "ptarget_wlan" exist.
* if join_res > 0, update "cur_network->network" from "pnetwork->network" if (ptarget_wlan !=NULL).
*/
/* #define REJOIN */
void rtw_joinbss_event_prehandle(_adapter *adapter, u8 *pbuf, u16 status)
{
_irqL irqL;
static u8 retry = 0;
struct sta_info *ptarget_sta = NULL, *pcur_sta = NULL;
struct sta_priv *pstapriv = &adapter->stapriv;
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
struct wlan_network *pnetwork = (struct wlan_network *)pbuf;
struct wlan_network *cur_network = &(pmlmepriv->cur_network);
struct wlan_network *pcur_wlan = NULL, *ptarget_wlan = NULL;
unsigned int the_same_macaddr = _FALSE;
#ifdef CONFIG_RTL8712
/* endian_convert */
pnetwork->join_res = le32_to_cpu(pnetwork->join_res);
pnetwork->network_type = le32_to_cpu(pnetwork->network_type);
pnetwork->network.Length = le32_to_cpu(pnetwork->network.Length);
pnetwork->network.Ssid.SsidLength = le32_to_cpu(pnetwork->network.Ssid.SsidLength);
pnetwork->network.Privacy = le32_to_cpu(pnetwork->network.Privacy);
pnetwork->network.Rssi = le32_to_cpu(pnetwork->network.Rssi);
pnetwork->network.NetworkTypeInUse = le32_to_cpu(pnetwork->network.NetworkTypeInUse) ;
pnetwork->network.Configuration.ATIMWindow = le32_to_cpu(pnetwork->network.Configuration.ATIMWindow);
pnetwork->network.Configuration.BeaconPeriod = le32_to_cpu(pnetwork->network.Configuration.BeaconPeriod);
pnetwork->network.Configuration.DSConfig = le32_to_cpu(pnetwork->network.Configuration.DSConfig);
pnetwork->network.Configuration.FHConfig.DwellTime = le32_to_cpu(pnetwork->network.Configuration.FHConfig.DwellTime);
pnetwork->network.Configuration.FHConfig.HopPattern = le32_to_cpu(pnetwork->network.Configuration.FHConfig.HopPattern);
pnetwork->network.Configuration.FHConfig.HopSet = le32_to_cpu(pnetwork->network.Configuration.FHConfig.HopSet);
pnetwork->network.Configuration.FHConfig.Length = le32_to_cpu(pnetwork->network.Configuration.FHConfig.Length);
pnetwork->network.Configuration.Length = le32_to_cpu(pnetwork->network.Configuration.Length);
pnetwork->network.InfrastructureMode = le32_to_cpu(pnetwork->network.InfrastructureMode);
pnetwork->network.IELength = le32_to_cpu(pnetwork->network.IELength);
#endif
rtw_get_encrypt_decrypt_from_registrypriv(adapter);
the_same_macaddr = _rtw_memcmp(pnetwork->network.MacAddress, cur_network->network.MacAddress, ETH_ALEN);
pnetwork->network.Length = get_WLAN_BSSID_EX_sz(&pnetwork->network);
if (pnetwork->network.Length > sizeof(WLAN_BSSID_EX))
goto exit;
_enter_critical_bh(&pmlmepriv->lock, &irqL);
pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0;
pmlmepriv->LinkDetectInfo.LowPowerTransitionCount = 0;
if (pnetwork->join_res > 0) {
_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
retry = 0;
if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) {
/* s1. find ptarget_wlan */
if (check_fwstate(pmlmepriv, _FW_LINKED)) {
if (the_same_macaddr == _TRUE)
ptarget_wlan = _rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress);
else {
pcur_wlan = _rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress);
if (pcur_wlan)
pcur_wlan->fixed = _FALSE;
pcur_sta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress);
if (pcur_sta) {
/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); */
rtw_free_stainfo(adapter, pcur_sta);
/* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); */
}
ptarget_wlan = _rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress);
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) {
if (ptarget_wlan)
ptarget_wlan->fixed = _TRUE;
}
}
} else {
ptarget_wlan = _rtw_find_same_network(&pmlmepriv->scanned_queue, pnetwork);
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) {
if (ptarget_wlan)
ptarget_wlan->fixed = _TRUE;
}
}
/* s2. update cur_network */
if (ptarget_wlan)
rtw_joinbss_update_network(adapter, ptarget_wlan, pnetwork);
else {
RTW_PRINT("Can't find ptarget_wlan when joinbss_event callback\n");
_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
goto ignore_joinbss_callback;
}
/* s3. find ptarget_sta & update ptarget_sta after update cur_network only for station mode */
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) {
ptarget_sta = rtw_joinbss_update_stainfo(adapter, pnetwork);
if (ptarget_sta == NULL) {
RTW_ERR("Can't update stainfo when joinbss_event callback\n");
_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
goto ignore_joinbss_callback;
}
}
/* s4. indicate connect */
if (MLME_IS_STA(adapter) || MLME_IS_ADHOC(adapter)) {
pmlmepriv->cur_network_scanned = ptarget_wlan;
rtw_indicate_connect(adapter);
}
/* s5. Cancle assoc_timer */
_cancel_timer_ex(&pmlmepriv->assoc_timer);
} else {
_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
goto ignore_joinbss_callback;
}
_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
} else if (pnetwork->join_res == -4) {
rtw_reset_securitypriv(adapter);
pmlmepriv->join_status = status;
_set_timer(&pmlmepriv->assoc_timer, 1);
/* rtw_free_assoc_resources(adapter, _TRUE); */
if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == _TRUE) {
_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
}
} else { /* if join_res < 0 (join fails), then try again */
#ifdef REJOIN
res = _FAIL;
if (retry < 2) {
res = rtw_select_and_join_from_scanned_queue(pmlmepriv);
}
if (res == _SUCCESS) {
/* extend time of assoc_timer */
_set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT);
retry++;
} else if (res == 2) { /* there is no need to wait for join */
_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
rtw_indicate_connect(adapter);
} else {
#endif
pmlmepriv->join_status = status;
_set_timer(&pmlmepriv->assoc_timer, 1);
/* rtw_free_assoc_resources(adapter, _TRUE); */
_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
#ifdef REJOIN
retry = 0;
}
#endif
}
ignore_joinbss_callback:
_exit_critical_bh(&pmlmepriv->lock, &irqL);
exit:
return;
}
void rtw_joinbss_event_callback(_adapter *adapter, u8 *pbuf)
{
struct wlan_network *pnetwork = (struct wlan_network *)pbuf;
mlmeext_joinbss_event_callback(adapter, pnetwork->join_res);
rtw_mi_os_xmit_schedule(adapter);
}
void rtw_sta_media_status_rpt(_adapter *adapter, struct sta_info *sta, bool connected)
{
struct macid_ctl_t *macid_ctl = &adapter->dvobj->macid_ctl;
bool miracast_enabled = 0;
bool miracast_sink = 0;
u8 role = H2C_MSR_ROLE_RSVD;
if (sta == NULL) {
RTW_PRINT(FUNC_ADPT_FMT" sta is NULL\n"
, FUNC_ADPT_ARG(adapter));
rtw_warn_on(1);
return;
}
if (sta->cmn.mac_id >= macid_ctl->num) {
RTW_PRINT(FUNC_ADPT_FMT" invalid macid:%u\n"
, FUNC_ADPT_ARG(adapter), sta->cmn.mac_id);
rtw_warn_on(1);
return;
}
if (!rtw_macid_is_used(macid_ctl, sta->cmn.mac_id)) {
RTW_PRINT(FUNC_ADPT_FMT" macid:%u not is used, set connected to 0\n"
, FUNC_ADPT_ARG(adapter), sta->cmn.mac_id);
connected = 0;
rtw_warn_on(1);
}
if (connected && !rtw_macid_is_bmc(macid_ctl, sta->cmn.mac_id)) {
miracast_enabled = STA_OP_WFD_MODE(sta) != 0 && is_miracast_enabled(adapter);
miracast_sink = miracast_enabled && (STA_OP_WFD_MODE(sta) & MIRACAST_SINK);
#ifdef CONFIG_TDLS
if (sta->tdls_sta_state & TDLS_LINKED_STATE)
role = H2C_MSR_ROLE_TDLS;
else
#endif
if (MLME_IS_STA(adapter)) {
if (MLME_IS_GC(adapter))
role = H2C_MSR_ROLE_GO;
else
role = H2C_MSR_ROLE_AP;
} else if (MLME_IS_AP(adapter)) {
if (MLME_IS_GO(adapter))
role = H2C_MSR_ROLE_GC;
else
role = H2C_MSR_ROLE_STA;
} else if (MLME_IS_ADHOC(adapter) || MLME_IS_ADHOC_MASTER(adapter))
role = H2C_MSR_ROLE_ADHOC;
else if (MLME_IS_MESH(adapter))
role = H2C_MSR_ROLE_MESH;
#ifdef CONFIG_WFD
if (role == H2C_MSR_ROLE_GC
|| role == H2C_MSR_ROLE_GO
|| role == H2C_MSR_ROLE_TDLS
) {
if (adapter->wfd_info.rtsp_ctrlport
|| adapter->wfd_info.tdls_rtsp_ctrlport
|| adapter->wfd_info.peer_rtsp_ctrlport)
rtw_wfd_st_switch(sta, 1);
}
#endif
}
rtw_hal_set_FwMediaStatusRpt_single_cmd(adapter
, connected
, miracast_enabled
, miracast_sink
, role
, sta->cmn.mac_id
);
}
u8 rtw_sta_media_status_rpt_cmd(_adapter *adapter, struct sta_info *sta, bool connected)
{
struct cmd_priv *cmdpriv = &adapter->cmdpriv;
struct cmd_obj *cmdobj;
struct drvextra_cmd_parm *cmd_parm;
struct sta_media_status_rpt_cmd_parm *rpt_parm;
u8 res = _SUCCESS;
cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (cmdobj == NULL) {
res = _FAIL;
goto exit;
}
cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
if (cmd_parm == NULL) {
rtw_mfree((u8 *)cmdobj, sizeof(struct cmd_obj));
res = _FAIL;
goto exit;
}
rpt_parm = (struct sta_media_status_rpt_cmd_parm *)rtw_zmalloc(sizeof(struct sta_media_status_rpt_cmd_parm));
if (rpt_parm == NULL) {
rtw_mfree((u8 *)cmdobj, sizeof(struct cmd_obj));
rtw_mfree((u8 *)cmd_parm, sizeof(struct drvextra_cmd_parm));
res = _FAIL;
goto exit;
}
rpt_parm->sta = sta;
rpt_parm->connected = connected;
cmd_parm->ec_id = STA_MSTATUS_RPT_WK_CID;
cmd_parm->type = 0;
cmd_parm->size = sizeof(struct sta_media_status_rpt_cmd_parm);
cmd_parm->pbuf = (u8 *)rpt_parm;
init_h2fwcmd_w_parm_no_rsp(cmdobj, cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
res = rtw_enqueue_cmd(cmdpriv, cmdobj);
exit:
return res;
}
inline void rtw_sta_media_status_rpt_cmd_hdl(_adapter *adapter, struct sta_media_status_rpt_cmd_parm *parm)
{
rtw_sta_media_status_rpt(adapter, parm->sta, parm->connected);
}
void rtw_stassoc_event_callback(_adapter *adapter, u8 *pbuf)
{
_irqL irqL;
struct sta_info *psta;
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
struct stassoc_event *pstassoc = (struct stassoc_event *)pbuf;
struct wlan_network *cur_network = &(pmlmepriv->cur_network);
struct wlan_network *ptarget_wlan = NULL;
#if CONFIG_RTW_MACADDR_ACL
if (rtw_access_ctrl(adapter, pstassoc->macaddr) == _FALSE)
return;
#endif
#if defined(CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME)
if (MLME_IS_AP(adapter) || MLME_IS_MESH(adapter)) {
psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr);
if (psta) {
u8 *passoc_req = NULL;
u32 assoc_req_len = 0;
rtw_sta_media_status_rpt(adapter, psta, 1);
#ifdef CONFIG_MCC_MODE
rtw_hal_mcc_update_macid_bitmap(adapter, psta->cmn.mac_id, _TRUE);
#endif /* CONFIG_MCC_MODE */
#ifndef CONFIG_AUTO_AP_MODE
ap_sta_info_defer_update(adapter, psta);
if (!MLME_IS_MESH(adapter)) {
/* report to upper layer */
RTW_INFO("indicate_sta_assoc_event to upper layer - hostapd\n");
#ifdef CONFIG_IOCTL_CFG80211
_enter_critical_bh(&psta->lock, &irqL);
if (psta->passoc_req && psta->assoc_req_len > 0) {
passoc_req = rtw_zmalloc(psta->assoc_req_len);
if (passoc_req) {
assoc_req_len = psta->assoc_req_len;
_rtw_memcpy(passoc_req, psta->passoc_req, assoc_req_len);
rtw_mfree(psta->passoc_req , psta->assoc_req_len);
psta->passoc_req = NULL;
psta->assoc_req_len = 0;
}
}
_exit_critical_bh(&psta->lock, &irqL);
if (passoc_req && assoc_req_len > 0) {
rtw_cfg80211_indicate_sta_assoc(adapter, passoc_req, assoc_req_len);
rtw_mfree(passoc_req, assoc_req_len);
}
#else /* !CONFIG_IOCTL_CFG80211 */
rtw_indicate_sta_assoc_event(adapter, psta);
#endif /* !CONFIG_IOCTL_CFG80211 */
}
#endif /* !CONFIG_AUTO_AP_MODE */
#ifdef CONFIG_BEAMFORMING
beamforming_wk_cmd(adapter, BEAMFORMING_CTRL_ENTER, (u8 *)psta, sizeof(struct sta_info), 0);
#endif/*CONFIG_BEAMFORMING*/
if (is_wep_enc(adapter->securitypriv.dot11PrivacyAlgrthm))
rtw_ap_wep_pk_setting(adapter, psta);
}
goto exit;
}
#endif /* defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */
/* for AD-HOC mode */
psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr);
if (psta == NULL) {
RTW_ERR(FUNC_ADPT_FMT" get no sta_info with "MAC_FMT"\n"
, FUNC_ADPT_ARG(adapter), MAC_ARG(pstassoc->macaddr));
rtw_warn_on(1);
goto exit;
}
rtw_sta_media_status_rpt(adapter, psta, 1);
if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)
psta->dot118021XPrivacy = adapter->securitypriv.dot11PrivacyAlgrthm;
psta->ieee8021x_blocked = _FALSE;
_enter_critical_bh(&pmlmepriv->lock, &irqL);
if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) ||
(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE)) {
if (adapter->stapriv.asoc_sta_count == 2) {
_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
ptarget_wlan = _rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress);
pmlmepriv->cur_network_scanned = ptarget_wlan;
if (ptarget_wlan)
ptarget_wlan->fixed = _TRUE;
_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
/* a sta + bc/mc_stainfo (not Ibss_stainfo) */
rtw_indicate_connect(adapter);
}
}
_exit_critical_bh(&pmlmepriv->lock, &irqL);
mlmeext_sta_add_event_callback(adapter, psta);
#ifdef CONFIG_RTL8711
/* submit SetStaKey_cmd to tell fw, fw will allocate an CAM entry for this sta */
rtw_setstakey_cmd(adapter, psta, GROUP_KEY, _TRUE);
#endif
exit:
#ifdef CONFIG_RTS_FULL_BW
rtw_set_rts_bw(adapter);
#endif/*CONFIG_RTS_FULL_BW*/
return;
}
#ifdef CONFIG_IEEE80211W
void rtw_sta_timeout_event_callback(_adapter *adapter, u8 *pbuf)
{
_irqL irqL;
struct sta_info *psta;
struct stadel_event *pstadel = (struct stadel_event *)pbuf;
struct sta_priv *pstapriv = &adapter->stapriv;
psta = rtw_get_stainfo(&adapter->stapriv, pstadel->macaddr);
if (psta) {
u8 updated = _FALSE;
_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
if (rtw_is_list_empty(&psta->asoc_list) == _FALSE) {
rtw_list_delete(&psta->asoc_list);
pstapriv->asoc_list_cnt--;
updated = ap_free_sta(adapter, psta, _TRUE, WLAN_REASON_PREV_AUTH_NOT_VALID, _TRUE);
}
_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
associated_clients_update(adapter, updated, STA_INFO_UPDATE_ALL);
}
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_RTW_80211R
void rtw_ft_info_init(struct ft_roam_info *pft)
{
memset(pft, 0, sizeof(struct ft_roam_info));
pft->ft_flags = 0
| RTW_FT_EN
| RTW_FT_OTD_EN
#ifdef CONFIG_RTW_BTM_ROAM
| RTW_FT_BTM_ROAM
#endif
;
pft->ft_updated_bcn = _FALSE;
}
u8 rtw_ft_chk_roaming_candidate(
_adapter *padapter, struct wlan_network *competitor)
{
u8 *pmdie;
u32 mdie_len = 0;
struct ft_roam_info *pft_roam = &(padapter->mlmepriv.ft_roam);
if (!(pmdie = rtw_get_ie(&competitor->network.IEs[12],
_MDIE_, &mdie_len, competitor->network.IELength-12)))
return _FALSE;
if (!_rtw_memcmp(&pft_roam->mdid, (pmdie+2), 2))
return _FALSE;
/*The candidate don't support over-the-DS*/
if (rtw_ft_valid_otd_candidate(padapter, pmdie)) {
RTW_INFO("FT: ignore the candidate("
MAC_FMT ") for over-the-DS\n",
MAC_ARG(competitor->network.MacAddress));
rtw_ft_clr_flags(padapter, RTW_FT_PEER_OTD_EN);
return _FALSE;
}
return _TRUE;
}
void rtw_ft_update_stainfo(_adapter *padapter, WLAN_BSSID_EX *pnetwork)
{
struct sta_priv *pstapriv = &padapter->stapriv;
struct sta_info *psta = NULL;
psta = rtw_get_stainfo(pstapriv, pnetwork->MacAddress);
if (psta == NULL)
psta = rtw_alloc_stainfo(pstapriv, pnetwork->MacAddress);
if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
padapter->securitypriv.binstallGrpkey = _FALSE;
padapter->securitypriv.busetkipkey = _FALSE;
padapter->securitypriv.bgrpkey_handshake = _FALSE;
psta->ieee8021x_blocked = _TRUE;
psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
memset((u8 *)&psta->dot118021x_UncstKey, 0, sizeof(union Keytype));
memset((u8 *)&psta->dot11tkiprxmickey, 0, sizeof(union Keytype));
memset((u8 *)&psta->dot11tkiptxmickey, 0, sizeof(union Keytype));
}
}
void rtw_ft_reassoc_event_callback(_adapter *padapter, u8 *pbuf)
{
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
struct stassoc_event *pstassoc = (struct stassoc_event *)pbuf;
struct ft_roam_info *pft_roam = &(pmlmepriv->ft_roam);
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)&(pmlmeinfo->network);
struct cfg80211_ft_event_params ft_evt_parms;
_irqL irqL;
memset(&ft_evt_parms, 0, sizeof(ft_evt_parms));
rtw_ft_update_stainfo(padapter, pnetwork);
ft_evt_parms.ies_len = pft_roam->ft_event.ies_len;
ft_evt_parms.ies = rtw_zmalloc(ft_evt_parms.ies_len);
if (ft_evt_parms.ies)
_rtw_memcpy((void *)ft_evt_parms.ies, pft_roam->ft_event.ies, ft_evt_parms.ies_len);
else
goto err_2;
ft_evt_parms.target_ap = rtw_zmalloc(ETH_ALEN);
if (ft_evt_parms.target_ap)
_rtw_memcpy((void *)ft_evt_parms.target_ap, pstassoc->macaddr, ETH_ALEN);
else
goto err_1;
ft_evt_parms.ric_ies = pft_roam->ft_event.ric_ies;
ft_evt_parms.ric_ies_len = pft_roam->ft_event.ric_ies_len;
rtw_ft_lock_set_status(padapter, RTW_FT_AUTHENTICATED_STA, &irqL);
rtw_cfg80211_ft_event(padapter, &ft_evt_parms);
RTW_INFO("%s: to "MAC_FMT"\n", __func__, MAC_ARG(ft_evt_parms.target_ap));
rtw_mfree((u8 *)pft_roam->ft_event.target_ap, ETH_ALEN);
err_1:
rtw_mfree((u8 *)ft_evt_parms.ies, ft_evt_parms.ies_len);
err_2:
return;
}
#endif
#if defined(CONFIG_RTW_WNM) || defined(CONFIG_RTW_80211K)
void rtw_roam_nb_info_init(_adapter *padapter)
{
struct roam_nb_info *pnb = &(padapter->mlmepriv.nb_info);
memset(&pnb->nb_rpt, 0, sizeof(pnb->nb_rpt));
memset(&pnb->nb_rpt_ch_list, 0, sizeof(pnb->nb_rpt_ch_list));
memset(&pnb->roam_target_addr, 0, ETH_ALEN);
pnb->nb_rpt_valid = _FALSE;
pnb->nb_rpt_ch_list_num = 0;
pnb->preference_en = _FALSE;
pnb->nb_rpt_is_same = _TRUE;
pnb->last_nb_rpt_entries = 0;
#ifdef CONFIG_RTW_WNM
rtw_init_timer(&pnb->roam_scan_timer,
padapter, rtw_wnm_roam_scan_hdl,
padapter);
#endif
}
u8 rtw_roam_nb_scan_list_set(
_adapter *padapter, struct sitesurvey_parm *pparm)
{
u8 ret = _FALSE;
u32 i;
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
struct roam_nb_info *pnb = &(pmlmepriv->nb_info);
if (!rtw_chk_roam_flags(padapter, RTW_ROAM_ACTIVE))
return ret;
if (!pmlmepriv->need_to_roam)
return ret;
if ((!pmlmepriv->nb_info.nb_rpt_valid) || (!pnb->nb_rpt_ch_list_num))
return ret;
if (!pparm)
return ret;
rtw_init_sitesurvey_parm(padapter, pparm);
if (rtw_roam_busy_scan(padapter, pnb)) {
pparm->ch_num = 1;
pparm->ch[pmlmepriv->ch_cnt].hw_value =
pnb->nb_rpt_ch_list[pmlmepriv->ch_cnt].hw_value;
pmlmepriv->ch_cnt++;
ret = _TRUE;
if (pmlmepriv->ch_cnt == pnb->nb_rpt_ch_list_num) {
pmlmepriv->nb_info.nb_rpt_valid = _FALSE;
pmlmepriv->ch_cnt = 0;
}
goto set_bssid_list;
}
pparm->ch_num = (pnb->nb_rpt_ch_list_num > RTW_CHANNEL_SCAN_AMOUNT)?
(RTW_CHANNEL_SCAN_AMOUNT):(pnb->nb_rpt_ch_list_num);
for (i=0; i<pparm->ch_num; i++) {
pparm->ch[i].hw_value = pnb->nb_rpt_ch_list[i].hw_value;
pparm->ch[i].flags = RTW_IEEE80211_CHAN_PASSIVE_SCAN;
}
pmlmepriv->nb_info.nb_rpt_valid = _FALSE;
pmlmepriv->ch_cnt = 0;
ret = _TRUE;
set_bssid_list:
rtw_set_802_11_bssid_list_scan(padapter, pparm);
return ret;
}
#endif
void rtw_sta_mstatus_disc_rpt(_adapter *adapter, u8 mac_id)
{
struct macid_ctl_t *macid_ctl = &adapter->dvobj->macid_ctl;
if (mac_id >= 0 && mac_id < macid_ctl->num) {
u8 id_is_shared = mac_id == RTW_DEFAULT_MGMT_MACID; /* TODO: real shared macid judgment */
RTW_INFO(FUNC_ADPT_FMT" - mac_id=%d%s\n", FUNC_ADPT_ARG(adapter)
, mac_id, id_is_shared ? " shared" : "");
if (!id_is_shared) {
rtw_hal_set_FwMediaStatusRpt_single_cmd(adapter, 0, 0, 0, 0, mac_id);
/*
* For safety, prevent from keeping macid sleep.
* If we can sure all power mode enter/leave are paired,
* this check can be removed.
* Lucas@20131113
*/
/* wakeup macid after disconnect. */
/*if (MLME_IS_STA(adapter))*/
rtw_hal_macid_wakeup(adapter, mac_id);
}
} else {
RTW_PRINT(FUNC_ADPT_FMT" invalid macid:%u\n"
, FUNC_ADPT_ARG(adapter), mac_id);
rtw_warn_on(1);
}
}
void rtw_sta_mstatus_report(_adapter *adapter)
{
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
struct wlan_network *tgt_network = &pmlmepriv->cur_network;
struct sta_info *psta = NULL;
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, WIFI_ASOC_STATE)) {
psta = rtw_get_stainfo(&adapter->stapriv, tgt_network->network.MacAddress);
if (psta)
rtw_sta_mstatus_disc_rpt(adapter, psta->cmn.mac_id);
else {
RTW_INFO("%s "ADPT_FMT" - mac_addr: "MAC_FMT" psta == NULL\n", __func__, ADPT_ARG(adapter), MAC_ARG(tgt_network->network.MacAddress));
rtw_warn_on(1);
}
}
}
void rtw_stadel_event_callback(_adapter *adapter, u8 *pbuf)
{
_irqL irqL, irqL2;
struct sta_info *psta;
struct wlan_network *pwlan = NULL;
WLAN_BSSID_EX *pdev_network = NULL;
u8 *pibss = NULL;
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
struct stadel_event *pstadel = (struct stadel_event *)pbuf;
struct wlan_network *tgt_network = &(pmlmepriv->cur_network);
RTW_INFO("%s(mac_id=%d)=" MAC_FMT "\n", __func__, pstadel->mac_id, MAC_ARG(pstadel->macaddr));
rtw_sta_mstatus_disc_rpt(adapter, pstadel->mac_id);
#ifdef CONFIG_MCC_MODE
rtw_hal_mcc_update_macid_bitmap(adapter, pstadel->mac_id, _FALSE);
#endif /* CONFIG_MCC_MODE */
psta = rtw_get_stainfo(&adapter->stapriv, pstadel->macaddr);
if (psta == NULL) {
RTW_INFO("%s(mac_id=%d)=" MAC_FMT " psta == NULL\n", __func__, pstadel->mac_id, MAC_ARG(pstadel->macaddr));
/*rtw_warn_on(1);*/
}
if (psta)
rtw_wfd_st_switch(psta, 0);
if (MLME_IS_MESH(adapter)) {
rtw_free_stainfo(adapter, psta);
goto exit;
}
if (MLME_IS_AP(adapter)) {
#ifdef CONFIG_IOCTL_CFG80211
#ifdef COMPAT_KERNEL_RELEASE
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)) || defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER)
rtw_cfg80211_indicate_sta_disassoc(adapter, pstadel->macaddr, *(u16 *)pstadel->rsvd);
#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)) || defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER) */
#endif /* CONFIG_IOCTL_CFG80211 */
rtw_free_stainfo(adapter, psta);
goto exit;
}
mlmeext_sta_del_event_callback(adapter);
_enter_critical_bh(&pmlmepriv->lock, &irqL2);
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
u16 reason = *((unsigned short *)(pstadel->rsvd));
bool roam = _FALSE;
struct wlan_network *roam_target = NULL;
#ifdef CONFIG_LAYER2_ROAMING
#ifdef CONFIG_RTW_80211R
if (rtw_ft_roam_expired(adapter, reason))
pmlmepriv->ft_roam.ft_roam_on_expired = _TRUE;
else
pmlmepriv->ft_roam.ft_roam_on_expired = _FALSE;
#endif
if (adapter->registrypriv.wifi_spec == 1)
roam = _FALSE;
else if (reason == WLAN_REASON_EXPIRATION_CHK && rtw_chk_roam_flags(adapter, RTW_ROAM_ON_EXPIRED))
roam = _TRUE;
else if (reason == WLAN_REASON_ACTIVE_ROAM && rtw_chk_roam_flags(adapter, RTW_ROAM_ACTIVE)) {
roam = _TRUE;
roam_target = pmlmepriv->roam_network;
}
#ifdef CONFIG_INTEL_WIDI
else if (adapter->mlmepriv.widi_state == INTEL_WIDI_STATE_CONNECTED)
roam = _TRUE;
#endif /* CONFIG_INTEL_WIDI */
if (roam == _TRUE) {
if (rtw_to_roam(adapter) > 0)
rtw_dec_to_roam(adapter); /* this stadel_event is caused by roaming, decrease to_roam */
else if (rtw_to_roam(adapter) == 0)
rtw_set_to_roam(adapter, adapter->registrypriv.max_roaming_times);
} else
rtw_set_to_roam(adapter, 0);
#endif /* CONFIG_LAYER2_ROAMING */
rtw_free_uc_swdec_pending_queue(adapter);
rtw_free_assoc_resources(adapter, _TRUE);
rtw_free_mlme_priv_ie_data(pmlmepriv);
rtw_indicate_disconnect(adapter, *(u16 *)pstadel->rsvd, pstadel->locally_generated);
#ifdef CONFIG_INTEL_WIDI
if (!rtw_to_roam(adapter))
process_intel_widi_disconnect(adapter, 1);
#endif /* CONFIG_INTEL_WIDI */
_rtw_roaming(adapter, roam_target);
}
if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ||
check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
rtw_free_stainfo(adapter, psta);
/* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
if (adapter->stapriv.asoc_sta_count == 1) { /* a sta + bc/mc_stainfo (not Ibss_stainfo) */
/* rtw_indicate_disconnect(adapter); */ /* removed@20091105 */
_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
/* free old ibss network */
/* pwlan = _rtw_find_network(&pmlmepriv->scanned_queue, pstadel->macaddr); */
pwlan = _rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress);
if (pwlan) {
pwlan->fixed = _FALSE;
rtw_free_network_nolock(adapter, pwlan);
}
_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
/* re-create ibss */
pdev_network = &(adapter->registrypriv.dev_network);
pibss = adapter->registrypriv.dev_network.MacAddress;
_rtw_memcpy(pdev_network, &tgt_network->network, get_WLAN_BSSID_EX_sz(&tgt_network->network));
memset(&pdev_network->Ssid, 0, sizeof(NDIS_802_11_SSID));
_rtw_memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(NDIS_802_11_SSID));
rtw_update_registrypriv_dev_network(adapter);
rtw_generate_random_ibss(pibss);
if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
set_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
_clr_fwstate_(pmlmepriv, WIFI_ADHOC_STATE);
}
if (rtw_create_ibss_cmd(adapter, 0) != _SUCCESS)
RTW_ERR("rtw_create_ibss_cmd FAIL\n");
}
}
_exit_critical_bh(&pmlmepriv->lock, &irqL2);
exit:
#ifdef CONFIG_RTS_FULL_BW
rtw_set_rts_bw(adapter);
#endif/*CONFIG_RTS_FULL_BW*/
return;
}
void rtw_cpwm_event_callback(PADAPTER padapter, u8 *pbuf)
{
#ifdef CONFIG_LPS_LCLK
struct reportpwrstate_parm *preportpwrstate;
#endif
#ifdef CONFIG_LPS_LCLK
preportpwrstate = (struct reportpwrstate_parm *)pbuf;
preportpwrstate->state |= (u8)(adapter_to_pwrctl(padapter)->cpwm_tog + 0x80);
cpwm_int_hdl(padapter, preportpwrstate);
#endif
}
void rtw_wmm_event_callback(PADAPTER padapter, u8 *pbuf)
{
WMMOnAssocRsp(padapter);
}
/*
* rtw_join_timeout_handler - Timeout/failure handler for CMD JoinBss
*/
void rtw_join_timeout_handler(void *ctx)
{
_adapter *adapter = (_adapter *)ctx;
_irqL irqL;
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
#if 0
if (rtw_is_drv_stopped(adapter)) {
_rtw_up_sema(&pmlmepriv->assoc_terminate);
return;
}
#endif
RTW_INFO("%s, fw_state=%x\n", __FUNCTION__, get_fwstate(pmlmepriv));
if (RTW_CANNOT_RUN(adapter))
return;
_enter_critical_bh(&pmlmepriv->lock, &irqL);
#ifdef CONFIG_LAYER2_ROAMING
if (rtw_to_roam(adapter) > 0) { /* join timeout caused by roaming */
while (1) {
rtw_dec_to_roam(adapter);
if (rtw_to_roam(adapter) != 0) { /* try another */
int do_join_r;
RTW_INFO("%s try another roaming\n", __FUNCTION__);
do_join_r = rtw_do_join(adapter);
if (_SUCCESS != do_join_r) {
RTW_INFO("%s roaming do_join return %d\n", __FUNCTION__ , do_join_r);
continue;
}
break;
} else {
#ifdef CONFIG_INTEL_WIDI
if (adapter->mlmepriv.widi_state == INTEL_WIDI_STATE_ROAMING) {
memset(pmlmepriv->sa_ext, 0x00, L2SDTA_SERVICE_VE_LEN);
intel_widi_wk_cmd(adapter, INTEL_WIDI_LISTEN_WK, NULL, 0);
RTW_INFO("change to widi listen\n");
}
#endif /* CONFIG_INTEL_WIDI */
RTW_INFO("%s We've try roaming but fail\n", __FUNCTION__);
#ifdef CONFIG_RTW_80211R
rtw_ft_clr_flags(adapter, RTW_FT_PEER_EN|RTW_FT_PEER_OTD_EN);
rtw_ft_reset_status(adapter);
#endif
rtw_indicate_disconnect(adapter, pmlmepriv->join_status, _FALSE);
break;
}
}
} else
#endif
{
rtw_indicate_disconnect(adapter, pmlmepriv->join_status, _FALSE);
free_scanqueue(pmlmepriv);/* ??? */
#ifdef CONFIG_IOCTL_CFG80211
/* indicate disconnect for the case that join_timeout and check_fwstate != FW_LINKED */
rtw_cfg80211_indicate_disconnect(adapter, pmlmepriv->join_status, _FALSE);
#endif /* CONFIG_IOCTL_CFG80211 */
}
pmlmepriv->join_status = 0; /* reset */
_exit_critical_bh(&pmlmepriv->lock, &irqL);
#ifdef CONFIG_DRVEXT_MODULE_WSC
drvext_assoc_fail_indicate(&adapter->drvextpriv);
#endif
}
/*
* rtw_scan_timeout_handler - Timeout/Faliure handler for CMD SiteSurvey
* @adapter: pointer to _adapter structure
*/
void rtw_scan_timeout_handler(void *ctx)
{
_adapter *adapter = (_adapter *)ctx;
_irqL irqL;
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
RTW_INFO(FUNC_ADPT_FMT" fw_state=%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv));
_enter_critical_bh(&pmlmepriv->lock, &irqL);
_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
_exit_critical_bh(&pmlmepriv->lock, &irqL);
#ifdef CONFIG_IOCTL_CFG80211
rtw_cfg80211_surveydone_event_callback(adapter);
#endif /* CONFIG_IOCTL_CFG80211 */
rtw_indicate_scan_done(adapter, _TRUE);
#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_IOCTL_CFG80211)
rtw_cfg80211_indicate_scan_done_for_buddy(adapter, _TRUE);
#endif
}
void rtw_mlme_reset_auto_scan_int(_adapter *adapter, u8 *reason)
{
#if defined(CONFIG_RTW_MESH) && defined(CONFIG_DFS_MASTER)
#if CONFIG_RTW_MESH_OFFCH_CAND
struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
#endif
#endif
u8 u_ch;
u32 interval_ms = 0xffffffff; /* 0xffffffff: special value to make min() works well, also means no auto scan */
*reason = RTW_AUTO_SCAN_REASON_UNSPECIFIED;
rtw_mi_get_ch_setting_union(adapter, &u_ch, NULL, NULL);
if (hal_chk_bw_cap(adapter, BW_CAP_40M)
&& is_client_associated_to_ap(adapter) == _TRUE
&& u_ch >= 1 && u_ch <= 14
&& adapter->registrypriv.wifi_spec
/* TODO: AP Connected is 40MHz capability? */
) {
interval_ms = rtw_min(interval_ms, 60 * 1000);
*reason |= RTW_AUTO_SCAN_REASON_2040_BSS;
}
#ifdef CONFIG_RTW_MESH
#if CONFIG_RTW_MESH_OFFCH_CAND
if (adapter->mesh_cfg.peer_sel_policy.offch_find_int_ms
&& rtw_mesh_offch_candidate_accepted(adapter)
#ifdef CONFIG_DFS_MASTER
&& (!rfctl->radar_detect_ch || (IS_CH_WAITING(rfctl) && !IS_UNDER_CAC(rfctl)))
#endif
) {
interval_ms = rtw_min(interval_ms, adapter->mesh_cfg.peer_sel_policy.offch_find_int_ms);
*reason |= RTW_AUTO_SCAN_REASON_MESH_OFFCH_CAND;
}
#endif
#endif /* CONFIG_RTW_MESH */
if (interval_ms == 0xffffffff)
interval_ms = 0;
rtw_mlme_set_auto_scan_int(adapter, interval_ms);
return;
}
void rtw_drv_scan_by_self(_adapter *padapter, u8 reason)
{
struct sitesurvey_parm parm;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
int i;
#if 1
u8 ssc_chk;
ssc_chk = rtw_sitesurvey_condition_check(padapter, _FALSE);
if( ssc_chk == SS_DENY_BUSY_TRAFFIC) {
#ifdef CONFIG_LAYER2_ROAMING
if (rtw_chk_roam_flags(padapter, RTW_ROAM_ACTIVE) && pmlmepriv->need_to_roam == _TRUE)
RTW_INFO(FUNC_ADPT_FMT" need to roam, don't care BusyTraffic\n", FUNC_ADPT_ARG(padapter));
else {
RTW_INFO(FUNC_ADPT_FMT" exit BusyTraffic\n", FUNC_ADPT_ARG(padapter));
goto exit;
}
#else
RTW_INFO(FUNC_ADPT_FMT" exit BusyTraffic\n", FUNC_ADPT_ARG(padapter));
goto exit;
#endif
}
else if (ssc_chk != SS_ALLOW)
goto exit;
if (!rtw_is_adapter_up(padapter))
goto exit;
#else
if (rtw_is_scan_deny(padapter))
goto exit;
if (!rtw_is_adapter_up(padapter))
goto exit;
if (rtw_mi_busy_traffic_check(padapter, _FALSE)) {
#ifdef CONFIG_LAYER2_ROAMING
if (rtw_chk_roam_flags(padapter, RTW_ROAM_ACTIVE) && pmlmepriv->need_to_roam == _TRUE) {
RTW_INFO("need to roam, don't care BusyTraffic\n");
} else
#endif
{
RTW_INFO(FUNC_ADPT_FMT" exit BusyTraffic\n", FUNC_ADPT_ARG(padapter));
goto exit;
}
}
if (check_fwstate(pmlmepriv, WIFI_AP_STATE) && check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
RTW_INFO(FUNC_ADPT_FMT" WIFI_AP_STATE && WIFI_UNDER_WPS\n", FUNC_ADPT_ARG(padapter));
goto exit;
}
if (check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY | _FW_UNDER_LINKING)) == _TRUE) {
RTW_INFO(FUNC_ADPT_FMT" _FW_UNDER_SURVEY|_FW_UNDER_LINKING\n", FUNC_ADPT_ARG(padapter));
goto exit;
}
#ifdef CONFIG_CONCURRENT_MODE
if (rtw_mi_buddy_check_fwstate(padapter, (_FW_UNDER_SURVEY | _FW_UNDER_LINKING | WIFI_UNDER_WPS))) {
RTW_INFO(FUNC_ADPT_FMT", but buddy_intf is under scanning or linking or wps_phase\n", FUNC_ADPT_ARG(padapter));
goto exit;
}
#endif
#endif
RTW_INFO(FUNC_ADPT_FMT" reason:0x%02x\n", FUNC_ADPT_ARG(padapter), reason);
/* only for 20/40 BSS */
if (reason == RTW_AUTO_SCAN_REASON_2040_BSS) {
rtw_init_sitesurvey_parm(padapter, &parm);
for (i=0;i<14;i++) {
parm.ch[i].hw_value = i + 1;
parm.ch[i].flags = RTW_IEEE80211_CHAN_PASSIVE_SCAN;
}
parm.ch_num = 14;
rtw_set_802_11_bssid_list_scan(padapter, &parm);
goto exit;
}
#if defined(CONFIG_RTW_WNM) || defined(CONFIG_RTW_80211K)
if ((reason == RTW_AUTO_SCAN_REASON_ROAM)
&& (rtw_roam_nb_scan_list_set(padapter, &parm)))
goto exit;
#endif
rtw_set_802_11_bssid_list_scan(padapter, NULL);
exit:
return;
}
static void rtw_auto_scan_handler(_adapter *padapter)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
u8 reason = RTW_AUTO_SCAN_REASON_UNSPECIFIED;
rtw_mlme_reset_auto_scan_int(padapter, &reason);
#ifdef CONFIG_P2P
if (!rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE))
goto exit;
#endif
#ifdef CONFIG_TDLS
if (padapter->tdlsinfo.link_established == _TRUE)
goto exit;
#endif
if (pmlmepriv->auto_scan_int_ms == 0
|| rtw_get_passing_time_ms(pmlmepriv->scan_start_time) < pmlmepriv->auto_scan_int_ms)
goto exit;
rtw_drv_scan_by_self(padapter, reason);
exit:
return;
}
static u8 is_drv_in_lps(_adapter *adapter)
{
u8 is_in_lps = _FALSE;
#ifdef CONFIG_LPS_LCLK_WD_TIMER /* to avoid leaving lps 32k frequently*/
if ((adapter_to_pwrctl(adapter)->bFwCurrentInPSMode == _TRUE)
#ifdef CONFIG_BT_COEXIST
&& (rtw_btcoex_IsBtControlLps(adapter) == _FALSE)
#endif
)
is_in_lps = _TRUE;
#endif /* CONFIG_LPS_LCLK_WD_TIMER*/
return is_in_lps;
}
void rtw_iface_dynamic_check_timer_handlder(_adapter *adapter)
{
#ifdef CONFIG_AP_MODE
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
#endif /* CONFIG_AP_MODE */
if (adapter->net_closed == _TRUE)
return;
#ifdef CONFIG_LPS_LCLK_WD_TIMER /* to avoid leaving lps 32k frequently*/
if (is_drv_in_lps(adapter)) {
u8 bEnterPS;
linked_status_chk(adapter, 1);
bEnterPS = traffic_status_watchdog(adapter, 1);
if (bEnterPS) {
/* rtw_lps_ctrl_wk_cmd(adapter, LPS_CTRL_ENTER, 0); */
rtw_hal_dm_watchdog_in_lps(adapter);
} else {
/* call rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_LEAVE, 0) in traffic_status_watchdog() */
}
}
#endif /* CONFIG_LPS_LCLK_WD_TIMER */
/* auto site survey */
rtw_auto_scan_handler(adapter);
#ifdef CONFIG_AP_MODE
if (MLME_IS_AP(adapter)|| MLME_IS_MESH(adapter)) {
#ifndef CONFIG_ACTIVE_KEEP_ALIVE_CHECK
expire_timeout_chk(adapter);
#endif /* !CONFIG_ACTIVE_KEEP_ALIVE_CHECK */
#ifdef CONFIG_BMC_TX_RATE_SELECT
rtw_update_bmc_sta_tx_rate(adapter);
#endif /*CONFIG_BMC_TX_RATE_SELECT*/
}
#endif /*CONFIG_AP_MODE*/
#ifdef CONFIG_BR_EXT
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
rcu_read_lock();
#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) */
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35))
if (adapter->pnetdev->br_port
#else /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) */
if (rcu_dereference(adapter->pnetdev->rx_handler_data)
#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) */
&& (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) == _TRUE)) {
/* expire NAT2.5 entry */
void nat25_db_expire(_adapter *priv);
nat25_db_expire(adapter);
if (adapter->pppoe_connection_in_progress > 0)
adapter->pppoe_connection_in_progress--;
/* due to rtw_dynamic_check_timer_handlder() is called every 2 seconds */
if (adapter->pppoe_connection_in_progress > 0)
adapter->pppoe_connection_in_progress--;
}
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
rcu_read_unlock();
#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) */
#endif /* CONFIG_BR_EXT */
}
/*TP_avg(t) = (1/10) * TP_avg(t-1) + (9/10) * TP(t) MBps*/
static void collect_sta_traffic_statistics(_adapter *adapter)
{
struct macid_ctl_t *macid_ctl = &adapter->dvobj->macid_ctl;
struct sta_info *sta;
u64 curr_tx_bytes = 0, curr_rx_bytes = 0;
u32 curr_tx_mbytes = 0, curr_rx_mbytes = 0;
int i;
for (i = 0; i < MACID_NUM_SW_LIMIT; i++) {
sta = macid_ctl->sta[i];
if (sta && !is_broadcast_mac_addr(sta->cmn.mac_addr)) {
if (sta->sta_stats.last_tx_bytes > sta->sta_stats.tx_bytes)
sta->sta_stats.last_tx_bytes = sta->sta_stats.tx_bytes;
if (sta->sta_stats.last_rx_bytes > sta->sta_stats.rx_bytes)
sta->sta_stats.last_rx_bytes = sta->sta_stats.rx_bytes;
if (sta->sta_stats.last_rx_bc_bytes > sta->sta_stats.rx_bc_bytes)
sta->sta_stats.last_rx_bc_bytes = sta->sta_stats.rx_bc_bytes;
if (sta->sta_stats.last_rx_mc_bytes > sta->sta_stats.rx_mc_bytes)
sta->sta_stats.last_rx_mc_bytes = sta->sta_stats.rx_mc_bytes;
curr_tx_bytes = sta->sta_stats.tx_bytes - sta->sta_stats.last_tx_bytes;
curr_rx_bytes = sta->sta_stats.rx_bytes - sta->sta_stats.last_rx_bytes;
sta->sta_stats.tx_tp_kbits = (curr_tx_bytes * 8 / 2) >> 10;/*Kbps*/
sta->sta_stats.rx_tp_kbits = (curr_rx_bytes * 8 / 2) >> 10;/*Kbps*/
sta->sta_stats.smooth_tx_tp_kbits = (sta->sta_stats.smooth_tx_tp_kbits * 6 / 10) + (sta->sta_stats.tx_tp_kbits * 4 / 10);/*Kbps*/
sta->sta_stats.smooth_rx_tp_kbits = (sta->sta_stats.smooth_rx_tp_kbits * 6 / 10) + (sta->sta_stats.rx_tp_kbits * 4 / 10);/*Kbps*/
curr_tx_mbytes = (curr_tx_bytes / 2) >> 20;/*MBps*/
curr_rx_mbytes = (curr_rx_bytes / 2) >> 20;/*MBps*/
sta->cmn.tx_moving_average_tp =
(sta->cmn.tx_moving_average_tp / 10) + (curr_tx_mbytes * 9 / 10); /*MBps*/
sta->cmn.rx_moving_average_tp =
(sta->cmn.rx_moving_average_tp / 10) + (curr_rx_mbytes * 9 /10); /*MBps*/
rtw_collect_bcn_info(sta->padapter);
if (adapter->bsta_tp_dump)
dump_sta_traffic(RTW_DBGDUMP, adapter, sta);
sta->sta_stats.last_tx_bytes = sta->sta_stats.tx_bytes;
sta->sta_stats.last_rx_bytes = sta->sta_stats.rx_bytes;
sta->sta_stats.last_rx_bc_bytes = sta->sta_stats.rx_bc_bytes;
sta->sta_stats.last_rx_mc_bytes = sta->sta_stats.rx_mc_bytes;
}
}
}
void rtw_sta_traffic_info(void *sel, _adapter *adapter)
{
struct macid_ctl_t *macid_ctl = &adapter->dvobj->macid_ctl;
struct sta_info *sta;
int i;
for (i = 0; i < MACID_NUM_SW_LIMIT; i++) {
sta = macid_ctl->sta[i];
if (sta && !is_broadcast_mac_addr(sta->cmn.mac_addr))
dump_sta_traffic(sel, adapter, sta);
}
}
/*#define DBG_TRAFFIC_STATISTIC*/
static void collect_traffic_statistics(_adapter *padapter)
{
struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
/*memset(&pdvobjpriv->traffic_stat, 0, sizeof(struct rtw_traffic_statistics));*/
/* Tx bytes reset*/
pdvobjpriv->traffic_stat.tx_bytes = 0;
pdvobjpriv->traffic_stat.tx_pkts = 0;
pdvobjpriv->traffic_stat.tx_drop = 0;
/* Rx bytes reset*/
pdvobjpriv->traffic_stat.rx_bytes = 0;
pdvobjpriv->traffic_stat.rx_pkts = 0;
pdvobjpriv->traffic_stat.rx_drop = 0;
rtw_mi_traffic_statistics(padapter);
/* Calculate throughput in last interval */
pdvobjpriv->traffic_stat.cur_tx_bytes = pdvobjpriv->traffic_stat.tx_bytes - pdvobjpriv->traffic_stat.last_tx_bytes;
pdvobjpriv->traffic_stat.cur_rx_bytes = pdvobjpriv->traffic_stat.rx_bytes - pdvobjpriv->traffic_stat.last_rx_bytes;
pdvobjpriv->traffic_stat.last_tx_bytes = pdvobjpriv->traffic_stat.tx_bytes;
pdvobjpriv->traffic_stat.last_rx_bytes = pdvobjpriv->traffic_stat.rx_bytes;
pdvobjpriv->traffic_stat.cur_tx_tp = (u32)(pdvobjpriv->traffic_stat.cur_tx_bytes * 8 / 2 / 1024 / 1024);/*Mbps*/
pdvobjpriv->traffic_stat.cur_rx_tp = (u32)(pdvobjpriv->traffic_stat.cur_rx_bytes * 8 / 2 / 1024 / 1024);/*Mbps*/
#ifdef DBG_TRAFFIC_STATISTIC
RTW_INFO("\n========================\n");
RTW_INFO("cur_tx_bytes:%lld\n", pdvobjpriv->traffic_stat.cur_tx_bytes);
RTW_INFO("cur_rx_bytes:%lld\n", pdvobjpriv->traffic_stat.cur_rx_bytes);
RTW_INFO("last_tx_bytes:%lld\n", pdvobjpriv->traffic_stat.last_tx_bytes);
RTW_INFO("last_rx_bytes:%lld\n", pdvobjpriv->traffic_stat.last_rx_bytes);
RTW_INFO("cur_tx_tp:%d (Mbps)\n", pdvobjpriv->traffic_stat.cur_tx_tp);
RTW_INFO("cur_rx_tp:%d (Mbps)\n", pdvobjpriv->traffic_stat.cur_rx_tp);
#endif
#ifdef CONFIG_RTW_NAPI
#ifdef CONFIG_RTW_NAPI_DYNAMIC
dynamic_napi_th_chk (padapter);
#endif /* CONFIG_RTW_NAPI_DYNAMIC */
#endif
}
void rtw_dynamic_check_timer_handlder(void *ctx)
{
struct dvobj_priv *pdvobj = (struct dvobj_priv *)ctx;
_adapter *adapter = dvobj_get_primary_adapter(pdvobj);
#if (MP_DRIVER == 1)
if (adapter->registrypriv.mp_mode == 1 && adapter->mppriv.mp_dm == 0) { /* for MP ODM dynamic Tx power tracking */
/* RTW_INFO("%s mp_dm =0 return\n", __func__); */
goto exit;
}
#endif
if (!adapter)
goto exit;
if (!rtw_is_hw_init_completed(adapter))
goto exit;
if (RTW_CANNOT_RUN(adapter))
goto exit;
collect_traffic_statistics(adapter);
collect_sta_traffic_statistics(adapter);
rtw_mi_dynamic_check_timer_handlder(adapter);
if (!is_drv_in_lps(adapter))
rtw_dynamic_chk_wk_cmd(adapter);
exit:
_set_timer(&pdvobj->dynamic_chk_timer, 2000);
}
#ifdef CONFIG_SET_SCAN_DENY_TIMER
inline bool rtw_is_scan_deny(_adapter *adapter)
{
struct mlme_priv *mlmepriv = &adapter->mlmepriv;
return (atomic_read(&mlmepriv->set_scan_deny) != 0) ? _TRUE : _FALSE;
}
inline void rtw_clear_scan_deny(_adapter *adapter)
{
struct mlme_priv *mlmepriv = &adapter->mlmepriv;
atomic_set(&mlmepriv->set_scan_deny, 0);
if (0)
RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter));
}
void rtw_set_scan_deny_timer_hdl(void *ctx)
{
_adapter *adapter = (_adapter *)ctx;
rtw_clear_scan_deny(adapter);
}
void rtw_set_scan_deny(_adapter *adapter, u32 ms)
{
struct mlme_priv *mlmepriv = &adapter->mlmepriv;
if (0)
RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter));
atomic_set(&mlmepriv->set_scan_deny, 1);
_set_timer(&mlmepriv->set_scan_deny_timer, ms);
}
#endif
#ifdef CONFIG_LAYER2_ROAMING
/*
* Select a new roaming candidate from the original @param candidate and @param competitor
* @return _TRUE: candidate is updated
* @return _FALSE: candidate is not updated
*/
static int rtw_check_roaming_candidate(struct mlme_priv *mlme
, struct wlan_network **candidate, struct wlan_network *competitor)
{
int updated = _FALSE;
_adapter *adapter = container_of(mlme, _adapter, mlmepriv);
struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
RT_CHANNEL_INFO *chset = rfctl->channel_set;
u8 ch = competitor->network.Configuration.DSConfig;
if (rtw_chset_search_ch(chset, ch) < 0)
goto exit;
if (IS_DFS_SLAVE_WITH_RD(rfctl)
&& !rtw_odm_dfs_domain_unknown(rfctl_to_dvobj(rfctl))
&& rtw_chset_is_ch_non_ocp(chset, ch))
goto exit;
#if defined(CONFIG_RTW_REPEATER_SON) && (!defined(CONFIG_RTW_REPEATER_SON_ROOT))
if (rtw_rson_isupdate_roamcan(mlme, candidate, competitor))
goto update;
goto exit;
#endif
if (is_same_ess(&competitor->network, &mlme->cur_network.network) == _FALSE)
goto exit;
if (rtw_is_desired_network(adapter, competitor) == _FALSE)
goto exit;
#ifdef CONFIG_LAYER2_ROAMING
if (mlme->need_to_roam == _FALSE)
goto exit;
#endif
#ifdef CONFIG_RTW_80211R
if (rtw_ft_chk_flags(adapter, RTW_FT_PEER_EN)) {
if (rtw_ft_chk_roaming_candidate(adapter, competitor) == _FALSE)
goto exit;
}
#endif
RTW_INFO("roam candidate:%s %s("MAC_FMT", ch%3u) rssi:%d, age:%5d\n",
(competitor == mlme->cur_network_scanned) ? "*" : " " ,
competitor->network.Ssid.Ssid,
MAC_ARG(competitor->network.MacAddress),
competitor->network.Configuration.DSConfig,
(int)competitor->network.Rssi,
rtw_get_passing_time_ms(competitor->last_scanned)
);
/* got specific addr to roam */
if (!is_zero_mac_addr(mlme->roam_tgt_addr)) {
if (_rtw_memcmp(mlme->roam_tgt_addr, competitor->network.MacAddress, ETH_ALEN) == _TRUE)
goto update;
else
goto exit;
}
#if 1
if (rtw_get_passing_time_ms(competitor->last_scanned) >= mlme->roam_scanr_exp_ms)
goto exit;
#if defined(CONFIG_RTW_80211R) && defined(CONFIG_RTW_WNM)
if (rtw_wnm_btm_diff_bss(adapter) &&
rtw_wnm_btm_roam_candidate(adapter, competitor)) {
goto update;
}
#endif
if (competitor->network.Rssi - mlme->cur_network_scanned->network.Rssi < mlme->roam_rssi_diff_th)
goto exit;
if (*candidate != NULL && (*candidate)->network.Rssi >= competitor->network.Rssi)
goto exit;
#else
goto exit;
#endif
update:
*candidate = competitor;
updated = _TRUE;
exit:
return updated;
}
int rtw_select_roaming_candidate(struct mlme_priv *mlme)
{
_irqL irqL;
int ret = _FAIL;
_list *phead;
_adapter *adapter;
_queue *queue = &(mlme->scanned_queue);
struct wlan_network *pnetwork = NULL;
struct wlan_network *candidate = NULL;
if (mlme->cur_network_scanned == NULL) {
rtw_warn_on(1);
goto exit;
}
_enter_critical_bh(&(mlme->scanned_queue.lock), &irqL);
phead = get_list_head(queue);
adapter = (_adapter *)mlme->nic_hdl;
mlme->pscanned = get_next(phead);
while (!rtw_end_of_queue_search(phead, mlme->pscanned)) {
pnetwork = LIST_CONTAINOR(mlme->pscanned, struct wlan_network, list);
if (pnetwork == NULL) {
ret = _FAIL;
goto exit;
}
mlme->pscanned = get_next(mlme->pscanned);
if (0)
RTW_INFO("%s("MAC_FMT", ch%u) rssi:%d\n"
, pnetwork->network.Ssid.Ssid
, MAC_ARG(pnetwork->network.MacAddress)
, pnetwork->network.Configuration.DSConfig
, (int)pnetwork->network.Rssi);
rtw_check_roaming_candidate(mlme, &candidate, pnetwork);
}
if (candidate == NULL) {
/* if parent note lost the path to root and there is no other cadidate, report disconnection */
#if defined(CONFIG_RTW_REPEATER_SON) && (!defined(CONFIG_RTW_REPEATER_SON_ROOT))
struct rtw_rson_struct rson_curr;
u8 rson_score;
rtw_get_rson_struct(&(mlme->cur_network_scanned->network), &rson_curr);
rson_score = rtw_cal_rson_score(&rson_curr, mlme->cur_network_scanned->network.Rssi);
if (check_fwstate(mlme, _FW_LINKED)
&& ((rson_score == RTW_RSON_SCORE_NOTCNNT)
|| (rson_score == RTW_RSON_SCORE_NOTSUP)))
receive_disconnect(adapter, mlme->cur_network_scanned->network.MacAddress
, WLAN_REASON_EXPIRATION_CHK, _FALSE);
#endif
RTW_INFO("%s: return _FAIL(candidate == NULL)\n", __FUNCTION__);
ret = _FAIL;
goto exit;
} else {
#if defined(CONFIG_RTW_REPEATER_SON) && (!defined(CONFIG_RTW_REPEATER_SON_ROOT))
struct rtw_rson_struct rson_curr;
u8 rson_score;
rtw_get_rson_struct(&(candidate->network), &rson_curr);
rson_score = rtw_cal_rson_score(&rson_curr, candidate->network.Rssi);
RTW_INFO("%s: candidate: %s("MAC_FMT", ch:%u) rson_score:%d\n", __FUNCTION__,
candidate->network.Ssid.Ssid, MAC_ARG(candidate->network.MacAddress),
candidate->network.Configuration.DSConfig, rson_score);
#else
RTW_INFO("%s: candidate: %s("MAC_FMT", ch:%u)\n", __FUNCTION__,
candidate->network.Ssid.Ssid, MAC_ARG(candidate->network.MacAddress),
candidate->network.Configuration.DSConfig);
#endif
mlme->roam_network = candidate;
if (_rtw_memcmp(candidate->network.MacAddress, mlme->roam_tgt_addr, ETH_ALEN) == _TRUE)
memset(mlme->roam_tgt_addr, 0, ETH_ALEN);
}
ret = _SUCCESS;
exit:
_exit_critical_bh(&(mlme->scanned_queue.lock), &irqL);
return ret;
}
#endif /* CONFIG_LAYER2_ROAMING */
/*
* Select a new join candidate from the original @param candidate and @param competitor
* @return _TRUE: candidate is updated
* @return _FALSE: candidate is not updated
*/
static int rtw_check_join_candidate(struct mlme_priv *mlme
, struct wlan_network **candidate, struct wlan_network *competitor)
{
int updated = _FALSE;
_adapter *adapter = container_of(mlme, _adapter, mlmepriv);
struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
RT_CHANNEL_INFO *chset = rfctl->channel_set;
u8 ch = competitor->network.Configuration.DSConfig;
if (rtw_chset_search_ch(chset, ch) < 0)
goto exit;
if (IS_DFS_SLAVE_WITH_RD(rfctl)
&& !rtw_odm_dfs_domain_unknown(rfctl_to_dvobj(rfctl))
&& rtw_chset_is_ch_non_ocp(chset, ch))
goto exit;
#if defined(CONFIG_RTW_REPEATER_SON) && (!defined(CONFIG_RTW_REPEATER_SON_ROOT))
s16 rson_score;
struct rtw_rson_struct rson_data;
if (rtw_rson_choose(candidate, competitor)) {
*candidate = competitor;
rtw_get_rson_struct(&((*candidate)->network), &rson_data);
rson_score = rtw_cal_rson_score(&rson_data, (*candidate)->network.Rssi);
RTW_INFO("[assoc_ssid:%s] new candidate: %s("MAC_FMT", ch%u) rson_score:%d\n",
mlme->assoc_ssid.Ssid,
(*candidate)->network.Ssid.Ssid,
MAC_ARG((*candidate)->network.MacAddress),
(*candidate)->network.Configuration.DSConfig,
rson_score);
return _TRUE;
}
return _FALSE;
#endif
/* check bssid, if needed */
if (mlme->assoc_by_bssid == _TRUE) {
if (_rtw_memcmp(competitor->network.MacAddress, mlme->assoc_bssid, ETH_ALEN) == _FALSE)
goto exit;
}
/* check ssid, if needed */
if (mlme->assoc_ssid.Ssid[0] && mlme->assoc_ssid.SsidLength) {
if (competitor->network.Ssid.SsidLength != mlme->assoc_ssid.SsidLength
|| _rtw_memcmp(competitor->network.Ssid.Ssid, mlme->assoc_ssid.Ssid, mlme->assoc_ssid.SsidLength) == _FALSE
)
goto exit;
}
if (rtw_is_desired_network(adapter, competitor) == _FALSE)
goto exit;
#ifdef CONFIG_LAYER2_ROAMING
if (rtw_to_roam(adapter) > 0) {
if (rtw_get_passing_time_ms(competitor->last_scanned) >= mlme->roam_scanr_exp_ms
|| is_same_ess(&competitor->network, &mlme->cur_network.network) == _FALSE
)
goto exit;
}
#endif
if (*candidate == NULL || (*candidate)->network.Rssi < competitor->network.Rssi) {
*candidate = competitor;
updated = _TRUE;
}
if (updated) {
RTW_INFO("[by_bssid:%u][assoc_ssid:%s][to_roam:%u] "
"new candidate: %s("MAC_FMT", ch%u) rssi:%d\n",
mlme->assoc_by_bssid,
mlme->assoc_ssid.Ssid,
rtw_to_roam(adapter),
(*candidate)->network.Ssid.Ssid,
MAC_ARG((*candidate)->network.MacAddress),
(*candidate)->network.Configuration.DSConfig,
(int)(*candidate)->network.Rssi
);
}
exit:
return updated;
}
/*
Calling context:
The caller of the sub-routine will be in critical section...
The caller must hold the following spinlock
pmlmepriv->lock
*/
int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv)
{
_irqL irqL;
int ret;
_list *phead;
_adapter *adapter;
_queue *queue = &(pmlmepriv->scanned_queue);
struct wlan_network *pnetwork = NULL;
struct wlan_network *candidate = NULL;
#ifdef CONFIG_ANTENNA_DIVERSITY
u8 bSupportAntDiv = _FALSE;
#endif
adapter = (_adapter *)pmlmepriv->nic_hdl;
_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
#ifdef CONFIG_LAYER2_ROAMING
if (pmlmepriv->roam_network) {
candidate = pmlmepriv->roam_network;
pmlmepriv->roam_network = NULL;
goto candidate_exist;
}
#endif
phead = get_list_head(queue);
pmlmepriv->pscanned = get_next(phead);
while (!rtw_end_of_queue_search(phead, pmlmepriv->pscanned)) {
pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list);
if (pnetwork == NULL) {
ret = _FAIL;
goto exit;
}
pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);
if (0)
RTW_INFO("%s("MAC_FMT", ch%u) rssi:%d\n"
, pnetwork->network.Ssid.Ssid
, MAC_ARG(pnetwork->network.MacAddress)
, pnetwork->network.Configuration.DSConfig
, (int)pnetwork->network.Rssi);
rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork);
}
if (candidate == NULL) {
RTW_INFO("%s: return _FAIL(candidate == NULL)\n", __FUNCTION__);
#ifdef CONFIG_WOWLAN
_clr_fwstate_(pmlmepriv, _FW_LINKED | _FW_UNDER_LINKING);
#endif
ret = _FAIL;
goto exit;
} else {
RTW_INFO("%s: candidate: %s("MAC_FMT", ch:%u)\n", __FUNCTION__,
candidate->network.Ssid.Ssid, MAC_ARG(candidate->network.MacAddress),
candidate->network.Configuration.DSConfig);
goto candidate_exist;
}
candidate_exist:
/* check for situation of _FW_LINKED */
if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) {
RTW_INFO("%s: _FW_LINKED while ask_for_joinbss!!!\n", __FUNCTION__);
#if 0 /* for WPA/WPA2 authentication, wpa_supplicant will expect authentication from AP, it is needed to reconnect AP... */
if (is_same_network(&pmlmepriv->cur_network.network, &candidate->network)) {
RTW_INFO("%s: _FW_LINKED and is same network, it needn't join again\n", __FUNCTION__);
rtw_indicate_connect(adapter);/* rtw_indicate_connect again */
ret = 2;
goto exit;
} else
#endif
{
rtw_disassoc_cmd(adapter, 0, 0);
rtw_indicate_disconnect(adapter, 0, _FALSE);
rtw_free_assoc_resources_cmd(adapter, _TRUE, 0);
}
}
#ifdef CONFIG_ANTENNA_DIVERSITY
rtw_hal_get_def_var(adapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &(bSupportAntDiv));
if (_TRUE == bSupportAntDiv) {
u8 CurrentAntenna;
rtw_hal_get_odm_var(adapter, HAL_ODM_ANTDIV_SELECT, &(CurrentAntenna), NULL);
RTW_INFO("#### Opt_Ant_(%s) , cur_Ant(%s)\n",
(MAIN_ANT == candidate->network.PhyInfo.Optimum_antenna) ? "MAIN_ANT" : "AUX_ANT",
(MAIN_ANT == CurrentAntenna) ? "MAIN_ANT" : "AUX_ANT"
);
}
#endif
set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
ret = rtw_joinbss_cmd(adapter, candidate);
exit:
_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
return ret;
}
sint rtw_set_auth(_adapter *adapter, struct security_priv *psecuritypriv)
{
struct cmd_obj *pcmd;
struct setauth_parm *psetauthparm;
struct cmd_priv *pcmdpriv = &(adapter->cmdpriv);
sint res = _SUCCESS;
pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (pcmd == NULL) {
res = _FAIL; /* try again */
goto exit;
}
psetauthparm = (struct setauth_parm *)rtw_zmalloc(sizeof(struct setauth_parm));
if (psetauthparm == NULL) {
rtw_mfree((unsigned char *)pcmd, sizeof(struct cmd_obj));
res = _FAIL;
goto exit;
}
memset(psetauthparm, 0, sizeof(struct setauth_parm));
psetauthparm->mode = (unsigned char)psecuritypriv->dot11AuthAlgrthm;
pcmd->cmdcode = _SetAuth_CMD_;
pcmd->parmbuf = (unsigned char *)psetauthparm;
pcmd->cmdsz = (sizeof(struct setauth_parm));
pcmd->rsp = NULL;
pcmd->rspsz = 0;
_rtw_init_listhead(&pcmd->list);
res = rtw_enqueue_cmd(pcmdpriv, pcmd);
exit:
return res;
}
sint rtw_set_key(_adapter *adapter, struct security_priv *psecuritypriv, sint keyid, u8 set_tx, bool enqueue)
{
u8 keylen;
struct cmd_obj *pcmd;
struct setkey_parm *psetkeyparm;
struct cmd_priv *pcmdpriv = &(adapter->cmdpriv);
sint res = _SUCCESS;
psetkeyparm = (struct setkey_parm *)rtw_zmalloc(sizeof(struct setkey_parm));
if (psetkeyparm == NULL) {
res = _FAIL;
goto exit;
}
memset(psetkeyparm, 0, sizeof(struct setkey_parm));
if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
psetkeyparm->algorithm = (unsigned char)psecuritypriv->dot118021XGrpPrivacy;
} else {
psetkeyparm->algorithm = (u8)psecuritypriv->dot11PrivacyAlgrthm;
}
psetkeyparm->keyid = (u8)keyid;/* 0~3 */
psetkeyparm->set_tx = set_tx;
if (is_wep_enc(psetkeyparm->algorithm))
adapter->securitypriv.key_mask |= BIT(psetkeyparm->keyid);
RTW_INFO("==> rtw_set_key algorithm(%x),keyid(%x),key_mask(%x)\n", psetkeyparm->algorithm, psetkeyparm->keyid, adapter->securitypriv.key_mask);
switch (psetkeyparm->algorithm) {
case _WEP40_:
keylen = 5;
_rtw_memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen);
break;
case _WEP104_:
keylen = 13;
_rtw_memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen);
break;
case _TKIP_:
keylen = 16;
_rtw_memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen);
break;
case _AES_:
keylen = 16;
_rtw_memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen);
break;
default:
res = _FAIL;
rtw_mfree((unsigned char *)psetkeyparm, sizeof(struct setkey_parm));
goto exit;
}
if (enqueue) {
pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (pcmd == NULL) {
rtw_mfree((unsigned char *)psetkeyparm, sizeof(struct setkey_parm));
res = _FAIL; /* try again */
goto exit;
}
pcmd->cmdcode = _SetKey_CMD_;
pcmd->parmbuf = (u8 *)psetkeyparm;
pcmd->cmdsz = (sizeof(struct setkey_parm));
pcmd->rsp = NULL;
pcmd->rspsz = 0;
_rtw_init_listhead(&pcmd->list);
/* _rtw_init_sema(&(pcmd->cmd_sem), 0); */
res = rtw_enqueue_cmd(pcmdpriv, pcmd);
} else {
setkey_hdl(adapter, (u8 *)psetkeyparm);
rtw_mfree((u8 *) psetkeyparm, sizeof(struct setkey_parm));
}
exit:
return res;
}
#ifdef CONFIG_WMMPS_STA
/*
* rtw_uapsd_use_default_setting
* This function is used for setting default uapsd max sp length to uapsd_max_sp_len
* in qos_priv data structure from registry. In additional, it will also map default uapsd
* ac to each uapsd TID, delivery-enabled and trigger-enabled of corresponding TID.
*
* Arguments:
* @padapter: _adapter pointer.
*
* Auther: Arvin Liu
* Date: 2017/05/03
*/
void rtw_uapsd_use_default_setting(_adapter *padapter)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct qos_priv *pqospriv = &pmlmepriv->qospriv;
struct registry_priv *pregistrypriv = &padapter->registrypriv;
if (pregistrypriv->uapsd_ac_enable != 0) {
pqospriv->uapsd_max_sp_len = pregistrypriv->uapsd_max_sp_len;
CLEAR_FLAGS(pqospriv->uapsd_tid);
CLEAR_FLAGS(pqospriv->uapsd_tid_delivery_enabled);
CLEAR_FLAGS(pqospriv->uapsd_tid_trigger_enabled);
/* check the uapsd setting of AC_VO from registry then map these setting to each TID if necessary */
if(TEST_FLAG(pregistrypriv->uapsd_ac_enable, DRV_CFG_UAPSD_VO)) {
SET_FLAG(pqospriv->uapsd_tid, WMM_TID7);
SET_FLAG(pqospriv->uapsd_tid_delivery_enabled, WMM_TID7);
SET_FLAG(pqospriv->uapsd_tid_trigger_enabled, WMM_TID7);
SET_FLAG(pqospriv->uapsd_tid, WMM_TID6);
SET_FLAG(pqospriv->uapsd_tid_delivery_enabled, WMM_TID6);
SET_FLAG(pqospriv->uapsd_tid_trigger_enabled, WMM_TID6);
}
/* check the uapsd setting of AC_VI from registry then map these setting to each TID if necessary */
if(TEST_FLAG(pregistrypriv->uapsd_ac_enable, DRV_CFG_UAPSD_VI)) {
SET_FLAG(pqospriv->uapsd_tid, WMM_TID5);
SET_FLAG(pqospriv->uapsd_tid_delivery_enabled, WMM_TID5);
SET_FLAG(pqospriv->uapsd_tid_trigger_enabled, WMM_TID5);
SET_FLAG(pqospriv->uapsd_tid, WMM_TID4);
SET_FLAG(pqospriv->uapsd_tid_delivery_enabled, WMM_TID4);
SET_FLAG(pqospriv->uapsd_tid_trigger_enabled, WMM_TID4);
}
/* check the uapsd setting of AC_BK from registry then map these setting to each TID if necessary */
if(TEST_FLAG(pregistrypriv->uapsd_ac_enable, DRV_CFG_UAPSD_BK)) {
SET_FLAG(pqospriv->uapsd_tid, WMM_TID2);
SET_FLAG(pqospriv->uapsd_tid_delivery_enabled, WMM_TID2);
SET_FLAG(pqospriv->uapsd_tid_trigger_enabled, WMM_TID2);
SET_FLAG(pqospriv->uapsd_tid, WMM_TID1);
SET_FLAG(pqospriv->uapsd_tid_delivery_enabled, WMM_TID1);
SET_FLAG(pqospriv->uapsd_tid_trigger_enabled, WMM_TID1);
}
/* check the uapsd setting of AC_BE from registry then map these setting to each TID if necessary */
if(TEST_FLAG(pregistrypriv->uapsd_ac_enable, DRV_CFG_UAPSD_BE)) {
SET_FLAG(pqospriv->uapsd_tid, WMM_TID3);
SET_FLAG(pqospriv->uapsd_tid_delivery_enabled, WMM_TID3);
SET_FLAG(pqospriv->uapsd_tid_trigger_enabled, WMM_TID3);
SET_FLAG(pqospriv->uapsd_tid, WMM_TID0);
SET_FLAG(pqospriv->uapsd_tid_delivery_enabled, WMM_TID0);
SET_FLAG(pqospriv->uapsd_tid_trigger_enabled, WMM_TID0);
}
RTW_INFO("[WMMPS] UAPSD MAX SP Len = 0x%02x, UAPSD TID enabled = 0x%02x\n",
pqospriv->uapsd_max_sp_len, (u8)pqospriv->uapsd_tid);
}
}
/*
* rtw_is_wmmps_mode
* This function is used for checking whether Driver and an AP support uapsd function or not.
* If both of them support uapsd function, it will return true. Otherwise returns false.
*
* Arguments:
* @padapter: _adapter pointer.
*
* Auther: Arvin Liu
* Date: 2017/06/12
*/
bool rtw_is_wmmps_mode(_adapter *padapter)
{
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
struct qos_priv *pqospriv = &pmlmepriv->qospriv;
if ((pqospriv->uapsd_ap_supported) && ((pqospriv->uapsd_tid & BIT_MASK_TID_TC) != 0))
return _TRUE;
return _FALSE;
}
#endif /* CONFIG_WMMPS_STA */
/* adjust IEs for rtw_joinbss_cmd in WMM */
int rtw_restruct_wmm_ie(_adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len, uint initial_out_len)
{
#ifdef CONFIG_WMMPS_STA
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
struct qos_priv *pqospriv = &pmlmepriv->qospriv;
#endif /* CONFIG_WMMPS_STA */
unsigned int ielength = 0;
unsigned int i, j;
u8 qos_info = 0;
i = 12; /* after the fixed IE */
while (i < in_len) {
ielength = initial_out_len;
if (in_ie[i] == 0xDD && in_ie[i + 2] == 0x00 && in_ie[i + 3] == 0x50 && in_ie[i + 4] == 0xF2 && in_ie[i + 5] == 0x02 && i + 5 < in_len) { /* WMM element ID and OUI */
/* Append WMM IE to the last index of out_ie */
#if 0
for (j = i; j < i + (in_ie[i + 1] + 2); j++) {
out_ie[ielength] = in_ie[j];
ielength++;
}
out_ie[initial_out_len + 8] = 0x00; /* force the QoS Info Field to be zero */
#endif
for (j = i; j < i + 9; j++) {
out_ie[ielength] = in_ie[j];
ielength++;
}
out_ie[initial_out_len + 1] = 0x07;
out_ie[initial_out_len + 6] = 0x00;
#ifdef CONFIG_WMMPS_STA
switch(pqospriv->uapsd_max_sp_len) {
case NO_LIMIT:
/* do nothing */
break;
case TWO_MSDU:
SET_FLAG(qos_info, BIT5);
break;
case FOUR_MSDU:
SET_FLAG(qos_info, BIT6);
break;
case SIX_MSDU:
SET_FLAG(qos_info, BIT5);
SET_FLAG(qos_info, BIT6);
break;
default:
/* do nothing */
break;
};
/* check TID7 and TID6 for AC_VO to set corresponding Qos_info bit in WMM IE */
if((TEST_FLAG(pqospriv->uapsd_tid, WMM_TID7)) && (TEST_FLAG(pqospriv->uapsd_tid, WMM_TID6)))
SET_FLAG(qos_info, WMM_IE_UAPSD_VO);
/* check TID5 and TID4 for AC_VI to set corresponding Qos_info bit in WMM IE */
if((TEST_FLAG(pqospriv->uapsd_tid, WMM_TID5)) && (TEST_FLAG(pqospriv->uapsd_tid, WMM_TID4)))
SET_FLAG(qos_info, WMM_IE_UAPSD_VI);
/* check TID2 and TID1 for AC_BK to set corresponding Qos_info bit in WMM IE */
if((TEST_FLAG(pqospriv->uapsd_tid, WMM_TID2)) && (TEST_FLAG(pqospriv->uapsd_tid, WMM_TID1)))
SET_FLAG(qos_info, WMM_IE_UAPSD_BK);
/* check TID3 and TID0 for AC_BE to set corresponding Qos_info bit in WMM IE */
if((TEST_FLAG(pqospriv->uapsd_tid, WMM_TID3)) && (TEST_FLAG(pqospriv->uapsd_tid, WMM_TID0)))
SET_FLAG(qos_info, WMM_IE_UAPSD_BE);
#endif /* CONFIG_WMMPS_STA */
out_ie[initial_out_len + 8] = qos_info;
break;
}
i += (in_ie[i + 1] + 2); /* to the next IE element */
}
return ielength;
}
/*
* Ported from 8185: IsInPreAuthKeyList(). (Renamed from SecIsInPreAuthKeyList(), 2006-10-13.)
* Added by Annie, 2006-05-07.
*
* Search by BSSID,
* Return Value:
* -1 :if there is no pre-auth key in the table
* >=0 :if there is pre-auth key, and return the entry id
*
* */
static int SecIsInPMKIDList(_adapter *Adapter, u8 *bssid)
{
struct security_priv *psecuritypriv = &Adapter->securitypriv;
int i = 0;
do {
if ((psecuritypriv->PMKIDList[i].bUsed) &&
(_rtw_memcmp(psecuritypriv->PMKIDList[i].Bssid, bssid, ETH_ALEN) == _TRUE))
break;
else {
i++;
/* continue; */
}
} while (i < NUM_PMKID_CACHE);
if (i == NUM_PMKID_CACHE) {
i = -1;/* Could not find. */
} else {
/* There is one Pre-Authentication Key for the specific BSSID. */
}
return i;
}
int rtw_cached_pmkid(_adapter *Adapter, u8 *bssid)
{
return SecIsInPMKIDList(Adapter, bssid);
}
int rtw_rsn_sync_pmkid(_adapter *adapter, u8 *ie, uint ie_len, int i_ent)
{
struct security_priv *sec = &adapter->securitypriv;
struct rsne_info info;
u8 gm_cs[4];
int i;
rtw_rsne_info_parse(ie, ie_len, &info);
if (info.err) {
RTW_WARN(FUNC_ADPT_FMT" rtw_rsne_info_parse error\n"
, FUNC_ADPT_ARG(adapter));
return 0;
}
if (i_ent < 0 && info.pmkid_cnt == 0)
goto exit;
if (i_ent >= 0 && info.pmkid_cnt == 1 && _rtw_memcmp(info.pmkid_list, sec->PMKIDList[i_ent].PMKID, 16)) {
RTW_INFO(FUNC_ADPT_FMT" has carried the same PMKID:"KEY_FMT"\n"
, FUNC_ADPT_ARG(adapter), KEY_ARG(&sec->PMKIDList[i_ent].PMKID));
goto exit;
}
/* bakcup group mgmt cs */
if (info.gmcs)
_rtw_memcpy(gm_cs, info.gmcs, 4);
if (info.pmkid_cnt) {
RTW_INFO(FUNC_ADPT_FMT" remove original PMKID, count:%u\n"
, FUNC_ADPT_ARG(adapter), info.pmkid_cnt);
for (i = 0; i < info.pmkid_cnt; i++)
RTW_INFO(" "KEY_FMT"\n", KEY_ARG(info.pmkid_list + i * 16));
}
if (i_ent >= 0) {
RTW_INFO(FUNC_ADPT_FMT" append PMKID:"KEY_FMT"\n"
, FUNC_ADPT_ARG(adapter), KEY_ARG(sec->PMKIDList[i_ent].PMKID));
info.pmkid_cnt = 1; /* update new pmkid_cnt */
_rtw_memcpy(info.pmkid_list, sec->PMKIDList[i_ent].PMKID, 16);
} else
info.pmkid_cnt = 0; /* update new pmkid_cnt */
RTW_PUT_LE16(info.pmkid_list - 2, info.pmkid_cnt);
if (info.gmcs)
_rtw_memcpy(info.pmkid_list + 16 * info.pmkid_cnt, gm_cs, 4);
ie_len = 1 + 1 + 2 + 4
+ 2 + 4 * info.pcs_cnt
+ 2 + 4 * info.akm_cnt
+ 2
+ 2 + 16 * info.pmkid_cnt
+ (info.gmcs ? 4 : 0)
;
ie[1] = (u8)(ie_len - 2);
exit:
return ie_len;
}
sint rtw_restruct_sec_ie(_adapter *adapter, u8 *out_ie)
{
u8 authmode = 0x0;
uint ielength = 0;
int iEntry;
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
struct security_priv *psecuritypriv = &adapter->securitypriv;
uint ndisauthmode = psecuritypriv->ndisauthtype;
if ((ndisauthmode == Ndis802_11AuthModeWPA) || (ndisauthmode == Ndis802_11AuthModeWPAPSK))
authmode = _WPA_IE_ID_;
if ((ndisauthmode == Ndis802_11AuthModeWPA2) || (ndisauthmode == Ndis802_11AuthModeWPA2PSK))
authmode = _WPA2_IE_ID_;
if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
_rtw_memcpy(out_ie, psecuritypriv->wps_ie, psecuritypriv->wps_ie_len);
ielength = psecuritypriv->wps_ie_len;
} else if ((authmode == _WPA_IE_ID_) || (authmode == _WPA2_IE_ID_)) {
/* copy RSN or SSN */
_rtw_memcpy(out_ie, psecuritypriv->supplicant_ie, psecuritypriv->supplicant_ie[1] + 2);
/* debug for CONFIG_IEEE80211W
{
int jj;
printk("supplicant_ie_length=%d &&&&&&&&&&&&&&&&&&&\n", psecuritypriv->supplicant_ie[1]+2);
for(jj=0; jj < psecuritypriv->supplicant_ie[1]+2; jj++)
printk(" %02x ", psecuritypriv->supplicant_ie[jj]);
printk("\n");
}*/
ielength = psecuritypriv->supplicant_ie[1] + 2;
rtw_report_sec_ie(adapter, authmode, psecuritypriv->supplicant_ie);
}
if (authmode == WLAN_EID_RSN) {
iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid);
ielength = rtw_rsn_sync_pmkid(adapter, out_ie, ielength, iEntry);
}
return ielength;
}
void rtw_init_registrypriv_dev_network(_adapter *adapter)
{
struct registry_priv *pregistrypriv = &adapter->registrypriv;
WLAN_BSSID_EX *pdev_network = &pregistrypriv->dev_network;
u8 *myhwaddr = adapter_mac_addr(adapter);
_rtw_memcpy(pdev_network->MacAddress, myhwaddr, ETH_ALEN);
_rtw_memcpy(&pdev_network->Ssid, &pregistrypriv->ssid, sizeof(NDIS_802_11_SSID));
pdev_network->Configuration.Length = sizeof(NDIS_802_11_CONFIGURATION);
pdev_network->Configuration.BeaconPeriod = 100;
pdev_network->Configuration.FHConfig.Length = 0;
pdev_network->Configuration.FHConfig.HopPattern = 0;
pdev_network->Configuration.FHConfig.HopSet = 0;
pdev_network->Configuration.FHConfig.DwellTime = 0;
}
void rtw_update_registrypriv_dev_network(_adapter *adapter)
{
int sz = 0;
struct registry_priv *pregistrypriv = &adapter->registrypriv;
WLAN_BSSID_EX *pdev_network = &pregistrypriv->dev_network;
struct security_priv *psecuritypriv = &adapter->securitypriv;
struct wlan_network *cur_network = &adapter->mlmepriv.cur_network;
/* struct xmit_priv *pxmitpriv = &adapter->xmitpriv; */
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
#if 0
pxmitpriv->vcs_setting = pregistrypriv->vrtl_carrier_sense;
pxmitpriv->vcs = pregistrypriv->vcs_type;
pxmitpriv->vcs_type = pregistrypriv->vcs_type;
/* pxmitpriv->rts_thresh = pregistrypriv->rts_thresh; */
pxmitpriv->frag_len = pregistrypriv->frag_thresh;
adapter->qospriv.qos_option = pregistrypriv->wmm_enable;
#endif
pdev_network->Privacy = (psecuritypriv->dot11PrivacyAlgrthm > 0 ? 1 : 0) ; /* adhoc no 802.1x */
pdev_network->Rssi = 0;
switch (pregistrypriv->wireless_mode) {
case WIRELESS_11B:
pdev_network->NetworkTypeInUse = (Ndis802_11DS);
break;
case WIRELESS_11G:
case WIRELESS_11BG:
case WIRELESS_11_24N:
case WIRELESS_11G_24N:
case WIRELESS_11BG_24N:
pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24);
break;
case WIRELESS_11A:
case WIRELESS_11A_5N:
pdev_network->NetworkTypeInUse = (Ndis802_11OFDM5);
break;
case WIRELESS_11ABGN:
if (pregistrypriv->channel > 14)
pdev_network->NetworkTypeInUse = (Ndis802_11OFDM5);
else
pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24);
break;
default:
/* TODO */
break;
}
pdev_network->Configuration.DSConfig = (pregistrypriv->channel);
if (cur_network->network.InfrastructureMode == Ndis802_11IBSS) {
pdev_network->Configuration.ATIMWindow = (0);
if (pmlmeext->cur_channel != 0)
pdev_network->Configuration.DSConfig = pmlmeext->cur_channel;
else
pdev_network->Configuration.DSConfig = 1;
}
pdev_network->InfrastructureMode = (cur_network->network.InfrastructureMode);
/* 1. Supported rates */
/* 2. IE */
/* rtw_set_supported_rate(pdev_network->SupportedRates, pregistrypriv->wireless_mode) ; */ /* will be called in rtw_generate_ie */
sz = rtw_generate_ie(pregistrypriv);
pdev_network->IELength = sz;
pdev_network->Length = get_WLAN_BSSID_EX_sz((WLAN_BSSID_EX *)pdev_network);
/* notes: translate IELength & Length after assign the Length to cmdsz in createbss_cmd(); */
/* pdev_network->IELength = cpu_to_le32(sz); */
}
void rtw_get_encrypt_decrypt_from_registrypriv(_adapter *adapter)
{
}
/* the fucntion is at passive_level */
void rtw_joinbss_reset(_adapter *padapter)
{
u8 threshold;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
/* todo: if you want to do something io/reg/hw setting before join_bss, please add code here */
#ifdef CONFIG_80211N_HT
struct ht_priv *phtpriv = &pmlmepriv->htpriv;
pmlmepriv->num_FortyMHzIntolerant = 0;
pmlmepriv->num_sta_no_ht = 0;
phtpriv->ampdu_enable = _FALSE;/* reset to disabled */
#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
/* TH=1 => means that invalidate usb rx aggregation */
/* TH=0 => means that validate usb rx aggregation, use init value. */
if (phtpriv->ht_option) {
if (padapter->registrypriv.wifi_spec == 1)
threshold = 1;
else
threshold = 0;
rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold));
} else {
threshold = 1;
rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold));
}
#endif/* #if defined( CONFIG_USB_HCI) || defined (CONFIG_SDIO_HCI) */
#endif/* #ifdef CONFIG_80211N_HT */
}
#ifdef CONFIG_80211N_HT
void rtw_ht_use_default_setting(_adapter *padapter)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct ht_priv *phtpriv = &pmlmepriv->htpriv;
struct registry_priv *pregistrypriv = &padapter->registrypriv;
BOOLEAN bHwLDPCSupport = _FALSE, bHwSTBCSupport = _FALSE;
#ifdef CONFIG_BEAMFORMING
BOOLEAN bHwSupportBeamformer = _FALSE, bHwSupportBeamformee = _FALSE;
#endif /* CONFIG_BEAMFORMING */
if (pregistrypriv->wifi_spec)
phtpriv->bss_coexist = 1;
else
phtpriv->bss_coexist = 0;
phtpriv->sgi_40m = TEST_FLAG(pregistrypriv->short_gi, BIT1) ? _TRUE : _FALSE;
phtpriv->sgi_20m = TEST_FLAG(pregistrypriv->short_gi, BIT0) ? _TRUE : _FALSE;
/* LDPC support */
rtw_hal_get_def_var(padapter, HAL_DEF_RX_LDPC, (u8 *)&bHwLDPCSupport);
CLEAR_FLAGS(phtpriv->ldpc_cap);
if (bHwLDPCSupport) {
if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT4))
SET_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_RX);
}
rtw_hal_get_def_var(padapter, HAL_DEF_TX_LDPC, (u8 *)&bHwLDPCSupport);
if (bHwLDPCSupport) {
if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT5))
SET_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_TX);
}
if (phtpriv->ldpc_cap)
RTW_INFO("[HT] HAL Support LDPC = 0x%02X\n", phtpriv->ldpc_cap);
/* STBC */
rtw_hal_get_def_var(padapter, HAL_DEF_TX_STBC, (u8 *)&bHwSTBCSupport);
CLEAR_FLAGS(phtpriv->stbc_cap);
if (bHwSTBCSupport) {
if (TEST_FLAG(pregistrypriv->stbc_cap, BIT5))
SET_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX);
}
rtw_hal_get_def_var(padapter, HAL_DEF_RX_STBC, (u8 *)&bHwSTBCSupport);
if (bHwSTBCSupport) {
if (TEST_FLAG(pregistrypriv->stbc_cap, BIT4))
SET_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_RX);
}
if (phtpriv->stbc_cap)
RTW_INFO("[HT] HAL Support STBC = 0x%02X\n", phtpriv->stbc_cap);
/* Beamforming setting */
CLEAR_FLAGS(phtpriv->beamform_cap);
#ifdef CONFIG_BEAMFORMING
#ifdef RTW_BEAMFORMING_VERSION_2
/* only enable beamforming in STA client mode */
if (MLME_IS_STA(padapter) && !MLME_IS_GC(padapter)
&& !MLME_IS_ADHOC(padapter)
&& !MLME_IS_MESH(padapter))
#endif
{
rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMER, (u8 *)&bHwSupportBeamformer);
rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMEE, (u8 *)&bHwSupportBeamformee);
if (TEST_FLAG(pregistrypriv->beamform_cap, BIT4) && bHwSupportBeamformer) {
SET_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE);
RTW_INFO("[HT] HAL Support Beamformer\n");
}
if (TEST_FLAG(pregistrypriv->beamform_cap, BIT5) && bHwSupportBeamformee) {
SET_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE);
RTW_INFO("[HT] HAL Support Beamformee\n");
}
}
#endif /* CONFIG_BEAMFORMING */
}
void rtw_build_wmm_ie_ht(_adapter *padapter, u8 *out_ie, uint *pout_len)
{
unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00};
int out_len;
u8 *pframe;
if (padapter->mlmepriv.qospriv.qos_option == 0) {
out_len = *pout_len;
pframe = rtw_set_ie(out_ie + out_len, _VENDOR_SPECIFIC_IE_,
_WMM_IE_Length_, WMM_IE, pout_len);
padapter->mlmepriv.qospriv.qos_option = 1;
}
}
#if defined(CONFIG_80211N_HT)
/* the fucntion is >= passive_level */
unsigned int rtw_restructure_ht_ie(_adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len, u8 channel)
{
u32 ielen, out_len;
u32 rx_packet_offset, max_recvbuf_sz;
HT_CAP_AMPDU_FACTOR max_rx_ampdu_factor;
HT_CAP_AMPDU_DENSITY best_ampdu_density;
unsigned char *p, *pframe;
struct rtw_ieee80211_ht_cap ht_capie;
u8 cbw40_enable = 0, rf_type = 0, rf_num = 0, rx_stbc_nss = 0, rx_nss = 0;
struct registry_priv *pregistrypriv = &padapter->registrypriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct ht_priv *phtpriv = &pmlmepriv->htpriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter);
#ifdef CONFIG_80211AC_VHT
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv;
#endif /* CONFIG_80211AC_VHT */
phtpriv->ht_option = _FALSE;
out_len = *pout_len;
memset(&ht_capie, 0, sizeof(struct rtw_ieee80211_ht_cap));
ht_capie.cap_info = IEEE80211_HT_CAP_DSSSCCK40;
if (phtpriv->sgi_20m)
ht_capie.cap_info |= IEEE80211_HT_CAP_SGI_20;
/* check if 40MHz is allowed according to hal cap and registry */
if (hal_chk_bw_cap(padapter, BW_CAP_40M)) {
if (channel > 14) {
if (REGSTY_IS_BW_5G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_40))
cbw40_enable = 1;
} else {
if (REGSTY_IS_BW_2G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_40))
cbw40_enable = 1;
}
}
if (cbw40_enable) {
struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter);
RT_CHANNEL_INFO *chset = rfctl->channel_set;
u8 oper_bw = CHANNEL_WIDTH_20, oper_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
if (in_ie == NULL) {
/* TDLS: TODO 20/40 issue */
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
oper_bw = padapter->mlmeextpriv.cur_bwmode;
if (oper_bw > CHANNEL_WIDTH_40)
oper_bw = CHANNEL_WIDTH_40;
} else
/* TDLS: TODO 40? */
oper_bw = CHANNEL_WIDTH_40;
} else {
p = rtw_get_ie(in_ie, WLAN_EID_HT_OPERATION, &ielen, in_len);
if (p && ielen == HT_OP_IE_LEN) {
if (GET_HT_OP_ELE_STA_CHL_WIDTH(p + 2)) {
switch (GET_HT_OP_ELE_2ND_CHL_OFFSET(p + 2)) {
case SCA:
oper_bw = CHANNEL_WIDTH_40;
oper_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
break;
case SCB:
oper_bw = CHANNEL_WIDTH_40;
oper_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
break;
}
}
}
}
/* adjust bw to fit in channel plan setting */
if (oper_bw == CHANNEL_WIDTH_40
&& oper_offset != HAL_PRIME_CHNL_OFFSET_DONT_CARE /* check this because TDLS has no info to set offset */
&& (!rtw_chset_is_chbw_valid(chset, channel, oper_bw, oper_offset)
|| (IS_DFS_SLAVE_WITH_RD(rfctl)
&& !rtw_odm_dfs_domain_unknown(rfctl_to_dvobj(rfctl))
&& rtw_chset_is_chbw_non_ocp(chset, channel, oper_bw, oper_offset))
)
) {
oper_bw = CHANNEL_WIDTH_20;
oper_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
rtw_warn_on(!rtw_chset_is_chbw_valid(chset, channel, oper_bw, oper_offset));
if (IS_DFS_SLAVE_WITH_RD(rfctl) && !rtw_odm_dfs_domain_unknown(rfctl_to_dvobj(rfctl)))
rtw_warn_on(rtw_chset_is_chbw_non_ocp(chset, channel, oper_bw, oper_offset));
}
if (oper_bw == CHANNEL_WIDTH_40) {
ht_capie.cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
if (phtpriv->sgi_40m)
ht_capie.cap_info |= IEEE80211_HT_CAP_SGI_40;
}
cbw40_enable = oper_bw == CHANNEL_WIDTH_40 ? 1 : 0;
}
/* todo: disable SM power save mode */
ht_capie.cap_info |= IEEE80211_HT_CAP_SM_PS;
/* RX LDPC */
if (TEST_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_RX)) {
ht_capie.cap_info |= IEEE80211_HT_CAP_LDPC_CODING;
RTW_INFO("[HT] Declare supporting RX LDPC\n");
}
/* TX STBC */
if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX)) {
ht_capie.cap_info |= IEEE80211_HT_CAP_TX_STBC;
RTW_INFO("[HT] Declare supporting TX STBC\n");
}
/* RX STBC */
if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_RX)) {
if ((pregistrypriv->rx_stbc == 0x3) || /* enable for 2.4/5 GHz */
((channel <= 14) && (pregistrypriv->rx_stbc == 0x1)) || /* enable for 2.4GHz */
((channel > 14) && (pregistrypriv->rx_stbc == 0x2)) || /* enable for 5GHz */
(pregistrypriv->wifi_spec == 1)) {
/* HAL_DEF_RX_STBC means STBC RX spatial stream, todo: VHT 4 streams */
rtw_hal_get_def_var(padapter, HAL_DEF_RX_STBC, (u8 *)(&rx_stbc_nss));
SET_HT_CAP_ELE_RX_STBC(&ht_capie, rx_stbc_nss);
RTW_INFO("[HT] Declare supporting RX STBC = %d\n", rx_stbc_nss);
}
}
/* fill default supported_mcs_set */
_rtw_memcpy(ht_capie.supp_mcs_set, pmlmeext->default_supported_mcs_set, 16);
/* update default supported_mcs_set */
rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
rx_nss = rtw_min(rf_type_to_rf_rx_cnt(rf_type), hal_spec->rx_nss_num);
switch (rx_nss) {
case 1:
set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_1R);
break;
case 2:
#ifdef CONFIG_DISABLE_MCS13TO15
if (cbw40_enable && pregistrypriv->wifi_spec != 1)
set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_2R_13TO15_OFF);
else
#endif
set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_2R);
break;
case 3:
set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_3R);
break;
case 4:
set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_4R);
break;
default:
RTW_WARN("rf_type:%d or rx_nss:%u is not expected\n", rf_type, hal_spec->rx_nss_num);
}
{
rtw_hal_get_def_var(padapter, HAL_DEF_RX_PACKET_OFFSET, &rx_packet_offset);
rtw_hal_get_def_var(padapter, HAL_DEF_MAX_RECVBUF_SZ, &max_recvbuf_sz);
if (max_recvbuf_sz - rx_packet_offset >= (8191 - 256)) {
RTW_INFO("%s IEEE80211_HT_CAP_MAX_AMSDU is set\n", __FUNCTION__);
ht_capie.cap_info = ht_capie.cap_info | IEEE80211_HT_CAP_MAX_AMSDU;
}
}
/*
AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k
AMPDU_para [4:2]:Min MPDU Start Spacing
*/
/*
#if defined(CONFIG_RTL8188E) && defined(CONFIG_SDIO_HCI)
ht_capie.ampdu_params_info = 2;
#else
ht_capie.ampdu_params_info = (IEEE80211_HT_AMPDU_PARM_FACTOR&0x03);
#endif
*/
if (padapter->driver_rx_ampdu_factor != 0xFF)
max_rx_ampdu_factor = (HT_CAP_AMPDU_FACTOR)padapter->driver_rx_ampdu_factor;
else
rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor);
/* rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); */
ht_capie.ampdu_params_info = (max_rx_ampdu_factor & 0x03);
if (padapter->driver_rx_ampdu_spacing != 0xFF)
ht_capie.ampdu_params_info |= ((padapter->driver_rx_ampdu_spacing & 0x07) << 2);
else {
if (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_) {
/*
* Todo : Each chip must to ask DD , this chip best ampdu_density setting
* By yiwei.sun
*/
rtw_hal_get_def_var(padapter, HW_VAR_BEST_AMPDU_DENSITY, &best_ampdu_density);
ht_capie.ampdu_params_info |= (IEEE80211_HT_AMPDU_PARM_DENSITY & (best_ampdu_density << 2));
} else
ht_capie.ampdu_params_info |= (IEEE80211_HT_AMPDU_PARM_DENSITY & 0x00);
}
#ifdef CONFIG_BEAMFORMING
ht_capie.tx_BF_cap_info = 0;
/* HT Beamformer*/
if (TEST_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE)) {
/* Transmit NDP Capable */
SET_HT_CAP_TXBF_TRANSMIT_NDP_CAP(&ht_capie, 1);
/* Explicit Compressed Steering Capable */
SET_HT_CAP_TXBF_EXPLICIT_COMP_STEERING_CAP(&ht_capie, 1);
/* Compressed Steering Number Antennas */
SET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS(&ht_capie, 1);
rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMER_CAP, (u8 *)&rf_num);
SET_HT_CAP_TXBF_CHNL_ESTIMATION_NUM_ANTENNAS(&ht_capie, rf_num);
}
/* HT Beamformee */
if (TEST_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE)) {
/* Receive NDP Capable */
SET_HT_CAP_TXBF_RECEIVE_NDP_CAP(&ht_capie, 1);
/* Explicit Compressed Beamforming Feedback Capable */
SET_HT_CAP_TXBF_EXPLICIT_COMP_FEEDBACK_CAP(&ht_capie, 2);
rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMEE_CAP, (u8 *)&rf_num);
#ifdef CONFIG_80211AC_VHT
/* IOT action suggested by Yu Chen 2017/3/3 */
if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_BROADCOM) &&
!pvhtpriv->ap_is_mu_bfer)
rf_num = (rf_num >= 2 ? 2 : rf_num);
#endif
SET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS(&ht_capie, rf_num);
}
#endif/*CONFIG_BEAMFORMING*/
pframe = rtw_set_ie(out_ie + out_len, _HT_CAPABILITY_IE_,
sizeof(struct rtw_ieee80211_ht_cap), (unsigned char *)&ht_capie, pout_len);
phtpriv->ht_option = _TRUE;
if (in_ie != NULL) {
p = rtw_get_ie(in_ie, _HT_ADD_INFO_IE_, &ielen, in_len);
if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) {
out_len = *pout_len;
pframe = rtw_set_ie(out_ie + out_len, _HT_ADD_INFO_IE_, ielen, p + 2 , pout_len);
}
}
return phtpriv->ht_option;
}
/* the fucntion is > passive_level (in critical_section) */
void rtw_update_ht_cap(_adapter *padapter, u8 *pie, uint ie_len, u8 channel)
{
u8 *p, max_ampdu_sz;
int len;
/* struct sta_info *bmc_sta, *psta; */
struct rtw_ieee80211_ht_cap *pht_capie;
struct ieee80211_ht_addt_info *pht_addtinfo;
/* struct recv_reorder_ctrl *preorder_ctrl; */
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct ht_priv *phtpriv = &pmlmepriv->htpriv;
/* struct recv_priv *precvpriv = &padapter->recvpriv; */
struct registry_priv *pregistrypriv = &padapter->registrypriv;
/* struct wlan_network *pcur_network = &(pmlmepriv->cur_network);; */
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
u8 cbw40_enable = 0;
if (!phtpriv->ht_option)
return;
if ((!pmlmeinfo->HT_info_enable) || (!pmlmeinfo->HT_caps_enable))
return;
RTW_INFO("+rtw_update_ht_cap()\n");
/* maybe needs check if ap supports rx ampdu. */
if ((phtpriv->ampdu_enable == _FALSE) && (pregistrypriv->ampdu_enable == 1)) {
if (pregistrypriv->wifi_spec == 1) {
/* remove this part because testbed AP should disable RX AMPDU */
/* phtpriv->ampdu_enable = _FALSE; */
phtpriv->ampdu_enable = _TRUE;
} else
phtpriv->ampdu_enable = _TRUE;
}
/* check Max Rx A-MPDU Size */
len = 0;
p = rtw_get_ie(pie + sizeof(NDIS_802_11_FIXED_IEs), _HT_CAPABILITY_IE_, &len, ie_len - sizeof(NDIS_802_11_FIXED_IEs));
if (p && len > 0) {
pht_capie = (struct rtw_ieee80211_ht_cap *)(p + 2);
max_ampdu_sz = (pht_capie->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_FACTOR);
max_ampdu_sz = 1 << (max_ampdu_sz + 3); /* max_ampdu_sz (kbytes); */
/* RTW_INFO("rtw_update_ht_cap(): max_ampdu_sz=%d\n", max_ampdu_sz); */
phtpriv->rx_ampdu_maxlen = max_ampdu_sz;
}
len = 0;
p = rtw_get_ie(pie + sizeof(NDIS_802_11_FIXED_IEs), _HT_ADD_INFO_IE_, &len, ie_len - sizeof(NDIS_802_11_FIXED_IEs));
if (p && len > 0) {
pht_addtinfo = (struct ieee80211_ht_addt_info *)(p + 2);
/* todo: */
}
if (hal_chk_bw_cap(padapter, BW_CAP_40M)) {
if (channel > 14) {
if (REGSTY_IS_BW_5G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_40))
cbw40_enable = 1;
} else {
if (REGSTY_IS_BW_2G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_40))
cbw40_enable = 1;
}
}
/* update cur_bwmode & cur_ch_offset */
if ((cbw40_enable) &&
(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & BIT(1)) &&
(pmlmeinfo->HT_info.infos[0] & BIT(2))) {
struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter);
int i;
u8 rf_type = RF_1T1R;
u8 tx_nss = 0;
rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num);
/* update the MCS set */
for (i = 0; i < 16; i++)
pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= pmlmeext->default_supported_mcs_set[i];
/* update the MCS rates */
switch (tx_nss) {
case 1:
set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_1R);
break;
case 2:
#ifdef CONFIG_DISABLE_MCS13TO15
if (pmlmeext->cur_bwmode == CHANNEL_WIDTH_40 && pregistrypriv->wifi_spec != 1)
set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R_13TO15_OFF);
else
#endif
set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R);
break;
case 3:
set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_3R);
break;
case 4:
set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_4R);
break;
default:
RTW_WARN("rf_type:%d or tx_nss_num:%u is not expected\n", rf_type, hal_spec->tx_nss_num);
}
/* switch to the 40M Hz mode accoring to the AP */
/* pmlmeext->cur_bwmode = CHANNEL_WIDTH_40; */
switch ((pmlmeinfo->HT_info.infos[0] & 0x3)) {
case EXTCHNL_OFFSET_UPPER:
pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
break;
case EXTCHNL_OFFSET_LOWER:
pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
break;
default:
pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
break;
}
}
/* */
/* Config SM Power Save setting */
/* */
pmlmeinfo->SM_PS = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2;
if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) {
#if 0
u8 i;
/* update the MCS rates */
for (i = 0; i < 16; i++)
pmlmeinfo->HT_caps.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i];
#endif
RTW_INFO("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __FUNCTION__);
}
/* */
/* Config current HT Protection mode. */
/* */
pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3;
}
#endif
#ifdef CONFIG_TDLS
void rtw_issue_addbareq_cmd_tdls(_adapter *padapter, struct xmit_frame *pxmitframe)
{
struct pkt_attrib *pattrib = &pxmitframe->attrib;
struct sta_info *ptdls_sta = NULL;
u8 issued;
int priority;
struct ht_priv *phtpriv;
priority = pattrib->priority;
if (pattrib->direct_link == _TRUE) {
ptdls_sta = rtw_get_stainfo(&padapter->stapriv, pattrib->dst);
if ((ptdls_sta != NULL) && (ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE)) {
phtpriv = &ptdls_sta->htpriv;
if ((phtpriv->ht_option == _TRUE) && (phtpriv->ampdu_enable == _TRUE)) {
issued = (phtpriv->agg_enable_bitmap >> priority) & 0x1;
issued |= (phtpriv->candidate_tid_bitmap >> priority) & 0x1;
if (0 == issued) {
RTW_INFO("[%s], p=%d\n", __FUNCTION__, priority);
ptdls_sta->htpriv.candidate_tid_bitmap |= BIT((u8)priority);
rtw_addbareq_cmd(padapter, (u8)priority, pattrib->dst);
}
}
}
}
}
#endif /* CONFIG_TDLS */
#ifdef CONFIG_80211N_HT
void rtw_issue_addbareq_cmd(_adapter *padapter, struct xmit_frame *pxmitframe)
{
u8 issued;
int priority;
struct sta_info *psta = NULL;
struct ht_priv *phtpriv;
struct pkt_attrib *pattrib = &pxmitframe->attrib;
s32 bmcst = IS_MCAST(pattrib->ra);
/* if(bmcst || (padapter->mlmepriv.LinkDetectInfo.bTxBusyTraffic == _FALSE)) */
if (bmcst || (padapter->mlmepriv.LinkDetectInfo.NumTxOkInPeriod < 100))
return;
priority = pattrib->priority;
#ifdef CONFIG_TDLS
rtw_issue_addbareq_cmd_tdls(padapter, pxmitframe);
#endif /* CONFIG_TDLS */
psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra);
if (pattrib->psta != psta) {
RTW_INFO("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta);
return;
}
if (psta == NULL) {
RTW_INFO("%s, psta==NUL\n", __func__);
return;
}
if (!(psta->state & _FW_LINKED)) {
RTW_INFO("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state);
return;
}
phtpriv = &psta->htpriv;
if ((phtpriv->ht_option == _TRUE) && (phtpriv->ampdu_enable == _TRUE)) {
issued = (phtpriv->agg_enable_bitmap >> priority) & 0x1;
issued |= (phtpriv->candidate_tid_bitmap >> priority) & 0x1;
if (0 == issued) {
RTW_INFO("rtw_issue_addbareq_cmd, p=%d\n", priority);
psta->htpriv.candidate_tid_bitmap |= BIT((u8)priority);
rtw_addbareq_cmd(padapter, (u8) priority, pattrib->ra);
}
}
}
#endif /* CONFIG_80211N_HT */
void rtw_append_exented_cap(_adapter *padapter, u8 *out_ie, uint *pout_len)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct ht_priv *phtpriv = &pmlmepriv->htpriv;
#ifdef CONFIG_80211AC_VHT
struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv;
#endif /* CONFIG_80211AC_VHT */
u8 cap_content[8] = { 0 };
u8 *pframe;
u8 null_content[8] = {0};
if (phtpriv->bss_coexist)
SET_EXT_CAPABILITY_ELE_BSS_COEXIST(cap_content, 1);
#ifdef CONFIG_80211AC_VHT
if (pvhtpriv->vht_option)
SET_EXT_CAPABILITY_ELE_OP_MODE_NOTIF(cap_content, 1);
#endif /* CONFIG_80211AC_VHT */
#ifdef CONFIG_RTW_WNM
rtw_wnm_set_ext_cap_btm(cap_content, 1);
#endif
/*
From 802.11 specification,if a STA does not support any of capabilities defined
in the Extended Capabilities element, then the STA is not required to
transmit the Extended Capabilities element.
*/
if (_FALSE == _rtw_memcmp(cap_content, null_content, 8))
pframe = rtw_set_ie(out_ie + *pout_len, EID_EXTCapability, 8, cap_content , pout_len);
}
#endif
#ifdef CONFIG_LAYER2_ROAMING
inline void rtw_set_to_roam(_adapter *adapter, u8 to_roam)
{
if (to_roam == 0)
adapter->mlmepriv.to_join = _FALSE;
adapter->mlmepriv.to_roam = to_roam;
}
inline u8 rtw_dec_to_roam(_adapter *adapter)
{
adapter->mlmepriv.to_roam--;
return adapter->mlmepriv.to_roam;
}
inline u8 rtw_to_roam(_adapter *adapter)
{
return adapter->mlmepriv.to_roam;
}
void rtw_roaming(_adapter *padapter, struct wlan_network *tgt_network)
{
_irqL irqL;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
_enter_critical_bh(&pmlmepriv->lock, &irqL);
_rtw_roaming(padapter, tgt_network);
_exit_critical_bh(&pmlmepriv->lock, &irqL);
}
void _rtw_roaming(_adapter *padapter, struct wlan_network *tgt_network)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wlan_network *cur_network = &pmlmepriv->cur_network;
int do_join_r;
if (0 < rtw_to_roam(padapter)) {
RTW_INFO("roaming from %s("MAC_FMT"), length:%d\n",
cur_network->network.Ssid.Ssid, MAC_ARG(cur_network->network.MacAddress),
cur_network->network.Ssid.SsidLength);
_rtw_memcpy(&pmlmepriv->assoc_ssid, &cur_network->network.Ssid, sizeof(NDIS_802_11_SSID));
pmlmepriv->assoc_by_bssid = _FALSE;
#ifdef CONFIG_WAPI_SUPPORT
rtw_wapi_return_all_sta_info(padapter);
#endif
while (1) {
do_join_r = rtw_do_join(padapter);
if (_SUCCESS == do_join_r)
break;
else {
RTW_INFO("roaming do_join return %d\n", do_join_r);
rtw_dec_to_roam(padapter);
if (rtw_to_roam(padapter) > 0)
continue;
else {
RTW_INFO("%s(%d) -to roaming fail, indicate_disconnect\n", __FUNCTION__, __LINE__);
#ifdef CONFIG_RTW_80211R
rtw_ft_clr_flags(padapter, RTW_FT_PEER_EN|RTW_FT_PEER_OTD_EN);
rtw_ft_reset_status(padapter);
#endif
rtw_indicate_disconnect(padapter, 0, _FALSE);
break;
}
}
}
}
}
#endif /* CONFIG_LAYER2_ROAMING */
bool rtw_adjust_chbw(_adapter *adapter, u8 req_ch, u8 *req_bw, u8 *req_offset)
{
struct registry_priv *regsty = adapter_to_regsty(adapter);
u8 allowed_bw;
if (req_ch < 14)
allowed_bw = REGSTY_BW_2G(regsty);
else if (req_ch == 14)
allowed_bw = CHANNEL_WIDTH_20;
else
allowed_bw = REGSTY_BW_5G(regsty);
allowed_bw = hal_largest_bw(adapter, allowed_bw);
if (allowed_bw == CHANNEL_WIDTH_80 && *req_bw > CHANNEL_WIDTH_80)
*req_bw = CHANNEL_WIDTH_80;
else if (allowed_bw == CHANNEL_WIDTH_40 && *req_bw > CHANNEL_WIDTH_40)
*req_bw = CHANNEL_WIDTH_40;
else if (allowed_bw == CHANNEL_WIDTH_20 && *req_bw > CHANNEL_WIDTH_20) {
*req_bw = CHANNEL_WIDTH_20;
*req_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
} else
return _FALSE;
return _TRUE;
}
sint rtw_linked_check(_adapter *padapter)
{
if (MLME_IS_AP(padapter) || MLME_IS_MESH(padapter)
|| MLME_IS_ADHOC(padapter) || MLME_IS_ADHOC_MASTER(padapter)
) {
if (padapter->stapriv.asoc_sta_count > 2)
return _TRUE;
} else {
/* Station mode */
if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == _TRUE)
return _TRUE;
}
return _FALSE;
}
/*#define DBG_ADAPTER_STATE_CHK*/
u8 rtw_is_adapter_up(_adapter *padapter)
{
if (padapter == NULL)
return _FALSE;
if (RTW_CANNOT_RUN(padapter)) {
#ifdef DBG_ADAPTER_STATE_CHK
RTW_INFO(FUNC_ADPT_FMT " FALSE -bDriverStopped(%s) bSurpriseRemoved(%s)\n"
, FUNC_ADPT_ARG(padapter)
, rtw_is_drv_stopped(padapter) ? "True" : "False"
, rtw_is_surprise_removed(padapter) ? "True" : "False");
#endif
return _FALSE;
}
if (!rtw_is_hw_init_completed(padapter)) {
#ifdef DBG_ADAPTER_STATE_CHK
RTW_INFO(FUNC_ADPT_FMT " FALSE -(hw_init_completed == _FALSE)\n", FUNC_ADPT_ARG(padapter));
#endif
return _FALSE;
}
if (padapter->bup == _FALSE) {
#ifdef DBG_ADAPTER_STATE_CHK
RTW_INFO(FUNC_ADPT_FMT " FALSE -(bup == _FALSE)\n", FUNC_ADPT_ARG(padapter));
#endif
return _FALSE;
}
return _TRUE;
}
bool is_miracast_enabled(_adapter *adapter)
{
bool enabled = 0;
#ifdef CONFIG_WFD
struct wifi_display_info *wfdinfo = &adapter->wfd_info;
enabled = (wfdinfo->stack_wfd_mode & (MIRACAST_SOURCE | MIRACAST_SINK))
|| (wfdinfo->op_wfd_mode & (MIRACAST_SOURCE | MIRACAST_SINK));
#endif
return enabled;
}
bool rtw_chk_miracast_mode(_adapter *adapter, u8 mode)
{
bool ret = 0;
#ifdef CONFIG_WFD
struct wifi_display_info *wfdinfo = &adapter->wfd_info;
ret = (wfdinfo->stack_wfd_mode & mode) || (wfdinfo->op_wfd_mode & mode);
#endif
return ret;
}
const char *get_miracast_mode_str(int mode)
{
if (mode == MIRACAST_SOURCE)
return "SOURCE";
else if (mode == MIRACAST_SINK)
return "SINK";
else if (mode == (MIRACAST_SOURCE | MIRACAST_SINK))
return "SOURCE&SINK";
else if (mode == MIRACAST_DISABLED)
return "DISABLED";
else
return "INVALID";
}
#ifdef CONFIG_WFD
static bool wfd_st_match_rule(_adapter *adapter, u8 *local_naddr, u8 *local_port, u8 *remote_naddr, u8 *remote_port)
{
struct wifi_display_info *wfdinfo = &adapter->wfd_info;
if (ntohs(*((u16 *)local_port)) == wfdinfo->rtsp_ctrlport
|| ntohs(*((u16 *)local_port)) == wfdinfo->tdls_rtsp_ctrlport
|| ntohs(*((u16 *)remote_port)) == wfdinfo->peer_rtsp_ctrlport)
return _TRUE;
return _FALSE;
}
static struct st_register wfd_st_reg = {
.s_proto = 0x06,
.rule = wfd_st_match_rule,
};
#endif /* CONFIG_WFD */
inline void rtw_wfd_st_switch(struct sta_info *sta, bool on)
{
#ifdef CONFIG_WFD
if (on)
rtw_st_ctl_register(&sta->st_ctl, SESSION_TRACKER_REG_ID_WFD, &wfd_st_reg);
else
rtw_st_ctl_unregister(&sta->st_ctl, SESSION_TRACKER_REG_ID_WFD);
#endif
}
void dump_arp_pkt(void *sel, u8 *da, u8 *sa, u8 *arp, bool tx)
{
RTW_PRINT_SEL(sel, "%s ARP da="MAC_FMT", sa="MAC_FMT"\n"
, tx ? "send" : "recv", MAC_ARG(da), MAC_ARG(sa));
RTW_PRINT_SEL(sel, "htype=%u, ptype=0x%04x, hlen=%u, plen=%u, oper=%u\n"
, GET_ARP_HTYPE(arp), GET_ARP_PTYPE(arp), GET_ARP_HLEN(arp)
, GET_ARP_PLEN(arp), GET_ARP_OPER(arp));
RTW_PRINT_SEL(sel, "sha="MAC_FMT", spa="IP_FMT"\n"
, MAC_ARG(ARP_SENDER_MAC_ADDR(arp)), IP_ARG(ARP_SENDER_IP_ADDR(arp)));
RTW_PRINT_SEL(sel, "tha="MAC_FMT", tpa="IP_FMT"\n"
, MAC_ARG(ARP_TARGET_MAC_ADDR(arp)), IP_ARG(ARP_TARGET_IP_ADDR(arp)));
}