diff options
Diffstat (limited to 'net/mac80211')
31 files changed, 1511 insertions, 255 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index aeb6a483b3bc..75cc6801a431 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -33,6 +33,13 @@ config MAC80211_RC_MINSTREL_HT | |||
33 | ---help--- | 33 | ---help--- |
34 | This option enables the 'minstrel_ht' TX rate control algorithm | 34 | This option enables the 'minstrel_ht' TX rate control algorithm |
35 | 35 | ||
36 | config MAC80211_RC_MINSTREL_VHT | ||
37 | bool "Minstrel 802.11ac support" if EXPERT | ||
38 | depends on MAC80211_RC_MINSTREL_HT | ||
39 | default n | ||
40 | ---help--- | ||
41 | This option enables VHT in the 'minstrel_ht' TX rate control algorithm | ||
42 | |||
36 | choice | 43 | choice |
37 | prompt "Default rate control algorithm" | 44 | prompt "Default rate control algorithm" |
38 | depends on MAC80211_HAS_RC | 45 | depends on MAC80211_HAS_RC |
@@ -169,6 +176,17 @@ config MAC80211_HT_DEBUG | |||
169 | 176 | ||
170 | Do not select this option. | 177 | Do not select this option. |
171 | 178 | ||
179 | config MAC80211_OCB_DEBUG | ||
180 | bool "Verbose OCB debugging" | ||
181 | depends on MAC80211_DEBUG_MENU | ||
182 | ---help--- | ||
183 | Selecting this option causes mac80211 to print out | ||
184 | very verbose OCB debugging messages. It should not | ||
185 | be selected on production systems as those messages | ||
186 | are remotely triggerable. | ||
187 | |||
188 | Do not select this option. | ||
189 | |||
172 | config MAC80211_IBSS_DEBUG | 190 | config MAC80211_IBSS_DEBUG |
173 | bool "Verbose IBSS debugging" | 191 | bool "Verbose IBSS debugging" |
174 | depends on MAC80211_DEBUG_MENU | 192 | depends on MAC80211_DEBUG_MENU |
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 7273d2796dd1..e53671b1105e 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -27,7 +27,8 @@ mac80211-y := \ | |||
27 | event.o \ | 27 | event.o \ |
28 | chan.o \ | 28 | chan.o \ |
29 | trace.o mlme.o \ | 29 | trace.o mlme.o \ |
30 | tdls.o | 30 | tdls.o \ |
31 | ocb.o | ||
31 | 32 | ||
32 | mac80211-$(CONFIG_MAC80211_LEDS) += led.o | 33 | mac80211-$(CONFIG_MAC80211_LEDS) += led.o |
33 | mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ | 34 | mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index d6986f3aa5c4..9242c60048cf 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -149,11 +149,6 @@ void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, | |||
149 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); | 149 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); |
150 | } | 150 | } |
151 | 151 | ||
152 | static inline int ieee80211_ac_from_tid(int tid) | ||
153 | { | ||
154 | return ieee802_1d_to_ac[tid & 7]; | ||
155 | } | ||
156 | |||
157 | /* | 152 | /* |
158 | * When multiple aggregation sessions on multiple stations | 153 | * When multiple aggregation sessions on multiple stations |
159 | * are being created/destroyed simultaneously, we need to | 154 | * are being created/destroyed simultaneously, we need to |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 343da1e35025..06185940cbb6 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "cfg.h" | 20 | #include "cfg.h" |
21 | #include "rate.h" | 21 | #include "rate.h" |
22 | #include "mesh.h" | 22 | #include "mesh.h" |
23 | #include "wme.h" | ||
23 | 24 | ||
24 | static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, | 25 | static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, |
25 | const char *name, | 26 | const char *name, |
@@ -190,7 +191,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
190 | * receive the key. When wpa_supplicant has roamed | 191 | * receive the key. When wpa_supplicant has roamed |
191 | * using FT, it attempts to set the key before | 192 | * using FT, it attempts to set the key before |
192 | * association has completed, this rejects that attempt | 193 | * association has completed, this rejects that attempt |
193 | * so it will set the key again after assocation. | 194 | * so it will set the key again after association. |
194 | * | 195 | * |
195 | * TODO: accept the key if we have a station entry and | 196 | * TODO: accept the key if we have a station entry and |
196 | * add it to the device after the station. | 197 | * add it to the device after the station. |
@@ -229,6 +230,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
229 | case NUM_NL80211_IFTYPES: | 230 | case NUM_NL80211_IFTYPES: |
230 | case NL80211_IFTYPE_P2P_CLIENT: | 231 | case NL80211_IFTYPE_P2P_CLIENT: |
231 | case NL80211_IFTYPE_P2P_GO: | 232 | case NL80211_IFTYPE_P2P_GO: |
233 | case NL80211_IFTYPE_OCB: | ||
232 | /* shouldn't happen */ | 234 | /* shouldn't happen */ |
233 | WARN_ON_ONCE(1); | 235 | WARN_ON_ONCE(1); |
234 | break; | 236 | break; |
@@ -1225,14 +1227,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
1225 | } | 1227 | } |
1226 | 1228 | ||
1227 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | 1229 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, |
1228 | const u8 *mac) | 1230 | struct station_del_parameters *params) |
1229 | { | 1231 | { |
1230 | struct ieee80211_sub_if_data *sdata; | 1232 | struct ieee80211_sub_if_data *sdata; |
1231 | 1233 | ||
1232 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1234 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1233 | 1235 | ||
1234 | if (mac) | 1236 | if (params->mac) |
1235 | return sta_info_destroy_addr_bss(sdata, mac); | 1237 | return sta_info_destroy_addr_bss(sdata, params->mac); |
1236 | 1238 | ||
1237 | sta_info_flush(sdata); | 1239 | sta_info_flush(sdata); |
1238 | return 0; | 1240 | return 0; |
@@ -1516,6 +1518,57 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
1516 | return 0; | 1518 | return 0; |
1517 | } | 1519 | } |
1518 | 1520 | ||
1521 | static void mpp_set_pinfo(struct mesh_path *mpath, u8 *mpp, | ||
1522 | struct mpath_info *pinfo) | ||
1523 | { | ||
1524 | memset(pinfo, 0, sizeof(*pinfo)); | ||
1525 | memcpy(mpp, mpath->mpp, ETH_ALEN); | ||
1526 | |||
1527 | pinfo->generation = mpp_paths_generation; | ||
1528 | } | ||
1529 | |||
1530 | static int ieee80211_get_mpp(struct wiphy *wiphy, struct net_device *dev, | ||
1531 | u8 *dst, u8 *mpp, struct mpath_info *pinfo) | ||
1532 | |||
1533 | { | ||
1534 | struct ieee80211_sub_if_data *sdata; | ||
1535 | struct mesh_path *mpath; | ||
1536 | |||
1537 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1538 | |||
1539 | rcu_read_lock(); | ||
1540 | mpath = mpp_path_lookup(sdata, dst); | ||
1541 | if (!mpath) { | ||
1542 | rcu_read_unlock(); | ||
1543 | return -ENOENT; | ||
1544 | } | ||
1545 | memcpy(dst, mpath->dst, ETH_ALEN); | ||
1546 | mpp_set_pinfo(mpath, mpp, pinfo); | ||
1547 | rcu_read_unlock(); | ||
1548 | return 0; | ||
1549 | } | ||
1550 | |||
1551 | static int ieee80211_dump_mpp(struct wiphy *wiphy, struct net_device *dev, | ||
1552 | int idx, u8 *dst, u8 *mpp, | ||
1553 | struct mpath_info *pinfo) | ||
1554 | { | ||
1555 | struct ieee80211_sub_if_data *sdata; | ||
1556 | struct mesh_path *mpath; | ||
1557 | |||
1558 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1559 | |||
1560 | rcu_read_lock(); | ||
1561 | mpath = mpp_path_lookup_by_idx(sdata, idx); | ||
1562 | if (!mpath) { | ||
1563 | rcu_read_unlock(); | ||
1564 | return -ENOENT; | ||
1565 | } | ||
1566 | memcpy(dst, mpath->dst, ETH_ALEN); | ||
1567 | mpp_set_pinfo(mpath, mpp, pinfo); | ||
1568 | rcu_read_unlock(); | ||
1569 | return 0; | ||
1570 | } | ||
1571 | |||
1519 | static int ieee80211_get_mesh_config(struct wiphy *wiphy, | 1572 | static int ieee80211_get_mesh_config(struct wiphy *wiphy, |
1520 | struct net_device *dev, | 1573 | struct net_device *dev, |
1521 | struct mesh_config *conf) | 1574 | struct mesh_config *conf) |
@@ -1966,6 +2019,17 @@ static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | |||
1966 | return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev)); | 2019 | return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev)); |
1967 | } | 2020 | } |
1968 | 2021 | ||
2022 | static int ieee80211_join_ocb(struct wiphy *wiphy, struct net_device *dev, | ||
2023 | struct ocb_setup *setup) | ||
2024 | { | ||
2025 | return ieee80211_ocb_join(IEEE80211_DEV_TO_SUB_IF(dev), setup); | ||
2026 | } | ||
2027 | |||
2028 | static int ieee80211_leave_ocb(struct wiphy *wiphy, struct net_device *dev) | ||
2029 | { | ||
2030 | return ieee80211_ocb_leave(IEEE80211_DEV_TO_SUB_IF(dev)); | ||
2031 | } | ||
2032 | |||
1969 | static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, | 2033 | static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, |
1970 | int rate[IEEE80211_NUM_BANDS]) | 2034 | int rate[IEEE80211_NUM_BANDS]) |
1971 | { | 2035 | { |
@@ -2081,6 +2145,9 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, | |||
2081 | struct ieee80211_local *local = wiphy_priv(wiphy); | 2145 | struct ieee80211_local *local = wiphy_priv(wiphy); |
2082 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | 2146 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
2083 | 2147 | ||
2148 | if (local->ops->get_txpower) | ||
2149 | return drv_get_txpower(local, sdata, dbm); | ||
2150 | |||
2084 | if (!local->use_chanctx) | 2151 | if (!local->use_chanctx) |
2085 | *dbm = local->hw.conf.power_level; | 2152 | *dbm = local->hw.conf.power_level; |
2086 | else | 2153 | else |
@@ -2850,11 +2917,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) | |||
2850 | if (sdata->reserved_ready) | 2917 | if (sdata->reserved_ready) |
2851 | return 0; | 2918 | return 0; |
2852 | 2919 | ||
2853 | err = ieee80211_vif_use_reserved_context(sdata); | 2920 | return ieee80211_vif_use_reserved_context(sdata); |
2854 | if (err) | ||
2855 | return err; | ||
2856 | |||
2857 | return 0; | ||
2858 | } | 2921 | } |
2859 | 2922 | ||
2860 | if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, | 2923 | if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, |
@@ -2868,7 +2931,6 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) | |||
2868 | return err; | 2931 | return err; |
2869 | 2932 | ||
2870 | ieee80211_bss_info_change_notify(sdata, changed); | 2933 | ieee80211_bss_info_change_notify(sdata, changed); |
2871 | cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); | ||
2872 | 2934 | ||
2873 | if (sdata->csa_block_tx) { | 2935 | if (sdata->csa_block_tx) { |
2874 | ieee80211_wake_vif_queues(local, sdata, | 2936 | ieee80211_wake_vif_queues(local, sdata, |
@@ -2876,6 +2938,12 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) | |||
2876 | sdata->csa_block_tx = false; | 2938 | sdata->csa_block_tx = false; |
2877 | } | 2939 | } |
2878 | 2940 | ||
2941 | err = drv_post_channel_switch(sdata); | ||
2942 | if (err) | ||
2943 | return err; | ||
2944 | |||
2945 | cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); | ||
2946 | |||
2879 | return 0; | 2947 | return 0; |
2880 | } | 2948 | } |
2881 | 2949 | ||
@@ -3053,9 +3121,11 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3053 | { | 3121 | { |
3054 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 3122 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
3055 | struct ieee80211_local *local = sdata->local; | 3123 | struct ieee80211_local *local = sdata->local; |
3124 | struct ieee80211_channel_switch ch_switch; | ||
3056 | struct ieee80211_chanctx_conf *conf; | 3125 | struct ieee80211_chanctx_conf *conf; |
3057 | struct ieee80211_chanctx *chanctx; | 3126 | struct ieee80211_chanctx *chanctx; |
3058 | int err, changed = 0; | 3127 | u32 changed = 0; |
3128 | int err; | ||
3059 | 3129 | ||
3060 | sdata_assert_lock(sdata); | 3130 | sdata_assert_lock(sdata); |
3061 | lockdep_assert_held(&local->mtx); | 3131 | lockdep_assert_held(&local->mtx); |
@@ -3088,6 +3158,10 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3088 | goto out; | 3158 | goto out; |
3089 | } | 3159 | } |
3090 | 3160 | ||
3161 | err = drv_pre_channel_switch(sdata, &ch_switch); | ||
3162 | if (err) | ||
3163 | goto out; | ||
3164 | |||
3091 | err = ieee80211_vif_reserve_chanctx(sdata, ¶ms->chandef, | 3165 | err = ieee80211_vif_reserve_chanctx(sdata, ¶ms->chandef, |
3092 | chanctx->mode, | 3166 | chanctx->mode, |
3093 | params->radar_required); | 3167 | params->radar_required); |
@@ -3101,6 +3175,12 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3101 | goto out; | 3175 | goto out; |
3102 | } | 3176 | } |
3103 | 3177 | ||
3178 | ch_switch.timestamp = 0; | ||
3179 | ch_switch.device_timestamp = 0; | ||
3180 | ch_switch.block_tx = params->block_tx; | ||
3181 | ch_switch.chandef = params->chandef; | ||
3182 | ch_switch.count = params->count; | ||
3183 | |||
3104 | err = ieee80211_set_csa_beacon(sdata, params, &changed); | 3184 | err = ieee80211_set_csa_beacon(sdata, params, &changed); |
3105 | if (err) { | 3185 | if (err) { |
3106 | ieee80211_vif_unreserve_chanctx(sdata); | 3186 | ieee80211_vif_unreserve_chanctx(sdata); |
@@ -3521,6 +3601,76 @@ static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy, | |||
3521 | return ret; | 3601 | return ret; |
3522 | } | 3602 | } |
3523 | 3603 | ||
3604 | static int ieee80211_add_tx_ts(struct wiphy *wiphy, struct net_device *dev, | ||
3605 | u8 tsid, const u8 *peer, u8 up, | ||
3606 | u16 admitted_time) | ||
3607 | { | ||
3608 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
3609 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3610 | int ac = ieee802_1d_to_ac[up]; | ||
3611 | |||
3612 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
3613 | return -EOPNOTSUPP; | ||
3614 | |||
3615 | if (!(sdata->wmm_acm & BIT(up))) | ||
3616 | return -EINVAL; | ||
3617 | |||
3618 | if (ifmgd->tx_tspec[ac].admitted_time) | ||
3619 | return -EBUSY; | ||
3620 | |||
3621 | if (admitted_time) { | ||
3622 | ifmgd->tx_tspec[ac].admitted_time = 32 * admitted_time; | ||
3623 | ifmgd->tx_tspec[ac].tsid = tsid; | ||
3624 | ifmgd->tx_tspec[ac].up = up; | ||
3625 | } | ||
3626 | |||
3627 | return 0; | ||
3628 | } | ||
3629 | |||
3630 | static int ieee80211_del_tx_ts(struct wiphy *wiphy, struct net_device *dev, | ||
3631 | u8 tsid, const u8 *peer) | ||
3632 | { | ||
3633 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
3634 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3635 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
3636 | int ac; | ||
3637 | |||
3638 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
3639 | struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac]; | ||
3640 | |||
3641 | /* skip unused entries */ | ||
3642 | if (!tx_tspec->admitted_time) | ||
3643 | continue; | ||
3644 | |||
3645 | if (tx_tspec->tsid != tsid) | ||
3646 | continue; | ||
3647 | |||
3648 | /* due to this new packets will be reassigned to non-ACM ACs */ | ||
3649 | tx_tspec->up = -1; | ||
3650 | |||
3651 | /* Make sure that all packets have been sent to avoid to | ||
3652 | * restore the QoS params on packets that are still on the | ||
3653 | * queues. | ||
3654 | */ | ||
3655 | synchronize_net(); | ||
3656 | ieee80211_flush_queues(local, sdata); | ||
3657 | |||
3658 | /* restore the normal QoS parameters | ||
3659 | * (unconditionally to avoid races) | ||
3660 | */ | ||
3661 | tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE; | ||
3662 | tx_tspec->downgraded = false; | ||
3663 | ieee80211_sta_handle_tspec_ac_params(sdata); | ||
3664 | |||
3665 | /* finally clear all the data */ | ||
3666 | memset(tx_tspec, 0, sizeof(*tx_tspec)); | ||
3667 | |||
3668 | return 0; | ||
3669 | } | ||
3670 | |||
3671 | return -ENOENT; | ||
3672 | } | ||
3673 | |||
3524 | const struct cfg80211_ops mac80211_config_ops = { | 3674 | const struct cfg80211_ops mac80211_config_ops = { |
3525 | .add_virtual_intf = ieee80211_add_iface, | 3675 | .add_virtual_intf = ieee80211_add_iface, |
3526 | .del_virtual_intf = ieee80211_del_iface, | 3676 | .del_virtual_intf = ieee80211_del_iface, |
@@ -3547,11 +3697,15 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
3547 | .change_mpath = ieee80211_change_mpath, | 3697 | .change_mpath = ieee80211_change_mpath, |
3548 | .get_mpath = ieee80211_get_mpath, | 3698 | .get_mpath = ieee80211_get_mpath, |
3549 | .dump_mpath = ieee80211_dump_mpath, | 3699 | .dump_mpath = ieee80211_dump_mpath, |
3700 | .get_mpp = ieee80211_get_mpp, | ||
3701 | .dump_mpp = ieee80211_dump_mpp, | ||
3550 | .update_mesh_config = ieee80211_update_mesh_config, | 3702 | .update_mesh_config = ieee80211_update_mesh_config, |
3551 | .get_mesh_config = ieee80211_get_mesh_config, | 3703 | .get_mesh_config = ieee80211_get_mesh_config, |
3552 | .join_mesh = ieee80211_join_mesh, | 3704 | .join_mesh = ieee80211_join_mesh, |
3553 | .leave_mesh = ieee80211_leave_mesh, | 3705 | .leave_mesh = ieee80211_leave_mesh, |
3554 | #endif | 3706 | #endif |
3707 | .join_ocb = ieee80211_join_ocb, | ||
3708 | .leave_ocb = ieee80211_leave_ocb, | ||
3555 | .change_bss = ieee80211_change_bss, | 3709 | .change_bss = ieee80211_change_bss, |
3556 | .set_txq_params = ieee80211_set_txq_params, | 3710 | .set_txq_params = ieee80211_set_txq_params, |
3557 | .set_monitor_channel = ieee80211_set_monitor_channel, | 3711 | .set_monitor_channel = ieee80211_set_monitor_channel, |
@@ -3597,4 +3751,6 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
3597 | .channel_switch = ieee80211_channel_switch, | 3751 | .channel_switch = ieee80211_channel_switch, |
3598 | .set_qos_map = ieee80211_set_qos_map, | 3752 | .set_qos_map = ieee80211_set_qos_map, |
3599 | .set_ap_chanwidth = ieee80211_set_ap_chanwidth, | 3753 | .set_ap_chanwidth = ieee80211_set_ap_chanwidth, |
3754 | .add_tx_ts = ieee80211_add_tx_ts, | ||
3755 | .del_tx_ts = ieee80211_del_tx_ts, | ||
3600 | }; | 3756 | }; |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 4c74e8da64b9..c7c514220298 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -270,6 +270,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, | |||
270 | case NL80211_IFTYPE_ADHOC: | 270 | case NL80211_IFTYPE_ADHOC: |
271 | case NL80211_IFTYPE_WDS: | 271 | case NL80211_IFTYPE_WDS: |
272 | case NL80211_IFTYPE_MESH_POINT: | 272 | case NL80211_IFTYPE_MESH_POINT: |
273 | case NL80211_IFTYPE_OCB: | ||
273 | width = vif->bss_conf.chandef.width; | 274 | width = vif->bss_conf.chandef.width; |
274 | break; | 275 | break; |
275 | case NL80211_IFTYPE_UNSPECIFIED: | 276 | case NL80211_IFTYPE_UNSPECIFIED: |
@@ -674,6 +675,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | |||
674 | case NL80211_IFTYPE_ADHOC: | 675 | case NL80211_IFTYPE_ADHOC: |
675 | case NL80211_IFTYPE_WDS: | 676 | case NL80211_IFTYPE_WDS: |
676 | case NL80211_IFTYPE_MESH_POINT: | 677 | case NL80211_IFTYPE_MESH_POINT: |
678 | case NL80211_IFTYPE_OCB: | ||
677 | break; | 679 | break; |
678 | default: | 680 | default: |
679 | WARN_ON_ONCE(1); | 681 | WARN_ON_ONCE(1); |
@@ -909,6 +911,7 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata) | |||
909 | case NL80211_IFTYPE_ADHOC: | 911 | case NL80211_IFTYPE_ADHOC: |
910 | case NL80211_IFTYPE_AP: | 912 | case NL80211_IFTYPE_AP: |
911 | case NL80211_IFTYPE_MESH_POINT: | 913 | case NL80211_IFTYPE_MESH_POINT: |
914 | case NL80211_IFTYPE_OCB: | ||
912 | ieee80211_queue_work(&sdata->local->hw, | 915 | ieee80211_queue_work(&sdata->local->hw, |
913 | &sdata->csa_finalize_work); | 916 | &sdata->csa_finalize_work); |
914 | break; | 917 | break; |
@@ -1634,7 +1637,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | |||
1634 | } | 1637 | } |
1635 | break; | 1638 | break; |
1636 | case IEEE80211_CHANCTX_WILL_BE_REPLACED: | 1639 | case IEEE80211_CHANCTX_WILL_BE_REPLACED: |
1637 | /* TODO: Perhaps the bandwith change could be treated as a | 1640 | /* TODO: Perhaps the bandwidth change could be treated as a |
1638 | * reservation itself? */ | 1641 | * reservation itself? */ |
1639 | ret = -EBUSY; | 1642 | ret = -EBUSY; |
1640 | goto out; | 1643 | goto out; |
diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h index 493d68061f0c..1956b3115dd5 100644 --- a/net/mac80211/debug.h +++ b/net/mac80211/debug.h | |||
@@ -2,6 +2,12 @@ | |||
2 | #define __MAC80211_DEBUG_H | 2 | #define __MAC80211_DEBUG_H |
3 | #include <net/cfg80211.h> | 3 | #include <net/cfg80211.h> |
4 | 4 | ||
5 | #ifdef CONFIG_MAC80211_OCB_DEBUG | ||
6 | #define MAC80211_OCB_DEBUG 1 | ||
7 | #else | ||
8 | #define MAC80211_OCB_DEBUG 0 | ||
9 | #endif | ||
10 | |||
5 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 11 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
6 | #define MAC80211_IBSS_DEBUG 1 | 12 | #define MAC80211_IBSS_DEBUG 1 |
7 | #else | 13 | #else |
@@ -131,6 +137,10 @@ do { \ | |||
131 | _sdata_dbg(MAC80211_HT_DEBUG && net_ratelimit(), \ | 137 | _sdata_dbg(MAC80211_HT_DEBUG && net_ratelimit(), \ |
132 | sdata, fmt, ##__VA_ARGS__) | 138 | sdata, fmt, ##__VA_ARGS__) |
133 | 139 | ||
140 | #define ocb_dbg(sdata, fmt, ...) \ | ||
141 | _sdata_dbg(MAC80211_OCB_DEBUG, \ | ||
142 | sdata, fmt, ##__VA_ARGS__) | ||
143 | |||
134 | #define ibss_dbg(sdata, fmt, ...) \ | 144 | #define ibss_dbg(sdata, fmt, ...) \ |
135 | _sdata_dbg(MAC80211_IBSS_DEBUG, \ | 145 | _sdata_dbg(MAC80211_IBSS_DEBUG, \ |
136 | sdata, fmt, ##__VA_ARGS__) | 146 | sdata, fmt, ##__VA_ARGS__) |
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 1521cabad3d6..5523b94c7c90 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
@@ -300,10 +300,8 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
300 | 300 | ||
301 | lockdep_assert_held(&sdata->local->key_mtx); | 301 | lockdep_assert_held(&sdata->local->key_mtx); |
302 | 302 | ||
303 | if (sdata->debugfs.default_unicast_key) { | 303 | debugfs_remove(sdata->debugfs.default_unicast_key); |
304 | debugfs_remove(sdata->debugfs.default_unicast_key); | 304 | sdata->debugfs.default_unicast_key = NULL; |
305 | sdata->debugfs.default_unicast_key = NULL; | ||
306 | } | ||
307 | 305 | ||
308 | if (sdata->default_unicast_key) { | 306 | if (sdata->default_unicast_key) { |
309 | key = key_mtx_dereference(sdata->local, | 307 | key = key_mtx_dereference(sdata->local, |
@@ -314,10 +312,8 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
314 | sdata->vif.debugfs_dir, buf); | 312 | sdata->vif.debugfs_dir, buf); |
315 | } | 313 | } |
316 | 314 | ||
317 | if (sdata->debugfs.default_multicast_key) { | 315 | debugfs_remove(sdata->debugfs.default_multicast_key); |
318 | debugfs_remove(sdata->debugfs.default_multicast_key); | 316 | sdata->debugfs.default_multicast_key = NULL; |
319 | sdata->debugfs.default_multicast_key = NULL; | ||
320 | } | ||
321 | 317 | ||
322 | if (sdata->default_multicast_key) { | 318 | if (sdata->default_multicast_key) { |
323 | key = key_mtx_dereference(sdata->local, | 319 | key = key_mtx_dereference(sdata->local, |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 196d48c68134..9759dd1f0734 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -214,7 +214,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, | |||
214 | BSS_CHANGED_BEACON_ENABLED) && | 214 | BSS_CHANGED_BEACON_ENABLED) && |
215 | sdata->vif.type != NL80211_IFTYPE_AP && | 215 | sdata->vif.type != NL80211_IFTYPE_AP && |
216 | sdata->vif.type != NL80211_IFTYPE_ADHOC && | 216 | sdata->vif.type != NL80211_IFTYPE_ADHOC && |
217 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT)) | 217 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT && |
218 | sdata->vif.type != NL80211_IFTYPE_OCB)) | ||
218 | return; | 219 | return; |
219 | 220 | ||
220 | if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || | 221 | if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || |
@@ -631,6 +632,12 @@ static inline int drv_conf_tx(struct ieee80211_local *local, | |||
631 | if (!check_sdata_in_driver(sdata)) | 632 | if (!check_sdata_in_driver(sdata)) |
632 | return -EIO; | 633 | return -EIO; |
633 | 634 | ||
635 | if (WARN_ONCE(params->cw_min == 0 || | ||
636 | params->cw_min > params->cw_max, | ||
637 | "%s: invalid CW_min/CW_max: %d/%d\n", | ||
638 | sdata->name, params->cw_min, params->cw_max)) | ||
639 | return -EINVAL; | ||
640 | |||
634 | trace_drv_conf_tx(local, sdata, ac, params); | 641 | trace_drv_conf_tx(local, sdata, ac, params); |
635 | if (local->ops->conf_tx) | 642 | if (local->ops->conf_tx) |
636 | ret = local->ops->conf_tx(&local->hw, &sdata->vif, | 643 | ret = local->ops->conf_tx(&local->hw, &sdata->vif, |
@@ -764,12 +771,13 @@ static inline void drv_flush(struct ieee80211_local *local, | |||
764 | } | 771 | } |
765 | 772 | ||
766 | static inline void drv_channel_switch(struct ieee80211_local *local, | 773 | static inline void drv_channel_switch(struct ieee80211_local *local, |
767 | struct ieee80211_channel_switch *ch_switch) | 774 | struct ieee80211_sub_if_data *sdata, |
775 | struct ieee80211_channel_switch *ch_switch) | ||
768 | { | 776 | { |
769 | might_sleep(); | 777 | might_sleep(); |
770 | 778 | ||
771 | trace_drv_channel_switch(local, ch_switch); | 779 | trace_drv_channel_switch(local, sdata, ch_switch); |
772 | local->ops->channel_switch(&local->hw, ch_switch); | 780 | local->ops->channel_switch(&local->hw, &sdata->vif, ch_switch); |
773 | trace_drv_return_void(local); | 781 | trace_drv_return_void(local); |
774 | } | 782 | } |
775 | 783 | ||
@@ -1144,13 +1152,15 @@ static inline void drv_stop_ap(struct ieee80211_local *local, | |||
1144 | trace_drv_return_void(local); | 1152 | trace_drv_return_void(local); |
1145 | } | 1153 | } |
1146 | 1154 | ||
1147 | static inline void drv_restart_complete(struct ieee80211_local *local) | 1155 | static inline void |
1156 | drv_reconfig_complete(struct ieee80211_local *local, | ||
1157 | enum ieee80211_reconfig_type reconfig_type) | ||
1148 | { | 1158 | { |
1149 | might_sleep(); | 1159 | might_sleep(); |
1150 | 1160 | ||
1151 | trace_drv_restart_complete(local); | 1161 | trace_drv_reconfig_complete(local, reconfig_type); |
1152 | if (local->ops->restart_complete) | 1162 | if (local->ops->reconfig_complete) |
1153 | local->ops->restart_complete(&local->hw); | 1163 | local->ops->reconfig_complete(&local->hw, reconfig_type); |
1154 | trace_drv_return_void(local); | 1164 | trace_drv_return_void(local); |
1155 | } | 1165 | } |
1156 | 1166 | ||
@@ -1196,6 +1206,40 @@ drv_channel_switch_beacon(struct ieee80211_sub_if_data *sdata, | |||
1196 | } | 1206 | } |
1197 | } | 1207 | } |
1198 | 1208 | ||
1209 | static inline int | ||
1210 | drv_pre_channel_switch(struct ieee80211_sub_if_data *sdata, | ||
1211 | struct ieee80211_channel_switch *ch_switch) | ||
1212 | { | ||
1213 | struct ieee80211_local *local = sdata->local; | ||
1214 | int ret = 0; | ||
1215 | |||
1216 | if (!check_sdata_in_driver(sdata)) | ||
1217 | return -EIO; | ||
1218 | |||
1219 | trace_drv_pre_channel_switch(local, sdata, ch_switch); | ||
1220 | if (local->ops->pre_channel_switch) | ||
1221 | ret = local->ops->pre_channel_switch(&local->hw, &sdata->vif, | ||
1222 | ch_switch); | ||
1223 | trace_drv_return_int(local, ret); | ||
1224 | return ret; | ||
1225 | } | ||
1226 | |||
1227 | static inline int | ||
1228 | drv_post_channel_switch(struct ieee80211_sub_if_data *sdata) | ||
1229 | { | ||
1230 | struct ieee80211_local *local = sdata->local; | ||
1231 | int ret = 0; | ||
1232 | |||
1233 | if (!check_sdata_in_driver(sdata)) | ||
1234 | return -EIO; | ||
1235 | |||
1236 | trace_drv_post_channel_switch(local, sdata); | ||
1237 | if (local->ops->post_channel_switch) | ||
1238 | ret = local->ops->post_channel_switch(&local->hw, &sdata->vif); | ||
1239 | trace_drv_return_int(local, ret); | ||
1240 | return ret; | ||
1241 | } | ||
1242 | |||
1199 | static inline int drv_join_ibss(struct ieee80211_local *local, | 1243 | static inline int drv_join_ibss(struct ieee80211_local *local, |
1200 | struct ieee80211_sub_if_data *sdata) | 1244 | struct ieee80211_sub_if_data *sdata) |
1201 | { | 1245 | { |
@@ -1238,4 +1282,18 @@ static inline u32 drv_get_expected_throughput(struct ieee80211_local *local, | |||
1238 | return ret; | 1282 | return ret; |
1239 | } | 1283 | } |
1240 | 1284 | ||
1285 | static inline int drv_get_txpower(struct ieee80211_local *local, | ||
1286 | struct ieee80211_sub_if_data *sdata, int *dbm) | ||
1287 | { | ||
1288 | int ret; | ||
1289 | |||
1290 | if (!local->ops->get_txpower) | ||
1291 | return -EOPNOTSUPP; | ||
1292 | |||
1293 | ret = local->ops->get_txpower(&local->hw, &sdata->vif, dbm); | ||
1294 | trace_drv_get_txpower(local, sdata, *dbm, ret); | ||
1295 | |||
1296 | return ret; | ||
1297 | } | ||
1298 | |||
1241 | #endif /* __MAC80211_DRIVER_OPS */ | 1299 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8c68da30595d..842e0661fb57 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -131,7 +131,7 @@ enum ieee80211_bss_corrupt_data_flags { | |||
131 | * | 131 | * |
132 | * These are bss flags that are attached to a bss in the | 132 | * These are bss flags that are attached to a bss in the |
133 | * @valid_data field of &struct ieee80211_bss. They show which parts | 133 | * @valid_data field of &struct ieee80211_bss. They show which parts |
134 | * of the data structure were recieved as a result of an un-corrupted | 134 | * of the data structure were received as a result of an un-corrupted |
135 | * beacon/probe response. | 135 | * beacon/probe response. |
136 | */ | 136 | */ |
137 | enum ieee80211_bss_valid_data_flags { | 137 | enum ieee80211_bss_valid_data_flags { |
@@ -399,6 +399,24 @@ struct ieee80211_mgd_assoc_data { | |||
399 | u8 ie[]; | 399 | u8 ie[]; |
400 | }; | 400 | }; |
401 | 401 | ||
402 | struct ieee80211_sta_tx_tspec { | ||
403 | /* timestamp of the first packet in the time slice */ | ||
404 | unsigned long time_slice_start; | ||
405 | |||
406 | u32 admitted_time; /* in usecs, unlike over the air */ | ||
407 | u8 tsid; | ||
408 | s8 up; /* signed to be able to invalidate with -1 during teardown */ | ||
409 | |||
410 | /* consumed TX time in microseconds in the time slice */ | ||
411 | u32 consumed_tx_time; | ||
412 | enum { | ||
413 | TX_TSPEC_ACTION_NONE = 0, | ||
414 | TX_TSPEC_ACTION_DOWNGRADE, | ||
415 | TX_TSPEC_ACTION_STOP_DOWNGRADE, | ||
416 | } action; | ||
417 | bool downgraded; | ||
418 | }; | ||
419 | |||
402 | struct ieee80211_if_managed { | 420 | struct ieee80211_if_managed { |
403 | struct timer_list timer; | 421 | struct timer_list timer; |
404 | struct timer_list conn_mon_timer; | 422 | struct timer_list conn_mon_timer; |
@@ -434,6 +452,8 @@ struct ieee80211_if_managed { | |||
434 | 452 | ||
435 | unsigned int flags; | 453 | unsigned int flags; |
436 | 454 | ||
455 | bool csa_waiting_bcn; | ||
456 | |||
437 | bool beacon_crc_valid; | 457 | bool beacon_crc_valid; |
438 | u32 beacon_crc; | 458 | u32 beacon_crc; |
439 | 459 | ||
@@ -507,6 +527,16 @@ struct ieee80211_if_managed { | |||
507 | 527 | ||
508 | u8 tdls_peer[ETH_ALEN] __aligned(2); | 528 | u8 tdls_peer[ETH_ALEN] __aligned(2); |
509 | struct delayed_work tdls_peer_del_work; | 529 | struct delayed_work tdls_peer_del_work; |
530 | |||
531 | /* WMM-AC TSPEC support */ | ||
532 | struct ieee80211_sta_tx_tspec tx_tspec[IEEE80211_NUM_ACS]; | ||
533 | /* Use a separate work struct so that we can do something here | ||
534 | * while the sdata->work is flushing the queues, for example. | ||
535 | * otherwise, in scenarios where we hardly get any traffic out | ||
536 | * on the BE queue, but there's a lot of VO traffic, we might | ||
537 | * get stuck in a downgraded situation and flush takes forever. | ||
538 | */ | ||
539 | struct delayed_work tx_tspec_wk; | ||
510 | }; | 540 | }; |
511 | 541 | ||
512 | struct ieee80211_if_ibss { | 542 | struct ieee80211_if_ibss { |
@@ -547,6 +577,25 @@ struct ieee80211_if_ibss { | |||
547 | }; | 577 | }; |
548 | 578 | ||
549 | /** | 579 | /** |
580 | * struct ieee80211_if_ocb - OCB mode state | ||
581 | * | ||
582 | * @housekeeping_timer: timer for periodic invocation of a housekeeping task | ||
583 | * @wrkq_flags: OCB deferred task action | ||
584 | * @incomplete_lock: delayed STA insertion lock | ||
585 | * @incomplete_stations: list of STAs waiting for delayed insertion | ||
586 | * @joined: indication if the interface is connected to an OCB network | ||
587 | */ | ||
588 | struct ieee80211_if_ocb { | ||
589 | struct timer_list housekeeping_timer; | ||
590 | unsigned long wrkq_flags; | ||
591 | |||
592 | spinlock_t incomplete_lock; | ||
593 | struct list_head incomplete_stations; | ||
594 | |||
595 | bool joined; | ||
596 | }; | ||
597 | |||
598 | /** | ||
550 | * struct ieee80211_mesh_sync_ops - Extensible synchronization framework interface | 599 | * struct ieee80211_mesh_sync_ops - Extensible synchronization framework interface |
551 | * | 600 | * |
552 | * these declarations define the interface, which enables | 601 | * these declarations define the interface, which enables |
@@ -839,6 +888,7 @@ struct ieee80211_sub_if_data { | |||
839 | struct ieee80211_if_managed mgd; | 888 | struct ieee80211_if_managed mgd; |
840 | struct ieee80211_if_ibss ibss; | 889 | struct ieee80211_if_ibss ibss; |
841 | struct ieee80211_if_mesh mesh; | 890 | struct ieee80211_if_mesh mesh; |
891 | struct ieee80211_if_ocb ocb; | ||
842 | u32 mntr_flags; | 892 | u32 mntr_flags; |
843 | } u; | 893 | } u; |
844 | 894 | ||
@@ -1307,6 +1357,9 @@ struct ieee80211_local { | |||
1307 | /* virtual monitor interface */ | 1357 | /* virtual monitor interface */ |
1308 | struct ieee80211_sub_if_data __rcu *monitor_sdata; | 1358 | struct ieee80211_sub_if_data __rcu *monitor_sdata; |
1309 | struct cfg80211_chan_def monitor_chandef; | 1359 | struct cfg80211_chan_def monitor_chandef; |
1360 | |||
1361 | /* extended capabilities provided by mac80211 */ | ||
1362 | u8 ext_capa[8]; | ||
1310 | }; | 1363 | }; |
1311 | 1364 | ||
1312 | static inline struct ieee80211_sub_if_data * | 1365 | static inline struct ieee80211_sub_if_data * |
@@ -1454,6 +1507,7 @@ void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata, | |||
1454 | __le16 fc, bool acked); | 1507 | __le16 fc, bool acked); |
1455 | void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata); | 1508 | void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata); |
1456 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); | 1509 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); |
1510 | void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata); | ||
1457 | 1511 | ||
1458 | /* IBSS code */ | 1512 | /* IBSS code */ |
1459 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); | 1513 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); |
@@ -1471,6 +1525,15 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
1471 | int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata); | 1525 | int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata); |
1472 | void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata); | 1526 | void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata); |
1473 | 1527 | ||
1528 | /* OCB code */ | ||
1529 | void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata); | ||
1530 | void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata, | ||
1531 | const u8 *bssid, const u8 *addr, u32 supp_rates); | ||
1532 | void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata); | ||
1533 | int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, | ||
1534 | struct ocb_setup *setup); | ||
1535 | int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata); | ||
1536 | |||
1474 | /* mesh code */ | 1537 | /* mesh code */ |
1475 | void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata); | 1538 | void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata); |
1476 | void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1539 | void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
@@ -1757,6 +1820,13 @@ static inline bool ieee80211_rx_reorder_ready(struct sk_buff_head *frames) | |||
1757 | return true; | 1820 | return true; |
1758 | } | 1821 | } |
1759 | 1822 | ||
1823 | extern const int ieee802_1d_to_ac[8]; | ||
1824 | |||
1825 | static inline int ieee80211_ac_from_tid(int tid) | ||
1826 | { | ||
1827 | return ieee802_1d_to_ac[tid & 7]; | ||
1828 | } | ||
1829 | |||
1760 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); | 1830 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); |
1761 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); | 1831 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); |
1762 | void ieee80211_dynamic_ps_timer(unsigned long data); | 1832 | void ieee80211_dynamic_ps_timer(unsigned long data); |
@@ -1766,7 +1836,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
1766 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1836 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
1767 | struct ieee80211_hdr *hdr); | 1837 | struct ieee80211_hdr *hdr); |
1768 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | 1838 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, |
1769 | struct ieee80211_hdr *hdr, bool ack); | 1839 | struct ieee80211_hdr *hdr, bool ack, u16 tx_time); |
1770 | 1840 | ||
1771 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 1841 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
1772 | unsigned long queues, | 1842 | unsigned long queues, |
@@ -1832,8 +1902,10 @@ int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata, | |||
1832 | void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); | 1902 | void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); |
1833 | void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata); | 1903 | void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata); |
1834 | 1904 | ||
1835 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | 1905 | size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen, |
1836 | const u8 *ids, int n_ids, size_t offset); | 1906 | const u8 *ids, int n_ids, |
1907 | const u8 *after_ric, int n_after_ric, | ||
1908 | size_t offset); | ||
1837 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); | 1909 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); |
1838 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 1910 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
1839 | u16 cap); | 1911 | u16 cap); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 653f5eb07a27..9df26adb864a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -259,6 +259,15 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, | |||
259 | list_for_each_entry(nsdata, &local->interfaces, list) { | 259 | list_for_each_entry(nsdata, &local->interfaces, list) { |
260 | if (nsdata != sdata && ieee80211_sdata_running(nsdata)) { | 260 | if (nsdata != sdata && ieee80211_sdata_running(nsdata)) { |
261 | /* | 261 | /* |
262 | * Only OCB and monitor mode may coexist | ||
263 | */ | ||
264 | if ((sdata->vif.type == NL80211_IFTYPE_OCB && | ||
265 | nsdata->vif.type != NL80211_IFTYPE_MONITOR) || | ||
266 | (sdata->vif.type != NL80211_IFTYPE_MONITOR && | ||
267 | nsdata->vif.type == NL80211_IFTYPE_OCB)) | ||
268 | return -EBUSY; | ||
269 | |||
270 | /* | ||
262 | * Allow only a single IBSS interface to be up at any | 271 | * Allow only a single IBSS interface to be up at any |
263 | * time. This is restricted because beacon distribution | 272 | * time. This is restricted because beacon distribution |
264 | * cannot work properly if both are in the same IBSS. | 273 | * cannot work properly if both are in the same IBSS. |
@@ -521,6 +530,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
521 | case NL80211_IFTYPE_MONITOR: | 530 | case NL80211_IFTYPE_MONITOR: |
522 | case NL80211_IFTYPE_ADHOC: | 531 | case NL80211_IFTYPE_ADHOC: |
523 | case NL80211_IFTYPE_P2P_DEVICE: | 532 | case NL80211_IFTYPE_P2P_DEVICE: |
533 | case NL80211_IFTYPE_OCB: | ||
524 | /* no special treatment */ | 534 | /* no special treatment */ |
525 | break; | 535 | break; |
526 | case NL80211_IFTYPE_UNSPECIFIED: | 536 | case NL80211_IFTYPE_UNSPECIFIED: |
@@ -631,6 +641,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
631 | case NL80211_IFTYPE_ADHOC: | 641 | case NL80211_IFTYPE_ADHOC: |
632 | case NL80211_IFTYPE_AP: | 642 | case NL80211_IFTYPE_AP: |
633 | case NL80211_IFTYPE_MESH_POINT: | 643 | case NL80211_IFTYPE_MESH_POINT: |
644 | case NL80211_IFTYPE_OCB: | ||
634 | netif_carrier_off(dev); | 645 | netif_carrier_off(dev); |
635 | break; | 646 | break; |
636 | case NL80211_IFTYPE_WDS: | 647 | case NL80211_IFTYPE_WDS: |
@@ -844,6 +855,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
844 | sdata_lock(sdata); | 855 | sdata_lock(sdata); |
845 | mutex_lock(&local->mtx); | 856 | mutex_lock(&local->mtx); |
846 | sdata->vif.csa_active = false; | 857 | sdata->vif.csa_active = false; |
858 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | ||
859 | sdata->u.mgd.csa_waiting_bcn = false; | ||
847 | if (sdata->csa_block_tx) { | 860 | if (sdata->csa_block_tx) { |
848 | ieee80211_wake_vif_queues(local, sdata, | 861 | ieee80211_wake_vif_queues(local, sdata, |
849 | IEEE80211_QUEUE_STOP_REASON_CSA); | 862 | IEEE80211_QUEUE_STOP_REASON_CSA); |
@@ -1285,6 +1298,9 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
1285 | break; | 1298 | break; |
1286 | ieee80211_mesh_work(sdata); | 1299 | ieee80211_mesh_work(sdata); |
1287 | break; | 1300 | break; |
1301 | case NL80211_IFTYPE_OCB: | ||
1302 | ieee80211_ocb_work(sdata); | ||
1303 | break; | ||
1288 | default: | 1304 | default: |
1289 | break; | 1305 | break; |
1290 | } | 1306 | } |
@@ -1304,6 +1320,9 @@ static void ieee80211_recalc_smps_work(struct work_struct *work) | |||
1304 | static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | 1320 | static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, |
1305 | enum nl80211_iftype type) | 1321 | enum nl80211_iftype type) |
1306 | { | 1322 | { |
1323 | static const u8 bssid_wildcard[ETH_ALEN] = {0xff, 0xff, 0xff, | ||
1324 | 0xff, 0xff, 0xff}; | ||
1325 | |||
1307 | /* clear type-dependent union */ | 1326 | /* clear type-dependent union */ |
1308 | memset(&sdata->u, 0, sizeof(sdata->u)); | 1327 | memset(&sdata->u, 0, sizeof(sdata->u)); |
1309 | 1328 | ||
@@ -1355,6 +1374,10 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
1355 | sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; | 1374 | sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; |
1356 | ieee80211_sta_setup_sdata(sdata); | 1375 | ieee80211_sta_setup_sdata(sdata); |
1357 | break; | 1376 | break; |
1377 | case NL80211_IFTYPE_OCB: | ||
1378 | sdata->vif.bss_conf.bssid = bssid_wildcard; | ||
1379 | ieee80211_ocb_setup_sdata(sdata); | ||
1380 | break; | ||
1358 | case NL80211_IFTYPE_ADHOC: | 1381 | case NL80211_IFTYPE_ADHOC: |
1359 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; | 1382 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; |
1360 | ieee80211_ibss_setup_sdata(sdata); | 1383 | ieee80211_ibss_setup_sdata(sdata); |
@@ -1402,6 +1425,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | |||
1402 | case NL80211_IFTYPE_AP: | 1425 | case NL80211_IFTYPE_AP: |
1403 | case NL80211_IFTYPE_STATION: | 1426 | case NL80211_IFTYPE_STATION: |
1404 | case NL80211_IFTYPE_ADHOC: | 1427 | case NL80211_IFTYPE_ADHOC: |
1428 | case NL80211_IFTYPE_OCB: | ||
1405 | /* | 1429 | /* |
1406 | * Could maybe also all others here? | 1430 | * Could maybe also all others here? |
1407 | * Just not sure how that interacts | 1431 | * Just not sure how that interacts |
@@ -1417,6 +1441,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | |||
1417 | case NL80211_IFTYPE_AP: | 1441 | case NL80211_IFTYPE_AP: |
1418 | case NL80211_IFTYPE_STATION: | 1442 | case NL80211_IFTYPE_STATION: |
1419 | case NL80211_IFTYPE_ADHOC: | 1443 | case NL80211_IFTYPE_ADHOC: |
1444 | case NL80211_IFTYPE_OCB: | ||
1420 | /* | 1445 | /* |
1421 | * Could probably support everything | 1446 | * Could probably support everything |
1422 | * but WDS here (WDS do_open can fail | 1447 | * but WDS here (WDS do_open can fail |
@@ -1675,7 +1700,10 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1675 | } | 1700 | } |
1676 | 1701 | ||
1677 | ieee80211_assign_perm_addr(local, ndev->perm_addr, type); | 1702 | ieee80211_assign_perm_addr(local, ndev->perm_addr, type); |
1678 | memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); | 1703 | if (params && is_valid_ether_addr(params->macaddr)) |
1704 | memcpy(ndev->dev_addr, params->macaddr, ETH_ALEN); | ||
1705 | else | ||
1706 | memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); | ||
1679 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); | 1707 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); |
1680 | 1708 | ||
1681 | /* don't use IEEE80211_DEV_TO_SUB_IF -- it checks too much */ | 1709 | /* don't use IEEE80211_DEV_TO_SUB_IF -- it checks too much */ |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 4712150dc210..434a91ad12c8 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -94,8 +94,17 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
94 | 94 | ||
95 | might_sleep(); | 95 | might_sleep(); |
96 | 96 | ||
97 | if (key->flags & KEY_FLAG_TAINTED) | 97 | if (key->flags & KEY_FLAG_TAINTED) { |
98 | /* If we get here, it's during resume and the key is | ||
99 | * tainted so shouldn't be used/programmed any more. | ||
100 | * However, its flags may still indicate that it was | ||
101 | * programmed into the device (since we're in resume) | ||
102 | * so clear that flag now to avoid trying to remove | ||
103 | * it again later. | ||
104 | */ | ||
105 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | ||
98 | return -EINVAL; | 106 | return -EINVAL; |
107 | } | ||
99 | 108 | ||
100 | if (!key->local->ops->set_key) | 109 | if (!key->local->ops->set_key) |
101 | goto out_unsupported; | 110 | goto out_unsupported; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0de7c93bf62b..282a4f36eb92 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -478,13 +478,9 @@ static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = { | |||
478 | }, | 478 | }, |
479 | }; | 479 | }; |
480 | 480 | ||
481 | static const u8 extended_capabilities[] = { | 481 | struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, |
482 | 0, 0, 0, 0, 0, 0, 0, | 482 | const struct ieee80211_ops *ops, |
483 | WLAN_EXT_CAPA8_OPMODE_NOTIF, | 483 | const char *requested_name) |
484 | }; | ||
485 | |||
486 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | ||
487 | const struct ieee80211_ops *ops) | ||
488 | { | 484 | { |
489 | struct ieee80211_local *local; | 485 | struct ieee80211_local *local; |
490 | int priv_size, i; | 486 | int priv_size, i; |
@@ -524,7 +520,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
524 | */ | 520 | */ |
525 | priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; | 521 | priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; |
526 | 522 | ||
527 | wiphy = wiphy_new(&mac80211_config_ops, priv_size); | 523 | wiphy = wiphy_new_nm(&mac80211_config_ops, priv_size, requested_name); |
528 | 524 | ||
529 | if (!wiphy) | 525 | if (!wiphy) |
530 | return NULL; | 526 | return NULL; |
@@ -539,10 +535,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
539 | WIPHY_FLAG_REPORTS_OBSS | | 535 | WIPHY_FLAG_REPORTS_OBSS | |
540 | WIPHY_FLAG_OFFCHAN_TX; | 536 | WIPHY_FLAG_OFFCHAN_TX; |
541 | 537 | ||
542 | wiphy->extended_capabilities = extended_capabilities; | ||
543 | wiphy->extended_capabilities_mask = extended_capabilities; | ||
544 | wiphy->extended_capabilities_len = ARRAY_SIZE(extended_capabilities); | ||
545 | |||
546 | if (ops->remain_on_channel) | 538 | if (ops->remain_on_channel) |
547 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 539 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
548 | 540 | ||
@@ -550,6 +542,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
550 | NL80211_FEATURE_SAE | | 542 | NL80211_FEATURE_SAE | |
551 | NL80211_FEATURE_HT_IBSS | | 543 | NL80211_FEATURE_HT_IBSS | |
552 | NL80211_FEATURE_VIF_TXPOWER | | 544 | NL80211_FEATURE_VIF_TXPOWER | |
545 | NL80211_FEATURE_MAC_ON_CREATE | | ||
553 | NL80211_FEATURE_USERSPACE_MPM; | 546 | NL80211_FEATURE_USERSPACE_MPM; |
554 | 547 | ||
555 | if (!ops->hw_scan) | 548 | if (!ops->hw_scan) |
@@ -591,6 +584,13 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
591 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; | 584 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; |
592 | wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask; | 585 | wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask; |
593 | 586 | ||
587 | local->ext_capa[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF; | ||
588 | |||
589 | wiphy->extended_capabilities = local->ext_capa; | ||
590 | wiphy->extended_capabilities_mask = local->ext_capa; | ||
591 | wiphy->extended_capabilities_len = | ||
592 | ARRAY_SIZE(local->ext_capa); | ||
593 | |||
594 | INIT_LIST_HEAD(&local->interfaces); | 594 | INIT_LIST_HEAD(&local->interfaces); |
595 | 595 | ||
596 | __hw_addr_init(&local->mc_list); | 596 | __hw_addr_init(&local->mc_list); |
@@ -651,7 +651,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
651 | 651 | ||
652 | return &local->hw; | 652 | return &local->hw; |
653 | } | 653 | } |
654 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 654 | EXPORT_SYMBOL(ieee80211_alloc_hw_nm); |
655 | 655 | ||
656 | static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | 656 | static int ieee80211_init_cipher_suites(struct ieee80211_local *local) |
657 | { | 657 | { |
@@ -787,13 +787,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
787 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)) | 787 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)) |
788 | return -EINVAL; | 788 | return -EINVAL; |
789 | 789 | ||
790 | /* DFS currently not supported with channel context drivers */ | 790 | /* DFS is not supported with multi-channel combinations yet */ |
791 | for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { | 791 | for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { |
792 | const struct ieee80211_iface_combination *comb; | 792 | const struct ieee80211_iface_combination *comb; |
793 | 793 | ||
794 | comb = &local->hw.wiphy->iface_combinations[i]; | 794 | comb = &local->hw.wiphy->iface_combinations[i]; |
795 | 795 | ||
796 | if (comb->radar_detect_widths) | 796 | if (comb->radar_detect_widths && |
797 | comb->num_different_channels > 1) | ||
797 | return -EINVAL; | 798 | return -EINVAL; |
798 | } | 799 | } |
799 | } | 800 | } |
@@ -958,6 +959,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
958 | if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) | 959 | if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) |
959 | local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; | 960 | local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; |
960 | 961 | ||
962 | /* mac80211 supports eCSA, if the driver supports STA CSA at all */ | ||
963 | if (local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA) | ||
964 | local->ext_capa[0] |= WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING; | ||
965 | |||
961 | local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM; | 966 | local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM; |
962 | 967 | ||
963 | result = wiphy_register(local->hw.wiphy); | 968 | result = wiphy_register(local->hw.wiphy); |
@@ -1019,7 +1024,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
1019 | } | 1024 | } |
1020 | 1025 | ||
1021 | /* add one default STA interface if supported */ | 1026 | /* add one default STA interface if supported */ |
1022 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) { | 1027 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) && |
1028 | !(hw->flags & IEEE80211_HW_NO_AUTO_VIF)) { | ||
1023 | result = ieee80211_if_add(local, "wlan%d", NULL, | 1029 | result = ieee80211_if_add(local, "wlan%d", NULL, |
1024 | NL80211_IFTYPE_STATION, NULL); | 1030 | NL80211_IFTYPE_STATION, NULL); |
1025 | if (result) | 1031 | if (result) |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index f39a19f9090f..50c8473cf9dc 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -270,6 +270,8 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata, | |||
270 | const u8 *dst, const u8 *mpp); | 270 | const u8 *dst, const u8 *mpp); |
271 | struct mesh_path * | 271 | struct mesh_path * |
272 | mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx); | 272 | mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx); |
273 | struct mesh_path * | ||
274 | mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx); | ||
273 | void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); | 275 | void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); |
274 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata); | 276 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata); |
275 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | 277 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, |
@@ -317,6 +319,7 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata); | |||
317 | 319 | ||
318 | bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt); | 320 | bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt); |
319 | extern int mesh_paths_generation; | 321 | extern int mesh_paths_generation; |
322 | extern int mpp_paths_generation; | ||
320 | 323 | ||
321 | #ifdef CONFIG_MAC80211_MESH | 324 | #ifdef CONFIG_MAC80211_MESH |
322 | static inline | 325 | static inline |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index a6699dceae7c..b890e225a8f1 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -44,6 +44,7 @@ static struct mesh_table __rcu *mesh_paths; | |||
44 | static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */ | 44 | static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */ |
45 | 45 | ||
46 | int mesh_paths_generation; | 46 | int mesh_paths_generation; |
47 | int mpp_paths_generation; | ||
47 | 48 | ||
48 | /* This lock will have the grow table function as writer and add / delete nodes | 49 | /* This lock will have the grow table function as writer and add / delete nodes |
49 | * as readers. RCU provides sufficient protection only when reading the table | 50 | * as readers. RCU provides sufficient protection only when reading the table |
@@ -410,6 +411,33 @@ mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx) | |||
410 | } | 411 | } |
411 | 412 | ||
412 | /** | 413 | /** |
414 | * mpp_path_lookup_by_idx - look up a path in the proxy path table by its index | ||
415 | * @idx: index | ||
416 | * @sdata: local subif, or NULL for all entries | ||
417 | * | ||
418 | * Returns: pointer to the proxy path structure, or NULL if not found. | ||
419 | * | ||
420 | * Locking: must be called within a read rcu section. | ||
421 | */ | ||
422 | struct mesh_path * | ||
423 | mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx) | ||
424 | { | ||
425 | struct mesh_table *tbl = rcu_dereference(mpp_paths); | ||
426 | struct mpath_node *node; | ||
427 | int i; | ||
428 | int j = 0; | ||
429 | |||
430 | for_each_mesh_entry(tbl, node, i) { | ||
431 | if (sdata && node->mpath->sdata != sdata) | ||
432 | continue; | ||
433 | if (j++ == idx) | ||
434 | return node->mpath; | ||
435 | } | ||
436 | |||
437 | return NULL; | ||
438 | } | ||
439 | |||
440 | /** | ||
413 | * mesh_path_add_gate - add the given mpath to a mesh gate to our path table | 441 | * mesh_path_add_gate - add the given mpath to a mesh gate to our path table |
414 | * @mpath: gate path to add to table | 442 | * @mpath: gate path to add to table |
415 | */ | 443 | */ |
@@ -691,6 +719,9 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata, | |||
691 | 719 | ||
692 | spin_unlock(&tbl->hashwlock[hash_idx]); | 720 | spin_unlock(&tbl->hashwlock[hash_idx]); |
693 | read_unlock_bh(&pathtbl_resize_lock); | 721 | read_unlock_bh(&pathtbl_resize_lock); |
722 | |||
723 | mpp_paths_generation++; | ||
724 | |||
694 | if (grow) { | 725 | if (grow) { |
695 | set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); | 726 | set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); |
696 | ieee80211_queue_work(&local->hw, &sdata->work); | 727 | ieee80211_queue_work(&local->hw, &sdata->work); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 93af0f1c9d99..0d166e766dad 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -775,11 +775,30 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
775 | WLAN_EID_QOS_CAPA, | 775 | WLAN_EID_QOS_CAPA, |
776 | WLAN_EID_RRM_ENABLED_CAPABILITIES, | 776 | WLAN_EID_RRM_ENABLED_CAPABILITIES, |
777 | WLAN_EID_MOBILITY_DOMAIN, | 777 | WLAN_EID_MOBILITY_DOMAIN, |
778 | WLAN_EID_FAST_BSS_TRANSITION, /* reassoc only */ | ||
779 | WLAN_EID_RIC_DATA, /* reassoc only */ | ||
778 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | 780 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, |
779 | }; | 781 | }; |
780 | noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, | 782 | static const u8 after_ric[] = { |
781 | before_ht, ARRAY_SIZE(before_ht), | 783 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, |
782 | offset); | 784 | WLAN_EID_HT_CAPABILITY, |
785 | WLAN_EID_BSS_COEX_2040, | ||
786 | WLAN_EID_EXT_CAPABILITY, | ||
787 | WLAN_EID_QOS_TRAFFIC_CAPA, | ||
788 | WLAN_EID_TIM_BCAST_REQ, | ||
789 | WLAN_EID_INTERWORKING, | ||
790 | /* 60GHz doesn't happen right now */ | ||
791 | WLAN_EID_VHT_CAPABILITY, | ||
792 | WLAN_EID_OPMODE_NOTIF, | ||
793 | }; | ||
794 | |||
795 | noffset = ieee80211_ie_split_ric(assoc_data->ie, | ||
796 | assoc_data->ie_len, | ||
797 | before_ht, | ||
798 | ARRAY_SIZE(before_ht), | ||
799 | after_ric, | ||
800 | ARRAY_SIZE(after_ric), | ||
801 | offset); | ||
783 | pos = skb_put(skb, noffset - offset); | 802 | pos = skb_put(skb, noffset - offset); |
784 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | 803 | memcpy(pos, assoc_data->ie + offset, noffset - offset); |
785 | offset = noffset; | 804 | offset = noffset; |
@@ -813,6 +832,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
813 | WLAN_EID_TIM_BCAST_REQ, | 832 | WLAN_EID_TIM_BCAST_REQ, |
814 | WLAN_EID_INTERWORKING, | 833 | WLAN_EID_INTERWORKING, |
815 | }; | 834 | }; |
835 | |||
836 | /* RIC already taken above, so no need to handle here anymore */ | ||
816 | noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, | 837 | noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, |
817 | before_vht, ARRAY_SIZE(before_vht), | 838 | before_vht, ARRAY_SIZE(before_vht), |
818 | offset); | 839 | offset); |
@@ -1001,14 +1022,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
1001 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 1022 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
1002 | ifmgd->associated->channel = sdata->csa_chandef.chan; | 1023 | ifmgd->associated->channel = sdata->csa_chandef.chan; |
1003 | 1024 | ||
1004 | sdata->vif.csa_active = false; | 1025 | ifmgd->csa_waiting_bcn = true; |
1005 | |||
1006 | /* XXX: wait for a beacon first? */ | ||
1007 | if (sdata->csa_block_tx) { | ||
1008 | ieee80211_wake_vif_queues(local, sdata, | ||
1009 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1010 | sdata->csa_block_tx = false; | ||
1011 | } | ||
1012 | 1026 | ||
1013 | ieee80211_sta_reset_beacon_monitor(sdata); | 1027 | ieee80211_sta_reset_beacon_monitor(sdata); |
1014 | ieee80211_sta_reset_conn_monitor(sdata); | 1028 | ieee80211_sta_reset_conn_monitor(sdata); |
@@ -1019,6 +1033,35 @@ out: | |||
1019 | sdata_unlock(sdata); | 1033 | sdata_unlock(sdata); |
1020 | } | 1034 | } |
1021 | 1035 | ||
1036 | static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata) | ||
1037 | { | ||
1038 | struct ieee80211_local *local = sdata->local; | ||
1039 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1040 | int ret; | ||
1041 | |||
1042 | sdata_assert_lock(sdata); | ||
1043 | |||
1044 | WARN_ON(!sdata->vif.csa_active); | ||
1045 | |||
1046 | if (sdata->csa_block_tx) { | ||
1047 | ieee80211_wake_vif_queues(local, sdata, | ||
1048 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1049 | sdata->csa_block_tx = false; | ||
1050 | } | ||
1051 | |||
1052 | sdata->vif.csa_active = false; | ||
1053 | ifmgd->csa_waiting_bcn = false; | ||
1054 | |||
1055 | ret = drv_post_channel_switch(sdata); | ||
1056 | if (ret) { | ||
1057 | sdata_info(sdata, | ||
1058 | "driver post channel switch failed, disconnecting\n"); | ||
1059 | ieee80211_queue_work(&local->hw, | ||
1060 | &ifmgd->csa_connection_drop_work); | ||
1061 | return; | ||
1062 | } | ||
1063 | } | ||
1064 | |||
1022 | void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) | 1065 | void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) |
1023 | { | 1066 | { |
1024 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 1067 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
@@ -1046,7 +1089,8 @@ static void ieee80211_chswitch_timer(unsigned long data) | |||
1046 | 1089 | ||
1047 | static void | 1090 | static void |
1048 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 1091 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
1049 | u64 timestamp, struct ieee802_11_elems *elems, | 1092 | u64 timestamp, u32 device_timestamp, |
1093 | struct ieee802_11_elems *elems, | ||
1050 | bool beacon) | 1094 | bool beacon) |
1051 | { | 1095 | { |
1052 | struct ieee80211_local *local = sdata->local; | 1096 | struct ieee80211_local *local = sdata->local; |
@@ -1056,6 +1100,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1056 | struct ieee80211_chanctx *chanctx; | 1100 | struct ieee80211_chanctx *chanctx; |
1057 | enum ieee80211_band current_band; | 1101 | enum ieee80211_band current_band; |
1058 | struct ieee80211_csa_ie csa_ie; | 1102 | struct ieee80211_csa_ie csa_ie; |
1103 | struct ieee80211_channel_switch ch_switch; | ||
1059 | int res; | 1104 | int res; |
1060 | 1105 | ||
1061 | sdata_assert_lock(sdata); | 1106 | sdata_assert_lock(sdata); |
@@ -1110,21 +1155,31 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1110 | 1155 | ||
1111 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); | 1156 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); |
1112 | 1157 | ||
1113 | if (local->use_chanctx) { | 1158 | if (local->use_chanctx && |
1114 | u32 num_chanctx = 0; | 1159 | !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) { |
1115 | list_for_each_entry(chanctx, &local->chanctx_list, list) | 1160 | sdata_info(sdata, |
1116 | num_chanctx++; | 1161 | "driver doesn't support chan-switch with channel contexts\n"); |
1162 | ieee80211_queue_work(&local->hw, | ||
1163 | &ifmgd->csa_connection_drop_work); | ||
1164 | mutex_unlock(&local->chanctx_mtx); | ||
1165 | mutex_unlock(&local->mtx); | ||
1166 | return; | ||
1167 | } | ||
1117 | 1168 | ||
1118 | if (num_chanctx > 1 || | 1169 | ch_switch.timestamp = timestamp; |
1119 | !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) { | 1170 | ch_switch.device_timestamp = device_timestamp; |
1120 | sdata_info(sdata, | 1171 | ch_switch.block_tx = csa_ie.mode; |
1121 | "not handling chan-switch with channel contexts\n"); | 1172 | ch_switch.chandef = csa_ie.chandef; |
1122 | ieee80211_queue_work(&local->hw, | 1173 | ch_switch.count = csa_ie.count; |
1123 | &ifmgd->csa_connection_drop_work); | 1174 | |
1124 | mutex_unlock(&local->chanctx_mtx); | 1175 | if (drv_pre_channel_switch(sdata, &ch_switch)) { |
1125 | mutex_unlock(&local->mtx); | 1176 | sdata_info(sdata, |
1126 | return; | 1177 | "preparing for channel switch failed, disconnecting\n"); |
1127 | } | 1178 | ieee80211_queue_work(&local->hw, |
1179 | &ifmgd->csa_connection_drop_work); | ||
1180 | mutex_unlock(&local->chanctx_mtx); | ||
1181 | mutex_unlock(&local->mtx); | ||
1182 | return; | ||
1128 | } | 1183 | } |
1129 | 1184 | ||
1130 | res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, | 1185 | res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, |
@@ -1152,14 +1207,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1152 | 1207 | ||
1153 | if (local->ops->channel_switch) { | 1208 | if (local->ops->channel_switch) { |
1154 | /* use driver's channel switch callback */ | 1209 | /* use driver's channel switch callback */ |
1155 | struct ieee80211_channel_switch ch_switch = { | 1210 | drv_channel_switch(local, sdata, &ch_switch); |
1156 | .timestamp = timestamp, | ||
1157 | .block_tx = csa_ie.mode, | ||
1158 | .chandef = csa_ie.chandef, | ||
1159 | .count = csa_ie.count, | ||
1160 | }; | ||
1161 | |||
1162 | drv_channel_switch(local, &ch_switch); | ||
1163 | return; | 1211 | return; |
1164 | } | 1212 | } |
1165 | 1213 | ||
@@ -1580,6 +1628,95 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work) | |||
1580 | mutex_unlock(&sdata->local->mtx); | 1628 | mutex_unlock(&sdata->local->mtx); |
1581 | } | 1629 | } |
1582 | 1630 | ||
1631 | static bool | ||
1632 | __ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) | ||
1633 | { | ||
1634 | struct ieee80211_local *local = sdata->local; | ||
1635 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1636 | bool ret; | ||
1637 | int ac; | ||
1638 | |||
1639 | if (local->hw.queues < IEEE80211_NUM_ACS) | ||
1640 | return false; | ||
1641 | |||
1642 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
1643 | struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac]; | ||
1644 | int non_acm_ac; | ||
1645 | unsigned long now = jiffies; | ||
1646 | |||
1647 | if (tx_tspec->action == TX_TSPEC_ACTION_NONE && | ||
1648 | tx_tspec->admitted_time && | ||
1649 | time_after(now, tx_tspec->time_slice_start + HZ)) { | ||
1650 | tx_tspec->consumed_tx_time = 0; | ||
1651 | tx_tspec->time_slice_start = now; | ||
1652 | |||
1653 | if (tx_tspec->downgraded) | ||
1654 | tx_tspec->action = | ||
1655 | TX_TSPEC_ACTION_STOP_DOWNGRADE; | ||
1656 | } | ||
1657 | |||
1658 | switch (tx_tspec->action) { | ||
1659 | case TX_TSPEC_ACTION_STOP_DOWNGRADE: | ||
1660 | /* take the original parameters */ | ||
1661 | if (drv_conf_tx(local, sdata, ac, &sdata->tx_conf[ac])) | ||
1662 | sdata_err(sdata, | ||
1663 | "failed to set TX queue parameters for queue %d\n", | ||
1664 | ac); | ||
1665 | tx_tspec->action = TX_TSPEC_ACTION_NONE; | ||
1666 | tx_tspec->downgraded = false; | ||
1667 | ret = true; | ||
1668 | break; | ||
1669 | case TX_TSPEC_ACTION_DOWNGRADE: | ||
1670 | if (time_after(now, tx_tspec->time_slice_start + HZ)) { | ||
1671 | tx_tspec->action = TX_TSPEC_ACTION_NONE; | ||
1672 | ret = true; | ||
1673 | break; | ||
1674 | } | ||
1675 | /* downgrade next lower non-ACM AC */ | ||
1676 | for (non_acm_ac = ac + 1; | ||
1677 | non_acm_ac < IEEE80211_NUM_ACS; | ||
1678 | non_acm_ac++) | ||
1679 | if (!(sdata->wmm_acm & BIT(7 - 2 * non_acm_ac))) | ||
1680 | break; | ||
1681 | /* The loop will result in using BK even if it requires | ||
1682 | * admission control, such configuration makes no sense | ||
1683 | * and we have to transmit somehow - the AC selection | ||
1684 | * does the same thing. | ||
1685 | */ | ||
1686 | if (drv_conf_tx(local, sdata, ac, | ||
1687 | &sdata->tx_conf[non_acm_ac])) | ||
1688 | sdata_err(sdata, | ||
1689 | "failed to set TX queue parameters for queue %d\n", | ||
1690 | ac); | ||
1691 | tx_tspec->action = TX_TSPEC_ACTION_NONE; | ||
1692 | ret = true; | ||
1693 | schedule_delayed_work(&ifmgd->tx_tspec_wk, | ||
1694 | tx_tspec->time_slice_start + HZ - now + 1); | ||
1695 | break; | ||
1696 | case TX_TSPEC_ACTION_NONE: | ||
1697 | /* nothing now */ | ||
1698 | break; | ||
1699 | } | ||
1700 | } | ||
1701 | |||
1702 | return ret; | ||
1703 | } | ||
1704 | |||
1705 | void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) | ||
1706 | { | ||
1707 | if (__ieee80211_sta_handle_tspec_ac_params(sdata)) | ||
1708 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); | ||
1709 | } | ||
1710 | |||
1711 | static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work) | ||
1712 | { | ||
1713 | struct ieee80211_sub_if_data *sdata; | ||
1714 | |||
1715 | sdata = container_of(work, struct ieee80211_sub_if_data, | ||
1716 | u.mgd.tx_tspec_wk.work); | ||
1717 | ieee80211_sta_handle_tspec_ac_params(sdata); | ||
1718 | } | ||
1719 | |||
1583 | /* MLME */ | 1720 | /* MLME */ |
1584 | static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, | 1721 | static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, |
1585 | struct ieee80211_sub_if_data *sdata, | 1722 | struct ieee80211_sub_if_data *sdata, |
@@ -1664,12 +1801,14 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
1664 | params.uapsd = uapsd; | 1801 | params.uapsd = uapsd; |
1665 | 1802 | ||
1666 | mlme_dbg(sdata, | 1803 | mlme_dbg(sdata, |
1667 | "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d\n", | 1804 | "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n", |
1668 | queue, aci, acm, | 1805 | queue, aci, acm, |
1669 | params.aifs, params.cw_min, params.cw_max, | 1806 | params.aifs, params.cw_min, params.cw_max, |
1670 | params.txop, params.uapsd); | 1807 | params.txop, params.uapsd, |
1808 | ifmgd->tx_tspec[queue].downgraded); | ||
1671 | sdata->tx_conf[queue] = params; | 1809 | sdata->tx_conf[queue] = params; |
1672 | if (drv_conf_tx(local, sdata, queue, ¶ms)) | 1810 | if (!ifmgd->tx_tspec[queue].downgraded && |
1811 | drv_conf_tx(local, sdata, queue, ¶ms)) | ||
1673 | sdata_err(sdata, | 1812 | sdata_err(sdata, |
1674 | "failed to set TX queue parameters for queue %d\n", | 1813 | "failed to set TX queue parameters for queue %d\n", |
1675 | queue); | 1814 | queue); |
@@ -1924,6 +2063,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1924 | ieee80211_vif_release_channel(sdata); | 2063 | ieee80211_vif_release_channel(sdata); |
1925 | 2064 | ||
1926 | sdata->vif.csa_active = false; | 2065 | sdata->vif.csa_active = false; |
2066 | ifmgd->csa_waiting_bcn = false; | ||
1927 | if (sdata->csa_block_tx) { | 2067 | if (sdata->csa_block_tx) { |
1928 | ieee80211_wake_vif_queues(local, sdata, | 2068 | ieee80211_wake_vif_queues(local, sdata, |
1929 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2069 | IEEE80211_QUEUE_STOP_REASON_CSA); |
@@ -1931,6 +2071,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1931 | } | 2071 | } |
1932 | mutex_unlock(&local->mtx); | 2072 | mutex_unlock(&local->mtx); |
1933 | 2073 | ||
2074 | /* existing TX TSPEC sessions no longer exist */ | ||
2075 | memset(ifmgd->tx_tspec, 0, sizeof(ifmgd->tx_tspec)); | ||
2076 | cancel_delayed_work_sync(&ifmgd->tx_tspec_wk); | ||
2077 | |||
1934 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | 2078 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; |
1935 | } | 2079 | } |
1936 | 2080 | ||
@@ -1983,9 +2127,46 @@ out: | |||
1983 | mutex_unlock(&local->mtx); | 2127 | mutex_unlock(&local->mtx); |
1984 | } | 2128 | } |
1985 | 2129 | ||
2130 | static void ieee80211_sta_tx_wmm_ac_notify(struct ieee80211_sub_if_data *sdata, | ||
2131 | struct ieee80211_hdr *hdr, | ||
2132 | u16 tx_time) | ||
2133 | { | ||
2134 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2135 | u16 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; | ||
2136 | int ac = ieee80211_ac_from_tid(tid); | ||
2137 | struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac]; | ||
2138 | unsigned long now = jiffies; | ||
2139 | |||
2140 | if (likely(!tx_tspec->admitted_time)) | ||
2141 | return; | ||
2142 | |||
2143 | if (time_after(now, tx_tspec->time_slice_start + HZ)) { | ||
2144 | tx_tspec->consumed_tx_time = 0; | ||
2145 | tx_tspec->time_slice_start = now; | ||
2146 | |||
2147 | if (tx_tspec->downgraded) { | ||
2148 | tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE; | ||
2149 | schedule_delayed_work(&ifmgd->tx_tspec_wk, 0); | ||
2150 | } | ||
2151 | } | ||
2152 | |||
2153 | if (tx_tspec->downgraded) | ||
2154 | return; | ||
2155 | |||
2156 | tx_tspec->consumed_tx_time += tx_time; | ||
2157 | |||
2158 | if (tx_tspec->consumed_tx_time >= tx_tspec->admitted_time) { | ||
2159 | tx_tspec->downgraded = true; | ||
2160 | tx_tspec->action = TX_TSPEC_ACTION_DOWNGRADE; | ||
2161 | schedule_delayed_work(&ifmgd->tx_tspec_wk, 0); | ||
2162 | } | ||
2163 | } | ||
2164 | |||
1986 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | 2165 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, |
1987 | struct ieee80211_hdr *hdr, bool ack) | 2166 | struct ieee80211_hdr *hdr, bool ack, u16 tx_time) |
1988 | { | 2167 | { |
2168 | ieee80211_sta_tx_wmm_ac_notify(sdata, hdr, tx_time); | ||
2169 | |||
1989 | if (!ieee80211_is_data(hdr->frame_control)) | 2170 | if (!ieee80211_is_data(hdr->frame_control)) |
1990 | return; | 2171 | return; |
1991 | 2172 | ||
@@ -2048,8 +2229,6 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
2048 | 2229 | ||
2049 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); | 2230 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); |
2050 | run_again(sdata, ifmgd->probe_timeout); | 2231 | run_again(sdata, ifmgd->probe_timeout); |
2051 | if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | ||
2052 | ieee80211_flush_queues(sdata->local, sdata); | ||
2053 | } | 2232 | } |
2054 | 2233 | ||
2055 | static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | 2234 | static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, |
@@ -2172,6 +2351,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2172 | true, frame_buf); | 2351 | true, frame_buf); |
2173 | mutex_lock(&local->mtx); | 2352 | mutex_lock(&local->mtx); |
2174 | sdata->vif.csa_active = false; | 2353 | sdata->vif.csa_active = false; |
2354 | ifmgd->csa_waiting_bcn = false; | ||
2175 | if (sdata->csa_block_tx) { | 2355 | if (sdata->csa_block_tx) { |
2176 | ieee80211_wake_vif_queues(local, sdata, | 2356 | ieee80211_wake_vif_queues(local, sdata, |
2177 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2357 | IEEE80211_QUEUE_STOP_REASON_CSA); |
@@ -3196,6 +3376,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3196 | } | 3376 | } |
3197 | } | 3377 | } |
3198 | 3378 | ||
3379 | if (ifmgd->csa_waiting_bcn) | ||
3380 | ieee80211_chswitch_post_beacon(sdata); | ||
3381 | |||
3199 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) | 3382 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) |
3200 | return; | 3383 | return; |
3201 | ifmgd->beacon_crc = ncrc; | 3384 | ifmgd->beacon_crc = ncrc; |
@@ -3204,6 +3387,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3204 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); | 3387 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); |
3205 | 3388 | ||
3206 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, | 3389 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, |
3390 | rx_status->device_timestamp, | ||
3207 | &elems, true); | 3391 | &elems, true); |
3208 | 3392 | ||
3209 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && | 3393 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && |
@@ -3335,8 +3519,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
3335 | break; | 3519 | break; |
3336 | 3520 | ||
3337 | ieee80211_sta_process_chanswitch(sdata, | 3521 | ieee80211_sta_process_chanswitch(sdata, |
3338 | rx_status->mactime, | 3522 | rx_status->mactime, |
3339 | &elems, false); | 3523 | rx_status->device_timestamp, |
3524 | &elems, false); | ||
3340 | } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { | 3525 | } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { |
3341 | ies_len = skb->len - | 3526 | ies_len = skb->len - |
3342 | offsetof(struct ieee80211_mgmt, | 3527 | offsetof(struct ieee80211_mgmt, |
@@ -3357,8 +3542,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
3357 | &mgmt->u.action.u.ext_chan_switch.data; | 3542 | &mgmt->u.action.u.ext_chan_switch.data; |
3358 | 3543 | ||
3359 | ieee80211_sta_process_chanswitch(sdata, | 3544 | ieee80211_sta_process_chanswitch(sdata, |
3360 | rx_status->mactime, | 3545 | rx_status->mactime, |
3361 | &elems, false); | 3546 | rx_status->device_timestamp, |
3547 | &elems, false); | ||
3362 | } | 3548 | } |
3363 | break; | 3549 | break; |
3364 | } | 3550 | } |
@@ -3665,11 +3851,12 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data) | |||
3665 | struct ieee80211_sub_if_data *sdata = | 3851 | struct ieee80211_sub_if_data *sdata = |
3666 | (struct ieee80211_sub_if_data *) data; | 3852 | (struct ieee80211_sub_if_data *) data; |
3667 | struct ieee80211_local *local = sdata->local; | 3853 | struct ieee80211_local *local = sdata->local; |
3854 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3668 | 3855 | ||
3669 | if (local->quiescing) | 3856 | if (local->quiescing) |
3670 | return; | 3857 | return; |
3671 | 3858 | ||
3672 | if (sdata->vif.csa_active) | 3859 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) |
3673 | return; | 3860 | return; |
3674 | 3861 | ||
3675 | sdata->u.mgd.connection_loss = false; | 3862 | sdata->u.mgd.connection_loss = false; |
@@ -3687,7 +3874,7 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data) | |||
3687 | if (local->quiescing) | 3874 | if (local->quiescing) |
3688 | return; | 3875 | return; |
3689 | 3876 | ||
3690 | if (sdata->vif.csa_active) | 3877 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) |
3691 | return; | 3878 | return; |
3692 | 3879 | ||
3693 | ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); | 3880 | ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); |
@@ -3799,6 +3986,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
3799 | (unsigned long) sdata); | 3986 | (unsigned long) sdata); |
3800 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, | 3987 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, |
3801 | (unsigned long) sdata); | 3988 | (unsigned long) sdata); |
3989 | INIT_DELAYED_WORK(&ifmgd->tx_tspec_wk, | ||
3990 | ieee80211_sta_handle_tspec_ac_params_wk); | ||
3802 | 3991 | ||
3803 | ifmgd->flags = 0; | 3992 | ifmgd->flags = 0; |
3804 | ifmgd->powersave = sdata->wdev.ps; | 3993 | ifmgd->powersave = sdata->wdev.ps; |
diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c new file mode 100644 index 000000000000..358d5f9d8207 --- /dev/null +++ b/net/mac80211/ocb.c | |||
@@ -0,0 +1,250 @@ | |||
1 | /* | ||
2 | * OCB mode implementation | ||
3 | * | ||
4 | * Copyright: (c) 2014 Czech Technical University in Prague | ||
5 | * (c) 2014 Volkswagen Group Research | ||
6 | * Author: Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz> | ||
7 | * Funded by: Volkswagen Group Research | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | #include <linux/if_ether.h> | ||
16 | #include <linux/skbuff.h> | ||
17 | #include <linux/if_arp.h> | ||
18 | #include <linux/etherdevice.h> | ||
19 | #include <linux/rtnetlink.h> | ||
20 | #include <net/mac80211.h> | ||
21 | #include <asm/unaligned.h> | ||
22 | |||
23 | #include "ieee80211_i.h" | ||
24 | #include "driver-ops.h" | ||
25 | #include "rate.h" | ||
26 | |||
27 | #define IEEE80211_OCB_HOUSEKEEPING_INTERVAL (60 * HZ) | ||
28 | #define IEEE80211_OCB_PEER_INACTIVITY_LIMIT (240 * HZ) | ||
29 | #define IEEE80211_OCB_MAX_STA_ENTRIES 128 | ||
30 | |||
31 | /** | ||
32 | * enum ocb_deferred_task_flags - mac80211 OCB deferred tasks | ||
33 | * @OCB_WORK_HOUSEKEEPING: run the periodic OCB housekeeping tasks | ||
34 | * | ||
35 | * These flags are used in @wrkq_flags field of &struct ieee80211_if_ocb | ||
36 | */ | ||
37 | enum ocb_deferred_task_flags { | ||
38 | OCB_WORK_HOUSEKEEPING, | ||
39 | }; | ||
40 | |||
41 | void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata, | ||
42 | const u8 *bssid, const u8 *addr, | ||
43 | u32 supp_rates) | ||
44 | { | ||
45 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
46 | struct ieee80211_local *local = sdata->local; | ||
47 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
48 | struct ieee80211_supported_band *sband; | ||
49 | enum nl80211_bss_scan_width scan_width; | ||
50 | struct sta_info *sta; | ||
51 | int band; | ||
52 | |||
53 | /* XXX: Consider removing the least recently used entry and | ||
54 | * allow new one to be added. | ||
55 | */ | ||
56 | if (local->num_sta >= IEEE80211_OCB_MAX_STA_ENTRIES) { | ||
57 | net_info_ratelimited("%s: No room for a new OCB STA entry %pM\n", | ||
58 | sdata->name, addr); | ||
59 | return; | ||
60 | } | ||
61 | |||
62 | ocb_dbg(sdata, "Adding new OCB station %pM\n", addr); | ||
63 | |||
64 | rcu_read_lock(); | ||
65 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
66 | if (WARN_ON_ONCE(!chanctx_conf)) { | ||
67 | rcu_read_unlock(); | ||
68 | return; | ||
69 | } | ||
70 | band = chanctx_conf->def.chan->band; | ||
71 | scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); | ||
72 | rcu_read_unlock(); | ||
73 | |||
74 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | ||
75 | if (!sta) | ||
76 | return; | ||
77 | |||
78 | sta->last_rx = jiffies; | ||
79 | |||
80 | /* Add only mandatory rates for now */ | ||
81 | sband = local->hw.wiphy->bands[band]; | ||
82 | sta->sta.supp_rates[band] = | ||
83 | ieee80211_mandatory_rates(sband, scan_width); | ||
84 | |||
85 | spin_lock(&ifocb->incomplete_lock); | ||
86 | list_add(&sta->list, &ifocb->incomplete_stations); | ||
87 | spin_unlock(&ifocb->incomplete_lock); | ||
88 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
89 | } | ||
90 | |||
91 | static struct sta_info *ieee80211_ocb_finish_sta(struct sta_info *sta) | ||
92 | __acquires(RCU) | ||
93 | { | ||
94 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
95 | u8 addr[ETH_ALEN]; | ||
96 | |||
97 | memcpy(addr, sta->sta.addr, ETH_ALEN); | ||
98 | |||
99 | ocb_dbg(sdata, "Adding new IBSS station %pM (dev=%s)\n", | ||
100 | addr, sdata->name); | ||
101 | |||
102 | sta_info_move_state(sta, IEEE80211_STA_AUTH); | ||
103 | sta_info_move_state(sta, IEEE80211_STA_ASSOC); | ||
104 | sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); | ||
105 | |||
106 | rate_control_rate_init(sta); | ||
107 | |||
108 | /* If it fails, maybe we raced another insertion? */ | ||
109 | if (sta_info_insert_rcu(sta)) | ||
110 | return sta_info_get(sdata, addr); | ||
111 | return sta; | ||
112 | } | ||
113 | |||
114 | static void ieee80211_ocb_housekeeping(struct ieee80211_sub_if_data *sdata) | ||
115 | { | ||
116 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
117 | |||
118 | ocb_dbg(sdata, "Running ocb housekeeping\n"); | ||
119 | |||
120 | ieee80211_sta_expire(sdata, IEEE80211_OCB_PEER_INACTIVITY_LIMIT); | ||
121 | |||
122 | mod_timer(&ifocb->housekeeping_timer, | ||
123 | round_jiffies(jiffies + IEEE80211_OCB_HOUSEKEEPING_INTERVAL)); | ||
124 | } | ||
125 | |||
126 | void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata) | ||
127 | { | ||
128 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
129 | struct sta_info *sta; | ||
130 | |||
131 | if (ifocb->joined != true) | ||
132 | return; | ||
133 | |||
134 | sdata_lock(sdata); | ||
135 | |||
136 | spin_lock_bh(&ifocb->incomplete_lock); | ||
137 | while (!list_empty(&ifocb->incomplete_stations)) { | ||
138 | sta = list_first_entry(&ifocb->incomplete_stations, | ||
139 | struct sta_info, list); | ||
140 | list_del(&sta->list); | ||
141 | spin_unlock_bh(&ifocb->incomplete_lock); | ||
142 | |||
143 | ieee80211_ocb_finish_sta(sta); | ||
144 | rcu_read_unlock(); | ||
145 | spin_lock_bh(&ifocb->incomplete_lock); | ||
146 | } | ||
147 | spin_unlock_bh(&ifocb->incomplete_lock); | ||
148 | |||
149 | if (test_and_clear_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags)) | ||
150 | ieee80211_ocb_housekeeping(sdata); | ||
151 | |||
152 | sdata_unlock(sdata); | ||
153 | } | ||
154 | |||
155 | static void ieee80211_ocb_housekeeping_timer(unsigned long data) | ||
156 | { | ||
157 | struct ieee80211_sub_if_data *sdata = (void *)data; | ||
158 | struct ieee80211_local *local = sdata->local; | ||
159 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
160 | |||
161 | set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags); | ||
162 | |||
163 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
164 | } | ||
165 | |||
166 | void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata) | ||
167 | { | ||
168 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
169 | |||
170 | setup_timer(&ifocb->housekeeping_timer, | ||
171 | ieee80211_ocb_housekeeping_timer, | ||
172 | (unsigned long)sdata); | ||
173 | INIT_LIST_HEAD(&ifocb->incomplete_stations); | ||
174 | spin_lock_init(&ifocb->incomplete_lock); | ||
175 | } | ||
176 | |||
177 | int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, | ||
178 | struct ocb_setup *setup) | ||
179 | { | ||
180 | struct ieee80211_local *local = sdata->local; | ||
181 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
182 | u32 changed = BSS_CHANGED_OCB; | ||
183 | int err; | ||
184 | |||
185 | if (ifocb->joined == true) | ||
186 | return -EINVAL; | ||
187 | |||
188 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | ||
189 | sdata->smps_mode = IEEE80211_SMPS_OFF; | ||
190 | sdata->needed_rx_chains = sdata->local->rx_chains; | ||
191 | |||
192 | mutex_lock(&sdata->local->mtx); | ||
193 | err = ieee80211_vif_use_channel(sdata, &setup->chandef, | ||
194 | IEEE80211_CHANCTX_SHARED); | ||
195 | mutex_unlock(&sdata->local->mtx); | ||
196 | if (err) | ||
197 | return err; | ||
198 | |||
199 | ieee80211_bss_info_change_notify(sdata, changed); | ||
200 | |||
201 | ifocb->joined = true; | ||
202 | |||
203 | set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags); | ||
204 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
205 | |||
206 | netif_carrier_on(sdata->dev); | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata) | ||
211 | { | ||
212 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
213 | struct ieee80211_local *local = sdata->local; | ||
214 | struct sta_info *sta; | ||
215 | |||
216 | ifocb->joined = false; | ||
217 | sta_info_flush(sdata); | ||
218 | |||
219 | spin_lock_bh(&ifocb->incomplete_lock); | ||
220 | while (!list_empty(&ifocb->incomplete_stations)) { | ||
221 | sta = list_first_entry(&ifocb->incomplete_stations, | ||
222 | struct sta_info, list); | ||
223 | list_del(&sta->list); | ||
224 | spin_unlock_bh(&ifocb->incomplete_lock); | ||
225 | |||
226 | sta_info_free(local, sta); | ||
227 | spin_lock_bh(&ifocb->incomplete_lock); | ||
228 | } | ||
229 | spin_unlock_bh(&ifocb->incomplete_lock); | ||
230 | |||
231 | netif_carrier_off(sdata->dev); | ||
232 | clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); | ||
233 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_OCB); | ||
234 | |||
235 | mutex_lock(&sdata->local->mtx); | ||
236 | ieee80211_vif_release_channel(sdata); | ||
237 | mutex_unlock(&sdata->local->mtx); | ||
238 | |||
239 | skb_queue_purge(&sdata->skb_queue); | ||
240 | |||
241 | del_timer_sync(&sdata->u.ocb.housekeeping_timer); | ||
242 | /* If the timer fired while we waited for it, it will have | ||
243 | * requeued the work. Now the work will be running again | ||
244 | * but will not rearm the timer again because it checks | ||
245 | * whether we are connected to the network or not -- at this | ||
246 | * point we shouldn't be anymore. | ||
247 | */ | ||
248 | |||
249 | return 0; | ||
250 | } | ||
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 2baa7ed8789d..c2b91bf47f6d 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -191,7 +191,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | |||
191 | * (1) if any success probabilitiy >= 95%, out of those rates | 191 | * (1) if any success probabilitiy >= 95%, out of those rates |
192 | * choose the maximum throughput rate as max_prob_rate | 192 | * choose the maximum throughput rate as max_prob_rate |
193 | * (2) if all success probabilities < 95%, the rate with | 193 | * (2) if all success probabilities < 95%, the rate with |
194 | * highest success probability is choosen as max_prob_rate */ | 194 | * highest success probability is chosen as max_prob_rate */ |
195 | if (mrs->probability >= MINSTREL_FRAC(95, 100)) { | 195 | if (mrs->probability >= MINSTREL_FRAC(95, 100)) { |
196 | if (mrs->cur_tp >= mi->r[tmp_prob_rate].stats.cur_tp) | 196 | if (mrs->cur_tp >= mi->r[tmp_prob_rate].stats.cur_tp) |
197 | tmp_prob_rate = i; | 197 | tmp_prob_rate = i; |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index df90ce2db00c..c50fd94d2aef 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/skbuff.h> | 10 | #include <linux/skbuff.h> |
11 | #include <linux/debugfs.h> | 11 | #include <linux/debugfs.h> |
12 | #include <linux/random.h> | 12 | #include <linux/random.h> |
13 | #include <linux/moduleparam.h> | ||
13 | #include <linux/ieee80211.h> | 14 | #include <linux/ieee80211.h> |
14 | #include <net/mac80211.h> | 15 | #include <net/mac80211.h> |
15 | #include "rate.h" | 16 | #include "rate.h" |
@@ -34,12 +35,17 @@ | |||
34 | /* Transmit duration for the raw data part of an average sized packet */ | 35 | /* Transmit duration for the raw data part of an average sized packet */ |
35 | #define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) | 36 | #define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) |
36 | 37 | ||
38 | #define BW_20 0 | ||
39 | #define BW_40 1 | ||
40 | #define BW_80 2 | ||
41 | |||
37 | /* | 42 | /* |
38 | * Define group sort order: HT40 -> SGI -> #streams | 43 | * Define group sort order: HT40 -> SGI -> #streams |
39 | */ | 44 | */ |
40 | #define GROUP_IDX(_streams, _sgi, _ht40) \ | 45 | #define GROUP_IDX(_streams, _sgi, _ht40) \ |
46 | MINSTREL_HT_GROUP_0 + \ | ||
41 | MINSTREL_MAX_STREAMS * 2 * _ht40 + \ | 47 | MINSTREL_MAX_STREAMS * 2 * _ht40 + \ |
42 | MINSTREL_MAX_STREAMS * _sgi + \ | 48 | MINSTREL_MAX_STREAMS * _sgi + \ |
43 | _streams - 1 | 49 | _streams - 1 |
44 | 50 | ||
45 | /* MCS rate information for an MCS group */ | 51 | /* MCS rate information for an MCS group */ |
@@ -47,6 +53,7 @@ | |||
47 | [GROUP_IDX(_streams, _sgi, _ht40)] = { \ | 53 | [GROUP_IDX(_streams, _sgi, _ht40)] = { \ |
48 | .streams = _streams, \ | 54 | .streams = _streams, \ |
49 | .flags = \ | 55 | .flags = \ |
56 | IEEE80211_TX_RC_MCS | \ | ||
50 | (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \ | 57 | (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \ |
51 | (_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \ | 58 | (_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \ |
52 | .duration = { \ | 59 | .duration = { \ |
@@ -61,6 +68,47 @@ | |||
61 | } \ | 68 | } \ |
62 | } | 69 | } |
63 | 70 | ||
71 | #define VHT_GROUP_IDX(_streams, _sgi, _bw) \ | ||
72 | (MINSTREL_VHT_GROUP_0 + \ | ||
73 | MINSTREL_MAX_STREAMS * 2 * (_bw) + \ | ||
74 | MINSTREL_MAX_STREAMS * (_sgi) + \ | ||
75 | (_streams) - 1) | ||
76 | |||
77 | #define BW2VBPS(_bw, r3, r2, r1) \ | ||
78 | (_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1) | ||
79 | |||
80 | #define VHT_GROUP(_streams, _sgi, _bw) \ | ||
81 | [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \ | ||
82 | .streams = _streams, \ | ||
83 | .flags = \ | ||
84 | IEEE80211_TX_RC_VHT_MCS | \ | ||
85 | (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \ | ||
86 | (_bw == BW_80 ? IEEE80211_TX_RC_80_MHZ_WIDTH : \ | ||
87 | _bw == BW_40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \ | ||
88 | .duration = { \ | ||
89 | MCS_DURATION(_streams, _sgi, \ | ||
90 | BW2VBPS(_bw, 117, 54, 26)), \ | ||
91 | MCS_DURATION(_streams, _sgi, \ | ||
92 | BW2VBPS(_bw, 234, 108, 52)), \ | ||
93 | MCS_DURATION(_streams, _sgi, \ | ||
94 | BW2VBPS(_bw, 351, 162, 78)), \ | ||
95 | MCS_DURATION(_streams, _sgi, \ | ||
96 | BW2VBPS(_bw, 468, 216, 104)), \ | ||
97 | MCS_DURATION(_streams, _sgi, \ | ||
98 | BW2VBPS(_bw, 702, 324, 156)), \ | ||
99 | MCS_DURATION(_streams, _sgi, \ | ||
100 | BW2VBPS(_bw, 936, 432, 208)), \ | ||
101 | MCS_DURATION(_streams, _sgi, \ | ||
102 | BW2VBPS(_bw, 1053, 486, 234)), \ | ||
103 | MCS_DURATION(_streams, _sgi, \ | ||
104 | BW2VBPS(_bw, 1170, 540, 260)), \ | ||
105 | MCS_DURATION(_streams, _sgi, \ | ||
106 | BW2VBPS(_bw, 1404, 648, 312)), \ | ||
107 | MCS_DURATION(_streams, _sgi, \ | ||
108 | BW2VBPS(_bw, 1560, 720, 346)) \ | ||
109 | } \ | ||
110 | } | ||
111 | |||
64 | #define CCK_DURATION(_bitrate, _short, _len) \ | 112 | #define CCK_DURATION(_bitrate, _short, _len) \ |
65 | (1000 * (10 /* SIFS */ + \ | 113 | (1000 * (10 /* SIFS */ + \ |
66 | (_short ? 72 + 24 : 144 + 48) + \ | 114 | (_short ? 72 + 24 : 144 + 48) + \ |
@@ -76,53 +124,96 @@ | |||
76 | CCK_ACK_DURATION(55, _short), \ | 124 | CCK_ACK_DURATION(55, _short), \ |
77 | CCK_ACK_DURATION(110, _short) | 125 | CCK_ACK_DURATION(110, _short) |
78 | 126 | ||
79 | #define CCK_GROUP \ | 127 | #define CCK_GROUP \ |
80 | [MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS] = { \ | 128 | [MINSTREL_CCK_GROUP] = { \ |
81 | .streams = 0, \ | 129 | .streams = 0, \ |
82 | .duration = { \ | 130 | .flags = 0, \ |
83 | CCK_DURATION_LIST(false), \ | 131 | .duration = { \ |
84 | CCK_DURATION_LIST(true) \ | 132 | CCK_DURATION_LIST(false), \ |
85 | } \ | 133 | CCK_DURATION_LIST(true) \ |
134 | } \ | ||
86 | } | 135 | } |
87 | 136 | ||
137 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT | ||
138 | static bool minstrel_vht_only = true; | ||
139 | module_param(minstrel_vht_only, bool, 0644); | ||
140 | MODULE_PARM_DESC(minstrel_vht_only, | ||
141 | "Use only VHT rates when VHT is supported by sta."); | ||
142 | #endif | ||
143 | |||
88 | /* | 144 | /* |
89 | * To enable sufficiently targeted rate sampling, MCS rates are divided into | 145 | * To enable sufficiently targeted rate sampling, MCS rates are divided into |
90 | * groups, based on the number of streams and flags (HT40, SGI) that they | 146 | * groups, based on the number of streams and flags (HT40, SGI) that they |
91 | * use. | 147 | * use. |
92 | * | 148 | * |
93 | * Sortorder has to be fixed for GROUP_IDX macro to be applicable: | 149 | * Sortorder has to be fixed for GROUP_IDX macro to be applicable: |
94 | * HT40 -> SGI -> #streams | 150 | * BW -> SGI -> #streams |
95 | */ | 151 | */ |
96 | const struct mcs_group minstrel_mcs_groups[] = { | 152 | const struct mcs_group minstrel_mcs_groups[] = { |
97 | MCS_GROUP(1, 0, 0), | 153 | MCS_GROUP(1, 0, BW_20), |
98 | MCS_GROUP(2, 0, 0), | 154 | MCS_GROUP(2, 0, BW_20), |
99 | #if MINSTREL_MAX_STREAMS >= 3 | 155 | #if MINSTREL_MAX_STREAMS >= 3 |
100 | MCS_GROUP(3, 0, 0), | 156 | MCS_GROUP(3, 0, BW_20), |
101 | #endif | 157 | #endif |
102 | 158 | ||
103 | MCS_GROUP(1, 1, 0), | 159 | MCS_GROUP(1, 1, BW_20), |
104 | MCS_GROUP(2, 1, 0), | 160 | MCS_GROUP(2, 1, BW_20), |
105 | #if MINSTREL_MAX_STREAMS >= 3 | 161 | #if MINSTREL_MAX_STREAMS >= 3 |
106 | MCS_GROUP(3, 1, 0), | 162 | MCS_GROUP(3, 1, BW_20), |
107 | #endif | 163 | #endif |
108 | 164 | ||
109 | MCS_GROUP(1, 0, 1), | 165 | MCS_GROUP(1, 0, BW_40), |
110 | MCS_GROUP(2, 0, 1), | 166 | MCS_GROUP(2, 0, BW_40), |
111 | #if MINSTREL_MAX_STREAMS >= 3 | 167 | #if MINSTREL_MAX_STREAMS >= 3 |
112 | MCS_GROUP(3, 0, 1), | 168 | MCS_GROUP(3, 0, BW_40), |
113 | #endif | 169 | #endif |
114 | 170 | ||
115 | MCS_GROUP(1, 1, 1), | 171 | MCS_GROUP(1, 1, BW_40), |
116 | MCS_GROUP(2, 1, 1), | 172 | MCS_GROUP(2, 1, BW_40), |
117 | #if MINSTREL_MAX_STREAMS >= 3 | 173 | #if MINSTREL_MAX_STREAMS >= 3 |
118 | MCS_GROUP(3, 1, 1), | 174 | MCS_GROUP(3, 1, BW_40), |
119 | #endif | 175 | #endif |
120 | 176 | ||
121 | /* must be last */ | 177 | CCK_GROUP, |
122 | CCK_GROUP | ||
123 | }; | ||
124 | 178 | ||
125 | #define MINSTREL_CCK_GROUP (ARRAY_SIZE(minstrel_mcs_groups) - 1) | 179 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT |
180 | VHT_GROUP(1, 0, BW_20), | ||
181 | VHT_GROUP(2, 0, BW_20), | ||
182 | #if MINSTREL_MAX_STREAMS >= 3 | ||
183 | VHT_GROUP(3, 0, BW_20), | ||
184 | #endif | ||
185 | |||
186 | VHT_GROUP(1, 1, BW_20), | ||
187 | VHT_GROUP(2, 1, BW_20), | ||
188 | #if MINSTREL_MAX_STREAMS >= 3 | ||
189 | VHT_GROUP(3, 1, BW_20), | ||
190 | #endif | ||
191 | |||
192 | VHT_GROUP(1, 0, BW_40), | ||
193 | VHT_GROUP(2, 0, BW_40), | ||
194 | #if MINSTREL_MAX_STREAMS >= 3 | ||
195 | VHT_GROUP(3, 0, BW_40), | ||
196 | #endif | ||
197 | |||
198 | VHT_GROUP(1, 1, BW_40), | ||
199 | VHT_GROUP(2, 1, BW_40), | ||
200 | #if MINSTREL_MAX_STREAMS >= 3 | ||
201 | VHT_GROUP(3, 1, BW_40), | ||
202 | #endif | ||
203 | |||
204 | VHT_GROUP(1, 0, BW_80), | ||
205 | VHT_GROUP(2, 0, BW_80), | ||
206 | #if MINSTREL_MAX_STREAMS >= 3 | ||
207 | VHT_GROUP(3, 0, BW_80), | ||
208 | #endif | ||
209 | |||
210 | VHT_GROUP(1, 1, BW_80), | ||
211 | VHT_GROUP(2, 1, BW_80), | ||
212 | #if MINSTREL_MAX_STREAMS >= 3 | ||
213 | VHT_GROUP(3, 1, BW_80), | ||
214 | #endif | ||
215 | #endif | ||
216 | }; | ||
126 | 217 | ||
127 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; | 218 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; |
128 | 219 | ||
@@ -130,16 +221,64 @@ static void | |||
130 | minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); | 221 | minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); |
131 | 222 | ||
132 | /* | 223 | /* |
224 | * Some VHT MCSes are invalid (when Ndbps / Nes is not an integer) | ||
225 | * e.g for MCS9@20MHzx1Nss: Ndbps=8x52*(5/6) Nes=1 | ||
226 | * | ||
227 | * Returns the valid mcs map for struct minstrel_mcs_group_data.supported | ||
228 | */ | ||
229 | static u16 | ||
230 | minstrel_get_valid_vht_rates(int bw, int nss, __le16 mcs_map) | ||
231 | { | ||
232 | u16 mask = 0; | ||
233 | |||
234 | if (bw == BW_20) { | ||
235 | if (nss != 3 && nss != 6) | ||
236 | mask = BIT(9); | ||
237 | } else if (bw == BW_80) { | ||
238 | if (nss == 3 || nss == 7) | ||
239 | mask = BIT(6); | ||
240 | else if (nss == 6) | ||
241 | mask = BIT(9); | ||
242 | } else { | ||
243 | WARN_ON(bw != BW_40); | ||
244 | } | ||
245 | |||
246 | switch ((le16_to_cpu(mcs_map) >> (2 * (nss - 1))) & 3) { | ||
247 | case IEEE80211_VHT_MCS_SUPPORT_0_7: | ||
248 | mask |= 0x300; | ||
249 | break; | ||
250 | case IEEE80211_VHT_MCS_SUPPORT_0_8: | ||
251 | mask |= 0x200; | ||
252 | break; | ||
253 | case IEEE80211_VHT_MCS_SUPPORT_0_9: | ||
254 | break; | ||
255 | default: | ||
256 | mask = 0x3ff; | ||
257 | } | ||
258 | |||
259 | return 0x3ff & ~mask; | ||
260 | } | ||
261 | |||
262 | /* | ||
133 | * Look up an MCS group index based on mac80211 rate information | 263 | * Look up an MCS group index based on mac80211 rate information |
134 | */ | 264 | */ |
135 | static int | 265 | static int |
136 | minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) | 266 | minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) |
137 | { | 267 | { |
138 | return GROUP_IDX((rate->idx / MCS_GROUP_RATES) + 1, | 268 | return GROUP_IDX((rate->idx / 8) + 1, |
139 | !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), | 269 | !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), |
140 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); | 270 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); |
141 | } | 271 | } |
142 | 272 | ||
273 | static int | ||
274 | minstrel_vht_get_group_idx(struct ieee80211_tx_rate *rate) | ||
275 | { | ||
276 | return VHT_GROUP_IDX(ieee80211_rate_get_vht_nss(rate), | ||
277 | !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), | ||
278 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + | ||
279 | 2*!!(rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)); | ||
280 | } | ||
281 | |||
143 | static struct minstrel_rate_stats * | 282 | static struct minstrel_rate_stats * |
144 | minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | 283 | minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, |
145 | struct ieee80211_tx_rate *rate) | 284 | struct ieee80211_tx_rate *rate) |
@@ -149,6 +288,9 @@ minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
149 | if (rate->flags & IEEE80211_TX_RC_MCS) { | 288 | if (rate->flags & IEEE80211_TX_RC_MCS) { |
150 | group = minstrel_ht_get_group_idx(rate); | 289 | group = minstrel_ht_get_group_idx(rate); |
151 | idx = rate->idx % 8; | 290 | idx = rate->idx % 8; |
291 | } else if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { | ||
292 | group = minstrel_vht_get_group_idx(rate); | ||
293 | idx = ieee80211_rate_get_vht_mcs(rate); | ||
152 | } else { | 294 | } else { |
153 | group = MINSTREL_CCK_GROUP; | 295 | group = MINSTREL_CCK_GROUP; |
154 | 296 | ||
@@ -240,8 +382,8 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) | |||
240 | * MCS groups, CCK rates do not provide aggregation and are therefore at last. | 382 | * MCS groups, CCK rates do not provide aggregation and are therefore at last. |
241 | */ | 383 | */ |
242 | static void | 384 | static void |
243 | minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u8 index, | 385 | minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index, |
244 | u8 *tp_list) | 386 | u16 *tp_list) |
245 | { | 387 | { |
246 | int cur_group, cur_idx, cur_thr, cur_prob; | 388 | int cur_group, cur_idx, cur_thr, cur_prob; |
247 | int tmp_group, tmp_idx, tmp_thr, tmp_prob; | 389 | int tmp_group, tmp_idx, tmp_thr, tmp_prob; |
@@ -278,7 +420,7 @@ minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u8 index, | |||
278 | * Find and set the topmost probability rate per sta and per group | 420 | * Find and set the topmost probability rate per sta and per group |
279 | */ | 421 | */ |
280 | static void | 422 | static void |
281 | minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u8 index) | 423 | minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index) |
282 | { | 424 | { |
283 | struct minstrel_mcs_group_data *mg; | 425 | struct minstrel_mcs_group_data *mg; |
284 | struct minstrel_rate_stats *mr; | 426 | struct minstrel_rate_stats *mr; |
@@ -321,8 +463,8 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u8 index) | |||
321 | */ | 463 | */ |
322 | static void | 464 | static void |
323 | minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi, | 465 | minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi, |
324 | u8 tmp_mcs_tp_rate[MAX_THR_RATES], | 466 | u16 tmp_mcs_tp_rate[MAX_THR_RATES], |
325 | u8 tmp_cck_tp_rate[MAX_THR_RATES]) | 467 | u16 tmp_cck_tp_rate[MAX_THR_RATES]) |
326 | { | 468 | { |
327 | unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp; | 469 | unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp; |
328 | int i; | 470 | int i; |
@@ -386,8 +528,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
386 | struct minstrel_mcs_group_data *mg; | 528 | struct minstrel_mcs_group_data *mg; |
387 | struct minstrel_rate_stats *mr; | 529 | struct minstrel_rate_stats *mr; |
388 | int group, i, j; | 530 | int group, i, j; |
389 | u8 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; | 531 | u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; |
390 | u8 tmp_cck_tp_rate[MAX_THR_RATES], index; | 532 | u16 tmp_cck_tp_rate[MAX_THR_RATES], index; |
391 | 533 | ||
392 | if (mi->ampdu_packets > 0) { | 534 | if (mi->ampdu_packets > 0) { |
393 | mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, | 535 | mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, |
@@ -485,7 +627,8 @@ minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct ieee80211_tx_rate *rat | |||
485 | if (!rate->count) | 627 | if (!rate->count) |
486 | return false; | 628 | return false; |
487 | 629 | ||
488 | if (rate->flags & IEEE80211_TX_RC_MCS) | 630 | if (rate->flags & IEEE80211_TX_RC_MCS || |
631 | rate->flags & IEEE80211_TX_RC_VHT_MCS) | ||
489 | return true; | 632 | return true; |
490 | 633 | ||
491 | return rate->idx == mp->cck_rates[0] || | 634 | return rate->idx == mp->cck_rates[0] || |
@@ -517,7 +660,7 @@ minstrel_next_sample_idx(struct minstrel_ht_sta *mi) | |||
517 | } | 660 | } |
518 | 661 | ||
519 | static void | 662 | static void |
520 | minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u8 *idx, bool primary) | 663 | minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary) |
521 | { | 664 | { |
522 | int group, orig_group; | 665 | int group, orig_group; |
523 | 666 | ||
@@ -714,7 +857,7 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
714 | const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; | 857 | const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; |
715 | struct minstrel_rate_stats *mr; | 858 | struct minstrel_rate_stats *mr; |
716 | u8 idx; | 859 | u8 idx; |
717 | u16 flags; | 860 | u16 flags = group->flags; |
718 | 861 | ||
719 | mr = minstrel_get_ratestats(mi, index); | 862 | mr = minstrel_get_ratestats(mi, index); |
720 | if (!mr->retry_updated) | 863 | if (!mr->retry_updated) |
@@ -730,13 +873,13 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
730 | ratetbl->rate[offset].count_rts = mr->retry_count_rtscts; | 873 | ratetbl->rate[offset].count_rts = mr->retry_count_rtscts; |
731 | } | 874 | } |
732 | 875 | ||
733 | if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { | 876 | if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) |
734 | idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; | 877 | idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; |
735 | flags = 0; | 878 | else if (flags & IEEE80211_TX_RC_VHT_MCS) |
736 | } else { | 879 | idx = ((group->streams - 1) << 4) | |
880 | ((index % MCS_GROUP_RATES) & 0xF); | ||
881 | else | ||
737 | idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8; | 882 | idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8; |
738 | flags = IEEE80211_TX_RC_MCS | group->flags; | ||
739 | } | ||
740 | 883 | ||
741 | if (offset > 0) { | 884 | if (offset > 0) { |
742 | ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts; | 885 | ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts; |
@@ -916,13 +1059,15 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
916 | if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { | 1059 | if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { |
917 | int idx = sample_idx % ARRAY_SIZE(mp->cck_rates); | 1060 | int idx = sample_idx % ARRAY_SIZE(mp->cck_rates); |
918 | rate->idx = mp->cck_rates[idx]; | 1061 | rate->idx = mp->cck_rates[idx]; |
919 | rate->flags = 0; | 1062 | } else if (sample_group->flags & IEEE80211_TX_RC_VHT_MCS) { |
920 | return; | 1063 | ieee80211_rate_set_vht(rate, sample_idx % MCS_GROUP_RATES, |
1064 | sample_group->streams); | ||
1065 | } else { | ||
1066 | rate->idx = sample_idx % MCS_GROUP_RATES + | ||
1067 | (sample_group->streams - 1) * 8; | ||
921 | } | 1068 | } |
922 | 1069 | ||
923 | rate->idx = sample_idx % MCS_GROUP_RATES + | 1070 | rate->flags = sample_group->flags; |
924 | (sample_group->streams - 1) * 8; | ||
925 | rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags; | ||
926 | } | 1071 | } |
927 | 1072 | ||
928 | static void | 1073 | static void |
@@ -962,6 +1107,8 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
962 | struct minstrel_ht_sta *mi = &msp->ht; | 1107 | struct minstrel_ht_sta *mi = &msp->ht; |
963 | struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; | 1108 | struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; |
964 | u16 sta_cap = sta->ht_cap.cap; | 1109 | u16 sta_cap = sta->ht_cap.cap; |
1110 | struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; | ||
1111 | int use_vht; | ||
965 | int n_supported = 0; | 1112 | int n_supported = 0; |
966 | int ack_dur; | 1113 | int ack_dur; |
967 | int stbc; | 1114 | int stbc; |
@@ -971,8 +1118,14 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
971 | if (!sta->ht_cap.ht_supported) | 1118 | if (!sta->ht_cap.ht_supported) |
972 | goto use_legacy; | 1119 | goto use_legacy; |
973 | 1120 | ||
974 | BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != | 1121 | BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != MINSTREL_GROUPS_NB); |
975 | MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1); | 1122 | |
1123 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT | ||
1124 | if (vht_cap->vht_supported) | ||
1125 | use_vht = vht_cap->vht_mcs.tx_mcs_map != cpu_to_le16(~0); | ||
1126 | else | ||
1127 | #endif | ||
1128 | use_vht = 0; | ||
976 | 1129 | ||
977 | msp->is_ht = true; | 1130 | msp->is_ht = true; |
978 | memset(mi, 0, sizeof(*mi)); | 1131 | memset(mi, 0, sizeof(*mi)); |
@@ -997,22 +1150,28 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
997 | } | 1150 | } |
998 | mi->sample_tries = 4; | 1151 | mi->sample_tries = 4; |
999 | 1152 | ||
1000 | stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >> | 1153 | /* TODO tx_flags for vht - ATM the RC API is not fine-grained enough */ |
1001 | IEEE80211_HT_CAP_RX_STBC_SHIFT; | 1154 | if (!use_vht) { |
1002 | mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT; | 1155 | stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >> |
1156 | IEEE80211_HT_CAP_RX_STBC_SHIFT; | ||
1157 | mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT; | ||
1003 | 1158 | ||
1004 | if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING) | 1159 | if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING) |
1005 | mi->tx_flags |= IEEE80211_TX_CTL_LDPC; | 1160 | mi->tx_flags |= IEEE80211_TX_CTL_LDPC; |
1161 | } | ||
1006 | 1162 | ||
1007 | for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { | 1163 | for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { |
1164 | u32 gflags = minstrel_mcs_groups[i].flags; | ||
1165 | int bw, nss; | ||
1166 | |||
1008 | mi->groups[i].supported = 0; | 1167 | mi->groups[i].supported = 0; |
1009 | if (i == MINSTREL_CCK_GROUP) { | 1168 | if (i == MINSTREL_CCK_GROUP) { |
1010 | minstrel_ht_update_cck(mp, mi, sband, sta); | 1169 | minstrel_ht_update_cck(mp, mi, sband, sta); |
1011 | continue; | 1170 | continue; |
1012 | } | 1171 | } |
1013 | 1172 | ||
1014 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) { | 1173 | if (gflags & IEEE80211_TX_RC_SHORT_GI) { |
1015 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { | 1174 | if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) { |
1016 | if (!(sta_cap & IEEE80211_HT_CAP_SGI_40)) | 1175 | if (!(sta_cap & IEEE80211_HT_CAP_SGI_40)) |
1017 | continue; | 1176 | continue; |
1018 | } else { | 1177 | } else { |
@@ -1021,17 +1180,51 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
1021 | } | 1180 | } |
1022 | } | 1181 | } |
1023 | 1182 | ||
1024 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH && | 1183 | if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH && |
1025 | sta->bandwidth < IEEE80211_STA_RX_BW_40) | 1184 | sta->bandwidth < IEEE80211_STA_RX_BW_40) |
1026 | continue; | 1185 | continue; |
1027 | 1186 | ||
1187 | nss = minstrel_mcs_groups[i].streams; | ||
1188 | |||
1028 | /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */ | 1189 | /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */ |
1029 | if (sta->smps_mode == IEEE80211_SMPS_STATIC && | 1190 | if (sta->smps_mode == IEEE80211_SMPS_STATIC && nss > 1) |
1030 | minstrel_mcs_groups[i].streams > 1) | 1191 | continue; |
1192 | |||
1193 | /* HT rate */ | ||
1194 | if (gflags & IEEE80211_TX_RC_MCS) { | ||
1195 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT | ||
1196 | if (use_vht && minstrel_vht_only) | ||
1197 | continue; | ||
1198 | #endif | ||
1199 | mi->groups[i].supported = mcs->rx_mask[nss - 1]; | ||
1200 | if (mi->groups[i].supported) | ||
1201 | n_supported++; | ||
1031 | continue; | 1202 | continue; |
1203 | } | ||
1204 | |||
1205 | /* VHT rate */ | ||
1206 | if (!vht_cap->vht_supported || | ||
1207 | WARN_ON(!(gflags & IEEE80211_TX_RC_VHT_MCS)) || | ||
1208 | WARN_ON(gflags & IEEE80211_TX_RC_160_MHZ_WIDTH)) | ||
1209 | continue; | ||
1210 | |||
1211 | if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH) { | ||
1212 | if (sta->bandwidth < IEEE80211_STA_RX_BW_80 || | ||
1213 | ((gflags & IEEE80211_TX_RC_SHORT_GI) && | ||
1214 | !(vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80))) { | ||
1215 | continue; | ||
1216 | } | ||
1217 | } | ||
1218 | |||
1219 | if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
1220 | bw = BW_40; | ||
1221 | else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH) | ||
1222 | bw = BW_80; | ||
1223 | else | ||
1224 | bw = BW_20; | ||
1032 | 1225 | ||
1033 | mi->groups[i].supported = | 1226 | mi->groups[i].supported = minstrel_get_valid_vht_rates(bw, nss, |
1034 | mcs->rx_mask[minstrel_mcs_groups[i].streams - 1]; | 1227 | vht_cap->vht_mcs.tx_mcs_map); |
1035 | 1228 | ||
1036 | if (mi->groups[i].supported) | 1229 | if (mi->groups[i].supported) |
1037 | n_supported++; | 1230 | n_supported++; |
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index 01570e0e014b..f2217d6aa0c2 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h | |||
@@ -13,10 +13,32 @@ | |||
13 | * The number of streams can be changed to 2 to reduce code | 13 | * The number of streams can be changed to 2 to reduce code |
14 | * size and memory footprint. | 14 | * size and memory footprint. |
15 | */ | 15 | */ |
16 | #define MINSTREL_MAX_STREAMS 3 | 16 | #define MINSTREL_MAX_STREAMS 3 |
17 | #define MINSTREL_STREAM_GROUPS 4 | 17 | #define MINSTREL_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */ |
18 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT | ||
19 | #define MINSTREL_VHT_STREAM_GROUPS 6 /* BW(=3) * SGI(=2) */ | ||
20 | #else | ||
21 | #define MINSTREL_VHT_STREAM_GROUPS 0 | ||
22 | #endif | ||
18 | 23 | ||
19 | #define MCS_GROUP_RATES 8 | 24 | #define MINSTREL_HT_GROUPS_NB (MINSTREL_MAX_STREAMS * \ |
25 | MINSTREL_HT_STREAM_GROUPS) | ||
26 | #define MINSTREL_VHT_GROUPS_NB (MINSTREL_MAX_STREAMS * \ | ||
27 | MINSTREL_VHT_STREAM_GROUPS) | ||
28 | #define MINSTREL_CCK_GROUPS_NB 1 | ||
29 | #define MINSTREL_GROUPS_NB (MINSTREL_HT_GROUPS_NB + \ | ||
30 | MINSTREL_VHT_GROUPS_NB + \ | ||
31 | MINSTREL_CCK_GROUPS_NB) | ||
32 | |||
33 | #define MINSTREL_HT_GROUP_0 0 | ||
34 | #define MINSTREL_CCK_GROUP (MINSTREL_HT_GROUP_0 + MINSTREL_HT_GROUPS_NB) | ||
35 | #define MINSTREL_VHT_GROUP_0 (MINSTREL_CCK_GROUP + 1) | ||
36 | |||
37 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT | ||
38 | #define MCS_GROUP_RATES 10 | ||
39 | #else | ||
40 | #define MCS_GROUP_RATES 8 | ||
41 | #endif | ||
20 | 42 | ||
21 | struct mcs_group { | 43 | struct mcs_group { |
22 | u32 flags; | 44 | u32 flags; |
@@ -31,11 +53,11 @@ struct minstrel_mcs_group_data { | |||
31 | u8 column; | 53 | u8 column; |
32 | 54 | ||
33 | /* bitfield of supported MCS rates of this group */ | 55 | /* bitfield of supported MCS rates of this group */ |
34 | u8 supported; | 56 | u16 supported; |
35 | 57 | ||
36 | /* sorted rate set within a MCS group*/ | 58 | /* sorted rate set within a MCS group*/ |
37 | u8 max_group_tp_rate[MAX_THR_RATES]; | 59 | u16 max_group_tp_rate[MAX_THR_RATES]; |
38 | u8 max_group_prob_rate; | 60 | u16 max_group_prob_rate; |
39 | 61 | ||
40 | /* MCS rate statistics */ | 62 | /* MCS rate statistics */ |
41 | struct minstrel_rate_stats rates[MCS_GROUP_RATES]; | 63 | struct minstrel_rate_stats rates[MCS_GROUP_RATES]; |
@@ -52,8 +74,8 @@ struct minstrel_ht_sta { | |||
52 | unsigned int avg_ampdu_len; | 74 | unsigned int avg_ampdu_len; |
53 | 75 | ||
54 | /* overall sorted rate set */ | 76 | /* overall sorted rate set */ |
55 | u8 max_tp_rate[MAX_THR_RATES]; | 77 | u16 max_tp_rate[MAX_THR_RATES]; |
56 | u8 max_prob_rate; | 78 | u16 max_prob_rate; |
57 | 79 | ||
58 | /* time of last status update */ | 80 | /* time of last status update */ |
59 | unsigned long stats_update; | 81 | unsigned long stats_update; |
@@ -80,7 +102,7 @@ struct minstrel_ht_sta { | |||
80 | u8 cck_supported_short; | 102 | u8 cck_supported_short; |
81 | 103 | ||
82 | /* MCS rate group info and statistics */ | 104 | /* MCS rate group info and statistics */ |
83 | struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1]; | 105 | struct minstrel_mcs_group_data groups[MINSTREL_GROUPS_NB]; |
84 | }; | 106 | }; |
85 | 107 | ||
86 | struct minstrel_ht_sta_priv { | 108 | struct minstrel_ht_sta_priv { |
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index d537bec93754..20c676b8e5b6 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c | |||
@@ -18,19 +18,23 @@ | |||
18 | static char * | 18 | static char * |
19 | minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) | 19 | minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) |
20 | { | 20 | { |
21 | unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; | ||
22 | const struct mcs_group *mg; | 21 | const struct mcs_group *mg; |
23 | unsigned int j, tp, prob, eprob; | 22 | unsigned int j, tp, prob, eprob; |
24 | char htmode = '2'; | 23 | char htmode = '2'; |
25 | char gimode = 'L'; | 24 | char gimode = 'L'; |
25 | u32 gflags; | ||
26 | 26 | ||
27 | if (!mi->groups[i].supported) | 27 | if (!mi->groups[i].supported) |
28 | return p; | 28 | return p; |
29 | 29 | ||
30 | mg = &minstrel_mcs_groups[i]; | 30 | mg = &minstrel_mcs_groups[i]; |
31 | if (mg->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 31 | gflags = mg->flags; |
32 | |||
33 | if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
32 | htmode = '4'; | 34 | htmode = '4'; |
33 | if (mg->flags & IEEE80211_TX_RC_SHORT_GI) | 35 | else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH) |
36 | htmode = '8'; | ||
37 | if (gflags & IEEE80211_TX_RC_SHORT_GI) | ||
34 | gimode = 'S'; | 38 | gimode = 'S'; |
35 | 39 | ||
36 | for (j = 0; j < MCS_GROUP_RATES; j++) { | 40 | for (j = 0; j < MCS_GROUP_RATES; j++) { |
@@ -41,10 +45,12 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) | |||
41 | if (!(mi->groups[i].supported & BIT(j))) | 45 | if (!(mi->groups[i].supported & BIT(j))) |
42 | continue; | 46 | continue; |
43 | 47 | ||
44 | if (i == max_mcs) | 48 | if (gflags & IEEE80211_TX_RC_MCS) |
45 | p += sprintf(p, "CCK/%cP ", j < 4 ? 'L' : 'S'); | 49 | p += sprintf(p, " HT%c0/%cGI ", htmode, gimode); |
50 | else if (gflags & IEEE80211_TX_RC_VHT_MCS) | ||
51 | p += sprintf(p, "VHT%c0/%cGI ", htmode, gimode); | ||
46 | else | 52 | else |
47 | p += sprintf(p, "HT%c0/%cGI ", htmode, gimode); | 53 | p += sprintf(p, " CCK/%cP ", j < 4 ? 'L' : 'S'); |
48 | 54 | ||
49 | *(p++) = (idx == mi->max_tp_rate[0]) ? 'A' : ' '; | 55 | *(p++) = (idx == mi->max_tp_rate[0]) ? 'A' : ' '; |
50 | *(p++) = (idx == mi->max_tp_rate[1]) ? 'B' : ' '; | 56 | *(p++) = (idx == mi->max_tp_rate[1]) ? 'B' : ' '; |
@@ -52,11 +58,14 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) | |||
52 | *(p++) = (idx == mi->max_tp_rate[3]) ? 'D' : ' '; | 58 | *(p++) = (idx == mi->max_tp_rate[3]) ? 'D' : ' '; |
53 | *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; | 59 | *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; |
54 | 60 | ||
55 | if (i == max_mcs) { | 61 | if (gflags & IEEE80211_TX_RC_MCS) { |
56 | int r = bitrates[j % 4]; | 62 | p += sprintf(p, " MCS%-2u ", (mg->streams - 1) * 8 + j); |
57 | p += sprintf(p, " %2u.%1uM", r / 10, r % 10); | 63 | } else if (gflags & IEEE80211_TX_RC_VHT_MCS) { |
64 | p += sprintf(p, " MCS%-1u/%1u", j, mg->streams); | ||
58 | } else { | 65 | } else { |
59 | p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j); | 66 | int r = bitrates[j % 4]; |
67 | |||
68 | p += sprintf(p, " %2u.%1uM ", r / 10, r % 10); | ||
60 | } | 69 | } |
61 | 70 | ||
62 | tp = mr->cur_tp / 10; | 71 | tp = mr->cur_tp / 10; |
@@ -85,7 +94,6 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) | |||
85 | struct minstrel_ht_sta *mi = &msp->ht; | 94 | struct minstrel_ht_sta *mi = &msp->ht; |
86 | struct minstrel_debugfs_info *ms; | 95 | struct minstrel_debugfs_info *ms; |
87 | unsigned int i; | 96 | unsigned int i; |
88 | unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; | ||
89 | char *p; | 97 | char *p; |
90 | int ret; | 98 | int ret; |
91 | 99 | ||
@@ -96,18 +104,19 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) | |||
96 | return ret; | 104 | return ret; |
97 | } | 105 | } |
98 | 106 | ||
99 | ms = kmalloc(8192, GFP_KERNEL); | 107 | ms = kmalloc(32768, GFP_KERNEL); |
100 | if (!ms) | 108 | if (!ms) |
101 | return -ENOMEM; | 109 | return -ENOMEM; |
102 | 110 | ||
103 | file->private_data = ms; | 111 | file->private_data = ms; |
104 | p = ms->buf; | 112 | p = ms->buf; |
105 | p += sprintf(p, "type rate tpt eprob *prob " | 113 | p += sprintf(p, " type rate tpt eprob *prob " |
106 | "ret *ok(*cum) ok( cum)\n"); | 114 | "ret *ok(*cum) ok( cum)\n"); |
107 | 115 | ||
108 | 116 | p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p); | |
109 | p = minstrel_ht_stats_dump(mi, max_mcs, p); | 117 | for (i = 0; i < MINSTREL_CCK_GROUP; i++) |
110 | for (i = 0; i < max_mcs; i++) | 118 | p = minstrel_ht_stats_dump(mi, i, p); |
119 | for (i++; i < ARRAY_SIZE(mi->groups); i++) | ||
111 | p = minstrel_ht_stats_dump(mi, i, p); | 120 | p = minstrel_ht_stats_dump(mi, i, p); |
112 | 121 | ||
113 | p += sprintf(p, "\nTotal packet count:: ideal %d " | 122 | p += sprintf(p, "\nTotal packet count:: ideal %d " |
@@ -119,7 +128,7 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) | |||
119 | MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10); | 128 | MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10); |
120 | ms->len = p - ms->buf; | 129 | ms->len = p - ms->buf; |
121 | 130 | ||
122 | WARN_ON(ms->len + sizeof(*ms) > 8192); | 131 | WARN_ON(ms->len + sizeof(*ms) > 32768); |
123 | 132 | ||
124 | return nonseekable_open(inode, file); | 133 | return nonseekable_open(inode, file); |
125 | } | 134 | } |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a37f9af634cb..a726bb169302 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1032,6 +1032,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
1032 | ieee80211_is_pspoll(hdr->frame_control)) && | 1032 | ieee80211_is_pspoll(hdr->frame_control)) && |
1033 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && | 1033 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && |
1034 | rx->sdata->vif.type != NL80211_IFTYPE_WDS && | 1034 | rx->sdata->vif.type != NL80211_IFTYPE_WDS && |
1035 | rx->sdata->vif.type != NL80211_IFTYPE_OCB && | ||
1035 | (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) { | 1036 | (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) { |
1036 | /* | 1037 | /* |
1037 | * accept port control frames from the AP even when it's not | 1038 | * accept port control frames from the AP even when it's not |
@@ -1272,6 +1273,12 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1272 | sta->last_rx_rate_vht_nss = status->vht_nss; | 1273 | sta->last_rx_rate_vht_nss = status->vht_nss; |
1273 | } | 1274 | } |
1274 | } | 1275 | } |
1276 | } else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) { | ||
1277 | u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, | ||
1278 | NL80211_IFTYPE_OCB); | ||
1279 | /* OCB uses wild-card BSSID */ | ||
1280 | if (is_broadcast_ether_addr(bssid)) | ||
1281 | sta->last_rx = jiffies; | ||
1275 | } else if (!is_multicast_ether_addr(hdr->addr1)) { | 1282 | } else if (!is_multicast_ether_addr(hdr->addr1)) { |
1276 | /* | 1283 | /* |
1277 | * Mesh beacons will update last_rx when if they are found to | 1284 | * Mesh beacons will update last_rx when if they are found to |
@@ -2820,6 +2827,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | |||
2820 | 2827 | ||
2821 | if (!ieee80211_vif_is_mesh(&sdata->vif) && | 2828 | if (!ieee80211_vif_is_mesh(&sdata->vif) && |
2822 | sdata->vif.type != NL80211_IFTYPE_ADHOC && | 2829 | sdata->vif.type != NL80211_IFTYPE_ADHOC && |
2830 | sdata->vif.type != NL80211_IFTYPE_OCB && | ||
2823 | sdata->vif.type != NL80211_IFTYPE_STATION) | 2831 | sdata->vif.type != NL80211_IFTYPE_STATION) |
2824 | return RX_DROP_MONITOR; | 2832 | return RX_DROP_MONITOR; |
2825 | 2833 | ||
@@ -3130,6 +3138,33 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
3130 | BIT(rate_idx)); | 3138 | BIT(rate_idx)); |
3131 | } | 3139 | } |
3132 | break; | 3140 | break; |
3141 | case NL80211_IFTYPE_OCB: | ||
3142 | if (!bssid) | ||
3143 | return false; | ||
3144 | if (ieee80211_is_beacon(hdr->frame_control)) { | ||
3145 | return false; | ||
3146 | } else if (!is_broadcast_ether_addr(bssid)) { | ||
3147 | ocb_dbg(sdata, "BSSID mismatch in OCB mode!\n"); | ||
3148 | return false; | ||
3149 | } else if (!multicast && | ||
3150 | !ether_addr_equal(sdata->dev->dev_addr, | ||
3151 | hdr->addr1)) { | ||
3152 | /* if we are in promisc mode we also accept | ||
3153 | * packets not destined for us | ||
3154 | */ | ||
3155 | if (!(sdata->dev->flags & IFF_PROMISC)) | ||
3156 | return false; | ||
3157 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | ||
3158 | } else if (!rx->sta) { | ||
3159 | int rate_idx; | ||
3160 | if (status->flag & RX_FLAG_HT) | ||
3161 | rate_idx = 0; /* TODO: HT rates */ | ||
3162 | else | ||
3163 | rate_idx = status->rate_idx; | ||
3164 | ieee80211_ocb_rx_no_sta(sdata, bssid, hdr->addr2, | ||
3165 | BIT(rate_idx)); | ||
3166 | } | ||
3167 | break; | ||
3133 | case NL80211_IFTYPE_MESH_POINT: | 3168 | case NL80211_IFTYPE_MESH_POINT: |
3134 | if (!multicast && | 3169 | if (!multicast && |
3135 | !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { | 3170 | !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index de494df3bab8..adc25371b171 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -501,7 +501,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) | |||
501 | /* make the station visible */ | 501 | /* make the station visible */ |
502 | sta_info_hash_add(local, sta); | 502 | sta_info_hash_add(local, sta); |
503 | 503 | ||
504 | list_add_rcu(&sta->list, &local->sta_list); | 504 | list_add_tail_rcu(&sta->list, &local->sta_list); |
505 | 505 | ||
506 | /* notify driver */ | 506 | /* notify driver */ |
507 | err = sta_info_insert_drv_state(local, sdata, sta); | 507 | err = sta_info_insert_drv_state(local, sdata, sta); |
@@ -1531,7 +1531,7 @@ void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta) | |||
1531 | break; | 1531 | break; |
1532 | case 0: | 1532 | case 0: |
1533 | /* XXX: what is a good value? */ | 1533 | /* XXX: what is a good value? */ |
1534 | n_frames = 8; | 1534 | n_frames = 128; |
1535 | break; | 1535 | break; |
1536 | } | 1536 | } |
1537 | 1537 | ||
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 89290e33dafe..9612d89fad56 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -704,7 +704,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
704 | 704 | ||
705 | if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) && | 705 | if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) && |
706 | (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) | 706 | (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) |
707 | ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, acked); | 707 | ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, |
708 | acked, info->status.tx_time); | ||
708 | 709 | ||
709 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { | 710 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { |
710 | if (info->flags & IEEE80211_TX_STAT_ACK) { | 711 | if (info->flags & IEEE80211_TX_STAT_ACK) { |
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 4ea25dec0698..b4f368e2cb3b 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c | |||
@@ -562,8 +562,10 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
562 | /* infer the initiator if we can, to support old userspace */ | 562 | /* infer the initiator if we can, to support old userspace */ |
563 | switch (action_code) { | 563 | switch (action_code) { |
564 | case WLAN_TDLS_SETUP_REQUEST: | 564 | case WLAN_TDLS_SETUP_REQUEST: |
565 | if (sta) | 565 | if (sta) { |
566 | set_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); | 566 | set_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); |
567 | sta->sta.tdls_initiator = false; | ||
568 | } | ||
567 | /* fall-through */ | 569 | /* fall-through */ |
568 | case WLAN_TDLS_SETUP_CONFIRM: | 570 | case WLAN_TDLS_SETUP_CONFIRM: |
569 | case WLAN_TDLS_DISCOVERY_REQUEST: | 571 | case WLAN_TDLS_DISCOVERY_REQUEST: |
@@ -575,8 +577,10 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
575 | * Make the last packet sent take effect for the initiator | 577 | * Make the last packet sent take effect for the initiator |
576 | * value. | 578 | * value. |
577 | */ | 579 | */ |
578 | if (sta) | 580 | if (sta) { |
579 | clear_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); | 581 | clear_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); |
582 | sta->sta.tdls_initiator = true; | ||
583 | } | ||
580 | /* fall-through */ | 584 | /* fall-through */ |
581 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | 585 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: |
582 | initiator = false; | 586 | initiator = false; |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 38fae7ebe984..809a4983eb4a 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -987,29 +987,34 @@ TRACE_EVENT(drv_flush, | |||
987 | 987 | ||
988 | TRACE_EVENT(drv_channel_switch, | 988 | TRACE_EVENT(drv_channel_switch, |
989 | TP_PROTO(struct ieee80211_local *local, | 989 | TP_PROTO(struct ieee80211_local *local, |
990 | struct ieee80211_sub_if_data *sdata, | ||
990 | struct ieee80211_channel_switch *ch_switch), | 991 | struct ieee80211_channel_switch *ch_switch), |
991 | 992 | ||
992 | TP_ARGS(local, ch_switch), | 993 | TP_ARGS(local, sdata, ch_switch), |
993 | 994 | ||
994 | TP_STRUCT__entry( | 995 | TP_STRUCT__entry( |
995 | LOCAL_ENTRY | 996 | LOCAL_ENTRY |
997 | VIF_ENTRY | ||
996 | CHANDEF_ENTRY | 998 | CHANDEF_ENTRY |
997 | __field(u64, timestamp) | 999 | __field(u64, timestamp) |
1000 | __field(u32, device_timestamp) | ||
998 | __field(bool, block_tx) | 1001 | __field(bool, block_tx) |
999 | __field(u8, count) | 1002 | __field(u8, count) |
1000 | ), | 1003 | ), |
1001 | 1004 | ||
1002 | TP_fast_assign( | 1005 | TP_fast_assign( |
1003 | LOCAL_ASSIGN; | 1006 | LOCAL_ASSIGN; |
1007 | VIF_ASSIGN; | ||
1004 | CHANDEF_ASSIGN(&ch_switch->chandef) | 1008 | CHANDEF_ASSIGN(&ch_switch->chandef) |
1005 | __entry->timestamp = ch_switch->timestamp; | 1009 | __entry->timestamp = ch_switch->timestamp; |
1010 | __entry->device_timestamp = ch_switch->device_timestamp; | ||
1006 | __entry->block_tx = ch_switch->block_tx; | 1011 | __entry->block_tx = ch_switch->block_tx; |
1007 | __entry->count = ch_switch->count; | 1012 | __entry->count = ch_switch->count; |
1008 | ), | 1013 | ), |
1009 | 1014 | ||
1010 | TP_printk( | 1015 | TP_printk( |
1011 | LOCAL_PR_FMT " new " CHANDEF_PR_FMT " count:%d", | 1016 | LOCAL_PR_FMT VIF_PR_FMT " new " CHANDEF_PR_FMT " count:%d", |
1012 | LOCAL_PR_ARG, CHANDEF_PR_ARG, __entry->count | 1017 | LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count |
1013 | ) | 1018 | ) |
1014 | ); | 1019 | ); |
1015 | 1020 | ||
@@ -1557,9 +1562,26 @@ DEFINE_EVENT(local_sdata_evt, drv_stop_ap, | |||
1557 | TP_ARGS(local, sdata) | 1562 | TP_ARGS(local, sdata) |
1558 | ); | 1563 | ); |
1559 | 1564 | ||
1560 | DEFINE_EVENT(local_only_evt, drv_restart_complete, | 1565 | TRACE_EVENT(drv_reconfig_complete, |
1561 | TP_PROTO(struct ieee80211_local *local), | 1566 | TP_PROTO(struct ieee80211_local *local, |
1562 | TP_ARGS(local) | 1567 | enum ieee80211_reconfig_type reconfig_type), |
1568 | TP_ARGS(local, reconfig_type), | ||
1569 | |||
1570 | TP_STRUCT__entry( | ||
1571 | LOCAL_ENTRY | ||
1572 | __field(u8, reconfig_type) | ||
1573 | ), | ||
1574 | |||
1575 | TP_fast_assign( | ||
1576 | LOCAL_ASSIGN; | ||
1577 | __entry->reconfig_type = reconfig_type; | ||
1578 | ), | ||
1579 | |||
1580 | TP_printk( | ||
1581 | LOCAL_PR_FMT " reconfig_type:%d", | ||
1582 | LOCAL_PR_ARG, __entry->reconfig_type | ||
1583 | ) | ||
1584 | |||
1563 | ); | 1585 | ); |
1564 | 1586 | ||
1565 | #if IS_ENABLED(CONFIG_IPV6) | 1587 | #if IS_ENABLED(CONFIG_IPV6) |
@@ -2106,6 +2128,72 @@ TRACE_EVENT(drv_channel_switch_beacon, | |||
2106 | ) | 2128 | ) |
2107 | ); | 2129 | ); |
2108 | 2130 | ||
2131 | TRACE_EVENT(drv_pre_channel_switch, | ||
2132 | TP_PROTO(struct ieee80211_local *local, | ||
2133 | struct ieee80211_sub_if_data *sdata, | ||
2134 | struct ieee80211_channel_switch *ch_switch), | ||
2135 | |||
2136 | TP_ARGS(local, sdata, ch_switch), | ||
2137 | |||
2138 | TP_STRUCT__entry( | ||
2139 | LOCAL_ENTRY | ||
2140 | VIF_ENTRY | ||
2141 | CHANDEF_ENTRY | ||
2142 | __field(u64, timestamp) | ||
2143 | __field(bool, block_tx) | ||
2144 | __field(u8, count) | ||
2145 | ), | ||
2146 | |||
2147 | TP_fast_assign( | ||
2148 | LOCAL_ASSIGN; | ||
2149 | VIF_ASSIGN; | ||
2150 | CHANDEF_ASSIGN(&ch_switch->chandef) | ||
2151 | __entry->timestamp = ch_switch->timestamp; | ||
2152 | __entry->block_tx = ch_switch->block_tx; | ||
2153 | __entry->count = ch_switch->count; | ||
2154 | ), | ||
2155 | |||
2156 | TP_printk( | ||
2157 | LOCAL_PR_FMT VIF_PR_FMT " prepare channel switch to " | ||
2158 | CHANDEF_PR_FMT " count:%d block_tx:%d timestamp:%llu", | ||
2159 | LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count, | ||
2160 | __entry->block_tx, __entry->timestamp | ||
2161 | ) | ||
2162 | ); | ||
2163 | |||
2164 | DEFINE_EVENT(local_sdata_evt, drv_post_channel_switch, | ||
2165 | TP_PROTO(struct ieee80211_local *local, | ||
2166 | struct ieee80211_sub_if_data *sdata), | ||
2167 | TP_ARGS(local, sdata) | ||
2168 | ); | ||
2169 | |||
2170 | TRACE_EVENT(drv_get_txpower, | ||
2171 | TP_PROTO(struct ieee80211_local *local, | ||
2172 | struct ieee80211_sub_if_data *sdata, | ||
2173 | int dbm, int ret), | ||
2174 | |||
2175 | TP_ARGS(local, sdata, dbm, ret), | ||
2176 | |||
2177 | TP_STRUCT__entry( | ||
2178 | LOCAL_ENTRY | ||
2179 | VIF_ENTRY | ||
2180 | __field(int, dbm) | ||
2181 | __field(int, ret) | ||
2182 | ), | ||
2183 | |||
2184 | TP_fast_assign( | ||
2185 | LOCAL_ASSIGN; | ||
2186 | VIF_ASSIGN; | ||
2187 | __entry->dbm = dbm; | ||
2188 | __entry->ret = ret; | ||
2189 | ), | ||
2190 | |||
2191 | TP_printk( | ||
2192 | LOCAL_PR_FMT VIF_PR_FMT " dbm:%d ret:%d", | ||
2193 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->dbm, __entry->ret | ||
2194 | ) | ||
2195 | ); | ||
2196 | |||
2109 | 2197 | ||
2110 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING | 2198 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING |
2111 | #undef TRACE_SYSTEM | 2199 | #undef TRACE_SYSTEM |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 900632a250ec..3ffd91f295a6 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -296,6 +296,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) | |||
296 | */ | 296 | */ |
297 | return TX_DROP; | 297 | return TX_DROP; |
298 | 298 | ||
299 | if (tx->sdata->vif.type == NL80211_IFTYPE_OCB) | ||
300 | return TX_CONTINUE; | ||
301 | |||
299 | if (tx->sdata->vif.type == NL80211_IFTYPE_WDS) | 302 | if (tx->sdata->vif.type == NL80211_IFTYPE_WDS) |
300 | return TX_CONTINUE; | 303 | return TX_CONTINUE; |
301 | 304 | ||
@@ -2013,6 +2016,17 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2013 | goto fail_rcu; | 2016 | goto fail_rcu; |
2014 | band = chanctx_conf->def.chan->band; | 2017 | band = chanctx_conf->def.chan->band; |
2015 | break; | 2018 | break; |
2019 | case NL80211_IFTYPE_OCB: | ||
2020 | /* DA SA BSSID */ | ||
2021 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | ||
2022 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | ||
2023 | eth_broadcast_addr(hdr.addr3); | ||
2024 | hdrlen = 24; | ||
2025 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
2026 | if (!chanctx_conf) | ||
2027 | goto fail_rcu; | ||
2028 | band = chanctx_conf->def.chan->band; | ||
2029 | break; | ||
2016 | case NL80211_IFTYPE_ADHOC: | 2030 | case NL80211_IFTYPE_ADHOC: |
2017 | /* DA SA BSSID */ | 2031 | /* DA SA BSSID */ |
2018 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 2032 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
@@ -2057,6 +2071,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2057 | * EAPOL frames from the local station. | 2071 | * EAPOL frames from the local station. |
2058 | */ | 2072 | */ |
2059 | if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) && | 2073 | if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) && |
2074 | (sdata->vif.type != NL80211_IFTYPE_OCB) && | ||
2060 | !multicast && !authorized && | 2075 | !multicast && !authorized && |
2061 | (cpu_to_be16(ethertype) != sdata->control_port_protocol || | 2076 | (cpu_to_be16(ethertype) != sdata->control_port_protocol || |
2062 | !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { | 2077 | !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 3c61060a4d2b..f9319a5dca64 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -693,6 +693,34 @@ void ieee80211_iterate_active_interfaces_rtnl( | |||
693 | } | 693 | } |
694 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); | 694 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); |
695 | 695 | ||
696 | static void __iterate_stations(struct ieee80211_local *local, | ||
697 | void (*iterator)(void *data, | ||
698 | struct ieee80211_sta *sta), | ||
699 | void *data) | ||
700 | { | ||
701 | struct sta_info *sta; | ||
702 | |||
703 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
704 | if (!sta->uploaded) | ||
705 | continue; | ||
706 | |||
707 | iterator(data, &sta->sta); | ||
708 | } | ||
709 | } | ||
710 | |||
711 | void ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw, | ||
712 | void (*iterator)(void *data, | ||
713 | struct ieee80211_sta *sta), | ||
714 | void *data) | ||
715 | { | ||
716 | struct ieee80211_local *local = hw_to_local(hw); | ||
717 | |||
718 | rcu_read_lock(); | ||
719 | __iterate_stations(local, iterator, data); | ||
720 | rcu_read_unlock(); | ||
721 | } | ||
722 | EXPORT_SYMBOL_GPL(ieee80211_iterate_stations_atomic); | ||
723 | |||
696 | struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev) | 724 | struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev) |
697 | { | 725 | { |
698 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | 726 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
@@ -1073,6 +1101,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
1073 | struct ieee80211_chanctx_conf *chanctx_conf; | 1101 | struct ieee80211_chanctx_conf *chanctx_conf; |
1074 | int ac; | 1102 | int ac; |
1075 | bool use_11b, enable_qos; | 1103 | bool use_11b, enable_qos; |
1104 | bool is_ocb; /* Use another EDCA parameters if dot11OCBActivated=true */ | ||
1076 | int aCWmin, aCWmax; | 1105 | int aCWmin, aCWmax; |
1077 | 1106 | ||
1078 | if (!local->ops->conf_tx) | 1107 | if (!local->ops->conf_tx) |
@@ -1097,6 +1126,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
1097 | */ | 1126 | */ |
1098 | enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION); | 1127 | enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION); |
1099 | 1128 | ||
1129 | is_ocb = (sdata->vif.type == NL80211_IFTYPE_OCB); | ||
1130 | |||
1100 | /* Set defaults according to 802.11-2007 Table 7-37 */ | 1131 | /* Set defaults according to 802.11-2007 Table 7-37 */ |
1101 | aCWmax = 1023; | 1132 | aCWmax = 1023; |
1102 | if (use_11b) | 1133 | if (use_11b) |
@@ -1118,7 +1149,10 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
1118 | qparam.cw_max = aCWmax; | 1149 | qparam.cw_max = aCWmax; |
1119 | qparam.cw_min = aCWmin; | 1150 | qparam.cw_min = aCWmin; |
1120 | qparam.txop = 0; | 1151 | qparam.txop = 0; |
1121 | qparam.aifs = 7; | 1152 | if (is_ocb) |
1153 | qparam.aifs = 9; | ||
1154 | else | ||
1155 | qparam.aifs = 7; | ||
1122 | break; | 1156 | break; |
1123 | /* never happens but let's not leave undefined */ | 1157 | /* never happens but let's not leave undefined */ |
1124 | default: | 1158 | default: |
@@ -1126,21 +1160,32 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
1126 | qparam.cw_max = aCWmax; | 1160 | qparam.cw_max = aCWmax; |
1127 | qparam.cw_min = aCWmin; | 1161 | qparam.cw_min = aCWmin; |
1128 | qparam.txop = 0; | 1162 | qparam.txop = 0; |
1129 | qparam.aifs = 3; | 1163 | if (is_ocb) |
1164 | qparam.aifs = 6; | ||
1165 | else | ||
1166 | qparam.aifs = 3; | ||
1130 | break; | 1167 | break; |
1131 | case IEEE80211_AC_VI: | 1168 | case IEEE80211_AC_VI: |
1132 | qparam.cw_max = aCWmin; | 1169 | qparam.cw_max = aCWmin; |
1133 | qparam.cw_min = (aCWmin + 1) / 2 - 1; | 1170 | qparam.cw_min = (aCWmin + 1) / 2 - 1; |
1134 | if (use_11b) | 1171 | if (is_ocb) |
1172 | qparam.txop = 0; | ||
1173 | else if (use_11b) | ||
1135 | qparam.txop = 6016/32; | 1174 | qparam.txop = 6016/32; |
1136 | else | 1175 | else |
1137 | qparam.txop = 3008/32; | 1176 | qparam.txop = 3008/32; |
1138 | qparam.aifs = 2; | 1177 | |
1178 | if (is_ocb) | ||
1179 | qparam.aifs = 3; | ||
1180 | else | ||
1181 | qparam.aifs = 2; | ||
1139 | break; | 1182 | break; |
1140 | case IEEE80211_AC_VO: | 1183 | case IEEE80211_AC_VO: |
1141 | qparam.cw_max = (aCWmin + 1) / 2 - 1; | 1184 | qparam.cw_max = (aCWmin + 1) / 2 - 1; |
1142 | qparam.cw_min = (aCWmin + 1) / 4 - 1; | 1185 | qparam.cw_min = (aCWmin + 1) / 4 - 1; |
1143 | if (use_11b) | 1186 | if (is_ocb) |
1187 | qparam.txop = 0; | ||
1188 | else if (use_11b) | ||
1144 | qparam.txop = 3264/32; | 1189 | qparam.txop = 3264/32; |
1145 | else | 1190 | else |
1146 | qparam.txop = 1504/32; | 1191 | qparam.txop = 1504/32; |
@@ -1813,6 +1858,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1813 | ieee80211_bss_info_change_notify(sdata, changed); | 1858 | ieee80211_bss_info_change_notify(sdata, changed); |
1814 | sdata_unlock(sdata); | 1859 | sdata_unlock(sdata); |
1815 | break; | 1860 | break; |
1861 | case NL80211_IFTYPE_OCB: | ||
1862 | changed |= BSS_CHANGED_OCB; | ||
1863 | ieee80211_bss_info_change_notify(sdata, changed); | ||
1864 | break; | ||
1816 | case NL80211_IFTYPE_ADHOC: | 1865 | case NL80211_IFTYPE_ADHOC: |
1817 | changed |= BSS_CHANGED_IBSS; | 1866 | changed |= BSS_CHANGED_IBSS; |
1818 | /* fall through */ | 1867 | /* fall through */ |
@@ -1949,7 +1998,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1949 | * We may want to change that later, however. | 1998 | * We may want to change that later, however. |
1950 | */ | 1999 | */ |
1951 | if (!local->suspended || reconfig_due_to_wowlan) | 2000 | if (!local->suspended || reconfig_due_to_wowlan) |
1952 | drv_restart_complete(local); | 2001 | drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_RESTART); |
1953 | 2002 | ||
1954 | if (!local->suspended) | 2003 | if (!local->suspended) |
1955 | return 0; | 2004 | return 0; |
@@ -1960,6 +2009,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1960 | mb(); | 2009 | mb(); |
1961 | local->resuming = false; | 2010 | local->resuming = false; |
1962 | 2011 | ||
2012 | if (!reconfig_due_to_wowlan) | ||
2013 | drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND); | ||
2014 | |||
1963 | list_for_each_entry(sdata, &local->interfaces, list) { | 2015 | list_for_each_entry(sdata, &local->interfaces, list) { |
1964 | if (!ieee80211_sdata_running(sdata)) | 2016 | if (!ieee80211_sdata_running(sdata)) |
1965 | continue; | 2017 | continue; |
@@ -2052,42 +2104,36 @@ static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) | |||
2052 | return false; | 2104 | return false; |
2053 | } | 2105 | } |
2054 | 2106 | ||
2055 | /** | 2107 | size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen, |
2056 | * ieee80211_ie_split - split an IE buffer according to ordering | 2108 | const u8 *ids, int n_ids, |
2057 | * | 2109 | const u8 *after_ric, int n_after_ric, |
2058 | * @ies: the IE buffer | 2110 | size_t offset) |
2059 | * @ielen: the length of the IE buffer | ||
2060 | * @ids: an array with element IDs that are allowed before | ||
2061 | * the split | ||
2062 | * @n_ids: the size of the element ID array | ||
2063 | * @offset: offset where to start splitting in the buffer | ||
2064 | * | ||
2065 | * This function splits an IE buffer by updating the @offset | ||
2066 | * variable to point to the location where the buffer should be | ||
2067 | * split. | ||
2068 | * | ||
2069 | * It assumes that the given IE buffer is well-formed, this | ||
2070 | * has to be guaranteed by the caller! | ||
2071 | * | ||
2072 | * It also assumes that the IEs in the buffer are ordered | ||
2073 | * correctly, if not the result of using this function will not | ||
2074 | * be ordered correctly either, i.e. it does no reordering. | ||
2075 | * | ||
2076 | * The function returns the offset where the next part of the | ||
2077 | * buffer starts, which may be @ielen if the entire (remainder) | ||
2078 | * of the buffer should be used. | ||
2079 | */ | ||
2080 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | ||
2081 | const u8 *ids, int n_ids, size_t offset) | ||
2082 | { | 2111 | { |
2083 | size_t pos = offset; | 2112 | size_t pos = offset; |
2084 | 2113 | ||
2085 | while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) | 2114 | while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) { |
2086 | pos += 2 + ies[pos + 1]; | 2115 | if (ies[pos] == WLAN_EID_RIC_DATA && n_after_ric) { |
2116 | pos += 2 + ies[pos + 1]; | ||
2117 | |||
2118 | while (pos < ielen && | ||
2119 | !ieee80211_id_in_list(after_ric, n_after_ric, | ||
2120 | ies[pos])) | ||
2121 | pos += 2 + ies[pos + 1]; | ||
2122 | } else { | ||
2123 | pos += 2 + ies[pos + 1]; | ||
2124 | } | ||
2125 | } | ||
2087 | 2126 | ||
2088 | return pos; | 2127 | return pos; |
2089 | } | 2128 | } |
2090 | 2129 | ||
2130 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | ||
2131 | const u8 *ids, int n_ids, size_t offset) | ||
2132 | { | ||
2133 | return ieee80211_ie_split_ric(ies, ielen, ids, n_ids, NULL, 0, offset); | ||
2134 | } | ||
2135 | EXPORT_SYMBOL(ieee80211_ie_split); | ||
2136 | |||
2091 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) | 2137 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) |
2092 | { | 2138 | { |
2093 | size_t pos = offset; | 2139 | size_t pos = offset; |
@@ -2526,11 +2572,23 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work) | |||
2526 | struct ieee80211_local *local = | 2572 | struct ieee80211_local *local = |
2527 | container_of(work, struct ieee80211_local, radar_detected_work); | 2573 | container_of(work, struct ieee80211_local, radar_detected_work); |
2528 | struct cfg80211_chan_def chandef = local->hw.conf.chandef; | 2574 | struct cfg80211_chan_def chandef = local->hw.conf.chandef; |
2575 | struct ieee80211_chanctx *ctx; | ||
2576 | int num_chanctx = 0; | ||
2577 | |||
2578 | mutex_lock(&local->chanctx_mtx); | ||
2579 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
2580 | if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) | ||
2581 | continue; | ||
2582 | |||
2583 | num_chanctx++; | ||
2584 | chandef = ctx->conf.def; | ||
2585 | } | ||
2586 | mutex_unlock(&local->chanctx_mtx); | ||
2529 | 2587 | ||
2530 | ieee80211_dfs_cac_cancel(local); | 2588 | ieee80211_dfs_cac_cancel(local); |
2531 | 2589 | ||
2532 | if (local->use_chanctx) | 2590 | if (num_chanctx > 1) |
2533 | /* currently not handled */ | 2591 | /* XXX: multi-channel is not supported yet */ |
2534 | WARN_ON(1); | 2592 | WARN_ON(1); |
2535 | else | 2593 | else |
2536 | cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL); | 2594 | cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL); |
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 9181fb6d6437..a4220e92f0cc 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
@@ -111,8 +111,6 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, | |||
111 | (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) | 111 | (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) |
112 | return newhdr + hdrlen; | 112 | return newhdr + hdrlen; |
113 | 113 | ||
114 | skb_set_network_header(skb, skb_network_offset(skb) + | ||
115 | IEEE80211_WEP_IV_LEN); | ||
116 | ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen); | 114 | ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen); |
117 | return newhdr + hdrlen; | 115 | return newhdr + hdrlen; |
118 | } | 116 | } |
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 3b873989992c..fdf52db95b33 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -54,10 +54,18 @@ static int wme_downgrade_ac(struct sk_buff *skb) | |||
54 | } | 54 | } |
55 | 55 | ||
56 | static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, | 56 | static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, |
57 | struct sk_buff *skb) | 57 | struct sta_info *sta, struct sk_buff *skb) |
58 | { | 58 | { |
59 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
60 | |||
59 | /* in case we are a client verify acm is not set for this ac */ | 61 | /* in case we are a client verify acm is not set for this ac */ |
60 | while (unlikely(sdata->wmm_acm & BIT(skb->priority))) { | 62 | while (sdata->wmm_acm & BIT(skb->priority)) { |
63 | int ac = ieee802_1d_to_ac[skb->priority]; | ||
64 | |||
65 | if (ifmgd->tx_tspec[ac].admitted_time && | ||
66 | skb->priority == ifmgd->tx_tspec[ac].up) | ||
67 | return ac; | ||
68 | |||
61 | if (wme_downgrade_ac(skb)) { | 69 | if (wme_downgrade_ac(skb)) { |
62 | /* | 70 | /* |
63 | * This should not really happen. The AP has marked all | 71 | * This should not really happen. The AP has marked all |
@@ -96,7 +104,7 @@ u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, | |||
96 | p = ieee80211_get_qos_ctl(hdr); | 104 | p = ieee80211_get_qos_ctl(hdr); |
97 | skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; | 105 | skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; |
98 | 106 | ||
99 | return ieee80211_downgrade_queue(sdata, skb); | 107 | return ieee80211_downgrade_queue(sdata, NULL, skb); |
100 | } | 108 | } |
101 | 109 | ||
102 | /* Indicate which queue to use. */ | 110 | /* Indicate which queue to use. */ |
@@ -108,6 +116,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
108 | const u8 *ra = NULL; | 116 | const u8 *ra = NULL; |
109 | bool qos = false; | 117 | bool qos = false; |
110 | struct mac80211_qos_map *qos_map; | 118 | struct mac80211_qos_map *qos_map; |
119 | u16 ret; | ||
111 | 120 | ||
112 | if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { | 121 | if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { |
113 | skb->priority = 0; /* required for correct WPA/11i MIC */ | 122 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
@@ -139,6 +148,10 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
139 | case NL80211_IFTYPE_ADHOC: | 148 | case NL80211_IFTYPE_ADHOC: |
140 | ra = skb->data; | 149 | ra = skb->data; |
141 | break; | 150 | break; |
151 | case NL80211_IFTYPE_OCB: | ||
152 | /* all stations are required to support WME */ | ||
153 | qos = true; | ||
154 | break; | ||
142 | default: | 155 | default: |
143 | break; | 156 | break; |
144 | } | 157 | } |
@@ -148,27 +161,29 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
148 | if (sta) | 161 | if (sta) |
149 | qos = sta->sta.wme; | 162 | qos = sta->sta.wme; |
150 | } | 163 | } |
151 | rcu_read_unlock(); | ||
152 | 164 | ||
153 | if (!qos) { | 165 | if (!qos) { |
154 | skb->priority = 0; /* required for correct WPA/11i MIC */ | 166 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
155 | return IEEE80211_AC_BE; | 167 | ret = IEEE80211_AC_BE; |
168 | goto out; | ||
156 | } | 169 | } |
157 | 170 | ||
158 | if (skb->protocol == sdata->control_port_protocol) { | 171 | if (skb->protocol == sdata->control_port_protocol) { |
159 | skb->priority = 7; | 172 | skb->priority = 7; |
160 | return ieee80211_downgrade_queue(sdata, skb); | 173 | goto downgrade; |
161 | } | 174 | } |
162 | 175 | ||
163 | /* use the data classifier to determine what 802.1d tag the | 176 | /* use the data classifier to determine what 802.1d tag the |
164 | * data frame has */ | 177 | * data frame has */ |
165 | rcu_read_lock(); | ||
166 | qos_map = rcu_dereference(sdata->qos_map); | 178 | qos_map = rcu_dereference(sdata->qos_map); |
167 | skb->priority = cfg80211_classify8021d(skb, qos_map ? | 179 | skb->priority = cfg80211_classify8021d(skb, qos_map ? |
168 | &qos_map->qos_map : NULL); | 180 | &qos_map->qos_map : NULL); |
169 | rcu_read_unlock(); | ||
170 | 181 | ||
171 | return ieee80211_downgrade_queue(sdata, skb); | 182 | downgrade: |
183 | ret = ieee80211_downgrade_queue(sdata, sta, skb); | ||
184 | out: | ||
185 | rcu_read_unlock(); | ||
186 | return ret; | ||
172 | } | 187 | } |
173 | 188 | ||
174 | /** | 189 | /** |
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index 7fea4bb8acbc..80151edc5195 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h | |||
@@ -13,8 +13,6 @@ | |||
13 | #include <linux/netdevice.h> | 13 | #include <linux/netdevice.h> |
14 | #include "ieee80211_i.h" | 14 | #include "ieee80211_i.h" |
15 | 15 | ||
16 | extern const int ieee802_1d_to_ac[8]; | ||
17 | |||
18 | u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, | 16 | u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, |
19 | struct sk_buff *skb, | 17 | struct sk_buff *skb, |
20 | struct ieee80211_hdr *hdr); | 18 | struct ieee80211_hdr *hdr); |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 983527a4c1ab..12398fde02e8 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -209,8 +209,6 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
209 | 209 | ||
210 | pos = skb_push(skb, IEEE80211_TKIP_IV_LEN); | 210 | pos = skb_push(skb, IEEE80211_TKIP_IV_LEN); |
211 | memmove(pos, pos + IEEE80211_TKIP_IV_LEN, hdrlen); | 211 | memmove(pos, pos + IEEE80211_TKIP_IV_LEN, hdrlen); |
212 | skb_set_network_header(skb, skb_network_offset(skb) + | ||
213 | IEEE80211_TKIP_IV_LEN); | ||
214 | pos += hdrlen; | 212 | pos += hdrlen; |
215 | 213 | ||
216 | /* the HW only needs room for the IV, but not the actual IV */ | 214 | /* the HW only needs room for the IV, but not the actual IV */ |
@@ -434,8 +432,6 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
434 | 432 | ||
435 | pos = skb_push(skb, IEEE80211_CCMP_HDR_LEN); | 433 | pos = skb_push(skb, IEEE80211_CCMP_HDR_LEN); |
436 | memmove(pos, pos + IEEE80211_CCMP_HDR_LEN, hdrlen); | 434 | memmove(pos, pos + IEEE80211_CCMP_HDR_LEN, hdrlen); |
437 | skb_set_network_header(skb, skb_network_offset(skb) + | ||
438 | IEEE80211_CCMP_HDR_LEN); | ||
439 | 435 | ||
440 | /* the HW only needs room for the IV, but not the actual IV */ | 436 | /* the HW only needs room for the IV, but not the actual IV */ |
441 | if (info->control.hw_key && | 437 | if (info->control.hw_key && |
@@ -575,7 +571,6 @@ ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx, | |||
575 | 571 | ||
576 | pos = skb_push(skb, cs->hdr_len); | 572 | pos = skb_push(skb, cs->hdr_len); |
577 | memmove(pos, pos + cs->hdr_len, hdrlen); | 573 | memmove(pos, pos + cs->hdr_len, hdrlen); |
578 | skb_set_network_header(skb, skb_network_offset(skb) + cs->hdr_len); | ||
579 | 574 | ||
580 | return TX_CONTINUE; | 575 | return TX_CONTINUE; |
581 | } | 576 | } |