diff options
Diffstat (limited to 'net')
35 files changed, 2075 insertions, 395 deletions
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 7d4971aa443f..58c94bb38e87 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -15,6 +15,7 @@ mac80211-y := \ | |||
15 | michael.o \ | 15 | michael.o \ |
16 | tkip.o \ | 16 | tkip.o \ |
17 | aes_ccm.o \ | 17 | aes_ccm.o \ |
18 | aes_cmac.o \ | ||
18 | cfg.o \ | 19 | cfg.o \ |
19 | rx.o \ | 20 | rx.o \ |
20 | spectmgmt.o \ | 21 | spectmgmt.o \ |
@@ -37,6 +38,8 @@ mac80211-$(CONFIG_MAC80211_MESH) += \ | |||
37 | mesh_plink.o \ | 38 | mesh_plink.o \ |
38 | mesh_hwmp.o | 39 | mesh_hwmp.o |
39 | 40 | ||
41 | mac80211-$(CONFIG_PM) += pm.o | ||
42 | |||
40 | # objects for PID algorithm | 43 | # objects for PID algorithm |
41 | rc80211_pid-y := rc80211_pid_algo.o | 44 | rc80211_pid-y := rc80211_pid_algo.o |
42 | rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o | 45 | rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o |
diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c new file mode 100644 index 000000000000..3d097b3d7b62 --- /dev/null +++ b/net/mac80211/aes_cmac.c | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * AES-128-CMAC with TLen 16 for IEEE 802.11w BIP | ||
3 | * Copyright 2008, Jouni Malinen <j@w1.fi> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/types.h> | ||
12 | #include <linux/crypto.h> | ||
13 | #include <linux/err.h> | ||
14 | |||
15 | #include <net/mac80211.h> | ||
16 | #include "key.h" | ||
17 | #include "aes_cmac.h" | ||
18 | |||
19 | #define AES_BLOCK_SIZE 16 | ||
20 | #define AES_CMAC_KEY_LEN 16 | ||
21 | #define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */ | ||
22 | #define AAD_LEN 20 | ||
23 | |||
24 | |||
25 | static void gf_mulx(u8 *pad) | ||
26 | { | ||
27 | int i, carry; | ||
28 | |||
29 | carry = pad[0] & 0x80; | ||
30 | for (i = 0; i < AES_BLOCK_SIZE - 1; i++) | ||
31 | pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7); | ||
32 | pad[AES_BLOCK_SIZE - 1] <<= 1; | ||
33 | if (carry) | ||
34 | pad[AES_BLOCK_SIZE - 1] ^= 0x87; | ||
35 | } | ||
36 | |||
37 | |||
38 | static void aes_128_cmac_vector(struct crypto_cipher *tfm, u8 *scratch, | ||
39 | size_t num_elem, | ||
40 | const u8 *addr[], const size_t *len, u8 *mac) | ||
41 | { | ||
42 | u8 *cbc, *pad; | ||
43 | const u8 *pos, *end; | ||
44 | size_t i, e, left, total_len; | ||
45 | |||
46 | cbc = scratch; | ||
47 | pad = scratch + AES_BLOCK_SIZE; | ||
48 | |||
49 | memset(cbc, 0, AES_BLOCK_SIZE); | ||
50 | |||
51 | total_len = 0; | ||
52 | for (e = 0; e < num_elem; e++) | ||
53 | total_len += len[e]; | ||
54 | left = total_len; | ||
55 | |||
56 | e = 0; | ||
57 | pos = addr[0]; | ||
58 | end = pos + len[0]; | ||
59 | |||
60 | while (left >= AES_BLOCK_SIZE) { | ||
61 | for (i = 0; i < AES_BLOCK_SIZE; i++) { | ||
62 | cbc[i] ^= *pos++; | ||
63 | if (pos >= end) { | ||
64 | e++; | ||
65 | pos = addr[e]; | ||
66 | end = pos + len[e]; | ||
67 | } | ||
68 | } | ||
69 | if (left > AES_BLOCK_SIZE) | ||
70 | crypto_cipher_encrypt_one(tfm, cbc, cbc); | ||
71 | left -= AES_BLOCK_SIZE; | ||
72 | } | ||
73 | |||
74 | memset(pad, 0, AES_BLOCK_SIZE); | ||
75 | crypto_cipher_encrypt_one(tfm, pad, pad); | ||
76 | gf_mulx(pad); | ||
77 | |||
78 | if (left || total_len == 0) { | ||
79 | for (i = 0; i < left; i++) { | ||
80 | cbc[i] ^= *pos++; | ||
81 | if (pos >= end) { | ||
82 | e++; | ||
83 | pos = addr[e]; | ||
84 | end = pos + len[e]; | ||
85 | } | ||
86 | } | ||
87 | cbc[left] ^= 0x80; | ||
88 | gf_mulx(pad); | ||
89 | } | ||
90 | |||
91 | for (i = 0; i < AES_BLOCK_SIZE; i++) | ||
92 | pad[i] ^= cbc[i]; | ||
93 | crypto_cipher_encrypt_one(tfm, pad, pad); | ||
94 | memcpy(mac, pad, CMAC_TLEN); | ||
95 | } | ||
96 | |||
97 | |||
98 | void ieee80211_aes_cmac(struct crypto_cipher *tfm, u8 *scratch, const u8 *aad, | ||
99 | const u8 *data, size_t data_len, u8 *mic) | ||
100 | { | ||
101 | const u8 *addr[3]; | ||
102 | size_t len[3]; | ||
103 | u8 zero[CMAC_TLEN]; | ||
104 | |||
105 | memset(zero, 0, CMAC_TLEN); | ||
106 | addr[0] = aad; | ||
107 | len[0] = AAD_LEN; | ||
108 | addr[1] = data; | ||
109 | len[1] = data_len - CMAC_TLEN; | ||
110 | addr[2] = zero; | ||
111 | len[2] = CMAC_TLEN; | ||
112 | |||
113 | aes_128_cmac_vector(tfm, scratch, 3, addr, len, mic); | ||
114 | } | ||
115 | |||
116 | |||
117 | struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[]) | ||
118 | { | ||
119 | struct crypto_cipher *tfm; | ||
120 | |||
121 | tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); | ||
122 | if (IS_ERR(tfm)) | ||
123 | return NULL; | ||
124 | |||
125 | crypto_cipher_setkey(tfm, key, AES_CMAC_KEY_LEN); | ||
126 | |||
127 | return tfm; | ||
128 | } | ||
129 | |||
130 | |||
131 | void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm) | ||
132 | { | ||
133 | if (tfm) | ||
134 | crypto_free_cipher(tfm); | ||
135 | } | ||
diff --git a/net/mac80211/aes_cmac.h b/net/mac80211/aes_cmac.h new file mode 100644 index 000000000000..0eb9a4831508 --- /dev/null +++ b/net/mac80211/aes_cmac.h | |||
@@ -0,0 +1,19 @@ | |||
1 | /* | ||
2 | * Copyright 2008, Jouni Malinen <j@w1.fi> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef AES_CMAC_H | ||
10 | #define AES_CMAC_H | ||
11 | |||
12 | #include <linux/crypto.h> | ||
13 | |||
14 | struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[]); | ||
15 | void ieee80211_aes_cmac(struct crypto_cipher *tfm, u8 *scratch, const u8 *aad, | ||
16 | const u8 *data, size_t data_len, u8 *mic); | ||
17 | void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm); | ||
18 | |||
19 | #endif /* AES_CMAC_H */ | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 9d4e4d846ec1..a1a1344c5c4b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -133,6 +133,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
133 | case WLAN_CIPHER_SUITE_CCMP: | 133 | case WLAN_CIPHER_SUITE_CCMP: |
134 | alg = ALG_CCMP; | 134 | alg = ALG_CCMP; |
135 | break; | 135 | break; |
136 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
137 | alg = ALG_AES_CMAC; | ||
138 | break; | ||
136 | default: | 139 | default: |
137 | return -EINVAL; | 140 | return -EINVAL; |
138 | } | 141 | } |
@@ -275,6 +278,17 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
275 | else | 278 | else |
276 | params.cipher = WLAN_CIPHER_SUITE_WEP104; | 279 | params.cipher = WLAN_CIPHER_SUITE_WEP104; |
277 | break; | 280 | break; |
281 | case ALG_AES_CMAC: | ||
282 | params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; | ||
283 | seq[0] = key->u.aes_cmac.tx_pn[5]; | ||
284 | seq[1] = key->u.aes_cmac.tx_pn[4]; | ||
285 | seq[2] = key->u.aes_cmac.tx_pn[3]; | ||
286 | seq[3] = key->u.aes_cmac.tx_pn[2]; | ||
287 | seq[4] = key->u.aes_cmac.tx_pn[1]; | ||
288 | seq[5] = key->u.aes_cmac.tx_pn[0]; | ||
289 | params.seq = seq; | ||
290 | params.seq_len = 6; | ||
291 | break; | ||
278 | } | 292 | } |
279 | 293 | ||
280 | params.key = key->conf.key; | 294 | params.key = key->conf.key; |
@@ -304,6 +318,22 @@ static int ieee80211_config_default_key(struct wiphy *wiphy, | |||
304 | return 0; | 318 | return 0; |
305 | } | 319 | } |
306 | 320 | ||
321 | static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy, | ||
322 | struct net_device *dev, | ||
323 | u8 key_idx) | ||
324 | { | ||
325 | struct ieee80211_sub_if_data *sdata; | ||
326 | |||
327 | rcu_read_lock(); | ||
328 | |||
329 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
330 | ieee80211_set_default_mgmt_key(sdata, key_idx); | ||
331 | |||
332 | rcu_read_unlock(); | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
307 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | 337 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) |
308 | { | 338 | { |
309 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 339 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
@@ -493,7 +523,8 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
493 | 523 | ||
494 | kfree(old); | 524 | kfree(old); |
495 | 525 | ||
496 | return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); | 526 | return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | |
527 | IEEE80211_IFCC_BEACON_ENABLED); | ||
497 | } | 528 | } |
498 | 529 | ||
499 | static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, | 530 | static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, |
@@ -553,7 +584,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) | |||
553 | synchronize_rcu(); | 584 | synchronize_rcu(); |
554 | kfree(old); | 585 | kfree(old); |
555 | 586 | ||
556 | return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); | 587 | return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED); |
557 | } | 588 | } |
558 | 589 | ||
559 | /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ | 590 | /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ |
@@ -630,6 +661,10 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
630 | sta->flags &= ~WLAN_STA_WME; | 661 | sta->flags &= ~WLAN_STA_WME; |
631 | if (params->station_flags & STATION_FLAG_WME) | 662 | if (params->station_flags & STATION_FLAG_WME) |
632 | sta->flags |= WLAN_STA_WME; | 663 | sta->flags |= WLAN_STA_WME; |
664 | |||
665 | sta->flags &= ~WLAN_STA_MFP; | ||
666 | if (params->station_flags & STATION_FLAG_MFP) | ||
667 | sta->flags |= WLAN_STA_MFP; | ||
633 | spin_unlock_bh(&sta->lock); | 668 | spin_unlock_bh(&sta->lock); |
634 | } | 669 | } |
635 | 670 | ||
@@ -1141,6 +1176,102 @@ static int ieee80211_set_channel(struct wiphy *wiphy, | |||
1141 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 1176 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
1142 | } | 1177 | } |
1143 | 1178 | ||
1179 | static int set_mgmt_extra_ie_sta(struct ieee80211_if_sta *ifsta, u8 subtype, | ||
1180 | u8 *ies, size_t ies_len) | ||
1181 | { | ||
1182 | switch (subtype) { | ||
1183 | case IEEE80211_STYPE_PROBE_REQ >> 4: | ||
1184 | kfree(ifsta->ie_probereq); | ||
1185 | ifsta->ie_probereq = ies; | ||
1186 | ifsta->ie_probereq_len = ies_len; | ||
1187 | return 0; | ||
1188 | case IEEE80211_STYPE_PROBE_RESP >> 4: | ||
1189 | kfree(ifsta->ie_proberesp); | ||
1190 | ifsta->ie_proberesp = ies; | ||
1191 | ifsta->ie_proberesp_len = ies_len; | ||
1192 | return 0; | ||
1193 | case IEEE80211_STYPE_AUTH >> 4: | ||
1194 | kfree(ifsta->ie_auth); | ||
1195 | ifsta->ie_auth = ies; | ||
1196 | ifsta->ie_auth_len = ies_len; | ||
1197 | return 0; | ||
1198 | case IEEE80211_STYPE_ASSOC_REQ >> 4: | ||
1199 | kfree(ifsta->ie_assocreq); | ||
1200 | ifsta->ie_assocreq = ies; | ||
1201 | ifsta->ie_assocreq_len = ies_len; | ||
1202 | return 0; | ||
1203 | case IEEE80211_STYPE_REASSOC_REQ >> 4: | ||
1204 | kfree(ifsta->ie_reassocreq); | ||
1205 | ifsta->ie_reassocreq = ies; | ||
1206 | ifsta->ie_reassocreq_len = ies_len; | ||
1207 | return 0; | ||
1208 | case IEEE80211_STYPE_DEAUTH >> 4: | ||
1209 | kfree(ifsta->ie_deauth); | ||
1210 | ifsta->ie_deauth = ies; | ||
1211 | ifsta->ie_deauth_len = ies_len; | ||
1212 | return 0; | ||
1213 | case IEEE80211_STYPE_DISASSOC >> 4: | ||
1214 | kfree(ifsta->ie_disassoc); | ||
1215 | ifsta->ie_disassoc = ies; | ||
1216 | ifsta->ie_disassoc_len = ies_len; | ||
1217 | return 0; | ||
1218 | } | ||
1219 | |||
1220 | return -EOPNOTSUPP; | ||
1221 | } | ||
1222 | |||
1223 | static int ieee80211_set_mgmt_extra_ie(struct wiphy *wiphy, | ||
1224 | struct net_device *dev, | ||
1225 | struct mgmt_extra_ie_params *params) | ||
1226 | { | ||
1227 | struct ieee80211_sub_if_data *sdata; | ||
1228 | u8 *ies; | ||
1229 | size_t ies_len; | ||
1230 | int ret = -EOPNOTSUPP; | ||
1231 | |||
1232 | if (params->ies) { | ||
1233 | ies = kmemdup(params->ies, params->ies_len, GFP_KERNEL); | ||
1234 | if (ies == NULL) | ||
1235 | return -ENOMEM; | ||
1236 | ies_len = params->ies_len; | ||
1237 | } else { | ||
1238 | ies = NULL; | ||
1239 | ies_len = 0; | ||
1240 | } | ||
1241 | |||
1242 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1243 | |||
1244 | switch (sdata->vif.type) { | ||
1245 | case NL80211_IFTYPE_STATION: | ||
1246 | case NL80211_IFTYPE_ADHOC: | ||
1247 | ret = set_mgmt_extra_ie_sta(&sdata->u.sta, params->subtype, | ||
1248 | ies, ies_len); | ||
1249 | break; | ||
1250 | default: | ||
1251 | ret = -EOPNOTSUPP; | ||
1252 | break; | ||
1253 | } | ||
1254 | |||
1255 | if (ret) | ||
1256 | kfree(ies); | ||
1257 | return ret; | ||
1258 | } | ||
1259 | |||
1260 | #ifdef CONFIG_PM | ||
1261 | static int ieee80211_suspend(struct wiphy *wiphy) | ||
1262 | { | ||
1263 | return __ieee80211_suspend(wiphy_priv(wiphy)); | ||
1264 | } | ||
1265 | |||
1266 | static int ieee80211_resume(struct wiphy *wiphy) | ||
1267 | { | ||
1268 | return __ieee80211_resume(wiphy_priv(wiphy)); | ||
1269 | } | ||
1270 | #else | ||
1271 | #define ieee80211_suspend NULL | ||
1272 | #define ieee80211_resume NULL | ||
1273 | #endif | ||
1274 | |||
1144 | struct cfg80211_ops mac80211_config_ops = { | 1275 | struct cfg80211_ops mac80211_config_ops = { |
1145 | .add_virtual_intf = ieee80211_add_iface, | 1276 | .add_virtual_intf = ieee80211_add_iface, |
1146 | .del_virtual_intf = ieee80211_del_iface, | 1277 | .del_virtual_intf = ieee80211_del_iface, |
@@ -1149,6 +1280,7 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1149 | .del_key = ieee80211_del_key, | 1280 | .del_key = ieee80211_del_key, |
1150 | .get_key = ieee80211_get_key, | 1281 | .get_key = ieee80211_get_key, |
1151 | .set_default_key = ieee80211_config_default_key, | 1282 | .set_default_key = ieee80211_config_default_key, |
1283 | .set_default_mgmt_key = ieee80211_config_default_mgmt_key, | ||
1152 | .add_beacon = ieee80211_add_beacon, | 1284 | .add_beacon = ieee80211_add_beacon, |
1153 | .set_beacon = ieee80211_set_beacon, | 1285 | .set_beacon = ieee80211_set_beacon, |
1154 | .del_beacon = ieee80211_del_beacon, | 1286 | .del_beacon = ieee80211_del_beacon, |
@@ -1169,4 +1301,7 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1169 | .change_bss = ieee80211_change_bss, | 1301 | .change_bss = ieee80211_change_bss, |
1170 | .set_txq_params = ieee80211_set_txq_params, | 1302 | .set_txq_params = ieee80211_set_txq_params, |
1171 | .set_channel = ieee80211_set_channel, | 1303 | .set_channel = ieee80211_set_channel, |
1304 | .set_mgmt_extra_ie = ieee80211_set_mgmt_extra_ie, | ||
1305 | .suspend = ieee80211_suspend, | ||
1306 | .resume = ieee80211_resume, | ||
1172 | }; | 1307 | }; |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 2697a2fe608f..e37f557de3f3 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -57,11 +57,62 @@ DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", | |||
57 | local->hw.conf.long_frame_max_tx_count); | 57 | local->hw.conf.long_frame_max_tx_count); |
58 | DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", | 58 | DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", |
59 | local->total_ps_buffered); | 59 | local->total_ps_buffered); |
60 | DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x", | 60 | DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x", |
61 | local->wep_iv & 0xffffff); | 61 | local->wep_iv & 0xffffff); |
62 | DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s", | 62 | DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s", |
63 | local->rate_ctrl ? local->rate_ctrl->ops->name : "<unset>"); | 63 | local->rate_ctrl ? local->rate_ctrl->ops->name : "<unset>"); |
64 | 64 | ||
65 | static ssize_t tsf_read(struct file *file, char __user *user_buf, | ||
66 | size_t count, loff_t *ppos) | ||
67 | { | ||
68 | struct ieee80211_local *local = file->private_data; | ||
69 | u64 tsf = 0; | ||
70 | char buf[100]; | ||
71 | |||
72 | if (local->ops->get_tsf) | ||
73 | tsf = local->ops->get_tsf(local_to_hw(local)); | ||
74 | |||
75 | snprintf(buf, sizeof(buf), "0x%016llx\n", (unsigned long long) tsf); | ||
76 | |||
77 | return simple_read_from_buffer(user_buf, count, ppos, buf, 19); | ||
78 | } | ||
79 | |||
80 | static ssize_t tsf_write(struct file *file, | ||
81 | const char __user *user_buf, | ||
82 | size_t count, loff_t *ppos) | ||
83 | { | ||
84 | struct ieee80211_local *local = file->private_data; | ||
85 | unsigned long long tsf; | ||
86 | char buf[100]; | ||
87 | size_t len; | ||
88 | |||
89 | len = min(count, sizeof(buf) - 1); | ||
90 | if (copy_from_user(buf, user_buf, len)) | ||
91 | return -EFAULT; | ||
92 | buf[len] = '\0'; | ||
93 | |||
94 | if (strncmp(buf, "reset", 5) == 0) { | ||
95 | if (local->ops->reset_tsf) { | ||
96 | local->ops->reset_tsf(local_to_hw(local)); | ||
97 | printk(KERN_INFO "%s: debugfs reset TSF\n", wiphy_name(local->hw.wiphy)); | ||
98 | } | ||
99 | } else { | ||
100 | tsf = simple_strtoul(buf, NULL, 0); | ||
101 | if (local->ops->set_tsf) { | ||
102 | local->ops->set_tsf(local_to_hw(local), tsf); | ||
103 | printk(KERN_INFO "%s: debugfs set TSF to %#018llx\n", wiphy_name(local->hw.wiphy), tsf); | ||
104 | } | ||
105 | } | ||
106 | |||
107 | return count; | ||
108 | } | ||
109 | |||
110 | static const struct file_operations tsf_ops = { | ||
111 | .read = tsf_read, | ||
112 | .write = tsf_write, | ||
113 | .open = mac80211_open_file_generic | ||
114 | }; | ||
115 | |||
65 | /* statistics stuff */ | 116 | /* statistics stuff */ |
66 | 117 | ||
67 | #define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \ | 118 | #define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \ |
@@ -136,8 +187,6 @@ DEBUGFS_STATS_FILE(multicast_received_frame_count, 20, "%u", | |||
136 | local->dot11MulticastReceivedFrameCount); | 187 | local->dot11MulticastReceivedFrameCount); |
137 | DEBUGFS_STATS_FILE(transmitted_frame_count, 20, "%u", | 188 | DEBUGFS_STATS_FILE(transmitted_frame_count, 20, "%u", |
138 | local->dot11TransmittedFrameCount); | 189 | local->dot11TransmittedFrameCount); |
139 | DEBUGFS_STATS_FILE(wep_undecryptable_count, 20, "%u", | ||
140 | local->dot11WEPUndecryptableCount); | ||
141 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | 190 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS |
142 | DEBUGFS_STATS_FILE(tx_handlers_drop, 20, "%u", | 191 | DEBUGFS_STATS_FILE(tx_handlers_drop, 20, "%u", |
143 | local->tx_handlers_drop); | 192 | local->tx_handlers_drop); |
@@ -204,6 +253,7 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
204 | DEBUGFS_ADD(long_retry_limit); | 253 | DEBUGFS_ADD(long_retry_limit); |
205 | DEBUGFS_ADD(total_ps_buffered); | 254 | DEBUGFS_ADD(total_ps_buffered); |
206 | DEBUGFS_ADD(wep_iv); | 255 | DEBUGFS_ADD(wep_iv); |
256 | DEBUGFS_ADD(tsf); | ||
207 | 257 | ||
208 | statsd = debugfs_create_dir("statistics", phyd); | 258 | statsd = debugfs_create_dir("statistics", phyd); |
209 | local->debugfs.statistics = statsd; | 259 | local->debugfs.statistics = statsd; |
@@ -221,7 +271,6 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
221 | DEBUGFS_STATS_ADD(received_fragment_count); | 271 | DEBUGFS_STATS_ADD(received_fragment_count); |
222 | DEBUGFS_STATS_ADD(multicast_received_frame_count); | 272 | DEBUGFS_STATS_ADD(multicast_received_frame_count); |
223 | DEBUGFS_STATS_ADD(transmitted_frame_count); | 273 | DEBUGFS_STATS_ADD(transmitted_frame_count); |
224 | DEBUGFS_STATS_ADD(wep_undecryptable_count); | ||
225 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | 274 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS |
226 | DEBUGFS_STATS_ADD(tx_handlers_drop); | 275 | DEBUGFS_STATS_ADD(tx_handlers_drop); |
227 | DEBUGFS_STATS_ADD(tx_handlers_queued); | 276 | DEBUGFS_STATS_ADD(tx_handlers_queued); |
@@ -258,6 +307,7 @@ void debugfs_hw_del(struct ieee80211_local *local) | |||
258 | DEBUGFS_DEL(long_retry_limit); | 307 | DEBUGFS_DEL(long_retry_limit); |
259 | DEBUGFS_DEL(total_ps_buffered); | 308 | DEBUGFS_DEL(total_ps_buffered); |
260 | DEBUGFS_DEL(wep_iv); | 309 | DEBUGFS_DEL(wep_iv); |
310 | DEBUGFS_DEL(tsf); | ||
261 | 311 | ||
262 | DEBUGFS_STATS_DEL(transmitted_fragment_count); | 312 | DEBUGFS_STATS_DEL(transmitted_fragment_count); |
263 | DEBUGFS_STATS_DEL(multicast_transmitted_frame_count); | 313 | DEBUGFS_STATS_DEL(multicast_transmitted_frame_count); |
@@ -268,7 +318,6 @@ void debugfs_hw_del(struct ieee80211_local *local) | |||
268 | DEBUGFS_STATS_DEL(received_fragment_count); | 318 | DEBUGFS_STATS_DEL(received_fragment_count); |
269 | DEBUGFS_STATS_DEL(multicast_received_frame_count); | 319 | DEBUGFS_STATS_DEL(multicast_received_frame_count); |
270 | DEBUGFS_STATS_DEL(transmitted_frame_count); | 320 | DEBUGFS_STATS_DEL(transmitted_frame_count); |
271 | DEBUGFS_STATS_DEL(wep_undecryptable_count); | ||
272 | DEBUGFS_STATS_DEL(num_scans); | 321 | DEBUGFS_STATS_DEL(num_scans); |
273 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | 322 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS |
274 | DEBUGFS_STATS_DEL(tx_handlers_drop); | 323 | DEBUGFS_STATS_DEL(tx_handlers_drop); |
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 6424ac565ae0..99c752588b30 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
@@ -76,6 +76,9 @@ static ssize_t key_algorithm_read(struct file *file, | |||
76 | case ALG_CCMP: | 76 | case ALG_CCMP: |
77 | alg = "CCMP\n"; | 77 | alg = "CCMP\n"; |
78 | break; | 78 | break; |
79 | case ALG_AES_CMAC: | ||
80 | alg = "AES-128-CMAC\n"; | ||
81 | break; | ||
79 | default: | 82 | default: |
80 | return 0; | 83 | return 0; |
81 | } | 84 | } |
@@ -105,6 +108,12 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, | |||
105 | len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", | 108 | len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", |
106 | tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]); | 109 | tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]); |
107 | break; | 110 | break; |
111 | case ALG_AES_CMAC: | ||
112 | tpn = key->u.aes_cmac.tx_pn; | ||
113 | len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", | ||
114 | tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], | ||
115 | tpn[5]); | ||
116 | break; | ||
108 | default: | 117 | default: |
109 | return 0; | 118 | return 0; |
110 | } | 119 | } |
@@ -142,6 +151,14 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, | |||
142 | } | 151 | } |
143 | len = p - buf; | 152 | len = p - buf; |
144 | break; | 153 | break; |
154 | case ALG_AES_CMAC: | ||
155 | rpn = key->u.aes_cmac.rx_pn; | ||
156 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
157 | "%02x%02x%02x%02x%02x%02x\n", | ||
158 | rpn[0], rpn[1], rpn[2], | ||
159 | rpn[3], rpn[4], rpn[5]); | ||
160 | len = p - buf; | ||
161 | break; | ||
145 | default: | 162 | default: |
146 | return 0; | 163 | return 0; |
147 | } | 164 | } |
@@ -156,13 +173,40 @@ static ssize_t key_replays_read(struct file *file, char __user *userbuf, | |||
156 | char buf[20]; | 173 | char buf[20]; |
157 | int len; | 174 | int len; |
158 | 175 | ||
159 | if (key->conf.alg != ALG_CCMP) | 176 | switch (key->conf.alg) { |
177 | case ALG_CCMP: | ||
178 | len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); | ||
179 | break; | ||
180 | case ALG_AES_CMAC: | ||
181 | len = scnprintf(buf, sizeof(buf), "%u\n", | ||
182 | key->u.aes_cmac.replays); | ||
183 | break; | ||
184 | default: | ||
160 | return 0; | 185 | return 0; |
161 | len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); | 186 | } |
162 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); | 187 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); |
163 | } | 188 | } |
164 | KEY_OPS(replays); | 189 | KEY_OPS(replays); |
165 | 190 | ||
191 | static ssize_t key_icverrors_read(struct file *file, char __user *userbuf, | ||
192 | size_t count, loff_t *ppos) | ||
193 | { | ||
194 | struct ieee80211_key *key = file->private_data; | ||
195 | char buf[20]; | ||
196 | int len; | ||
197 | |||
198 | switch (key->conf.alg) { | ||
199 | case ALG_AES_CMAC: | ||
200 | len = scnprintf(buf, sizeof(buf), "%u\n", | ||
201 | key->u.aes_cmac.icverrors); | ||
202 | break; | ||
203 | default: | ||
204 | return 0; | ||
205 | } | ||
206 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); | ||
207 | } | ||
208 | KEY_OPS(icverrors); | ||
209 | |||
166 | static ssize_t key_key_read(struct file *file, char __user *userbuf, | 210 | static ssize_t key_key_read(struct file *file, char __user *userbuf, |
167 | size_t count, loff_t *ppos) | 211 | size_t count, loff_t *ppos) |
168 | { | 212 | { |
@@ -222,6 +266,7 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key) | |||
222 | DEBUGFS_ADD(tx_spec); | 266 | DEBUGFS_ADD(tx_spec); |
223 | DEBUGFS_ADD(rx_spec); | 267 | DEBUGFS_ADD(rx_spec); |
224 | DEBUGFS_ADD(replays); | 268 | DEBUGFS_ADD(replays); |
269 | DEBUGFS_ADD(icverrors); | ||
225 | DEBUGFS_ADD(key); | 270 | DEBUGFS_ADD(key); |
226 | DEBUGFS_ADD(ifindex); | 271 | DEBUGFS_ADD(ifindex); |
227 | }; | 272 | }; |
@@ -243,6 +288,7 @@ void ieee80211_debugfs_key_remove(struct ieee80211_key *key) | |||
243 | DEBUGFS_DEL(tx_spec); | 288 | DEBUGFS_DEL(tx_spec); |
244 | DEBUGFS_DEL(rx_spec); | 289 | DEBUGFS_DEL(rx_spec); |
245 | DEBUGFS_DEL(replays); | 290 | DEBUGFS_DEL(replays); |
291 | DEBUGFS_DEL(icverrors); | ||
246 | DEBUGFS_DEL(key); | 292 | DEBUGFS_DEL(key); |
247 | DEBUGFS_DEL(ifindex); | 293 | DEBUGFS_DEL(ifindex); |
248 | 294 | ||
@@ -280,6 +326,35 @@ void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata) | |||
280 | sdata->common_debugfs.default_key = NULL; | 326 | sdata->common_debugfs.default_key = NULL; |
281 | } | 327 | } |
282 | 328 | ||
329 | void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata) | ||
330 | { | ||
331 | char buf[50]; | ||
332 | struct ieee80211_key *key; | ||
333 | |||
334 | if (!sdata->debugfsdir) | ||
335 | return; | ||
336 | |||
337 | /* this is running under the key lock */ | ||
338 | |||
339 | key = sdata->default_mgmt_key; | ||
340 | if (key) { | ||
341 | sprintf(buf, "../keys/%d", key->debugfs.cnt); | ||
342 | sdata->common_debugfs.default_mgmt_key = | ||
343 | debugfs_create_symlink("default_mgmt_key", | ||
344 | sdata->debugfsdir, buf); | ||
345 | } else | ||
346 | ieee80211_debugfs_key_remove_mgmt_default(sdata); | ||
347 | } | ||
348 | |||
349 | void ieee80211_debugfs_key_remove_mgmt_default(struct ieee80211_sub_if_data *sdata) | ||
350 | { | ||
351 | if (!sdata) | ||
352 | return; | ||
353 | |||
354 | debugfs_remove(sdata->common_debugfs.default_mgmt_key); | ||
355 | sdata->common_debugfs.default_mgmt_key = NULL; | ||
356 | } | ||
357 | |||
283 | void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, | 358 | void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, |
284 | struct sta_info *sta) | 359 | struct sta_info *sta) |
285 | { | 360 | { |
diff --git a/net/mac80211/debugfs_key.h b/net/mac80211/debugfs_key.h index b1a3754ee240..54717b4e1371 100644 --- a/net/mac80211/debugfs_key.h +++ b/net/mac80211/debugfs_key.h | |||
@@ -6,6 +6,10 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key); | |||
6 | void ieee80211_debugfs_key_remove(struct ieee80211_key *key); | 6 | void ieee80211_debugfs_key_remove(struct ieee80211_key *key); |
7 | void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata); | 7 | void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata); |
8 | void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata); | 8 | void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata); |
9 | void ieee80211_debugfs_key_add_mgmt_default( | ||
10 | struct ieee80211_sub_if_data *sdata); | ||
11 | void ieee80211_debugfs_key_remove_mgmt_default( | ||
12 | struct ieee80211_sub_if_data *sdata); | ||
9 | void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, | 13 | void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, |
10 | struct sta_info *sta); | 14 | struct sta_info *sta); |
11 | #else | 15 | #else |
@@ -19,6 +23,12 @@ static inline void ieee80211_debugfs_key_add_default( | |||
19 | static inline void ieee80211_debugfs_key_remove_default( | 23 | static inline void ieee80211_debugfs_key_remove_default( |
20 | struct ieee80211_sub_if_data *sdata) | 24 | struct ieee80211_sub_if_data *sdata) |
21 | {} | 25 | {} |
26 | static inline void ieee80211_debugfs_key_add_mgmt_default( | ||
27 | struct ieee80211_sub_if_data *sdata) | ||
28 | {} | ||
29 | static inline void ieee80211_debugfs_key_remove_mgmt_default( | ||
30 | struct ieee80211_sub_if_data *sdata) | ||
31 | {} | ||
22 | static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, | 32 | static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, |
23 | struct sta_info *sta) | 33 | struct sta_info *sta) |
24 | {} | 34 | {} |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index a2fbe0131312..90230c718b5b 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -67,14 +67,15 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | |||
67 | char buf[100]; | 67 | char buf[100]; |
68 | struct sta_info *sta = file->private_data; | 68 | struct sta_info *sta = file->private_data; |
69 | u32 staflags = get_sta_flags(sta); | 69 | u32 staflags = get_sta_flags(sta); |
70 | int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s", | 70 | int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s", |
71 | staflags & WLAN_STA_AUTH ? "AUTH\n" : "", | 71 | staflags & WLAN_STA_AUTH ? "AUTH\n" : "", |
72 | staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "", | 72 | staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "", |
73 | staflags & WLAN_STA_PS ? "PS\n" : "", | 73 | staflags & WLAN_STA_PS ? "PS\n" : "", |
74 | staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", | 74 | staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", |
75 | staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", | 75 | staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", |
76 | staflags & WLAN_STA_WME ? "WME\n" : "", | 76 | staflags & WLAN_STA_WME ? "WME\n" : "", |
77 | staflags & WLAN_STA_WDS ? "WDS\n" : ""); | 77 | staflags & WLAN_STA_WDS ? "WDS\n" : "", |
78 | staflags & WLAN_STA_MFP ? "MFP\n" : ""); | ||
78 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | 79 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); |
79 | } | 80 | } |
80 | STA_OPS(flags); | 81 | STA_OPS(flags); |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index c5c0c5271096..7a38d2e76ca9 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -130,14 +130,15 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
130 | } | 130 | } |
131 | } | 131 | } |
132 | 132 | ||
133 | ht_changed = local->hw.conf.ht.enabled != enable_ht || | 133 | ht_changed = conf_is_ht(&local->hw.conf) != enable_ht || |
134 | channel_type != local->hw.conf.ht.channel_type; | 134 | channel_type != local->hw.conf.channel_type; |
135 | 135 | ||
136 | local->oper_channel_type = channel_type; | 136 | local->oper_channel_type = channel_type; |
137 | local->hw.conf.ht.enabled = enable_ht; | ||
138 | 137 | ||
139 | if (ht_changed) | 138 | if (ht_changed) { |
140 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT); | 139 | /* channel_type change automatically detected */ |
140 | ieee80211_hw_config(local, 0); | ||
141 | } | ||
141 | 142 | ||
142 | /* disable HT */ | 143 | /* disable HT */ |
143 | if (!enable_ht) | 144 | if (!enable_ht) |
@@ -201,7 +202,7 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, | |||
201 | mgmt->u.action.u.addba_req.start_seq_num = | 202 | mgmt->u.action.u.addba_req.start_seq_num = |
202 | cpu_to_le16(start_seq_num << 4); | 203 | cpu_to_le16(start_seq_num << 4); |
203 | 204 | ||
204 | ieee80211_tx_skb(sdata, skb, 0); | 205 | ieee80211_tx_skb(sdata, skb, 1); |
205 | } | 206 | } |
206 | 207 | ||
207 | static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid, | 208 | static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid, |
@@ -247,7 +248,7 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d | |||
247 | mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout); | 248 | mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout); |
248 | mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); | 249 | mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); |
249 | 250 | ||
250 | ieee80211_tx_skb(sdata, skb, 0); | 251 | ieee80211_tx_skb(sdata, skb, 1); |
251 | } | 252 | } |
252 | 253 | ||
253 | static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | 254 | static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, |
@@ -290,7 +291,7 @@ static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | |||
290 | mgmt->u.action.u.delba.params = cpu_to_le16(params); | 291 | mgmt->u.action.u.delba.params = cpu_to_le16(params); |
291 | mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); | 292 | mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); |
292 | 293 | ||
293 | ieee80211_tx_skb(sdata, skb, 0); | 294 | ieee80211_tx_skb(sdata, skb, 1); |
294 | } | 295 | } |
295 | 296 | ||
296 | void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn) | 297 | void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn) |
@@ -949,7 +950,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
949 | 950 | ||
950 | /* prepare reordering buffer */ | 951 | /* prepare reordering buffer */ |
951 | tid_agg_rx->reorder_buf = | 952 | tid_agg_rx->reorder_buf = |
952 | kmalloc(buf_size * sizeof(struct sk_buff *), GFP_ATOMIC); | 953 | kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC); |
953 | if (!tid_agg_rx->reorder_buf) { | 954 | if (!tid_agg_rx->reorder_buf) { |
954 | #ifdef CONFIG_MAC80211_HT_DEBUG | 955 | #ifdef CONFIG_MAC80211_HT_DEBUG |
955 | if (net_ratelimit()) | 956 | if (net_ratelimit()) |
@@ -959,8 +960,6 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
959 | kfree(sta->ampdu_mlme.tid_rx[tid]); | 960 | kfree(sta->ampdu_mlme.tid_rx[tid]); |
960 | goto end; | 961 | goto end; |
961 | } | 962 | } |
962 | memset(tid_agg_rx->reorder_buf, 0, | ||
963 | buf_size * sizeof(struct sk_buff *)); | ||
964 | 963 | ||
965 | if (local->ops->ampdu_action) | 964 | if (local->ops->ampdu_action) |
966 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START, | 965 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START, |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f3eec989662b..eaf3603862b7 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -43,7 +43,7 @@ struct ieee80211_local; | |||
43 | 43 | ||
44 | /* Required encryption head and tailroom */ | 44 | /* Required encryption head and tailroom */ |
45 | #define IEEE80211_ENCRYPT_HEADROOM 8 | 45 | #define IEEE80211_ENCRYPT_HEADROOM 8 |
46 | #define IEEE80211_ENCRYPT_TAILROOM 12 | 46 | #define IEEE80211_ENCRYPT_TAILROOM 18 |
47 | 47 | ||
48 | /* IEEE 802.11 (Ch. 9.5 Defragmentation) requires support for concurrent | 48 | /* IEEE 802.11 (Ch. 9.5 Defragmentation) requires support for concurrent |
49 | * reception of at least three fragmented frames. This limit can be increased | 49 | * reception of at least three fragmented frames. This limit can be increased |
@@ -258,6 +258,9 @@ struct mesh_preq_queue { | |||
258 | #define IEEE80211_STA_AUTO_BSSID_SEL BIT(11) | 258 | #define IEEE80211_STA_AUTO_BSSID_SEL BIT(11) |
259 | #define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12) | 259 | #define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12) |
260 | #define IEEE80211_STA_PRIVACY_INVOKED BIT(13) | 260 | #define IEEE80211_STA_PRIVACY_INVOKED BIT(13) |
261 | #define IEEE80211_STA_TKIP_WEP_USED BIT(14) | ||
262 | #define IEEE80211_STA_CSA_RECEIVED BIT(15) | ||
263 | #define IEEE80211_STA_MFP_ENABLED BIT(16) | ||
261 | /* flags for MLME request */ | 264 | /* flags for MLME request */ |
262 | #define IEEE80211_STA_REQ_SCAN 0 | 265 | #define IEEE80211_STA_REQ_SCAN 0 |
263 | #define IEEE80211_STA_REQ_DIRECT_PROBE 1 | 266 | #define IEEE80211_STA_REQ_DIRECT_PROBE 1 |
@@ -282,7 +285,9 @@ enum ieee80211_sta_mlme_state { | |||
282 | 285 | ||
283 | struct ieee80211_if_sta { | 286 | struct ieee80211_if_sta { |
284 | struct timer_list timer; | 287 | struct timer_list timer; |
288 | struct timer_list chswitch_timer; | ||
285 | struct work_struct work; | 289 | struct work_struct work; |
290 | struct work_struct chswitch_work; | ||
286 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; | 291 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; |
287 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 292 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
288 | enum ieee80211_sta_mlme_state state; | 293 | enum ieee80211_sta_mlme_state state; |
@@ -315,11 +320,33 @@ struct ieee80211_if_sta { | |||
315 | int auth_alg; /* currently used IEEE 802.11 authentication algorithm */ | 320 | int auth_alg; /* currently used IEEE 802.11 authentication algorithm */ |
316 | int auth_transaction; | 321 | int auth_transaction; |
317 | 322 | ||
323 | enum { | ||
324 | IEEE80211_MFP_DISABLED, | ||
325 | IEEE80211_MFP_OPTIONAL, | ||
326 | IEEE80211_MFP_REQUIRED | ||
327 | } mfp; /* management frame protection */ | ||
328 | |||
318 | unsigned long ibss_join_req; | 329 | unsigned long ibss_join_req; |
319 | struct sk_buff *probe_resp; /* ProbeResp template for IBSS */ | 330 | struct sk_buff *probe_resp; /* ProbeResp template for IBSS */ |
320 | u32 supp_rates_bits[IEEE80211_NUM_BANDS]; | 331 | u32 supp_rates_bits[IEEE80211_NUM_BANDS]; |
321 | 332 | ||
322 | int wmm_last_param_set; | 333 | int wmm_last_param_set; |
334 | |||
335 | /* Extra IE data for management frames */ | ||
336 | u8 *ie_probereq; | ||
337 | size_t ie_probereq_len; | ||
338 | u8 *ie_proberesp; | ||
339 | size_t ie_proberesp_len; | ||
340 | u8 *ie_auth; | ||
341 | size_t ie_auth_len; | ||
342 | u8 *ie_assocreq; | ||
343 | size_t ie_assocreq_len; | ||
344 | u8 *ie_reassocreq; | ||
345 | size_t ie_reassocreq_len; | ||
346 | u8 *ie_deauth; | ||
347 | size_t ie_deauth_len; | ||
348 | u8 *ie_disassoc; | ||
349 | size_t ie_disassoc_len; | ||
323 | }; | 350 | }; |
324 | 351 | ||
325 | struct ieee80211_if_mesh { | 352 | struct ieee80211_if_mesh { |
@@ -404,8 +431,10 @@ struct ieee80211_sub_if_data { | |||
404 | unsigned int fragment_next; | 431 | unsigned int fragment_next; |
405 | 432 | ||
406 | #define NUM_DEFAULT_KEYS 4 | 433 | #define NUM_DEFAULT_KEYS 4 |
407 | struct ieee80211_key *keys[NUM_DEFAULT_KEYS]; | 434 | #define NUM_DEFAULT_MGMT_KEYS 2 |
435 | struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; | ||
408 | struct ieee80211_key *default_key; | 436 | struct ieee80211_key *default_key; |
437 | struct ieee80211_key *default_mgmt_key; | ||
409 | 438 | ||
410 | u16 sequence_number; | 439 | u16 sequence_number; |
411 | 440 | ||
@@ -477,6 +506,7 @@ struct ieee80211_sub_if_data { | |||
477 | } debugfs; | 506 | } debugfs; |
478 | struct { | 507 | struct { |
479 | struct dentry *default_key; | 508 | struct dentry *default_key; |
509 | struct dentry *default_mgmt_key; | ||
480 | } common_debugfs; | 510 | } common_debugfs; |
481 | 511 | ||
482 | #ifdef CONFIG_MAC80211_MESH | 512 | #ifdef CONFIG_MAC80211_MESH |
@@ -541,6 +571,7 @@ enum { | |||
541 | enum queue_stop_reason { | 571 | enum queue_stop_reason { |
542 | IEEE80211_QUEUE_STOP_REASON_DRIVER, | 572 | IEEE80211_QUEUE_STOP_REASON_DRIVER, |
543 | IEEE80211_QUEUE_STOP_REASON_PS, | 573 | IEEE80211_QUEUE_STOP_REASON_PS, |
574 | IEEE80211_QUEUE_STOP_REASON_CSA | ||
544 | }; | 575 | }; |
545 | 576 | ||
546 | /* maximum number of hardware queues we support. */ | 577 | /* maximum number of hardware queues we support. */ |
@@ -612,7 +643,9 @@ struct ieee80211_local { | |||
612 | struct crypto_blkcipher *wep_rx_tfm; | 643 | struct crypto_blkcipher *wep_rx_tfm; |
613 | u32 wep_iv; | 644 | u32 wep_iv; |
614 | 645 | ||
646 | /* see iface.c */ | ||
615 | struct list_head interfaces; | 647 | struct list_head interfaces; |
648 | struct mutex iflist_mtx; | ||
616 | 649 | ||
617 | /* | 650 | /* |
618 | * Key lock, protects sdata's key_list and sta_info's | 651 | * Key lock, protects sdata's key_list and sta_info's |
@@ -630,7 +663,7 @@ struct ieee80211_local { | |||
630 | unsigned long last_scan_completed; | 663 | unsigned long last_scan_completed; |
631 | struct delayed_work scan_work; | 664 | struct delayed_work scan_work; |
632 | struct ieee80211_sub_if_data *scan_sdata; | 665 | struct ieee80211_sub_if_data *scan_sdata; |
633 | struct ieee80211_channel *oper_channel, *scan_channel; | 666 | struct ieee80211_channel *oper_channel, *scan_channel, *csa_channel; |
634 | enum nl80211_channel_type oper_channel_type; | 667 | enum nl80211_channel_type oper_channel_type; |
635 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; | 668 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; |
636 | size_t scan_ssid_len; | 669 | size_t scan_ssid_len; |
@@ -649,7 +682,6 @@ struct ieee80211_local { | |||
649 | u32 dot11ReceivedFragmentCount; | 682 | u32 dot11ReceivedFragmentCount; |
650 | u32 dot11MulticastReceivedFrameCount; | 683 | u32 dot11MulticastReceivedFrameCount; |
651 | u32 dot11TransmittedFrameCount; | 684 | u32 dot11TransmittedFrameCount; |
652 | u32 dot11WEPUndecryptableCount; | ||
653 | 685 | ||
654 | #ifdef CONFIG_MAC80211_LEDS | 686 | #ifdef CONFIG_MAC80211_LEDS |
655 | int tx_led_counter, rx_led_counter; | 687 | int tx_led_counter, rx_led_counter; |
@@ -696,11 +728,13 @@ struct ieee80211_local { | |||
696 | unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ | 728 | unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ |
697 | 729 | ||
698 | bool powersave; | 730 | bool powersave; |
699 | int dynamic_ps_timeout; | ||
700 | struct work_struct dynamic_ps_enable_work; | 731 | struct work_struct dynamic_ps_enable_work; |
701 | struct work_struct dynamic_ps_disable_work; | 732 | struct work_struct dynamic_ps_disable_work; |
702 | struct timer_list dynamic_ps_timer; | 733 | struct timer_list dynamic_ps_timer; |
703 | 734 | ||
735 | int user_power_level; /* in dBm */ | ||
736 | int power_constr_level; /* in dBm */ | ||
737 | |||
704 | #ifdef CONFIG_MAC80211_DEBUGFS | 738 | #ifdef CONFIG_MAC80211_DEBUGFS |
705 | struct local_debugfsdentries { | 739 | struct local_debugfsdentries { |
706 | struct dentry *rcdir; | 740 | struct dentry *rcdir; |
@@ -712,6 +746,7 @@ struct ieee80211_local { | |||
712 | struct dentry *long_retry_limit; | 746 | struct dentry *long_retry_limit; |
713 | struct dentry *total_ps_buffered; | 747 | struct dentry *total_ps_buffered; |
714 | struct dentry *wep_iv; | 748 | struct dentry *wep_iv; |
749 | struct dentry *tsf; | ||
715 | struct dentry *statistics; | 750 | struct dentry *statistics; |
716 | struct local_debugfsdentries_statsdentries { | 751 | struct local_debugfsdentries_statsdentries { |
717 | struct dentry *transmitted_fragment_count; | 752 | struct dentry *transmitted_fragment_count; |
@@ -805,6 +840,7 @@ struct ieee802_11_elems { | |||
805 | u8 *country_elem; | 840 | u8 *country_elem; |
806 | u8 *pwr_constr_elem; | 841 | u8 *pwr_constr_elem; |
807 | u8 *quiet_elem; /* first quite element */ | 842 | u8 *quiet_elem; /* first quite element */ |
843 | u8 *timeout_int; | ||
808 | 844 | ||
809 | /* length of them, respectively */ | 845 | /* length of them, respectively */ |
810 | u8 ssid_len; | 846 | u8 ssid_len; |
@@ -832,6 +868,7 @@ struct ieee802_11_elems { | |||
832 | u8 pwr_constr_elem_len; | 868 | u8 pwr_constr_elem_len; |
833 | u8 quiet_elem_len; | 869 | u8 quiet_elem_len; |
834 | u8 num_of_quiet_elem; /* can be more the one */ | 870 | u8 num_of_quiet_elem; /* can be more the one */ |
871 | u8 timeout_int_len; | ||
835 | }; | 872 | }; |
836 | 873 | ||
837 | static inline struct ieee80211_local *hw_to_local( | 874 | static inline struct ieee80211_local *hw_to_local( |
@@ -875,11 +912,11 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid); | |||
875 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, | 912 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, |
876 | struct ieee80211_if_sta *ifsta); | 913 | struct ieee80211_if_sta *ifsta); |
877 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | 914 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, |
878 | u8 *bssid, u8 *addr, u64 supp_rates); | 915 | u8 *bssid, u8 *addr, u32 supp_rates); |
879 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason); | 916 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason); |
880 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); | 917 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); |
881 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); | 918 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); |
882 | u64 ieee80211_sta_get_rates(struct ieee80211_local *local, | 919 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, |
883 | struct ieee802_11_elems *elems, | 920 | struct ieee802_11_elems *elems, |
884 | enum ieee80211_band band); | 921 | enum ieee80211_band band); |
885 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 922 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
@@ -963,6 +1000,18 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
963 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1000 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
964 | struct ieee80211_mgmt *mgmt, | 1001 | struct ieee80211_mgmt *mgmt, |
965 | size_t len); | 1002 | size_t len); |
1003 | void ieee80211_chswitch_timer(unsigned long data); | ||
1004 | void ieee80211_chswitch_work(struct work_struct *work); | ||
1005 | void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, | ||
1006 | struct ieee80211_channel_sw_ie *sw_elem, | ||
1007 | struct ieee80211_bss *bss); | ||
1008 | void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | ||
1009 | u16 capab_info, u8 *pwr_constr_elem, | ||
1010 | u8 pwr_constr_elem_len); | ||
1011 | |||
1012 | /* Suspend/resume */ | ||
1013 | int __ieee80211_suspend(struct ieee80211_hw *hw); | ||
1014 | int __ieee80211_resume(struct ieee80211_hw *hw); | ||
966 | 1015 | ||
967 | /* utility functions/constants */ | 1016 | /* utility functions/constants */ |
968 | extern void *mac80211_wiphy_privid; /* for wiphy privid */ | 1017 | extern void *mac80211_wiphy_privid; /* for wiphy privid */ |
@@ -980,12 +1029,15 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
980 | void ieee802_11_parse_elems(u8 *start, size_t len, | 1029 | void ieee802_11_parse_elems(u8 *start, size_t len, |
981 | struct ieee802_11_elems *elems); | 1030 | struct ieee802_11_elems *elems); |
982 | int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq); | 1031 | int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq); |
983 | u64 ieee80211_mandatory_rates(struct ieee80211_local *local, | 1032 | u32 ieee80211_mandatory_rates(struct ieee80211_local *local, |
984 | enum ieee80211_band band); | 1033 | enum ieee80211_band band); |
985 | 1034 | ||
986 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); | 1035 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); |
987 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); | 1036 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); |
988 | void ieee80211_dynamic_ps_timer(unsigned long data); | 1037 | void ieee80211_dynamic_ps_timer(unsigned long data); |
1038 | void ieee80211_send_nullfunc(struct ieee80211_local *local, | ||
1039 | struct ieee80211_sub_if_data *sdata, | ||
1040 | int powersave); | ||
989 | 1041 | ||
990 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 1042 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
991 | enum queue_stop_reason reason); | 1043 | enum queue_stop_reason reason); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b9074824862a..00562a8b99cf 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -21,6 +21,23 @@ | |||
21 | #include "mesh.h" | 21 | #include "mesh.h" |
22 | #include "led.h" | 22 | #include "led.h" |
23 | 23 | ||
24 | /** | ||
25 | * DOC: Interface list locking | ||
26 | * | ||
27 | * The interface list in each struct ieee80211_local is protected | ||
28 | * three-fold: | ||
29 | * | ||
30 | * (1) modifications may only be done under the RTNL | ||
31 | * (2) modifications and readers are protected against each other by | ||
32 | * the iflist_mtx. | ||
33 | * (3) modifications are done in an RCU manner so atomic readers | ||
34 | * can traverse the list in RCU-safe blocks. | ||
35 | * | ||
36 | * As a consequence, reads (traversals) of the list can be protected | ||
37 | * by either the RTNL, the iflist_mtx or RCU. | ||
38 | */ | ||
39 | |||
40 | |||
24 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | 41 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) |
25 | { | 42 | { |
26 | int meshhdrlen; | 43 | int meshhdrlen; |
@@ -383,6 +400,8 @@ static int ieee80211_stop(struct net_device *dev) | |||
383 | atomic_dec(&local->iff_promiscs); | 400 | atomic_dec(&local->iff_promiscs); |
384 | 401 | ||
385 | dev_mc_unsync(local->mdev, dev); | 402 | dev_mc_unsync(local->mdev, dev); |
403 | del_timer_sync(&local->dynamic_ps_timer); | ||
404 | cancel_work_sync(&local->dynamic_ps_enable_work); | ||
386 | 405 | ||
387 | /* APs need special treatment */ | 406 | /* APs need special treatment */ |
388 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 407 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
@@ -441,6 +460,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
441 | WLAN_REASON_DEAUTH_LEAVING); | 460 | WLAN_REASON_DEAUTH_LEAVING); |
442 | 461 | ||
443 | memset(sdata->u.sta.bssid, 0, ETH_ALEN); | 462 | memset(sdata->u.sta.bssid, 0, ETH_ALEN); |
463 | del_timer_sync(&sdata->u.sta.chswitch_timer); | ||
444 | del_timer_sync(&sdata->u.sta.timer); | 464 | del_timer_sync(&sdata->u.sta.timer); |
445 | /* | 465 | /* |
446 | * If the timer fired while we waited for it, it will have | 466 | * If the timer fired while we waited for it, it will have |
@@ -450,6 +470,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
450 | * it no longer is. | 470 | * it no longer is. |
451 | */ | 471 | */ |
452 | cancel_work_sync(&sdata->u.sta.work); | 472 | cancel_work_sync(&sdata->u.sta.work); |
473 | cancel_work_sync(&sdata->u.sta.chswitch_work); | ||
453 | /* | 474 | /* |
454 | * When we get here, the interface is marked down. | 475 | * When we get here, the interface is marked down. |
455 | * Call synchronize_rcu() to wait for the RX path | 476 | * Call synchronize_rcu() to wait for the RX path |
@@ -459,7 +480,8 @@ static int ieee80211_stop(struct net_device *dev) | |||
459 | synchronize_rcu(); | 480 | synchronize_rcu(); |
460 | skb_queue_purge(&sdata->u.sta.skb_queue); | 481 | skb_queue_purge(&sdata->u.sta.skb_queue); |
461 | 482 | ||
462 | sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; | 483 | sdata->u.sta.flags &= ~(IEEE80211_STA_PRIVACY_INVOKED | |
484 | IEEE80211_STA_TKIP_WEP_USED); | ||
463 | kfree(sdata->u.sta.extra_ie); | 485 | kfree(sdata->u.sta.extra_ie); |
464 | sdata->u.sta.extra_ie = NULL; | 486 | sdata->u.sta.extra_ie = NULL; |
465 | sdata->u.sta.extra_ie_len = 0; | 487 | sdata->u.sta.extra_ie_len = 0; |
@@ -627,6 +649,13 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
627 | kfree(sdata->u.sta.assocreq_ies); | 649 | kfree(sdata->u.sta.assocreq_ies); |
628 | kfree(sdata->u.sta.assocresp_ies); | 650 | kfree(sdata->u.sta.assocresp_ies); |
629 | kfree_skb(sdata->u.sta.probe_resp); | 651 | kfree_skb(sdata->u.sta.probe_resp); |
652 | kfree(sdata->u.sta.ie_probereq); | ||
653 | kfree(sdata->u.sta.ie_proberesp); | ||
654 | kfree(sdata->u.sta.ie_auth); | ||
655 | kfree(sdata->u.sta.ie_assocreq); | ||
656 | kfree(sdata->u.sta.ie_reassocreq); | ||
657 | kfree(sdata->u.sta.ie_deauth); | ||
658 | kfree(sdata->u.sta.ie_disassoc); | ||
630 | break; | 659 | break; |
631 | case NL80211_IFTYPE_WDS: | 660 | case NL80211_IFTYPE_WDS: |
632 | case NL80211_IFTYPE_AP_VLAN: | 661 | case NL80211_IFTYPE_AP_VLAN: |
@@ -788,7 +817,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
788 | params->mesh_id_len, | 817 | params->mesh_id_len, |
789 | params->mesh_id); | 818 | params->mesh_id); |
790 | 819 | ||
820 | mutex_lock(&local->iflist_mtx); | ||
791 | list_add_tail_rcu(&sdata->list, &local->interfaces); | 821 | list_add_tail_rcu(&sdata->list, &local->interfaces); |
822 | mutex_unlock(&local->iflist_mtx); | ||
792 | 823 | ||
793 | if (new_dev) | 824 | if (new_dev) |
794 | *new_dev = ndev; | 825 | *new_dev = ndev; |
@@ -804,7 +835,10 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata) | |||
804 | { | 835 | { |
805 | ASSERT_RTNL(); | 836 | ASSERT_RTNL(); |
806 | 837 | ||
838 | mutex_lock(&sdata->local->iflist_mtx); | ||
807 | list_del_rcu(&sdata->list); | 839 | list_del_rcu(&sdata->list); |
840 | mutex_unlock(&sdata->local->iflist_mtx); | ||
841 | |||
808 | synchronize_rcu(); | 842 | synchronize_rcu(); |
809 | unregister_netdevice(sdata->dev); | 843 | unregister_netdevice(sdata->dev); |
810 | } | 844 | } |
@@ -820,7 +854,16 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) | |||
820 | ASSERT_RTNL(); | 854 | ASSERT_RTNL(); |
821 | 855 | ||
822 | list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { | 856 | list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { |
857 | /* | ||
858 | * we cannot hold the iflist_mtx across unregister_netdevice, | ||
859 | * but we only need to hold it for list modifications to lock | ||
860 | * out readers since we're under the RTNL here as all other | ||
861 | * writers. | ||
862 | */ | ||
863 | mutex_lock(&local->iflist_mtx); | ||
823 | list_del(&sdata->list); | 864 | list_del(&sdata->list); |
865 | mutex_unlock(&local->iflist_mtx); | ||
866 | |||
824 | unregister_netdevice(sdata->dev); | 867 | unregister_netdevice(sdata->dev); |
825 | } | 868 | } |
826 | } | 869 | } |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 999f7aa42326..19b480de4bbc 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include "ieee80211_i.h" | 18 | #include "ieee80211_i.h" |
19 | #include "debugfs_key.h" | 19 | #include "debugfs_key.h" |
20 | #include "aes_ccm.h" | 20 | #include "aes_ccm.h" |
21 | #include "aes_cmac.h" | ||
21 | 22 | ||
22 | 23 | ||
23 | /** | 24 | /** |
@@ -47,7 +48,6 @@ | |||
47 | */ | 48 | */ |
48 | 49 | ||
49 | static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | 50 | static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
50 | static const u8 zero_addr[ETH_ALEN]; | ||
51 | 51 | ||
52 | /* key mutex: used to synchronise todo runners */ | 52 | /* key mutex: used to synchronise todo runners */ |
53 | static DEFINE_MUTEX(key_mutex); | 53 | static DEFINE_MUTEX(key_mutex); |
@@ -108,29 +108,18 @@ static void assert_key_lock(void) | |||
108 | WARN_ON(!mutex_is_locked(&key_mutex)); | 108 | WARN_ON(!mutex_is_locked(&key_mutex)); |
109 | } | 109 | } |
110 | 110 | ||
111 | static const u8 *get_mac_for_key(struct ieee80211_key *key) | 111 | static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key) |
112 | { | 112 | { |
113 | const u8 *addr = bcast_addr; | ||
114 | |||
115 | /* | ||
116 | * If we're an AP we won't ever receive frames with a non-WEP | ||
117 | * group key so we tell the driver that by using the zero MAC | ||
118 | * address to indicate a transmit-only key. | ||
119 | */ | ||
120 | if (key->conf.alg != ALG_WEP && | ||
121 | (key->sdata->vif.type == NL80211_IFTYPE_AP || | ||
122 | key->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) | ||
123 | addr = zero_addr; | ||
124 | |||
125 | if (key->sta) | 113 | if (key->sta) |
126 | addr = key->sta->sta.addr; | 114 | return &key->sta->sta; |
127 | 115 | ||
128 | return addr; | 116 | return NULL; |
129 | } | 117 | } |
130 | 118 | ||
131 | static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | 119 | static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) |
132 | { | 120 | { |
133 | const u8 *addr; | 121 | struct ieee80211_sub_if_data *sdata; |
122 | struct ieee80211_sta *sta; | ||
134 | int ret; | 123 | int ret; |
135 | 124 | ||
136 | assert_key_lock(); | 125 | assert_key_lock(); |
@@ -139,11 +128,16 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
139 | if (!key->local->ops->set_key) | 128 | if (!key->local->ops->set_key) |
140 | return; | 129 | return; |
141 | 130 | ||
142 | addr = get_mac_for_key(key); | 131 | sta = get_sta_for_key(key); |
132 | |||
133 | sdata = key->sdata; | ||
134 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
135 | sdata = container_of(sdata->bss, | ||
136 | struct ieee80211_sub_if_data, | ||
137 | u.ap); | ||
143 | 138 | ||
144 | ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY, | 139 | ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY, |
145 | key->sdata->dev->dev_addr, addr, | 140 | &sdata->vif, sta, &key->conf); |
146 | &key->conf); | ||
147 | 141 | ||
148 | if (!ret) { | 142 | if (!ret) { |
149 | spin_lock(&todo_lock); | 143 | spin_lock(&todo_lock); |
@@ -155,12 +149,13 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
155 | printk(KERN_ERR "mac80211-%s: failed to set key " | 149 | printk(KERN_ERR "mac80211-%s: failed to set key " |
156 | "(%d, %pM) to hardware (%d)\n", | 150 | "(%d, %pM) to hardware (%d)\n", |
157 | wiphy_name(key->local->hw.wiphy), | 151 | wiphy_name(key->local->hw.wiphy), |
158 | key->conf.keyidx, addr, ret); | 152 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); |
159 | } | 153 | } |
160 | 154 | ||
161 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | 155 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) |
162 | { | 156 | { |
163 | const u8 *addr; | 157 | struct ieee80211_sub_if_data *sdata; |
158 | struct ieee80211_sta *sta; | ||
164 | int ret; | 159 | int ret; |
165 | 160 | ||
166 | assert_key_lock(); | 161 | assert_key_lock(); |
@@ -176,17 +171,22 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | |||
176 | } | 171 | } |
177 | spin_unlock(&todo_lock); | 172 | spin_unlock(&todo_lock); |
178 | 173 | ||
179 | addr = get_mac_for_key(key); | 174 | sta = get_sta_for_key(key); |
175 | sdata = key->sdata; | ||
176 | |||
177 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
178 | sdata = container_of(sdata->bss, | ||
179 | struct ieee80211_sub_if_data, | ||
180 | u.ap); | ||
180 | 181 | ||
181 | ret = key->local->ops->set_key(local_to_hw(key->local), DISABLE_KEY, | 182 | ret = key->local->ops->set_key(local_to_hw(key->local), DISABLE_KEY, |
182 | key->sdata->dev->dev_addr, addr, | 183 | &sdata->vif, sta, &key->conf); |
183 | &key->conf); | ||
184 | 184 | ||
185 | if (ret) | 185 | if (ret) |
186 | printk(KERN_ERR "mac80211-%s: failed to remove key " | 186 | printk(KERN_ERR "mac80211-%s: failed to remove key " |
187 | "(%d, %pM) from hardware (%d)\n", | 187 | "(%d, %pM) from hardware (%d)\n", |
188 | wiphy_name(key->local->hw.wiphy), | 188 | wiphy_name(key->local->hw.wiphy), |
189 | key->conf.keyidx, addr, ret); | 189 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); |
190 | 190 | ||
191 | spin_lock(&todo_lock); | 191 | spin_lock(&todo_lock); |
192 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | 192 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
@@ -216,13 +216,38 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) | |||
216 | spin_unlock_irqrestore(&sdata->local->key_lock, flags); | 216 | spin_unlock_irqrestore(&sdata->local->key_lock, flags); |
217 | } | 217 | } |
218 | 218 | ||
219 | static void | ||
220 | __ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx) | ||
221 | { | ||
222 | struct ieee80211_key *key = NULL; | ||
223 | |||
224 | if (idx >= NUM_DEFAULT_KEYS && | ||
225 | idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) | ||
226 | key = sdata->keys[idx]; | ||
227 | |||
228 | rcu_assign_pointer(sdata->default_mgmt_key, key); | ||
229 | |||
230 | if (key) | ||
231 | add_todo(key, KEY_FLAG_TODO_DEFMGMTKEY); | ||
232 | } | ||
233 | |||
234 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | ||
235 | int idx) | ||
236 | { | ||
237 | unsigned long flags; | ||
238 | |||
239 | spin_lock_irqsave(&sdata->local->key_lock, flags); | ||
240 | __ieee80211_set_default_mgmt_key(sdata, idx); | ||
241 | spin_unlock_irqrestore(&sdata->local->key_lock, flags); | ||
242 | } | ||
243 | |||
219 | 244 | ||
220 | static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | 245 | static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, |
221 | struct sta_info *sta, | 246 | struct sta_info *sta, |
222 | struct ieee80211_key *old, | 247 | struct ieee80211_key *old, |
223 | struct ieee80211_key *new) | 248 | struct ieee80211_key *new) |
224 | { | 249 | { |
225 | int idx, defkey; | 250 | int idx, defkey, defmgmtkey; |
226 | 251 | ||
227 | if (new) | 252 | if (new) |
228 | list_add(&new->list, &sdata->key_list); | 253 | list_add(&new->list, &sdata->key_list); |
@@ -238,13 +263,19 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
238 | idx = new->conf.keyidx; | 263 | idx = new->conf.keyidx; |
239 | 264 | ||
240 | defkey = old && sdata->default_key == old; | 265 | defkey = old && sdata->default_key == old; |
266 | defmgmtkey = old && sdata->default_mgmt_key == old; | ||
241 | 267 | ||
242 | if (defkey && !new) | 268 | if (defkey && !new) |
243 | __ieee80211_set_default_key(sdata, -1); | 269 | __ieee80211_set_default_key(sdata, -1); |
270 | if (defmgmtkey && !new) | ||
271 | __ieee80211_set_default_mgmt_key(sdata, -1); | ||
244 | 272 | ||
245 | rcu_assign_pointer(sdata->keys[idx], new); | 273 | rcu_assign_pointer(sdata->keys[idx], new); |
246 | if (defkey && new) | 274 | if (defkey && new) |
247 | __ieee80211_set_default_key(sdata, new->conf.keyidx); | 275 | __ieee80211_set_default_key(sdata, new->conf.keyidx); |
276 | if (defmgmtkey && new) | ||
277 | __ieee80211_set_default_mgmt_key(sdata, | ||
278 | new->conf.keyidx); | ||
248 | } | 279 | } |
249 | 280 | ||
250 | if (old) { | 281 | if (old) { |
@@ -263,7 +294,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
263 | { | 294 | { |
264 | struct ieee80211_key *key; | 295 | struct ieee80211_key *key; |
265 | 296 | ||
266 | BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS); | 297 | BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS); |
267 | 298 | ||
268 | key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); | 299 | key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); |
269 | if (!key) | 300 | if (!key) |
@@ -292,6 +323,10 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
292 | key->conf.iv_len = CCMP_HDR_LEN; | 323 | key->conf.iv_len = CCMP_HDR_LEN; |
293 | key->conf.icv_len = CCMP_MIC_LEN; | 324 | key->conf.icv_len = CCMP_MIC_LEN; |
294 | break; | 325 | break; |
326 | case ALG_AES_CMAC: | ||
327 | key->conf.iv_len = 0; | ||
328 | key->conf.icv_len = sizeof(struct ieee80211_mmie); | ||
329 | break; | ||
295 | } | 330 | } |
296 | memcpy(key->conf.key, key_data, key_len); | 331 | memcpy(key->conf.key, key_data, key_len); |
297 | INIT_LIST_HEAD(&key->list); | 332 | INIT_LIST_HEAD(&key->list); |
@@ -309,6 +344,19 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
309 | } | 344 | } |
310 | } | 345 | } |
311 | 346 | ||
347 | if (alg == ALG_AES_CMAC) { | ||
348 | /* | ||
349 | * Initialize AES key state here as an optimization so that | ||
350 | * it does not need to be initialized for every packet. | ||
351 | */ | ||
352 | key->u.aes_cmac.tfm = | ||
353 | ieee80211_aes_cmac_key_setup(key_data); | ||
354 | if (!key->u.aes_cmac.tfm) { | ||
355 | kfree(key); | ||
356 | return NULL; | ||
357 | } | ||
358 | } | ||
359 | |||
312 | return key; | 360 | return key; |
313 | } | 361 | } |
314 | 362 | ||
@@ -462,6 +510,8 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) | |||
462 | 510 | ||
463 | if (key->conf.alg == ALG_CCMP) | 511 | if (key->conf.alg == ALG_CCMP) |
464 | ieee80211_aes_key_free(key->u.ccmp.tfm); | 512 | ieee80211_aes_key_free(key->u.ccmp.tfm); |
513 | if (key->conf.alg == ALG_AES_CMAC) | ||
514 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); | ||
465 | ieee80211_debugfs_key_remove(key); | 515 | ieee80211_debugfs_key_remove(key); |
466 | 516 | ||
467 | kfree(key); | 517 | kfree(key); |
@@ -484,6 +534,7 @@ static void __ieee80211_key_todo(void) | |||
484 | list_del_init(&key->todo); | 534 | list_del_init(&key->todo); |
485 | todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS | | 535 | todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS | |
486 | KEY_FLAG_TODO_DEFKEY | | 536 | KEY_FLAG_TODO_DEFKEY | |
537 | KEY_FLAG_TODO_DEFMGMTKEY | | ||
487 | KEY_FLAG_TODO_HWACCEL_ADD | | 538 | KEY_FLAG_TODO_HWACCEL_ADD | |
488 | KEY_FLAG_TODO_HWACCEL_REMOVE | | 539 | KEY_FLAG_TODO_HWACCEL_REMOVE | |
489 | KEY_FLAG_TODO_DELETE); | 540 | KEY_FLAG_TODO_DELETE); |
@@ -501,6 +552,11 @@ static void __ieee80211_key_todo(void) | |||
501 | ieee80211_debugfs_key_add_default(key->sdata); | 552 | ieee80211_debugfs_key_add_default(key->sdata); |
502 | work_done = true; | 553 | work_done = true; |
503 | } | 554 | } |
555 | if (todoflags & KEY_FLAG_TODO_DEFMGMTKEY) { | ||
556 | ieee80211_debugfs_key_remove_mgmt_default(key->sdata); | ||
557 | ieee80211_debugfs_key_add_mgmt_default(key->sdata); | ||
558 | work_done = true; | ||
559 | } | ||
504 | if (todoflags & KEY_FLAG_TODO_HWACCEL_ADD) { | 560 | if (todoflags & KEY_FLAG_TODO_HWACCEL_ADD) { |
505 | ieee80211_key_enable_hw_accel(key); | 561 | ieee80211_key_enable_hw_accel(key); |
506 | work_done = true; | 562 | work_done = true; |
@@ -536,6 +592,7 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | |||
536 | ieee80211_key_lock(); | 592 | ieee80211_key_lock(); |
537 | 593 | ||
538 | ieee80211_debugfs_key_remove_default(sdata); | 594 | ieee80211_debugfs_key_remove_default(sdata); |
595 | ieee80211_debugfs_key_remove_mgmt_default(sdata); | ||
539 | 596 | ||
540 | spin_lock_irqsave(&sdata->local->key_lock, flags); | 597 | spin_lock_irqsave(&sdata->local->key_lock, flags); |
541 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) | 598 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 425816e0996c..215d3ef42a4f 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -46,6 +46,8 @@ struct sta_info; | |||
46 | * acceleration. | 46 | * acceleration. |
47 | * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated. | 47 | * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated. |
48 | * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs. | 48 | * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs. |
49 | * @KEY_FLAG_TODO_DEFMGMTKEY: Key is default management key and debugfs needs | ||
50 | * to be updated. | ||
49 | */ | 51 | */ |
50 | enum ieee80211_internal_key_flags { | 52 | enum ieee80211_internal_key_flags { |
51 | KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), | 53 | KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), |
@@ -54,6 +56,7 @@ enum ieee80211_internal_key_flags { | |||
54 | KEY_FLAG_TODO_HWACCEL_REMOVE = BIT(3), | 56 | KEY_FLAG_TODO_HWACCEL_REMOVE = BIT(3), |
55 | KEY_FLAG_TODO_DEFKEY = BIT(4), | 57 | KEY_FLAG_TODO_DEFKEY = BIT(4), |
56 | KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5), | 58 | KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5), |
59 | KEY_FLAG_TODO_DEFMGMTKEY = BIT(6), | ||
57 | }; | 60 | }; |
58 | 61 | ||
59 | struct tkip_ctx { | 62 | struct tkip_ctx { |
@@ -96,6 +99,16 @@ struct ieee80211_key { | |||
96 | u8 tx_crypto_buf[6 * AES_BLOCK_LEN]; | 99 | u8 tx_crypto_buf[6 * AES_BLOCK_LEN]; |
97 | u8 rx_crypto_buf[6 * AES_BLOCK_LEN]; | 100 | u8 rx_crypto_buf[6 * AES_BLOCK_LEN]; |
98 | } ccmp; | 101 | } ccmp; |
102 | struct { | ||
103 | u8 tx_pn[6]; | ||
104 | u8 rx_pn[6]; | ||
105 | struct crypto_cipher *tfm; | ||
106 | u32 replays; /* dot11RSNAStatsCMACReplays */ | ||
107 | u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ | ||
108 | /* scratch buffers for virt_to_page() (crypto API) */ | ||
109 | u8 tx_crypto_buf[2 * AES_BLOCK_LEN]; | ||
110 | u8 rx_crypto_buf[2 * AES_BLOCK_LEN]; | ||
111 | } aes_cmac; | ||
99 | } u; | 112 | } u; |
100 | 113 | ||
101 | /* number of times this key has been used */ | 114 | /* number of times this key has been used */ |
@@ -114,6 +127,7 @@ struct ieee80211_key { | |||
114 | struct dentry *tx_spec; | 127 | struct dentry *tx_spec; |
115 | struct dentry *rx_spec; | 128 | struct dentry *rx_spec; |
116 | struct dentry *replays; | 129 | struct dentry *replays; |
130 | struct dentry *icverrors; | ||
117 | struct dentry *key; | 131 | struct dentry *key; |
118 | struct dentry *ifindex; | 132 | struct dentry *ifindex; |
119 | int cnt; | 133 | int cnt; |
@@ -140,6 +154,8 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
140 | struct sta_info *sta); | 154 | struct sta_info *sta); |
141 | void ieee80211_key_free(struct ieee80211_key *key); | 155 | void ieee80211_key_free(struct ieee80211_key *key); |
142 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); | 156 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); |
157 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | ||
158 | int idx); | ||
143 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); | 159 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); |
144 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); | 160 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); |
145 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); | 161 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 24b14363d6e7..a109c06e8e4e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -168,7 +168,6 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | |||
168 | return 0; | 168 | return 0; |
169 | 169 | ||
170 | memset(&conf, 0, sizeof(conf)); | 170 | memset(&conf, 0, sizeof(conf)); |
171 | conf.changed = changed; | ||
172 | 171 | ||
173 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 172 | if (sdata->vif.type == NL80211_IFTYPE_STATION || |
174 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 173 | sdata->vif.type == NL80211_IFTYPE_ADHOC) |
@@ -176,16 +175,57 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | |||
176 | else if (sdata->vif.type == NL80211_IFTYPE_AP) | 175 | else if (sdata->vif.type == NL80211_IFTYPE_AP) |
177 | conf.bssid = sdata->dev->dev_addr; | 176 | conf.bssid = sdata->dev->dev_addr; |
178 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 177 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
179 | u8 zero[ETH_ALEN] = { 0 }; | 178 | static const u8 zero[ETH_ALEN] = { 0 }; |
180 | conf.bssid = zero; | 179 | conf.bssid = zero; |
181 | } else { | 180 | } else { |
182 | WARN_ON(1); | 181 | WARN_ON(1); |
183 | return -EINVAL; | 182 | return -EINVAL; |
184 | } | 183 | } |
185 | 184 | ||
185 | switch (sdata->vif.type) { | ||
186 | case NL80211_IFTYPE_AP: | ||
187 | case NL80211_IFTYPE_ADHOC: | ||
188 | case NL80211_IFTYPE_MESH_POINT: | ||
189 | break; | ||
190 | default: | ||
191 | /* do not warn to simplify caller in scan.c */ | ||
192 | changed &= ~IEEE80211_IFCC_BEACON_ENABLED; | ||
193 | if (WARN_ON(changed & IEEE80211_IFCC_BEACON)) | ||
194 | return -EINVAL; | ||
195 | changed &= ~IEEE80211_IFCC_BEACON; | ||
196 | break; | ||
197 | } | ||
198 | |||
199 | if (changed & IEEE80211_IFCC_BEACON_ENABLED) { | ||
200 | if (local->sw_scanning) { | ||
201 | conf.enable_beacon = false; | ||
202 | } else { | ||
203 | /* | ||
204 | * Beacon should be enabled, but AP mode must | ||
205 | * check whether there is a beacon configured. | ||
206 | */ | ||
207 | switch (sdata->vif.type) { | ||
208 | case NL80211_IFTYPE_AP: | ||
209 | conf.enable_beacon = | ||
210 | !!rcu_dereference(sdata->u.ap.beacon); | ||
211 | break; | ||
212 | case NL80211_IFTYPE_ADHOC: | ||
213 | case NL80211_IFTYPE_MESH_POINT: | ||
214 | conf.enable_beacon = true; | ||
215 | break; | ||
216 | default: | ||
217 | /* not reached */ | ||
218 | WARN_ON(1); | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | |||
186 | if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID))) | 224 | if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID))) |
187 | return -EINVAL; | 225 | return -EINVAL; |
188 | 226 | ||
227 | conf.changed = changed; | ||
228 | |||
189 | return local->ops->config_interface(local_to_hw(local), | 229 | return local->ops->config_interface(local_to_hw(local), |
190 | &sdata->vif, &conf); | 230 | &sdata->vif, &conf); |
191 | } | 231 | } |
@@ -208,26 +248,22 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
208 | } | 248 | } |
209 | 249 | ||
210 | if (chan != local->hw.conf.channel || | 250 | if (chan != local->hw.conf.channel || |
211 | channel_type != local->hw.conf.ht.channel_type) { | 251 | channel_type != local->hw.conf.channel_type) { |
212 | local->hw.conf.channel = chan; | 252 | local->hw.conf.channel = chan; |
213 | local->hw.conf.ht.channel_type = channel_type; | 253 | local->hw.conf.channel_type = channel_type; |
214 | switch (channel_type) { | ||
215 | case NL80211_CHAN_NO_HT: | ||
216 | local->hw.conf.ht.enabled = false; | ||
217 | break; | ||
218 | case NL80211_CHAN_HT20: | ||
219 | case NL80211_CHAN_HT40MINUS: | ||
220 | case NL80211_CHAN_HT40PLUS: | ||
221 | local->hw.conf.ht.enabled = true; | ||
222 | break; | ||
223 | } | ||
224 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; | 254 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; |
225 | } | 255 | } |
226 | 256 | ||
227 | if (!local->hw.conf.power_level) | 257 | if (local->sw_scanning) |
228 | power = chan->max_power; | 258 | power = chan->max_power; |
229 | else | 259 | else |
230 | power = min(chan->max_power, local->hw.conf.power_level); | 260 | power = local->power_constr_level ? |
261 | (chan->max_power - local->power_constr_level) : | ||
262 | chan->max_power; | ||
263 | |||
264 | if (local->user_power_level) | ||
265 | power = min(power, local->user_power_level); | ||
266 | |||
231 | if (local->hw.conf.power_level != power) { | 267 | if (local->hw.conf.power_level != power) { |
232 | changed |= IEEE80211_CONF_CHANGE_POWER; | 268 | changed |= IEEE80211_CONF_CHANGE_POWER; |
233 | local->hw.conf.power_level = power; | 269 | local->hw.conf.power_level = power; |
@@ -722,6 +758,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
722 | local->hw.conf.radio_enabled = true; | 758 | local->hw.conf.radio_enabled = true; |
723 | 759 | ||
724 | INIT_LIST_HEAD(&local->interfaces); | 760 | INIT_LIST_HEAD(&local->interfaces); |
761 | mutex_init(&local->iflist_mtx); | ||
725 | 762 | ||
726 | spin_lock_init(&local->key_lock); | 763 | spin_lock_init(&local->key_lock); |
727 | 764 | ||
@@ -822,7 +859,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
822 | mdev->set_multicast_list = ieee80211_master_set_multicast_list; | 859 | mdev->set_multicast_list = ieee80211_master_set_multicast_list; |
823 | 860 | ||
824 | local->hw.workqueue = | 861 | local->hw.workqueue = |
825 | create_freezeable_workqueue(wiphy_name(local->hw.wiphy)); | 862 | create_singlethread_workqueue(wiphy_name(local->hw.wiphy)); |
826 | if (!local->hw.workqueue) { | 863 | if (!local->hw.workqueue) { |
827 | result = -ENOMEM; | 864 | result = -ENOMEM; |
828 | goto fail_workqueue; | 865 | goto fail_workqueue; |
@@ -972,6 +1009,8 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) | |||
972 | { | 1009 | { |
973 | struct ieee80211_local *local = hw_to_local(hw); | 1010 | struct ieee80211_local *local = hw_to_local(hw); |
974 | 1011 | ||
1012 | mutex_destroy(&local->iflist_mtx); | ||
1013 | |||
975 | wiphy_free(local->hw.wiphy); | 1014 | wiphy_free(local->hw.wiphy); |
976 | } | 1015 | } |
977 | EXPORT_SYMBOL(ieee80211_free_hw); | 1016 | EXPORT_SYMBOL(ieee80211_free_hw); |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 82f568e94365..8a1fcaeee4f2 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -442,7 +442,8 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
442 | 442 | ||
443 | ifmsh->housekeeping = true; | 443 | ifmsh->housekeeping = true; |
444 | queue_work(local->hw.workqueue, &ifmsh->work); | 444 | queue_work(local->hw.workqueue, &ifmsh->work); |
445 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); | 445 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | |
446 | IEEE80211_IFCC_BEACON_ENABLED); | ||
446 | } | 447 | } |
447 | 448 | ||
448 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | 449 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) |
@@ -476,7 +477,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
476 | struct ieee80211_local *local = sdata->local; | 477 | struct ieee80211_local *local = sdata->local; |
477 | struct ieee802_11_elems elems; | 478 | struct ieee802_11_elems elems; |
478 | struct ieee80211_channel *channel; | 479 | struct ieee80211_channel *channel; |
479 | u64 supp_rates = 0; | 480 | u32 supp_rates = 0; |
480 | size_t baselen; | 481 | size_t baselen; |
481 | int freq; | 482 | int freq; |
482 | enum ieee80211_band band = rx_status->band; | 483 | enum ieee80211_band band = rx_status->band; |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index c197ab545e54..9e064ee98ee0 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -24,15 +24,15 @@ | |||
24 | * | 24 | * |
25 | * | 25 | * |
26 | * | 26 | * |
27 | * @MESH_PATH_ACTIVE: the mesh path is can be used for forwarding | 27 | * @MESH_PATH_ACTIVE: the mesh path can be used for forwarding |
28 | * @MESH_PATH_RESOLVED: the discovery process is running for this mesh path | 28 | * @MESH_PATH_RESOLVING: the discovery process is running for this mesh path |
29 | * @MESH_PATH_DSN_VALID: the mesh path contains a valid destination sequence | 29 | * @MESH_PATH_DSN_VALID: the mesh path contains a valid destination sequence |
30 | * number | 30 | * number |
31 | * @MESH_PATH_FIXED: the mesh path has been manually set and should not be | 31 | * @MESH_PATH_FIXED: the mesh path has been manually set and should not be |
32 | * modified | 32 | * modified |
33 | * @MESH_PATH_RESOLVED: the mesh path can has been resolved | 33 | * @MESH_PATH_RESOLVED: the mesh path can has been resolved |
34 | * | 34 | * |
35 | * MESH_PATH_RESOLVED and MESH_PATH_DELETE are used by the mesh path timer to | 35 | * MESH_PATH_RESOLVED is used by the mesh path timer to |
36 | * decide when to stop or cancel the mesh path discovery. | 36 | * decide when to stop or cancel the mesh path discovery. |
37 | */ | 37 | */ |
38 | enum mesh_path_flags { | 38 | enum mesh_path_flags { |
@@ -236,14 +236,13 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | |||
236 | struct ieee80211_mgmt *mgmt, size_t len); | 236 | struct ieee80211_mgmt *mgmt, size_t len); |
237 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata); | 237 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata); |
238 | /* Mesh plinks */ | 238 | /* Mesh plinks */ |
239 | void mesh_neighbour_update(u8 *hw_addr, u64 rates, | 239 | void mesh_neighbour_update(u8 *hw_addr, u32 rates, |
240 | struct ieee80211_sub_if_data *sdata, bool add); | 240 | struct ieee80211_sub_if_data *sdata, bool add); |
241 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie); | 241 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie); |
242 | void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); | 242 | void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); |
243 | void mesh_plink_broken(struct sta_info *sta); | 243 | void mesh_plink_broken(struct sta_info *sta); |
244 | void mesh_plink_deactivate(struct sta_info *sta); | 244 | void mesh_plink_deactivate(struct sta_info *sta); |
245 | int mesh_plink_open(struct sta_info *sta); | 245 | int mesh_plink_open(struct sta_info *sta); |
246 | int mesh_plink_close(struct sta_info *sta); | ||
247 | void mesh_plink_block(struct sta_info *sta); | 246 | void mesh_plink_block(struct sta_info *sta); |
248 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | 247 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, |
249 | struct ieee80211_mgmt *mgmt, size_t len, | 248 | struct ieee80211_mgmt *mgmt, size_t len, |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 71fe60961230..4f862b2a0041 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -149,7 +149,7 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | |||
149 | pos += ETH_ALEN; | 149 | pos += ETH_ALEN; |
150 | memcpy(pos, &dst_dsn, 4); | 150 | memcpy(pos, &dst_dsn, 4); |
151 | 151 | ||
152 | ieee80211_tx_skb(sdata, skb, 0); | 152 | ieee80211_tx_skb(sdata, skb, 1); |
153 | return 0; | 153 | return 0; |
154 | } | 154 | } |
155 | 155 | ||
@@ -198,7 +198,7 @@ int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, | |||
198 | pos += ETH_ALEN; | 198 | pos += ETH_ALEN; |
199 | memcpy(pos, &dst_dsn, 4); | 199 | memcpy(pos, &dst_dsn, 4); |
200 | 200 | ||
201 | ieee80211_tx_skb(sdata, skb, 0); | 201 | ieee80211_tx_skb(sdata, skb, 1); |
202 | return 0; | 202 | return 0; |
203 | } | 203 | } |
204 | 204 | ||
@@ -759,7 +759,7 @@ enddiscovery: | |||
759 | } | 759 | } |
760 | 760 | ||
761 | /** | 761 | /** |
762 | * ieee80211s_lookup_nexthop - put the appropriate next hop on a mesh frame | 762 | * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame |
763 | * | 763 | * |
764 | * @skb: 802.11 frame to be sent | 764 | * @skb: 802.11 frame to be sent |
765 | * @sdata: network subif the frame will be sent through | 765 | * @sdata: network subif the frame will be sent through |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 1159bdb4119c..a8bbdeca013a 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -93,7 +93,7 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta) | |||
93 | * on it in the lifecycle management section! | 93 | * on it in the lifecycle management section! |
94 | */ | 94 | */ |
95 | static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | 95 | static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, |
96 | u8 *hw_addr, u64 rates) | 96 | u8 *hw_addr, u32 rates) |
97 | { | 97 | { |
98 | struct ieee80211_local *local = sdata->local; | 98 | struct ieee80211_local *local = sdata->local; |
99 | struct sta_info *sta; | 99 | struct sta_info *sta; |
@@ -218,11 +218,11 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
218 | memcpy(pos, &reason, 2); | 218 | memcpy(pos, &reason, 2); |
219 | } | 219 | } |
220 | 220 | ||
221 | ieee80211_tx_skb(sdata, skb, 0); | 221 | ieee80211_tx_skb(sdata, skb, 1); |
222 | return 0; | 222 | return 0; |
223 | } | 223 | } |
224 | 224 | ||
225 | void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct ieee80211_sub_if_data *sdata, | 225 | void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data *sdata, |
226 | bool peer_accepting_plinks) | 226 | bool peer_accepting_plinks) |
227 | { | 227 | { |
228 | struct ieee80211_local *local = sdata->local; | 228 | struct ieee80211_local *local = sdata->local; |
@@ -361,36 +361,6 @@ void mesh_plink_block(struct sta_info *sta) | |||
361 | spin_unlock_bh(&sta->lock); | 361 | spin_unlock_bh(&sta->lock); |
362 | } | 362 | } |
363 | 363 | ||
364 | int mesh_plink_close(struct sta_info *sta) | ||
365 | { | ||
366 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
367 | __le16 llid, plid, reason; | ||
368 | |||
369 | mpl_dbg("Mesh plink: closing link with %pM\n", sta->sta.addr); | ||
370 | spin_lock_bh(&sta->lock); | ||
371 | sta->reason = cpu_to_le16(MESH_LINK_CANCELLED); | ||
372 | reason = sta->reason; | ||
373 | |||
374 | if (sta->plink_state == PLINK_LISTEN || | ||
375 | sta->plink_state == PLINK_BLOCKED) { | ||
376 | mesh_plink_fsm_restart(sta); | ||
377 | spin_unlock_bh(&sta->lock); | ||
378 | return 0; | ||
379 | } else if (sta->plink_state == PLINK_ESTAB) { | ||
380 | __mesh_plink_deactivate(sta); | ||
381 | /* The timer should not be running */ | ||
382 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | ||
383 | } else if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) | ||
384 | sta->ignore_plink_timer = true; | ||
385 | |||
386 | sta->plink_state = PLINK_HOLDING; | ||
387 | llid = sta->llid; | ||
388 | plid = sta->plid; | ||
389 | spin_unlock_bh(&sta->lock); | ||
390 | mesh_plink_frame_tx(sta->sdata, PLINK_CLOSE, sta->sta.addr, llid, | ||
391 | plid, reason); | ||
392 | return 0; | ||
393 | } | ||
394 | 364 | ||
395 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, | 365 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, |
396 | size_t len, struct ieee80211_rx_status *rx_status) | 366 | size_t len, struct ieee80211_rx_status *rx_status) |
@@ -477,7 +447,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
477 | spin_lock_bh(&sta->lock); | 447 | spin_lock_bh(&sta->lock); |
478 | } else if (!sta) { | 448 | } else if (!sta) { |
479 | /* ftype == PLINK_OPEN */ | 449 | /* ftype == PLINK_OPEN */ |
480 | u64 rates; | 450 | u32 rates; |
481 | if (!mesh_plink_free_count(sdata)) { | 451 | if (!mesh_plink_free_count(sdata)) { |
482 | mpl_dbg("Mesh plink error: no more free plinks\n"); | 452 | mpl_dbg("Mesh plink error: no more free plinks\n"); |
483 | rcu_read_unlock(); | 453 | rcu_read_unlock(); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2b890af01ba4..9d51e278c1e5 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * BSS client mode implementation | 2 | * BSS client mode implementation |
3 | * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> | 3 | * Copyright 2003-2008, Jouni Malinen <j@w1.fi> |
4 | * Copyright 2004, Instant802 Networks, Inc. | 4 | * Copyright 2004, Instant802 Networks, Inc. |
5 | * Copyright 2005, Devicescape Software, Inc. | 5 | * Copyright 2005, Devicescape Software, Inc. |
6 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 6 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
@@ -73,7 +73,7 @@ static u8 *ieee80211_bss_get_ie(struct ieee80211_bss *bss, u8 ie) | |||
73 | 73 | ||
74 | static int ieee80211_compatible_rates(struct ieee80211_bss *bss, | 74 | static int ieee80211_compatible_rates(struct ieee80211_bss *bss, |
75 | struct ieee80211_supported_band *sband, | 75 | struct ieee80211_supported_band *sband, |
76 | u64 *rates) | 76 | u32 *rates) |
77 | { | 77 | { |
78 | int i, j, count; | 78 | int i, j, count; |
79 | *rates = 0; | 79 | *rates = 0; |
@@ -93,14 +93,14 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss, | |||
93 | } | 93 | } |
94 | 94 | ||
95 | /* also used by mesh code */ | 95 | /* also used by mesh code */ |
96 | u64 ieee80211_sta_get_rates(struct ieee80211_local *local, | 96 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, |
97 | struct ieee802_11_elems *elems, | 97 | struct ieee802_11_elems *elems, |
98 | enum ieee80211_band band) | 98 | enum ieee80211_band band) |
99 | { | 99 | { |
100 | struct ieee80211_supported_band *sband; | 100 | struct ieee80211_supported_band *sband; |
101 | struct ieee80211_rate *bitrates; | 101 | struct ieee80211_rate *bitrates; |
102 | size_t num_rates; | 102 | size_t num_rates; |
103 | u64 supp_rates; | 103 | u32 supp_rates; |
104 | int i, j; | 104 | int i, j; |
105 | sband = local->hw.wiphy->bands[band]; | 105 | sband = local->hw.wiphy->bands[band]; |
106 | 106 | ||
@@ -131,6 +131,12 @@ u64 ieee80211_sta_get_rates(struct ieee80211_local *local, | |||
131 | 131 | ||
132 | /* frame sending functions */ | 132 | /* frame sending functions */ |
133 | 133 | ||
134 | static void add_extra_ies(struct sk_buff *skb, u8 *ies, size_t ies_len) | ||
135 | { | ||
136 | if (ies) | ||
137 | memcpy(skb_put(skb, ies_len), ies, ies_len); | ||
138 | } | ||
139 | |||
134 | /* also used by scanning code */ | 140 | /* also used by scanning code */ |
135 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 141 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
136 | u8 *ssid, size_t ssid_len) | 142 | u8 *ssid, size_t ssid_len) |
@@ -142,7 +148,8 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
142 | u8 *pos, *supp_rates, *esupp_rates = NULL; | 148 | u8 *pos, *supp_rates, *esupp_rates = NULL; |
143 | int i; | 149 | int i; |
144 | 150 | ||
145 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200); | 151 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + |
152 | sdata->u.sta.ie_probereq_len); | ||
146 | if (!skb) { | 153 | if (!skb) { |
147 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | 154 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " |
148 | "request\n", sdata->dev->name); | 155 | "request\n", sdata->dev->name); |
@@ -189,6 +196,9 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
189 | *pos = rate->bitrate / 5; | 196 | *pos = rate->bitrate / 5; |
190 | } | 197 | } |
191 | 198 | ||
199 | add_extra_ies(skb, sdata->u.sta.ie_probereq, | ||
200 | sdata->u.sta.ie_probereq_len); | ||
201 | |||
192 | ieee80211_tx_skb(sdata, skb, 0); | 202 | ieee80211_tx_skb(sdata, skb, 0); |
193 | } | 203 | } |
194 | 204 | ||
@@ -202,7 +212,8 @@ static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
202 | struct ieee80211_mgmt *mgmt; | 212 | struct ieee80211_mgmt *mgmt; |
203 | 213 | ||
204 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 214 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
205 | sizeof(*mgmt) + 6 + extra_len); | 215 | sizeof(*mgmt) + 6 + extra_len + |
216 | sdata->u.sta.ie_auth_len); | ||
206 | if (!skb) { | 217 | if (!skb) { |
207 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | 218 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " |
208 | "frame\n", sdata->dev->name); | 219 | "frame\n", sdata->dev->name); |
@@ -225,6 +236,7 @@ static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
225 | mgmt->u.auth.status_code = cpu_to_le16(0); | 236 | mgmt->u.auth.status_code = cpu_to_le16(0); |
226 | if (extra) | 237 | if (extra) |
227 | memcpy(skb_put(skb, extra_len), extra, extra_len); | 238 | memcpy(skb_put(skb, extra_len), extra, extra_len); |
239 | add_extra_ies(skb, sdata->u.sta.ie_auth, sdata->u.sta.ie_auth_len); | ||
228 | 240 | ||
229 | ieee80211_tx_skb(sdata, skb, encrypt); | 241 | ieee80211_tx_skb(sdata, skb, encrypt); |
230 | } | 242 | } |
@@ -235,17 +247,26 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
235 | struct ieee80211_local *local = sdata->local; | 247 | struct ieee80211_local *local = sdata->local; |
236 | struct sk_buff *skb; | 248 | struct sk_buff *skb; |
237 | struct ieee80211_mgmt *mgmt; | 249 | struct ieee80211_mgmt *mgmt; |
238 | u8 *pos, *ies, *ht_ie; | 250 | u8 *pos, *ies, *ht_ie, *e_ies; |
239 | int i, len, count, rates_len, supp_rates_len; | 251 | int i, len, count, rates_len, supp_rates_len; |
240 | u16 capab; | 252 | u16 capab; |
241 | struct ieee80211_bss *bss; | 253 | struct ieee80211_bss *bss; |
242 | int wmm = 0; | 254 | int wmm = 0; |
243 | struct ieee80211_supported_band *sband; | 255 | struct ieee80211_supported_band *sband; |
244 | u64 rates = 0; | 256 | u32 rates = 0; |
257 | size_t e_ies_len; | ||
258 | |||
259 | if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { | ||
260 | e_ies = sdata->u.sta.ie_reassocreq; | ||
261 | e_ies_len = sdata->u.sta.ie_reassocreq_len; | ||
262 | } else { | ||
263 | e_ies = sdata->u.sta.ie_assocreq; | ||
264 | e_ies_len = sdata->u.sta.ie_assocreq_len; | ||
265 | } | ||
245 | 266 | ||
246 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 267 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
247 | sizeof(*mgmt) + 200 + ifsta->extra_ie_len + | 268 | sizeof(*mgmt) + 200 + ifsta->extra_ie_len + |
248 | ifsta->ssid_len); | 269 | ifsta->ssid_len + e_ies_len); |
249 | if (!skb) { | 270 | if (!skb) { |
250 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | 271 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " |
251 | "frame\n", sdata->dev->name); | 272 | "frame\n", sdata->dev->name); |
@@ -391,10 +412,17 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
391 | } | 412 | } |
392 | 413 | ||
393 | /* wmm support is a must to HT */ | 414 | /* wmm support is a must to HT */ |
415 | /* | ||
416 | * IEEE802.11n does not allow TKIP/WEP as pairwise | ||
417 | * ciphers in HT mode. We still associate in non-ht | ||
418 | * mode (11a/b/g) if any one of these ciphers is | ||
419 | * configured as pairwise. | ||
420 | */ | ||
394 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && | 421 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && |
395 | sband->ht_cap.ht_supported && | 422 | sband->ht_cap.ht_supported && |
396 | (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) && | 423 | (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) && |
397 | ht_ie[1] >= sizeof(struct ieee80211_ht_info)) { | 424 | ht_ie[1] >= sizeof(struct ieee80211_ht_info) && |
425 | (!(ifsta->flags & IEEE80211_STA_TKIP_WEP_USED))) { | ||
398 | struct ieee80211_ht_info *ht_info = | 426 | struct ieee80211_ht_info *ht_info = |
399 | (struct ieee80211_ht_info *)(ht_ie + 2); | 427 | (struct ieee80211_ht_info *)(ht_ie + 2); |
400 | u16 cap = sband->ht_cap.cap; | 428 | u16 cap = sband->ht_cap.cap; |
@@ -429,6 +457,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
429 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | 457 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); |
430 | } | 458 | } |
431 | 459 | ||
460 | add_extra_ies(skb, e_ies, e_ies_len); | ||
461 | |||
432 | kfree(ifsta->assocreq_ies); | 462 | kfree(ifsta->assocreq_ies); |
433 | ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; | 463 | ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; |
434 | ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); | 464 | ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); |
@@ -446,8 +476,19 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
446 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 476 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
447 | struct sk_buff *skb; | 477 | struct sk_buff *skb; |
448 | struct ieee80211_mgmt *mgmt; | 478 | struct ieee80211_mgmt *mgmt; |
479 | u8 *ies; | ||
480 | size_t ies_len; | ||
449 | 481 | ||
450 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); | 482 | if (stype == IEEE80211_STYPE_DEAUTH) { |
483 | ies = sdata->u.sta.ie_deauth; | ||
484 | ies_len = sdata->u.sta.ie_deauth_len; | ||
485 | } else { | ||
486 | ies = sdata->u.sta.ie_disassoc; | ||
487 | ies_len = sdata->u.sta.ie_disassoc_len; | ||
488 | } | ||
489 | |||
490 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + | ||
491 | ies_len); | ||
451 | if (!skb) { | 492 | if (!skb) { |
452 | printk(KERN_DEBUG "%s: failed to allocate buffer for " | 493 | printk(KERN_DEBUG "%s: failed to allocate buffer for " |
453 | "deauth/disassoc frame\n", sdata->dev->name); | 494 | "deauth/disassoc frame\n", sdata->dev->name); |
@@ -465,7 +506,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
465 | /* u.deauth.reason_code == u.disassoc.reason_code */ | 506 | /* u.deauth.reason_code == u.disassoc.reason_code */ |
466 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); | 507 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); |
467 | 508 | ||
468 | ieee80211_tx_skb(sdata, skb, 0); | 509 | add_extra_ies(skb, ies, ies_len); |
510 | |||
511 | ieee80211_tx_skb(sdata, skb, ifsta->flags & IEEE80211_STA_MFP_ENABLED); | ||
469 | } | 512 | } |
470 | 513 | ||
471 | /* MLME */ | 514 | /* MLME */ |
@@ -568,6 +611,30 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
568 | } | 611 | } |
569 | } | 612 | } |
570 | 613 | ||
614 | static bool check_tim(struct ieee802_11_elems *elems, u16 aid, bool *is_mc) | ||
615 | { | ||
616 | u8 mask; | ||
617 | u8 index, indexn1, indexn2; | ||
618 | struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie *) elems->tim; | ||
619 | |||
620 | aid &= 0x3fff; | ||
621 | index = aid / 8; | ||
622 | mask = 1 << (aid & 7); | ||
623 | |||
624 | if (tim->bitmap_ctrl & 0x01) | ||
625 | *is_mc = true; | ||
626 | |||
627 | indexn1 = tim->bitmap_ctrl & 0xfe; | ||
628 | indexn2 = elems->tim_len + indexn1 - 4; | ||
629 | |||
630 | if (index < indexn1 || index > indexn2) | ||
631 | return false; | ||
632 | |||
633 | index -= indexn1; | ||
634 | |||
635 | return !!(tim->virtual_map[index] & mask); | ||
636 | } | ||
637 | |||
571 | static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | 638 | static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, |
572 | u16 capab, bool erp_valid, u8 erp) | 639 | u16 capab, bool erp_valid, u8 erp) |
573 | { | 640 | { |
@@ -745,13 +812,16 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
745 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); | 812 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); |
746 | 813 | ||
747 | if (local->powersave) { | 814 | if (local->powersave) { |
748 | if (local->dynamic_ps_timeout > 0) | 815 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) && |
816 | local->hw.conf.dynamic_ps_timeout > 0) { | ||
749 | mod_timer(&local->dynamic_ps_timer, jiffies + | 817 | mod_timer(&local->dynamic_ps_timer, jiffies + |
750 | msecs_to_jiffies(local->dynamic_ps_timeout)); | 818 | msecs_to_jiffies( |
751 | else { | 819 | local->hw.conf.dynamic_ps_timeout)); |
820 | } else { | ||
821 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | ||
822 | ieee80211_send_nullfunc(local, sdata, 1); | ||
752 | conf->flags |= IEEE80211_CONF_PS; | 823 | conf->flags |= IEEE80211_CONF_PS; |
753 | ieee80211_hw_config(local, | 824 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
754 | IEEE80211_CONF_CHANGE_PS); | ||
755 | } | 825 | } |
756 | } | 826 | } |
757 | 827 | ||
@@ -868,9 +938,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
868 | 938 | ||
869 | rcu_read_unlock(); | 939 | rcu_read_unlock(); |
870 | 940 | ||
871 | local->hw.conf.ht.enabled = false; | 941 | /* channel(_type) changes are handled by ieee80211_hw_config */ |
872 | local->oper_channel_type = NL80211_CHAN_NO_HT; | 942 | local->oper_channel_type = NL80211_CHAN_NO_HT; |
873 | config_changed |= IEEE80211_CONF_CHANGE_HT; | 943 | |
944 | local->power_constr_level = 0; | ||
874 | 945 | ||
875 | del_timer_sync(&local->dynamic_ps_timer); | 946 | del_timer_sync(&local->dynamic_ps_timer); |
876 | cancel_work_sync(&local->dynamic_ps_enable_work); | 947 | cancel_work_sync(&local->dynamic_ps_enable_work); |
@@ -1211,7 +1282,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1211 | struct ieee80211_local *local = sdata->local; | 1282 | struct ieee80211_local *local = sdata->local; |
1212 | struct ieee80211_supported_band *sband; | 1283 | struct ieee80211_supported_band *sband; |
1213 | struct sta_info *sta; | 1284 | struct sta_info *sta; |
1214 | u64 rates, basic_rates; | 1285 | u32 rates, basic_rates; |
1215 | u16 capab_info, status_code, aid; | 1286 | u16 capab_info, status_code, aid; |
1216 | struct ieee802_11_elems elems; | 1287 | struct ieee802_11_elems elems; |
1217 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 1288 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
@@ -1242,6 +1313,24 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1242 | sdata->dev->name, reassoc ? "Rea" : "A", mgmt->sa, | 1313 | sdata->dev->name, reassoc ? "Rea" : "A", mgmt->sa, |
1243 | capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); | 1314 | capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); |
1244 | 1315 | ||
1316 | pos = mgmt->u.assoc_resp.variable; | ||
1317 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
1318 | |||
1319 | if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && | ||
1320 | elems.timeout_int && elems.timeout_int_len == 5 && | ||
1321 | elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { | ||
1322 | u32 tu, ms; | ||
1323 | tu = get_unaligned_le32(elems.timeout_int + 1); | ||
1324 | ms = tu * 1024 / 1000; | ||
1325 | printk(KERN_DEBUG "%s: AP rejected association temporarily; " | ||
1326 | "comeback duration %u TU (%u ms)\n", | ||
1327 | sdata->dev->name, tu, ms); | ||
1328 | if (ms > IEEE80211_ASSOC_TIMEOUT) | ||
1329 | mod_timer(&ifsta->timer, | ||
1330 | jiffies + msecs_to_jiffies(ms)); | ||
1331 | return; | ||
1332 | } | ||
1333 | |||
1245 | if (status_code != WLAN_STATUS_SUCCESS) { | 1334 | if (status_code != WLAN_STATUS_SUCCESS) { |
1246 | printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", | 1335 | printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", |
1247 | sdata->dev->name, status_code); | 1336 | sdata->dev->name, status_code); |
@@ -1257,9 +1346,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1257 | "set\n", sdata->dev->name, aid); | 1346 | "set\n", sdata->dev->name, aid); |
1258 | aid &= ~(BIT(15) | BIT(14)); | 1347 | aid &= ~(BIT(15) | BIT(14)); |
1259 | 1348 | ||
1260 | pos = mgmt->u.assoc_resp.variable; | ||
1261 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
1262 | |||
1263 | if (!elems.supp_rates) { | 1349 | if (!elems.supp_rates) { |
1264 | printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", | 1350 | printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", |
1265 | sdata->dev->name); | 1351 | sdata->dev->name); |
@@ -1375,6 +1461,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1375 | 1461 | ||
1376 | rate_control_rate_init(sta); | 1462 | rate_control_rate_init(sta); |
1377 | 1463 | ||
1464 | if (ifsta->flags & IEEE80211_STA_MFP_ENABLED) | ||
1465 | set_sta_flags(sta, WLAN_STA_MFP); | ||
1466 | |||
1378 | if (elems.wmm_param) | 1467 | if (elems.wmm_param) |
1379 | set_sta_flags(sta, WLAN_STA_WME); | 1468 | set_sta_flags(sta, WLAN_STA_WME); |
1380 | 1469 | ||
@@ -1421,7 +1510,8 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
1421 | struct ieee80211_supported_band *sband; | 1510 | struct ieee80211_supported_band *sband; |
1422 | union iwreq_data wrqu; | 1511 | union iwreq_data wrqu; |
1423 | 1512 | ||
1424 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | 1513 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 + |
1514 | sdata->u.sta.ie_proberesp_len); | ||
1425 | if (!skb) { | 1515 | if (!skb) { |
1426 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | 1516 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " |
1427 | "response\n", sdata->dev->name); | 1517 | "response\n", sdata->dev->name); |
@@ -1504,9 +1594,13 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
1504 | memcpy(pos, &bss->supp_rates[8], rates); | 1594 | memcpy(pos, &bss->supp_rates[8], rates); |
1505 | } | 1595 | } |
1506 | 1596 | ||
1597 | add_extra_ies(skb, sdata->u.sta.ie_proberesp, | ||
1598 | sdata->u.sta.ie_proberesp_len); | ||
1599 | |||
1507 | ifsta->probe_resp = skb; | 1600 | ifsta->probe_resp = skb; |
1508 | 1601 | ||
1509 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); | 1602 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | |
1603 | IEEE80211_IFCC_BEACON_ENABLED); | ||
1510 | 1604 | ||
1511 | 1605 | ||
1512 | rates = 0; | 1606 | rates = 0; |
@@ -1521,6 +1615,7 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
1521 | 1615 | ||
1522 | ieee80211_sta_def_wmm_params(sdata, bss); | 1616 | ieee80211_sta_def_wmm_params(sdata, bss); |
1523 | 1617 | ||
1618 | ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; | ||
1524 | ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED; | 1619 | ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED; |
1525 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | 1620 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); |
1526 | 1621 | ||
@@ -1546,7 +1641,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1546 | struct sta_info *sta; | 1641 | struct sta_info *sta; |
1547 | struct ieee80211_channel *channel; | 1642 | struct ieee80211_channel *channel; |
1548 | u64 beacon_timestamp, rx_timestamp; | 1643 | u64 beacon_timestamp, rx_timestamp; |
1549 | u64 supp_rates = 0; | 1644 | u32 supp_rates = 0; |
1550 | enum ieee80211_band band = rx_status->band; | 1645 | enum ieee80211_band band = rx_status->band; |
1551 | 1646 | ||
1552 | if (elems->ds_params && elems->ds_params_len == 1) | 1647 | if (elems->ds_params && elems->ds_params_len == 1) |
@@ -1567,7 +1662,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1567 | 1662 | ||
1568 | sta = sta_info_get(local, mgmt->sa); | 1663 | sta = sta_info_get(local, mgmt->sa); |
1569 | if (sta) { | 1664 | if (sta) { |
1570 | u64 prev_rates; | 1665 | u32 prev_rates; |
1571 | 1666 | ||
1572 | prev_rates = sta->sta.supp_rates[band]; | 1667 | prev_rates = sta->sta.supp_rates[band]; |
1573 | /* make sure mandatory rates are always added */ | 1668 | /* make sure mandatory rates are always added */ |
@@ -1597,6 +1692,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1597 | if (!bss) | 1692 | if (!bss) |
1598 | return; | 1693 | return; |
1599 | 1694 | ||
1695 | if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && | ||
1696 | (memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0)) { | ||
1697 | struct ieee80211_channel_sw_ie *sw_elem = | ||
1698 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; | ||
1699 | ieee80211_process_chanswitch(sdata, sw_elem, bss); | ||
1700 | } | ||
1701 | |||
1600 | /* was just updated in ieee80211_bss_info_update */ | 1702 | /* was just updated in ieee80211_bss_info_update */ |
1601 | beacon_timestamp = bss->timestamp; | 1703 | beacon_timestamp = bss->timestamp; |
1602 | 1704 | ||
@@ -1612,6 +1714,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1612 | 1714 | ||
1613 | /* check if we need to merge IBSS */ | 1715 | /* check if we need to merge IBSS */ |
1614 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && beacon && | 1716 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && beacon && |
1717 | (!(sdata->u.sta.flags & IEEE80211_STA_BSSID_SET)) && | ||
1615 | bss->capability & WLAN_CAPABILITY_IBSS && | 1718 | bss->capability & WLAN_CAPABILITY_IBSS && |
1616 | bss->freq == local->oper_channel->center_freq && | 1719 | bss->freq == local->oper_channel->center_freq && |
1617 | elems->ssid_len == sdata->u.sta.ssid_len && | 1720 | elems->ssid_len == sdata->u.sta.ssid_len && |
@@ -1712,7 +1815,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1712 | struct ieee802_11_elems elems; | 1815 | struct ieee802_11_elems elems; |
1713 | struct ieee80211_local *local = sdata->local; | 1816 | struct ieee80211_local *local = sdata->local; |
1714 | u32 changed = 0; | 1817 | u32 changed = 0; |
1715 | bool erp_valid; | 1818 | bool erp_valid, directed_tim, is_mc = false; |
1716 | u8 erp_value = 0; | 1819 | u8 erp_value = 0; |
1717 | 1820 | ||
1718 | /* Process beacon from the current BSS */ | 1821 | /* Process beacon from the current BSS */ |
@@ -1732,9 +1835,22 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1732 | memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) | 1835 | memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) |
1733 | return; | 1836 | return; |
1734 | 1837 | ||
1838 | if (rx_status->freq != local->hw.conf.channel->center_freq) | ||
1839 | return; | ||
1840 | |||
1735 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, | 1841 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, |
1736 | elems.wmm_param_len); | 1842 | elems.wmm_param_len); |
1737 | 1843 | ||
1844 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK && | ||
1845 | local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
1846 | directed_tim = check_tim(&elems, ifsta->aid, &is_mc); | ||
1847 | |||
1848 | if (directed_tim || is_mc) { | ||
1849 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; | ||
1850 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
1851 | ieee80211_send_nullfunc(local, sdata, 0); | ||
1852 | } | ||
1853 | } | ||
1738 | 1854 | ||
1739 | if (elems.erp_info && elems.erp_info_len >= 1) { | 1855 | if (elems.erp_info && elems.erp_info_len >= 1) { |
1740 | erp_valid = true; | 1856 | erp_valid = true; |
@@ -1778,6 +1894,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1778 | * for the BSSID we are associated to */ | 1894 | * for the BSSID we are associated to */ |
1779 | regulatory_hint_11d(local->hw.wiphy, | 1895 | regulatory_hint_11d(local->hw.wiphy, |
1780 | elems.country_elem, elems.country_elem_len); | 1896 | elems.country_elem, elems.country_elem_len); |
1897 | |||
1898 | /* TODO: IBSS also needs this */ | ||
1899 | if (elems.pwr_constr_elem) | ||
1900 | ieee80211_handle_pwr_constr(sdata, | ||
1901 | le16_to_cpu(mgmt->u.probe_resp.capab_info), | ||
1902 | elems.pwr_constr_elem, | ||
1903 | elems.pwr_constr_elem_len); | ||
1781 | } | 1904 | } |
1782 | 1905 | ||
1783 | ieee80211_bss_info_change_notify(sdata, changed); | 1906 | ieee80211_bss_info_change_notify(sdata, changed); |
@@ -1787,8 +1910,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1787 | static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | 1910 | static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, |
1788 | struct ieee80211_if_sta *ifsta, | 1911 | struct ieee80211_if_sta *ifsta, |
1789 | struct ieee80211_mgmt *mgmt, | 1912 | struct ieee80211_mgmt *mgmt, |
1790 | size_t len, | 1913 | size_t len) |
1791 | struct ieee80211_rx_status *rx_status) | ||
1792 | { | 1914 | { |
1793 | struct ieee80211_local *local = sdata->local; | 1915 | struct ieee80211_local *local = sdata->local; |
1794 | int tx_last_beacon; | 1916 | int tx_last_beacon; |
@@ -1903,8 +2025,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1903 | 2025 | ||
1904 | switch (fc & IEEE80211_FCTL_STYPE) { | 2026 | switch (fc & IEEE80211_FCTL_STYPE) { |
1905 | case IEEE80211_STYPE_PROBE_REQ: | 2027 | case IEEE80211_STYPE_PROBE_REQ: |
1906 | ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt, skb->len, | 2028 | ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt, skb->len); |
1907 | rx_status); | ||
1908 | break; | 2029 | break; |
1909 | case IEEE80211_STYPE_PROBE_RESP: | 2030 | case IEEE80211_STYPE_PROBE_RESP: |
1910 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, rx_status); | 2031 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, rx_status); |
@@ -1965,6 +2086,10 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata, | |||
1965 | if (ieee80211_sta_active_ibss(sdata)) | 2086 | if (ieee80211_sta_active_ibss(sdata)) |
1966 | return; | 2087 | return; |
1967 | 2088 | ||
2089 | if ((sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) && | ||
2090 | (!(sdata->u.sta.flags & IEEE80211_STA_AUTO_CHANNEL_SEL))) | ||
2091 | return; | ||
2092 | |||
1968 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " | 2093 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " |
1969 | "IBSS networks with same SSID (merge)\n", sdata->dev->name); | 2094 | "IBSS networks with same SSID (merge)\n", sdata->dev->name); |
1970 | ieee80211_request_scan(sdata, ifsta->ssid, ifsta->ssid_len); | 2095 | ieee80211_request_scan(sdata, ifsta->ssid, ifsta->ssid_len); |
@@ -2054,19 +2179,18 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, | |||
2054 | int i; | 2179 | int i; |
2055 | int ret; | 2180 | int ret; |
2056 | 2181 | ||
2057 | #if 0 | 2182 | if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) { |
2058 | /* Easier testing, use fixed BSSID. */ | 2183 | memcpy(bssid, ifsta->bssid, ETH_ALEN); |
2059 | memset(bssid, 0xfe, ETH_ALEN); | 2184 | } else { |
2060 | #else | 2185 | /* Generate random, not broadcast, locally administered BSSID. Mix in |
2061 | /* Generate random, not broadcast, locally administered BSSID. Mix in | 2186 | * own MAC address to make sure that devices that do not have proper |
2062 | * own MAC address to make sure that devices that do not have proper | 2187 | * random number generator get different BSSID. */ |
2063 | * random number generator get different BSSID. */ | 2188 | get_random_bytes(bssid, ETH_ALEN); |
2064 | get_random_bytes(bssid, ETH_ALEN); | 2189 | for (i = 0; i < ETH_ALEN; i++) |
2065 | for (i = 0; i < ETH_ALEN; i++) | 2190 | bssid[i] ^= sdata->dev->dev_addr[i]; |
2066 | bssid[i] ^= sdata->dev->dev_addr[i]; | 2191 | bssid[0] &= ~0x01; |
2067 | bssid[0] &= ~0x01; | 2192 | bssid[0] |= 0x02; |
2068 | bssid[0] |= 0x02; | 2193 | } |
2069 | #endif | ||
2070 | 2194 | ||
2071 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", | 2195 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", |
2072 | sdata->dev->name, bssid); | 2196 | sdata->dev->name, bssid); |
@@ -2127,6 +2251,9 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata, | |||
2127 | memcmp(ifsta->ssid, bss->ssid, bss->ssid_len) != 0 | 2251 | memcmp(ifsta->ssid, bss->ssid, bss->ssid_len) != 0 |
2128 | || !(bss->capability & WLAN_CAPABILITY_IBSS)) | 2252 | || !(bss->capability & WLAN_CAPABILITY_IBSS)) |
2129 | continue; | 2253 | continue; |
2254 | if ((ifsta->flags & IEEE80211_STA_BSSID_SET) && | ||
2255 | memcmp(ifsta->bssid, bss->bssid, ETH_ALEN) != 0) | ||
2256 | continue; | ||
2130 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 2257 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
2131 | printk(KERN_DEBUG " bssid=%pM found\n", bss->bssid); | 2258 | printk(KERN_DEBUG " bssid=%pM found\n", bss->bssid); |
2132 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 2259 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
@@ -2143,7 +2270,9 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata, | |||
2143 | "%pM\n", bssid, ifsta->bssid); | 2270 | "%pM\n", bssid, ifsta->bssid); |
2144 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 2271 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
2145 | 2272 | ||
2146 | if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { | 2273 | if (found && |
2274 | ((!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) || | ||
2275 | memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0)) { | ||
2147 | int ret; | 2276 | int ret; |
2148 | int search_freq; | 2277 | int search_freq; |
2149 | 2278 | ||
@@ -2258,6 +2387,10 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | |||
2258 | selected->ssid_len); | 2387 | selected->ssid_len); |
2259 | ieee80211_sta_set_bssid(sdata, selected->bssid); | 2388 | ieee80211_sta_set_bssid(sdata, selected->bssid); |
2260 | ieee80211_sta_def_wmm_params(sdata, selected); | 2389 | ieee80211_sta_def_wmm_params(sdata, selected); |
2390 | if (sdata->u.sta.mfp == IEEE80211_MFP_REQUIRED) | ||
2391 | sdata->u.sta.flags |= IEEE80211_STA_MFP_ENABLED; | ||
2392 | else | ||
2393 | sdata->u.sta.flags &= ~IEEE80211_STA_MFP_ENABLED; | ||
2261 | 2394 | ||
2262 | /* Send out direct probe if no probe resp was received or | 2395 | /* Send out direct probe if no probe resp was received or |
2263 | * the one we have is outdated | 2396 | * the one we have is outdated |
@@ -2376,8 +2509,11 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
2376 | 2509 | ||
2377 | ifsta = &sdata->u.sta; | 2510 | ifsta = &sdata->u.sta; |
2378 | INIT_WORK(&ifsta->work, ieee80211_sta_work); | 2511 | INIT_WORK(&ifsta->work, ieee80211_sta_work); |
2512 | INIT_WORK(&ifsta->chswitch_work, ieee80211_chswitch_work); | ||
2379 | setup_timer(&ifsta->timer, ieee80211_sta_timer, | 2513 | setup_timer(&ifsta->timer, ieee80211_sta_timer, |
2380 | (unsigned long) sdata); | 2514 | (unsigned long) sdata); |
2515 | setup_timer(&ifsta->chswitch_timer, ieee80211_chswitch_timer, | ||
2516 | (unsigned long) sdata); | ||
2381 | skb_queue_head_init(&ifsta->skb_queue); | 2517 | skb_queue_head_init(&ifsta->skb_queue); |
2382 | 2518 | ||
2383 | ifsta->capab = WLAN_CAPABILITY_ESS; | 2519 | ifsta->capab = WLAN_CAPABILITY_ESS; |
@@ -2396,7 +2532,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
2396 | * must be callable in atomic context. | 2532 | * must be callable in atomic context. |
2397 | */ | 2533 | */ |
2398 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | 2534 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, |
2399 | u8 *bssid,u8 *addr, u64 supp_rates) | 2535 | u8 *bssid,u8 *addr, u32 supp_rates) |
2400 | { | 2536 | { |
2401 | struct ieee80211_local *local = sdata->local; | 2537 | struct ieee80211_local *local = sdata->local; |
2402 | struct sta_info *sta; | 2538 | struct sta_info *sta; |
@@ -2474,16 +2610,16 @@ int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size | |||
2474 | memset(ifsta->ssid, 0, sizeof(ifsta->ssid)); | 2610 | memset(ifsta->ssid, 0, sizeof(ifsta->ssid)); |
2475 | memcpy(ifsta->ssid, ssid, len); | 2611 | memcpy(ifsta->ssid, ssid, len); |
2476 | ifsta->ssid_len = len; | 2612 | ifsta->ssid_len = len; |
2477 | ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | ||
2478 | } | 2613 | } |
2479 | 2614 | ||
2615 | ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | ||
2616 | |||
2480 | if (len) | 2617 | if (len) |
2481 | ifsta->flags |= IEEE80211_STA_SSID_SET; | 2618 | ifsta->flags |= IEEE80211_STA_SSID_SET; |
2482 | else | 2619 | else |
2483 | ifsta->flags &= ~IEEE80211_STA_SSID_SET; | 2620 | ifsta->flags &= ~IEEE80211_STA_SSID_SET; |
2484 | 2621 | ||
2485 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | 2622 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
2486 | !(ifsta->flags & IEEE80211_STA_BSSID_SET)) { | ||
2487 | ifsta->ibss_join_req = jiffies; | 2623 | ifsta->ibss_join_req = jiffies; |
2488 | ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH; | 2624 | ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH; |
2489 | return ieee80211_sta_find_ibss(sdata, ifsta); | 2625 | return ieee80211_sta_find_ibss(sdata, ifsta); |
@@ -2503,31 +2639,25 @@ int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size | |||
2503 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | 2639 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) |
2504 | { | 2640 | { |
2505 | struct ieee80211_if_sta *ifsta; | 2641 | struct ieee80211_if_sta *ifsta; |
2506 | int res; | ||
2507 | 2642 | ||
2508 | ifsta = &sdata->u.sta; | 2643 | ifsta = &sdata->u.sta; |
2509 | 2644 | ||
2510 | if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { | 2645 | if (is_valid_ether_addr(bssid)) { |
2511 | memcpy(ifsta->bssid, bssid, ETH_ALEN); | 2646 | memcpy(ifsta->bssid, bssid, ETH_ALEN); |
2512 | res = 0; | 2647 | ifsta->flags |= IEEE80211_STA_BSSID_SET; |
2513 | /* | 2648 | } else { |
2514 | * Hack! See also ieee80211_sta_set_ssid. | 2649 | memset(ifsta->bssid, 0, ETH_ALEN); |
2515 | */ | 2650 | ifsta->flags &= ~IEEE80211_STA_BSSID_SET; |
2516 | if (netif_running(sdata->dev)) | 2651 | } |
2517 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); | 2652 | |
2518 | if (res) { | 2653 | if (netif_running(sdata->dev)) { |
2654 | if (ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID)) { | ||
2519 | printk(KERN_DEBUG "%s: Failed to config new BSSID to " | 2655 | printk(KERN_DEBUG "%s: Failed to config new BSSID to " |
2520 | "the low-level driver\n", sdata->dev->name); | 2656 | "the low-level driver\n", sdata->dev->name); |
2521 | return res; | ||
2522 | } | 2657 | } |
2523 | } | 2658 | } |
2524 | 2659 | ||
2525 | if (is_valid_ether_addr(bssid)) | 2660 | return ieee80211_sta_set_ssid(sdata, ifsta->ssid, ifsta->ssid_len); |
2526 | ifsta->flags |= IEEE80211_STA_BSSID_SET; | ||
2527 | else | ||
2528 | ifsta->flags &= ~IEEE80211_STA_BSSID_SET; | ||
2529 | |||
2530 | return 0; | ||
2531 | } | 2661 | } |
2532 | 2662 | ||
2533 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) | 2663 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) |
@@ -2623,12 +2753,15 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
2623 | struct ieee80211_local *local = | 2753 | struct ieee80211_local *local = |
2624 | container_of(work, struct ieee80211_local, | 2754 | container_of(work, struct ieee80211_local, |
2625 | dynamic_ps_enable_work); | 2755 | dynamic_ps_enable_work); |
2756 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | ||
2626 | 2757 | ||
2627 | if (local->hw.conf.flags & IEEE80211_CONF_PS) | 2758 | if (local->hw.conf.flags & IEEE80211_CONF_PS) |
2628 | return; | 2759 | return; |
2629 | 2760 | ||
2630 | local->hw.conf.flags |= IEEE80211_CONF_PS; | 2761 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) |
2762 | ieee80211_send_nullfunc(local, sdata, 1); | ||
2631 | 2763 | ||
2764 | local->hw.conf.flags |= IEEE80211_CONF_PS; | ||
2632 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 2765 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
2633 | } | 2766 | } |
2634 | 2767 | ||
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c new file mode 100644 index 000000000000..44525f517077 --- /dev/null +++ b/net/mac80211/pm.c | |||
@@ -0,0 +1,117 @@ | |||
1 | #include <net/mac80211.h> | ||
2 | #include <net/rtnetlink.h> | ||
3 | |||
4 | #include "ieee80211_i.h" | ||
5 | #include "led.h" | ||
6 | |||
7 | int __ieee80211_suspend(struct ieee80211_hw *hw) | ||
8 | { | ||
9 | struct ieee80211_local *local = hw_to_local(hw); | ||
10 | struct ieee80211_sub_if_data *sdata; | ||
11 | struct ieee80211_if_init_conf conf; | ||
12 | struct sta_info *sta; | ||
13 | |||
14 | flush_workqueue(local->hw.workqueue); | ||
15 | |||
16 | /* disable keys */ | ||
17 | list_for_each_entry(sdata, &local->interfaces, list) | ||
18 | ieee80211_disable_keys(sdata); | ||
19 | |||
20 | /* remove STAs */ | ||
21 | list_for_each_entry(sta, &local->sta_list, list) { | ||
22 | |||
23 | if (local->ops->sta_notify) { | ||
24 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
25 | sdata = container_of(sdata->bss, | ||
26 | struct ieee80211_sub_if_data, | ||
27 | u.ap); | ||
28 | |||
29 | local->ops->sta_notify(hw, &sdata->vif, | ||
30 | STA_NOTIFY_REMOVE, &sta->sta); | ||
31 | } | ||
32 | } | ||
33 | |||
34 | /* remove all interfaces */ | ||
35 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
36 | |||
37 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | ||
38 | sdata->vif.type != NL80211_IFTYPE_MONITOR && | ||
39 | netif_running(sdata->dev)) { | ||
40 | conf.vif = &sdata->vif; | ||
41 | conf.type = sdata->vif.type; | ||
42 | conf.mac_addr = sdata->dev->dev_addr; | ||
43 | local->ops->remove_interface(hw, &conf); | ||
44 | } | ||
45 | } | ||
46 | |||
47 | /* flush again, in case driver queued work */ | ||
48 | flush_workqueue(local->hw.workqueue); | ||
49 | |||
50 | /* stop hardware */ | ||
51 | if (local->open_count) { | ||
52 | ieee80211_led_radio(local, false); | ||
53 | local->ops->stop(hw); | ||
54 | } | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | int __ieee80211_resume(struct ieee80211_hw *hw) | ||
59 | { | ||
60 | struct ieee80211_local *local = hw_to_local(hw); | ||
61 | struct ieee80211_sub_if_data *sdata; | ||
62 | struct ieee80211_if_init_conf conf; | ||
63 | struct sta_info *sta; | ||
64 | int res; | ||
65 | |||
66 | /* restart hardware */ | ||
67 | if (local->open_count) { | ||
68 | res = local->ops->start(hw); | ||
69 | |||
70 | ieee80211_led_radio(local, hw->conf.radio_enabled); | ||
71 | } | ||
72 | |||
73 | /* add interfaces */ | ||
74 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
75 | |||
76 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | ||
77 | sdata->vif.type != NL80211_IFTYPE_MONITOR && | ||
78 | netif_running(sdata->dev)) { | ||
79 | conf.vif = &sdata->vif; | ||
80 | conf.type = sdata->vif.type; | ||
81 | conf.mac_addr = sdata->dev->dev_addr; | ||
82 | res = local->ops->add_interface(hw, &conf); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | /* add STAs back */ | ||
87 | list_for_each_entry(sta, &local->sta_list, list) { | ||
88 | |||
89 | if (local->ops->sta_notify) { | ||
90 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
91 | sdata = container_of(sdata->bss, | ||
92 | struct ieee80211_sub_if_data, | ||
93 | u.ap); | ||
94 | |||
95 | local->ops->sta_notify(hw, &sdata->vif, | ||
96 | STA_NOTIFY_ADD, &sta->sta); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | /* add back keys */ | ||
101 | list_for_each_entry(sdata, &local->interfaces, list) | ||
102 | if (netif_running(sdata->dev)) | ||
103 | ieee80211_enable_keys(sdata); | ||
104 | |||
105 | /* setup RTS threshold */ | ||
106 | if (local->ops->set_rts_threshold) | ||
107 | local->ops->set_rts_threshold(hw, local->rts_threshold); | ||
108 | |||
109 | /* reconfigure hardware */ | ||
110 | ieee80211_hw_config(local, ~0); | ||
111 | |||
112 | netif_addr_lock_bh(local->mdev); | ||
113 | ieee80211_configure_filter(local); | ||
114 | netif_addr_unlock_bh(local->mdev); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7175ae80c36a..19ffc8ef1d1d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -102,7 +102,7 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local, | |||
102 | return len; | 102 | return len; |
103 | } | 103 | } |
104 | 104 | ||
105 | /** | 105 | /* |
106 | * ieee80211_add_rx_radiotap_header - add radiotap header | 106 | * ieee80211_add_rx_radiotap_header - add radiotap header |
107 | * | 107 | * |
108 | * add a radiotap header containing all the fields which the hardware provided. | 108 | * add a radiotap header containing all the fields which the hardware provided. |
@@ -158,7 +158,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
158 | */ | 158 | */ |
159 | *pos = 0; | 159 | *pos = 0; |
160 | } else { | 160 | } else { |
161 | rthdr->it_present |= (1 << IEEE80211_RADIOTAP_RATE); | 161 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE); |
162 | *pos = rate->bitrate / 5; | 162 | *pos = rate->bitrate / 5; |
163 | } | 163 | } |
164 | pos++; | 164 | pos++; |
@@ -371,39 +371,50 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) | |||
371 | rx->skb->priority = (tid > 7) ? 0 : tid; | 371 | rx->skb->priority = (tid > 7) ? 0 : tid; |
372 | } | 372 | } |
373 | 373 | ||
374 | static void ieee80211_verify_ip_alignment(struct ieee80211_rx_data *rx) | 374 | /** |
375 | * DOC: Packet alignment | ||
376 | * | ||
377 | * Drivers always need to pass packets that are aligned to two-byte boundaries | ||
378 | * to the stack. | ||
379 | * | ||
380 | * Additionally, should, if possible, align the payload data in a way that | ||
381 | * guarantees that the contained IP header is aligned to a four-byte | ||
382 | * boundary. In the case of regular frames, this simply means aligning the | ||
383 | * payload to a four-byte boundary (because either the IP header is directly | ||
384 | * contained, or IV/RFC1042 headers that have a length divisible by four are | ||
385 | * in front of it). | ||
386 | * | ||
387 | * With A-MSDU frames, however, the payload data address must yield two modulo | ||
388 | * four because there are 14-byte 802.3 headers within the A-MSDU frames that | ||
389 | * push the IP header further back to a multiple of four again. Thankfully, the | ||
390 | * specs were sane enough this time around to require padding each A-MSDU | ||
391 | * subframe to a length that is a multiple of four. | ||
392 | * | ||
393 | * Padding like Atheros hardware adds which is inbetween the 802.11 header and | ||
394 | * the payload is not supported, the driver is required to move the 802.11 | ||
395 | * header to be directly in front of the payload in that case. | ||
396 | */ | ||
397 | static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx) | ||
375 | { | 398 | { |
376 | #ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT | ||
377 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 399 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
378 | int hdrlen; | 400 | int hdrlen; |
379 | 401 | ||
402 | #ifndef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT | ||
403 | return; | ||
404 | #endif | ||
405 | |||
406 | if (WARN_ONCE((unsigned long)rx->skb->data & 1, | ||
407 | "unaligned packet at 0x%p\n", rx->skb->data)) | ||
408 | return; | ||
409 | |||
380 | if (!ieee80211_is_data_present(hdr->frame_control)) | 410 | if (!ieee80211_is_data_present(hdr->frame_control)) |
381 | return; | 411 | return; |
382 | 412 | ||
383 | /* | ||
384 | * Drivers are required to align the payload data in a way that | ||
385 | * guarantees that the contained IP header is aligned to a four- | ||
386 | * byte boundary. In the case of regular frames, this simply means | ||
387 | * aligning the payload to a four-byte boundary (because either | ||
388 | * the IP header is directly contained, or IV/RFC1042 headers that | ||
389 | * have a length divisible by four are in front of it. | ||
390 | * | ||
391 | * With A-MSDU frames, however, the payload data address must | ||
392 | * yield two modulo four because there are 14-byte 802.3 headers | ||
393 | * within the A-MSDU frames that push the IP header further back | ||
394 | * to a multiple of four again. Thankfully, the specs were sane | ||
395 | * enough this time around to require padding each A-MSDU subframe | ||
396 | * to a length that is a multiple of four. | ||
397 | * | ||
398 | * Padding like atheros hardware adds which is inbetween the 802.11 | ||
399 | * header and the payload is not supported, the driver is required | ||
400 | * to move the 802.11 header further back in that case. | ||
401 | */ | ||
402 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 413 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
403 | if (rx->flags & IEEE80211_RX_AMSDU) | 414 | if (rx->flags & IEEE80211_RX_AMSDU) |
404 | hdrlen += ETH_HLEN; | 415 | hdrlen += ETH_HLEN; |
405 | WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3); | 416 | WARN_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3, |
406 | #endif | 417 | "unaligned IP payload at 0x%p\n", rx->skb->data + hdrlen); |
407 | } | 418 | } |
408 | 419 | ||
409 | 420 | ||
@@ -435,6 +446,52 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) | |||
435 | return RX_CONTINUE; | 446 | return RX_CONTINUE; |
436 | } | 447 | } |
437 | 448 | ||
449 | |||
450 | static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb) | ||
451 | { | ||
452 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
453 | |||
454 | if (skb->len < 24 || is_multicast_ether_addr(hdr->addr1)) | ||
455 | return 0; | ||
456 | |||
457 | return ieee80211_is_robust_mgmt_frame(hdr); | ||
458 | } | ||
459 | |||
460 | |||
461 | static int ieee80211_is_multicast_robust_mgmt_frame(struct sk_buff *skb) | ||
462 | { | ||
463 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
464 | |||
465 | if (skb->len < 24 || !is_multicast_ether_addr(hdr->addr1)) | ||
466 | return 0; | ||
467 | |||
468 | return ieee80211_is_robust_mgmt_frame(hdr); | ||
469 | } | ||
470 | |||
471 | |||
472 | /* Get the BIP key index from MMIE; return -1 if this is not a BIP frame */ | ||
473 | static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | ||
474 | { | ||
475 | struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data; | ||
476 | struct ieee80211_mmie *mmie; | ||
477 | |||
478 | if (skb->len < 24 + sizeof(*mmie) || | ||
479 | !is_multicast_ether_addr(hdr->da)) | ||
480 | return -1; | ||
481 | |||
482 | if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr)) | ||
483 | return -1; /* not a robust management frame */ | ||
484 | |||
485 | mmie = (struct ieee80211_mmie *) | ||
486 | (skb->data + skb->len - sizeof(*mmie)); | ||
487 | if (mmie->element_id != WLAN_EID_MMIE || | ||
488 | mmie->length != sizeof(*mmie) - 2) | ||
489 | return -1; | ||
490 | |||
491 | return le16_to_cpu(mmie->key_id); | ||
492 | } | ||
493 | |||
494 | |||
438 | static ieee80211_rx_result | 495 | static ieee80211_rx_result |
439 | ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | 496 | ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) |
440 | { | 497 | { |
@@ -550,21 +607,23 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
550 | int hdrlen; | 607 | int hdrlen; |
551 | ieee80211_rx_result result = RX_DROP_UNUSABLE; | 608 | ieee80211_rx_result result = RX_DROP_UNUSABLE; |
552 | struct ieee80211_key *stakey = NULL; | 609 | struct ieee80211_key *stakey = NULL; |
610 | int mmie_keyidx = -1; | ||
553 | 611 | ||
554 | /* | 612 | /* |
555 | * Key selection 101 | 613 | * Key selection 101 |
556 | * | 614 | * |
557 | * There are three types of keys: | 615 | * There are four types of keys: |
558 | * - GTK (group keys) | 616 | * - GTK (group keys) |
617 | * - IGTK (group keys for management frames) | ||
559 | * - PTK (pairwise keys) | 618 | * - PTK (pairwise keys) |
560 | * - STK (station-to-station pairwise keys) | 619 | * - STK (station-to-station pairwise keys) |
561 | * | 620 | * |
562 | * When selecting a key, we have to distinguish between multicast | 621 | * When selecting a key, we have to distinguish between multicast |
563 | * (including broadcast) and unicast frames, the latter can only | 622 | * (including broadcast) and unicast frames, the latter can only |
564 | * use PTKs and STKs while the former always use GTKs. Unless, of | 623 | * use PTKs and STKs while the former always use GTKs and IGTKs. |
565 | * course, actual WEP keys ("pre-RSNA") are used, then unicast | 624 | * Unless, of course, actual WEP keys ("pre-RSNA") are used, then |
566 | * frames can also use key indizes like GTKs. Hence, if we don't | 625 | * unicast frames can also use key indices like GTKs. Hence, if we |
567 | * have a PTK/STK we check the key index for a WEP key. | 626 | * don't have a PTK/STK we check the key index for a WEP key. |
568 | * | 627 | * |
569 | * Note that in a regular BSS, multicast frames are sent by the | 628 | * Note that in a regular BSS, multicast frames are sent by the |
570 | * AP only, associated stations unicast the frame to the AP first | 629 | * AP only, associated stations unicast the frame to the AP first |
@@ -577,8 +636,14 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
577 | * possible. | 636 | * possible. |
578 | */ | 637 | */ |
579 | 638 | ||
580 | if (!ieee80211_has_protected(hdr->frame_control)) | 639 | if (!ieee80211_has_protected(hdr->frame_control)) { |
581 | return RX_CONTINUE; | 640 | if (!ieee80211_is_mgmt(hdr->frame_control) || |
641 | rx->sta == NULL || !test_sta_flags(rx->sta, WLAN_STA_MFP)) | ||
642 | return RX_CONTINUE; | ||
643 | mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); | ||
644 | if (mmie_keyidx < 0) | ||
645 | return RX_CONTINUE; | ||
646 | } | ||
582 | 647 | ||
583 | /* | 648 | /* |
584 | * No point in finding a key and decrypting if the frame is neither | 649 | * No point in finding a key and decrypting if the frame is neither |
@@ -592,6 +657,16 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
592 | 657 | ||
593 | if (!is_multicast_ether_addr(hdr->addr1) && stakey) { | 658 | if (!is_multicast_ether_addr(hdr->addr1) && stakey) { |
594 | rx->key = stakey; | 659 | rx->key = stakey; |
660 | } else if (mmie_keyidx >= 0) { | ||
661 | /* Broadcast/multicast robust management frame / BIP */ | ||
662 | if ((rx->status->flag & RX_FLAG_DECRYPTED) && | ||
663 | (rx->status->flag & RX_FLAG_IV_STRIPPED)) | ||
664 | return RX_CONTINUE; | ||
665 | |||
666 | if (mmie_keyidx < NUM_DEFAULT_KEYS || | ||
667 | mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) | ||
668 | return RX_DROP_MONITOR; /* unexpected BIP keyidx */ | ||
669 | rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]); | ||
595 | } else { | 670 | } else { |
596 | /* | 671 | /* |
597 | * The device doesn't give us the IV so we won't be | 672 | * The device doesn't give us the IV so we won't be |
@@ -654,6 +729,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
654 | case ALG_CCMP: | 729 | case ALG_CCMP: |
655 | result = ieee80211_crypto_ccmp_decrypt(rx); | 730 | result = ieee80211_crypto_ccmp_decrypt(rx); |
656 | break; | 731 | break; |
732 | case ALG_AES_CMAC: | ||
733 | result = ieee80211_crypto_aes_cmac_decrypt(rx); | ||
734 | break; | ||
657 | } | 735 | } |
658 | 736 | ||
659 | /* either the frame has been decrypted or will be dropped */ | 737 | /* either the frame has been decrypted or will be dropped */ |
@@ -1101,6 +1179,15 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) | |||
1101 | /* Drop unencrypted frames if key is set. */ | 1179 | /* Drop unencrypted frames if key is set. */ |
1102 | if (unlikely(!ieee80211_has_protected(fc) && | 1180 | if (unlikely(!ieee80211_has_protected(fc) && |
1103 | !ieee80211_is_nullfunc(fc) && | 1181 | !ieee80211_is_nullfunc(fc) && |
1182 | (!ieee80211_is_mgmt(fc) || | ||
1183 | (ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && | ||
1184 | rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP))) && | ||
1185 | (rx->key || rx->sdata->drop_unencrypted))) | ||
1186 | return -EACCES; | ||
1187 | /* BIP does not use Protected field, so need to check MMIE */ | ||
1188 | if (unlikely(rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP) && | ||
1189 | ieee80211_is_multicast_robust_mgmt_frame(rx->skb) && | ||
1190 | ieee80211_get_mmie_keyidx(rx->skb) < 0 && | ||
1104 | (rx->key || rx->sdata->drop_unencrypted))) | 1191 | (rx->key || rx->sdata->drop_unencrypted))) |
1105 | return -EACCES; | 1192 | return -EACCES; |
1106 | 1193 | ||
@@ -1267,10 +1354,37 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
1267 | } | 1354 | } |
1268 | 1355 | ||
1269 | if (skb) { | 1356 | if (skb) { |
1270 | /* deliver to local stack */ | 1357 | int align __maybe_unused; |
1271 | skb->protocol = eth_type_trans(skb, dev); | 1358 | |
1272 | memset(skb->cb, 0, sizeof(skb->cb)); | 1359 | #if defined(CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT) || !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) |
1273 | netif_rx(skb); | 1360 | /* |
1361 | * 'align' will only take the values 0 or 2 here | ||
1362 | * since all frames are required to be aligned | ||
1363 | * to 2-byte boundaries when being passed to | ||
1364 | * mac80211. That also explains the __skb_push() | ||
1365 | * below. | ||
1366 | */ | ||
1367 | align = (unsigned long)skb->data & 4; | ||
1368 | if (align) { | ||
1369 | if (WARN_ON(skb_headroom(skb) < 3)) { | ||
1370 | dev_kfree_skb(skb); | ||
1371 | skb = NULL; | ||
1372 | } else { | ||
1373 | u8 *data = skb->data; | ||
1374 | size_t len = skb->len; | ||
1375 | u8 *new = __skb_push(skb, align); | ||
1376 | memmove(new, data, len); | ||
1377 | __skb_trim(skb, len); | ||
1378 | } | ||
1379 | } | ||
1380 | #endif | ||
1381 | |||
1382 | if (skb) { | ||
1383 | /* deliver to local stack */ | ||
1384 | skb->protocol = eth_type_trans(skb, dev); | ||
1385 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
1386 | netif_rx(skb); | ||
1387 | } | ||
1274 | } | 1388 | } |
1275 | 1389 | ||
1276 | if (xmit_skb) { | 1390 | if (xmit_skb) { |
@@ -1339,14 +1453,20 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) | |||
1339 | if (remaining <= subframe_len + padding) | 1453 | if (remaining <= subframe_len + padding) |
1340 | frame = skb; | 1454 | frame = skb; |
1341 | else { | 1455 | else { |
1342 | frame = dev_alloc_skb(local->hw.extra_tx_headroom + | 1456 | /* |
1343 | subframe_len); | 1457 | * Allocate and reserve two bytes more for payload |
1458 | * alignment since sizeof(struct ethhdr) is 14. | ||
1459 | */ | ||
1460 | frame = dev_alloc_skb( | ||
1461 | ALIGN(local->hw.extra_tx_headroom, 4) + | ||
1462 | subframe_len + 2); | ||
1344 | 1463 | ||
1345 | if (frame == NULL) | 1464 | if (frame == NULL) |
1346 | return RX_DROP_UNUSABLE; | 1465 | return RX_DROP_UNUSABLE; |
1347 | 1466 | ||
1348 | skb_reserve(frame, local->hw.extra_tx_headroom + | 1467 | skb_reserve(frame, |
1349 | sizeof(struct ethhdr)); | 1468 | ALIGN(local->hw.extra_tx_headroom, 4) + |
1469 | sizeof(struct ethhdr) + 2); | ||
1350 | memcpy(skb_put(frame, ntohs(len)), skb->data, | 1470 | memcpy(skb_put(frame, ntohs(len)), skb->data, |
1351 | ntohs(len)); | 1471 | ntohs(len)); |
1352 | 1472 | ||
@@ -1547,12 +1667,65 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) | |||
1547 | return RX_CONTINUE; | 1667 | return RX_CONTINUE; |
1548 | } | 1668 | } |
1549 | 1669 | ||
1670 | static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, | ||
1671 | struct ieee80211_mgmt *mgmt, | ||
1672 | size_t len) | ||
1673 | { | ||
1674 | struct ieee80211_local *local = sdata->local; | ||
1675 | struct sk_buff *skb; | ||
1676 | struct ieee80211_mgmt *resp; | ||
1677 | |||
1678 | if (compare_ether_addr(mgmt->da, sdata->dev->dev_addr) != 0) { | ||
1679 | /* Not to own unicast address */ | ||
1680 | return; | ||
1681 | } | ||
1682 | |||
1683 | if (compare_ether_addr(mgmt->sa, sdata->u.sta.bssid) != 0 || | ||
1684 | compare_ether_addr(mgmt->bssid, sdata->u.sta.bssid) != 0) { | ||
1685 | /* Not from the current AP. */ | ||
1686 | return; | ||
1687 | } | ||
1688 | |||
1689 | if (sdata->u.sta.state == IEEE80211_STA_MLME_ASSOCIATE) { | ||
1690 | /* Association in progress; ignore SA Query */ | ||
1691 | return; | ||
1692 | } | ||
1693 | |||
1694 | if (len < 24 + 1 + sizeof(resp->u.action.u.sa_query)) { | ||
1695 | /* Too short SA Query request frame */ | ||
1696 | return; | ||
1697 | } | ||
1698 | |||
1699 | skb = dev_alloc_skb(sizeof(*resp) + local->hw.extra_tx_headroom); | ||
1700 | if (skb == NULL) | ||
1701 | return; | ||
1702 | |||
1703 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1704 | resp = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
1705 | memset(resp, 0, 24); | ||
1706 | memcpy(resp->da, mgmt->sa, ETH_ALEN); | ||
1707 | memcpy(resp->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
1708 | memcpy(resp->bssid, sdata->u.sta.bssid, ETH_ALEN); | ||
1709 | resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
1710 | IEEE80211_STYPE_ACTION); | ||
1711 | skb_put(skb, 1 + sizeof(resp->u.action.u.sa_query)); | ||
1712 | resp->u.action.category = WLAN_CATEGORY_SA_QUERY; | ||
1713 | resp->u.action.u.sa_query.action = WLAN_ACTION_SA_QUERY_RESPONSE; | ||
1714 | memcpy(resp->u.action.u.sa_query.trans_id, | ||
1715 | mgmt->u.action.u.sa_query.trans_id, | ||
1716 | WLAN_SA_QUERY_TR_ID_LEN); | ||
1717 | |||
1718 | ieee80211_tx_skb(sdata, skb, 1); | ||
1719 | } | ||
1720 | |||
1550 | static ieee80211_rx_result debug_noinline | 1721 | static ieee80211_rx_result debug_noinline |
1551 | ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | 1722 | ieee80211_rx_h_action(struct ieee80211_rx_data *rx) |
1552 | { | 1723 | { |
1553 | struct ieee80211_local *local = rx->local; | 1724 | struct ieee80211_local *local = rx->local; |
1554 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); | 1725 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); |
1726 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
1555 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; | 1727 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; |
1728 | struct ieee80211_bss *bss; | ||
1556 | int len = rx->skb->len; | 1729 | int len = rx->skb->len; |
1557 | 1730 | ||
1558 | if (!ieee80211_is_action(mgmt->frame_control)) | 1731 | if (!ieee80211_is_action(mgmt->frame_control)) |
@@ -1564,6 +1737,9 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1564 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | 1737 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) |
1565 | return RX_DROP_MONITOR; | 1738 | return RX_DROP_MONITOR; |
1566 | 1739 | ||
1740 | if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) | ||
1741 | return RX_DROP_MONITOR; | ||
1742 | |||
1567 | /* all categories we currently handle have action_code */ | 1743 | /* all categories we currently handle have action_code */ |
1568 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | 1744 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) |
1569 | return RX_DROP_MONITOR; | 1745 | return RX_DROP_MONITOR; |
@@ -1601,6 +1777,42 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1601 | return RX_DROP_MONITOR; | 1777 | return RX_DROP_MONITOR; |
1602 | ieee80211_process_measurement_req(sdata, mgmt, len); | 1778 | ieee80211_process_measurement_req(sdata, mgmt, len); |
1603 | break; | 1779 | break; |
1780 | case WLAN_ACTION_SPCT_CHL_SWITCH: | ||
1781 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
1782 | sizeof(mgmt->u.action.u.chan_switch))) | ||
1783 | return RX_DROP_MONITOR; | ||
1784 | |||
1785 | if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0) | ||
1786 | return RX_DROP_MONITOR; | ||
1787 | |||
1788 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | ||
1789 | local->hw.conf.channel->center_freq, | ||
1790 | ifsta->ssid, ifsta->ssid_len); | ||
1791 | if (!bss) | ||
1792 | return RX_DROP_MONITOR; | ||
1793 | |||
1794 | ieee80211_process_chanswitch(sdata, | ||
1795 | &mgmt->u.action.u.chan_switch.sw_elem, bss); | ||
1796 | ieee80211_rx_bss_put(local, bss); | ||
1797 | break; | ||
1798 | } | ||
1799 | break; | ||
1800 | case WLAN_CATEGORY_SA_QUERY: | ||
1801 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
1802 | sizeof(mgmt->u.action.u.sa_query))) | ||
1803 | return RX_DROP_MONITOR; | ||
1804 | switch (mgmt->u.action.u.sa_query.action) { | ||
1805 | case WLAN_ACTION_SA_QUERY_REQUEST: | ||
1806 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
1807 | return RX_DROP_MONITOR; | ||
1808 | ieee80211_process_sa_query_req(sdata, mgmt, len); | ||
1809 | break; | ||
1810 | case WLAN_ACTION_SA_QUERY_RESPONSE: | ||
1811 | /* | ||
1812 | * SA Query response is currently only used in AP mode | ||
1813 | * and it is processed in user space. | ||
1814 | */ | ||
1815 | return RX_CONTINUE; | ||
1604 | } | 1816 | } |
1605 | break; | 1817 | break; |
1606 | default: | 1818 | default: |
@@ -1616,10 +1828,14 @@ static ieee80211_rx_result debug_noinline | |||
1616 | ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | 1828 | ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) |
1617 | { | 1829 | { |
1618 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); | 1830 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); |
1831 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; | ||
1619 | 1832 | ||
1620 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | 1833 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) |
1621 | return RX_DROP_MONITOR; | 1834 | return RX_DROP_MONITOR; |
1622 | 1835 | ||
1836 | if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) | ||
1837 | return RX_DROP_MONITOR; | ||
1838 | |||
1623 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 1839 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
1624 | return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status); | 1840 | return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status); |
1625 | 1841 | ||
@@ -1956,7 +2172,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
1956 | rx.flags |= IEEE80211_RX_IN_SCAN; | 2172 | rx.flags |= IEEE80211_RX_IN_SCAN; |
1957 | 2173 | ||
1958 | ieee80211_parse_qos(&rx); | 2174 | ieee80211_parse_qos(&rx); |
1959 | ieee80211_verify_ip_alignment(&rx); | 2175 | ieee80211_verify_alignment(&rx); |
1960 | 2176 | ||
1961 | skb = rx.skb; | 2177 | skb = rx.skb; |
1962 | 2178 | ||
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index f5c7c3371929..282e6a0dec01 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | #include <linux/wireless.h> | 21 | #include <linux/wireless.h> |
22 | #include <linux/if_arp.h> | 22 | #include <linux/if_arp.h> |
23 | #include <linux/rtnetlink.h> | ||
23 | #include <net/mac80211.h> | 24 | #include <net/mac80211.h> |
24 | #include <net/iw_handler.h> | 25 | #include <net/iw_handler.h> |
25 | 26 | ||
@@ -395,7 +396,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
395 | return RX_QUEUED; | 396 | return RX_QUEUED; |
396 | } | 397 | } |
397 | 398 | ||
398 | static void ieee80211_send_nullfunc(struct ieee80211_local *local, | 399 | void ieee80211_send_nullfunc(struct ieee80211_local *local, |
399 | struct ieee80211_sub_if_data *sdata, | 400 | struct ieee80211_sub_if_data *sdata, |
400 | int powersave) | 401 | int powersave) |
401 | { | 402 | { |
@@ -472,8 +473,11 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) | |||
472 | netif_addr_unlock(local->mdev); | 473 | netif_addr_unlock(local->mdev); |
473 | netif_tx_unlock_bh(local->mdev); | 474 | netif_tx_unlock_bh(local->mdev); |
474 | 475 | ||
475 | rcu_read_lock(); | 476 | mutex_lock(&local->iflist_mtx); |
476 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 477 | list_for_each_entry(sdata, &local->interfaces, list) { |
478 | if (!netif_running(sdata->dev)) | ||
479 | continue; | ||
480 | |||
477 | /* Tell AP we're back */ | 481 | /* Tell AP we're back */ |
478 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 482 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
479 | if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { | 483 | if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { |
@@ -482,8 +486,10 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) | |||
482 | } | 486 | } |
483 | } else | 487 | } else |
484 | netif_tx_wake_all_queues(sdata->dev); | 488 | netif_tx_wake_all_queues(sdata->dev); |
489 | |||
490 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED); | ||
485 | } | 491 | } |
486 | rcu_read_unlock(); | 492 | mutex_unlock(&local->iflist_mtx); |
487 | 493 | ||
488 | done: | 494 | done: |
489 | ieee80211_mlme_notify_scan_completed(local); | 495 | ieee80211_mlme_notify_scan_completed(local); |
@@ -491,7 +497,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) | |||
491 | } | 497 | } |
492 | EXPORT_SYMBOL(ieee80211_scan_completed); | 498 | EXPORT_SYMBOL(ieee80211_scan_completed); |
493 | 499 | ||
494 | |||
495 | void ieee80211_scan_work(struct work_struct *work) | 500 | void ieee80211_scan_work(struct work_struct *work) |
496 | { | 501 | { |
497 | struct ieee80211_local *local = | 502 | struct ieee80211_local *local = |
@@ -633,8 +638,13 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | |||
633 | 638 | ||
634 | local->sw_scanning = true; | 639 | local->sw_scanning = true; |
635 | 640 | ||
636 | rcu_read_lock(); | 641 | mutex_lock(&local->iflist_mtx); |
637 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 642 | list_for_each_entry(sdata, &local->interfaces, list) { |
643 | if (!netif_running(sdata->dev)) | ||
644 | continue; | ||
645 | |||
646 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED); | ||
647 | |||
638 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 648 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
639 | if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { | 649 | if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { |
640 | netif_tx_stop_all_queues(sdata->dev); | 650 | netif_tx_stop_all_queues(sdata->dev); |
@@ -643,7 +653,7 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | |||
643 | } else | 653 | } else |
644 | netif_tx_stop_all_queues(sdata->dev); | 654 | netif_tx_stop_all_queues(sdata->dev); |
645 | } | 655 | } |
646 | rcu_read_unlock(); | 656 | mutex_unlock(&local->iflist_mtx); |
647 | 657 | ||
648 | if (ssid) { | 658 | if (ssid) { |
649 | local->scan_ssid_len = ssid_len; | 659 | local->scan_ssid_len = ssid_len; |
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index f72bad636d8e..8d4ec2968f8f 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c | |||
@@ -65,7 +65,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da | |||
65 | IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED; | 65 | IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED; |
66 | msr_report->u.action.u.measurement.msr_elem.type = request_ie->type; | 66 | msr_report->u.action.u.measurement.msr_elem.type = request_ie->type; |
67 | 67 | ||
68 | ieee80211_tx_skb(sdata, skb, 0); | 68 | ieee80211_tx_skb(sdata, skb, 1); |
69 | } | 69 | } |
70 | 70 | ||
71 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 71 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
@@ -84,3 +84,101 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | |||
84 | mgmt->sa, mgmt->bssid, | 84 | mgmt->sa, mgmt->bssid, |
85 | mgmt->u.action.u.measurement.dialog_token); | 85 | mgmt->u.action.u.measurement.dialog_token); |
86 | } | 86 | } |
87 | |||
88 | void ieee80211_chswitch_work(struct work_struct *work) | ||
89 | { | ||
90 | struct ieee80211_sub_if_data *sdata = | ||
91 | container_of(work, struct ieee80211_sub_if_data, u.sta.chswitch_work); | ||
92 | struct ieee80211_bss *bss; | ||
93 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
94 | |||
95 | if (!netif_running(sdata->dev)) | ||
96 | return; | ||
97 | |||
98 | bss = ieee80211_rx_bss_get(sdata->local, ifsta->bssid, | ||
99 | sdata->local->hw.conf.channel->center_freq, | ||
100 | ifsta->ssid, ifsta->ssid_len); | ||
101 | if (!bss) | ||
102 | goto exit; | ||
103 | |||
104 | sdata->local->oper_channel = sdata->local->csa_channel; | ||
105 | if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL)) | ||
106 | bss->freq = sdata->local->oper_channel->center_freq; | ||
107 | |||
108 | ieee80211_rx_bss_put(sdata->local, bss); | ||
109 | exit: | ||
110 | ifsta->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
111 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||
112 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
113 | } | ||
114 | |||
115 | void ieee80211_chswitch_timer(unsigned long data) | ||
116 | { | ||
117 | struct ieee80211_sub_if_data *sdata = | ||
118 | (struct ieee80211_sub_if_data *) data; | ||
119 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
120 | |||
121 | queue_work(sdata->local->hw.workqueue, &ifsta->chswitch_work); | ||
122 | } | ||
123 | |||
124 | void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, | ||
125 | struct ieee80211_channel_sw_ie *sw_elem, | ||
126 | struct ieee80211_bss *bss) | ||
127 | { | ||
128 | struct ieee80211_channel *new_ch; | ||
129 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
130 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); | ||
131 | |||
132 | /* FIXME: Handle ADHOC later */ | ||
133 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
134 | return; | ||
135 | |||
136 | if (ifsta->state != IEEE80211_STA_MLME_ASSOCIATED) | ||
137 | return; | ||
138 | |||
139 | if (sdata->local->sw_scanning || sdata->local->hw_scanning) | ||
140 | return; | ||
141 | |||
142 | /* Disregard subsequent beacons if we are already running a timer | ||
143 | processing a CSA */ | ||
144 | |||
145 | if (ifsta->flags & IEEE80211_STA_CSA_RECEIVED) | ||
146 | return; | ||
147 | |||
148 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | ||
149 | if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) | ||
150 | return; | ||
151 | |||
152 | sdata->local->csa_channel = new_ch; | ||
153 | |||
154 | if (sw_elem->count <= 1) { | ||
155 | queue_work(sdata->local->hw.workqueue, &ifsta->chswitch_work); | ||
156 | } else { | ||
157 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||
158 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
159 | ifsta->flags |= IEEE80211_STA_CSA_RECEIVED; | ||
160 | mod_timer(&ifsta->chswitch_timer, | ||
161 | jiffies + msecs_to_jiffies(sw_elem->count * bss->beacon_int)); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | ||
166 | u16 capab_info, u8 *pwr_constr_elem, | ||
167 | u8 pwr_constr_elem_len) | ||
168 | { | ||
169 | struct ieee80211_conf *conf = &sdata->local->hw.conf; | ||
170 | |||
171 | if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT)) | ||
172 | return; | ||
173 | |||
174 | /* Power constraint IE length should be 1 octet */ | ||
175 | if (pwr_constr_elem_len != 1) | ||
176 | return; | ||
177 | |||
178 | if ((*pwr_constr_elem <= conf->channel->max_power) && | ||
179 | (*pwr_constr_elem != sdata->local->power_constr_level)) { | ||
180 | sdata->local->power_constr_level = *pwr_constr_elem; | ||
181 | ieee80211_hw_config(sdata->local, 0); | ||
182 | } | ||
183 | } | ||
184 | |||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index e49a5b99cf10..d13a44b935e2 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -34,6 +34,7 @@ | |||
34 | * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the | 34 | * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the |
35 | * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next | 35 | * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next |
36 | * frame to this station is transmitted. | 36 | * frame to this station is transmitted. |
37 | * @WLAN_STA_MFP: Management frame protection is used with this STA. | ||
37 | */ | 38 | */ |
38 | enum ieee80211_sta_info_flags { | 39 | enum ieee80211_sta_info_flags { |
39 | WLAN_STA_AUTH = 1<<0, | 40 | WLAN_STA_AUTH = 1<<0, |
@@ -46,6 +47,7 @@ enum ieee80211_sta_info_flags { | |||
46 | WLAN_STA_WDS = 1<<7, | 47 | WLAN_STA_WDS = 1<<7, |
47 | WLAN_STA_PSPOLL = 1<<8, | 48 | WLAN_STA_PSPOLL = 1<<8, |
48 | WLAN_STA_CLEAR_PS_FILT = 1<<9, | 49 | WLAN_STA_CLEAR_PS_FILT = 1<<9, |
50 | WLAN_STA_MFP = 1<<10, | ||
49 | }; | 51 | }; |
50 | 52 | ||
51 | #define STA_TID_NUM 16 | 53 | #define STA_TID_NUM 16 |
@@ -382,8 +384,6 @@ static inline u32 get_sta_flags(struct sta_info *sta) | |||
382 | } | 384 | } |
383 | 385 | ||
384 | 386 | ||
385 | /* Maximum number of concurrently registered stations */ | ||
386 | #define MAX_STA_COUNT 2007 | ||
387 | 387 | ||
388 | #define STA_HASH_SIZE 256 | 388 | #define STA_HASH_SIZE 256 |
389 | #define STA_HASH(sta) (sta[5]) | 389 | #define STA_HASH(sta) (sta[5]) |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 4278e545638f..7b013fb0d27f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -330,6 +330,22 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) | |||
330 | return TX_CONTINUE; | 330 | return TX_CONTINUE; |
331 | } | 331 | } |
332 | 332 | ||
333 | static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta, | ||
334 | struct sk_buff *skb) | ||
335 | { | ||
336 | if (!ieee80211_is_mgmt(fc)) | ||
337 | return 0; | ||
338 | |||
339 | if (sta == NULL || !test_sta_flags(sta, WLAN_STA_MFP)) | ||
340 | return 0; | ||
341 | |||
342 | if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) | ||
343 | skb->data)) | ||
344 | return 0; | ||
345 | |||
346 | return 1; | ||
347 | } | ||
348 | |||
333 | static ieee80211_tx_result | 349 | static ieee80211_tx_result |
334 | ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | 350 | ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) |
335 | { | 351 | { |
@@ -409,11 +425,17 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
409 | tx->key = NULL; | 425 | tx->key = NULL; |
410 | else if (tx->sta && (key = rcu_dereference(tx->sta->key))) | 426 | else if (tx->sta && (key = rcu_dereference(tx->sta->key))) |
411 | tx->key = key; | 427 | tx->key = key; |
428 | else if (ieee80211_is_mgmt(hdr->frame_control) && | ||
429 | (key = rcu_dereference(tx->sdata->default_mgmt_key))) | ||
430 | tx->key = key; | ||
412 | else if ((key = rcu_dereference(tx->sdata->default_key))) | 431 | else if ((key = rcu_dereference(tx->sdata->default_key))) |
413 | tx->key = key; | 432 | tx->key = key; |
414 | else if (tx->sdata->drop_unencrypted && | 433 | else if (tx->sdata->drop_unencrypted && |
415 | (tx->skb->protocol != cpu_to_be16(ETH_P_PAE)) && | 434 | (tx->skb->protocol != cpu_to_be16(ETH_P_PAE)) && |
416 | !(info->flags & IEEE80211_TX_CTL_INJECTED)) { | 435 | !(info->flags & IEEE80211_TX_CTL_INJECTED) && |
436 | (!ieee80211_is_robust_mgmt_frame(hdr) || | ||
437 | (ieee80211_is_action(hdr->frame_control) && | ||
438 | tx->sta && test_sta_flags(tx->sta, WLAN_STA_MFP)))) { | ||
417 | I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); | 439 | I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); |
418 | return TX_DROP; | 440 | return TX_DROP; |
419 | } else | 441 | } else |
@@ -428,10 +450,19 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
428 | if (ieee80211_is_auth(hdr->frame_control)) | 450 | if (ieee80211_is_auth(hdr->frame_control)) |
429 | break; | 451 | break; |
430 | case ALG_TKIP: | 452 | case ALG_TKIP: |
431 | case ALG_CCMP: | ||
432 | if (!ieee80211_is_data_present(hdr->frame_control)) | 453 | if (!ieee80211_is_data_present(hdr->frame_control)) |
433 | tx->key = NULL; | 454 | tx->key = NULL; |
434 | break; | 455 | break; |
456 | case ALG_CCMP: | ||
457 | if (!ieee80211_is_data_present(hdr->frame_control) && | ||
458 | !ieee80211_use_mfp(hdr->frame_control, tx->sta, | ||
459 | tx->skb)) | ||
460 | tx->key = NULL; | ||
461 | break; | ||
462 | case ALG_AES_CMAC: | ||
463 | if (!ieee80211_is_mgmt(hdr->frame_control)) | ||
464 | tx->key = NULL; | ||
465 | break; | ||
435 | } | 466 | } |
436 | } | 467 | } |
437 | 468 | ||
@@ -787,6 +818,8 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | |||
787 | return ieee80211_crypto_tkip_encrypt(tx); | 818 | return ieee80211_crypto_tkip_encrypt(tx); |
788 | case ALG_CCMP: | 819 | case ALG_CCMP: |
789 | return ieee80211_crypto_ccmp_encrypt(tx); | 820 | return ieee80211_crypto_ccmp_encrypt(tx); |
821 | case ALG_AES_CMAC: | ||
822 | return ieee80211_crypto_aes_cmac_encrypt(tx); | ||
790 | } | 823 | } |
791 | 824 | ||
792 | /* not reached */ | 825 | /* not reached */ |
@@ -1053,7 +1086,6 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, | |||
1053 | if (skb) { | 1086 | if (skb) { |
1054 | if (netif_subqueue_stopped(local->mdev, skb)) | 1087 | if (netif_subqueue_stopped(local->mdev, skb)) |
1055 | return IEEE80211_TX_AGAIN; | 1088 | return IEEE80211_TX_AGAIN; |
1056 | info = IEEE80211_SKB_CB(skb); | ||
1057 | 1089 | ||
1058 | ret = local->ops->tx(local_to_hw(local), skb); | 1090 | ret = local->ops->tx(local_to_hw(local), skb); |
1059 | if (ret) | 1091 | if (ret) |
@@ -1296,6 +1328,19 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1296 | return 0; | 1328 | return 0; |
1297 | } | 1329 | } |
1298 | 1330 | ||
1331 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && | ||
1332 | local->hw.conf.dynamic_ps_timeout > 0) { | ||
1333 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
1334 | ieee80211_stop_queues_by_reason(&local->hw, | ||
1335 | IEEE80211_QUEUE_STOP_REASON_PS); | ||
1336 | queue_work(local->hw.workqueue, | ||
1337 | &local->dynamic_ps_disable_work); | ||
1338 | } | ||
1339 | |||
1340 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
1341 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | ||
1342 | } | ||
1343 | |||
1299 | memset(info, 0, sizeof(*info)); | 1344 | memset(info, 0, sizeof(*info)); |
1300 | 1345 | ||
1301 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | 1346 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; |
@@ -1475,19 +1520,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1475 | goto fail; | 1520 | goto fail; |
1476 | } | 1521 | } |
1477 | 1522 | ||
1478 | if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) && | ||
1479 | local->dynamic_ps_timeout > 0) { | ||
1480 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
1481 | ieee80211_stop_queues_by_reason(&local->hw, | ||
1482 | IEEE80211_QUEUE_STOP_REASON_PS); | ||
1483 | queue_work(local->hw.workqueue, | ||
1484 | &local->dynamic_ps_disable_work); | ||
1485 | } | ||
1486 | |||
1487 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
1488 | msecs_to_jiffies(local->dynamic_ps_timeout)); | ||
1489 | } | ||
1490 | |||
1491 | nh_pos = skb_network_header(skb) - skb->data; | 1523 | nh_pos = skb_network_header(skb) - skb->data; |
1492 | h_pos = skb_transport_header(skb) - skb->data; | 1524 | h_pos = skb_transport_header(skb) - skb->data; |
1493 | 1525 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index fb89e1d0aa03..73c7d7345abd 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -41,6 +41,15 @@ const unsigned char rfc1042_header[] __aligned(2) = | |||
41 | const unsigned char bridge_tunnel_header[] __aligned(2) = | 41 | const unsigned char bridge_tunnel_header[] __aligned(2) = |
42 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | 42 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; |
43 | 43 | ||
44 | struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) | ||
45 | { | ||
46 | struct ieee80211_local *local; | ||
47 | BUG_ON(!wiphy); | ||
48 | |||
49 | local = wiphy_priv(wiphy); | ||
50 | return &local->hw; | ||
51 | } | ||
52 | EXPORT_SYMBOL(wiphy_to_ieee80211_hw); | ||
44 | 53 | ||
45 | u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, | 54 | u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, |
46 | enum nl80211_iftype type) | 55 | enum nl80211_iftype type) |
@@ -352,8 +361,8 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
352 | } | 361 | } |
353 | } | 362 | } |
354 | 363 | ||
355 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | 364 | static void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, |
356 | enum queue_stop_reason reason) | 365 | enum queue_stop_reason reason) |
357 | { | 366 | { |
358 | struct ieee80211_local *local = hw_to_local(hw); | 367 | struct ieee80211_local *local = hw_to_local(hw); |
359 | unsigned long flags; | 368 | unsigned long flags; |
@@ -382,8 +391,8 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
382 | netif_stop_subqueue(local->mdev, queue); | 391 | netif_stop_subqueue(local->mdev, queue); |
383 | } | 392 | } |
384 | 393 | ||
385 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | 394 | static void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, |
386 | enum queue_stop_reason reason) | 395 | enum queue_stop_reason reason) |
387 | { | 396 | { |
388 | struct ieee80211_local *local = hw_to_local(hw); | 397 | struct ieee80211_local *local = hw_to_local(hw); |
389 | unsigned long flags; | 398 | unsigned long flags; |
@@ -459,7 +468,7 @@ void ieee80211_iterate_active_interfaces( | |||
459 | struct ieee80211_local *local = hw_to_local(hw); | 468 | struct ieee80211_local *local = hw_to_local(hw); |
460 | struct ieee80211_sub_if_data *sdata; | 469 | struct ieee80211_sub_if_data *sdata; |
461 | 470 | ||
462 | rtnl_lock(); | 471 | mutex_lock(&local->iflist_mtx); |
463 | 472 | ||
464 | list_for_each_entry(sdata, &local->interfaces, list) { | 473 | list_for_each_entry(sdata, &local->interfaces, list) { |
465 | switch (sdata->vif.type) { | 474 | switch (sdata->vif.type) { |
@@ -480,7 +489,7 @@ void ieee80211_iterate_active_interfaces( | |||
480 | &sdata->vif); | 489 | &sdata->vif); |
481 | } | 490 | } |
482 | 491 | ||
483 | rtnl_unlock(); | 492 | mutex_unlock(&local->iflist_mtx); |
484 | } | 493 | } |
485 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); | 494 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); |
486 | 495 | ||
@@ -653,6 +662,10 @@ void ieee802_11_parse_elems(u8 *start, size_t len, | |||
653 | elems->pwr_constr_elem = pos; | 662 | elems->pwr_constr_elem = pos; |
654 | elems->pwr_constr_elem_len = elen; | 663 | elems->pwr_constr_elem_len = elen; |
655 | break; | 664 | break; |
665 | case WLAN_EID_TIMEOUT_INTERVAL: | ||
666 | elems->timeout_int = pos; | ||
667 | elems->timeout_int_len = elen; | ||
668 | break; | ||
656 | default: | 669 | default: |
657 | break; | 670 | break; |
658 | } | 671 | } |
@@ -727,12 +740,12 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz) | |||
727 | return ret; | 740 | return ret; |
728 | } | 741 | } |
729 | 742 | ||
730 | u64 ieee80211_mandatory_rates(struct ieee80211_local *local, | 743 | u32 ieee80211_mandatory_rates(struct ieee80211_local *local, |
731 | enum ieee80211_band band) | 744 | enum ieee80211_band band) |
732 | { | 745 | { |
733 | struct ieee80211_supported_band *sband; | 746 | struct ieee80211_supported_band *sband; |
734 | struct ieee80211_rate *bitrates; | 747 | struct ieee80211_rate *bitrates; |
735 | u64 mandatory_rates; | 748 | u32 mandatory_rates; |
736 | enum ieee80211_rate_flags mandatory_flag; | 749 | enum ieee80211_rate_flags mandatory_flag; |
737 | int i; | 750 | int i; |
738 | 751 | ||
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 7162d5816f39..5c88b8246bbb 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -37,7 +37,14 @@ static int ieee80211_set_encryption(struct ieee80211_sub_if_data *sdata, u8 *sta | |||
37 | struct ieee80211_key *key; | 37 | struct ieee80211_key *key; |
38 | int err; | 38 | int err; |
39 | 39 | ||
40 | if (idx < 0 || idx >= NUM_DEFAULT_KEYS) { | 40 | if (alg == ALG_AES_CMAC) { |
41 | if (idx < NUM_DEFAULT_KEYS || | ||
42 | idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) { | ||
43 | printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d " | ||
44 | "(BIP)\n", sdata->dev->name, idx); | ||
45 | return -EINVAL; | ||
46 | } | ||
47 | } else if (idx < 0 || idx >= NUM_DEFAULT_KEYS) { | ||
41 | printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n", | 48 | printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n", |
42 | sdata->dev->name, idx); | 49 | sdata->dev->name, idx); |
43 | return -EINVAL; | 50 | return -EINVAL; |
@@ -103,6 +110,9 @@ static int ieee80211_set_encryption(struct ieee80211_sub_if_data *sdata, u8 *sta | |||
103 | 110 | ||
104 | if (set_tx_key || (!sta && !sdata->default_key && key)) | 111 | if (set_tx_key || (!sta && !sdata->default_key && key)) |
105 | ieee80211_set_default_key(sdata, idx); | 112 | ieee80211_set_default_key(sdata, idx); |
113 | if (alg == ALG_AES_CMAC && | ||
114 | (set_tx_key || (!sta && !sdata->default_mgmt_key && key))) | ||
115 | ieee80211_set_default_mgmt_key(sdata, idx); | ||
106 | } | 116 | } |
107 | 117 | ||
108 | out_unlock: | 118 | out_unlock: |
@@ -230,13 +240,15 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, | |||
230 | { | 240 | { |
231 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 241 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
232 | 242 | ||
233 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 243 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC || |
244 | sdata->vif.type == NL80211_IFTYPE_STATION) | ||
234 | sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; | 245 | sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; |
235 | 246 | ||
236 | /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ | 247 | /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ |
237 | if (freq->e == 0) { | 248 | if (freq->e == 0) { |
238 | if (freq->m < 0) { | 249 | if (freq->m < 0) { |
239 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 250 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC || |
251 | sdata->vif.type == NL80211_IFTYPE_STATION) | ||
240 | sdata->u.sta.flags |= | 252 | sdata->u.sta.flags |= |
241 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 253 | IEEE80211_STA_AUTO_CHANNEL_SEL; |
242 | return 0; | 254 | return 0; |
@@ -549,10 +561,9 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev, | |||
549 | else /* Automatic power level setting */ | 561 | else /* Automatic power level setting */ |
550 | new_power_level = chan->max_power; | 562 | new_power_level = chan->max_power; |
551 | 563 | ||
552 | if (local->hw.conf.power_level != new_power_level) { | 564 | local->user_power_level = new_power_level; |
553 | local->hw.conf.power_level = new_power_level; | 565 | if (local->hw.conf.power_level != new_power_level) |
554 | reconf_flags |= IEEE80211_CONF_CHANGE_POWER; | 566 | reconf_flags |= IEEE80211_CONF_CHANGE_POWER; |
555 | } | ||
556 | 567 | ||
557 | if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { | 568 | if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { |
558 | local->hw.conf.radio_enabled = !(data->txpower.disabled); | 569 | local->hw.conf.radio_enabled = !(data->txpower.disabled); |
@@ -836,6 +847,9 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, | |||
836 | int ret = 0, timeout = 0; | 847 | int ret = 0, timeout = 0; |
837 | bool ps; | 848 | bool ps; |
838 | 849 | ||
850 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) | ||
851 | return -EOPNOTSUPP; | ||
852 | |||
839 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 853 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
840 | return -EINVAL; | 854 | return -EINVAL; |
841 | 855 | ||
@@ -852,31 +866,49 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, | |||
852 | ps = true; | 866 | ps = true; |
853 | break; | 867 | break; |
854 | default: /* Otherwise we ignore */ | 868 | default: /* Otherwise we ignore */ |
855 | break; | 869 | return -EINVAL; |
856 | } | 870 | } |
857 | 871 | ||
872 | if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT)) | ||
873 | return -EINVAL; | ||
874 | |||
858 | if (wrq->flags & IW_POWER_TIMEOUT) | 875 | if (wrq->flags & IW_POWER_TIMEOUT) |
859 | timeout = wrq->value / 1000; | 876 | timeout = wrq->value / 1000; |
860 | 877 | ||
861 | set: | 878 | set: |
862 | if (ps == local->powersave && timeout == local->dynamic_ps_timeout) | 879 | if (ps == local->powersave && timeout == conf->dynamic_ps_timeout) |
863 | return ret; | 880 | return ret; |
864 | 881 | ||
865 | local->powersave = ps; | 882 | local->powersave = ps; |
866 | local->dynamic_ps_timeout = timeout; | 883 | conf->dynamic_ps_timeout = timeout; |
867 | 884 | ||
868 | if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { | 885 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) |
869 | if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) && | 886 | ret = ieee80211_hw_config(local, |
870 | local->dynamic_ps_timeout > 0) | 887 | IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT); |
871 | mod_timer(&local->dynamic_ps_timer, jiffies + | 888 | |
872 | msecs_to_jiffies(local->dynamic_ps_timeout)); | 889 | if (!(sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)) |
873 | else { | 890 | return ret; |
874 | if (local->powersave) | 891 | |
875 | conf->flags |= IEEE80211_CONF_PS; | 892 | if (conf->dynamic_ps_timeout > 0 && |
876 | else | 893 | !(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) { |
877 | conf->flags &= ~IEEE80211_CONF_PS; | 894 | mod_timer(&local->dynamic_ps_timer, jiffies + |
895 | msecs_to_jiffies(conf->dynamic_ps_timeout)); | ||
896 | } else { | ||
897 | if (local->powersave) { | ||
898 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | ||
899 | ieee80211_send_nullfunc(local, sdata, 1); | ||
900 | conf->flags |= IEEE80211_CONF_PS; | ||
901 | ret = ieee80211_hw_config(local, | ||
902 | IEEE80211_CONF_CHANGE_PS); | ||
903 | } else { | ||
904 | conf->flags &= ~IEEE80211_CONF_PS; | ||
905 | ret = ieee80211_hw_config(local, | ||
906 | IEEE80211_CONF_CHANGE_PS); | ||
907 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | ||
908 | ieee80211_send_nullfunc(local, sdata, 0); | ||
909 | del_timer_sync(&local->dynamic_ps_timer); | ||
910 | cancel_work_sync(&local->dynamic_ps_enable_work); | ||
878 | } | 911 | } |
879 | ret = ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
880 | } | 912 | } |
881 | 913 | ||
882 | return ret; | 914 | return ret; |
@@ -903,11 +935,22 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev, | |||
903 | 935 | ||
904 | switch (data->flags & IW_AUTH_INDEX) { | 936 | switch (data->flags & IW_AUTH_INDEX) { |
905 | case IW_AUTH_WPA_VERSION: | 937 | case IW_AUTH_WPA_VERSION: |
906 | case IW_AUTH_CIPHER_PAIRWISE: | ||
907 | case IW_AUTH_CIPHER_GROUP: | 938 | case IW_AUTH_CIPHER_GROUP: |
908 | case IW_AUTH_WPA_ENABLED: | 939 | case IW_AUTH_WPA_ENABLED: |
909 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | 940 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: |
910 | case IW_AUTH_KEY_MGMT: | 941 | case IW_AUTH_KEY_MGMT: |
942 | case IW_AUTH_CIPHER_GROUP_MGMT: | ||
943 | break; | ||
944 | case IW_AUTH_CIPHER_PAIRWISE: | ||
945 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
946 | if (data->value & (IW_AUTH_CIPHER_WEP40 | | ||
947 | IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_TKIP)) | ||
948 | sdata->u.sta.flags |= | ||
949 | IEEE80211_STA_TKIP_WEP_USED; | ||
950 | else | ||
951 | sdata->u.sta.flags &= | ||
952 | ~IEEE80211_STA_TKIP_WEP_USED; | ||
953 | } | ||
911 | break; | 954 | break; |
912 | case IW_AUTH_DROP_UNENCRYPTED: | 955 | case IW_AUTH_DROP_UNENCRYPTED: |
913 | sdata->drop_unencrypted = !!data->value; | 956 | sdata->drop_unencrypted = !!data->value; |
@@ -934,6 +977,17 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev, | |||
934 | else | 977 | else |
935 | ret = -EOPNOTSUPP; | 978 | ret = -EOPNOTSUPP; |
936 | break; | 979 | break; |
980 | case IW_AUTH_MFP: | ||
981 | if (!(sdata->local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) { | ||
982 | ret = -EOPNOTSUPP; | ||
983 | break; | ||
984 | } | ||
985 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | ||
986 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
987 | sdata->u.sta.mfp = data->value; | ||
988 | else | ||
989 | ret = -EOPNOTSUPP; | ||
990 | break; | ||
937 | default: | 991 | default: |
938 | ret = -EOPNOTSUPP; | 992 | ret = -EOPNOTSUPP; |
939 | break; | 993 | break; |
@@ -1017,6 +1071,9 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev, | |||
1017 | case IW_ENCODE_ALG_CCMP: | 1071 | case IW_ENCODE_ALG_CCMP: |
1018 | alg = ALG_CCMP; | 1072 | alg = ALG_CCMP; |
1019 | break; | 1073 | break; |
1074 | case IW_ENCODE_ALG_AES_CMAC: | ||
1075 | alg = ALG_AES_CMAC; | ||
1076 | break; | ||
1020 | default: | 1077 | default: |
1021 | return -EOPNOTSUPP; | 1078 | return -EOPNOTSUPP; |
1022 | } | 1079 | } |
@@ -1025,20 +1082,41 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev, | |||
1025 | remove = 1; | 1082 | remove = 1; |
1026 | 1083 | ||
1027 | idx = erq->flags & IW_ENCODE_INDEX; | 1084 | idx = erq->flags & IW_ENCODE_INDEX; |
1028 | if (idx < 1 || idx > 4) { | 1085 | if (alg == ALG_AES_CMAC) { |
1029 | idx = -1; | 1086 | if (idx < NUM_DEFAULT_KEYS + 1 || |
1030 | if (!sdata->default_key) | 1087 | idx > NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) { |
1031 | idx = 0; | 1088 | idx = -1; |
1032 | else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | 1089 | if (!sdata->default_mgmt_key) |
1033 | if (sdata->default_key == sdata->keys[i]) { | 1090 | idx = 0; |
1034 | idx = i; | 1091 | else for (i = NUM_DEFAULT_KEYS; |
1035 | break; | 1092 | i < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS; |
1093 | i++) { | ||
1094 | if (sdata->default_mgmt_key == sdata->keys[i]) | ||
1095 | { | ||
1096 | idx = i; | ||
1097 | break; | ||
1098 | } | ||
1036 | } | 1099 | } |
1037 | } | 1100 | if (idx < 0) |
1038 | if (idx < 0) | 1101 | return -EINVAL; |
1039 | return -EINVAL; | 1102 | } else |
1040 | } else | 1103 | idx--; |
1041 | idx--; | 1104 | } else { |
1105 | if (idx < 1 || idx > 4) { | ||
1106 | idx = -1; | ||
1107 | if (!sdata->default_key) | ||
1108 | idx = 0; | ||
1109 | else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | ||
1110 | if (sdata->default_key == sdata->keys[i]) { | ||
1111 | idx = i; | ||
1112 | break; | ||
1113 | } | ||
1114 | } | ||
1115 | if (idx < 0) | ||
1116 | return -EINVAL; | ||
1117 | } else | ||
1118 | idx--; | ||
1119 | } | ||
1042 | 1120 | ||
1043 | return ieee80211_set_encryption(sdata, ext->addr.sa_data, idx, alg, | 1121 | return ieee80211_set_encryption(sdata, ext->addr.sa_data, idx, alg, |
1044 | remove, | 1122 | remove, |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 7aa63caf8d50..9101b48ec2ae 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2002-2004, Instant802 Networks, Inc. | 2 | * Copyright 2002-2004, Instant802 Networks, Inc. |
3 | * Copyright 2008, Jouni Malinen <j@w1.fi> | ||
3 | * | 4 | * |
4 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License version 2 as | 6 | * it under the terms of the GNU General Public License version 2 as |
@@ -19,6 +20,7 @@ | |||
19 | #include "michael.h" | 20 | #include "michael.h" |
20 | #include "tkip.h" | 21 | #include "tkip.h" |
21 | #include "aes_ccm.h" | 22 | #include "aes_ccm.h" |
23 | #include "aes_cmac.h" | ||
22 | #include "wpa.h" | 24 | #include "wpa.h" |
23 | 25 | ||
24 | ieee80211_tx_result | 26 | ieee80211_tx_result |
@@ -266,7 +268,7 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch, | |||
266 | int encrypted) | 268 | int encrypted) |
267 | { | 269 | { |
268 | __le16 mask_fc; | 270 | __le16 mask_fc; |
269 | int a4_included; | 271 | int a4_included, mgmt; |
270 | u8 qos_tid; | 272 | u8 qos_tid; |
271 | u8 *b_0, *aad; | 273 | u8 *b_0, *aad; |
272 | u16 data_len, len_a; | 274 | u16 data_len, len_a; |
@@ -277,12 +279,15 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch, | |||
277 | aad = scratch + 4 * AES_BLOCK_LEN; | 279 | aad = scratch + 4 * AES_BLOCK_LEN; |
278 | 280 | ||
279 | /* | 281 | /* |
280 | * Mask FC: zero subtype b4 b5 b6 | 282 | * Mask FC: zero subtype b4 b5 b6 (if not mgmt) |
281 | * Retry, PwrMgt, MoreData; set Protected | 283 | * Retry, PwrMgt, MoreData; set Protected |
282 | */ | 284 | */ |
285 | mgmt = ieee80211_is_mgmt(hdr->frame_control); | ||
283 | mask_fc = hdr->frame_control; | 286 | mask_fc = hdr->frame_control; |
284 | mask_fc &= ~cpu_to_le16(0x0070 | IEEE80211_FCTL_RETRY | | 287 | mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY | |
285 | IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA); | 288 | IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA); |
289 | if (!mgmt) | ||
290 | mask_fc &= ~cpu_to_le16(0x0070); | ||
286 | mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | 291 | mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); |
287 | 292 | ||
288 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 293 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
@@ -300,8 +305,10 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch, | |||
300 | 305 | ||
301 | /* First block, b_0 */ | 306 | /* First block, b_0 */ |
302 | b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */ | 307 | b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */ |
303 | /* Nonce: QoS Priority | A2 | PN */ | 308 | /* Nonce: Nonce Flags | A2 | PN |
304 | b_0[1] = qos_tid; | 309 | * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7) |
310 | */ | ||
311 | b_0[1] = qos_tid | (mgmt << 4); | ||
305 | memcpy(&b_0[2], hdr->addr2, ETH_ALEN); | 312 | memcpy(&b_0[2], hdr->addr2, ETH_ALEN); |
306 | memcpy(&b_0[8], pn, CCMP_PN_LEN); | 313 | memcpy(&b_0[8], pn, CCMP_PN_LEN); |
307 | /* l(m) */ | 314 | /* l(m) */ |
@@ -360,9 +367,14 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
360 | int hdrlen, len, tail; | 367 | int hdrlen, len, tail; |
361 | u8 *pos, *pn; | 368 | u8 *pos, *pn; |
362 | int i; | 369 | int i; |
370 | bool skip_hw; | ||
371 | |||
372 | skip_hw = (tx->key->conf.flags & IEEE80211_KEY_FLAG_SW_MGMT) && | ||
373 | ieee80211_is_mgmt(hdr->frame_control); | ||
363 | 374 | ||
364 | if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && | 375 | if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && |
365 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { | 376 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && |
377 | !skip_hw) { | ||
366 | /* hwaccel - with no need for preallocated room for CCMP | 378 | /* hwaccel - with no need for preallocated room for CCMP |
367 | * header or MIC fields */ | 379 | * header or MIC fields */ |
368 | info->control.hw_key = &tx->key->conf; | 380 | info->control.hw_key = &tx->key->conf; |
@@ -397,7 +409,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
397 | 409 | ||
398 | ccmp_pn2hdr(pos, pn, key->conf.keyidx); | 410 | ccmp_pn2hdr(pos, pn, key->conf.keyidx); |
399 | 411 | ||
400 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { | 412 | if ((key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !skip_hw) { |
401 | /* hwaccel - with preallocated room for CCMP header */ | 413 | /* hwaccel - with preallocated room for CCMP header */ |
402 | info->control.hw_key = &tx->key->conf; | 414 | info->control.hw_key = &tx->key->conf; |
403 | return 0; | 415 | return 0; |
@@ -446,7 +458,8 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
446 | 458 | ||
447 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 459 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
448 | 460 | ||
449 | if (!ieee80211_is_data(hdr->frame_control)) | 461 | if (!ieee80211_is_data(hdr->frame_control) && |
462 | !ieee80211_is_robust_mgmt_frame(hdr)) | ||
450 | return RX_CONTINUE; | 463 | return RX_CONTINUE; |
451 | 464 | ||
452 | data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN; | 465 | data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN; |
@@ -485,3 +498,126 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
485 | 498 | ||
486 | return RX_CONTINUE; | 499 | return RX_CONTINUE; |
487 | } | 500 | } |
501 | |||
502 | |||
503 | static void bip_aad(struct sk_buff *skb, u8 *aad) | ||
504 | { | ||
505 | /* BIP AAD: FC(masked) || A1 || A2 || A3 */ | ||
506 | |||
507 | /* FC type/subtype */ | ||
508 | aad[0] = skb->data[0]; | ||
509 | /* Mask FC Retry, PwrMgt, MoreData flags to zero */ | ||
510 | aad[1] = skb->data[1] & ~(BIT(4) | BIT(5) | BIT(6)); | ||
511 | /* A1 || A2 || A3 */ | ||
512 | memcpy(aad + 2, skb->data + 4, 3 * ETH_ALEN); | ||
513 | } | ||
514 | |||
515 | |||
516 | static inline void bip_ipn_swap(u8 *d, const u8 *s) | ||
517 | { | ||
518 | *d++ = s[5]; | ||
519 | *d++ = s[4]; | ||
520 | *d++ = s[3]; | ||
521 | *d++ = s[2]; | ||
522 | *d++ = s[1]; | ||
523 | *d = s[0]; | ||
524 | } | ||
525 | |||
526 | |||
527 | ieee80211_tx_result | ||
528 | ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx) | ||
529 | { | ||
530 | struct sk_buff *skb = tx->skb; | ||
531 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
532 | struct ieee80211_key *key = tx->key; | ||
533 | struct ieee80211_mmie *mmie; | ||
534 | u8 *pn, aad[20]; | ||
535 | int i; | ||
536 | |||
537 | if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { | ||
538 | /* hwaccel */ | ||
539 | info->control.hw_key = &tx->key->conf; | ||
540 | return 0; | ||
541 | } | ||
542 | |||
543 | if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) | ||
544 | return TX_DROP; | ||
545 | |||
546 | mmie = (struct ieee80211_mmie *) skb_put(skb, sizeof(*mmie)); | ||
547 | mmie->element_id = WLAN_EID_MMIE; | ||
548 | mmie->length = sizeof(*mmie) - 2; | ||
549 | mmie->key_id = cpu_to_le16(key->conf.keyidx); | ||
550 | |||
551 | /* PN = PN + 1 */ | ||
552 | pn = key->u.aes_cmac.tx_pn; | ||
553 | |||
554 | for (i = sizeof(key->u.aes_cmac.tx_pn) - 1; i >= 0; i--) { | ||
555 | pn[i]++; | ||
556 | if (pn[i]) | ||
557 | break; | ||
558 | } | ||
559 | bip_ipn_swap(mmie->sequence_number, pn); | ||
560 | |||
561 | bip_aad(skb, aad); | ||
562 | |||
563 | /* | ||
564 | * MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) | ||
565 | */ | ||
566 | ieee80211_aes_cmac(key->u.aes_cmac.tfm, key->u.aes_cmac.tx_crypto_buf, | ||
567 | aad, skb->data + 24, skb->len - 24, mmie->mic); | ||
568 | |||
569 | return TX_CONTINUE; | ||
570 | } | ||
571 | |||
572 | |||
573 | ieee80211_rx_result | ||
574 | ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) | ||
575 | { | ||
576 | struct sk_buff *skb = rx->skb; | ||
577 | struct ieee80211_key *key = rx->key; | ||
578 | struct ieee80211_mmie *mmie; | ||
579 | u8 aad[20], mic[8], ipn[6]; | ||
580 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
581 | |||
582 | if (!ieee80211_is_mgmt(hdr->frame_control)) | ||
583 | return RX_CONTINUE; | ||
584 | |||
585 | if ((rx->status->flag & RX_FLAG_DECRYPTED) && | ||
586 | (rx->status->flag & RX_FLAG_IV_STRIPPED)) | ||
587 | return RX_CONTINUE; | ||
588 | |||
589 | if (skb->len < 24 + sizeof(*mmie)) | ||
590 | return RX_DROP_UNUSABLE; | ||
591 | |||
592 | mmie = (struct ieee80211_mmie *) | ||
593 | (skb->data + skb->len - sizeof(*mmie)); | ||
594 | if (mmie->element_id != WLAN_EID_MMIE || | ||
595 | mmie->length != sizeof(*mmie) - 2) | ||
596 | return RX_DROP_UNUSABLE; /* Invalid MMIE */ | ||
597 | |||
598 | bip_ipn_swap(ipn, mmie->sequence_number); | ||
599 | |||
600 | if (memcmp(ipn, key->u.aes_cmac.rx_pn, 6) <= 0) { | ||
601 | key->u.aes_cmac.replays++; | ||
602 | return RX_DROP_UNUSABLE; | ||
603 | } | ||
604 | |||
605 | if (!(rx->status->flag & RX_FLAG_DECRYPTED)) { | ||
606 | /* hardware didn't decrypt/verify MIC */ | ||
607 | bip_aad(skb, aad); | ||
608 | ieee80211_aes_cmac(key->u.aes_cmac.tfm, | ||
609 | key->u.aes_cmac.rx_crypto_buf, aad, | ||
610 | skb->data + 24, skb->len - 24, mic); | ||
611 | if (memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) { | ||
612 | key->u.aes_cmac.icverrors++; | ||
613 | return RX_DROP_UNUSABLE; | ||
614 | } | ||
615 | } | ||
616 | |||
617 | memcpy(key->u.aes_cmac.rx_pn, ipn, 6); | ||
618 | |||
619 | /* Remove MMIE */ | ||
620 | skb_trim(skb, skb->len - sizeof(*mmie)); | ||
621 | |||
622 | return RX_CONTINUE; | ||
623 | } | ||
diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index d42d221d8a1d..baba0608313e 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h | |||
@@ -28,4 +28,9 @@ ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx); | |||
28 | ieee80211_rx_result | 28 | ieee80211_rx_result |
29 | ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx); | 29 | ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx); |
30 | 30 | ||
31 | ieee80211_tx_result | ||
32 | ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx); | ||
33 | ieee80211_rx_result | ||
34 | ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx); | ||
35 | |||
31 | #endif /* WPA_H */ | 36 | #endif /* WPA_H */ |
diff --git a/net/wireless/core.c b/net/wireless/core.c index b96fc0c3f1c4..125226476089 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -273,10 +273,16 @@ int wiphy_register(struct wiphy *wiphy) | |||
273 | 273 | ||
274 | sband->band = band; | 274 | sband->band = band; |
275 | 275 | ||
276 | if (!sband->n_channels || !sband->n_bitrates) { | 276 | if (WARN_ON(!sband->n_channels || !sband->n_bitrates)) |
277 | WARN_ON(1); | 277 | return -EINVAL; |
278 | |||
279 | /* | ||
280 | * Since we use a u32 for rate bitmaps in | ||
281 | * ieee80211_get_response_rate, we cannot | ||
282 | * have more than 32 legacy rates. | ||
283 | */ | ||
284 | if (WARN_ON(sband->n_bitrates > 32)) | ||
278 | return -EINVAL; | 285 | return -EINVAL; |
279 | } | ||
280 | 286 | ||
281 | for (i = 0; i < sband->n_channels; i++) { | 287 | for (i = 0; i < sband->n_channels; i++) { |
282 | sband->channels[i].orig_flags = | 288 | sband->channels[i].orig_flags = |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1e728fff474e..e69da8d20474 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -105,6 +105,10 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
105 | 105 | ||
106 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, | 106 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, |
107 | .len = NL80211_HT_CAPABILITY_LEN }, | 107 | .len = NL80211_HT_CAPABILITY_LEN }, |
108 | |||
109 | [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, | ||
110 | [NL80211_ATTR_IE] = { .type = NLA_BINARY, | ||
111 | .len = IEEE80211_MAX_DATA_LEN }, | ||
108 | }; | 112 | }; |
109 | 113 | ||
110 | /* message building helper */ | 114 | /* message building helper */ |
@@ -738,7 +742,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
738 | if (info->attrs[NL80211_ATTR_KEY_IDX]) | 742 | if (info->attrs[NL80211_ATTR_KEY_IDX]) |
739 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | 743 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); |
740 | 744 | ||
741 | if (key_idx > 3) | 745 | if (key_idx > 5) |
742 | return -EINVAL; | 746 | return -EINVAL; |
743 | 747 | ||
744 | if (info->attrs[NL80211_ATTR_MAC]) | 748 | if (info->attrs[NL80211_ATTR_MAC]) |
@@ -804,30 +808,41 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
804 | int err; | 808 | int err; |
805 | struct net_device *dev; | 809 | struct net_device *dev; |
806 | u8 key_idx; | 810 | u8 key_idx; |
811 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, | ||
812 | u8 key_index); | ||
807 | 813 | ||
808 | if (!info->attrs[NL80211_ATTR_KEY_IDX]) | 814 | if (!info->attrs[NL80211_ATTR_KEY_IDX]) |
809 | return -EINVAL; | 815 | return -EINVAL; |
810 | 816 | ||
811 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | 817 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); |
812 | 818 | ||
813 | if (key_idx > 3) | 819 | if (info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) { |
820 | if (key_idx < 4 || key_idx > 5) | ||
821 | return -EINVAL; | ||
822 | } else if (key_idx > 3) | ||
814 | return -EINVAL; | 823 | return -EINVAL; |
815 | 824 | ||
816 | /* currently only support setting default key */ | 825 | /* currently only support setting default key */ |
817 | if (!info->attrs[NL80211_ATTR_KEY_DEFAULT]) | 826 | if (!info->attrs[NL80211_ATTR_KEY_DEFAULT] && |
827 | !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) | ||
818 | return -EINVAL; | 828 | return -EINVAL; |
819 | 829 | ||
820 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 830 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
821 | if (err) | 831 | if (err) |
822 | return err; | 832 | return err; |
823 | 833 | ||
824 | if (!drv->ops->set_default_key) { | 834 | if (info->attrs[NL80211_ATTR_KEY_DEFAULT]) |
835 | func = drv->ops->set_default_key; | ||
836 | else | ||
837 | func = drv->ops->set_default_mgmt_key; | ||
838 | |||
839 | if (!func) { | ||
825 | err = -EOPNOTSUPP; | 840 | err = -EOPNOTSUPP; |
826 | goto out; | 841 | goto out; |
827 | } | 842 | } |
828 | 843 | ||
829 | rtnl_lock(); | 844 | rtnl_lock(); |
830 | err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx); | 845 | err = func(&drv->wiphy, dev, key_idx); |
831 | rtnl_unlock(); | 846 | rtnl_unlock(); |
832 | 847 | ||
833 | out: | 848 | out: |
@@ -863,7 +878,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
863 | if (info->attrs[NL80211_ATTR_MAC]) | 878 | if (info->attrs[NL80211_ATTR_MAC]) |
864 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 879 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
865 | 880 | ||
866 | if (key_idx > 3) | 881 | if (key_idx > 5) |
867 | return -EINVAL; | 882 | return -EINVAL; |
868 | 883 | ||
869 | /* | 884 | /* |
@@ -894,6 +909,10 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
894 | if (params.key_len != 13) | 909 | if (params.key_len != 13) |
895 | return -EINVAL; | 910 | return -EINVAL; |
896 | break; | 911 | break; |
912 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
913 | if (params.key_len != 16) | ||
914 | return -EINVAL; | ||
915 | break; | ||
897 | default: | 916 | default: |
898 | return -EINVAL; | 917 | return -EINVAL; |
899 | } | 918 | } |
@@ -928,7 +947,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
928 | if (info->attrs[NL80211_ATTR_KEY_IDX]) | 947 | if (info->attrs[NL80211_ATTR_KEY_IDX]) |
929 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | 948 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); |
930 | 949 | ||
931 | if (key_idx > 3) | 950 | if (key_idx > 5) |
932 | return -EINVAL; | 951 | return -EINVAL; |
933 | 952 | ||
934 | if (info->attrs[NL80211_ATTR_MAC]) | 953 | if (info->attrs[NL80211_ATTR_MAC]) |
@@ -1889,6 +1908,11 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
1889 | mutex_lock(&cfg80211_drv_mutex); | 1908 | mutex_lock(&cfg80211_drv_mutex); |
1890 | r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY); | 1909 | r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY); |
1891 | mutex_unlock(&cfg80211_drv_mutex); | 1910 | mutex_unlock(&cfg80211_drv_mutex); |
1911 | /* This means the regulatory domain was already set, however | ||
1912 | * we don't want to confuse userspace with a "successful error" | ||
1913 | * message so lets just treat it as a success */ | ||
1914 | if (r == -EALREADY) | ||
1915 | r = 0; | ||
1892 | return r; | 1916 | return r; |
1893 | } | 1917 | } |
1894 | 1918 | ||
@@ -2134,6 +2158,43 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2134 | return -EINVAL; | 2158 | return -EINVAL; |
2135 | } | 2159 | } |
2136 | 2160 | ||
2161 | static int nl80211_set_mgmt_extra_ie(struct sk_buff *skb, | ||
2162 | struct genl_info *info) | ||
2163 | { | ||
2164 | struct cfg80211_registered_device *drv; | ||
2165 | int err; | ||
2166 | struct net_device *dev; | ||
2167 | struct mgmt_extra_ie_params params; | ||
2168 | |||
2169 | memset(¶ms, 0, sizeof(params)); | ||
2170 | |||
2171 | if (!info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) | ||
2172 | return -EINVAL; | ||
2173 | params.subtype = nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]); | ||
2174 | if (params.subtype > 15) | ||
2175 | return -EINVAL; /* FC Subtype field is 4 bits (0..15) */ | ||
2176 | |||
2177 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2178 | params.ies = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2179 | params.ies_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2180 | } | ||
2181 | |||
2182 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2183 | if (err) | ||
2184 | return err; | ||
2185 | |||
2186 | if (drv->ops->set_mgmt_extra_ie) { | ||
2187 | rtnl_lock(); | ||
2188 | err = drv->ops->set_mgmt_extra_ie(&drv->wiphy, dev, ¶ms); | ||
2189 | rtnl_unlock(); | ||
2190 | } else | ||
2191 | err = -EOPNOTSUPP; | ||
2192 | |||
2193 | cfg80211_put_dev(drv); | ||
2194 | dev_put(dev); | ||
2195 | return err; | ||
2196 | } | ||
2197 | |||
2137 | static struct genl_ops nl80211_ops[] = { | 2198 | static struct genl_ops nl80211_ops[] = { |
2138 | { | 2199 | { |
2139 | .cmd = NL80211_CMD_GET_WIPHY, | 2200 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -2295,6 +2356,12 @@ static struct genl_ops nl80211_ops[] = { | |||
2295 | .policy = nl80211_policy, | 2356 | .policy = nl80211_policy, |
2296 | .flags = GENL_ADMIN_PERM, | 2357 | .flags = GENL_ADMIN_PERM, |
2297 | }, | 2358 | }, |
2359 | { | ||
2360 | .cmd = NL80211_CMD_SET_MGMT_EXTRA_IE, | ||
2361 | .doit = nl80211_set_mgmt_extra_ie, | ||
2362 | .policy = nl80211_policy, | ||
2363 | .flags = GENL_ADMIN_PERM, | ||
2364 | }, | ||
2298 | }; | 2365 | }; |
2299 | 2366 | ||
2300 | /* multicast groups */ | 2367 | /* multicast groups */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 85c9034c59b2..f643d3981102 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -42,38 +42,6 @@ | |||
42 | #include "core.h" | 42 | #include "core.h" |
43 | #include "reg.h" | 43 | #include "reg.h" |
44 | 44 | ||
45 | /** | ||
46 | * struct regulatory_request - receipt of last regulatory request | ||
47 | * | ||
48 | * @wiphy: this is set if this request's initiator is | ||
49 | * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This | ||
50 | * can be used by the wireless core to deal with conflicts | ||
51 | * and potentially inform users of which devices specifically | ||
52 | * cased the conflicts. | ||
53 | * @initiator: indicates who sent this request, could be any of | ||
54 | * of those set in reg_set_by, %REGDOM_SET_BY_* | ||
55 | * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested | ||
56 | * regulatory domain. We have a few special codes: | ||
57 | * 00 - World regulatory domain | ||
58 | * 99 - built by driver but a specific alpha2 cannot be determined | ||
59 | * 98 - result of an intersection between two regulatory domains | ||
60 | * @intersect: indicates whether the wireless core should intersect | ||
61 | * the requested regulatory domain with the presently set regulatory | ||
62 | * domain. | ||
63 | * @country_ie_checksum: checksum of the last processed and accepted | ||
64 | * country IE | ||
65 | * @country_ie_env: lets us know if the AP is telling us we are outdoor, | ||
66 | * indoor, or if it doesn't matter | ||
67 | */ | ||
68 | struct regulatory_request { | ||
69 | struct wiphy *wiphy; | ||
70 | enum reg_set_by initiator; | ||
71 | char alpha2[2]; | ||
72 | bool intersect; | ||
73 | u32 country_ie_checksum; | ||
74 | enum environment_cap country_ie_env; | ||
75 | }; | ||
76 | |||
77 | /* Receipt of information from last regulatory request */ | 45 | /* Receipt of information from last regulatory request */ |
78 | static struct regulatory_request *last_request; | 46 | static struct regulatory_request *last_request; |
79 | 47 | ||
@@ -790,42 +758,35 @@ static u32 map_regdom_flags(u32 rd_flags) | |||
790 | return channel_flags; | 758 | return channel_flags; |
791 | } | 759 | } |
792 | 760 | ||
793 | /** | 761 | static int freq_reg_info_regd(struct wiphy *wiphy, |
794 | * freq_reg_info - get regulatory information for the given frequency | 762 | u32 center_freq, |
795 | * @center_freq: Frequency in KHz for which we want regulatory information for | 763 | u32 *bandwidth, |
796 | * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one | 764 | const struct ieee80211_reg_rule **reg_rule, |
797 | * you can set this to 0. If this frequency is allowed we then set | 765 | const struct ieee80211_regdomain *custom_regd) |
798 | * this value to the maximum allowed bandwidth. | ||
799 | * @reg_rule: the regulatory rule which we have for this frequency | ||
800 | * | ||
801 | * Use this function to get the regulatory rule for a specific frequency on | ||
802 | * a given wireless device. If the device has a specific regulatory domain | ||
803 | * it wants to follow we respect that unless a country IE has been received | ||
804 | * and processed already. | ||
805 | * | ||
806 | * Returns 0 if it was able to find a valid regulatory rule which does | ||
807 | * apply to the given center_freq otherwise it returns non-zero. It will | ||
808 | * also return -ERANGE if we determine the given center_freq does not even have | ||
809 | * a regulatory rule for a frequency range in the center_freq's band. See | ||
810 | * freq_in_rule_band() for our current definition of a band -- this is purely | ||
811 | * subjective and right now its 802.11 specific. | ||
812 | */ | ||
813 | static int freq_reg_info(u32 center_freq, u32 *bandwidth, | ||
814 | const struct ieee80211_reg_rule **reg_rule) | ||
815 | { | 766 | { |
816 | int i; | 767 | int i; |
817 | bool band_rule_found = false; | 768 | bool band_rule_found = false; |
769 | const struct ieee80211_regdomain *regd; | ||
818 | u32 max_bandwidth = 0; | 770 | u32 max_bandwidth = 0; |
819 | 771 | ||
820 | if (!cfg80211_regdomain) | 772 | regd = custom_regd ? custom_regd : cfg80211_regdomain; |
773 | |||
774 | /* Follow the driver's regulatory domain, if present, unless a country | ||
775 | * IE has been processed or a user wants to help complaince further */ | ||
776 | if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE && | ||
777 | last_request->initiator != REGDOM_SET_BY_USER && | ||
778 | wiphy->regd) | ||
779 | regd = wiphy->regd; | ||
780 | |||
781 | if (!regd) | ||
821 | return -EINVAL; | 782 | return -EINVAL; |
822 | 783 | ||
823 | for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) { | 784 | for (i = 0; i < regd->n_reg_rules; i++) { |
824 | const struct ieee80211_reg_rule *rr; | 785 | const struct ieee80211_reg_rule *rr; |
825 | const struct ieee80211_freq_range *fr = NULL; | 786 | const struct ieee80211_freq_range *fr = NULL; |
826 | const struct ieee80211_power_rule *pr = NULL; | 787 | const struct ieee80211_power_rule *pr = NULL; |
827 | 788 | ||
828 | rr = &cfg80211_regdomain->reg_rules[i]; | 789 | rr = ®d->reg_rules[i]; |
829 | fr = &rr->freq_range; | 790 | fr = &rr->freq_range; |
830 | pr = &rr->power_rule; | 791 | pr = &rr->power_rule; |
831 | 792 | ||
@@ -849,6 +810,14 @@ static int freq_reg_info(u32 center_freq, u32 *bandwidth, | |||
849 | 810 | ||
850 | return !max_bandwidth; | 811 | return !max_bandwidth; |
851 | } | 812 | } |
813 | EXPORT_SYMBOL(freq_reg_info); | ||
814 | |||
815 | int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth, | ||
816 | const struct ieee80211_reg_rule **reg_rule) | ||
817 | { | ||
818 | return freq_reg_info_regd(wiphy, center_freq, | ||
819 | bandwidth, reg_rule, NULL); | ||
820 | } | ||
852 | 821 | ||
853 | static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | 822 | static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, |
854 | unsigned int chan_idx) | 823 | unsigned int chan_idx) |
@@ -867,7 +836,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
867 | 836 | ||
868 | flags = chan->orig_flags; | 837 | flags = chan->orig_flags; |
869 | 838 | ||
870 | r = freq_reg_info(MHZ_TO_KHZ(chan->center_freq), | 839 | r = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq), |
871 | &max_bandwidth, ®_rule); | 840 | &max_bandwidth, ®_rule); |
872 | 841 | ||
873 | if (r) { | 842 | if (r) { |
@@ -907,6 +876,22 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
907 | 876 | ||
908 | power_rule = ®_rule->power_rule; | 877 | power_rule = ®_rule->power_rule; |
909 | 878 | ||
879 | if (last_request->initiator == REGDOM_SET_BY_DRIVER && | ||
880 | last_request->wiphy && last_request->wiphy == wiphy && | ||
881 | last_request->wiphy->strict_regulatory) { | ||
882 | /* This gaurantees the driver's requested regulatory domain | ||
883 | * will always be used as a base for further regulatory | ||
884 | * settings */ | ||
885 | chan->flags = chan->orig_flags = | ||
886 | map_regdom_flags(reg_rule->flags); | ||
887 | chan->max_antenna_gain = chan->orig_mag = | ||
888 | (int) MBI_TO_DBI(power_rule->max_antenna_gain); | ||
889 | chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); | ||
890 | chan->max_power = chan->orig_mpwr = | ||
891 | (int) MBM_TO_DBM(power_rule->max_eirp); | ||
892 | return; | ||
893 | } | ||
894 | |||
910 | chan->flags = flags | map_regdom_flags(reg_rule->flags); | 895 | chan->flags = flags | map_regdom_flags(reg_rule->flags); |
911 | chan->max_antenna_gain = min(chan->orig_mag, | 896 | chan->max_antenna_gain = min(chan->orig_mag, |
912 | (int) MBI_TO_DBI(power_rule->max_antenna_gain)); | 897 | (int) MBI_TO_DBI(power_rule->max_antenna_gain)); |
@@ -935,7 +920,12 @@ static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby) | |||
935 | if (!last_request) | 920 | if (!last_request) |
936 | return true; | 921 | return true; |
937 | if (setby == REGDOM_SET_BY_CORE && | 922 | if (setby == REGDOM_SET_BY_CORE && |
938 | wiphy->fw_handles_regulatory) | 923 | wiphy->custom_regulatory) |
924 | return true; | ||
925 | /* wiphy->regd will be set once the device has its own | ||
926 | * desired regulatory domain set */ | ||
927 | if (wiphy->strict_regulatory && !wiphy->regd && | ||
928 | !is_world_regdom(last_request->alpha2)) | ||
939 | return true; | 929 | return true; |
940 | return false; | 930 | return false; |
941 | } | 931 | } |
@@ -945,20 +935,103 @@ static void update_all_wiphy_regulatory(enum reg_set_by setby) | |||
945 | struct cfg80211_registered_device *drv; | 935 | struct cfg80211_registered_device *drv; |
946 | 936 | ||
947 | list_for_each_entry(drv, &cfg80211_drv_list, list) | 937 | list_for_each_entry(drv, &cfg80211_drv_list, list) |
948 | if (!ignore_reg_update(&drv->wiphy, setby)) | 938 | wiphy_update_regulatory(&drv->wiphy, setby); |
949 | wiphy_update_regulatory(&drv->wiphy, setby); | ||
950 | } | 939 | } |
951 | 940 | ||
952 | void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) | 941 | void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) |
953 | { | 942 | { |
954 | enum ieee80211_band band; | 943 | enum ieee80211_band band; |
944 | |||
945 | if (ignore_reg_update(wiphy, setby)) | ||
946 | return; | ||
955 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 947 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
956 | if (wiphy->bands[band]) | 948 | if (wiphy->bands[band]) |
957 | handle_band(wiphy, band); | 949 | handle_band(wiphy, band); |
958 | if (wiphy->reg_notifier) | 950 | } |
959 | wiphy->reg_notifier(wiphy, setby); | 951 | if (wiphy->reg_notifier) |
952 | wiphy->reg_notifier(wiphy, last_request); | ||
953 | } | ||
954 | |||
955 | static void handle_channel_custom(struct wiphy *wiphy, | ||
956 | enum ieee80211_band band, | ||
957 | unsigned int chan_idx, | ||
958 | const struct ieee80211_regdomain *regd) | ||
959 | { | ||
960 | int r; | ||
961 | u32 max_bandwidth = 0; | ||
962 | const struct ieee80211_reg_rule *reg_rule = NULL; | ||
963 | const struct ieee80211_power_rule *power_rule = NULL; | ||
964 | struct ieee80211_supported_band *sband; | ||
965 | struct ieee80211_channel *chan; | ||
966 | |||
967 | sband = wiphy->bands[band]; | ||
968 | BUG_ON(chan_idx >= sband->n_channels); | ||
969 | chan = &sband->channels[chan_idx]; | ||
970 | |||
971 | r = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq), | ||
972 | &max_bandwidth, ®_rule, regd); | ||
973 | |||
974 | if (r) { | ||
975 | chan->flags = IEEE80211_CHAN_DISABLED; | ||
976 | return; | ||
977 | } | ||
978 | |||
979 | power_rule = ®_rule->power_rule; | ||
980 | |||
981 | chan->flags |= map_regdom_flags(reg_rule->flags); | ||
982 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); | ||
983 | chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); | ||
984 | chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); | ||
985 | } | ||
986 | |||
987 | static void handle_band_custom(struct wiphy *wiphy, enum ieee80211_band band, | ||
988 | const struct ieee80211_regdomain *regd) | ||
989 | { | ||
990 | unsigned int i; | ||
991 | struct ieee80211_supported_band *sband; | ||
992 | |||
993 | BUG_ON(!wiphy->bands[band]); | ||
994 | sband = wiphy->bands[band]; | ||
995 | |||
996 | for (i = 0; i < sband->n_channels; i++) | ||
997 | handle_channel_custom(wiphy, band, i, regd); | ||
998 | } | ||
999 | |||
1000 | /* Used by drivers prior to wiphy registration */ | ||
1001 | void wiphy_apply_custom_regulatory(struct wiphy *wiphy, | ||
1002 | const struct ieee80211_regdomain *regd) | ||
1003 | { | ||
1004 | enum ieee80211_band band; | ||
1005 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
1006 | if (wiphy->bands[band]) | ||
1007 | handle_band_custom(wiphy, band, regd); | ||
960 | } | 1008 | } |
961 | } | 1009 | } |
1010 | EXPORT_SYMBOL(wiphy_apply_custom_regulatory); | ||
1011 | |||
1012 | static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, | ||
1013 | const struct ieee80211_regdomain *src_regd) | ||
1014 | { | ||
1015 | struct ieee80211_regdomain *regd; | ||
1016 | int size_of_regd = 0; | ||
1017 | unsigned int i; | ||
1018 | |||
1019 | size_of_regd = sizeof(struct ieee80211_regdomain) + | ||
1020 | ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule)); | ||
1021 | |||
1022 | regd = kzalloc(size_of_regd, GFP_KERNEL); | ||
1023 | if (!regd) | ||
1024 | return -ENOMEM; | ||
1025 | |||
1026 | memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain)); | ||
1027 | |||
1028 | for (i = 0; i < src_regd->n_reg_rules; i++) | ||
1029 | memcpy(®d->reg_rules[i], &src_regd->reg_rules[i], | ||
1030 | sizeof(struct ieee80211_reg_rule)); | ||
1031 | |||
1032 | *dst_regd = regd; | ||
1033 | return 0; | ||
1034 | } | ||
962 | 1035 | ||
963 | /* Return value which can be used by ignore_request() to indicate | 1036 | /* Return value which can be used by ignore_request() to indicate |
964 | * it has been determined we should intersect two regulatory domains */ | 1037 | * it has been determined we should intersect two regulatory domains */ |
@@ -1007,9 +1080,14 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, | |||
1007 | } | 1080 | } |
1008 | return REG_INTERSECT; | 1081 | return REG_INTERSECT; |
1009 | case REGDOM_SET_BY_DRIVER: | 1082 | case REGDOM_SET_BY_DRIVER: |
1010 | if (last_request->initiator == REGDOM_SET_BY_DRIVER) | 1083 | if (last_request->initiator == REGDOM_SET_BY_CORE) { |
1084 | if (is_old_static_regdom(cfg80211_regdomain)) | ||
1085 | return 0; | ||
1086 | if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) | ||
1087 | return 0; | ||
1011 | return -EALREADY; | 1088 | return -EALREADY; |
1012 | return 0; | 1089 | } |
1090 | return REG_INTERSECT; | ||
1013 | case REGDOM_SET_BY_USER: | 1091 | case REGDOM_SET_BY_USER: |
1014 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) | 1092 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) |
1015 | return REG_INTERSECT; | 1093 | return REG_INTERSECT; |
@@ -1018,6 +1096,20 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, | |||
1018 | if (last_request->initiator == REGDOM_SET_BY_USER && | 1096 | if (last_request->initiator == REGDOM_SET_BY_USER && |
1019 | last_request->intersect) | 1097 | last_request->intersect) |
1020 | return -EOPNOTSUPP; | 1098 | return -EOPNOTSUPP; |
1099 | /* Process user requests only after previous user/driver/core | ||
1100 | * requests have been processed */ | ||
1101 | if (last_request->initiator == REGDOM_SET_BY_CORE || | ||
1102 | last_request->initiator == REGDOM_SET_BY_DRIVER || | ||
1103 | last_request->initiator == REGDOM_SET_BY_USER) { | ||
1104 | if (!alpha2_equal(last_request->alpha2, | ||
1105 | cfg80211_regdomain->alpha2)) | ||
1106 | return -EAGAIN; | ||
1107 | } | ||
1108 | |||
1109 | if (!is_old_static_regdom(cfg80211_regdomain) && | ||
1110 | alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) | ||
1111 | return -EALREADY; | ||
1112 | |||
1021 | return 0; | 1113 | return 0; |
1022 | } | 1114 | } |
1023 | 1115 | ||
@@ -1036,11 +1128,28 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, | |||
1036 | 1128 | ||
1037 | r = ignore_request(wiphy, set_by, alpha2); | 1129 | r = ignore_request(wiphy, set_by, alpha2); |
1038 | 1130 | ||
1039 | if (r == REG_INTERSECT) | 1131 | if (r == REG_INTERSECT) { |
1132 | if (set_by == REGDOM_SET_BY_DRIVER) { | ||
1133 | r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain); | ||
1134 | if (r) | ||
1135 | return r; | ||
1136 | } | ||
1040 | intersect = true; | 1137 | intersect = true; |
1041 | else if (r) | 1138 | } else if (r) { |
1139 | /* If the regulatory domain being requested by the | ||
1140 | * driver has already been set just copy it to the | ||
1141 | * wiphy */ | ||
1142 | if (r == -EALREADY && set_by == REGDOM_SET_BY_DRIVER) { | ||
1143 | r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain); | ||
1144 | if (r) | ||
1145 | return r; | ||
1146 | r = -EALREADY; | ||
1147 | goto new_request; | ||
1148 | } | ||
1042 | return r; | 1149 | return r; |
1150 | } | ||
1043 | 1151 | ||
1152 | new_request: | ||
1044 | request = kzalloc(sizeof(struct regulatory_request), | 1153 | request = kzalloc(sizeof(struct regulatory_request), |
1045 | GFP_KERNEL); | 1154 | GFP_KERNEL); |
1046 | if (!request) | 1155 | if (!request) |
@@ -1056,6 +1165,11 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, | |||
1056 | 1165 | ||
1057 | kfree(last_request); | 1166 | kfree(last_request); |
1058 | last_request = request; | 1167 | last_request = request; |
1168 | |||
1169 | /* When r == REG_INTERSECT we do need to call CRDA */ | ||
1170 | if (r < 0) | ||
1171 | return r; | ||
1172 | |||
1059 | /* | 1173 | /* |
1060 | * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled | 1174 | * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled |
1061 | * AND if CRDA is NOT present nothing will happen, if someone | 1175 | * AND if CRDA is NOT present nothing will happen, if someone |
@@ -1071,10 +1185,15 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, | |||
1071 | 1185 | ||
1072 | void regulatory_hint(struct wiphy *wiphy, const char *alpha2) | 1186 | void regulatory_hint(struct wiphy *wiphy, const char *alpha2) |
1073 | { | 1187 | { |
1188 | int r; | ||
1074 | BUG_ON(!alpha2); | 1189 | BUG_ON(!alpha2); |
1075 | 1190 | ||
1076 | mutex_lock(&cfg80211_drv_mutex); | 1191 | mutex_lock(&cfg80211_drv_mutex); |
1077 | __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2, 0, ENVIRON_ANY); | 1192 | r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, |
1193 | alpha2, 0, ENVIRON_ANY); | ||
1194 | /* This is required so that the orig_* parameters are saved */ | ||
1195 | if (r == -EALREADY && wiphy->strict_regulatory) | ||
1196 | wiphy_update_regulatory(wiphy, REGDOM_SET_BY_DRIVER); | ||
1078 | mutex_unlock(&cfg80211_drv_mutex); | 1197 | mutex_unlock(&cfg80211_drv_mutex); |
1079 | } | 1198 | } |
1080 | EXPORT_SYMBOL(regulatory_hint); | 1199 | EXPORT_SYMBOL(regulatory_hint); |
@@ -1247,7 +1366,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) | |||
1247 | "domain intersected: \n"); | 1366 | "domain intersected: \n"); |
1248 | } else | 1367 | } else |
1249 | printk(KERN_INFO "cfg80211: Current regulatory " | 1368 | printk(KERN_INFO "cfg80211: Current regulatory " |
1250 | "intersected: \n"); | 1369 | "domain intersected: \n"); |
1251 | } else if (is_world_regdom(rd->alpha2)) | 1370 | } else if (is_world_regdom(rd->alpha2)) |
1252 | printk(KERN_INFO "cfg80211: World regulatory " | 1371 | printk(KERN_INFO "cfg80211: World regulatory " |
1253 | "domain updated:\n"); | 1372 | "domain updated:\n"); |
@@ -1349,6 +1468,23 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1349 | } | 1468 | } |
1350 | 1469 | ||
1351 | if (!last_request->intersect) { | 1470 | if (!last_request->intersect) { |
1471 | int r; | ||
1472 | |||
1473 | if (last_request->initiator != REGDOM_SET_BY_DRIVER) { | ||
1474 | reset_regdomains(); | ||
1475 | cfg80211_regdomain = rd; | ||
1476 | return 0; | ||
1477 | } | ||
1478 | |||
1479 | /* For a driver hint, lets copy the regulatory domain the | ||
1480 | * driver wanted to the wiphy to deal with conflicts */ | ||
1481 | |||
1482 | BUG_ON(last_request->wiphy->regd); | ||
1483 | |||
1484 | r = reg_copy_regd(&last_request->wiphy->regd, rd); | ||
1485 | if (r) | ||
1486 | return r; | ||
1487 | |||
1352 | reset_regdomains(); | 1488 | reset_regdomains(); |
1353 | cfg80211_regdomain = rd; | 1489 | cfg80211_regdomain = rd; |
1354 | return 0; | 1490 | return 0; |
@@ -1362,8 +1498,14 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1362 | if (!intersected_rd) | 1498 | if (!intersected_rd) |
1363 | return -EINVAL; | 1499 | return -EINVAL; |
1364 | 1500 | ||
1365 | /* We can trash what CRDA provided now */ | 1501 | /* We can trash what CRDA provided now. |
1366 | kfree(rd); | 1502 | * However if a driver requested this specific regulatory |
1503 | * domain we keep it for its private use */ | ||
1504 | if (last_request->initiator == REGDOM_SET_BY_DRIVER) | ||
1505 | last_request->wiphy->regd = rd; | ||
1506 | else | ||
1507 | kfree(rd); | ||
1508 | |||
1367 | rd = NULL; | 1509 | rd = NULL; |
1368 | 1510 | ||
1369 | reset_regdomains(); | 1511 | reset_regdomains(); |
@@ -1447,6 +1589,7 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
1447 | /* Caller must hold cfg80211_drv_mutex */ | 1589 | /* Caller must hold cfg80211_drv_mutex */ |
1448 | void reg_device_remove(struct wiphy *wiphy) | 1590 | void reg_device_remove(struct wiphy *wiphy) |
1449 | { | 1591 | { |
1592 | kfree(wiphy->regd); | ||
1450 | if (!last_request || !last_request->wiphy) | 1593 | if (!last_request || !last_request->wiphy) |
1451 | return; | 1594 | return; |
1452 | if (last_request->wiphy != wiphy) | 1595 | if (last_request->wiphy != wiphy) |
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index a76ea3ff7cd6..eb1dd5bc9b27 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -11,13 +11,6 @@ void regulatory_exit(void); | |||
11 | 11 | ||
12 | int set_regdom(const struct ieee80211_regdomain *rd); | 12 | int set_regdom(const struct ieee80211_regdomain *rd); |
13 | 13 | ||
14 | enum environment_cap { | ||
15 | ENVIRON_ANY, | ||
16 | ENVIRON_INDOOR, | ||
17 | ENVIRON_OUTDOOR, | ||
18 | }; | ||
19 | |||
20 | |||
21 | /** | 14 | /** |
22 | * __regulatory_hint - hint to the wireless core a regulatory domain | 15 | * __regulatory_hint - hint to the wireless core a regulatory domain |
23 | * @wiphy: if the hint comes from country information from an AP, this | 16 | * @wiphy: if the hint comes from country information from an AP, this |
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 79a382877641..26a72b0797a0 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c | |||
@@ -55,6 +55,34 @@ static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
55 | } | 55 | } |
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | static int wiphy_suspend(struct device *dev, pm_message_t state) | ||
59 | { | ||
60 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); | ||
61 | int ret = 0; | ||
62 | |||
63 | if (rdev->ops->suspend) { | ||
64 | rtnl_lock(); | ||
65 | ret = rdev->ops->suspend(&rdev->wiphy); | ||
66 | rtnl_unlock(); | ||
67 | } | ||
68 | |||
69 | return ret; | ||
70 | } | ||
71 | |||
72 | static int wiphy_resume(struct device *dev) | ||
73 | { | ||
74 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); | ||
75 | int ret = 0; | ||
76 | |||
77 | if (rdev->ops->resume) { | ||
78 | rtnl_lock(); | ||
79 | ret = rdev->ops->resume(&rdev->wiphy); | ||
80 | rtnl_unlock(); | ||
81 | } | ||
82 | |||
83 | return ret; | ||
84 | } | ||
85 | |||
58 | struct class ieee80211_class = { | 86 | struct class ieee80211_class = { |
59 | .name = "ieee80211", | 87 | .name = "ieee80211", |
60 | .owner = THIS_MODULE, | 88 | .owner = THIS_MODULE, |
@@ -63,6 +91,8 @@ struct class ieee80211_class = { | |||
63 | #ifdef CONFIG_HOTPLUG | 91 | #ifdef CONFIG_HOTPLUG |
64 | .dev_uevent = wiphy_uevent, | 92 | .dev_uevent = wiphy_uevent, |
65 | #endif | 93 | #endif |
94 | .suspend = wiphy_suspend, | ||
95 | .resume = wiphy_resume, | ||
66 | }; | 96 | }; |
67 | 97 | ||
68 | int wiphy_sysfs_init(void) | 98 | int wiphy_sysfs_init(void) |
diff --git a/net/wireless/util.c b/net/wireless/util.c index e76cc28b0345..487cdd9bcffc 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -9,7 +9,7 @@ | |||
9 | 9 | ||
10 | struct ieee80211_rate * | 10 | struct ieee80211_rate * |
11 | ieee80211_get_response_rate(struct ieee80211_supported_band *sband, | 11 | ieee80211_get_response_rate(struct ieee80211_supported_band *sband, |
12 | u64 basic_rates, int bitrate) | 12 | u32 basic_rates, int bitrate) |
13 | { | 13 | { |
14 | struct ieee80211_rate *result = &sband->bitrates[0]; | 14 | struct ieee80211_rate *result = &sband->bitrates[0]; |
15 | int i; | 15 | int i; |