|
@@ -1319,6 +1319,43 @@ static u32 wl18xx_pre_pkt_send(struct wl1271 *wl,
|
|
|
return buf_offset;
|
|
|
}
|
|
|
|
|
|
+static void wl18xx_sta_rc_update(struct wl1271 *wl,
|
|
|
+ struct wl12xx_vif *wlvif,
|
|
|
+ struct ieee80211_sta *sta,
|
|
|
+ u32 changed)
|
|
|
+{
|
|
|
+ bool wide = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
|
|
+
|
|
|
+ wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide);
|
|
|
+
|
|
|
+ if (!(changed & IEEE80211_RC_BW_CHANGED))
|
|
|
+ return;
|
|
|
+
|
|
|
+ mutex_lock(&wl->mutex);
|
|
|
+
|
|
|
+ /* sanity */
|
|
|
+ if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS))
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ /* ignore the change before association */
|
|
|
+ if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we started out as wide, we can change the operation mode. If we
|
|
|
+ * thought this was a 20mhz AP, we have to reconnect
|
|
|
+ */
|
|
|
+ if (wlvif->sta.role_chan_type == NL80211_CHAN_HT40MINUS ||
|
|
|
+ wlvif->sta.role_chan_type == NL80211_CHAN_HT40PLUS)
|
|
|
+ wl18xx_acx_peer_ht_operation_mode(wl, wlvif->sta.hlid, wide);
|
|
|
+ else
|
|
|
+ ieee80211_connection_loss(wl12xx_wlvif_to_vif(wlvif));
|
|
|
+
|
|
|
+out:
|
|
|
+ mutex_unlock(&wl->mutex);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
static int wl18xx_setup(struct wl1271 *wl);
|
|
|
|
|
|
static struct wlcore_ops wl18xx_ops = {
|
|
@@ -1354,6 +1391,7 @@ static struct wlcore_ops wl18xx_ops = {
|
|
|
.set_key = wl18xx_set_key,
|
|
|
.channel_switch = wl18xx_cmd_channel_switch,
|
|
|
.pre_pkt_send = wl18xx_pre_pkt_send,
|
|
|
+ .sta_rc_update = wl18xx_sta_rc_update,
|
|
|
};
|
|
|
|
|
|
/* HT cap appropriate for wide channels in 2Ghz */
|