Commit d3c990fb authored by Ron Rindjunsky's avatar Ron Rindjunsky Committed by David S. Miller

mac80211: adding 802.11n configuration flows

This patch configures the 802.11n mode of operation
internally in ieee80211_conf structure and in the low-level
driver as well (through op conf_ht).
It does not include AP configuration flows.
Signed-off-by: default avatarRon Rindjunsky <ron.rindjunsky@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fd4c7f2f
......@@ -1041,6 +1041,8 @@ enum ieee80211_erp_change_flags {
* @tx_last_beacon: Determine whether the last IBSS beacon was sent by us.
* This is needed only for IBSS mode and the result of this function is
* used to determine whether to reply to Probe Requests.
*
* @conf_ht: Configures low level driver with 802.11n HT data. Must be atomic.
*/
struct ieee80211_ops {
int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb,
......@@ -1086,6 +1088,7 @@ struct ieee80211_ops {
struct sk_buff *skb,
struct ieee80211_tx_control *control);
int (*tx_last_beacon)(struct ieee80211_hw *hw);
int (*conf_ht)(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
};
/**
......
......@@ -34,6 +34,8 @@
#include "debugfs.h"
#include "debugfs_netdev.h"
#define SUPP_MCS_SET_LEN 16
/*
* For seeing transmitted packets on monitor interfaces
* we have a radiotap header too.
......@@ -563,6 +565,55 @@ int ieee80211_hw_config(struct ieee80211_local *local)
return ret;
}
/**
* ieee80211_hw_config_ht should be used only after legacy configuration
* has been determined, as ht configuration depends upon the hardware's
* HT abilities for a _specific_ band.
*/
int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht,
struct ieee80211_ht_info *req_ht_cap,
struct ieee80211_ht_bss_info *req_bss_cap)
{
struct ieee80211_conf *conf = &local->hw.conf;
struct ieee80211_hw_mode *mode = conf->mode;
int i;
/* HT is not supported */
if (!mode->ht_info.ht_supported) {
conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
return -EOPNOTSUPP;
}
/* disable HT */
if (!enable_ht) {
conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
} else {
conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
conf->ht_conf.cap = req_ht_cap->cap & mode->ht_info.cap;
conf->ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
conf->ht_conf.cap |=
mode->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
conf->ht_bss_conf.primary_channel =
req_bss_cap->primary_channel;
conf->ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
conf->ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
for (i = 0; i < SUPP_MCS_SET_LEN; i++)
conf->ht_conf.supp_mcs_set[i] =
mode->ht_info.supp_mcs_set[i] &
req_ht_cap->supp_mcs_set[i];
/* In STA mode, this gives us indication
* to the AP's mode of operation */
conf->ht_conf.ht_supported = 1;
conf->ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
conf->ht_conf.ampdu_density = req_ht_cap->ampdu_density;
}
local->ops->conf_ht(local_to_hw(local), &local->hw.conf);
return 0;
}
void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
......
......@@ -708,6 +708,9 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
void ieee80211_if_setup(struct net_device *dev);
struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local,
int phymode, int hwrate);
int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht,
struct ieee80211_ht_info *req_ht_cap,
struct ieee80211_ht_bss_info *req_bss_cap);
/* ieee80211_ioctl.c */
extern const struct iw_handler_def ieee80211_iw_handler_def;
......
......@@ -1437,6 +1437,19 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
}
sta->supp_rates = rates;
if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
local->ops->conf_ht) {
struct ieee80211_ht_bss_info bss_info;
ieee80211_ht_cap_ie_to_ht_info(
(struct ieee80211_ht_cap *)
elems.ht_cap_elem, &sta->ht_info);
ieee80211_ht_addt_info_ie_to_ht_bss_info(
(struct ieee80211_ht_addt_info *)
elems.ht_info_elem, &bss_info);
ieee80211_hw_config_ht(local, 1, &sta->ht_info, &bss_info);
}
rate_control_rate_init(sta, local);
if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
......@@ -1859,6 +1872,8 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
struct ieee80211_if_sta *ifsta;
size_t baselen;
struct ieee802_11_elems elems;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_conf *conf = &local->hw.conf;
ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 1);
......@@ -1881,6 +1896,23 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
if (elems.erp_info && elems.erp_info_len >= 1)
ieee80211_handle_erp_ie(dev, elems.erp_info[0]);
if (elems.ht_cap_elem && elems.ht_info_elem &&
elems.wmm_param && local->ops->conf_ht &&
conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
struct ieee80211_ht_bss_info bss_info;
ieee80211_ht_addt_info_ie_to_ht_bss_info(
(struct ieee80211_ht_addt_info *)
elems.ht_info_elem, &bss_info);
/* check if AP changed bss inforamation */
if ((conf->ht_bss_conf.primary_channel !=
bss_info.primary_channel) ||
(conf->ht_bss_conf.bss_cap != bss_info.bss_cap) ||
(conf->ht_bss_conf.bss_op_mode != bss_info.bss_op_mode))
ieee80211_hw_config_ht(local, 1, &conf->ht_conf,
&bss_info);
}
if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
elems.wmm_param_len);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment