diff options
Diffstat (limited to 'drivers/net/wireless/rtlwifi/base.c')
-rw-r--r-- | drivers/net/wireless/rtlwifi/base.c | 646 |
1 files changed, 419 insertions, 227 deletions
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 8234cdb03b11..58ba71830886 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * @@ -34,7 +30,7 @@ #include "cam.h" #include "ps.h" #include "regd.h" - +#include "pci.h" #include <linux/ip.h> #include <linux/module.h> #include <linux/udp.h> @@ -211,7 +207,6 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, *highest supported RX rate */ if (rtlpriv->dm.supp_phymode_switch) { - RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "Support phy mode switch\n"); @@ -244,6 +239,83 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, } } +static void _rtl_init_hw_vht_capab(struct ieee80211_hw *hw, + struct ieee80211_sta_vht_cap *vht_cap) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { + u16 mcs_map; + + vht_cap->vht_supported = true; + vht_cap->cap = + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 | + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | + IEEE80211_VHT_CAP_SHORT_GI_80 | + IEEE80211_VHT_CAP_TXSTBC | + IEEE80211_VHT_CAP_RXSTBC_1 | + IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | + IEEE80211_VHT_CAP_HTC_VHT | + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | + IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | + IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | + 0; + + mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | + IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 14; + + vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->vht_mcs.rx_highest = + cpu_to_le16(MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9); + vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->vht_mcs.tx_highest = + cpu_to_le16(MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9); + } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { + u16 mcs_map; + + vht_cap->vht_supported = true; + vht_cap->cap = + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 | + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | + IEEE80211_VHT_CAP_SHORT_GI_80 | + IEEE80211_VHT_CAP_TXSTBC | + IEEE80211_VHT_CAP_RXSTBC_1 | + IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | + IEEE80211_VHT_CAP_HTC_VHT | + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | + IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | + IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | + 0; + + mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 2 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 14; + + vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->vht_mcs.rx_highest = + cpu_to_le16(MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9); + vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); + vht_cap->vht_mcs.tx_highest = + cpu_to_le16(MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9); + } +} + static void _rtl_init_mac80211(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -252,9 +324,8 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct ieee80211_supported_band *sband; - - if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY && rtlhal->bandset == - BAND_ON_BOTH) { + if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY && + rtlhal->bandset == BAND_ON_BOTH) { /* 1: 2.4 G bands */ /* <1> use mac->bands as mem for hw->wiphy->bands */ sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); @@ -282,6 +353,7 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) /* <3> init ht cap base on ant_num */ _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + _rtl_init_hw_vht_capab(hw, &sband->vht_cap); /* <4> set mac->sband to wiphy->sband */ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; } else { @@ -292,8 +364,8 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) /* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] * to default value(1T1R) */ memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), - &rtl_band_2ghz, - sizeof(struct ieee80211_supported_band)); + &rtl_band_2ghz, + sizeof(struct ieee80211_supported_band)); /* <3> init ht cap base on ant_num */ _rtl_init_hw_ht_capab(hw, &sband->ht_cap); @@ -307,12 +379,13 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) /* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ] * to default value(1T1R) */ memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]), - &rtl_band_5ghz, - sizeof(struct ieee80211_supported_band)); + &rtl_band_5ghz, + sizeof(struct ieee80211_supported_band)); /* <3> init ht cap base on ant_num */ _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + _rtl_init_hw_vht_capab(hw, &sband->vht_cap); /* <4> set mac->sband to wiphy->sband */ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; } else { @@ -326,7 +399,6 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_CONNECTION_MONITOR | /* IEEE80211_HW_SUPPORTS_CQM_RSSI | */ - IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_MFP_CAPABLE | IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0; @@ -336,7 +408,6 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) IEEE80211_HW_PS_NULLFUNC_STACK | /* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */ 0; - hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | @@ -344,8 +415,10 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) BIT(NL80211_IFTYPE_MESH_POINT) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); - hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + + hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + hw->wiphy->rts_threshold = 2347; hw->queues = AC_MAX; @@ -358,6 +431,21 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) /* hw->max_rates = 1; */ hw->sta_data_size = sizeof(struct rtl_sta_info); +/* wowlan is not supported by kernel if CONFIG_PM is not defined */ +#ifdef CONFIG_PM + if (rtlpriv->psc.wo_wlan_mode) { + if (rtlpriv->psc.wo_wlan_mode & WAKE_ON_MAGIC_PACKET) + rtlpriv->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT; + if (rtlpriv->psc.wo_wlan_mode & WAKE_ON_PATTERN_MATCH) { + rtlpriv->wowlan.n_patterns = + MAX_SUPPORT_WOL_PATTERN_NUM; + rtlpriv->wowlan.pattern_min_len = MIN_WOL_PATTERN_SIZE; + rtlpriv->wowlan.pattern_max_len = MAX_WOL_PATTERN_SIZE; + } + hw->wiphy->wowlan = &rtlpriv->wowlan; + } +#endif + /* <6> mac address */ if (is_valid_ether_addr(rtlefuse->dev_addr)) { SET_IEEE80211_PERM_ADDR(hw, rtlefuse->dev_addr); @@ -366,7 +454,6 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) get_random_bytes((rtlmac1 + (ETH_ALEN - 1)), 1); SET_IEEE80211_PERM_ADDR(hw, rtlmac1); } - } static void _rtl_init_deferred_work(struct ieee80211_hw *hw) @@ -378,10 +465,9 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw) rtl_watch_dog_timer_callback, (unsigned long)hw); setup_timer(&rtlpriv->works.dualmac_easyconcurrent_retrytimer, rtl_easy_concurrent_retrytimer_callback, (unsigned long)hw); - /* <2> work queue */ rtlpriv->works.hw = hw; - rtlpriv->works.rtl_wq = alloc_workqueue("%s", 0, 0, rtlpriv->cfg->name); + rtlpriv->works.rtl_wq = alloc_workqueue(rtlpriv->cfg->name, 0, 0); INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq, (void *)rtl_watchdog_wq_callback); INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq, @@ -424,7 +510,7 @@ void rtl_init_rfkill(struct ieee80211_hw *hw) radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid); if (valid) { - pr_info("wireless switch is %s\n", + pr_info("rtlwifi: wireless switch is %s\n", rtlpriv->rfkill.rfkill_state ? "on" : "off"); rtlpriv->rfkill.rfkill_state = radio_state; @@ -466,22 +552,18 @@ int rtl_init_core(struct ieee80211_hw *hw) /* <4> locks */ mutex_init(&rtlpriv->locks.conf_mutex); - mutex_init(&rtlpriv->locks.ps_mutex); spin_lock_init(&rtlpriv->locks.ips_lock); spin_lock_init(&rtlpriv->locks.irq_th_lock); - spin_lock_init(&rtlpriv->locks.irq_pci_lock); - spin_lock_init(&rtlpriv->locks.tx_lock); spin_lock_init(&rtlpriv->locks.h2c_lock); spin_lock_init(&rtlpriv->locks.rf_ps_lock); spin_lock_init(&rtlpriv->locks.rf_lock); spin_lock_init(&rtlpriv->locks.waitq_lock); spin_lock_init(&rtlpriv->locks.entry_list_lock); - spin_lock_init(&rtlpriv->locks.fw_ps_lock); spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock); spin_lock_init(&rtlpriv->locks.check_sendpkt_lock); spin_lock_init(&rtlpriv->locks.fw_ps_lock); spin_lock_init(&rtlpriv->locks.lps_lock); - + spin_lock_init(&rtlpriv->locks.iqk_lock); /* <5> init list */ INIT_LIST_HEAD(&rtlpriv->entry_list); @@ -539,6 +621,7 @@ static void _rtl_query_shortgi(struct ieee80211_hw *hw, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); u8 rate_flag = info->control.rates[0].flags; u8 sgi_40 = 0, sgi_20 = 0, bw_40 = 0; + u8 sgi_80 = 0, bw_80 = 0; tcb_desc->use_shortgi = false; if (sta == NULL) @@ -546,24 +629,35 @@ static void _rtl_query_shortgi(struct ieee80211_hw *hw, sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; + sgi_80 = sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80; - if (!(sta->ht_cap.ht_supported)) + if ((!sta->ht_cap.ht_supported) && (!sta->vht_cap.vht_supported)) return; if (!sgi_40 && !sgi_20) return; - if (mac->opmode == NL80211_IFTYPE_STATION) + if (mac->opmode == NL80211_IFTYPE_STATION) { bw_40 = mac->bw_40; - else if (mac->opmode == NL80211_IFTYPE_AP || + bw_80 = mac->bw_80; + } else if (mac->opmode == NL80211_IFTYPE_AP || mac->opmode == NL80211_IFTYPE_ADHOC || - mac->opmode == NL80211_IFTYPE_MESH_POINT) - bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; + mac->opmode == NL80211_IFTYPE_MESH_POINT) { + bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; + bw_80 = sta->vht_cap.vht_supported; + } - if (bw_40 && sgi_40) - tcb_desc->use_shortgi = true; - else if ((bw_40 == false) && sgi_20) - tcb_desc->use_shortgi = true; + if (bw_80) { + if (sgi_80) + tcb_desc->use_shortgi = true; + else + tcb_desc->use_shortgi = false; + } else { + if (bw_40 && sgi_40) + tcb_desc->use_shortgi = true; + else if (!bw_40 && sgi_20) + tcb_desc->use_shortgi = true; + } if (!(rate_flag & IEEE80211_TX_RC_SHORT_GI)) tcb_desc->use_shortgi = false; @@ -613,7 +707,7 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, if (mac->opmode == NL80211_IFTYPE_STATION) { tcb_desc->ratr_index = 0; } else if (mac->opmode == NL80211_IFTYPE_ADHOC || - mac->opmode == NL80211_IFTYPE_MESH_POINT) { + mac->opmode == NL80211_IFTYPE_MESH_POINT) { if (tcb_desc->multicast || tcb_desc->broadcast) { tcb_desc->hw_rate = rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M]; @@ -634,7 +728,13 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, mac->opmode == NL80211_IFTYPE_MESH_POINT) { tcb_desc->mac_id = 0; - if (mac->mode == WIRELESS_MODE_N_24G) + if (mac->mode == WIRELESS_MODE_AC_5G) + tcb_desc->ratr_index = + RATR_INX_WIRELESS_AC_5N; + else if (mac->mode == WIRELESS_MODE_AC_24G) + tcb_desc->ratr_index = + RATR_INX_WIRELESS_AC_24N; + else if (mac->mode == WIRELESS_MODE_N_24G) tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB; else if (mac->mode == WIRELESS_MODE_N_5G) tcb_desc->ratr_index = RATR_INX_WIRELESS_NG; @@ -644,8 +744,9 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, tcb_desc->ratr_index = RATR_INX_WIRELESS_B; else if (mac->mode & WIRELESS_MODE_A) tcb_desc->ratr_index = RATR_INX_WIRELESS_G; + } else if (mac->opmode == NL80211_IFTYPE_AP || - mac->opmode == NL80211_IFTYPE_ADHOC) { + mac->opmode == NL80211_IFTYPE_ADHOC) { if (NULL != sta) { if (sta->aid > 0) tcb_desc->mac_id = sta->aid + 1; @@ -671,7 +772,8 @@ static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw, if (mac->opmode == NL80211_IFTYPE_AP || mac->opmode == NL80211_IFTYPE_ADHOC || mac->opmode == NL80211_IFTYPE_MESH_POINT) { - if (sta->bandwidth == IEEE80211_STA_RX_BW_20) + if (!(sta->ht_cap.ht_supported) || + !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) return; } else if (mac->opmode == NL80211_IFTYPE_STATION) { if (!mac->bw_40 || !(sta->ht_cap.ht_supported)) @@ -684,16 +786,74 @@ static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw, if (tcb_desc->hw_rate <= rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M]) return; - tcb_desc->packet_bw = true; + tcb_desc->packet_bw = HT_CHANNEL_WIDTH_20_40; + + if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8812AE || + rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8821AE) { + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC || + mac->opmode == NL80211_IFTYPE_MESH_POINT) { + if (!(sta->vht_cap.vht_supported)) + return; + } else if (mac->opmode == NL80211_IFTYPE_STATION) { + if (!mac->bw_80 || + !(sta->vht_cap.vht_supported)) + return; + } + if (tcb_desc->hw_rate <= + rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15]) + return; + tcb_desc->packet_bw = HT_CHANNEL_WIDTH_80; + } } -static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw) +static u8 _rtl_get_vht_highest_n_rate(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); u8 hw_rate; + u16 tx_mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.tx_mcs_map); + + if ((get_rf_type(rtlphy) == RF_2T2R) && + (tx_mcs_map & 0x000c) != 0x000c) { + if ((tx_mcs_map & 0x000c) >> 2 == + IEEE80211_VHT_MCS_SUPPORT_0_7) + hw_rate = + rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS7]; + else if ((tx_mcs_map & 0x000c) >> 2 == + IEEE80211_VHT_MCS_SUPPORT_0_8) + hw_rate = + rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS9]; + else + hw_rate = + rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS9]; + } else { + if ((tx_mcs_map & 0x0003) == + IEEE80211_VHT_MCS_SUPPORT_0_7) + hw_rate = + rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS7]; + else if ((tx_mcs_map & 0x0003) == + IEEE80211_VHT_MCS_SUPPORT_0_8) + hw_rate = + rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS9]; + else + hw_rate = + rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS9]; + } + + return hw_rate; +} + +static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &rtlpriv->phy; + u8 hw_rate; - if (get_rf_type(rtlphy) == RF_2T2R) + if ((get_rf_type(rtlphy) == RF_2T2R) && + (sta->ht_cap.mcs.rx_mask[1] != 0)) hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15]; else hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS7]; @@ -801,9 +961,7 @@ int rtlwifi_rate_mapping(struct ieee80211_hw *hw, break; } } - } else { - switch (desc_rate) { case DESC92_RATEMCS0: rate_idx = 0; @@ -862,31 +1020,6 @@ int rtlwifi_rate_mapping(struct ieee80211_hw *hw, } EXPORT_SYMBOL(rtlwifi_rate_mapping); -bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - struct rtl_priv *rtlpriv = rtl_priv(hw); - __le16 fc = rtl_get_fc(skb); - - if (rtlpriv->dm.supp_phymode_switch && - mac->link_state < MAC80211_LINKED && - (ieee80211_is_auth(fc) || ieee80211_is_probe_req(fc))) { - if (rtlpriv->cfg->ops->chk_switch_dmdp) - rtlpriv->cfg->ops->chk_switch_dmdp(hw); - } - if (ieee80211_is_auth(fc)) { - RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n"); - rtl_ips_nic_on(hw); - - mac->link_state = MAC80211_LINKING; - /* Dual mac */ - rtlpriv->phy.need_iqk = true; - } - - return true; -} -EXPORT_SYMBOL_GPL(rtl_tx_mgmt_proc); - void rtl_get_tcb_desc(struct ieee80211_hw *hw, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, @@ -896,13 +1029,11 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); struct ieee80211_hdr *hdr = rtl_get_hdr(skb); struct ieee80211_rate *txrate; - __le16 fc = hdr->frame_control; + __le16 fc = rtl_get_fc(skb); txrate = ieee80211_get_tx_rate(hw, info); if (txrate) tcb_desc->hw_rate = txrate->hw_value; - else - tcb_desc->hw_rate = 0; if (ieee80211_is_data(fc)) { /* @@ -929,15 +1060,21 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, *and N rate will all be controlled by FW *when tcb_desc->use_driver_rate = false */ - if (sta && (sta->ht_cap.ht_supported)) { - tcb_desc->hw_rate = _rtl_get_highest_n_rate(hw); + if (sta && sta->vht_cap.vht_supported) { + tcb_desc->hw_rate = + _rtl_get_vht_highest_n_rate(hw, sta); } else { - if (rtlmac->mode == WIRELESS_MODE_B) { + if (sta && (sta->ht_cap.ht_supported)) { tcb_desc->hw_rate = - rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]; + _rtl_get_highest_n_rate(hw, sta); } else { - tcb_desc->hw_rate = - rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M]; + if (rtlmac->mode == WIRELESS_MODE_B) { + tcb_desc->hw_rate = + rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]; + } else { + tcb_desc->hw_rate = + rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M]; + } } } } @@ -962,54 +1099,58 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, } EXPORT_SYMBOL(rtl_get_tcb_desc); -static bool addbareq_rx(struct ieee80211_hw *hw, struct sk_buff *skb) +bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb) { + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_priv *rtlpriv = rtl_priv(hw); - struct ieee80211_sta *sta = NULL; - struct ieee80211_hdr *hdr = rtl_get_hdr(skb); - struct rtl_sta_info *sta_entry = NULL; - struct ieee80211_mgmt *mgmt = (void *)skb->data; - u16 capab = 0, tid = 0; - struct rtl_tid_data *tid_data; - struct sk_buff *skb_delba = NULL; - struct ieee80211_rx_status rx_status = { 0 }; + __le16 fc = rtl_get_fc(skb); - rcu_read_lock(); - sta = rtl_find_sta(hw, hdr->addr3); - if (sta == NULL) { - RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_EMERG, - "sta is NULL\n"); - rcu_read_unlock(); - return true; + if (rtlpriv->dm.supp_phymode_switch && + mac->link_state < MAC80211_LINKED && + (ieee80211_is_auth(fc) || ieee80211_is_probe_req(fc))) { + if (rtlpriv->cfg->ops->chk_switch_dmdp) + rtlpriv->cfg->ops->chk_switch_dmdp(hw); } + if (ieee80211_is_auth(fc)) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n"); + rtl_ips_nic_on(hw); + + mac->link_state = MAC80211_LINKING; + /* Dul mac */ + rtlpriv->phy.need_iqk = true; - sta_entry = (struct rtl_sta_info *)sta->drv_priv; - if (!sta_entry) { - rcu_read_unlock(); - return true; } - capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); - tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; - tid_data = &sta_entry->tids[tid]; - if (tid_data->agg.rx_agg_state == RTL_RX_AGG_START) { - skb_delba = rtl_make_del_ba(hw, hdr->addr2, hdr->addr3, tid); - if (skb_delba) { - rx_status.freq = hw->conf.chandef.chan->center_freq; - rx_status.band = hw->conf.chandef.chan->band; - rx_status.flag |= RX_FLAG_DECRYPTED; - rx_status.flag |= RX_FLAG_MACTIME_END; - rx_status.rate_idx = 0; - rx_status.signal = 50 + 10; - memcpy(IEEE80211_SKB_RXCB(skb_delba), &rx_status, - sizeof(rx_status)); - RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, - "fake del\n", skb_delba->data, - skb_delba->len); - ieee80211_rx_irqsafe(hw, skb_delba); - } + + return true; +} +EXPORT_SYMBOL_GPL(rtl_tx_mgmt_proc); + +struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw, u8 *sa, + u8 *bssid, u16 tid); + +static void process_agg_start(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u16 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_rx_status rx_status = { 0 }; + struct sk_buff *skb_delba = NULL; + + skb_delba = rtl_make_del_ba(hw, hdr->addr2, hdr->addr3, tid); + if (skb_delba) { + rx_status.freq = hw->conf.chandef.chan->center_freq; + rx_status.band = hw->conf.chandef.chan->band; + rx_status.flag |= RX_FLAG_DECRYPTED; + rx_status.flag |= RX_FLAG_MACTIME_START; + rx_status.rate_idx = 0; + rx_status.signal = 50 + 10; + memcpy(IEEE80211_SKB_RXCB(skb_delba), + &rx_status, sizeof(rx_status)); + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, + "fake del\n", + skb_delba->data, + skb_delba->len); + ieee80211_rx_irqsafe(hw, skb_delba); } - rcu_read_unlock(); - return false; } bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) @@ -1017,8 +1158,8 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct ieee80211_hdr *hdr = rtl_get_hdr(skb); struct rtl_priv *rtlpriv = rtl_priv(hw); - __le16 fc = hdr->frame_control; - u8 *act = (u8 *)skb->data + MAC80211_3ADDR_LEN; + __le16 fc = rtl_get_fc(skb); + u8 *act = (u8 *)(((u8 *)skb->data + MAC80211_3ADDR_LEN)); u8 category; if (!ieee80211_is_action(fc)) @@ -1034,18 +1175,47 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) return false; RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, - "%s ACT_ADDBAREQ From :%pM\n", - is_tx ? "Tx" : "Rx", hdr->addr2); + "%s ACT_ADDBAREQ From :%pM\n", + is_tx ? "Tx" : "Rx", hdr->addr2); RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "req\n", - skb->data, skb->len); - if (!is_tx) - if (addbareq_rx(hw, skb)) + skb->data, skb->len); + if (!is_tx) { + struct ieee80211_sta *sta = NULL; + struct rtl_sta_info *sta_entry = NULL; + struct rtl_tid_data *tid_data; + struct ieee80211_mgmt *mgmt = (void *)skb->data; + u16 capab = 0, tid = 0; + + rcu_read_lock(); + sta = rtl_find_sta(hw, hdr->addr3); + if (sta == NULL) { + RT_TRACE(rtlpriv, COMP_SEND | COMP_RECV, + DBG_DMESG, "sta is NULL\n"); + rcu_read_unlock(); + return true; + } + + sta_entry = + (struct rtl_sta_info *)sta->drv_priv; + if (!sta_entry) { + rcu_read_unlock(); return true; + } + capab = + le16_to_cpu(mgmt->u.action.u.addba_req.capab); + tid = (capab & + IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; + tid_data = &sta_entry->tids[tid]; + if (tid_data->agg.rx_agg_state == + RTL_RX_AGG_START) + process_agg_start(hw, hdr, tid); + rcu_read_unlock(); + } break; case ACT_ADDBARSP: RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, "%s ACT_ADDBARSP From :%pM\n", - is_tx ? "Tx" : "Rx", hdr->addr2); + is_tx ? "Tx" : "Rx", hdr->addr2); break; case ACT_DELBA: RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, @@ -1061,6 +1231,17 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) } EXPORT_SYMBOL_GPL(rtl_action_proc); +static void setup_arp_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc) +{ + rtlpriv->ra.is_special_data = true; + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_special_packet_notify( + rtlpriv, 1); + rtlpriv->enter_ps = false; + schedule_work(&rtlpriv->works.lps_change_work); + ppsc->last_delaylps_stamp_jiffies = jiffies; +} + /*should call before software enc*/ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) { @@ -1069,57 +1250,77 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) __le16 fc = rtl_get_fc(skb); u16 ether_type; u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb); + u8 encrypt_header_len = 0; + u8 offset; const struct iphdr *ip; if (!ieee80211_is_data(fc)) - return false; - - ip = (const struct iphdr *)(skb->data + mac_hdr_len + - SNAP_SIZE + PROTOC_TYPE_SIZE); - ether_type = be16_to_cpup((__be16 *) - (skb->data + mac_hdr_len + SNAP_SIZE)); + goto end; - switch (ether_type) { - case ETH_P_IP: { - struct udphdr *udp; - u16 src; - u16 dst; - - if (ip->protocol != IPPROTO_UDP) - return false; - udp = (struct udphdr *)((u8 *)ip + (ip->ihl << 2)); - src = be16_to_cpu(udp->source); - dst = be16_to_cpu(udp->dest); - - /* If this case involves port 68 (UDP BOOTP client) connecting - * with port 67 (UDP BOOTP server), then return true so that - * the lowest speed is used. - */ - if (!((src == 68 && dst == 67) || (src == 67 && dst == 68))) - return false; - - RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, - "dhcp %s !!\n", is_tx ? "Tx" : "Rx"); + switch (rtlpriv->sec.pairwise_enc_algorithm) { + case WEP40_ENCRYPTION: + case WEP104_ENCRYPTION: + encrypt_header_len = 4;/*WEP_IV_LEN*/ break; - } - case ETH_P_ARP: + case TKIP_ENCRYPTION: + encrypt_header_len = 8;/*TKIP_IV_LEN*/ break; - case ETH_P_PAE: - RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, - "802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx"); + case AESCCMP_ENCRYPTION: + encrypt_header_len = 8;/*CCMP_HDR_LEN;*/ break; - case ETH_P_IPV6: - /* TODO: Is this right? */ - return false; default: - return false; + break; } - if (is_tx) { - rtlpriv->enter_ps = false; - schedule_work(&rtlpriv->works.lps_change_work); - ppsc->last_delaylps_stamp_jiffies = jiffies; + + offset = mac_hdr_len + SNAP_SIZE + encrypt_header_len; + ether_type = be16_to_cpup((__be16 *)(skb->data + offset)); + + if (ETH_P_IP == ether_type) { + ip = (struct iphdr *)((u8 *)skb->data + offset + + PROTOC_TYPE_SIZE); + if (IPPROTO_UDP == ip->protocol) { + struct udphdr *udp = (struct udphdr *)((u8 *)ip + + (ip->ihl << 2)); + if (((((u8 *)udp)[1] == 68) && + (((u8 *)udp)[3] == 67)) || + ((((u8 *)udp)[1] == 67) && + (((u8 *)udp)[3] == 68))) { + /* 68 : UDP BOOTP client + * 67 : UDP BOOTP server + */ + RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), + DBG_DMESG, "dhcp %s !!\n", + (is_tx) ? "Tx" : "Rx"); + + if (is_tx) + setup_arp_tx(rtlpriv, ppsc); + return true; + } + } + } else if (ETH_P_ARP == ether_type) { + if (is_tx) + setup_arp_tx(rtlpriv, ppsc); + + return true; + } else if (ETH_P_PAE == ether_type) { + RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, + "802.1X %s EAPOL pkt!!\n", (is_tx) ? "Tx" : "Rx"); + + if (is_tx) { + rtlpriv->ra.is_special_data = true; + rtlpriv->enter_ps = false; + schedule_work(&rtlpriv->works.lps_change_work); + ppsc->last_delaylps_stamp_jiffies = jiffies; + } + + return true; + } else if (0x86DD == ether_type) { + return true; } - return true; + +end: + rtlpriv->ra.is_special_data = false; + return false; } EXPORT_SYMBOL_GPL(rtl_is_special_data); @@ -1133,7 +1334,6 @@ int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_tid_data *tid_data; - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_sta_info *sta_entry = NULL; if (sta == NULL) @@ -1147,14 +1347,14 @@ int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return -ENXIO; tid_data = &sta_entry->tids[tid]; - RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "on ra = %pM tid = %d seq:%d\n", - sta->addr, tid, tid_data->seq_number); + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, + "on ra = %pM tid = %d seq:%d\n", sta->addr, tid, + tid_data->seq_number); *ssn = tid_data->seq_number; tid_data->agg.agg_state = RTL_AGG_START; - ieee80211_start_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid); - + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); return 0; } @@ -1162,28 +1362,23 @@ int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_tid_data *tid_data; struct rtl_sta_info *sta_entry = NULL; if (sta == NULL) return -EINVAL; - if (!sta->addr) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "ra = NULL\n"); - return -EINVAL; - } - - RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "on ra = %pM tid = %d\n", - sta->addr, tid); + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, + "on ra = %pM tid = %d\n", sta->addr, tid); if (unlikely(tid >= MAX_TID_COUNT)) return -EINVAL; sta_entry = (struct rtl_sta_info *)sta->drv_priv; + tid_data = &sta_entry->tids[tid]; sta_entry->tids[tid].agg.agg_state = RTL_AGG_STOP; - ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid); - + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); return 0; } @@ -1222,11 +1417,6 @@ int rtl_rx_agg_stop(struct ieee80211_hw *hw, if (sta == NULL) return -EINVAL; - if (!sta->addr) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "ra = NULL\n"); - return -EINVAL; - } - RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "on ra = %pM tid = %d\n", sta->addr, tid); @@ -1238,7 +1428,6 @@ int rtl_rx_agg_stop(struct ieee80211_hw *hw, return 0; } - int rtl_tx_agg_oper(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tid) { @@ -1248,13 +1437,8 @@ int rtl_tx_agg_oper(struct ieee80211_hw *hw, if (sta == NULL) return -EINVAL; - if (!sta->addr) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "ra = NULL\n"); - return -EINVAL; - } - - RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "on ra = %pM tid = %d\n", - sta->addr, tid); + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, + "on ra = %pM tid = %d\n", sta->addr, tid); if (unlikely(tid >= MAX_TID_COUNT)) return -EINVAL; @@ -1292,7 +1476,7 @@ void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb) return; /* and only beacons from the associated BSSID, please */ - if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid)) + if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) return; rtlpriv->link_info.bcn_rx_inperiod++; @@ -1332,8 +1516,7 @@ void rtl_watchdog_wq_callback(void *data) mac->cnt_after_linked = 0; } - /* - *<2> to check if traffic busy, if + /* <2> to check if traffic busy, if * busytraffic we don't change channel */ if (mac->link_state >= MAC80211_LINKED) { @@ -1381,21 +1564,21 @@ void rtl_watchdog_wq_callback(void *data) for (tid = 0; tid <= 7; tid++) { for (idx = 0; idx <= 2; idx++) rtlpriv->link_info.tidtx_in4period[tid][idx] = - rtlpriv->link_info.tidtx_in4period[tid] - [idx + 1]; + rtlpriv->link_info.tidtx_in4period[tid] + [idx + 1]; rtlpriv->link_info.tidtx_in4period[tid][3] = rtlpriv->link_info.tidtx_inperiod[tid]; for (idx = 0; idx <= 3; idx++) tidtx_inp4eriod[tid] += - rtlpriv->link_info.tidtx_in4period[tid][idx]; + rtlpriv->link_info.tidtx_in4period[tid][idx]; aver_tidtx_inperiod[tid] = tidtx_inp4eriod[tid] / 4; if (aver_tidtx_inperiod[tid] > 5000) rtlpriv->link_info.higher_busytxtraffic[tid] = - true; + true; else rtlpriv->link_info.higher_busytxtraffic[tid] = - false; + false; } if (((rtlpriv->link_info.num_rx_inperiod + @@ -1418,32 +1601,37 @@ void rtl_watchdog_wq_callback(void *data) rtlpriv->link_info.higher_busyrxtraffic = higher_busyrxtraffic; /* <3> DM */ - rtlpriv->cfg->ops->dm_watchdog(hw); + if (!rtlpriv->cfg->mod_params->disable_watchdog) + rtlpriv->cfg->ops->dm_watchdog(hw); /* <4> roaming */ if (mac->link_state == MAC80211_LINKED && mac->opmode == NL80211_IFTYPE_STATION) { if ((rtlpriv->link_info.bcn_rx_inperiod + - rtlpriv->link_info.num_rx_inperiod) == 0) { + rtlpriv->link_info.num_rx_inperiod) == 0) { rtlpriv->link_info.roam_times++; RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG, "AP off for %d s\n", - (rtlpriv->link_info.roam_times * 2)); + (rtlpriv->link_info.roam_times * 2)); - /* if we can't recv beacon for 6s, we should - * reconnect this AP + /* if we can't recv beacon for 10s, + * we should reconnect this AP */ - if ((rtlpriv->link_info.roam_times >= 3) && - !is_zero_ether_addr(rtlpriv->mac80211.bssid)) { + if (rtlpriv->link_info.roam_times >= 5) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AP off, try to reconnect now\n"); rtlpriv->link_info.roam_times = 0; - ieee80211_connection_loss(rtlpriv->mac80211.vif); + ieee80211_connection_loss( + rtlpriv->mac80211.vif); } } else { rtlpriv->link_info.roam_times = 0; } } + + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_periodical(rtlpriv); + rtlpriv->link_info.bcn_rx_inperiod = 0; } @@ -1458,7 +1646,6 @@ void rtl_watch_dog_timer_callback(unsigned long data) mod_timer(&rtlpriv->works.watchdog_timer, jiffies + MSECS(RTL_WATCH_DOG_TIME)); } - void rtl_fwevt_wq_callback(void *data) { struct rtl_works *rtlworks = @@ -1468,7 +1655,6 @@ void rtl_fwevt_wq_callback(void *data) rtlpriv->cfg->ops->c2h_command_handle(hw); } - void rtl_easy_concurrent_retrytimer_callback(unsigned long data) { struct ieee80211_hw *hw = (struct ieee80211_hw *)data; @@ -1480,7 +1666,6 @@ void rtl_easy_concurrent_retrytimer_callback(unsigned long data) rtlpriv->cfg->ops->dualmac_easy_concurrent(hw); } - /********************************************************* * * frame process functions @@ -1508,7 +1693,8 @@ u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie) /* when we use 2 rx ants we send IEEE80211_SMPS_OFF */ /* when we use 1 rx ant we send IEEE80211_SMPS_STATIC */ static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw, - enum ieee80211_smps_mode smps, u8 *da, u8 *bssid) + enum ieee80211_smps_mode smps, + u8 *da, u8 *bssid) { struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct sk_buff *skb; |