|
|
@@ -50,8 +50,9 @@
|
|
|
*3) functions called by core.c
|
|
|
*4) wq & timer callback functions
|
|
|
*5) frame process functions
|
|
|
- *6) sysfs functions
|
|
|
- *7) ...
|
|
|
+ *6) IOT functions
|
|
|
+ *7) sysfs functions
|
|
|
+ *8) ...
|
|
|
*/
|
|
|
|
|
|
/*********************************************************
|
|
|
@@ -59,7 +60,7 @@
|
|
|
* mac80211 init functions
|
|
|
*
|
|
|
*********************************************************/
|
|
|
-static struct ieee80211_channel rtl_channeltable[] = {
|
|
|
+static struct ieee80211_channel rtl_channeltable_2g[] = {
|
|
|
{.center_freq = 2412, .hw_value = 1,},
|
|
|
{.center_freq = 2417, .hw_value = 2,},
|
|
|
{.center_freq = 2422, .hw_value = 3,},
|
|
|
@@ -76,7 +77,34 @@ static struct ieee80211_channel rtl_channeltable[] = {
|
|
|
{.center_freq = 2484, .hw_value = 14,},
|
|
|
};
|
|
|
|
|
|
-static struct ieee80211_rate rtl_ratetable[] = {
|
|
|
+static struct ieee80211_channel rtl_channeltable_5g[] = {
|
|
|
+ {.center_freq = 5180, .hw_value = 36,},
|
|
|
+ {.center_freq = 5200, .hw_value = 40,},
|
|
|
+ {.center_freq = 5220, .hw_value = 44,},
|
|
|
+ {.center_freq = 5240, .hw_value = 48,},
|
|
|
+ {.center_freq = 5260, .hw_value = 52,},
|
|
|
+ {.center_freq = 5280, .hw_value = 56,},
|
|
|
+ {.center_freq = 5300, .hw_value = 60,},
|
|
|
+ {.center_freq = 5320, .hw_value = 64,},
|
|
|
+ {.center_freq = 5500, .hw_value = 100,},
|
|
|
+ {.center_freq = 5520, .hw_value = 104,},
|
|
|
+ {.center_freq = 5540, .hw_value = 108,},
|
|
|
+ {.center_freq = 5560, .hw_value = 112,},
|
|
|
+ {.center_freq = 5580, .hw_value = 116,},
|
|
|
+ {.center_freq = 5600, .hw_value = 120,},
|
|
|
+ {.center_freq = 5620, .hw_value = 124,},
|
|
|
+ {.center_freq = 5640, .hw_value = 128,},
|
|
|
+ {.center_freq = 5660, .hw_value = 132,},
|
|
|
+ {.center_freq = 5680, .hw_value = 136,},
|
|
|
+ {.center_freq = 5700, .hw_value = 140,},
|
|
|
+ {.center_freq = 5745, .hw_value = 149,},
|
|
|
+ {.center_freq = 5765, .hw_value = 153,},
|
|
|
+ {.center_freq = 5785, .hw_value = 157,},
|
|
|
+ {.center_freq = 5805, .hw_value = 161,},
|
|
|
+ {.center_freq = 5825, .hw_value = 165,},
|
|
|
+};
|
|
|
+
|
|
|
+static struct ieee80211_rate rtl_ratetable_2g[] = {
|
|
|
{.bitrate = 10, .hw_value = 0x00,},
|
|
|
{.bitrate = 20, .hw_value = 0x01,},
|
|
|
{.bitrate = 55, .hw_value = 0x02,},
|
|
|
@@ -91,18 +119,57 @@ static struct ieee80211_rate rtl_ratetable[] = {
|
|
|
{.bitrate = 540, .hw_value = 0x0b,},
|
|
|
};
|
|
|
|
|
|
+static struct ieee80211_rate rtl_ratetable_5g[] = {
|
|
|
+ {.bitrate = 60, .hw_value = 0x04,},
|
|
|
+ {.bitrate = 90, .hw_value = 0x05,},
|
|
|
+ {.bitrate = 120, .hw_value = 0x06,},
|
|
|
+ {.bitrate = 180, .hw_value = 0x07,},
|
|
|
+ {.bitrate = 240, .hw_value = 0x08,},
|
|
|
+ {.bitrate = 360, .hw_value = 0x09,},
|
|
|
+ {.bitrate = 480, .hw_value = 0x0a,},
|
|
|
+ {.bitrate = 540, .hw_value = 0x0b,},
|
|
|
+};
|
|
|
+
|
|
|
static const struct ieee80211_supported_band rtl_band_2ghz = {
|
|
|
.band = IEEE80211_BAND_2GHZ,
|
|
|
|
|
|
- .channels = rtl_channeltable,
|
|
|
- .n_channels = ARRAY_SIZE(rtl_channeltable),
|
|
|
+ .channels = rtl_channeltable_2g,
|
|
|
+ .n_channels = ARRAY_SIZE(rtl_channeltable_2g),
|
|
|
|
|
|
- .bitrates = rtl_ratetable,
|
|
|
- .n_bitrates = ARRAY_SIZE(rtl_ratetable),
|
|
|
+ .bitrates = rtl_ratetable_2g,
|
|
|
+ .n_bitrates = ARRAY_SIZE(rtl_ratetable_2g),
|
|
|
|
|
|
.ht_cap = {0},
|
|
|
};
|
|
|
|
|
|
+static struct ieee80211_supported_band rtl_band_5ghz = {
|
|
|
+ .band = IEEE80211_BAND_5GHZ,
|
|
|
+
|
|
|
+ .channels = rtl_channeltable_5g,
|
|
|
+ .n_channels = ARRAY_SIZE(rtl_channeltable_5g),
|
|
|
+
|
|
|
+ .bitrates = rtl_ratetable_5g,
|
|
|
+ .n_bitrates = ARRAY_SIZE(rtl_ratetable_5g),
|
|
|
+
|
|
|
+ .ht_cap = {0},
|
|
|
+};
|
|
|
+
|
|
|
+static const u8 tid_to_ac[] = {
|
|
|
+ 2, /* IEEE80211_AC_BE */
|
|
|
+ 3, /* IEEE80211_AC_BK */
|
|
|
+ 3, /* IEEE80211_AC_BK */
|
|
|
+ 2, /* IEEE80211_AC_BE */
|
|
|
+ 1, /* IEEE80211_AC_VI */
|
|
|
+ 1, /* IEEE80211_AC_VI */
|
|
|
+ 0, /* IEEE80211_AC_VO */
|
|
|
+ 0, /* IEEE80211_AC_VO */
|
|
|
+};
|
|
|
+
|
|
|
+u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid)
|
|
|
+{
|
|
|
+ return tid_to_ac[tid];
|
|
|
+}
|
|
|
+
|
|
|
static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
|
|
|
struct ieee80211_sta_ht_cap *ht_cap)
|
|
|
{
|
|
|
@@ -115,6 +182,9 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
|
|
|
IEEE80211_HT_CAP_SGI_20 |
|
|
|
IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU;
|
|
|
|
|
|
+ if (rtlpriv->rtlhal.disable_amsdu_8k)
|
|
|
+ ht_cap->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU;
|
|
|
+
|
|
|
/*
|
|
|
*Maximum length of AMPDU that the STA can receive.
|
|
|
*Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
|
|
|
@@ -159,37 +229,99 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
|
|
|
|
|
|
static void _rtl_init_mac80211(struct ieee80211_hw *hw)
|
|
|
{
|
|
|
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
|
|
|
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
|
|
|
struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
|
|
|
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
|
|
|
struct ieee80211_supported_band *sband;
|
|
|
|
|
|
- /* <1> use mac->bands as mem for hw->wiphy->bands */
|
|
|
- sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]);
|
|
|
|
|
|
- /*
|
|
|
- * <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));
|
|
|
+ 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]);
|
|
|
+
|
|
|
+ /* <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));
|
|
|
|
|
|
- /* <3> init ht cap base on ant_num */
|
|
|
- _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
|
|
|
+ /* <3> init ht cap base on ant_num */
|
|
|
+ _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
|
|
|
|
|
|
- /* <4> set mac->sband to wiphy->sband */
|
|
|
- hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
|
|
|
+ /* <4> set mac->sband to wiphy->sband */
|
|
|
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
|
|
|
|
|
|
+ /* 2: 5 G bands */
|
|
|
+ /* <1> use mac->bands as mem for hw->wiphy->bands */
|
|
|
+ sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]);
|
|
|
+
|
|
|
+ /* <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));
|
|
|
+
|
|
|
+ /* <3> init ht cap base on ant_num */
|
|
|
+ _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
|
|
|
+
|
|
|
+ /* <4> set mac->sband to wiphy->sband */
|
|
|
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband;
|
|
|
+ } else {
|
|
|
+ if (rtlhal->current_bandtype == BAND_ON_2_4G) {
|
|
|
+ /* <1> use mac->bands as mem for hw->wiphy->bands */
|
|
|
+ sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]);
|
|
|
+
|
|
|
+ /* <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));
|
|
|
+
|
|
|
+ /* <3> init ht cap base on ant_num */
|
|
|
+ _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
|
|
|
+
|
|
|
+ /* <4> set mac->sband to wiphy->sband */
|
|
|
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
|
|
|
+ } else if (rtlhal->current_bandtype == BAND_ON_5G) {
|
|
|
+ /* <1> use mac->bands as mem for hw->wiphy->bands */
|
|
|
+ sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]);
|
|
|
+
|
|
|
+ /* <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));
|
|
|
+
|
|
|
+ /* <3> init ht cap base on ant_num */
|
|
|
+ _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
|
|
|
+
|
|
|
+ /* <4> set mac->sband to wiphy->sband */
|
|
|
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband;
|
|
|
+ } else {
|
|
|
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
|
|
|
+ ("Err BAND %d\n",
|
|
|
+ rtlhal->current_bandtype));
|
|
|
+ }
|
|
|
+ }
|
|
|
/* <5> set hw caps */
|
|
|
hw->flags = IEEE80211_HW_SIGNAL_DBM |
|
|
|
IEEE80211_HW_RX_INCLUDES_FCS |
|
|
|
- IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_AMPDU_AGGREGATION | /*PS*/
|
|
|
- /*IEEE80211_HW_SUPPORTS_PS | */
|
|
|
- /*IEEE80211_HW_PS_NULLFUNC_STACK | */
|
|
|
- /*IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */
|
|
|
+ IEEE80211_HW_BEACON_FILTER |
|
|
|
+ IEEE80211_HW_AMPDU_AGGREGATION |
|
|
|
IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0;
|
|
|
|
|
|
+ /* swlps or hwlps has been set in diff chip in init_sw_vars */
|
|
|
+ if (rtlpriv->psc.swctrl_lps)
|
|
|
+ hw->flags |= IEEE80211_HW_SUPPORTS_PS |
|
|
|
+ IEEE80211_HW_PS_NULLFUNC_STACK |
|
|
|
+ /* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */
|
|
|
+ 0;
|
|
|
+
|
|
|
hw->wiphy->interface_modes =
|
|
|
- BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
|
|
|
+ BIT(NL80211_IFTYPE_AP) |
|
|
|
+ BIT(NL80211_IFTYPE_STATION) |
|
|
|
+ BIT(NL80211_IFTYPE_ADHOC);
|
|
|
|
|
|
hw->wiphy->rts_threshold = 2347;
|
|
|
|
|
|
@@ -199,9 +331,10 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
|
|
|
/* TODO: Correct this value for our hw */
|
|
|
/* TODO: define these hard code value */
|
|
|
hw->channel_change_time = 100;
|
|
|
- hw->max_listen_interval = 5;
|
|
|
+ hw->max_listen_interval = 10;
|
|
|
hw->max_rate_tries = 4;
|
|
|
/* hw->max_rates = 1; */
|
|
|
+ hw->sta_data_size = sizeof(struct rtl_sta_info);
|
|
|
|
|
|
/* <6> mac address */
|
|
|
if (is_valid_ether_addr(rtlefuse->dev_addr)) {
|
|
|
@@ -230,6 +363,10 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
|
|
|
(void *)rtl_watchdog_wq_callback);
|
|
|
INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq,
|
|
|
(void *)rtl_ips_nic_off_wq_callback);
|
|
|
+ INIT_DELAYED_WORK(&rtlpriv->works.ps_work,
|
|
|
+ (void *)rtl_swlps_wq_callback);
|
|
|
+ INIT_DELAYED_WORK(&rtlpriv->works.ps_rfon_wq,
|
|
|
+ (void *)rtl_swlps_rfon_wq_callback);
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -241,6 +378,8 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw)
|
|
|
|
|
|
cancel_delayed_work(&rtlpriv->works.watchdog_wq);
|
|
|
cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
|
|
|
+ cancel_delayed_work(&rtlpriv->works.ps_work);
|
|
|
+ cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
|
|
|
}
|
|
|
|
|
|
void rtl_init_rfkill(struct ieee80211_hw *hw)
|
|
|
@@ -310,6 +449,8 @@ int rtl_init_core(struct ieee80211_hw *hw)
|
|
|
spin_lock_init(&rtlpriv->locks.rf_ps_lock);
|
|
|
spin_lock_init(&rtlpriv->locks.rf_lock);
|
|
|
spin_lock_init(&rtlpriv->locks.lps_lock);
|
|
|
+ spin_lock_init(&rtlpriv->locks.waitq_lock);
|
|
|
+ spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock);
|
|
|
|
|
|
rtlmac->link_state = MAC80211_NOLINK;
|
|
|
|
|
|
@@ -329,12 +470,6 @@ void rtl_init_rx_config(struct ieee80211_hw *hw)
|
|
|
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
|
|
|
|
|
|
rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf));
|
|
|
- rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MGT_FILTER,
|
|
|
- (u8 *) (&mac->rx_mgt_filter));
|
|
|
- rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_CTRL_FILTER,
|
|
|
- (u8 *) (&mac->rx_ctrl_filter));
|
|
|
- rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_DATA_FILTER,
|
|
|
- (u8 *) (&mac->rx_data_filter));
|
|
|
}
|
|
|
|
|
|
/*********************************************************
|
|
|
@@ -361,28 +496,40 @@ static void _rtl_qurey_shortpreamble_mode(struct ieee80211_hw *hw,
|
|
|
}
|
|
|
|
|
|
static void _rtl_query_shortgi(struct ieee80211_hw *hw,
|
|
|
+ struct ieee80211_sta *sta,
|
|
|
struct rtl_tcb_desc *tcb_desc,
|
|
|
struct ieee80211_tx_info *info)
|
|
|
{
|
|
|
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;
|
|
|
tcb_desc->use_shortgi = false;
|
|
|
|
|
|
- if (!mac->ht_enable)
|
|
|
+ if (sta == NULL)
|
|
|
+ return;
|
|
|
+
|
|
|
+ sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
|
|
|
+ sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20;
|
|
|
+
|
|
|
+ if (!(sta->ht_cap.ht_supported))
|
|
|
return;
|
|
|
|
|
|
- if (!mac->sgi_40 && !mac->sgi_20)
|
|
|
+ if (!sgi_40 && !sgi_20)
|
|
|
return;
|
|
|
|
|
|
- if ((mac->bw_40 == true) && mac->sgi_40)
|
|
|
+ if (mac->opmode == NL80211_IFTYPE_STATION)
|
|
|
+ bw_40 = mac->bw_40;
|
|
|
+ else if (mac->opmode == NL80211_IFTYPE_AP ||
|
|
|
+ mac->opmode == NL80211_IFTYPE_ADHOC)
|
|
|
+ bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
|
|
+
|
|
|
+ if ((bw_40 == true) && sgi_40)
|
|
|
tcb_desc->use_shortgi = true;
|
|
|
- else if ((mac->bw_40 == false) && mac->sgi_20)
|
|
|
+ else if ((bw_40 == false) && sgi_20)
|
|
|
tcb_desc->use_shortgi = true;
|
|
|
|
|
|
if (!(rate_flag & IEEE80211_TX_RC_SHORT_GI))
|
|
|
tcb_desc->use_shortgi = false;
|
|
|
-
|
|
|
}
|
|
|
|
|
|
static void _rtl_query_protection_mode(struct ieee80211_hw *hw,
|
|
|
@@ -410,19 +557,25 @@ static void _rtl_query_protection_mode(struct ieee80211_hw *hw,
|
|
|
tcb_desc->rts_enable = true;
|
|
|
tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M];
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
|
|
|
static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
|
|
|
+ struct ieee80211_sta *sta,
|
|
|
struct rtl_tcb_desc *tcb_desc)
|
|
|
{
|
|
|
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
|
|
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
|
|
|
+ struct rtl_sta_info *sta_entry = NULL;
|
|
|
+ u8 ratr_index = 7;
|
|
|
|
|
|
+ if (sta) {
|
|
|
+ sta_entry = (struct rtl_sta_info *) sta->drv_priv;
|
|
|
+ ratr_index = sta_entry->ratr_index;
|
|
|
+ }
|
|
|
if (!tcb_desc->disable_ratefallback || !tcb_desc->use_driver_rate) {
|
|
|
- if (mac->opmode == NL80211_IFTYPE_STATION)
|
|
|
+ if (mac->opmode == NL80211_IFTYPE_STATION) {
|
|
|
tcb_desc->ratr_index = 0;
|
|
|
- else if (mac->opmode == NL80211_IFTYPE_ADHOC) {
|
|
|
+ } else if (mac->opmode == NL80211_IFTYPE_ADHOC) {
|
|
|
if (tcb_desc->multicast || tcb_desc->broadcast) {
|
|
|
tcb_desc->hw_rate =
|
|
|
rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M];
|
|
|
@@ -430,36 +583,61 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
|
|
|
} else {
|
|
|
/* TODO */
|
|
|
}
|
|
|
+ tcb_desc->ratr_index = ratr_index;
|
|
|
+ } else if (mac->opmode == NL80211_IFTYPE_AP) {
|
|
|
+ tcb_desc->ratr_index = ratr_index;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (rtlpriv->dm.useramask) {
|
|
|
- /* TODO adhoc and station handled differently in the future */
|
|
|
- tcb_desc->mac_id = 0;
|
|
|
-
|
|
|
- if ((mac->mode == WIRELESS_MODE_N_24G) ||
|
|
|
- (mac->mode == WIRELESS_MODE_N_5G)) {
|
|
|
- tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB;
|
|
|
- } else if (mac->mode & WIRELESS_MODE_G) {
|
|
|
- tcb_desc->ratr_index = RATR_INX_WIRELESS_GB;
|
|
|
- } else if (mac->mode & WIRELESS_MODE_B) {
|
|
|
- tcb_desc->ratr_index = RATR_INX_WIRELESS_B;
|
|
|
+ /* TODO we will differentiate adhoc and station futrue */
|
|
|
+ if (mac->opmode == NL80211_IFTYPE_STATION) {
|
|
|
+ tcb_desc->mac_id = 0;
|
|
|
+
|
|
|
+ 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;
|
|
|
+ else if (mac->mode & WIRELESS_MODE_G)
|
|
|
+ tcb_desc->ratr_index = RATR_INX_WIRELESS_GB;
|
|
|
+ else if (mac->mode & WIRELESS_MODE_B)
|
|
|
+ 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) {
|
|
|
+ if (NULL != sta) {
|
|
|
+ if (sta->aid > 0)
|
|
|
+ tcb_desc->mac_id = sta->aid + 1;
|
|
|
+ else
|
|
|
+ tcb_desc->mac_id = 1;
|
|
|
+ } else {
|
|
|
+ tcb_desc->mac_id = 0;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
|
|
|
+ struct ieee80211_sta *sta,
|
|
|
struct rtl_tcb_desc *tcb_desc)
|
|
|
{
|
|
|
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
|
|
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
|
|
|
|
|
|
tcb_desc->packet_bw = false;
|
|
|
-
|
|
|
- if (!mac->bw_40 || !mac->ht_enable)
|
|
|
+ if (!sta)
|
|
|
return;
|
|
|
-
|
|
|
+ if (mac->opmode == NL80211_IFTYPE_AP ||
|
|
|
+ mac->opmode == NL80211_IFTYPE_ADHOC) {
|
|
|
+ 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))
|
|
|
+ return;
|
|
|
+ }
|
|
|
if (tcb_desc->multicast || tcb_desc->broadcast)
|
|
|
return;
|
|
|
|
|
|
@@ -486,22 +664,21 @@ static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw)
|
|
|
|
|
|
void rtl_get_tcb_desc(struct ieee80211_hw *hw,
|
|
|
struct ieee80211_tx_info *info,
|
|
|
+ struct ieee80211_sta *sta,
|
|
|
struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc)
|
|
|
{
|
|
|
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
|
|
struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
|
|
|
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
|
|
|
+ struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
|
|
|
struct ieee80211_rate *txrate;
|
|
|
__le16 fc = hdr->frame_control;
|
|
|
|
|
|
- memset(tcb_desc, 0, sizeof(struct rtl_tcb_desc));
|
|
|
+ txrate = ieee80211_get_tx_rate(hw, info);
|
|
|
+ tcb_desc->hw_rate = txrate->hw_value;
|
|
|
|
|
|
if (ieee80211_is_data(fc)) {
|
|
|
- txrate = ieee80211_get_tx_rate(hw, info);
|
|
|
- tcb_desc->hw_rate = txrate->hw_value;
|
|
|
-
|
|
|
/*
|
|
|
- *we set data rate RTL_RC_CCK_RATE1M
|
|
|
+ *we set data rate INX 0
|
|
|
*in rtl_rc.c if skb is special data or
|
|
|
*mgt which need low data rate.
|
|
|
*/
|
|
|
@@ -510,12 +687,11 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
|
|
|
*So tcb_desc->hw_rate is just used for
|
|
|
*special data and mgt frames
|
|
|
*/
|
|
|
- if (tcb_desc->hw_rate < rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]) {
|
|
|
+ if (info->control.rates[0].idx == 0 &&
|
|
|
+ ieee80211_is_nullfunc(fc)) {
|
|
|
tcb_desc->use_driver_rate = true;
|
|
|
- tcb_desc->ratr_index = 7;
|
|
|
+ tcb_desc->ratr_index = RATR_INX_WIRELESS_MC;
|
|
|
|
|
|
- tcb_desc->hw_rate =
|
|
|
- rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M];
|
|
|
tcb_desc->disable_ratefallback = 1;
|
|
|
} else {
|
|
|
/*
|
|
|
@@ -525,7 +701,7 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
|
|
|
*and N rate will all be controled by FW
|
|
|
*when tcb_desc->use_driver_rate = false
|
|
|
*/
|
|
|
- if (rtlmac->ht_enable) {
|
|
|
+ if (sta && (sta->ht_cap.ht_supported)) {
|
|
|
tcb_desc->hw_rate = _rtl_get_highest_n_rate(hw);
|
|
|
} else {
|
|
|
if (rtlmac->mode == WIRELESS_MODE_B) {
|
|
|
@@ -543,43 +719,25 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
|
|
|
else if (is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
|
|
|
tcb_desc->broadcast = 1;
|
|
|
|
|
|
- _rtl_txrate_selectmode(hw, tcb_desc);
|
|
|
- _rtl_query_bandwidth_mode(hw, tcb_desc);
|
|
|
+ _rtl_txrate_selectmode(hw, sta, tcb_desc);
|
|
|
+ _rtl_query_bandwidth_mode(hw, sta, tcb_desc);
|
|
|
_rtl_qurey_shortpreamble_mode(hw, tcb_desc, info);
|
|
|
- _rtl_query_shortgi(hw, tcb_desc, info);
|
|
|
+ _rtl_query_shortgi(hw, sta, tcb_desc, info);
|
|
|
_rtl_query_protection_mode(hw, tcb_desc, info);
|
|
|
} else {
|
|
|
tcb_desc->use_driver_rate = true;
|
|
|
- tcb_desc->ratr_index = 7;
|
|
|
+ tcb_desc->ratr_index = RATR_INX_WIRELESS_MC;
|
|
|
tcb_desc->disable_ratefallback = 1;
|
|
|
tcb_desc->mac_id = 0;
|
|
|
-
|
|
|
- tcb_desc->hw_rate = rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M];
|
|
|
+ tcb_desc->packet_bw = false;
|
|
|
}
|
|
|
}
|
|
|
EXPORT_SYMBOL(rtl_get_tcb_desc);
|
|
|
|
|
|
-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_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
|
|
|
- __le16 fc = hdr->frame_control;
|
|
|
-
|
|
|
- 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;
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
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 = (struct ieee80211_hdr *)(skb->data);
|
|
|
+ struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
|
|
|
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
|
|
__le16 fc = hdr->frame_control;
|
|
|
u8 *act = (u8 *) (((u8 *) skb->data + MAC80211_3ADDR_LEN));
|
|
|
@@ -624,9 +782,8 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
|
|
|
u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
|
|
|
{
|
|
|
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
|
|
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
|
|
|
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
|
|
|
- __le16 fc = hdr->frame_control;
|
|
|
+ __le16 fc = rtl_get_fc(skb);
|
|
|
u16 ether_type;
|
|
|
u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb);
|
|
|
const struct iphdr *ip;
|
|
|
@@ -634,12 +791,11 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
|
|
|
if (!ieee80211_is_data(fc))
|
|
|
return false;
|
|
|
|
|
|
- if (ieee80211_is_nullfunc(fc))
|
|
|
- return true;
|
|
|
|
|
|
ip = (struct iphdr *)((u8 *) skb->data + mac_hdr_len +
|
|
|
SNAP_SIZE + PROTOC_TYPE_SIZE);
|
|
|
ether_type = *(u16 *) ((u8 *) skb->data + mac_hdr_len + SNAP_SIZE);
|
|
|
+ ether_type = ntohs(ether_type);
|
|
|
|
|
|
if (ETH_P_IP == ether_type) {
|
|
|
if (IPPROTO_UDP == ip->protocol) {
|
|
|
@@ -696,61 +852,92 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
|
|
|
* functions called by core.c
|
|
|
*
|
|
|
*********************************************************/
|
|
|
-int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, u16 tid, u16 *ssn)
|
|
|
+int rtl_tx_agg_start(struct ieee80211_hw *hw,
|
|
|
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn)
|
|
|
{
|
|
|
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;
|
|
|
|
|
|
- RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
|
|
|
- ("on ra = %pM tid = %d\n", ra, tid));
|
|
|
+ if (sta == NULL)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
if (unlikely(tid >= MAX_TID_COUNT))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (mac->tids[tid].agg.agg_state != RTL_AGG_OFF) {
|
|
|
- RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
|
|
|
- ("Start AGG when state is not RTL_AGG_OFF !\n"));
|
|
|
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
|
|
|
+ if (!sta_entry)
|
|
|
return -ENXIO;
|
|
|
- }
|
|
|
-
|
|
|
- tid_data = &mac->tids[tid];
|
|
|
- *ssn = SEQ_TO_SN(tid_data->seq_number);
|
|
|
+ tid_data = &sta_entry->tids[tid];
|
|
|
|
|
|
RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
|
|
|
- ("HW queue is empty tid:%d\n", tid));
|
|
|
- tid_data->agg.agg_state = RTL_AGG_ON;
|
|
|
+ ("on ra = %pM tid = %d seq:%d\n", sta->addr, tid,
|
|
|
+ tid_data->seq_number));
|
|
|
|
|
|
- ieee80211_start_tx_ba_cb_irqsafe(mac->vif, ra, tid);
|
|
|
+ *ssn = tid_data->seq_number;
|
|
|
+ tid_data->agg.agg_state = RTL_AGG_START;
|
|
|
+
|
|
|
+ ieee80211_start_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 * ra, u16 tid)
|
|
|
+int rtl_tx_agg_stop(struct ieee80211_hw *hw,
|
|
|
+ struct ieee80211_sta *sta, u16 tid)
|
|
|
{
|
|
|
- int ssn = -1;
|
|
|
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 (!ra) {
|
|
|
+ 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));
|
|
|
+
|
|
|
if (unlikely(tid >= MAX_TID_COUNT))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (mac->tids[tid].agg.agg_state != RTL_AGG_ON)
|
|
|
- RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
|
|
|
- ("Stopping AGG while state not ON or starting\n"));
|
|
|
+ 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;
|
|
|
|
|
|
- tid_data = &mac->tids[tid];
|
|
|
- ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
|
|
|
+ ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid);
|
|
|
|
|
|
- mac->tids[tid].agg.agg_state = RTL_AGG_OFF;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int rtl_tx_agg_oper(struct ieee80211_hw *hw,
|
|
|
+ struct ieee80211_sta *sta, u16 tid)
|
|
|
+{
|
|
|
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
|
|
|
+ struct rtl_tid_data *tid_data;
|
|
|
+ struct rtl_sta_info *sta_entry = NULL;
|
|
|
|
|
|
- ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, ra, tid);
|
|
|
+ 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));
|
|
|
+
|
|
|
+ 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_OPERATIONAL;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -769,18 +956,16 @@ void rtl_watchdog_wq_callback(void *data)
|
|
|
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
|
|
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
|
|
|
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
|
|
|
-
|
|
|
bool busytraffic = false;
|
|
|
bool higher_busytraffic = false;
|
|
|
bool higher_busyrxtraffic = false;
|
|
|
- bool higher_busytxtraffic = false;
|
|
|
-
|
|
|
- u8 idx = 0;
|
|
|
+ u8 idx, tid;
|
|
|
u32 rx_cnt_inp4eriod = 0;
|
|
|
u32 tx_cnt_inp4eriod = 0;
|
|
|
u32 aver_rx_cnt_inperiod = 0;
|
|
|
u32 aver_tx_cnt_inperiod = 0;
|
|
|
-
|
|
|
+ u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0};
|
|
|
+ u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0};
|
|
|
bool enter_ps = false;
|
|
|
|
|
|
if (is_hal_stop(rtlhal))
|
|
|
@@ -794,9 +979,6 @@ void rtl_watchdog_wq_callback(void *data)
|
|
|
mac->cnt_after_linked = 0;
|
|
|
}
|
|
|
|
|
|
- /* <2> DM */
|
|
|
- rtlpriv->cfg->ops->dm_watchdog(hw);
|
|
|
-
|
|
|
/*
|
|
|
*<3> to check if traffic busy, if
|
|
|
* busytraffic we don't change channel
|
|
|
@@ -835,8 +1017,27 @@ void rtl_watchdog_wq_callback(void *data)
|
|
|
/* Extremely high Rx data. */
|
|
|
if (aver_rx_cnt_inperiod > 5000)
|
|
|
higher_busyrxtraffic = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* check every tid's tx traffic */
|
|
|
+ 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][3] =
|
|
|
+ rtlpriv->link_info.tidtx_inperiod[tid];
|
|
|
+
|
|
|
+ for (idx = 0; idx <= 3; idx++)
|
|
|
+ tidtx_inp4eriod[tid] +=
|
|
|
+ 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;
|
|
|
else
|
|
|
- higher_busytxtraffic = false;
|
|
|
+ rtlpriv->link_info.higher_busytxtraffic[tid] =
|
|
|
+ false;
|
|
|
}
|
|
|
|
|
|
if (((rtlpriv->link_info.num_rx_inperiod +
|
|
|
@@ -855,11 +1056,15 @@ void rtl_watchdog_wq_callback(void *data)
|
|
|
|
|
|
rtlpriv->link_info.num_rx_inperiod = 0;
|
|
|
rtlpriv->link_info.num_tx_inperiod = 0;
|
|
|
+ for (tid = 0; tid <= 7; tid++)
|
|
|
+ rtlpriv->link_info.tidtx_inperiod[tid] = 0;
|
|
|
|
|
|
rtlpriv->link_info.busytraffic = busytraffic;
|
|
|
rtlpriv->link_info.higher_busytraffic = higher_busytraffic;
|
|
|
rtlpriv->link_info.higher_busyrxtraffic = higher_busyrxtraffic;
|
|
|
|
|
|
+ /* <3> DM */
|
|
|
+ rtlpriv->cfg->ops->dm_watchdog(hw);
|
|
|
}
|
|
|
|
|
|
void rtl_watch_dog_timer_callback(unsigned long data)
|
|
|
@@ -874,6 +1079,274 @@ void rtl_watch_dog_timer_callback(unsigned long data)
|
|
|
jiffies + MSECS(RTL_WATCH_DOG_TIME));
|
|
|
}
|
|
|
|
|
|
+/*********************************************************
|
|
|
+ *
|
|
|
+ * frame process functions
|
|
|
+ *
|
|
|
+ *********************************************************/
|
|
|
+u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie)
|
|
|
+{
|
|
|
+ struct ieee80211_mgmt *mgmt = (void *)data;
|
|
|
+ u8 *pos, *end;
|
|
|
+
|
|
|
+ pos = (u8 *)mgmt->u.beacon.variable;
|
|
|
+ end = data + len;
|
|
|
+ while (pos < end) {
|
|
|
+ if (pos + 2 + pos[1] > end)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (pos[0] == ie)
|
|
|
+ return pos;
|
|
|
+
|
|
|
+ pos += 2 + pos[1];
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/* when we use 2 rx ants we send IEEE80211_SMPS_OFF */
|
|
|
+/* when we use 1 rx ant we send IEEE80211_SMPS_STATIC */
|
|
|
+struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw,
|
|
|
+ enum ieee80211_smps_mode smps, u8 *da, u8 *bssid)
|
|
|
+{
|
|
|
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
|
|
|
+ struct sk_buff *skb;
|
|
|
+ struct ieee80211_mgmt *action_frame;
|
|
|
+
|
|
|
+ /* 27 = header + category + action + smps mode */
|
|
|
+ skb = dev_alloc_skb(27 + hw->extra_tx_headroom);
|
|
|
+ if (!skb)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ skb_reserve(skb, hw->extra_tx_headroom);
|
|
|
+ action_frame = (void *)skb_put(skb, 27);
|
|
|
+ memset(action_frame, 0, 27);
|
|
|
+ memcpy(action_frame->da, da, ETH_ALEN);
|
|
|
+ memcpy(action_frame->sa, rtlefuse->dev_addr, ETH_ALEN);
|
|
|
+ memcpy(action_frame->bssid, bssid, ETH_ALEN);
|
|
|
+ action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
|
|
+ IEEE80211_STYPE_ACTION);
|
|
|
+ action_frame->u.action.category = WLAN_CATEGORY_HT;
|
|
|
+ action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS;
|
|
|
+ switch (smps) {
|
|
|
+ case IEEE80211_SMPS_AUTOMATIC:/* 0 */
|
|
|
+ case IEEE80211_SMPS_NUM_MODES:/* 4 */
|
|
|
+ WARN_ON(1);
|
|
|
+ case IEEE80211_SMPS_OFF:/* 1 */ /*MIMO_PS_NOLIMIT*/
|
|
|
+ action_frame->u.action.u.ht_smps.smps_control =
|
|
|
+ WLAN_HT_SMPS_CONTROL_DISABLED;/* 0 */
|
|
|
+ break;
|
|
|
+ case IEEE80211_SMPS_STATIC:/* 2 */ /*MIMO_PS_STATIC*/
|
|
|
+ action_frame->u.action.u.ht_smps.smps_control =
|
|
|
+ WLAN_HT_SMPS_CONTROL_STATIC;/* 1 */
|
|
|
+ break;
|
|
|
+ case IEEE80211_SMPS_DYNAMIC:/* 3 */ /*MIMO_PS_DYNAMIC*/
|
|
|
+ action_frame->u.action.u.ht_smps.smps_control =
|
|
|
+ WLAN_HT_SMPS_CONTROL_DYNAMIC;/* 3 */
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return skb;
|
|
|
+}
|
|
|
+
|
|
|
+int rtl_send_smps_action(struct ieee80211_hw *hw,
|
|
|
+ struct ieee80211_sta *sta, u8 *da, u8 *bssid,
|
|
|
+ enum ieee80211_smps_mode smps)
|
|
|
+{
|
|
|
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
|
|
|
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
|
|
|
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
|
|
|
+ struct sk_buff *skb = rtl_make_smps_action(hw, smps, da, bssid);
|
|
|
+ struct rtl_tcb_desc tcb_desc;
|
|
|
+ memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
|
|
|
+
|
|
|
+ if (rtlpriv->mac80211.act_scanning)
|
|
|
+ goto err_free;
|
|
|
+
|
|
|
+ if (!sta)
|
|
|
+ goto err_free;
|
|
|
+
|
|
|
+ if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON))
|
|
|
+ goto err_free;
|
|
|
+
|
|
|
+ if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
|
|
|
+ goto err_free;
|
|
|
+
|
|
|
+ /* this is a type = mgmt * stype = action frame */
|
|
|
+ if (skb) {
|
|
|
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
|
+ struct rtl_sta_info *sta_entry =
|
|
|
+ (struct rtl_sta_info *) sta->drv_priv;
|
|
|
+ sta_entry->mimo_ps = smps;
|
|
|
+ rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
|
|
|
+
|
|
|
+ info->control.rates[0].idx = 0;
|
|
|
+ info->control.sta = sta;
|
|
|
+ info->band = hw->conf.channel->band;
|
|
|
+#if 0
|
|
|
+ rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);
|
|
|
+#else
|
|
|
+ rtlpriv->intf_ops->adapter_tx(hw, skb);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+
|
|
|
+err_free:
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*********************************************************
|
|
|
+ *
|
|
|
+ * IOT functions
|
|
|
+ *
|
|
|
+ *********************************************************/
|
|
|
+static bool rtl_chk_vendor_ouisub(struct ieee80211_hw *hw,
|
|
|
+ struct octet_string vendor_ie)
|
|
|
+{
|
|
|
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
|
|
|
+ bool matched = false;
|
|
|
+ static u8 athcap_1[] = { 0x00, 0x03, 0x7F };
|
|
|
+ static u8 athcap_2[] = { 0x00, 0x13, 0x74 };
|
|
|
+ static u8 broadcap_1[] = { 0x00, 0x10, 0x18 };
|
|
|
+ static u8 broadcap_2[] = { 0x00, 0x0a, 0xf7 };
|
|
|
+ static u8 broadcap_3[] = { 0x00, 0x05, 0xb5 };
|
|
|
+ static u8 racap[] = { 0x00, 0x0c, 0x43 };
|
|
|
+ static u8 ciscocap[] = { 0x00, 0x40, 0x96 };
|
|
|
+ static u8 marvcap[] = { 0x00, 0x50, 0x43 };
|
|
|
+
|
|
|
+ if (memcmp(vendor_ie.octet, athcap_1, 3) == 0 ||
|
|
|
+ memcmp(vendor_ie.octet, athcap_2, 3) == 0) {
|
|
|
+ rtlpriv->mac80211.vendor = PEER_ATH;
|
|
|
+ matched = true;
|
|
|
+ } else if (memcmp(vendor_ie.octet, broadcap_1, 3) == 0 ||
|
|
|
+ memcmp(vendor_ie.octet, broadcap_2, 3) == 0 ||
|
|
|
+ memcmp(vendor_ie.octet, broadcap_3, 3) == 0) {
|
|
|
+ rtlpriv->mac80211.vendor = PEER_BROAD;
|
|
|
+ matched = true;
|
|
|
+ } else if (memcmp(vendor_ie.octet, racap, 3) == 0) {
|
|
|
+ rtlpriv->mac80211.vendor = PEER_RAL;
|
|
|
+ matched = true;
|
|
|
+ } else if (memcmp(vendor_ie.octet, ciscocap, 3) == 0) {
|
|
|
+ rtlpriv->mac80211.vendor = PEER_CISCO;
|
|
|
+ matched = true;
|
|
|
+ } else if (memcmp(vendor_ie.octet, marvcap, 3) == 0) {
|
|
|
+ rtlpriv->mac80211.vendor = PEER_MARV;
|
|
|
+ matched = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return matched;
|
|
|
+}
|
|
|
+
|
|
|
+bool rtl_find_221_ie(struct ieee80211_hw *hw, u8 *data,
|
|
|
+ unsigned int len)
|
|
|
+{
|
|
|
+ struct ieee80211_mgmt *mgmt = (void *)data;
|
|
|
+ struct octet_string vendor_ie;
|
|
|
+ u8 *pos, *end;
|
|
|
+
|
|
|
+ pos = (u8 *)mgmt->u.beacon.variable;
|
|
|
+ end = data + len;
|
|
|
+ while (pos < end) {
|
|
|
+ if (pos[0] == 221) {
|
|
|
+ vendor_ie.length = pos[1];
|
|
|
+ vendor_ie.octet = &pos[2];
|
|
|
+ if (rtl_chk_vendor_ouisub(hw, vendor_ie))
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pos + 2 + pos[1] > end)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ pos += 2 + pos[1];
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len)
|
|
|
+{
|
|
|
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
|
|
|
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
|
|
|
+ struct ieee80211_hdr *hdr = (void *)data;
|
|
|
+ u32 vendor = PEER_UNKNOWN;
|
|
|
+
|
|
|
+ static u8 ap3_1[3] = { 0x00, 0x14, 0xbf };
|
|
|
+ static u8 ap3_2[3] = { 0x00, 0x1a, 0x70 };
|
|
|
+ static u8 ap3_3[3] = { 0x00, 0x1d, 0x7e };
|
|
|
+ static u8 ap4_1[3] = { 0x00, 0x90, 0xcc };
|
|
|
+ static u8 ap4_2[3] = { 0x00, 0x0e, 0x2e };
|
|
|
+ static u8 ap4_3[3] = { 0x00, 0x18, 0x02 };
|
|
|
+ static u8 ap4_4[3] = { 0x00, 0x17, 0x3f };
|
|
|
+ static u8 ap4_5[3] = { 0x00, 0x1c, 0xdf };
|
|
|
+ static u8 ap5_1[3] = { 0x00, 0x1c, 0xf0 };
|
|
|
+ static u8 ap5_2[3] = { 0x00, 0x21, 0x91 };
|
|
|
+ static u8 ap5_3[3] = { 0x00, 0x24, 0x01 };
|
|
|
+ static u8 ap5_4[3] = { 0x00, 0x15, 0xe9 };
|
|
|
+ static u8 ap5_5[3] = { 0x00, 0x17, 0x9A };
|
|
|
+ static u8 ap5_6[3] = { 0x00, 0x18, 0xE7 };
|
|
|
+ static u8 ap6_1[3] = { 0x00, 0x17, 0x94 };
|
|
|
+ static u8 ap7_1[3] = { 0x00, 0x14, 0xa4 };
|
|
|
+
|
|
|
+ if (mac->opmode != NL80211_IFTYPE_STATION)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (mac->link_state == MAC80211_NOLINK) {
|
|
|
+ mac->vendor = PEER_UNKNOWN;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mac->cnt_after_linked > 2)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* check if this really is a beacon */
|
|
|
+ if (!ieee80211_is_beacon(hdr->frame_control))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* min. beacon length + FCS_LEN */
|
|
|
+ if (len <= 40 + FCS_LEN)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* and only beacons from the associated BSSID, please */
|
|
|
+ if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (rtl_find_221_ie(hw, data, len))
|
|
|
+ vendor = mac->vendor;
|
|
|
+
|
|
|
+ if ((memcmp(mac->bssid, ap5_1, 3) == 0) ||
|
|
|
+ (memcmp(mac->bssid, ap5_2, 3) == 0) ||
|
|
|
+ (memcmp(mac->bssid, ap5_3, 3) == 0) ||
|
|
|
+ (memcmp(mac->bssid, ap5_4, 3) == 0) ||
|
|
|
+ (memcmp(mac->bssid, ap5_5, 3) == 0) ||
|
|
|
+ (memcmp(mac->bssid, ap5_6, 3) == 0) ||
|
|
|
+ vendor == PEER_ATH) {
|
|
|
+ vendor = PEER_ATH;
|
|
|
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>ath find\n"));
|
|
|
+ } else if ((memcmp(mac->bssid, ap4_4, 3) == 0) ||
|
|
|
+ (memcmp(mac->bssid, ap4_5, 3) == 0) ||
|
|
|
+ (memcmp(mac->bssid, ap4_1, 3) == 0) ||
|
|
|
+ (memcmp(mac->bssid, ap4_2, 3) == 0) ||
|
|
|
+ (memcmp(mac->bssid, ap4_3, 3) == 0) ||
|
|
|
+ vendor == PEER_RAL) {
|
|
|
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>ral findn\n"));
|
|
|
+ vendor = PEER_RAL;
|
|
|
+ } else if (memcmp(mac->bssid, ap6_1, 3) == 0 ||
|
|
|
+ vendor == PEER_CISCO) {
|
|
|
+ vendor = PEER_CISCO;
|
|
|
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>cisco find\n"));
|
|
|
+ } else if ((memcmp(mac->bssid, ap3_1, 3) == 0) ||
|
|
|
+ (memcmp(mac->bssid, ap3_2, 3) == 0) ||
|
|
|
+ (memcmp(mac->bssid, ap3_3, 3) == 0) ||
|
|
|
+ vendor == PEER_BROAD) {
|
|
|
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>broad find\n"));
|
|
|
+ vendor = PEER_BROAD;
|
|
|
+ } else if (memcmp(mac->bssid, ap7_1, 3) == 0 ||
|
|
|
+ vendor == PEER_MARV) {
|
|
|
+ vendor = PEER_MARV;
|
|
|
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>marv find\n"));
|
|
|
+ }
|
|
|
+
|
|
|
+ mac->vendor = vendor;
|
|
|
+}
|
|
|
+
|
|
|
/*********************************************************
|
|
|
*
|
|
|
* sysfs functions
|
|
|
@@ -941,12 +1414,13 @@ static int __init rtl_core_module_init(void)
|
|
|
if (rtl_rate_control_register())
|
|
|
printk(KERN_ERR "rtlwifi: Unable to register rtl_rc,"
|
|
|
"use default RC !!\n");
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static void __exit rtl_core_module_exit(void)
|
|
|
{
|
|
|
- /*RC*/
|
|
|
+ /*RC*/
|
|
|
rtl_rate_control_unregister();
|
|
|
}
|
|
|
|