diff options
-rw-r--r-- | include/net/mac80211.h | 3 | ||||
-rw-r--r-- | net/mac80211/ieee80211.c | 51 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/ieee80211_sta.c | 32 |
4 files changed, 89 insertions, 0 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 79e96455438..0d67b331ee7 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -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); }; /** diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 4f8b6653e36..d6a97a68a62 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -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); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 66b6cf3a62a..2dcb9425fe8 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -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; diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 1d553d78b22..87830c04a1c 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -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); |