diff options
author | John W. Linville <linville@tuxdriver.com> | 2011-11-28 14:11:18 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-28 14:11:18 -0500 |
commit | 39338b56382ac640614851a80e0bd71994cc664d (patch) | |
tree | c319e23181be286b1d320c29f755a81e5ef61172 /net | |
parent | 8b7ff200010600ef7cd9d002f9f8f97edfc7578e (diff) | |
parent | eb1852b10593dc3ca73e02bf9ac4753a5a464905 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 2 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.c | 4 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 8 | ||||
-rw-r--r-- | net/mac80211/ht.c | 83 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 75 | ||||
-rw-r--r-- | net/mac80211/iface.c | 2 | ||||
-rw-r--r-- | net/mac80211/main.c | 20 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 2 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 7 | ||||
-rw-r--r-- | net/mac80211/mesh_pathtbl.c | 27 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 3 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 30 | ||||
-rw-r--r-- | net/mac80211/offchannel.c | 4 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel_ht.c | 62 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 2 | ||||
-rw-r--r-- | net/mac80211/tx.c | 222 | ||||
-rw-r--r-- | net/mac80211/util.c | 186 | ||||
-rw-r--r-- | net/mac80211/wep.c | 5 | ||||
-rw-r--r-- | net/mac80211/work.c | 16 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 25 | ||||
-rw-r--r-- | net/wireless/core.h | 10 | ||||
-rw-r--r-- | net/wireless/mlme.c | 37 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 133 | ||||
-rw-r--r-- | net/wireless/reg.c | 39 | ||||
-rw-r--r-- | net/wireless/reg.h | 1 | ||||
-rw-r--r-- | net/wireless/sme.c | 7 | ||||
-rw-r--r-- | net/wireless/util.c | 186 |
27 files changed, 785 insertions, 413 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 1063a7e57d62..2577c45069e5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -832,7 +832,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
832 | } | 832 | } |
833 | 833 | ||
834 | if (params->ht_capa) | 834 | if (params->ht_capa) |
835 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, | 835 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
836 | params->ht_capa, | 836 | params->ht_capa, |
837 | &sta->sta.ht_cap); | 837 | &sta->sta.ht_cap); |
838 | 838 | ||
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 3110cbdc501b..2406b3e7393f 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -63,10 +63,10 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | |||
63 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" | 63 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" |
64 | 64 | ||
65 | int res = scnprintf(buf, sizeof(buf), | 65 | int res = scnprintf(buf, sizeof(buf), |
66 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", | 66 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", |
67 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), | 67 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), |
68 | TEST(PS_DRIVER), TEST(AUTHORIZED), | 68 | TEST(PS_DRIVER), TEST(AUTHORIZED), |
69 | TEST(SHORT_PREAMBLE), TEST(ASSOC_AP), | 69 | TEST(SHORT_PREAMBLE), |
70 | TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT), | 70 | TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT), |
71 | TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), | 71 | TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), |
72 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), | 72 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index b12ed52732c8..49cc5e0e8a6a 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -15,6 +15,14 @@ static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb) | |||
15 | local->ops->tx(&local->hw, skb); | 15 | local->ops->tx(&local->hw, skb); |
16 | } | 16 | } |
17 | 17 | ||
18 | static inline void drv_tx_frags(struct ieee80211_local *local, | ||
19 | struct ieee80211_vif *vif, | ||
20 | struct ieee80211_sta *sta, | ||
21 | struct sk_buff_head *skbs) | ||
22 | { | ||
23 | local->ops->tx_frags(&local->hw, vif, sta, skbs); | ||
24 | } | ||
25 | |||
18 | static inline int drv_start(struct ieee80211_local *local) | 26 | static inline int drv_start(struct ieee80211_local *local) |
19 | { | 27 | { |
20 | int ret; | 28 | int ret; |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index d06975098aad..810cfbea6ad1 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -19,7 +19,82 @@ | |||
19 | #include "ieee80211_i.h" | 19 | #include "ieee80211_i.h" |
20 | #include "rate.h" | 20 | #include "rate.h" |
21 | 21 | ||
22 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, | 22 | bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata) |
23 | { | ||
24 | const __le16 flg = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40); | ||
25 | if ((sdata->u.mgd.ht_capa_mask.cap_info & flg) && | ||
26 | !(sdata->u.mgd.ht_capa.cap_info & flg)) | ||
27 | return true; | ||
28 | return false; | ||
29 | } | ||
30 | |||
31 | void __check_htcap_disable(struct ieee80211_sub_if_data *sdata, | ||
32 | struct ieee80211_sta_ht_cap *ht_cap, | ||
33 | u16 flag) | ||
34 | { | ||
35 | __le16 le_flag = cpu_to_le16(flag); | ||
36 | if (sdata->u.mgd.ht_capa_mask.cap_info & le_flag) { | ||
37 | if (!(sdata->u.mgd.ht_capa.cap_info & le_flag)) | ||
38 | ht_cap->cap &= ~flag; | ||
39 | } | ||
40 | } | ||
41 | |||
42 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | ||
43 | struct ieee80211_sta_ht_cap *ht_cap) | ||
44 | { | ||
45 | u8 *scaps = (u8 *)(&sdata->u.mgd.ht_capa.mcs.rx_mask); | ||
46 | u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask); | ||
47 | int i; | ||
48 | |||
49 | if (sdata->vif.type != NL80211_IFTYPE_STATION) { | ||
50 | WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION); | ||
51 | return; | ||
52 | } | ||
53 | |||
54 | /* NOTE: If you add more over-rides here, update register_hw | ||
55 | * ht_capa_mod_msk logic in main.c as well. | ||
56 | * And, if this method can ever change ht_cap.ht_supported, fix | ||
57 | * the check in ieee80211_add_ht_ie. | ||
58 | */ | ||
59 | |||
60 | /* check for HT over-rides, MCS rates first. */ | ||
61 | for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) { | ||
62 | u8 m = smask[i]; | ||
63 | ht_cap->mcs.rx_mask[i] &= ~m; /* turn off all masked bits */ | ||
64 | /* Add back rates that are supported */ | ||
65 | ht_cap->mcs.rx_mask[i] |= (m & scaps[i]); | ||
66 | } | ||
67 | |||
68 | /* Force removal of HT-40 capabilities? */ | ||
69 | __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SUP_WIDTH_20_40); | ||
70 | __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SGI_40); | ||
71 | |||
72 | /* Allow user to disable the max-AMSDU bit. */ | ||
73 | __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_MAX_AMSDU); | ||
74 | |||
75 | /* Allow user to decrease AMPDU factor */ | ||
76 | if (sdata->u.mgd.ht_capa_mask.ampdu_params_info & | ||
77 | IEEE80211_HT_AMPDU_PARM_FACTOR) { | ||
78 | u8 n = sdata->u.mgd.ht_capa.ampdu_params_info | ||
79 | & IEEE80211_HT_AMPDU_PARM_FACTOR; | ||
80 | if (n < ht_cap->ampdu_factor) | ||
81 | ht_cap->ampdu_factor = n; | ||
82 | } | ||
83 | |||
84 | /* Allow the user to increase AMPDU density. */ | ||
85 | if (sdata->u.mgd.ht_capa_mask.ampdu_params_info & | ||
86 | IEEE80211_HT_AMPDU_PARM_DENSITY) { | ||
87 | u8 n = (sdata->u.mgd.ht_capa.ampdu_params_info & | ||
88 | IEEE80211_HT_AMPDU_PARM_DENSITY) | ||
89 | >> IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT; | ||
90 | if (n > ht_cap->ampdu_density) | ||
91 | ht_cap->ampdu_density = n; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | |||
96 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | ||
97 | struct ieee80211_supported_band *sband, | ||
23 | struct ieee80211_ht_cap *ht_cap_ie, | 98 | struct ieee80211_ht_cap *ht_cap_ie, |
24 | struct ieee80211_sta_ht_cap *ht_cap) | 99 | struct ieee80211_sta_ht_cap *ht_cap) |
25 | { | 100 | { |
@@ -103,6 +178,12 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, | |||
103 | /* handle MCS rate 32 too */ | 178 | /* handle MCS rate 32 too */ |
104 | if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) | 179 | if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) |
105 | ht_cap->mcs.rx_mask[32/8] |= 1; | 180 | ht_cap->mcs.rx_mask[32/8] |= 1; |
181 | |||
182 | /* | ||
183 | * If user has specified capability over-rides, take care | ||
184 | * of that here. | ||
185 | */ | ||
186 | ieee80211_apply_htcap_overrides(sdata, ht_cap); | ||
106 | } | 187 | } |
107 | 188 | ||
108 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx) | 189 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx) |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 068cc92d16aa..762243e469df 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -142,6 +142,7 @@ typedef unsigned __bitwise__ ieee80211_tx_result; | |||
142 | 142 | ||
143 | struct ieee80211_tx_data { | 143 | struct ieee80211_tx_data { |
144 | struct sk_buff *skb; | 144 | struct sk_buff *skb; |
145 | struct sk_buff_head skbs; | ||
145 | struct ieee80211_local *local; | 146 | struct ieee80211_local *local; |
146 | struct ieee80211_sub_if_data *sdata; | 147 | struct ieee80211_sub_if_data *sdata; |
147 | struct sta_info *sta; | 148 | struct sta_info *sta; |
@@ -448,6 +449,9 @@ struct ieee80211_if_managed { | |||
448 | */ | 449 | */ |
449 | int rssi_min_thold, rssi_max_thold; | 450 | int rssi_min_thold, rssi_max_thold; |
450 | int last_ave_beacon_signal; | 451 | int last_ave_beacon_signal; |
452 | |||
453 | struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */ | ||
454 | struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */ | ||
451 | }; | 455 | }; |
452 | 456 | ||
453 | struct ieee80211_if_ibss { | 457 | struct ieee80211_if_ibss { |
@@ -1039,6 +1043,69 @@ struct ieee80211_ra_tid { | |||
1039 | u16 tid; | 1043 | u16 tid; |
1040 | }; | 1044 | }; |
1041 | 1045 | ||
1046 | /* Parsed Information Elements */ | ||
1047 | struct ieee802_11_elems { | ||
1048 | u8 *ie_start; | ||
1049 | size_t total_len; | ||
1050 | |||
1051 | /* pointers to IEs */ | ||
1052 | u8 *ssid; | ||
1053 | u8 *supp_rates; | ||
1054 | u8 *fh_params; | ||
1055 | u8 *ds_params; | ||
1056 | u8 *cf_params; | ||
1057 | struct ieee80211_tim_ie *tim; | ||
1058 | u8 *ibss_params; | ||
1059 | u8 *challenge; | ||
1060 | u8 *wpa; | ||
1061 | u8 *rsn; | ||
1062 | u8 *erp_info; | ||
1063 | u8 *ext_supp_rates; | ||
1064 | u8 *wmm_info; | ||
1065 | u8 *wmm_param; | ||
1066 | struct ieee80211_ht_cap *ht_cap_elem; | ||
1067 | struct ieee80211_ht_info *ht_info_elem; | ||
1068 | struct ieee80211_meshconf_ie *mesh_config; | ||
1069 | u8 *mesh_id; | ||
1070 | u8 *peering; | ||
1071 | u8 *preq; | ||
1072 | u8 *prep; | ||
1073 | u8 *perr; | ||
1074 | struct ieee80211_rann_ie *rann; | ||
1075 | u8 *ch_switch_elem; | ||
1076 | u8 *country_elem; | ||
1077 | u8 *pwr_constr_elem; | ||
1078 | u8 *quiet_elem; /* first quite element */ | ||
1079 | u8 *timeout_int; | ||
1080 | |||
1081 | /* length of them, respectively */ | ||
1082 | u8 ssid_len; | ||
1083 | u8 supp_rates_len; | ||
1084 | u8 fh_params_len; | ||
1085 | u8 ds_params_len; | ||
1086 | u8 cf_params_len; | ||
1087 | u8 tim_len; | ||
1088 | u8 ibss_params_len; | ||
1089 | u8 challenge_len; | ||
1090 | u8 wpa_len; | ||
1091 | u8 rsn_len; | ||
1092 | u8 erp_info_len; | ||
1093 | u8 ext_supp_rates_len; | ||
1094 | u8 wmm_info_len; | ||
1095 | u8 wmm_param_len; | ||
1096 | u8 mesh_id_len; | ||
1097 | u8 peering_len; | ||
1098 | u8 preq_len; | ||
1099 | u8 prep_len; | ||
1100 | u8 perr_len; | ||
1101 | u8 ch_switch_elem_len; | ||
1102 | u8 country_elem_len; | ||
1103 | u8 pwr_constr_elem_len; | ||
1104 | u8 quiet_elem_len; | ||
1105 | u8 num_of_quiet_elem; /* can be more the one */ | ||
1106 | u8 timeout_int_len; | ||
1107 | }; | ||
1108 | |||
1042 | static inline struct ieee80211_local *hw_to_local( | 1109 | static inline struct ieee80211_local *hw_to_local( |
1043 | struct ieee80211_hw *hw) | 1110 | struct ieee80211_hw *hw) |
1044 | { | 1111 | { |
@@ -1188,7 +1255,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1188 | struct net_device *dev); | 1255 | struct net_device *dev); |
1189 | 1256 | ||
1190 | /* HT */ | 1257 | /* HT */ |
1191 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, | 1258 | bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata); |
1259 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | ||
1260 | struct ieee80211_sta_ht_cap *ht_cap); | ||
1261 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | ||
1262 | struct ieee80211_supported_band *sband, | ||
1192 | struct ieee80211_ht_cap *ht_cap_ie, | 1263 | struct ieee80211_ht_cap *ht_cap_ie, |
1193 | struct ieee80211_sta_ht_cap *ht_cap); | 1264 | struct ieee80211_sta_ht_cap *ht_cap); |
1194 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | 1265 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, |
@@ -1343,7 +1414,7 @@ void ieee80211_recalc_smps(struct ieee80211_local *local); | |||
1343 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | 1414 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, |
1344 | const u8 *ids, int n_ids, size_t offset); | 1415 | const u8 *ids, int n_ids, size_t offset); |
1345 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); | 1416 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); |
1346 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband, | 1417 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
1347 | u16 cap); | 1418 | u16 cap); |
1348 | u8 *ieee80211_ie_build_ht_info(u8 *pos, | 1419 | u8 *ieee80211_ie_build_ht_info(u8 *pos, |
1349 | struct ieee80211_sta_ht_cap *ht_cap, | 1420 | struct ieee80211_sta_ht_cap *ht_cap, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 12a6d4bb5d37..b34ca0cbdf6c 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -474,7 +474,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
474 | RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); | 474 | RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); |
475 | synchronize_rcu(); | 475 | synchronize_rcu(); |
476 | kfree(old_beacon); | 476 | kfree(old_beacon); |
477 | kfree(old_probe_resp); | 477 | kfree_skb(old_probe_resp); |
478 | 478 | ||
479 | /* down all dependent devices, that is VLANs */ | 479 | /* down all dependent devices, that is VLANs */ |
480 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, | 480 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e323d4e6647b..dddedfad5404 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -558,6 +558,19 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { | |||
558 | }, | 558 | }, |
559 | }; | 559 | }; |
560 | 560 | ||
561 | static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { | ||
562 | .ampdu_params_info = IEEE80211_HT_AMPDU_PARM_FACTOR | | ||
563 | IEEE80211_HT_AMPDU_PARM_DENSITY, | ||
564 | |||
565 | .cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | ||
566 | IEEE80211_HT_CAP_MAX_AMSDU | | ||
567 | IEEE80211_HT_CAP_SGI_40), | ||
568 | .mcs = { | ||
569 | .rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff, | ||
570 | 0xff, 0xff, 0xff, 0xff, 0xff, }, | ||
571 | }, | ||
572 | }; | ||
573 | |||
561 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 574 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
562 | const struct ieee80211_ops *ops) | 575 | const struct ieee80211_ops *ops) |
563 | { | 576 | { |
@@ -594,7 +607,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
594 | wiphy->flags |= WIPHY_FLAG_NETNS_OK | | 607 | wiphy->flags |= WIPHY_FLAG_NETNS_OK | |
595 | WIPHY_FLAG_4ADDR_AP | | 608 | WIPHY_FLAG_4ADDR_AP | |
596 | WIPHY_FLAG_4ADDR_STATION | | 609 | WIPHY_FLAG_4ADDR_STATION | |
597 | WIPHY_FLAG_REPORTS_OBSS; | 610 | WIPHY_FLAG_REPORTS_OBSS | |
611 | WIPHY_FLAG_OFFCHAN_TX | | ||
612 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | ||
598 | 613 | ||
599 | wiphy->features = NL80211_FEATURE_SK_TX_STATUS; | 614 | wiphy->features = NL80211_FEATURE_SK_TX_STATUS; |
600 | 615 | ||
@@ -609,7 +624,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
609 | 624 | ||
610 | local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); | 625 | local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); |
611 | 626 | ||
612 | BUG_ON(!ops->tx); | 627 | BUG_ON(!ops->tx && !ops->tx_frags); |
613 | BUG_ON(!ops->start); | 628 | BUG_ON(!ops->start); |
614 | BUG_ON(!ops->stop); | 629 | BUG_ON(!ops->stop); |
615 | BUG_ON(!ops->config); | 630 | BUG_ON(!ops->config); |
@@ -629,6 +644,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
629 | local->user_power_level = -1; | 644 | local->user_power_level = -1; |
630 | local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; | 645 | local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; |
631 | local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; | 646 | local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; |
647 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; | ||
632 | 648 | ||
633 | INIT_LIST_HEAD(&local->interfaces); | 649 | INIT_LIST_HEAD(&local->interfaces); |
634 | 650 | ||
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index b3a125f60347..ee82d2f7f114 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -366,7 +366,7 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb, | |||
366 | return -ENOMEM; | 366 | return -ENOMEM; |
367 | 367 | ||
368 | pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap)); | 368 | pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap)); |
369 | ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap); | 369 | ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap); |
370 | 370 | ||
371 | return 0; | 371 | return 0; |
372 | } | 372 | } |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index a7afb2d32def..ce3db2735d7c 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -867,10 +867,11 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) | |||
867 | return; | 867 | return; |
868 | } | 868 | } |
869 | 869 | ||
870 | spin_lock_bh(&mpath->state_lock); | 870 | spin_lock(&mpath->state_lock); |
871 | if (mpath->flags & MESH_PATH_REQ_QUEUED) { | 871 | if (mpath->flags & MESH_PATH_REQ_QUEUED) { |
872 | spin_unlock_bh(&mpath->state_lock); | 872 | spin_unlock(&mpath->state_lock); |
873 | spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); | 873 | spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); |
874 | kfree(preq_node); | ||
874 | return; | 875 | return; |
875 | } | 876 | } |
876 | 877 | ||
@@ -878,7 +879,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) | |||
878 | preq_node->flags = flags; | 879 | preq_node->flags = flags; |
879 | 880 | ||
880 | mpath->flags |= MESH_PATH_REQ_QUEUED; | 881 | mpath->flags |= MESH_PATH_REQ_QUEUED; |
881 | spin_unlock_bh(&mpath->state_lock); | 882 | spin_unlock(&mpath->state_lock); |
882 | 883 | ||
883 | list_add_tail(&preq_node->list, &ifmsh->preq_queue.list); | 884 | list_add_tail(&preq_node->list, &ifmsh->preq_queue.list); |
884 | ++ifmsh->preq_queue_len; | 885 | ++ifmsh->preq_queue_len; |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 4fc23d1b9c3a..7bd2a76aef0e 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -69,8 +69,6 @@ static inline struct mesh_table *resize_dereference_mpp_paths(void) | |||
69 | lockdep_is_held(&pathtbl_resize_lock)); | 69 | lockdep_is_held(&pathtbl_resize_lock)); |
70 | } | 70 | } |
71 | 71 | ||
72 | static int mesh_gate_add(struct mesh_table *tbl, struct mesh_path *mpath); | ||
73 | |||
74 | /* | 72 | /* |
75 | * CAREFUL -- "tbl" must not be an expression, | 73 | * CAREFUL -- "tbl" must not be an expression, |
76 | * in particular not an rcu_dereference(), since | 74 | * in particular not an rcu_dereference(), since |
@@ -420,21 +418,18 @@ static void mesh_gate_node_reclaim(struct rcu_head *rp) | |||
420 | } | 418 | } |
421 | 419 | ||
422 | /** | 420 | /** |
423 | * mesh_gate_add - mark mpath as path to a mesh gate and add to known_gates | 421 | * mesh_path_add_gate - add the given mpath to a mesh gate to our path table |
424 | * @mesh_tbl: table which contains known_gates list | 422 | * @mpath: gate path to add to table |
425 | * @mpath: mpath to known mesh gate | ||
426 | * | ||
427 | * Returns: 0 on success | ||
428 | * | ||
429 | */ | 423 | */ |
430 | static int mesh_gate_add(struct mesh_table *tbl, struct mesh_path *mpath) | 424 | int mesh_path_add_gate(struct mesh_path *mpath) |
431 | { | 425 | { |
426 | struct mesh_table *tbl; | ||
432 | struct mpath_node *gate, *new_gate; | 427 | struct mpath_node *gate, *new_gate; |
433 | struct hlist_node *n; | 428 | struct hlist_node *n; |
434 | int err; | 429 | int err; |
435 | 430 | ||
436 | rcu_read_lock(); | 431 | rcu_read_lock(); |
437 | tbl = rcu_dereference(tbl); | 432 | tbl = rcu_dereference(mesh_paths); |
438 | 433 | ||
439 | hlist_for_each_entry_rcu(gate, n, tbl->known_gates, list) | 434 | hlist_for_each_entry_rcu(gate, n, tbl->known_gates, list) |
440 | if (gate->mpath == mpath) { | 435 | if (gate->mpath == mpath) { |
@@ -478,8 +473,6 @@ static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath) | |||
478 | struct mpath_node *gate; | 473 | struct mpath_node *gate; |
479 | struct hlist_node *p, *q; | 474 | struct hlist_node *p, *q; |
480 | 475 | ||
481 | tbl = rcu_dereference(tbl); | ||
482 | |||
483 | hlist_for_each_entry_safe(gate, p, q, tbl->known_gates, list) | 476 | hlist_for_each_entry_safe(gate, p, q, tbl->known_gates, list) |
484 | if (gate->mpath == mpath) { | 477 | if (gate->mpath == mpath) { |
485 | spin_lock_bh(&tbl->gates_lock); | 478 | spin_lock_bh(&tbl->gates_lock); |
@@ -498,16 +491,6 @@ static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath) | |||
498 | } | 491 | } |
499 | 492 | ||
500 | /** | 493 | /** |
501 | * | ||
502 | * mesh_path_add_gate - add the given mpath to a mesh gate to our path table | ||
503 | * @mpath: gate path to add to table | ||
504 | */ | ||
505 | int mesh_path_add_gate(struct mesh_path *mpath) | ||
506 | { | ||
507 | return mesh_gate_add(mesh_paths, mpath); | ||
508 | } | ||
509 | |||
510 | /** | ||
511 | * mesh_gate_num - number of gates known to this interface | 494 | * mesh_gate_num - number of gates known to this interface |
512 | * @sdata: subif data | 495 | * @sdata: subif data |
513 | */ | 496 | */ |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 0140e88a8220..7314372b12ba 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -101,7 +101,8 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
101 | set_sta_flag(sta, WLAN_STA_WME); | 101 | set_sta_flag(sta, WLAN_STA_WME); |
102 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; | 102 | sta->sta.supp_rates[local->hw.conf.channel->band] = rates; |
103 | if (elems->ht_cap_elem) | 103 | if (elems->ht_cap_elem) |
104 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, elems->ht_cap_elem, | 104 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
105 | elems->ht_cap_elem, | ||
105 | &sta->sta.ht_cap); | 106 | &sta->sta.ht_cap); |
106 | rate_control_rate_init(sta); | 107 | rate_control_rate_init(sta); |
107 | 108 | ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f9ec15b3fe09..09019d135942 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -209,6 +209,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
209 | channel_type = NL80211_CHAN_HT20; | 209 | channel_type = NL80211_CHAN_HT20; |
210 | 210 | ||
211 | if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && | 211 | if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && |
212 | !ieee80111_cfg_override_disables_ht40(sdata) && | ||
212 | (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && | 213 | (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && |
213 | (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { | 214 | (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { |
214 | switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 215 | switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { |
@@ -1120,6 +1121,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1120 | 1121 | ||
1121 | /* on the next assoc, re-program HT parameters */ | 1122 | /* on the next assoc, re-program HT parameters */ |
1122 | sdata->ht_opmode_valid = false; | 1123 | sdata->ht_opmode_valid = false; |
1124 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); | ||
1125 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); | ||
1123 | 1126 | ||
1124 | local->power_constr_level = 0; | 1127 | local->power_constr_level = 0; |
1125 | 1128 | ||
@@ -1359,9 +1362,6 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | |||
1359 | ieee80211_set_disassoc(sdata, true, true); | 1362 | ieee80211_set_disassoc(sdata, true, true); |
1360 | mutex_unlock(&ifmgd->mtx); | 1363 | mutex_unlock(&ifmgd->mtx); |
1361 | 1364 | ||
1362 | mutex_lock(&local->mtx); | ||
1363 | ieee80211_recalc_idle(local); | ||
1364 | mutex_unlock(&local->mtx); | ||
1365 | /* | 1365 | /* |
1366 | * must be outside lock due to cfg80211, | 1366 | * must be outside lock due to cfg80211, |
1367 | * but that's not a problem. | 1367 | * but that's not a problem. |
@@ -1370,6 +1370,10 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | |||
1370 | IEEE80211_STYPE_DEAUTH, | 1370 | IEEE80211_STYPE_DEAUTH, |
1371 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | 1371 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
1372 | NULL, true); | 1372 | NULL, true); |
1373 | |||
1374 | mutex_lock(&local->mtx); | ||
1375 | ieee80211_recalc_idle(local); | ||
1376 | mutex_unlock(&local->mtx); | ||
1373 | } | 1377 | } |
1374 | 1378 | ||
1375 | void ieee80211_beacon_connection_loss_work(struct work_struct *work) | 1379 | void ieee80211_beacon_connection_loss_work(struct work_struct *work) |
@@ -1575,7 +1579,6 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1575 | 1579 | ||
1576 | set_sta_flag(sta, WLAN_STA_AUTH); | 1580 | set_sta_flag(sta, WLAN_STA_AUTH); |
1577 | set_sta_flag(sta, WLAN_STA_ASSOC); | 1581 | set_sta_flag(sta, WLAN_STA_ASSOC); |
1578 | set_sta_flag(sta, WLAN_STA_ASSOC_AP); | ||
1579 | if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) | 1582 | if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) |
1580 | set_sta_flag(sta, WLAN_STA_AUTHORIZED); | 1583 | set_sta_flag(sta, WLAN_STA_AUTHORIZED); |
1581 | 1584 | ||
@@ -1613,7 +1616,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1613 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | 1616 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; |
1614 | 1617 | ||
1615 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 1618 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) |
1616 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, | 1619 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
1617 | elems.ht_cap_elem, &sta->sta.ht_cap); | 1620 | elems.ht_cap_elem, &sta->sta.ht_cap); |
1618 | 1621 | ||
1619 | ap_ht_cap_flags = sta->sta.ht_cap.cap; | 1622 | ap_ht_cap_flags = sta->sta.ht_cap.cap; |
@@ -1982,7 +1985,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1982 | 1985 | ||
1983 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1986 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1984 | 1987 | ||
1985 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, | 1988 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
1986 | elems.ht_cap_elem, &sta->sta.ht_cap); | 1989 | elems.ht_cap_elem, &sta->sta.ht_cap); |
1987 | 1990 | ||
1988 | ap_ht_cap_flags = sta->sta.ht_cap.cap; | 1991 | ap_ht_cap_flags = sta->sta.ht_cap.cap; |
@@ -2136,9 +2139,6 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
2136 | 2139 | ||
2137 | ieee80211_set_disassoc(sdata, true, true); | 2140 | ieee80211_set_disassoc(sdata, true, true); |
2138 | mutex_unlock(&ifmgd->mtx); | 2141 | mutex_unlock(&ifmgd->mtx); |
2139 | mutex_lock(&local->mtx); | ||
2140 | ieee80211_recalc_idle(local); | ||
2141 | mutex_unlock(&local->mtx); | ||
2142 | /* | 2142 | /* |
2143 | * must be outside lock due to cfg80211, | 2143 | * must be outside lock due to cfg80211, |
2144 | * but that's not a problem. | 2144 | * but that's not a problem. |
@@ -2146,6 +2146,11 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
2146 | ieee80211_send_deauth_disassoc(sdata, bssid, | 2146 | ieee80211_send_deauth_disassoc(sdata, bssid, |
2147 | IEEE80211_STYPE_DEAUTH, reason, | 2147 | IEEE80211_STYPE_DEAUTH, reason, |
2148 | NULL, true); | 2148 | NULL, true); |
2149 | |||
2150 | mutex_lock(&local->mtx); | ||
2151 | ieee80211_recalc_idle(local); | ||
2152 | mutex_unlock(&local->mtx); | ||
2153 | |||
2149 | mutex_lock(&ifmgd->mtx); | 2154 | mutex_lock(&ifmgd->mtx); |
2150 | } | 2155 | } |
2151 | 2156 | ||
@@ -2640,6 +2645,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2640 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 2645 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; |
2641 | 2646 | ||
2642 | 2647 | ||
2648 | if (req->flags & ASSOC_REQ_DISABLE_HT) | ||
2649 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | ||
2650 | |||
2651 | memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); | ||
2652 | memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, | ||
2653 | sizeof(ifmgd->ht_capa_mask)); | ||
2654 | |||
2643 | if (req->ie && req->ie_len) { | 2655 | if (req->ie && req->ie_len) { |
2644 | memcpy(wk->ie, req->ie, req->ie_len); | 2656 | memcpy(wk->ie, req->ie, req->ie_len); |
2645 | wk->ie_len = req->ie_len; | 2657 | wk->ie_len = req->ie_len; |
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 3d414411a96e..ebd8cccac8f2 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -212,8 +212,6 @@ static void ieee80211_hw_roc_start(struct work_struct *work) | |||
212 | return; | 212 | return; |
213 | } | 213 | } |
214 | 214 | ||
215 | ieee80211_recalc_idle(local); | ||
216 | |||
217 | if (local->hw_roc_skb) { | 215 | if (local->hw_roc_skb) { |
218 | sdata = IEEE80211_DEV_TO_SUB_IF(local->hw_roc_dev); | 216 | sdata = IEEE80211_DEV_TO_SUB_IF(local->hw_roc_dev); |
219 | ieee80211_tx_skb(sdata, local->hw_roc_skb); | 217 | ieee80211_tx_skb(sdata, local->hw_roc_skb); |
@@ -227,6 +225,8 @@ static void ieee80211_hw_roc_start(struct work_struct *work) | |||
227 | GFP_KERNEL); | 225 | GFP_KERNEL); |
228 | } | 226 | } |
229 | 227 | ||
228 | ieee80211_recalc_idle(local); | ||
229 | |||
230 | mutex_unlock(&local->mtx); | 230 | mutex_unlock(&local->mtx); |
231 | } | 231 | } |
232 | 232 | ||
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index cdb28535716b..ff5f7b84e825 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -36,8 +36,17 @@ | |||
36 | /* Transmit duration for the raw data part of an average sized packet */ | 36 | /* Transmit duration for the raw data part of an average sized packet */ |
37 | #define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) | 37 | #define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) |
38 | 38 | ||
39 | /* | ||
40 | * Define group sort order: HT40 -> SGI -> #streams | ||
41 | */ | ||
42 | #define GROUP_IDX(_streams, _sgi, _ht40) \ | ||
43 | MINSTREL_MAX_STREAMS * 2 * _ht40 + \ | ||
44 | MINSTREL_MAX_STREAMS * _sgi + \ | ||
45 | _streams - 1 | ||
46 | |||
39 | /* MCS rate information for an MCS group */ | 47 | /* MCS rate information for an MCS group */ |
40 | #define MCS_GROUP(_streams, _sgi, _ht40) { \ | 48 | #define MCS_GROUP(_streams, _sgi, _ht40) \ |
49 | [GROUP_IDX(_streams, _sgi, _ht40)] = { \ | ||
41 | .streams = _streams, \ | 50 | .streams = _streams, \ |
42 | .flags = \ | 51 | .flags = \ |
43 | (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \ | 52 | (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \ |
@@ -58,6 +67,9 @@ | |||
58 | * To enable sufficiently targeted rate sampling, MCS rates are divided into | 67 | * To enable sufficiently targeted rate sampling, MCS rates are divided into |
59 | * groups, based on the number of streams and flags (HT40, SGI) that they | 68 | * groups, based on the number of streams and flags (HT40, SGI) that they |
60 | * use. | 69 | * use. |
70 | * | ||
71 | * Sortorder has to be fixed for GROUP_IDX macro to be applicable: | ||
72 | * HT40 -> SGI -> #streams | ||
61 | */ | 73 | */ |
62 | const struct mcs_group minstrel_mcs_groups[] = { | 74 | const struct mcs_group minstrel_mcs_groups[] = { |
63 | MCS_GROUP(1, 0, 0), | 75 | MCS_GROUP(1, 0, 0), |
@@ -102,21 +114,9 @@ minstrel_ewma(int old, int new, int weight) | |||
102 | static int | 114 | static int |
103 | minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) | 115 | minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) |
104 | { | 116 | { |
105 | int streams = (rate->idx / MCS_GROUP_RATES) + 1; | 117 | return GROUP_IDX((rate->idx / MCS_GROUP_RATES) + 1, |
106 | u32 flags = IEEE80211_TX_RC_SHORT_GI | IEEE80211_TX_RC_40_MHZ_WIDTH; | 118 | !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), |
107 | int i; | 119 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); |
108 | |||
109 | for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) { | ||
110 | if (minstrel_mcs_groups[i].streams != streams) | ||
111 | continue; | ||
112 | if (minstrel_mcs_groups[i].flags != (rate->flags & flags)) | ||
113 | continue; | ||
114 | |||
115 | return i; | ||
116 | } | ||
117 | |||
118 | WARN_ON(1); | ||
119 | return 0; | ||
120 | } | 120 | } |
121 | 121 | ||
122 | static inline struct minstrel_rate_stats * | 122 | static inline struct minstrel_rate_stats * |
@@ -130,7 +130,7 @@ minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) | |||
130 | * Recalculate success probabilities and counters for a rate using EWMA | 130 | * Recalculate success probabilities and counters for a rate using EWMA |
131 | */ | 131 | */ |
132 | static void | 132 | static void |
133 | minstrel_calc_rate_ewma(struct minstrel_priv *mp, struct minstrel_rate_stats *mr) | 133 | minstrel_calc_rate_ewma(struct minstrel_rate_stats *mr) |
134 | { | 134 | { |
135 | if (unlikely(mr->attempts > 0)) { | 135 | if (unlikely(mr->attempts > 0)) { |
136 | mr->sample_skipped = 0; | 136 | mr->sample_skipped = 0; |
@@ -156,8 +156,7 @@ minstrel_calc_rate_ewma(struct minstrel_priv *mp, struct minstrel_rate_stats *mr | |||
156 | * the expected number of retransmissions and their expected length | 156 | * the expected number of retransmissions and their expected length |
157 | */ | 157 | */ |
158 | static void | 158 | static void |
159 | minstrel_ht_calc_tp(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | 159 | minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) |
160 | int group, int rate) | ||
161 | { | 160 | { |
162 | struct minstrel_rate_stats *mr; | 161 | struct minstrel_rate_stats *mr; |
163 | unsigned int usecs; | 162 | unsigned int usecs; |
@@ -226,8 +225,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
226 | mr = &mg->rates[i]; | 225 | mr = &mg->rates[i]; |
227 | mr->retry_updated = false; | 226 | mr->retry_updated = false; |
228 | index = MCS_GROUP_RATES * group + i; | 227 | index = MCS_GROUP_RATES * group + i; |
229 | minstrel_calc_rate_ewma(mp, mr); | 228 | minstrel_calc_rate_ewma(mr); |
230 | minstrel_ht_calc_tp(mp, mi, group, i); | 229 | minstrel_ht_calc_tp(mi, group, i); |
231 | 230 | ||
232 | if (!mr->cur_tp) | 231 | if (!mr->cur_tp) |
233 | continue; | 232 | continue; |
@@ -300,10 +299,10 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
300 | static bool | 299 | static bool |
301 | minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate) | 300 | minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate) |
302 | { | 301 | { |
303 | if (!rate->count) | 302 | if (rate->idx < 0) |
304 | return false; | 303 | return false; |
305 | 304 | ||
306 | if (rate->idx < 0) | 305 | if (!rate->count) |
307 | return false; | 306 | return false; |
308 | 307 | ||
309 | return !!(rate->flags & IEEE80211_TX_RC_MCS); | 308 | return !!(rate->flags & IEEE80211_TX_RC_MCS); |
@@ -357,7 +356,7 @@ minstrel_downgrade_rate(struct minstrel_ht_sta *mi, unsigned int *idx, | |||
357 | } | 356 | } |
358 | 357 | ||
359 | static void | 358 | static void |
360 | minstrel_aggr_check(struct minstrel_priv *mp, struct ieee80211_sta *pubsta, struct sk_buff *skb) | 359 | minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb) |
361 | { | 360 | { |
362 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 361 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
363 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | 362 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); |
@@ -455,7 +454,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
455 | if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { | 454 | if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { |
456 | minstrel_ht_update_stats(mp, mi); | 455 | minstrel_ht_update_stats(mp, mi); |
457 | if (!(info->flags & IEEE80211_TX_CTL_AMPDU)) | 456 | if (!(info->flags & IEEE80211_TX_CTL_AMPDU)) |
458 | minstrel_aggr_check(mp, sta, skb); | 457 | minstrel_aggr_check(sta, skb); |
459 | } | 458 | } |
460 | } | 459 | } |
461 | 460 | ||
@@ -515,7 +514,6 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
515 | static void | 514 | static void |
516 | minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | 515 | minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, |
517 | struct ieee80211_tx_rate *rate, int index, | 516 | struct ieee80211_tx_rate *rate, int index, |
518 | struct ieee80211_tx_rate_control *txrc, | ||
519 | bool sample, bool rtscts) | 517 | bool sample, bool rtscts) |
520 | { | 518 | { |
521 | const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; | 519 | const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; |
@@ -628,11 +626,11 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
628 | if (sample_idx >= 0) { | 626 | if (sample_idx >= 0) { |
629 | sample = true; | 627 | sample = true; |
630 | minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx, | 628 | minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx, |
631 | txrc, true, false); | 629 | true, false); |
632 | info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; | 630 | info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; |
633 | } else { | 631 | } else { |
634 | minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate, | 632 | minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate, |
635 | txrc, false, false); | 633 | false, false); |
636 | } | 634 | } |
637 | 635 | ||
638 | if (mp->hw->max_rates >= 3) { | 636 | if (mp->hw->max_rates >= 3) { |
@@ -643,13 +641,13 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
643 | */ | 641 | */ |
644 | if (sample_idx >= 0) | 642 | if (sample_idx >= 0) |
645 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate, | 643 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate, |
646 | txrc, false, false); | 644 | false, false); |
647 | else | 645 | else |
648 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2, | 646 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2, |
649 | txrc, false, true); | 647 | false, true); |
650 | 648 | ||
651 | minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate, | 649 | minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate, |
652 | txrc, false, !sample); | 650 | false, !sample); |
653 | 651 | ||
654 | ar[3].count = 0; | 652 | ar[3].count = 0; |
655 | ar[3].idx = -1; | 653 | ar[3].idx = -1; |
@@ -660,7 +658,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
660 | * max_tp_rate -> max_prob_rate by default. | 658 | * max_tp_rate -> max_prob_rate by default. |
661 | */ | 659 | */ |
662 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_prob_rate, | 660 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_prob_rate, |
663 | txrc, false, !sample); | 661 | false, !sample); |
664 | 662 | ||
665 | ar[2].count = 0; | 663 | ar[2].count = 0; |
666 | ar[2].idx = -1; | 664 | ar[2].idx = -1; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index c5923ab8a070..6280e8bca49d 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -30,7 +30,6 @@ | |||
30 | * when virtual port control is not in use. | 30 | * when virtual port control is not in use. |
31 | * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble | 31 | * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble |
32 | * frames. | 32 | * frames. |
33 | * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP. | ||
34 | * @WLAN_STA_WME: Station is a QoS-STA. | 33 | * @WLAN_STA_WME: Station is a QoS-STA. |
35 | * @WLAN_STA_WDS: Station is one of our WDS peers. | 34 | * @WLAN_STA_WDS: Station is one of our WDS peers. |
36 | * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the | 35 | * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the |
@@ -60,7 +59,6 @@ enum ieee80211_sta_info_flags { | |||
60 | WLAN_STA_PS_STA, | 59 | WLAN_STA_PS_STA, |
61 | WLAN_STA_AUTHORIZED, | 60 | WLAN_STA_AUTHORIZED, |
62 | WLAN_STA_SHORT_PREAMBLE, | 61 | WLAN_STA_SHORT_PREAMBLE, |
63 | WLAN_STA_ASSOC_AP, | ||
64 | WLAN_STA_WME, | 62 | WLAN_STA_WME, |
65 | WLAN_STA_WDS, | 63 | WLAN_STA_WDS, |
66 | WLAN_STA_CLEAR_PS_FILT, | 64 | WLAN_STA_CLEAR_PS_FILT, |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f044963feb9a..8d31933abe6a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -36,7 +36,8 @@ | |||
36 | 36 | ||
37 | /* misc utils */ | 37 | /* misc utils */ |
38 | 38 | ||
39 | static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, | 39 | static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, |
40 | struct sk_buff *skb, int group_addr, | ||
40 | int next_frag_len) | 41 | int next_frag_len) |
41 | { | 42 | { |
42 | int rate, mrate, erp, dur, i; | 43 | int rate, mrate, erp, dur, i; |
@@ -44,7 +45,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, | |||
44 | struct ieee80211_local *local = tx->local; | 45 | struct ieee80211_local *local = tx->local; |
45 | struct ieee80211_supported_band *sband; | 46 | struct ieee80211_supported_band *sband; |
46 | struct ieee80211_hdr *hdr; | 47 | struct ieee80211_hdr *hdr; |
47 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | 48 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
48 | 49 | ||
49 | /* assume HW handles this */ | 50 | /* assume HW handles this */ |
50 | if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) | 51 | if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) |
@@ -76,7 +77,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, | |||
76 | * at the highest possible rate belonging to the PHY rates in the | 77 | * at the highest possible rate belonging to the PHY rates in the |
77 | * BSSBasicRateSet | 78 | * BSSBasicRateSet |
78 | */ | 79 | */ |
79 | hdr = (struct ieee80211_hdr *)tx->skb->data; | 80 | hdr = (struct ieee80211_hdr *)skb->data; |
80 | if (ieee80211_is_ctl(hdr->frame_control)) { | 81 | if (ieee80211_is_ctl(hdr->frame_control)) { |
81 | /* TODO: These control frames are not currently sent by | 82 | /* TODO: These control frames are not currently sent by |
82 | * mac80211, but should they be implemented, this function | 83 | * mac80211, but should they be implemented, this function |
@@ -572,8 +573,6 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
572 | switch (tx->key->conf.cipher) { | 573 | switch (tx->key->conf.cipher) { |
573 | case WLAN_CIPHER_SUITE_WEP40: | 574 | case WLAN_CIPHER_SUITE_WEP40: |
574 | case WLAN_CIPHER_SUITE_WEP104: | 575 | case WLAN_CIPHER_SUITE_WEP104: |
575 | if (ieee80211_is_auth(hdr->frame_control)) | ||
576 | break; | ||
577 | case WLAN_CIPHER_SUITE_TKIP: | 576 | case WLAN_CIPHER_SUITE_TKIP: |
578 | if (!ieee80211_is_data_present(hdr->frame_control)) | 577 | if (!ieee80211_is_data_present(hdr->frame_control)) |
579 | tx->key = NULL; | 578 | tx->key = NULL; |
@@ -844,11 +843,13 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) | |||
844 | return TX_CONTINUE; | 843 | return TX_CONTINUE; |
845 | } | 844 | } |
846 | 845 | ||
847 | static int ieee80211_fragment(struct ieee80211_local *local, | 846 | static int ieee80211_fragment(struct ieee80211_tx_data *tx, |
848 | struct sk_buff *skb, int hdrlen, | 847 | struct sk_buff *skb, int hdrlen, |
849 | int frag_threshold) | 848 | int frag_threshold) |
850 | { | 849 | { |
851 | struct sk_buff *tail = skb, *tmp; | 850 | struct ieee80211_local *local = tx->local; |
851 | struct ieee80211_tx_info *info; | ||
852 | struct sk_buff *tmp; | ||
852 | int per_fragm = frag_threshold - hdrlen - FCS_LEN; | 853 | int per_fragm = frag_threshold - hdrlen - FCS_LEN; |
853 | int pos = hdrlen + per_fragm; | 854 | int pos = hdrlen + per_fragm; |
854 | int rem = skb->len - hdrlen - per_fragm; | 855 | int rem = skb->len - hdrlen - per_fragm; |
@@ -856,6 +857,8 @@ static int ieee80211_fragment(struct ieee80211_local *local, | |||
856 | if (WARN_ON(rem < 0)) | 857 | if (WARN_ON(rem < 0)) |
857 | return -EINVAL; | 858 | return -EINVAL; |
858 | 859 | ||
860 | /* first fragment was already added to queue by caller */ | ||
861 | |||
859 | while (rem) { | 862 | while (rem) { |
860 | int fraglen = per_fragm; | 863 | int fraglen = per_fragm; |
861 | 864 | ||
@@ -868,12 +871,21 @@ static int ieee80211_fragment(struct ieee80211_local *local, | |||
868 | IEEE80211_ENCRYPT_TAILROOM); | 871 | IEEE80211_ENCRYPT_TAILROOM); |
869 | if (!tmp) | 872 | if (!tmp) |
870 | return -ENOMEM; | 873 | return -ENOMEM; |
871 | tail->next = tmp; | 874 | |
872 | tail = tmp; | 875 | __skb_queue_tail(&tx->skbs, tmp); |
876 | |||
873 | skb_reserve(tmp, local->tx_headroom + | 877 | skb_reserve(tmp, local->tx_headroom + |
874 | IEEE80211_ENCRYPT_HEADROOM); | 878 | IEEE80211_ENCRYPT_HEADROOM); |
875 | /* copy control information */ | 879 | /* copy control information */ |
876 | memcpy(tmp->cb, skb->cb, sizeof(tmp->cb)); | 880 | memcpy(tmp->cb, skb->cb, sizeof(tmp->cb)); |
881 | |||
882 | info = IEEE80211_SKB_CB(tmp); | ||
883 | info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | | ||
884 | IEEE80211_TX_CTL_FIRST_FRAGMENT); | ||
885 | |||
886 | if (rem) | ||
887 | info->flags |= IEEE80211_TX_CTL_MORE_FRAMES; | ||
888 | |||
877 | skb_copy_queue_mapping(tmp, skb); | 889 | skb_copy_queue_mapping(tmp, skb); |
878 | tmp->priority = skb->priority; | 890 | tmp->priority = skb->priority; |
879 | tmp->dev = skb->dev; | 891 | tmp->dev = skb->dev; |
@@ -885,6 +897,7 @@ static int ieee80211_fragment(struct ieee80211_local *local, | |||
885 | pos += fraglen; | 897 | pos += fraglen; |
886 | } | 898 | } |
887 | 899 | ||
900 | /* adjust first fragment's length */ | ||
888 | skb->len = hdrlen + per_fragm; | 901 | skb->len = hdrlen + per_fragm; |
889 | return 0; | 902 | return 0; |
890 | } | 903 | } |
@@ -899,6 +912,10 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
899 | int hdrlen; | 912 | int hdrlen; |
900 | int fragnum; | 913 | int fragnum; |
901 | 914 | ||
915 | /* no matter what happens, tx->skb moves to tx->skbs */ | ||
916 | __skb_queue_tail(&tx->skbs, skb); | ||
917 | tx->skb = NULL; | ||
918 | |||
902 | if (info->flags & IEEE80211_TX_CTL_DONTFRAG) | 919 | if (info->flags & IEEE80211_TX_CTL_DONTFRAG) |
903 | return TX_CONTINUE; | 920 | return TX_CONTINUE; |
904 | 921 | ||
@@ -927,21 +944,21 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
927 | * of the fragments then we will simply pretend to accept the skb | 944 | * of the fragments then we will simply pretend to accept the skb |
928 | * but store it away as pending. | 945 | * but store it away as pending. |
929 | */ | 946 | */ |
930 | if (ieee80211_fragment(tx->local, skb, hdrlen, frag_threshold)) | 947 | if (ieee80211_fragment(tx, skb, hdrlen, frag_threshold)) |
931 | return TX_DROP; | 948 | return TX_DROP; |
932 | 949 | ||
933 | /* update duration/seq/flags of fragments */ | 950 | /* update duration/seq/flags of fragments */ |
934 | fragnum = 0; | 951 | fragnum = 0; |
935 | do { | 952 | |
953 | skb_queue_walk(&tx->skbs, skb) { | ||
936 | int next_len; | 954 | int next_len; |
937 | const __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); | 955 | const __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); |
938 | 956 | ||
939 | hdr = (void *)skb->data; | 957 | hdr = (void *)skb->data; |
940 | info = IEEE80211_SKB_CB(skb); | 958 | info = IEEE80211_SKB_CB(skb); |
941 | 959 | ||
942 | if (skb->next) { | 960 | if (!skb_queue_is_last(&tx->skbs, skb)) { |
943 | hdr->frame_control |= morefrags; | 961 | hdr->frame_control |= morefrags; |
944 | next_len = skb->next->len; | ||
945 | /* | 962 | /* |
946 | * No multi-rate retries for fragmented frames, that | 963 | * No multi-rate retries for fragmented frames, that |
947 | * would completely throw off the NAV at other STAs. | 964 | * would completely throw off the NAV at other STAs. |
@@ -956,10 +973,9 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
956 | hdr->frame_control &= ~morefrags; | 973 | hdr->frame_control &= ~morefrags; |
957 | next_len = 0; | 974 | next_len = 0; |
958 | } | 975 | } |
959 | hdr->duration_id = ieee80211_duration(tx, 0, next_len); | ||
960 | hdr->seq_ctrl |= cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG); | 976 | hdr->seq_ctrl |= cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG); |
961 | fragnum++; | 977 | fragnum++; |
962 | } while ((skb = skb->next)); | 978 | } |
963 | 979 | ||
964 | return TX_CONTINUE; | 980 | return TX_CONTINUE; |
965 | } | 981 | } |
@@ -967,16 +983,16 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
967 | static ieee80211_tx_result debug_noinline | 983 | static ieee80211_tx_result debug_noinline |
968 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) | 984 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) |
969 | { | 985 | { |
970 | struct sk_buff *skb = tx->skb; | 986 | struct sk_buff *skb; |
971 | 987 | ||
972 | if (!tx->sta) | 988 | if (!tx->sta) |
973 | return TX_CONTINUE; | 989 | return TX_CONTINUE; |
974 | 990 | ||
975 | tx->sta->tx_packets++; | 991 | tx->sta->tx_packets++; |
976 | do { | 992 | skb_queue_walk(&tx->skbs, skb) { |
977 | tx->sta->tx_fragments++; | 993 | tx->sta->tx_fragments++; |
978 | tx->sta->tx_bytes += skb->len; | 994 | tx->sta->tx_bytes += skb->len; |
979 | } while ((skb = skb->next)); | 995 | } |
980 | 996 | ||
981 | return TX_CONTINUE; | 997 | return TX_CONTINUE; |
982 | } | 998 | } |
@@ -1015,21 +1031,25 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | |||
1015 | static ieee80211_tx_result debug_noinline | 1031 | static ieee80211_tx_result debug_noinline |
1016 | ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) | 1032 | ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) |
1017 | { | 1033 | { |
1018 | struct sk_buff *skb = tx->skb; | 1034 | struct sk_buff *skb; |
1019 | struct ieee80211_hdr *hdr; | 1035 | struct ieee80211_hdr *hdr; |
1020 | int next_len; | 1036 | int next_len; |
1021 | bool group_addr; | 1037 | bool group_addr; |
1022 | 1038 | ||
1023 | do { | 1039 | skb_queue_walk(&tx->skbs, skb) { |
1024 | hdr = (void *) skb->data; | 1040 | hdr = (void *) skb->data; |
1025 | if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) | 1041 | if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) |
1026 | break; /* must not overwrite AID */ | 1042 | break; /* must not overwrite AID */ |
1027 | next_len = skb->next ? skb->next->len : 0; | 1043 | if (!skb_queue_is_last(&tx->skbs, skb)) { |
1044 | struct sk_buff *next = skb_queue_next(&tx->skbs, skb); | ||
1045 | next_len = next->len; | ||
1046 | } else | ||
1047 | next_len = 0; | ||
1028 | group_addr = is_multicast_ether_addr(hdr->addr1); | 1048 | group_addr = is_multicast_ether_addr(hdr->addr1); |
1029 | 1049 | ||
1030 | hdr->duration_id = | 1050 | hdr->duration_id = |
1031 | ieee80211_duration(tx, group_addr, next_len); | 1051 | ieee80211_duration(tx, skb, group_addr, next_len); |
1032 | } while ((skb = skb->next)); | 1052 | } |
1033 | 1053 | ||
1034 | return TX_CONTINUE; | 1054 | return TX_CONTINUE; |
1035 | } | 1055 | } |
@@ -1108,6 +1128,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1108 | tx->local = local; | 1128 | tx->local = local; |
1109 | tx->sdata = sdata; | 1129 | tx->sdata = sdata; |
1110 | tx->channel = local->hw.conf.channel; | 1130 | tx->channel = local->hw.conf.channel; |
1131 | __skb_queue_head_init(&tx->skbs); | ||
1111 | 1132 | ||
1112 | /* | 1133 | /* |
1113 | * If this flag is set to true anywhere, and we get here, | 1134 | * If this flag is set to true anywhere, and we get here, |
@@ -1180,22 +1201,18 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1180 | return TX_CONTINUE; | 1201 | return TX_CONTINUE; |
1181 | } | 1202 | } |
1182 | 1203 | ||
1183 | /* | 1204 | static bool ieee80211_tx_frags(struct ieee80211_local *local, |
1184 | * Returns false if the frame couldn't be transmitted but was queued instead. | 1205 | struct ieee80211_vif *vif, |
1185 | */ | 1206 | struct ieee80211_sta *sta, |
1186 | static bool __ieee80211_tx(struct ieee80211_local *local, struct sk_buff **skbp, | 1207 | struct sk_buff_head *skbs, |
1187 | struct sta_info *sta, bool txpending) | 1208 | bool txpending) |
1188 | { | 1209 | { |
1189 | struct sk_buff *skb = *skbp, *next; | 1210 | struct sk_buff *skb, *tmp; |
1190 | struct ieee80211_tx_info *info; | 1211 | struct ieee80211_tx_info *info; |
1191 | struct ieee80211_sub_if_data *sdata; | ||
1192 | unsigned long flags; | 1212 | unsigned long flags; |
1193 | int len; | ||
1194 | bool fragm = false; | ||
1195 | 1213 | ||
1196 | while (skb) { | 1214 | skb_queue_walk_safe(skbs, skb, tmp) { |
1197 | int q = skb_get_queue_mapping(skb); | 1215 | int q = skb_get_queue_mapping(skb); |
1198 | __le16 fc; | ||
1199 | 1216 | ||
1200 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 1217 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
1201 | if (local->queue_stop_reasons[q] || | 1218 | if (local->queue_stop_reasons[q] || |
@@ -1205,24 +1222,10 @@ static bool __ieee80211_tx(struct ieee80211_local *local, struct sk_buff **skbp, | |||
1205 | * transmission from the tx-pending tasklet when the | 1222 | * transmission from the tx-pending tasklet when the |
1206 | * queue is woken again. | 1223 | * queue is woken again. |
1207 | */ | 1224 | */ |
1208 | 1225 | if (txpending) | |
1209 | do { | 1226 | skb_queue_splice(skbs, &local->pending[q]); |
1210 | next = skb->next; | 1227 | else |
1211 | skb->next = NULL; | 1228 | skb_queue_splice_tail(skbs, &local->pending[q]); |
1212 | /* | ||
1213 | * NB: If txpending is true, next must already | ||
1214 | * be NULL since we must've gone through this | ||
1215 | * loop before already; therefore we can just | ||
1216 | * queue the frame to the head without worrying | ||
1217 | * about reordering of fragments. | ||
1218 | */ | ||
1219 | if (unlikely(txpending)) | ||
1220 | __skb_queue_head(&local->pending[q], | ||
1221 | skb); | ||
1222 | else | ||
1223 | __skb_queue_tail(&local->pending[q], | ||
1224 | skb); | ||
1225 | } while ((skb = next)); | ||
1226 | 1229 | ||
1227 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, | 1230 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, |
1228 | flags); | 1231 | flags); |
@@ -1231,47 +1234,72 @@ static bool __ieee80211_tx(struct ieee80211_local *local, struct sk_buff **skbp, | |||
1231 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 1234 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
1232 | 1235 | ||
1233 | info = IEEE80211_SKB_CB(skb); | 1236 | info = IEEE80211_SKB_CB(skb); |
1237 | info->control.vif = vif; | ||
1238 | info->control.sta = sta; | ||
1234 | 1239 | ||
1235 | if (fragm) | 1240 | __skb_unlink(skb, skbs); |
1236 | info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | | 1241 | drv_tx(local, skb); |
1237 | IEEE80211_TX_CTL_FIRST_FRAGMENT); | 1242 | } |
1238 | |||
1239 | next = skb->next; | ||
1240 | len = skb->len; | ||
1241 | 1243 | ||
1242 | if (next) | 1244 | return true; |
1243 | info->flags |= IEEE80211_TX_CTL_MORE_FRAMES; | 1245 | } |
1244 | 1246 | ||
1245 | sdata = vif_to_sdata(info->control.vif); | 1247 | /* |
1248 | * Returns false if the frame couldn't be transmitted but was queued instead. | ||
1249 | */ | ||
1250 | static bool __ieee80211_tx(struct ieee80211_local *local, | ||
1251 | struct sk_buff_head *skbs, int led_len, | ||
1252 | struct sta_info *sta, bool txpending) | ||
1253 | { | ||
1254 | struct ieee80211_tx_info *info; | ||
1255 | struct ieee80211_sub_if_data *sdata; | ||
1256 | struct ieee80211_vif *vif; | ||
1257 | struct ieee80211_sta *pubsta; | ||
1258 | struct sk_buff *skb; | ||
1259 | bool result = true; | ||
1260 | __le16 fc; | ||
1246 | 1261 | ||
1247 | switch (sdata->vif.type) { | 1262 | if (WARN_ON(skb_queue_empty(skbs))) |
1248 | case NL80211_IFTYPE_MONITOR: | 1263 | return true; |
1249 | info->control.vif = NULL; | ||
1250 | break; | ||
1251 | case NL80211_IFTYPE_AP_VLAN: | ||
1252 | info->control.vif = &container_of(sdata->bss, | ||
1253 | struct ieee80211_sub_if_data, u.ap)->vif; | ||
1254 | break; | ||
1255 | default: | ||
1256 | /* keep */ | ||
1257 | break; | ||
1258 | } | ||
1259 | 1264 | ||
1260 | if (sta && sta->uploaded) | 1265 | skb = skb_peek(skbs); |
1261 | info->control.sta = &sta->sta; | 1266 | fc = ((struct ieee80211_hdr *)skb->data)->frame_control; |
1262 | else | 1267 | info = IEEE80211_SKB_CB(skb); |
1263 | info->control.sta = NULL; | 1268 | sdata = vif_to_sdata(info->control.vif); |
1269 | if (sta && !sta->uploaded) | ||
1270 | sta = NULL; | ||
1264 | 1271 | ||
1265 | fc = ((struct ieee80211_hdr *)skb->data)->frame_control; | 1272 | if (sta) |
1266 | drv_tx(local, skb); | 1273 | pubsta = &sta->sta; |
1274 | else | ||
1275 | pubsta = NULL; | ||
1267 | 1276 | ||
1268 | ieee80211_tpt_led_trig_tx(local, fc, len); | 1277 | switch (sdata->vif.type) { |
1269 | *skbp = skb = next; | 1278 | case NL80211_IFTYPE_MONITOR: |
1270 | ieee80211_led_tx(local, 1); | 1279 | sdata = NULL; |
1271 | fragm = true; | 1280 | vif = NULL; |
1281 | break; | ||
1282 | case NL80211_IFTYPE_AP_VLAN: | ||
1283 | sdata = container_of(sdata->bss, | ||
1284 | struct ieee80211_sub_if_data, u.ap); | ||
1285 | /* fall through */ | ||
1286 | default: | ||
1287 | vif = &sdata->vif; | ||
1288 | break; | ||
1272 | } | 1289 | } |
1273 | 1290 | ||
1274 | return true; | 1291 | if (local->ops->tx_frags) |
1292 | drv_tx_frags(local, vif, pubsta, skbs); | ||
1293 | else | ||
1294 | result = ieee80211_tx_frags(local, vif, pubsta, skbs, | ||
1295 | txpending); | ||
1296 | |||
1297 | ieee80211_tpt_led_trig_tx(local, fc, led_len); | ||
1298 | ieee80211_led_tx(local, 1); | ||
1299 | |||
1300 | WARN_ON(!skb_queue_empty(skbs)); | ||
1301 | |||
1302 | return result; | ||
1275 | } | 1303 | } |
1276 | 1304 | ||
1277 | /* | 1305 | /* |
@@ -1280,8 +1308,7 @@ static bool __ieee80211_tx(struct ieee80211_local *local, struct sk_buff **skbp, | |||
1280 | */ | 1308 | */ |
1281 | static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | 1309 | static int invoke_tx_handlers(struct ieee80211_tx_data *tx) |
1282 | { | 1310 | { |
1283 | struct sk_buff *skb = tx->skb; | 1311 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); |
1284 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
1285 | ieee80211_tx_result res = TX_DROP; | 1312 | ieee80211_tx_result res = TX_DROP; |
1286 | 1313 | ||
1287 | #define CALL_TXH(txh) \ | 1314 | #define CALL_TXH(txh) \ |
@@ -1315,13 +1342,10 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1315 | txh_done: | 1342 | txh_done: |
1316 | if (unlikely(res == TX_DROP)) { | 1343 | if (unlikely(res == TX_DROP)) { |
1317 | I802_DEBUG_INC(tx->local->tx_handlers_drop); | 1344 | I802_DEBUG_INC(tx->local->tx_handlers_drop); |
1318 | while (skb) { | 1345 | if (tx->skb) |
1319 | struct sk_buff *next; | 1346 | dev_kfree_skb(tx->skb); |
1320 | 1347 | else | |
1321 | next = skb->next; | 1348 | __skb_queue_purge(&tx->skbs); |
1322 | dev_kfree_skb(skb); | ||
1323 | skb = next; | ||
1324 | } | ||
1325 | return -1; | 1349 | return -1; |
1326 | } else if (unlikely(res == TX_QUEUED)) { | 1350 | } else if (unlikely(res == TX_QUEUED)) { |
1327 | I802_DEBUG_INC(tx->local->tx_handlers_queued); | 1351 | I802_DEBUG_INC(tx->local->tx_handlers_queued); |
@@ -1342,6 +1366,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | |||
1342 | ieee80211_tx_result res_prepare; | 1366 | ieee80211_tx_result res_prepare; |
1343 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1367 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1344 | bool result = true; | 1368 | bool result = true; |
1369 | int led_len; | ||
1345 | 1370 | ||
1346 | if (unlikely(skb->len < 10)) { | 1371 | if (unlikely(skb->len < 10)) { |
1347 | dev_kfree_skb(skb); | 1372 | dev_kfree_skb(skb); |
@@ -1351,6 +1376,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | |||
1351 | rcu_read_lock(); | 1376 | rcu_read_lock(); |
1352 | 1377 | ||
1353 | /* initialises tx */ | 1378 | /* initialises tx */ |
1379 | led_len = skb->len; | ||
1354 | res_prepare = ieee80211_tx_prepare(sdata, &tx, skb); | 1380 | res_prepare = ieee80211_tx_prepare(sdata, &tx, skb); |
1355 | 1381 | ||
1356 | if (unlikely(res_prepare == TX_DROP)) { | 1382 | if (unlikely(res_prepare == TX_DROP)) { |
@@ -1364,7 +1390,8 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | |||
1364 | info->band = tx.channel->band; | 1390 | info->band = tx.channel->band; |
1365 | 1391 | ||
1366 | if (!invoke_tx_handlers(&tx)) | 1392 | if (!invoke_tx_handlers(&tx)) |
1367 | result = __ieee80211_tx(local, &tx.skb, tx.sta, txpending); | 1393 | result = __ieee80211_tx(local, &tx.skbs, led_len, |
1394 | tx.sta, txpending); | ||
1368 | out: | 1395 | out: |
1369 | rcu_read_unlock(); | 1396 | rcu_read_unlock(); |
1370 | return result; | 1397 | return result; |
@@ -2112,10 +2139,15 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, | |||
2112 | if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { | 2139 | if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { |
2113 | result = ieee80211_tx(sdata, skb, true); | 2140 | result = ieee80211_tx(sdata, skb, true); |
2114 | } else { | 2141 | } else { |
2142 | struct sk_buff_head skbs; | ||
2143 | |||
2144 | __skb_queue_head_init(&skbs); | ||
2145 | __skb_queue_tail(&skbs, skb); | ||
2146 | |||
2115 | hdr = (struct ieee80211_hdr *)skb->data; | 2147 | hdr = (struct ieee80211_hdr *)skb->data; |
2116 | sta = sta_info_get(sdata, hdr->addr1); | 2148 | sta = sta_info_get(sdata, hdr->addr1); |
2117 | 2149 | ||
2118 | result = __ieee80211_tx(local, &skb, sta, true); | 2150 | result = __ieee80211_tx(local, &skbs, skb->len, sta, true); |
2119 | } | 2151 | } |
2120 | 2152 | ||
2121 | return result; | 2153 | return result; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 3a00814699f0..3b9b492e9403 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/etherdevice.h> | 20 | #include <linux/etherdevice.h> |
21 | #include <linux/if_arp.h> | 21 | #include <linux/if_arp.h> |
22 | #include <linux/bitmap.h> | 22 | #include <linux/bitmap.h> |
23 | #include <linux/crc32.h> | ||
23 | #include <net/net_namespace.h> | 24 | #include <net/net_namespace.h> |
24 | #include <net/cfg80211.h> | 25 | #include <net/cfg80211.h> |
25 | #include <net/rtnetlink.h> | 26 | #include <net/rtnetlink.h> |
@@ -96,13 +97,13 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, | |||
96 | 97 | ||
97 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) | 98 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) |
98 | { | 99 | { |
99 | struct sk_buff *skb = tx->skb; | 100 | struct sk_buff *skb; |
100 | struct ieee80211_hdr *hdr; | 101 | struct ieee80211_hdr *hdr; |
101 | 102 | ||
102 | do { | 103 | skb_queue_walk(&tx->skbs, skb) { |
103 | hdr = (struct ieee80211_hdr *) skb->data; | 104 | hdr = (struct ieee80211_hdr *) skb->data; |
104 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | 105 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); |
105 | } while ((skb = skb->next)); | 106 | } |
106 | } | 107 | } |
107 | 108 | ||
108 | int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, | 109 | int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, |
@@ -564,6 +565,172 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, | |||
564 | } | 565 | } |
565 | EXPORT_SYMBOL(ieee80211_queue_delayed_work); | 566 | EXPORT_SYMBOL(ieee80211_queue_delayed_work); |
566 | 567 | ||
568 | u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | ||
569 | struct ieee802_11_elems *elems, | ||
570 | u64 filter, u32 crc) | ||
571 | { | ||
572 | size_t left = len; | ||
573 | u8 *pos = start; | ||
574 | bool calc_crc = filter != 0; | ||
575 | |||
576 | memset(elems, 0, sizeof(*elems)); | ||
577 | elems->ie_start = start; | ||
578 | elems->total_len = len; | ||
579 | |||
580 | while (left >= 2) { | ||
581 | u8 id, elen; | ||
582 | |||
583 | id = *pos++; | ||
584 | elen = *pos++; | ||
585 | left -= 2; | ||
586 | |||
587 | if (elen > left) | ||
588 | break; | ||
589 | |||
590 | if (calc_crc && id < 64 && (filter & (1ULL << id))) | ||
591 | crc = crc32_be(crc, pos - 2, elen + 2); | ||
592 | |||
593 | switch (id) { | ||
594 | case WLAN_EID_SSID: | ||
595 | elems->ssid = pos; | ||
596 | elems->ssid_len = elen; | ||
597 | break; | ||
598 | case WLAN_EID_SUPP_RATES: | ||
599 | elems->supp_rates = pos; | ||
600 | elems->supp_rates_len = elen; | ||
601 | break; | ||
602 | case WLAN_EID_FH_PARAMS: | ||
603 | elems->fh_params = pos; | ||
604 | elems->fh_params_len = elen; | ||
605 | break; | ||
606 | case WLAN_EID_DS_PARAMS: | ||
607 | elems->ds_params = pos; | ||
608 | elems->ds_params_len = elen; | ||
609 | break; | ||
610 | case WLAN_EID_CF_PARAMS: | ||
611 | elems->cf_params = pos; | ||
612 | elems->cf_params_len = elen; | ||
613 | break; | ||
614 | case WLAN_EID_TIM: | ||
615 | if (elen >= sizeof(struct ieee80211_tim_ie)) { | ||
616 | elems->tim = (void *)pos; | ||
617 | elems->tim_len = elen; | ||
618 | } | ||
619 | break; | ||
620 | case WLAN_EID_IBSS_PARAMS: | ||
621 | elems->ibss_params = pos; | ||
622 | elems->ibss_params_len = elen; | ||
623 | break; | ||
624 | case WLAN_EID_CHALLENGE: | ||
625 | elems->challenge = pos; | ||
626 | elems->challenge_len = elen; | ||
627 | break; | ||
628 | case WLAN_EID_VENDOR_SPECIFIC: | ||
629 | if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && | ||
630 | pos[2] == 0xf2) { | ||
631 | /* Microsoft OUI (00:50:F2) */ | ||
632 | |||
633 | if (calc_crc) | ||
634 | crc = crc32_be(crc, pos - 2, elen + 2); | ||
635 | |||
636 | if (pos[3] == 1) { | ||
637 | /* OUI Type 1 - WPA IE */ | ||
638 | elems->wpa = pos; | ||
639 | elems->wpa_len = elen; | ||
640 | } else if (elen >= 5 && pos[3] == 2) { | ||
641 | /* OUI Type 2 - WMM IE */ | ||
642 | if (pos[4] == 0) { | ||
643 | elems->wmm_info = pos; | ||
644 | elems->wmm_info_len = elen; | ||
645 | } else if (pos[4] == 1) { | ||
646 | elems->wmm_param = pos; | ||
647 | elems->wmm_param_len = elen; | ||
648 | } | ||
649 | } | ||
650 | } | ||
651 | break; | ||
652 | case WLAN_EID_RSN: | ||
653 | elems->rsn = pos; | ||
654 | elems->rsn_len = elen; | ||
655 | break; | ||
656 | case WLAN_EID_ERP_INFO: | ||
657 | elems->erp_info = pos; | ||
658 | elems->erp_info_len = elen; | ||
659 | break; | ||
660 | case WLAN_EID_EXT_SUPP_RATES: | ||
661 | elems->ext_supp_rates = pos; | ||
662 | elems->ext_supp_rates_len = elen; | ||
663 | break; | ||
664 | case WLAN_EID_HT_CAPABILITY: | ||
665 | if (elen >= sizeof(struct ieee80211_ht_cap)) | ||
666 | elems->ht_cap_elem = (void *)pos; | ||
667 | break; | ||
668 | case WLAN_EID_HT_INFORMATION: | ||
669 | if (elen >= sizeof(struct ieee80211_ht_info)) | ||
670 | elems->ht_info_elem = (void *)pos; | ||
671 | break; | ||
672 | case WLAN_EID_MESH_ID: | ||
673 | elems->mesh_id = pos; | ||
674 | elems->mesh_id_len = elen; | ||
675 | break; | ||
676 | case WLAN_EID_MESH_CONFIG: | ||
677 | if (elen >= sizeof(struct ieee80211_meshconf_ie)) | ||
678 | elems->mesh_config = (void *)pos; | ||
679 | break; | ||
680 | case WLAN_EID_PEER_MGMT: | ||
681 | elems->peering = pos; | ||
682 | elems->peering_len = elen; | ||
683 | break; | ||
684 | case WLAN_EID_PREQ: | ||
685 | elems->preq = pos; | ||
686 | elems->preq_len = elen; | ||
687 | break; | ||
688 | case WLAN_EID_PREP: | ||
689 | elems->prep = pos; | ||
690 | elems->prep_len = elen; | ||
691 | break; | ||
692 | case WLAN_EID_PERR: | ||
693 | elems->perr = pos; | ||
694 | elems->perr_len = elen; | ||
695 | break; | ||
696 | case WLAN_EID_RANN: | ||
697 | if (elen >= sizeof(struct ieee80211_rann_ie)) | ||
698 | elems->rann = (void *)pos; | ||
699 | break; | ||
700 | case WLAN_EID_CHANNEL_SWITCH: | ||
701 | elems->ch_switch_elem = pos; | ||
702 | elems->ch_switch_elem_len = elen; | ||
703 | break; | ||
704 | case WLAN_EID_QUIET: | ||
705 | if (!elems->quiet_elem) { | ||
706 | elems->quiet_elem = pos; | ||
707 | elems->quiet_elem_len = elen; | ||
708 | } | ||
709 | elems->num_of_quiet_elem++; | ||
710 | break; | ||
711 | case WLAN_EID_COUNTRY: | ||
712 | elems->country_elem = pos; | ||
713 | elems->country_elem_len = elen; | ||
714 | break; | ||
715 | case WLAN_EID_PWR_CONSTRAINT: | ||
716 | elems->pwr_constr_elem = pos; | ||
717 | elems->pwr_constr_elem_len = elen; | ||
718 | break; | ||
719 | case WLAN_EID_TIMEOUT_INTERVAL: | ||
720 | elems->timeout_int = pos; | ||
721 | elems->timeout_int_len = elen; | ||
722 | break; | ||
723 | default: | ||
724 | break; | ||
725 | } | ||
726 | |||
727 | left -= elen; | ||
728 | pos += elen; | ||
729 | } | ||
730 | |||
731 | return crc; | ||
732 | } | ||
733 | |||
567 | void ieee802_11_parse_elems(u8 *start, size_t len, | 734 | void ieee802_11_parse_elems(u8 *start, size_t len, |
568 | struct ieee802_11_elems *elems) | 735 | struct ieee802_11_elems *elems) |
569 | { | 736 | { |
@@ -813,7 +980,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
813 | } | 980 | } |
814 | 981 | ||
815 | if (sband->ht_cap.ht_supported) | 982 | if (sband->ht_cap.ht_supported) |
816 | pos = ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap); | 983 | pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, |
984 | sband->ht_cap.cap); | ||
817 | 985 | ||
818 | /* | 986 | /* |
819 | * If adding more here, adjust code in main.c | 987 | * If adding more here, adjust code in main.c |
@@ -1356,7 +1524,7 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif) | |||
1356 | } | 1524 | } |
1357 | EXPORT_SYMBOL(ieee80211_disable_rssi_reports); | 1525 | EXPORT_SYMBOL(ieee80211_disable_rssi_reports); |
1358 | 1526 | ||
1359 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband, | 1527 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
1360 | u16 cap) | 1528 | u16 cap) |
1361 | { | 1529 | { |
1362 | __le16 tmp; | 1530 | __le16 tmp; |
@@ -1371,13 +1539,13 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband, | |||
1371 | pos += sizeof(u16); | 1539 | pos += sizeof(u16); |
1372 | 1540 | ||
1373 | /* AMPDU parameters */ | 1541 | /* AMPDU parameters */ |
1374 | *pos++ = sband->ht_cap.ampdu_factor | | 1542 | *pos++ = ht_cap->ampdu_factor | |
1375 | (sband->ht_cap.ampdu_density << | 1543 | (ht_cap->ampdu_density << |
1376 | IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); | 1544 | IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); |
1377 | 1545 | ||
1378 | /* MCS set */ | 1546 | /* MCS set */ |
1379 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | 1547 | memcpy(pos, &ht_cap->mcs, sizeof(ht_cap->mcs)); |
1380 | pos += sizeof(sband->ht_cap.mcs); | 1548 | pos += sizeof(ht_cap->mcs); |
1381 | 1549 | ||
1382 | /* extended capabilities */ | 1550 | /* extended capabilities */ |
1383 | pos += sizeof(__le16); | 1551 | pos += sizeof(__le16); |
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index a1c6bfd55f0f..68ad351479df 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
@@ -330,13 +330,12 @@ ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx) | |||
330 | 330 | ||
331 | ieee80211_tx_set_protected(tx); | 331 | ieee80211_tx_set_protected(tx); |
332 | 332 | ||
333 | skb = tx->skb; | 333 | skb_queue_walk(&tx->skbs, skb) { |
334 | do { | ||
335 | if (wep_encrypt_skb(tx, skb) < 0) { | 334 | if (wep_encrypt_skb(tx, skb) < 0) { |
336 | I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); | 335 | I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); |
337 | return TX_DROP; | 336 | return TX_DROP; |
338 | } | 337 | } |
339 | } while ((skb = skb->next)); | 338 | } |
340 | 339 | ||
341 | return TX_CONTINUE; | 340 | return TX_CONTINUE; |
342 | } | 341 | } |
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 3dd5a89e99a7..6884a2d986dc 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
@@ -94,7 +94,8 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, | |||
94 | 94 | ||
95 | /* frame sending functions */ | 95 | /* frame sending functions */ |
96 | 96 | ||
97 | static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie, | 97 | static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, |
98 | struct sk_buff *skb, const u8 *ht_info_ie, | ||
98 | struct ieee80211_supported_band *sband, | 99 | struct ieee80211_supported_band *sband, |
99 | struct ieee80211_channel *channel, | 100 | struct ieee80211_channel *channel, |
100 | enum ieee80211_smps_mode smps) | 101 | enum ieee80211_smps_mode smps) |
@@ -102,7 +103,10 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie, | |||
102 | struct ieee80211_ht_info *ht_info; | 103 | struct ieee80211_ht_info *ht_info; |
103 | u8 *pos; | 104 | u8 *pos; |
104 | u32 flags = channel->flags; | 105 | u32 flags = channel->flags; |
105 | u16 cap = sband->ht_cap.cap; | 106 | u16 cap; |
107 | struct ieee80211_sta_ht_cap ht_cap; | ||
108 | |||
109 | BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap)); | ||
106 | 110 | ||
107 | if (!sband->ht_cap.ht_supported) | 111 | if (!sband->ht_cap.ht_supported) |
108 | return; | 112 | return; |
@@ -113,9 +117,13 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie, | |||
113 | if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info)) | 117 | if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info)) |
114 | return; | 118 | return; |
115 | 119 | ||
120 | memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); | ||
121 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); | ||
122 | |||
116 | ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2); | 123 | ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2); |
117 | 124 | ||
118 | /* determine capability flags */ | 125 | /* determine capability flags */ |
126 | cap = ht_cap.cap; | ||
119 | 127 | ||
120 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 128 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { |
121 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | 129 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: |
@@ -154,7 +162,7 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie, | |||
154 | 162 | ||
155 | /* reserve and fill IE */ | 163 | /* reserve and fill IE */ |
156 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); | 164 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); |
157 | ieee80211_ie_build_ht_cap(pos, sband, cap); | 165 | ieee80211_ie_build_ht_cap(pos, &ht_cap, cap); |
158 | } | 166 | } |
159 | 167 | ||
160 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | 168 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, |
@@ -329,7 +337,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
329 | 337 | ||
330 | if (wk->assoc.use_11n && wk->assoc.wmm_used && | 338 | if (wk->assoc.use_11n && wk->assoc.wmm_used && |
331 | local->hw.queues >= 4) | 339 | local->hw.queues >= 4) |
332 | ieee80211_add_ht_ie(skb, wk->assoc.ht_information_ie, | 340 | ieee80211_add_ht_ie(sdata, skb, wk->assoc.ht_information_ie, |
333 | sband, wk->chan, wk->assoc.smps); | 341 | sband, wk->chan, wk->assoc.smps); |
334 | 342 | ||
335 | /* if present, add any custom non-vendor IEs that go after HT */ | 343 | /* if present, add any custom non-vendor IEs that go after HT */ |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 106e15a4649f..93aab0715e8a 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -223,14 +223,14 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
223 | ieee80211_tx_result | 223 | ieee80211_tx_result |
224 | ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) | 224 | ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) |
225 | { | 225 | { |
226 | struct sk_buff *skb = tx->skb; | 226 | struct sk_buff *skb; |
227 | 227 | ||
228 | ieee80211_tx_set_protected(tx); | 228 | ieee80211_tx_set_protected(tx); |
229 | 229 | ||
230 | do { | 230 | skb_queue_walk(&tx->skbs, skb) { |
231 | if (tkip_encrypt_skb(tx, skb) < 0) | 231 | if (tkip_encrypt_skb(tx, skb) < 0) |
232 | return TX_DROP; | 232 | return TX_DROP; |
233 | } while ((skb = skb->next)); | 233 | } |
234 | 234 | ||
235 | return TX_CONTINUE; | 235 | return TX_CONTINUE; |
236 | } | 236 | } |
@@ -449,14 +449,14 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
449 | ieee80211_tx_result | 449 | ieee80211_tx_result |
450 | ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) | 450 | ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) |
451 | { | 451 | { |
452 | struct sk_buff *skb = tx->skb; | 452 | struct sk_buff *skb; |
453 | 453 | ||
454 | ieee80211_tx_set_protected(tx); | 454 | ieee80211_tx_set_protected(tx); |
455 | 455 | ||
456 | do { | 456 | skb_queue_walk(&tx->skbs, skb) { |
457 | if (ccmp_encrypt_skb(tx, skb) < 0) | 457 | if (ccmp_encrypt_skb(tx, skb) < 0) |
458 | return TX_DROP; | 458 | return TX_DROP; |
459 | } while ((skb = skb->next)); | 459 | } |
460 | 460 | ||
461 | return TX_CONTINUE; | 461 | return TX_CONTINUE; |
462 | } | 462 | } |
@@ -554,15 +554,22 @@ static inline void bip_ipn_swap(u8 *d, const u8 *s) | |||
554 | ieee80211_tx_result | 554 | ieee80211_tx_result |
555 | ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx) | 555 | ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx) |
556 | { | 556 | { |
557 | struct sk_buff *skb = tx->skb; | 557 | struct sk_buff *skb; |
558 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 558 | struct ieee80211_tx_info *info; |
559 | struct ieee80211_key *key = tx->key; | 559 | struct ieee80211_key *key = tx->key; |
560 | struct ieee80211_mmie *mmie; | 560 | struct ieee80211_mmie *mmie; |
561 | u8 aad[20]; | 561 | u8 aad[20]; |
562 | u64 pn64; | 562 | u64 pn64; |
563 | 563 | ||
564 | if (WARN_ON(skb_queue_len(&tx->skbs) != 1)) | ||
565 | return TX_DROP; | ||
566 | |||
567 | skb = skb_peek(&tx->skbs); | ||
568 | |||
569 | info = IEEE80211_SKB_CB(skb); | ||
570 | |||
564 | if (info->control.hw_key) | 571 | if (info->control.hw_key) |
565 | return 0; | 572 | return TX_CONTINUE; |
566 | 573 | ||
567 | if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) | 574 | if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) |
568 | return TX_DROP; | 575 | return TX_DROP; |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 1c7d4df5418c..fb08c28fc90a 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -341,13 +341,17 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
341 | const u8 *bssid, const u8 *prev_bssid, | 341 | const u8 *bssid, const u8 *prev_bssid, |
342 | const u8 *ssid, int ssid_len, | 342 | const u8 *ssid, int ssid_len, |
343 | const u8 *ie, int ie_len, bool use_mfp, | 343 | const u8 *ie, int ie_len, bool use_mfp, |
344 | struct cfg80211_crypto_settings *crypt); | 344 | struct cfg80211_crypto_settings *crypt, |
345 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
346 | struct ieee80211_ht_cap *ht_capa_mask); | ||
345 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 347 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
346 | struct net_device *dev, struct ieee80211_channel *chan, | 348 | struct net_device *dev, struct ieee80211_channel *chan, |
347 | const u8 *bssid, const u8 *prev_bssid, | 349 | const u8 *bssid, const u8 *prev_bssid, |
348 | const u8 *ssid, int ssid_len, | 350 | const u8 *ssid, int ssid_len, |
349 | const u8 *ie, int ie_len, bool use_mfp, | 351 | const u8 *ie, int ie_len, bool use_mfp, |
350 | struct cfg80211_crypto_settings *crypt); | 352 | struct cfg80211_crypto_settings *crypt, |
353 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
354 | struct ieee80211_ht_cap *ht_capa_mask); | ||
351 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | 355 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, |
352 | struct net_device *dev, const u8 *bssid, | 356 | struct net_device *dev, const u8 *bssid, |
353 | const u8 *ie, int ie_len, u16 reason, | 357 | const u8 *ie, int ie_len, u16 reason, |
@@ -379,6 +383,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
379 | bool channel_type_valid, unsigned int wait, | 383 | bool channel_type_valid, unsigned int wait, |
380 | const u8 *buf, size_t len, bool no_cck, | 384 | const u8 *buf, size_t len, bool no_cck, |
381 | bool dont_wait_for_ack, u64 *cookie); | 385 | bool dont_wait_for_ack, u64 *cookie); |
386 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | ||
387 | const struct ieee80211_ht_cap *ht_capa_mask); | ||
382 | 388 | ||
383 | /* SME */ | 389 | /* SME */ |
384 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 390 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 6c1bafd508c8..438dfc105b4a 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -501,13 +501,32 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
501 | return err; | 501 | return err; |
502 | } | 502 | } |
503 | 503 | ||
504 | /* Do a logical ht_capa &= ht_capa_mask. */ | ||
505 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | ||
506 | const struct ieee80211_ht_cap *ht_capa_mask) | ||
507 | { | ||
508 | int i; | ||
509 | u8 *p1, *p2; | ||
510 | if (!ht_capa_mask) { | ||
511 | memset(ht_capa, 0, sizeof(*ht_capa)); | ||
512 | return; | ||
513 | } | ||
514 | |||
515 | p1 = (u8*)(ht_capa); | ||
516 | p2 = (u8*)(ht_capa_mask); | ||
517 | for (i = 0; i<sizeof(*ht_capa); i++) | ||
518 | p1[i] &= p2[i]; | ||
519 | } | ||
520 | |||
504 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 521 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
505 | struct net_device *dev, | 522 | struct net_device *dev, |
506 | struct ieee80211_channel *chan, | 523 | struct ieee80211_channel *chan, |
507 | const u8 *bssid, const u8 *prev_bssid, | 524 | const u8 *bssid, const u8 *prev_bssid, |
508 | const u8 *ssid, int ssid_len, | 525 | const u8 *ssid, int ssid_len, |
509 | const u8 *ie, int ie_len, bool use_mfp, | 526 | const u8 *ie, int ie_len, bool use_mfp, |
510 | struct cfg80211_crypto_settings *crypt) | 527 | struct cfg80211_crypto_settings *crypt, |
528 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
529 | struct ieee80211_ht_cap *ht_capa_mask) | ||
511 | { | 530 | { |
512 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 531 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
513 | struct cfg80211_assoc_request req; | 532 | struct cfg80211_assoc_request req; |
@@ -537,6 +556,15 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
537 | memcpy(&req.crypto, crypt, sizeof(req.crypto)); | 556 | memcpy(&req.crypto, crypt, sizeof(req.crypto)); |
538 | req.use_mfp = use_mfp; | 557 | req.use_mfp = use_mfp; |
539 | req.prev_bssid = prev_bssid; | 558 | req.prev_bssid = prev_bssid; |
559 | req.flags = assoc_flags; | ||
560 | if (ht_capa) | ||
561 | memcpy(&req.ht_capa, ht_capa, sizeof(req.ht_capa)); | ||
562 | if (ht_capa_mask) | ||
563 | memcpy(&req.ht_capa_mask, ht_capa_mask, | ||
564 | sizeof(req.ht_capa_mask)); | ||
565 | cfg80211_oper_and_ht_capa(&req.ht_capa_mask, | ||
566 | rdev->wiphy.ht_capa_mod_mask); | ||
567 | |||
540 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, | 568 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, |
541 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | 569 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); |
542 | if (!req.bss) { | 570 | if (!req.bss) { |
@@ -574,14 +602,17 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
574 | const u8 *bssid, const u8 *prev_bssid, | 602 | const u8 *bssid, const u8 *prev_bssid, |
575 | const u8 *ssid, int ssid_len, | 603 | const u8 *ssid, int ssid_len, |
576 | const u8 *ie, int ie_len, bool use_mfp, | 604 | const u8 *ie, int ie_len, bool use_mfp, |
577 | struct cfg80211_crypto_settings *crypt) | 605 | struct cfg80211_crypto_settings *crypt, |
606 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
607 | struct ieee80211_ht_cap *ht_capa_mask) | ||
578 | { | 608 | { |
579 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 609 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
580 | int err; | 610 | int err; |
581 | 611 | ||
582 | wdev_lock(wdev); | 612 | wdev_lock(wdev); |
583 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 613 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, |
584 | ssid, ssid_len, ie, ie_len, use_mfp, crypt); | 614 | ssid, ssid_len, ie, ie_len, use_mfp, crypt, |
615 | assoc_flags, ht_capa, ht_capa_mask); | ||
585 | wdev_unlock(wdev); | 616 | wdev_unlock(wdev); |
586 | 617 | ||
587 | return err; | 618 | return err; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 6bc7c4b32fa5..a1cabde7cb5f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -199,6 +199,11 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
199 | [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG }, | 199 | [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG }, |
200 | [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY, | 200 | [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY, |
201 | .len = IEEE80211_MAX_DATA_LEN }, | 201 | .len = IEEE80211_MAX_DATA_LEN }, |
202 | [NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 }, | ||
203 | [NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG }, | ||
204 | [NL80211_ATTR_HT_CAPABILITY_MASK] = { | ||
205 | .len = NL80211_HT_CAPABILITY_LEN | ||
206 | }, | ||
202 | }; | 207 | }; |
203 | 208 | ||
204 | /* policy for the key attributes */ | 209 | /* policy for the key attributes */ |
@@ -881,7 +886,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
881 | CMD(set_pmksa, SET_PMKSA); | 886 | CMD(set_pmksa, SET_PMKSA); |
882 | CMD(del_pmksa, DEL_PMKSA); | 887 | CMD(del_pmksa, DEL_PMKSA); |
883 | CMD(flush_pmksa, FLUSH_PMKSA); | 888 | CMD(flush_pmksa, FLUSH_PMKSA); |
884 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | 889 | if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) |
890 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | ||
885 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); | 891 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); |
886 | CMD(mgmt_tx, FRAME); | 892 | CMD(mgmt_tx, FRAME); |
887 | CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL); | 893 | CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL); |
@@ -903,6 +909,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
903 | NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS); | 909 | NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS); |
904 | } | 910 | } |
905 | 911 | ||
912 | #ifdef CONFIG_NL80211_TESTMODE | ||
913 | CMD(testmode_cmd, TESTMODE); | ||
914 | #endif | ||
915 | |||
906 | #undef CMD | 916 | #undef CMD |
907 | 917 | ||
908 | if (dev->ops->connect || dev->ops->auth) { | 918 | if (dev->ops->connect || dev->ops->auth) { |
@@ -917,11 +927,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
917 | 927 | ||
918 | nla_nest_end(msg, nl_cmds); | 928 | nla_nest_end(msg, nl_cmds); |
919 | 929 | ||
920 | if (dev->ops->remain_on_channel) | 930 | if (dev->ops->remain_on_channel && |
931 | dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) | ||
921 | NLA_PUT_U32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, | 932 | NLA_PUT_U32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, |
922 | dev->wiphy.max_remain_on_channel_duration); | 933 | dev->wiphy.max_remain_on_channel_duration); |
923 | 934 | ||
924 | if (dev->ops->mgmt_tx_cancel_wait) | 935 | if (dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) |
925 | NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); | 936 | NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); |
926 | 937 | ||
927 | if (mgmt_stypes) { | 938 | if (mgmt_stypes) { |
@@ -1025,6 +1036,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1025 | 1036 | ||
1026 | NLA_PUT_U32(msg, NL80211_ATTR_FEATURE_FLAGS, dev->wiphy.features); | 1037 | NLA_PUT_U32(msg, NL80211_ATTR_FEATURE_FLAGS, dev->wiphy.features); |
1027 | 1038 | ||
1039 | if (dev->wiphy.ht_capa_mod_mask) | ||
1040 | NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, | ||
1041 | sizeof(*dev->wiphy.ht_capa_mod_mask), | ||
1042 | dev->wiphy.ht_capa_mod_mask); | ||
1043 | |||
1028 | return genlmsg_end(msg, hdr); | 1044 | return genlmsg_end(msg, hdr); |
1029 | 1045 | ||
1030 | nla_put_failure: | 1046 | nla_put_failure: |
@@ -2478,26 +2494,34 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
2478 | /* | 2494 | /* |
2479 | * Get vlan interface making sure it is running and on the right wiphy. | 2495 | * Get vlan interface making sure it is running and on the right wiphy. |
2480 | */ | 2496 | */ |
2481 | static int get_vlan(struct genl_info *info, | 2497 | static struct net_device *get_vlan(struct genl_info *info, |
2482 | struct cfg80211_registered_device *rdev, | 2498 | struct cfg80211_registered_device *rdev) |
2483 | struct net_device **vlan) | ||
2484 | { | 2499 | { |
2485 | struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN]; | 2500 | struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN]; |
2486 | *vlan = NULL; | 2501 | struct net_device *v; |
2487 | 2502 | int ret; | |
2488 | if (vlanattr) { | 2503 | |
2489 | *vlan = dev_get_by_index(genl_info_net(info), | 2504 | if (!vlanattr) |
2490 | nla_get_u32(vlanattr)); | 2505 | return NULL; |
2491 | if (!*vlan) | 2506 | |
2492 | return -ENODEV; | 2507 | v = dev_get_by_index(genl_info_net(info), nla_get_u32(vlanattr)); |
2493 | if (!(*vlan)->ieee80211_ptr) | 2508 | if (!v) |
2494 | return -EINVAL; | 2509 | return ERR_PTR(-ENODEV); |
2495 | if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) | 2510 | |
2496 | return -EINVAL; | 2511 | if (!v->ieee80211_ptr || v->ieee80211_ptr->wiphy != &rdev->wiphy) { |
2497 | if (!netif_running(*vlan)) | 2512 | ret = -EINVAL; |
2498 | return -ENETDOWN; | 2513 | goto error; |
2499 | } | 2514 | } |
2500 | return 0; | 2515 | |
2516 | if (!netif_running(v)) { | ||
2517 | ret = -ENETDOWN; | ||
2518 | goto error; | ||
2519 | } | ||
2520 | |||
2521 | return v; | ||
2522 | error: | ||
2523 | dev_put(v); | ||
2524 | return ERR_PTR(ret); | ||
2501 | } | 2525 | } |
2502 | 2526 | ||
2503 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | 2527 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) |
@@ -2547,9 +2571,9 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2547 | params.plink_state = | 2571 | params.plink_state = |
2548 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); | 2572 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); |
2549 | 2573 | ||
2550 | err = get_vlan(info, rdev, ¶ms.vlan); | 2574 | params.vlan = get_vlan(info, rdev); |
2551 | if (err) | 2575 | if (IS_ERR(params.vlan)) |
2552 | goto out; | 2576 | return PTR_ERR(params.vlan); |
2553 | 2577 | ||
2554 | /* validate settings */ | 2578 | /* validate settings */ |
2555 | err = 0; | 2579 | err = 0; |
@@ -2717,9 +2741,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
2717 | (rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))) | 2741 | (rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))) |
2718 | return -EINVAL; | 2742 | return -EINVAL; |
2719 | 2743 | ||
2720 | err = get_vlan(info, rdev, ¶ms.vlan); | 2744 | params.vlan = get_vlan(info, rdev); |
2721 | if (err) | 2745 | if (IS_ERR(params.vlan)) |
2722 | goto out; | 2746 | return PTR_ERR(params.vlan); |
2723 | 2747 | ||
2724 | /* validate settings */ | 2748 | /* validate settings */ |
2725 | err = 0; | 2749 | err = 0; |
@@ -3382,6 +3406,9 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
3382 | 3406 | ||
3383 | NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, | 3407 | NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, |
3384 | cfg80211_regdomain->alpha2); | 3408 | cfg80211_regdomain->alpha2); |
3409 | if (cfg80211_regdomain->dfs_region) | ||
3410 | NLA_PUT_U8(msg, NL80211_ATTR_DFS_REGION, | ||
3411 | cfg80211_regdomain->dfs_region); | ||
3385 | 3412 | ||
3386 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); | 3413 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); |
3387 | if (!nl_reg_rules) | 3414 | if (!nl_reg_rules) |
@@ -3440,6 +3467,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3440 | char *alpha2 = NULL; | 3467 | char *alpha2 = NULL; |
3441 | int rem_reg_rules = 0, r = 0; | 3468 | int rem_reg_rules = 0, r = 0; |
3442 | u32 num_rules = 0, rule_idx = 0, size_of_regd; | 3469 | u32 num_rules = 0, rule_idx = 0, size_of_regd; |
3470 | u8 dfs_region = 0; | ||
3443 | struct ieee80211_regdomain *rd = NULL; | 3471 | struct ieee80211_regdomain *rd = NULL; |
3444 | 3472 | ||
3445 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) | 3473 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) |
@@ -3450,6 +3478,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3450 | 3478 | ||
3451 | alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); | 3479 | alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); |
3452 | 3480 | ||
3481 | if (info->attrs[NL80211_ATTR_DFS_REGION]) | ||
3482 | dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]); | ||
3483 | |||
3453 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], | 3484 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], |
3454 | rem_reg_rules) { | 3485 | rem_reg_rules) { |
3455 | num_rules++; | 3486 | num_rules++; |
@@ -3477,6 +3508,13 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3477 | rd->alpha2[0] = alpha2[0]; | 3508 | rd->alpha2[0] = alpha2[0]; |
3478 | rd->alpha2[1] = alpha2[1]; | 3509 | rd->alpha2[1] = alpha2[1]; |
3479 | 3510 | ||
3511 | /* | ||
3512 | * Disable DFS master mode if the DFS region was | ||
3513 | * not supported or known on this kernel. | ||
3514 | */ | ||
3515 | if (reg_supported_dfs_region(dfs_region)) | ||
3516 | rd->dfs_region = dfs_region; | ||
3517 | |||
3480 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], | 3518 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], |
3481 | rem_reg_rules) { | 3519 | rem_reg_rules) { |
3482 | nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, | 3520 | nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, |
@@ -4384,6 +4422,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
4384 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; | 4422 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; |
4385 | int err, ssid_len, ie_len = 0; | 4423 | int err, ssid_len, ie_len = 0; |
4386 | bool use_mfp = false; | 4424 | bool use_mfp = false; |
4425 | u32 flags = 0; | ||
4426 | struct ieee80211_ht_cap *ht_capa = NULL; | ||
4427 | struct ieee80211_ht_cap *ht_capa_mask = NULL; | ||
4387 | 4428 | ||
4388 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 4429 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
4389 | return -EINVAL; | 4430 | return -EINVAL; |
@@ -4427,11 +4468,25 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
4427 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) | 4468 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) |
4428 | prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); | 4469 | prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); |
4429 | 4470 | ||
4471 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT])) | ||
4472 | flags |= ASSOC_REQ_DISABLE_HT; | ||
4473 | |||
4474 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) | ||
4475 | ht_capa_mask = | ||
4476 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]); | ||
4477 | |||
4478 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) { | ||
4479 | if (!ht_capa_mask) | ||
4480 | return -EINVAL; | ||
4481 | ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | ||
4482 | } | ||
4483 | |||
4430 | err = nl80211_crypto_settings(rdev, info, &crypto, 1); | 4484 | err = nl80211_crypto_settings(rdev, info, &crypto, 1); |
4431 | if (!err) | 4485 | if (!err) |
4432 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 4486 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, |
4433 | ssid, ssid_len, ie, ie_len, use_mfp, | 4487 | ssid, ssid_len, ie, ie_len, use_mfp, |
4434 | &crypto); | 4488 | &crypto, flags, ht_capa, |
4489 | ht_capa_mask); | ||
4435 | 4490 | ||
4436 | return err; | 4491 | return err; |
4437 | } | 4492 | } |
@@ -4921,6 +4976,22 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
4921 | return PTR_ERR(connkeys); | 4976 | return PTR_ERR(connkeys); |
4922 | } | 4977 | } |
4923 | 4978 | ||
4979 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT])) | ||
4980 | connect.flags |= ASSOC_REQ_DISABLE_HT; | ||
4981 | |||
4982 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) | ||
4983 | memcpy(&connect.ht_capa_mask, | ||
4984 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]), | ||
4985 | sizeof(connect.ht_capa_mask)); | ||
4986 | |||
4987 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) { | ||
4988 | if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) | ||
4989 | return -EINVAL; | ||
4990 | memcpy(&connect.ht_capa, | ||
4991 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]), | ||
4992 | sizeof(connect.ht_capa)); | ||
4993 | } | ||
4994 | |||
4924 | err = cfg80211_connect(rdev, dev, &connect, connkeys); | 4995 | err = cfg80211_connect(rdev, dev, &connect, connkeys); |
4925 | if (err) | 4996 | if (err) |
4926 | kfree(connkeys); | 4997 | kfree(connkeys); |
@@ -5108,7 +5179,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
5108 | duration > rdev->wiphy.max_remain_on_channel_duration) | 5179 | duration > rdev->wiphy.max_remain_on_channel_duration) |
5109 | return -EINVAL; | 5180 | return -EINVAL; |
5110 | 5181 | ||
5111 | if (!rdev->ops->remain_on_channel) | 5182 | if (!rdev->ops->remain_on_channel || |
5183 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)) | ||
5112 | return -EOPNOTSUPP; | 5184 | return -EOPNOTSUPP; |
5113 | 5185 | ||
5114 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 5186 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
@@ -5321,7 +5393,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5321 | return -EOPNOTSUPP; | 5393 | return -EOPNOTSUPP; |
5322 | 5394 | ||
5323 | if (info->attrs[NL80211_ATTR_DURATION]) { | 5395 | if (info->attrs[NL80211_ATTR_DURATION]) { |
5324 | if (!rdev->ops->mgmt_tx_cancel_wait) | 5396 | if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) |
5325 | return -EINVAL; | 5397 | return -EINVAL; |
5326 | wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); | 5398 | wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); |
5327 | } | 5399 | } |
@@ -5339,6 +5411,9 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5339 | 5411 | ||
5340 | offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK]; | 5412 | offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK]; |
5341 | 5413 | ||
5414 | if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) | ||
5415 | return -EINVAL; | ||
5416 | |||
5342 | no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); | 5417 | no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); |
5343 | 5418 | ||
5344 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 5419 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 77e926738014..76b35df39623 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -1123,6 +1123,8 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, | |||
1123 | if (ignore_reg_update(wiphy, initiator)) | 1123 | if (ignore_reg_update(wiphy, initiator)) |
1124 | return; | 1124 | return; |
1125 | 1125 | ||
1126 | last_request->dfs_region = cfg80211_regdomain->dfs_region; | ||
1127 | |||
1126 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 1128 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
1127 | if (wiphy->bands[band]) | 1129 | if (wiphy->bands[band]) |
1128 | handle_band(wiphy, band, initiator); | 1130 | handle_band(wiphy, band, initiator); |
@@ -1948,6 +1950,42 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) | |||
1948 | } | 1950 | } |
1949 | } | 1951 | } |
1950 | 1952 | ||
1953 | bool reg_supported_dfs_region(u8 dfs_region) | ||
1954 | { | ||
1955 | switch (dfs_region) { | ||
1956 | case NL80211_DFS_UNSET: | ||
1957 | case NL80211_DFS_FCC: | ||
1958 | case NL80211_DFS_ETSI: | ||
1959 | case NL80211_DFS_JP: | ||
1960 | return true; | ||
1961 | default: | ||
1962 | REG_DBG_PRINT("Ignoring uknown DFS master region: %d\n", | ||
1963 | dfs_region); | ||
1964 | return false; | ||
1965 | } | ||
1966 | } | ||
1967 | |||
1968 | static void print_dfs_region(u8 dfs_region) | ||
1969 | { | ||
1970 | if (!dfs_region) | ||
1971 | return; | ||
1972 | |||
1973 | switch (dfs_region) { | ||
1974 | case NL80211_DFS_FCC: | ||
1975 | pr_info(" DFS Master region FCC"); | ||
1976 | break; | ||
1977 | case NL80211_DFS_ETSI: | ||
1978 | pr_info(" DFS Master region ETSI"); | ||
1979 | break; | ||
1980 | case NL80211_DFS_JP: | ||
1981 | pr_info(" DFS Master region JP"); | ||
1982 | break; | ||
1983 | default: | ||
1984 | pr_info(" DFS Master region Uknown"); | ||
1985 | break; | ||
1986 | } | ||
1987 | } | ||
1988 | |||
1951 | static void print_regdomain(const struct ieee80211_regdomain *rd) | 1989 | static void print_regdomain(const struct ieee80211_regdomain *rd) |
1952 | { | 1990 | { |
1953 | 1991 | ||
@@ -1975,6 +2013,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) | |||
1975 | pr_info("Regulatory domain changed to country: %c%c\n", | 2013 | pr_info("Regulatory domain changed to country: %c%c\n", |
1976 | rd->alpha2[0], rd->alpha2[1]); | 2014 | rd->alpha2[0], rd->alpha2[1]); |
1977 | } | 2015 | } |
2016 | print_dfs_region(rd->dfs_region); | ||
1978 | print_rd_rules(rd); | 2017 | print_rd_rules(rd); |
1979 | } | 2018 | } |
1980 | 2019 | ||
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 4a56799d868d..786e414afd91 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -5,6 +5,7 @@ extern const struct ieee80211_regdomain *cfg80211_regdomain; | |||
5 | 5 | ||
6 | bool is_world_regdom(const char *alpha2); | 6 | bool is_world_regdom(const char *alpha2); |
7 | bool reg_is_valid_request(const char *alpha2); | 7 | bool reg_is_valid_request(const char *alpha2); |
8 | bool reg_supported_dfs_region(u8 dfs_region); | ||
8 | 9 | ||
9 | int regulatory_hint_user(const char *alpha2); | 10 | int regulatory_hint_user(const char *alpha2); |
10 | 11 | ||
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 0acfdc9beacf..f0c900ce2fb9 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -190,7 +190,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
190 | prev_bssid, | 190 | prev_bssid, |
191 | params->ssid, params->ssid_len, | 191 | params->ssid, params->ssid_len, |
192 | params->ie, params->ie_len, | 192 | params->ie, params->ie_len, |
193 | false, ¶ms->crypto); | 193 | false, ¶ms->crypto, |
194 | params->flags, ¶ms->ht_capa, | ||
195 | ¶ms->ht_capa_mask); | ||
194 | if (err) | 196 | if (err) |
195 | __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, | 197 | __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, |
196 | NULL, 0, | 198 | NULL, 0, |
@@ -774,6 +776,9 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
774 | wdev->connect_keys = NULL; | 776 | wdev->connect_keys = NULL; |
775 | } | 777 | } |
776 | 778 | ||
779 | cfg80211_oper_and_ht_capa(&connect->ht_capa_mask, | ||
780 | rdev->wiphy.ht_capa_mod_mask); | ||
781 | |||
777 | if (connkeys && connkeys->def >= 0) { | 782 | if (connkeys && connkeys->def >= 0) { |
778 | int idx; | 783 | int idx; |
779 | u32 cipher; | 784 | u32 cipher; |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 4dde429441d2..9c601d59b77a 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -7,7 +7,6 @@ | |||
7 | #include <linux/bitops.h> | 7 | #include <linux/bitops.h> |
8 | #include <linux/etherdevice.h> | 8 | #include <linux/etherdevice.h> |
9 | #include <linux/slab.h> | 9 | #include <linux/slab.h> |
10 | #include <linux/crc32.h> | ||
11 | #include <net/cfg80211.h> | 10 | #include <net/cfg80211.h> |
12 | #include <net/ip.h> | 11 | #include <net/ip.h> |
13 | #include "core.h" | 12 | #include "core.h" |
@@ -240,17 +239,6 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | |||
240 | return 0; | 239 | return 0; |
241 | } | 240 | } |
242 | 241 | ||
243 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ | ||
244 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ | ||
245 | const unsigned char rfc1042_header[] __aligned(2) = | ||
246 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | ||
247 | EXPORT_SYMBOL(rfc1042_header); | ||
248 | |||
249 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ | ||
250 | const unsigned char bridge_tunnel_header[] __aligned(2) = | ||
251 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | ||
252 | EXPORT_SYMBOL(bridge_tunnel_header); | ||
253 | |||
254 | unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc) | 242 | unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc) |
255 | { | 243 | { |
256 | unsigned int hdrlen = 24; | 244 | unsigned int hdrlen = 24; |
@@ -1051,169 +1039,13 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, | |||
1051 | return 0; | 1039 | return 0; |
1052 | } | 1040 | } |
1053 | 1041 | ||
1054 | u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | 1042 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ |
1055 | struct ieee802_11_elems *elems, | 1043 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ |
1056 | u64 filter, u32 crc) | 1044 | const unsigned char rfc1042_header[] __aligned(2) = |
1057 | { | 1045 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; |
1058 | size_t left = len; | 1046 | EXPORT_SYMBOL(rfc1042_header); |
1059 | u8 *pos = start; | ||
1060 | bool calc_crc = filter != 0; | ||
1061 | |||
1062 | memset(elems, 0, sizeof(*elems)); | ||
1063 | elems->ie_start = start; | ||
1064 | elems->total_len = len; | ||
1065 | |||
1066 | while (left >= 2) { | ||
1067 | u8 id, elen; | ||
1068 | |||
1069 | id = *pos++; | ||
1070 | elen = *pos++; | ||
1071 | left -= 2; | ||
1072 | |||
1073 | if (elen > left) | ||
1074 | break; | ||
1075 | |||
1076 | if (calc_crc && id < 64 && (filter & (1ULL << id))) | ||
1077 | crc = crc32_be(crc, pos - 2, elen + 2); | ||
1078 | |||
1079 | switch (id) { | ||
1080 | case WLAN_EID_SSID: | ||
1081 | elems->ssid = pos; | ||
1082 | elems->ssid_len = elen; | ||
1083 | break; | ||
1084 | case WLAN_EID_SUPP_RATES: | ||
1085 | elems->supp_rates = pos; | ||
1086 | elems->supp_rates_len = elen; | ||
1087 | break; | ||
1088 | case WLAN_EID_FH_PARAMS: | ||
1089 | elems->fh_params = pos; | ||
1090 | elems->fh_params_len = elen; | ||
1091 | break; | ||
1092 | case WLAN_EID_DS_PARAMS: | ||
1093 | elems->ds_params = pos; | ||
1094 | elems->ds_params_len = elen; | ||
1095 | break; | ||
1096 | case WLAN_EID_CF_PARAMS: | ||
1097 | elems->cf_params = pos; | ||
1098 | elems->cf_params_len = elen; | ||
1099 | break; | ||
1100 | case WLAN_EID_TIM: | ||
1101 | if (elen >= sizeof(struct ieee80211_tim_ie)) { | ||
1102 | elems->tim = (void *)pos; | ||
1103 | elems->tim_len = elen; | ||
1104 | } | ||
1105 | break; | ||
1106 | case WLAN_EID_IBSS_PARAMS: | ||
1107 | elems->ibss_params = pos; | ||
1108 | elems->ibss_params_len = elen; | ||
1109 | break; | ||
1110 | case WLAN_EID_CHALLENGE: | ||
1111 | elems->challenge = pos; | ||
1112 | elems->challenge_len = elen; | ||
1113 | break; | ||
1114 | case WLAN_EID_VENDOR_SPECIFIC: | ||
1115 | if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && | ||
1116 | pos[2] == 0xf2) { | ||
1117 | /* Microsoft OUI (00:50:F2) */ | ||
1118 | |||
1119 | if (calc_crc) | ||
1120 | crc = crc32_be(crc, pos - 2, elen + 2); | ||
1121 | |||
1122 | if (pos[3] == 1) { | ||
1123 | /* OUI Type 1 - WPA IE */ | ||
1124 | elems->wpa = pos; | ||
1125 | elems->wpa_len = elen; | ||
1126 | } else if (elen >= 5 && pos[3] == 2) { | ||
1127 | /* OUI Type 2 - WMM IE */ | ||
1128 | if (pos[4] == 0) { | ||
1129 | elems->wmm_info = pos; | ||
1130 | elems->wmm_info_len = elen; | ||
1131 | } else if (pos[4] == 1) { | ||
1132 | elems->wmm_param = pos; | ||
1133 | elems->wmm_param_len = elen; | ||
1134 | } | ||
1135 | } | ||
1136 | } | ||
1137 | break; | ||
1138 | case WLAN_EID_RSN: | ||
1139 | elems->rsn = pos; | ||
1140 | elems->rsn_len = elen; | ||
1141 | break; | ||
1142 | case WLAN_EID_ERP_INFO: | ||
1143 | elems->erp_info = pos; | ||
1144 | elems->erp_info_len = elen; | ||
1145 | break; | ||
1146 | case WLAN_EID_EXT_SUPP_RATES: | ||
1147 | elems->ext_supp_rates = pos; | ||
1148 | elems->ext_supp_rates_len = elen; | ||
1149 | break; | ||
1150 | case WLAN_EID_HT_CAPABILITY: | ||
1151 | if (elen >= sizeof(struct ieee80211_ht_cap)) | ||
1152 | elems->ht_cap_elem = (void *)pos; | ||
1153 | break; | ||
1154 | case WLAN_EID_HT_INFORMATION: | ||
1155 | if (elen >= sizeof(struct ieee80211_ht_info)) | ||
1156 | elems->ht_info_elem = (void *)pos; | ||
1157 | break; | ||
1158 | case WLAN_EID_MESH_ID: | ||
1159 | elems->mesh_id = pos; | ||
1160 | elems->mesh_id_len = elen; | ||
1161 | break; | ||
1162 | case WLAN_EID_MESH_CONFIG: | ||
1163 | if (elen >= sizeof(struct ieee80211_meshconf_ie)) | ||
1164 | elems->mesh_config = (void *)pos; | ||
1165 | break; | ||
1166 | case WLAN_EID_PEER_MGMT: | ||
1167 | elems->peering = pos; | ||
1168 | elems->peering_len = elen; | ||
1169 | break; | ||
1170 | case WLAN_EID_PREQ: | ||
1171 | elems->preq = pos; | ||
1172 | elems->preq_len = elen; | ||
1173 | break; | ||
1174 | case WLAN_EID_PREP: | ||
1175 | elems->prep = pos; | ||
1176 | elems->prep_len = elen; | ||
1177 | break; | ||
1178 | case WLAN_EID_PERR: | ||
1179 | elems->perr = pos; | ||
1180 | elems->perr_len = elen; | ||
1181 | break; | ||
1182 | case WLAN_EID_RANN: | ||
1183 | if (elen >= sizeof(struct ieee80211_rann_ie)) | ||
1184 | elems->rann = (void *)pos; | ||
1185 | break; | ||
1186 | case WLAN_EID_CHANNEL_SWITCH: | ||
1187 | elems->ch_switch_elem = pos; | ||
1188 | elems->ch_switch_elem_len = elen; | ||
1189 | break; | ||
1190 | case WLAN_EID_QUIET: | ||
1191 | if (!elems->quiet_elem) { | ||
1192 | elems->quiet_elem = pos; | ||
1193 | elems->quiet_elem_len = elen; | ||
1194 | } | ||
1195 | elems->num_of_quiet_elem++; | ||
1196 | break; | ||
1197 | case WLAN_EID_COUNTRY: | ||
1198 | elems->country_elem = pos; | ||
1199 | elems->country_elem_len = elen; | ||
1200 | break; | ||
1201 | case WLAN_EID_PWR_CONSTRAINT: | ||
1202 | elems->pwr_constr_elem = pos; | ||
1203 | elems->pwr_constr_elem_len = elen; | ||
1204 | break; | ||
1205 | case WLAN_EID_TIMEOUT_INTERVAL: | ||
1206 | elems->timeout_int = pos; | ||
1207 | elems->timeout_int_len = elen; | ||
1208 | break; | ||
1209 | default: | ||
1210 | break; | ||
1211 | } | ||
1212 | |||
1213 | left -= elen; | ||
1214 | pos += elen; | ||
1215 | } | ||
1216 | 1047 | ||
1217 | return crc; | 1048 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ |
1218 | } | 1049 | const unsigned char bridge_tunnel_header[] __aligned(2) = |
1219 | EXPORT_SYMBOL(ieee802_11_parse_elems_crc); | 1050 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; |
1051 | EXPORT_SYMBOL(bridge_tunnel_header); | ||