diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 118 |
1 files changed, 105 insertions, 13 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 4bc8a9250cfd..334213571ad0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -316,6 +316,17 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy, | |||
316 | return 0; | 316 | return 0; |
317 | } | 317 | } |
318 | 318 | ||
319 | static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, int idx) | ||
320 | { | ||
321 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) { | ||
322 | struct ieee80211_supported_band *sband; | ||
323 | sband = sta->local->hw.wiphy->bands[ | ||
324 | sta->local->hw.conf.channel->band]; | ||
325 | rate->legacy = sband->bitrates[idx].bitrate; | ||
326 | } else | ||
327 | rate->mcs = idx; | ||
328 | } | ||
329 | |||
319 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | 330 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) |
320 | { | 331 | { |
321 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 332 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
@@ -330,6 +341,7 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
330 | STATION_INFO_TX_RETRIES | | 341 | STATION_INFO_TX_RETRIES | |
331 | STATION_INFO_TX_FAILED | | 342 | STATION_INFO_TX_FAILED | |
332 | STATION_INFO_TX_BITRATE | | 343 | STATION_INFO_TX_BITRATE | |
344 | STATION_INFO_RX_BITRATE | | ||
333 | STATION_INFO_RX_DROP_MISC; | 345 | STATION_INFO_RX_DROP_MISC; |
334 | 346 | ||
335 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | 347 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); |
@@ -355,15 +367,16 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
355 | sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 367 | sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
356 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI) | 368 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI) |
357 | sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; | 369 | sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; |
370 | rate_idx_to_bitrate(&sinfo->txrate, sta, sta->last_tx_rate.idx); | ||
358 | 371 | ||
359 | if (!(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) { | 372 | sinfo->rxrate.flags = 0; |
360 | struct ieee80211_supported_band *sband; | 373 | if (sta->last_rx_rate_flag & RX_FLAG_HT) |
361 | sband = sta->local->hw.wiphy->bands[ | 374 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS; |
362 | sta->local->hw.conf.channel->band]; | 375 | if (sta->last_rx_rate_flag & RX_FLAG_40MHZ) |
363 | sinfo->txrate.legacy = | 376 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
364 | sband->bitrates[sta->last_tx_rate.idx].bitrate; | 377 | if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) |
365 | } else | 378 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI; |
366 | sinfo->txrate.mcs = sta->last_tx_rate.idx; | 379 | rate_idx_to_bitrate(&sinfo->rxrate, sta, sta->last_rx_rate_idx); |
367 | 380 | ||
368 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 381 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
369 | #ifdef CONFIG_MAC80211_MESH | 382 | #ifdef CONFIG_MAC80211_MESH |
@@ -821,6 +834,10 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
821 | 834 | ||
822 | rcu_read_unlock(); | 835 | rcu_read_unlock(); |
823 | 836 | ||
837 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
838 | params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) | ||
839 | ieee80211_recalc_ps(local, -1); | ||
840 | |||
824 | return 0; | 841 | return 0; |
825 | } | 842 | } |
826 | 843 | ||
@@ -1215,6 +1232,9 @@ static int ieee80211_set_channel(struct wiphy *wiphy, | |||
1215 | { | 1232 | { |
1216 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1233 | struct ieee80211_local *local = wiphy_priv(wiphy); |
1217 | struct ieee80211_sub_if_data *sdata = NULL; | 1234 | struct ieee80211_sub_if_data *sdata = NULL; |
1235 | struct ieee80211_channel *old_oper; | ||
1236 | enum nl80211_channel_type old_oper_type; | ||
1237 | enum nl80211_channel_type old_vif_oper_type= NL80211_CHAN_NO_HT; | ||
1218 | 1238 | ||
1219 | if (netdev) | 1239 | if (netdev) |
1220 | sdata = IEEE80211_DEV_TO_SUB_IF(netdev); | 1240 | sdata = IEEE80211_DEV_TO_SUB_IF(netdev); |
@@ -1232,13 +1252,23 @@ static int ieee80211_set_channel(struct wiphy *wiphy, | |||
1232 | break; | 1252 | break; |
1233 | } | 1253 | } |
1234 | 1254 | ||
1235 | local->oper_channel = chan; | 1255 | if (sdata) |
1256 | old_vif_oper_type = sdata->vif.bss_conf.channel_type; | ||
1257 | old_oper_type = local->_oper_channel_type; | ||
1236 | 1258 | ||
1237 | if (!ieee80211_set_channel_type(local, sdata, channel_type)) | 1259 | if (!ieee80211_set_channel_type(local, sdata, channel_type)) |
1238 | return -EBUSY; | 1260 | return -EBUSY; |
1239 | 1261 | ||
1240 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 1262 | old_oper = local->oper_channel; |
1241 | if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR) | 1263 | local->oper_channel = chan; |
1264 | |||
1265 | /* Update driver if changes were actually made. */ | ||
1266 | if ((old_oper != local->oper_channel) || | ||
1267 | (old_oper_type != local->_oper_channel_type)) | ||
1268 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
1269 | |||
1270 | if ((sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR) && | ||
1271 | old_vif_oper_type != sdata->vif.bss_conf.channel_type) | ||
1242 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); | 1272 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); |
1243 | 1273 | ||
1244 | return 0; | 1274 | return 0; |
@@ -1274,8 +1304,11 @@ static int ieee80211_scan(struct wiphy *wiphy, | |||
1274 | case NL80211_IFTYPE_P2P_GO: | 1304 | case NL80211_IFTYPE_P2P_GO: |
1275 | if (sdata->local->ops->hw_scan) | 1305 | if (sdata->local->ops->hw_scan) |
1276 | break; | 1306 | break; |
1277 | /* FIXME: implement NoA while scanning in software */ | 1307 | /* |
1278 | return -EOPNOTSUPP; | 1308 | * FIXME: implement NoA while scanning in software, |
1309 | * for now fall through to allow scanning only when | ||
1310 | * beaconing hasn't been configured yet | ||
1311 | */ | ||
1279 | case NL80211_IFTYPE_AP: | 1312 | case NL80211_IFTYPE_AP: |
1280 | if (sdata->u.ap.beacon) | 1313 | if (sdata->u.ap.beacon) |
1281 | return -EOPNOTSUPP; | 1314 | return -EOPNOTSUPP; |
@@ -1784,6 +1817,33 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
1784 | 1817 | ||
1785 | *cookie = (unsigned long) skb; | 1818 | *cookie = (unsigned long) skb; |
1786 | 1819 | ||
1820 | if (is_offchan && local->ops->offchannel_tx) { | ||
1821 | int ret; | ||
1822 | |||
1823 | IEEE80211_SKB_CB(skb)->band = chan->band; | ||
1824 | |||
1825 | mutex_lock(&local->mtx); | ||
1826 | |||
1827 | if (local->hw_offchan_tx_cookie) { | ||
1828 | mutex_unlock(&local->mtx); | ||
1829 | return -EBUSY; | ||
1830 | } | ||
1831 | |||
1832 | /* TODO: bitrate control, TX processing? */ | ||
1833 | ret = drv_offchannel_tx(local, skb, chan, channel_type, wait); | ||
1834 | |||
1835 | if (ret == 0) | ||
1836 | local->hw_offchan_tx_cookie = *cookie; | ||
1837 | mutex_unlock(&local->mtx); | ||
1838 | |||
1839 | /* | ||
1840 | * Allow driver to return 1 to indicate it wants to have the | ||
1841 | * frame transmitted with a remain_on_channel + regular TX. | ||
1842 | */ | ||
1843 | if (ret != 1) | ||
1844 | return ret; | ||
1845 | } | ||
1846 | |||
1787 | if (is_offchan && local->ops->remain_on_channel) { | 1847 | if (is_offchan && local->ops->remain_on_channel) { |
1788 | unsigned int duration; | 1848 | unsigned int duration; |
1789 | int ret; | 1849 | int ret; |
@@ -1822,6 +1882,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
1822 | *cookie ^= 2; | 1882 | *cookie ^= 2; |
1823 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN; | 1883 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN; |
1824 | local->hw_roc_skb = skb; | 1884 | local->hw_roc_skb = skb; |
1885 | local->hw_roc_skb_for_status = skb; | ||
1825 | mutex_unlock(&local->mtx); | 1886 | mutex_unlock(&local->mtx); |
1826 | 1887 | ||
1827 | return 0; | 1888 | return 0; |
@@ -1846,6 +1907,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
1846 | 1907 | ||
1847 | wk->type = IEEE80211_WORK_OFFCHANNEL_TX; | 1908 | wk->type = IEEE80211_WORK_OFFCHANNEL_TX; |
1848 | wk->chan = chan; | 1909 | wk->chan = chan; |
1910 | wk->chan_type = channel_type; | ||
1849 | wk->sdata = sdata; | 1911 | wk->sdata = sdata; |
1850 | wk->done = ieee80211_offchan_tx_done; | 1912 | wk->done = ieee80211_offchan_tx_done; |
1851 | wk->offchan_tx.frame = skb; | 1913 | wk->offchan_tx.frame = skb; |
@@ -1868,6 +1930,18 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, | |||
1868 | 1930 | ||
1869 | mutex_lock(&local->mtx); | 1931 | mutex_lock(&local->mtx); |
1870 | 1932 | ||
1933 | if (local->ops->offchannel_tx_cancel_wait && | ||
1934 | local->hw_offchan_tx_cookie == cookie) { | ||
1935 | ret = drv_offchannel_tx_cancel_wait(local); | ||
1936 | |||
1937 | if (!ret) | ||
1938 | local->hw_offchan_tx_cookie = 0; | ||
1939 | |||
1940 | mutex_unlock(&local->mtx); | ||
1941 | |||
1942 | return ret; | ||
1943 | } | ||
1944 | |||
1871 | if (local->ops->cancel_remain_on_channel) { | 1945 | if (local->ops->cancel_remain_on_channel) { |
1872 | cookie ^= 2; | 1946 | cookie ^= 2; |
1873 | ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); | 1947 | ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); |
@@ -1875,6 +1949,7 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, | |||
1875 | if (ret == 0) { | 1949 | if (ret == 0) { |
1876 | kfree_skb(local->hw_roc_skb); | 1950 | kfree_skb(local->hw_roc_skb); |
1877 | local->hw_roc_skb = NULL; | 1951 | local->hw_roc_skb = NULL; |
1952 | local->hw_roc_skb_for_status = NULL; | ||
1878 | } | 1953 | } |
1879 | 1954 | ||
1880 | mutex_unlock(&local->mtx); | 1955 | mutex_unlock(&local->mtx); |
@@ -1937,6 +2012,21 @@ static int ieee80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant) | |||
1937 | return drv_get_antenna(local, tx_ant, rx_ant); | 2012 | return drv_get_antenna(local, tx_ant, rx_ant); |
1938 | } | 2013 | } |
1939 | 2014 | ||
2015 | static int ieee80211_set_ringparam(struct wiphy *wiphy, u32 tx, u32 rx) | ||
2016 | { | ||
2017 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
2018 | |||
2019 | return drv_set_ringparam(local, tx, rx); | ||
2020 | } | ||
2021 | |||
2022 | static void ieee80211_get_ringparam(struct wiphy *wiphy, | ||
2023 | u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) | ||
2024 | { | ||
2025 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
2026 | |||
2027 | drv_get_ringparam(local, tx, tx_max, rx, rx_max); | ||
2028 | } | ||
2029 | |||
1940 | struct cfg80211_ops mac80211_config_ops = { | 2030 | struct cfg80211_ops mac80211_config_ops = { |
1941 | .add_virtual_intf = ieee80211_add_iface, | 2031 | .add_virtual_intf = ieee80211_add_iface, |
1942 | .del_virtual_intf = ieee80211_del_iface, | 2032 | .del_virtual_intf = ieee80211_del_iface, |
@@ -1994,4 +2084,6 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1994 | .mgmt_frame_register = ieee80211_mgmt_frame_register, | 2084 | .mgmt_frame_register = ieee80211_mgmt_frame_register, |
1995 | .set_antenna = ieee80211_set_antenna, | 2085 | .set_antenna = ieee80211_set_antenna, |
1996 | .get_antenna = ieee80211_get_antenna, | 2086 | .get_antenna = ieee80211_get_antenna, |
2087 | .set_ringparam = ieee80211_set_ringparam, | ||
2088 | .get_ringparam = ieee80211_get_ringparam, | ||
1997 | }; | 2089 | }; |