diff options
author | David S. Miller <davem@davemloft.net> | 2016-09-18 22:29:08 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-09-18 22:29:08 -0400 |
commit | c13ed534b8db543e4d8ead3885f4b06585a5771c (patch) | |
tree | b371024a63efe057e0bed95fc5ed77900b113e7d /net | |
parent | 22da73492541736eff5f6a6634c732e36c52a133 (diff) | |
parent | fbd05e4a6e82fd573d3aa79e284e424b8d78c149 (diff) |
Merge tag 'mac80211-next-for-davem-2016-09-16' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg says:
====================
This time we have various things - all across the board:
* MU-MIMO sniffer support in mac80211
* a create_singlethread_workqueue() cleanup
* interface dump filtering that was documented but not implemented
* support for the new radiotap timestamp field
* send delBA in two unexpected conditions (as required by the spec)
* connect keys cleanups - allow only WEP with index 0-3
* per-station aggregation limit to work around broken APs
* debugfs improvement for the integrated codel algorithm
and various other small improvements and cleanups.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
30 files changed, 404 insertions, 264 deletions
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index a9aff6079c42..a5d69dfc8e03 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -298,10 +298,13 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, | |||
298 | buf_size = IEEE80211_MAX_AMPDU_BUF; | 298 | buf_size = IEEE80211_MAX_AMPDU_BUF; |
299 | 299 | ||
300 | /* make sure the size doesn't exceed the maximum supported by the hw */ | 300 | /* make sure the size doesn't exceed the maximum supported by the hw */ |
301 | if (buf_size > local->hw.max_rx_aggregation_subframes) | 301 | if (buf_size > sta->sta.max_rx_aggregation_subframes) |
302 | buf_size = local->hw.max_rx_aggregation_subframes; | 302 | buf_size = sta->sta.max_rx_aggregation_subframes; |
303 | params.buf_size = buf_size; | 303 | params.buf_size = buf_size; |
304 | 304 | ||
305 | ht_dbg(sta->sdata, "AddBA Req buf_size=%d for %pM\n", | ||
306 | buf_size, sta->sta.addr); | ||
307 | |||
305 | /* examine state machine */ | 308 | /* examine state machine */ |
306 | mutex_lock(&sta->ampdu_mlme.mtx); | 309 | mutex_lock(&sta->ampdu_mlme.mtx); |
307 | 310 | ||
@@ -406,8 +409,10 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, | |||
406 | } | 409 | } |
407 | 410 | ||
408 | end: | 411 | end: |
409 | if (status == WLAN_STATUS_SUCCESS) | 412 | if (status == WLAN_STATUS_SUCCESS) { |
410 | __set_bit(tid, sta->ampdu_mlme.agg_session_valid); | 413 | __set_bit(tid, sta->ampdu_mlme.agg_session_valid); |
414 | __clear_bit(tid, sta->ampdu_mlme.unexpected_agg); | ||
415 | } | ||
411 | mutex_unlock(&sta->ampdu_mlme.mtx); | 416 | mutex_unlock(&sta->ampdu_mlme.mtx); |
412 | 417 | ||
413 | end_no_lock: | 418 | end_no_lock: |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 543b1d4fc33d..e29ff5749944 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -39,7 +39,7 @@ static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, | |||
39 | 39 | ||
40 | if (type == NL80211_IFTYPE_MONITOR && flags) { | 40 | if (type == NL80211_IFTYPE_MONITOR && flags) { |
41 | sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | 41 | sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
42 | sdata->u.mntr_flags = *flags; | 42 | sdata->u.mntr.flags = *flags; |
43 | } | 43 | } |
44 | 44 | ||
45 | return wdev; | 45 | return wdev; |
@@ -73,8 +73,29 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
73 | sdata->u.mgd.use_4addr = params->use_4addr; | 73 | sdata->u.mgd.use_4addr = params->use_4addr; |
74 | } | 74 | } |
75 | 75 | ||
76 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) { | 76 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { |
77 | struct ieee80211_local *local = sdata->local; | 77 | struct ieee80211_local *local = sdata->local; |
78 | struct ieee80211_sub_if_data *monitor_sdata; | ||
79 | u32 mu_mntr_cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER; | ||
80 | |||
81 | monitor_sdata = rtnl_dereference(local->monitor_sdata); | ||
82 | if (monitor_sdata && | ||
83 | wiphy_ext_feature_isset(wiphy, mu_mntr_cap_flag)) { | ||
84 | memcpy(monitor_sdata->vif.bss_conf.mu_group.membership, | ||
85 | params->vht_mumimo_groups, WLAN_MEMBERSHIP_LEN); | ||
86 | memcpy(monitor_sdata->vif.bss_conf.mu_group.position, | ||
87 | params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN, | ||
88 | WLAN_USER_POSITION_LEN); | ||
89 | monitor_sdata->vif.mu_mimo_owner = true; | ||
90 | ieee80211_bss_info_change_notify(monitor_sdata, | ||
91 | BSS_CHANGED_MU_GROUPS); | ||
92 | |||
93 | ether_addr_copy(monitor_sdata->u.mntr.mu_follow_addr, | ||
94 | params->macaddr); | ||
95 | } | ||
96 | |||
97 | if (!flags) | ||
98 | return 0; | ||
78 | 99 | ||
79 | if (ieee80211_sdata_running(sdata)) { | 100 | if (ieee80211_sdata_running(sdata)) { |
80 | u32 mask = MONITOR_FLAG_COOK_FRAMES | | 101 | u32 mask = MONITOR_FLAG_COOK_FRAMES | |
@@ -89,11 +110,11 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
89 | * cooked_mntrs, monitor and all fif_* counters | 110 | * cooked_mntrs, monitor and all fif_* counters |
90 | * reconfigure hardware | 111 | * reconfigure hardware |
91 | */ | 112 | */ |
92 | if ((*flags & mask) != (sdata->u.mntr_flags & mask)) | 113 | if ((*flags & mask) != (sdata->u.mntr.flags & mask)) |
93 | return -EBUSY; | 114 | return -EBUSY; |
94 | 115 | ||
95 | ieee80211_adjust_monitor_flags(sdata, -1); | 116 | ieee80211_adjust_monitor_flags(sdata, -1); |
96 | sdata->u.mntr_flags = *flags; | 117 | sdata->u.mntr.flags = *flags; |
97 | ieee80211_adjust_monitor_flags(sdata, 1); | 118 | ieee80211_adjust_monitor_flags(sdata, 1); |
98 | 119 | ||
99 | ieee80211_configure_filter(local); | 120 | ieee80211_configure_filter(local); |
@@ -103,7 +124,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
103 | * and ieee80211_do_open take care of "everything" | 124 | * and ieee80211_do_open take care of "everything" |
104 | * mentioned in the comment above. | 125 | * mentioned in the comment above. |
105 | */ | 126 | */ |
106 | sdata->u.mntr_flags = *flags; | 127 | sdata->u.mntr.flags = *flags; |
107 | } | 128 | } |
108 | } | 129 | } |
109 | 130 | ||
@@ -2940,10 +2961,6 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
2940 | } | 2961 | } |
2941 | 2962 | ||
2942 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); | 2963 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); |
2943 | if (!chanctx) { | ||
2944 | err = -EBUSY; | ||
2945 | goto out; | ||
2946 | } | ||
2947 | 2964 | ||
2948 | ch_switch.timestamp = 0; | 2965 | ch_switch.timestamp = 0; |
2949 | ch_switch.device_timestamp = 0; | 2966 | ch_switch.device_timestamp = 0; |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 2906c1004e1a..8ca62b6bb02a 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -71,138 +71,39 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x", | |||
71 | DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s", | 71 | DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s", |
72 | local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); | 72 | local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); |
73 | 73 | ||
74 | struct aqm_info { | 74 | static ssize_t aqm_read(struct file *file, |
75 | struct ieee80211_local *local; | 75 | char __user *user_buf, |
76 | size_t size; | 76 | size_t count, |
77 | size_t len; | 77 | loff_t *ppos) |
78 | unsigned char buf[0]; | ||
79 | }; | ||
80 | |||
81 | #define AQM_HDR_LEN 200 | ||
82 | #define AQM_HW_ENTRY_LEN 40 | ||
83 | #define AQM_TXQ_ENTRY_LEN 110 | ||
84 | |||
85 | static int aqm_open(struct inode *inode, struct file *file) | ||
86 | { | 78 | { |
87 | struct ieee80211_local *local = inode->i_private; | 79 | struct ieee80211_local *local = file->private_data; |
88 | struct ieee80211_sub_if_data *sdata; | ||
89 | struct sta_info *sta; | ||
90 | struct txq_info *txqi; | ||
91 | struct fq *fq = &local->fq; | 80 | struct fq *fq = &local->fq; |
92 | struct aqm_info *info = NULL; | 81 | char buf[200]; |
93 | int len = 0; | 82 | int len = 0; |
94 | int i; | ||
95 | |||
96 | if (!local->ops->wake_tx_queue) | ||
97 | return -EOPNOTSUPP; | ||
98 | |||
99 | len += AQM_HDR_LEN; | ||
100 | len += 6 * AQM_HW_ENTRY_LEN; | ||
101 | |||
102 | rcu_read_lock(); | ||
103 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | ||
104 | len += AQM_TXQ_ENTRY_LEN; | ||
105 | list_for_each_entry_rcu(sta, &local->sta_list, list) | ||
106 | len += AQM_TXQ_ENTRY_LEN * ARRAY_SIZE(sta->sta.txq); | ||
107 | rcu_read_unlock(); | ||
108 | |||
109 | info = vmalloc(len); | ||
110 | if (!info) | ||
111 | return -ENOMEM; | ||
112 | 83 | ||
113 | spin_lock_bh(&local->fq.lock); | 84 | spin_lock_bh(&local->fq.lock); |
114 | rcu_read_lock(); | 85 | rcu_read_lock(); |
115 | 86 | ||
116 | file->private_data = info; | 87 | len = scnprintf(buf, sizeof(buf), |
117 | info->local = local; | 88 | "access name value\n" |
118 | info->size = len; | 89 | "R fq_flows_cnt %u\n" |
119 | len = 0; | 90 | "R fq_backlog %u\n" |
120 | 91 | "R fq_overlimit %u\n" | |
121 | len += scnprintf(info->buf + len, info->size - len, | 92 | "R fq_collisions %u\n" |
122 | "* hw\n" | 93 | "RW fq_limit %u\n" |
123 | "access name value\n" | 94 | "RW fq_quantum %u\n", |
124 | "R fq_flows_cnt %u\n" | 95 | fq->flows_cnt, |
125 | "R fq_backlog %u\n" | 96 | fq->backlog, |
126 | "R fq_overlimit %u\n" | 97 | fq->overlimit, |
127 | "R fq_collisions %u\n" | 98 | fq->collisions, |
128 | "RW fq_limit %u\n" | 99 | fq->limit, |
129 | "RW fq_quantum %u\n", | 100 | fq->quantum); |
130 | fq->flows_cnt, | ||
131 | fq->backlog, | ||
132 | fq->overlimit, | ||
133 | fq->collisions, | ||
134 | fq->limit, | ||
135 | fq->quantum); | ||
136 | |||
137 | len += scnprintf(info->buf + len, | ||
138 | info->size - len, | ||
139 | "* vif\n" | ||
140 | "ifname addr ac backlog-bytes backlog-packets flows overlimit collisions tx-bytes tx-packets\n"); | ||
141 | |||
142 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
143 | txqi = to_txq_info(sdata->vif.txq); | ||
144 | len += scnprintf(info->buf + len, info->size - len, | ||
145 | "%s %pM %u %u %u %u %u %u %u %u\n", | ||
146 | sdata->name, | ||
147 | sdata->vif.addr, | ||
148 | txqi->txq.ac, | ||
149 | txqi->tin.backlog_bytes, | ||
150 | txqi->tin.backlog_packets, | ||
151 | txqi->tin.flows, | ||
152 | txqi->tin.overlimit, | ||
153 | txqi->tin.collisions, | ||
154 | txqi->tin.tx_bytes, | ||
155 | txqi->tin.tx_packets); | ||
156 | } | ||
157 | |||
158 | len += scnprintf(info->buf + len, | ||
159 | info->size - len, | ||
160 | "* sta\n" | ||
161 | "ifname addr tid ac backlog-bytes backlog-packets flows overlimit collisions tx-bytes tx-packets\n"); | ||
162 | |||
163 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
164 | sdata = sta->sdata; | ||
165 | for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { | ||
166 | txqi = to_txq_info(sta->sta.txq[i]); | ||
167 | len += scnprintf(info->buf + len, info->size - len, | ||
168 | "%s %pM %d %d %u %u %u %u %u %u %u\n", | ||
169 | sdata->name, | ||
170 | sta->sta.addr, | ||
171 | txqi->txq.tid, | ||
172 | txqi->txq.ac, | ||
173 | txqi->tin.backlog_bytes, | ||
174 | txqi->tin.backlog_packets, | ||
175 | txqi->tin.flows, | ||
176 | txqi->tin.overlimit, | ||
177 | txqi->tin.collisions, | ||
178 | txqi->tin.tx_bytes, | ||
179 | txqi->tin.tx_packets); | ||
180 | } | ||
181 | } | ||
182 | |||
183 | info->len = len; | ||
184 | 101 | ||
185 | rcu_read_unlock(); | 102 | rcu_read_unlock(); |
186 | spin_unlock_bh(&local->fq.lock); | 103 | spin_unlock_bh(&local->fq.lock); |
187 | 104 | ||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static int aqm_release(struct inode *inode, struct file *file) | ||
192 | { | ||
193 | vfree(file->private_data); | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | static ssize_t aqm_read(struct file *file, | ||
198 | char __user *user_buf, | ||
199 | size_t count, | ||
200 | loff_t *ppos) | ||
201 | { | ||
202 | struct aqm_info *info = file->private_data; | ||
203 | |||
204 | return simple_read_from_buffer(user_buf, count, ppos, | 105 | return simple_read_from_buffer(user_buf, count, ppos, |
205 | info->buf, info->len); | 106 | buf, len); |
206 | } | 107 | } |
207 | 108 | ||
208 | static ssize_t aqm_write(struct file *file, | 109 | static ssize_t aqm_write(struct file *file, |
@@ -210,8 +111,7 @@ static ssize_t aqm_write(struct file *file, | |||
210 | size_t count, | 111 | size_t count, |
211 | loff_t *ppos) | 112 | loff_t *ppos) |
212 | { | 113 | { |
213 | struct aqm_info *info = file->private_data; | 114 | struct ieee80211_local *local = file->private_data; |
214 | struct ieee80211_local *local = info->local; | ||
215 | char buf[100]; | 115 | char buf[100]; |
216 | size_t len; | 116 | size_t len; |
217 | 117 | ||
@@ -237,8 +137,7 @@ static ssize_t aqm_write(struct file *file, | |||
237 | static const struct file_operations aqm_ops = { | 137 | static const struct file_operations aqm_ops = { |
238 | .write = aqm_write, | 138 | .write = aqm_write, |
239 | .read = aqm_read, | 139 | .read = aqm_read, |
240 | .open = aqm_open, | 140 | .open = simple_open, |
241 | .release = aqm_release, | ||
242 | .llseek = default_llseek, | 141 | .llseek = default_llseek, |
243 | }; | 142 | }; |
244 | 143 | ||
@@ -302,6 +201,7 @@ static const char *hw_flag_names[] = { | |||
302 | FLAG(USES_RSS), | 201 | FLAG(USES_RSS), |
303 | FLAG(TX_AMSDU), | 202 | FLAG(TX_AMSDU), |
304 | FLAG(TX_FRAG_LIST), | 203 | FLAG(TX_FRAG_LIST), |
204 | FLAG(REPORTS_LOW_ACK), | ||
305 | #undef FLAG | 205 | #undef FLAG |
306 | }; | 206 | }; |
307 | 207 | ||
@@ -428,7 +328,9 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
428 | DEBUGFS_ADD(hwflags); | 328 | DEBUGFS_ADD(hwflags); |
429 | DEBUGFS_ADD(user_power); | 329 | DEBUGFS_ADD(user_power); |
430 | DEBUGFS_ADD(power); | 330 | DEBUGFS_ADD(power); |
431 | DEBUGFS_ADD_MODE(aqm, 0600); | 331 | |
332 | if (local->ops->wake_tx_queue) | ||
333 | DEBUGFS_ADD_MODE(aqm, 0600); | ||
432 | 334 | ||
433 | statsd = debugfs_create_dir("statistics", phyd); | 335 | statsd = debugfs_create_dir("statistics", phyd); |
434 | 336 | ||
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index a5ba739cd2a7..5d35c0f37bb7 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -30,7 +30,7 @@ static ssize_t ieee80211_if_read( | |||
30 | size_t count, loff_t *ppos, | 30 | size_t count, loff_t *ppos, |
31 | ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int)) | 31 | ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int)) |
32 | { | 32 | { |
33 | char buf[70]; | 33 | char buf[200]; |
34 | ssize_t ret = -EINVAL; | 34 | ssize_t ret = -EINVAL; |
35 | 35 | ||
36 | read_lock(&dev_base_lock); | 36 | read_lock(&dev_base_lock); |
@@ -486,6 +486,38 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast( | |||
486 | } | 486 | } |
487 | IEEE80211_IF_FILE_R(num_buffered_multicast); | 487 | IEEE80211_IF_FILE_R(num_buffered_multicast); |
488 | 488 | ||
489 | static ssize_t ieee80211_if_fmt_aqm( | ||
490 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | ||
491 | { | ||
492 | struct ieee80211_local *local = sdata->local; | ||
493 | struct txq_info *txqi = to_txq_info(sdata->vif.txq); | ||
494 | int len; | ||
495 | |||
496 | spin_lock_bh(&local->fq.lock); | ||
497 | rcu_read_lock(); | ||
498 | |||
499 | len = scnprintf(buf, | ||
500 | buflen, | ||
501 | "ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets\n" | ||
502 | "%u %u %u %u %u %u %u %u %u %u\n", | ||
503 | txqi->txq.ac, | ||
504 | txqi->tin.backlog_bytes, | ||
505 | txqi->tin.backlog_packets, | ||
506 | txqi->tin.flows, | ||
507 | txqi->cstats.drop_count, | ||
508 | txqi->cstats.ecn_mark, | ||
509 | txqi->tin.overlimit, | ||
510 | txqi->tin.collisions, | ||
511 | txqi->tin.tx_bytes, | ||
512 | txqi->tin.tx_packets); | ||
513 | |||
514 | rcu_read_unlock(); | ||
515 | spin_unlock_bh(&local->fq.lock); | ||
516 | |||
517 | return len; | ||
518 | } | ||
519 | IEEE80211_IF_FILE_R(aqm); | ||
520 | |||
489 | /* IBSS attributes */ | 521 | /* IBSS attributes */ |
490 | static ssize_t ieee80211_if_fmt_tsf( | 522 | static ssize_t ieee80211_if_fmt_tsf( |
491 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | 523 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) |
@@ -618,6 +650,9 @@ static void add_common_files(struct ieee80211_sub_if_data *sdata) | |||
618 | DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_2ghz); | 650 | DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_2ghz); |
619 | DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz); | 651 | DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz); |
620 | DEBUGFS_ADD(hw_queues); | 652 | DEBUGFS_ADD(hw_queues); |
653 | |||
654 | if (sdata->local->ops->wake_tx_queue) | ||
655 | DEBUGFS_ADD(aqm); | ||
621 | } | 656 | } |
622 | 657 | ||
623 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) | 658 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index fd334133ff45..a2fcdb47a0e6 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -133,6 +133,55 @@ static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf, | |||
133 | } | 133 | } |
134 | STA_OPS(last_seq_ctrl); | 134 | STA_OPS(last_seq_ctrl); |
135 | 135 | ||
136 | #define AQM_TXQ_ENTRY_LEN 130 | ||
137 | |||
138 | static ssize_t sta_aqm_read(struct file *file, char __user *userbuf, | ||
139 | size_t count, loff_t *ppos) | ||
140 | { | ||
141 | struct sta_info *sta = file->private_data; | ||
142 | struct ieee80211_local *local = sta->local; | ||
143 | size_t bufsz = AQM_TXQ_ENTRY_LEN*(IEEE80211_NUM_TIDS+1); | ||
144 | char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf; | ||
145 | struct txq_info *txqi; | ||
146 | ssize_t rv; | ||
147 | int i; | ||
148 | |||
149 | if (!buf) | ||
150 | return -ENOMEM; | ||
151 | |||
152 | spin_lock_bh(&local->fq.lock); | ||
153 | rcu_read_lock(); | ||
154 | |||
155 | p += scnprintf(p, | ||
156 | bufsz+buf-p, | ||
157 | "tid ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets\n"); | ||
158 | |||
159 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { | ||
160 | txqi = to_txq_info(sta->sta.txq[i]); | ||
161 | p += scnprintf(p, bufsz+buf-p, | ||
162 | "%d %d %u %u %u %u %u %u %u %u %u\n", | ||
163 | txqi->txq.tid, | ||
164 | txqi->txq.ac, | ||
165 | txqi->tin.backlog_bytes, | ||
166 | txqi->tin.backlog_packets, | ||
167 | txqi->tin.flows, | ||
168 | txqi->cstats.drop_count, | ||
169 | txqi->cstats.ecn_mark, | ||
170 | txqi->tin.overlimit, | ||
171 | txqi->tin.collisions, | ||
172 | txqi->tin.tx_bytes, | ||
173 | txqi->tin.tx_packets); | ||
174 | } | ||
175 | |||
176 | rcu_read_unlock(); | ||
177 | spin_unlock_bh(&local->fq.lock); | ||
178 | |||
179 | rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); | ||
180 | kfree(buf); | ||
181 | return rv; | ||
182 | } | ||
183 | STA_OPS(aqm); | ||
184 | |||
136 | static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, | 185 | static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, |
137 | size_t count, loff_t *ppos) | 186 | size_t count, loff_t *ppos) |
138 | { | 187 | { |
@@ -478,6 +527,9 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) | |||
478 | DEBUGFS_ADD_COUNTER(rx_fragments, rx_stats.fragments); | 527 | DEBUGFS_ADD_COUNTER(rx_fragments, rx_stats.fragments); |
479 | DEBUGFS_ADD_COUNTER(tx_filtered, status_stats.filtered); | 528 | DEBUGFS_ADD_COUNTER(tx_filtered, status_stats.filtered); |
480 | 529 | ||
530 | if (local->ops->wake_tx_queue) | ||
531 | DEBUGFS_ADD(aqm); | ||
532 | |||
481 | if (sizeof(sta->driver_buffered_tids) == sizeof(u32)) | 533 | if (sizeof(sta->driver_buffered_tids) == sizeof(u32)) |
482 | debugfs_create_x32("driver_buffered_tids", 0400, | 534 | debugfs_create_x32("driver_buffered_tids", 0400, |
483 | sta->debugfs_dir, | 535 | sta->debugfs_dir, |
@@ -492,10 +544,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) | |||
492 | 544 | ||
493 | void ieee80211_sta_debugfs_remove(struct sta_info *sta) | 545 | void ieee80211_sta_debugfs_remove(struct sta_info *sta) |
494 | { | 546 | { |
495 | struct ieee80211_local *local = sta->local; | ||
496 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
497 | |||
498 | drv_sta_remove_debugfs(local, sdata, &sta->sta, sta->debugfs_dir); | ||
499 | debugfs_remove_recursive(sta->debugfs_dir); | 547 | debugfs_remove_recursive(sta->debugfs_dir); |
500 | sta->debugfs_dir = NULL; | 548 | sta->debugfs_dir = NULL; |
501 | } | 549 | } |
diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c index c258f1041d33..c701b6438bd9 100644 --- a/net/mac80211/driver-ops.c +++ b/net/mac80211/driver-ops.c | |||
@@ -62,7 +62,7 @@ int drv_add_interface(struct ieee80211_local *local, | |||
62 | if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 62 | if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
63 | (sdata->vif.type == NL80211_IFTYPE_MONITOR && | 63 | (sdata->vif.type == NL80211_IFTYPE_MONITOR && |
64 | !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) && | 64 | !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) && |
65 | !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)))) | 65 | !(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE)))) |
66 | return -EINVAL; | 66 | return -EINVAL; |
67 | 67 | ||
68 | trace_drv_add_interface(local, sdata); | 68 | trace_drv_add_interface(local, sdata); |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 42a41ae405ba..fe35a1c0dc86 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -162,7 +162,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, | |||
162 | return; | 162 | return; |
163 | 163 | ||
164 | if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || | 164 | if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || |
165 | sdata->vif.type == NL80211_IFTYPE_MONITOR)) | 165 | (sdata->vif.type == NL80211_IFTYPE_MONITOR && |
166 | !sdata->vif.mu_mimo_owner))) | ||
166 | return; | 167 | return; |
167 | 168 | ||
168 | if (!check_sdata_in_driver(sdata)) | 169 | if (!check_sdata_in_driver(sdata)) |
@@ -498,21 +499,6 @@ static inline void drv_sta_add_debugfs(struct ieee80211_local *local, | |||
498 | local->ops->sta_add_debugfs(&local->hw, &sdata->vif, | 499 | local->ops->sta_add_debugfs(&local->hw, &sdata->vif, |
499 | sta, dir); | 500 | sta, dir); |
500 | } | 501 | } |
501 | |||
502 | static inline void drv_sta_remove_debugfs(struct ieee80211_local *local, | ||
503 | struct ieee80211_sub_if_data *sdata, | ||
504 | struct ieee80211_sta *sta, | ||
505 | struct dentry *dir) | ||
506 | { | ||
507 | might_sleep(); | ||
508 | |||
509 | sdata = get_bss_sdata(sdata); | ||
510 | check_sdata_in_driver(sdata); | ||
511 | |||
512 | if (local->ops->sta_remove_debugfs) | ||
513 | local->ops->sta_remove_debugfs(&local->hw, &sdata->vif, | ||
514 | sta, dir); | ||
515 | } | ||
516 | #endif | 502 | #endif |
517 | 503 | ||
518 | static inline void drv_sta_pre_rcu_remove(struct ieee80211_local *local, | 504 | static inline void drv_sta_pre_rcu_remove(struct ieee80211_local *local, |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f56d342c31b8..c71c73594790 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -3,7 +3,7 @@ | |||
3 | * Copyright 2005, Devicescape Software, Inc. | 3 | * Copyright 2005, Devicescape Software, Inc. |
4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
5 | * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net> | 5 | * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net> |
6 | * Copyright 2013-2014 Intel Mobile Communications GmbH | 6 | * Copyright 2013-2015 Intel Mobile Communications GmbH |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
@@ -818,12 +818,18 @@ struct txq_info { | |||
818 | struct fq_tin tin; | 818 | struct fq_tin tin; |
819 | struct fq_flow def_flow; | 819 | struct fq_flow def_flow; |
820 | struct codel_vars def_cvars; | 820 | struct codel_vars def_cvars; |
821 | struct codel_stats cstats; | ||
821 | unsigned long flags; | 822 | unsigned long flags; |
822 | 823 | ||
823 | /* keep last! */ | 824 | /* keep last! */ |
824 | struct ieee80211_txq txq; | 825 | struct ieee80211_txq txq; |
825 | }; | 826 | }; |
826 | 827 | ||
828 | struct ieee80211_if_mntr { | ||
829 | u32 flags; | ||
830 | u8 mu_follow_addr[ETH_ALEN] __aligned(2); | ||
831 | }; | ||
832 | |||
827 | struct ieee80211_sub_if_data { | 833 | struct ieee80211_sub_if_data { |
828 | struct list_head list; | 834 | struct list_head list; |
829 | 835 | ||
@@ -922,7 +928,7 @@ struct ieee80211_sub_if_data { | |||
922 | struct ieee80211_if_ibss ibss; | 928 | struct ieee80211_if_ibss ibss; |
923 | struct ieee80211_if_mesh mesh; | 929 | struct ieee80211_if_mesh mesh; |
924 | struct ieee80211_if_ocb ocb; | 930 | struct ieee80211_if_ocb ocb; |
925 | u32 mntr_flags; | 931 | struct ieee80211_if_mntr mntr; |
926 | } u; | 932 | } u; |
927 | 933 | ||
928 | #ifdef CONFIG_MAC80211_DEBUGFS | 934 | #ifdef CONFIG_MAC80211_DEBUGFS |
@@ -1112,7 +1118,6 @@ struct ieee80211_local { | |||
1112 | struct fq fq; | 1118 | struct fq fq; |
1113 | struct codel_vars *cvars; | 1119 | struct codel_vars *cvars; |
1114 | struct codel_params cparams; | 1120 | struct codel_params cparams; |
1115 | struct codel_stats cstats; | ||
1116 | 1121 | ||
1117 | const struct ieee80211_ops *ops; | 1122 | const struct ieee80211_ops *ops; |
1118 | 1123 | ||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b123a9e325b3..b0abddc714ef 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -43,6 +43,8 @@ | |||
43 | * by either the RTNL, the iflist_mtx or RCU. | 43 | * by either the RTNL, the iflist_mtx or RCU. |
44 | */ | 44 | */ |
45 | 45 | ||
46 | static void ieee80211_iface_work(struct work_struct *work); | ||
47 | |||
46 | bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) | 48 | bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) |
47 | { | 49 | { |
48 | struct ieee80211_chanctx_conf *chanctx_conf; | 50 | struct ieee80211_chanctx_conf *chanctx_conf; |
@@ -188,7 +190,7 @@ static int ieee80211_verify_mac(struct ieee80211_sub_if_data *sdata, u8 *addr, | |||
188 | continue; | 190 | continue; |
189 | 191 | ||
190 | if (iter->vif.type == NL80211_IFTYPE_MONITOR && | 192 | if (iter->vif.type == NL80211_IFTYPE_MONITOR && |
191 | !(iter->u.mntr_flags & MONITOR_FLAG_ACTIVE)) | 193 | !(iter->u.mntr.flags & MONITOR_FLAG_ACTIVE)) |
192 | continue; | 194 | continue; |
193 | 195 | ||
194 | m = iter->vif.addr; | 196 | m = iter->vif.addr; |
@@ -217,7 +219,7 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr) | |||
217 | return -EBUSY; | 219 | return -EBUSY; |
218 | 220 | ||
219 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR && | 221 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR && |
220 | !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) | 222 | !(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE)) |
221 | check_dup = false; | 223 | check_dup = false; |
222 | 224 | ||
223 | ret = ieee80211_verify_mac(sdata, sa->sa_data, check_dup); | 225 | ret = ieee80211_verify_mac(sdata, sa->sa_data, check_dup); |
@@ -357,7 +359,7 @@ void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | |||
357 | const int offset) | 359 | const int offset) |
358 | { | 360 | { |
359 | struct ieee80211_local *local = sdata->local; | 361 | struct ieee80211_local *local = sdata->local; |
360 | u32 flags = sdata->u.mntr_flags; | 362 | u32 flags = sdata->u.mntr.flags; |
361 | 363 | ||
362 | #define ADJUST(_f, _s) do { \ | 364 | #define ADJUST(_f, _s) do { \ |
363 | if (flags & MONITOR_FLAG_##_f) \ | 365 | if (flags & MONITOR_FLAG_##_f) \ |
@@ -448,6 +450,9 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | |||
448 | return ret; | 450 | return ret; |
449 | } | 451 | } |
450 | 452 | ||
453 | skb_queue_head_init(&sdata->skb_queue); | ||
454 | INIT_WORK(&sdata->work, ieee80211_iface_work); | ||
455 | |||
451 | return 0; | 456 | return 0; |
452 | } | 457 | } |
453 | 458 | ||
@@ -589,12 +594,12 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
589 | } | 594 | } |
590 | break; | 595 | break; |
591 | case NL80211_IFTYPE_MONITOR: | 596 | case NL80211_IFTYPE_MONITOR: |
592 | if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) { | 597 | if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) { |
593 | local->cooked_mntrs++; | 598 | local->cooked_mntrs++; |
594 | break; | 599 | break; |
595 | } | 600 | } |
596 | 601 | ||
597 | if (sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE) { | 602 | if (sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) { |
598 | res = drv_add_interface(local, sdata); | 603 | res = drv_add_interface(local, sdata); |
599 | if (res) | 604 | if (res) |
600 | goto err_stop; | 605 | goto err_stop; |
@@ -926,7 +931,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
926 | /* no need to tell driver */ | 931 | /* no need to tell driver */ |
927 | break; | 932 | break; |
928 | case NL80211_IFTYPE_MONITOR: | 933 | case NL80211_IFTYPE_MONITOR: |
929 | if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) { | 934 | if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) { |
930 | local->cooked_mntrs--; | 935 | local->cooked_mntrs--; |
931 | break; | 936 | break; |
932 | } | 937 | } |
@@ -1012,7 +1017,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
1012 | ieee80211_recalc_idle(local); | 1017 | ieee80211_recalc_idle(local); |
1013 | mutex_unlock(&local->mtx); | 1018 | mutex_unlock(&local->mtx); |
1014 | 1019 | ||
1015 | if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) | 1020 | if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE)) |
1016 | break; | 1021 | break; |
1017 | 1022 | ||
1018 | /* fall through */ | 1023 | /* fall through */ |
@@ -1444,7 +1449,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
1444 | case NL80211_IFTYPE_MONITOR: | 1449 | case NL80211_IFTYPE_MONITOR: |
1445 | sdata->dev->type = ARPHRD_IEEE80211_RADIOTAP; | 1450 | sdata->dev->type = ARPHRD_IEEE80211_RADIOTAP; |
1446 | sdata->dev->netdev_ops = &ieee80211_monitorif_ops; | 1451 | sdata->dev->netdev_ops = &ieee80211_monitorif_ops; |
1447 | sdata->u.mntr_flags = MONITOR_FLAG_CONTROL | | 1452 | sdata->u.mntr.flags = MONITOR_FLAG_CONTROL | |
1448 | MONITOR_FLAG_OTHER_BSS; | 1453 | MONITOR_FLAG_OTHER_BSS; |
1449 | break; | 1454 | break; |
1450 | case NL80211_IFTYPE_WDS: | 1455 | case NL80211_IFTYPE_WDS: |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d00ea9b13f49..ac053a9df36d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -660,6 +660,9 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, | |||
660 | 660 | ||
661 | ieee80211_roc_setup(local); | 661 | ieee80211_roc_setup(local); |
662 | 662 | ||
663 | local->hw.radiotap_timestamp.units_pos = -1; | ||
664 | local->hw.radiotap_timestamp.accuracy = -1; | ||
665 | |||
663 | return &local->hw; | 666 | return &local->hw; |
664 | err_free: | 667 | err_free: |
665 | wiphy_free(wiphy); | 668 | wiphy_free(wiphy); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 8d426f637f58..7486f2dab4ba 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1672,11 +1672,15 @@ __ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) | |||
1672 | non_acm_ac++) | 1672 | non_acm_ac++) |
1673 | if (!(sdata->wmm_acm & BIT(7 - 2 * non_acm_ac))) | 1673 | if (!(sdata->wmm_acm & BIT(7 - 2 * non_acm_ac))) |
1674 | break; | 1674 | break; |
1675 | /* The loop will result in using BK even if it requires | 1675 | /* Usually the loop will result in using BK even if it |
1676 | * admission control, such configuration makes no sense | 1676 | * requires admission control, but such a configuration |
1677 | * and we have to transmit somehow - the AC selection | 1677 | * makes no sense and we have to transmit somehow - the |
1678 | * does the same thing. | 1678 | * AC selection does the same thing. |
1679 | * If we started out trying to downgrade from BK, then | ||
1680 | * the extra condition here might be needed. | ||
1679 | */ | 1681 | */ |
1682 | if (non_acm_ac >= IEEE80211_NUM_ACS) | ||
1683 | non_acm_ac = IEEE80211_AC_BK; | ||
1680 | if (drv_conf_tx(local, sdata, ac, | 1684 | if (drv_conf_tx(local, sdata, ac, |
1681 | &sdata->tx_conf[non_acm_ac])) | 1685 | &sdata->tx_conf[non_acm_ac])) |
1682 | sdata_err(sdata, | 1686 | sdata_err(sdata, |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 00a43a70e1fc..28a3a0957c9e 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -178,8 +178,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
178 | WARN_ON(!list_empty(&local->chanctx_list)); | 178 | WARN_ON(!list_empty(&local->chanctx_list)); |
179 | 179 | ||
180 | /* stop hardware - this must stop RX */ | 180 | /* stop hardware - this must stop RX */ |
181 | if (local->open_count) | 181 | ieee80211_stop_device(local); |
182 | ieee80211_stop_device(local); | ||
183 | 182 | ||
184 | suspend: | 183 | suspend: |
185 | local->suspended = true; | 184 | local->suspended = true; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9dce3b157908..e796060b7c5e 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -180,6 +180,11 @@ ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local, | |||
180 | len += 12; | 180 | len += 12; |
181 | } | 181 | } |
182 | 182 | ||
183 | if (local->hw.radiotap_timestamp.units_pos >= 0) { | ||
184 | len = ALIGN(len, 8); | ||
185 | len += 12; | ||
186 | } | ||
187 | |||
183 | if (status->chains) { | 188 | if (status->chains) { |
184 | /* antenna and antenna signal fields */ | 189 | /* antenna and antenna signal fields */ |
185 | len += 2 * hweight8(status->chains); | 190 | len += 2 * hweight8(status->chains); |
@@ -447,6 +452,31 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
447 | pos += 2; | 452 | pos += 2; |
448 | } | 453 | } |
449 | 454 | ||
455 | if (local->hw.radiotap_timestamp.units_pos >= 0) { | ||
456 | u16 accuracy = 0; | ||
457 | u8 flags = IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT; | ||
458 | |||
459 | rthdr->it_present |= | ||
460 | cpu_to_le32(1 << IEEE80211_RADIOTAP_TIMESTAMP); | ||
461 | |||
462 | /* ensure 8 byte alignment */ | ||
463 | while ((pos - (u8 *)rthdr) & 7) | ||
464 | pos++; | ||
465 | |||
466 | put_unaligned_le64(status->device_timestamp, pos); | ||
467 | pos += sizeof(u64); | ||
468 | |||
469 | if (local->hw.radiotap_timestamp.accuracy >= 0) { | ||
470 | accuracy = local->hw.radiotap_timestamp.accuracy; | ||
471 | flags |= IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY; | ||
472 | } | ||
473 | put_unaligned_le16(accuracy, pos); | ||
474 | pos += sizeof(u16); | ||
475 | |||
476 | *pos++ = local->hw.radiotap_timestamp.units_pos; | ||
477 | *pos++ = flags; | ||
478 | } | ||
479 | |||
450 | for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) { | 480 | for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) { |
451 | *pos++ = status->chain_signal[chain]; | 481 | *pos++ = status->chain_signal[chain]; |
452 | *pos++ = chain; | 482 | *pos++ = chain; |
@@ -485,6 +515,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
485 | struct net_device *prev_dev = NULL; | 515 | struct net_device *prev_dev = NULL; |
486 | int present_fcs_len = 0; | 516 | int present_fcs_len = 0; |
487 | unsigned int rtap_vendor_space = 0; | 517 | unsigned int rtap_vendor_space = 0; |
518 | struct ieee80211_mgmt *mgmt; | ||
519 | struct ieee80211_sub_if_data *monitor_sdata = | ||
520 | rcu_dereference(local->monitor_sdata); | ||
488 | 521 | ||
489 | if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) { | 522 | if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) { |
490 | struct ieee80211_vendor_radiotap *rtap = (void *)origskb->data; | 523 | struct ieee80211_vendor_radiotap *rtap = (void *)origskb->data; |
@@ -567,7 +600,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
567 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | 600 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) |
568 | continue; | 601 | continue; |
569 | 602 | ||
570 | if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) | 603 | if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) |
571 | continue; | 604 | continue; |
572 | 605 | ||
573 | if (!ieee80211_sdata_running(sdata)) | 606 | if (!ieee80211_sdata_running(sdata)) |
@@ -585,6 +618,23 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
585 | ieee80211_rx_stats(sdata->dev, skb->len); | 618 | ieee80211_rx_stats(sdata->dev, skb->len); |
586 | } | 619 | } |
587 | 620 | ||
621 | mgmt = (void *)skb->data; | ||
622 | if (monitor_sdata && | ||
623 | skb->len >= IEEE80211_MIN_ACTION_SIZE + 1 + VHT_MUMIMO_GROUPS_DATA_LEN && | ||
624 | ieee80211_is_action(mgmt->frame_control) && | ||
625 | mgmt->u.action.category == WLAN_CATEGORY_VHT && | ||
626 | mgmt->u.action.u.vht_group_notif.action_code == WLAN_VHT_ACTION_GROUPID_MGMT && | ||
627 | is_valid_ether_addr(monitor_sdata->u.mntr.mu_follow_addr) && | ||
628 | ether_addr_equal(mgmt->da, monitor_sdata->u.mntr.mu_follow_addr)) { | ||
629 | struct sk_buff *mu_skb = skb_copy(skb, GFP_ATOMIC); | ||
630 | |||
631 | if (mu_skb) { | ||
632 | mu_skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME; | ||
633 | skb_queue_tail(&monitor_sdata->skb_queue, mu_skb); | ||
634 | ieee80211_queue_work(&local->hw, &monitor_sdata->work); | ||
635 | } | ||
636 | } | ||
637 | |||
588 | if (prev_dev) { | 638 | if (prev_dev) { |
589 | skb->dev = prev_dev; | 639 | skb->dev = prev_dev; |
590 | netif_receive_skb(skb); | 640 | netif_receive_skb(skb); |
@@ -1072,8 +1122,15 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, | |||
1072 | tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; | 1122 | tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; |
1073 | 1123 | ||
1074 | tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); | 1124 | tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); |
1075 | if (!tid_agg_rx) | 1125 | if (!tid_agg_rx) { |
1126 | if (ack_policy == IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK && | ||
1127 | !test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) && | ||
1128 | !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg)) | ||
1129 | ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid, | ||
1130 | WLAN_BACK_RECIPIENT, | ||
1131 | WLAN_REASON_QSTA_REQUIRE_SETUP); | ||
1076 | goto dont_reorder; | 1132 | goto dont_reorder; |
1133 | } | ||
1077 | 1134 | ||
1078 | /* qos null data frames are excluded */ | 1135 | /* qos null data frames are excluded */ |
1079 | if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) | 1136 | if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) |
@@ -2535,6 +2592,12 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) | |||
2535 | 2592 | ||
2536 | tid = le16_to_cpu(bar_data.control) >> 12; | 2593 | tid = le16_to_cpu(bar_data.control) >> 12; |
2537 | 2594 | ||
2595 | if (!test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) && | ||
2596 | !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg)) | ||
2597 | ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid, | ||
2598 | WLAN_BACK_RECIPIENT, | ||
2599 | WLAN_REASON_QSTA_REQUIRE_SETUP); | ||
2600 | |||
2538 | tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]); | 2601 | tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]); |
2539 | if (!tid_agg_rx) | 2602 | if (!tid_agg_rx) |
2540 | return RX_DROP_MONITOR; | 2603 | return RX_DROP_MONITOR; |
@@ -3147,7 +3210,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, | |||
3147 | continue; | 3210 | continue; |
3148 | 3211 | ||
3149 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR || | 3212 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR || |
3150 | !(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)) | 3213 | !(sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)) |
3151 | continue; | 3214 | continue; |
3152 | 3215 | ||
3153 | if (prev_dev) { | 3216 | if (prev_dev) { |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 070b40f15850..23d8ac829279 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -420,7 +420,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, | |||
420 | { | 420 | { |
421 | struct ieee80211_local *local = hw_to_local(hw); | 421 | struct ieee80211_local *local = hw_to_local(hw); |
422 | 422 | ||
423 | trace_api_scan_completed(local, info); | 423 | trace_api_scan_completed(local, info->aborted); |
424 | 424 | ||
425 | set_bit(SCAN_COMPLETED, &local->scanning); | 425 | set_bit(SCAN_COMPLETED, &local->scanning); |
426 | if (info->aborted) | 426 | if (info->aborted) |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 19f14c907d74..1b1b28ff4fdb 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -340,6 +340,9 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
340 | 340 | ||
341 | memcpy(sta->addr, addr, ETH_ALEN); | 341 | memcpy(sta->addr, addr, ETH_ALEN); |
342 | memcpy(sta->sta.addr, addr, ETH_ALEN); | 342 | memcpy(sta->sta.addr, addr, ETH_ALEN); |
343 | sta->sta.max_rx_aggregation_subframes = | ||
344 | local->hw.max_rx_aggregation_subframes; | ||
345 | |||
343 | sta->local = local; | 346 | sta->local = local; |
344 | sta->sdata = sdata; | 347 | sta->sdata = sdata; |
345 | sta->rx_stats.last_rx = jiffies; | 348 | sta->rx_stats.last_rx = jiffies; |
@@ -687,7 +690,7 @@ static void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending) | |||
687 | } | 690 | } |
688 | 691 | ||
689 | /* No need to do anything if the driver does all */ | 692 | /* No need to do anything if the driver does all */ |
690 | if (ieee80211_hw_check(&local->hw, AP_LINK_PS)) | 693 | if (!local->ops->set_tim) |
691 | return; | 694 | return; |
692 | 695 | ||
693 | if (sta->dead) | 696 | if (sta->dead) |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 0556be3e3628..530231b73278 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -230,6 +230,8 @@ struct tid_ampdu_rx { | |||
230 | * @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the | 230 | * @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the |
231 | * driver requested to close until the work for it runs | 231 | * driver requested to close until the work for it runs |
232 | * @agg_session_valid: bitmap indicating which TID has a rx BA session open on | 232 | * @agg_session_valid: bitmap indicating which TID has a rx BA session open on |
233 | * @unexpected_agg: bitmap indicating which TID already sent a delBA due to | ||
234 | * unexpected aggregation related frames outside a session | ||
233 | * @work: work struct for starting/stopping aggregation | 235 | * @work: work struct for starting/stopping aggregation |
234 | * @tid_tx: aggregation info for Tx per TID | 236 | * @tid_tx: aggregation info for Tx per TID |
235 | * @tid_start_tx: sessions where start was requested | 237 | * @tid_start_tx: sessions where start was requested |
@@ -244,6 +246,7 @@ struct sta_ampdu_mlme { | |||
244 | unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; | 246 | unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; |
245 | unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; | 247 | unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; |
246 | unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; | 248 | unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; |
249 | unsigned long unexpected_agg[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; | ||
247 | /* tx */ | 250 | /* tx */ |
248 | struct work_struct work; | 251 | struct work_struct work; |
249 | struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS]; | 252 | struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS]; |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index a2a68269675d..ea39f8a7baf3 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -557,6 +557,12 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local, | |||
557 | static void ieee80211_lost_packet(struct sta_info *sta, | 557 | static void ieee80211_lost_packet(struct sta_info *sta, |
558 | struct ieee80211_tx_info *info) | 558 | struct ieee80211_tx_info *info) |
559 | { | 559 | { |
560 | /* If driver relies on its own algorithm for station kickout, skip | ||
561 | * mac80211 packet loss mechanism. | ||
562 | */ | ||
563 | if (ieee80211_hw_check(&sta->local->hw, REPORTS_LOW_ACK)) | ||
564 | return; | ||
565 | |||
560 | /* This packet was aggregated but doesn't carry status info */ | 566 | /* This packet was aggregated but doesn't carry status info */ |
561 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && | 567 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && |
562 | !(info->flags & IEEE80211_TX_STAT_AMPDU)) | 568 | !(info->flags & IEEE80211_TX_STAT_AMPDU)) |
@@ -709,7 +715,7 @@ void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb, | |||
709 | if (!ieee80211_sdata_running(sdata)) | 715 | if (!ieee80211_sdata_running(sdata)) |
710 | continue; | 716 | continue; |
711 | 717 | ||
712 | if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) && | 718 | if ((sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) && |
713 | !send_to_cooked) | 719 | !send_to_cooked) |
714 | continue; | 720 | continue; |
715 | 721 | ||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1d0746dfea57..61d302d97145 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1343,7 +1343,7 @@ static struct sk_buff *fq_tin_dequeue_func(struct fq *fq, | |||
1343 | local = container_of(fq, struct ieee80211_local, fq); | 1343 | local = container_of(fq, struct ieee80211_local, fq); |
1344 | txqi = container_of(tin, struct txq_info, tin); | 1344 | txqi = container_of(tin, struct txq_info, tin); |
1345 | cparams = &local->cparams; | 1345 | cparams = &local->cparams; |
1346 | cstats = &local->cstats; | 1346 | cstats = &txqi->cstats; |
1347 | 1347 | ||
1348 | if (flow == &txqi->def_flow) | 1348 | if (flow == &txqi->def_flow) |
1349 | cvars = &txqi->def_cvars; | 1349 | cvars = &txqi->def_cvars; |
@@ -1403,6 +1403,7 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata, | |||
1403 | fq_tin_init(&txqi->tin); | 1403 | fq_tin_init(&txqi->tin); |
1404 | fq_flow_init(&txqi->def_flow); | 1404 | fq_flow_init(&txqi->def_flow); |
1405 | codel_vars_init(&txqi->def_cvars); | 1405 | codel_vars_init(&txqi->def_cvars); |
1406 | codel_stats_init(&txqi->cstats); | ||
1406 | 1407 | ||
1407 | txqi->txq.vif = &sdata->vif; | 1408 | txqi->txq.vif = &sdata->vif; |
1408 | 1409 | ||
@@ -1441,7 +1442,6 @@ int ieee80211_txq_setup_flows(struct ieee80211_local *local) | |||
1441 | return ret; | 1442 | return ret; |
1442 | 1443 | ||
1443 | codel_params_init(&local->cparams); | 1444 | codel_params_init(&local->cparams); |
1444 | codel_stats_init(&local->cstats); | ||
1445 | local->cparams.interval = MS2TIME(100); | 1445 | local->cparams.interval = MS2TIME(100); |
1446 | local->cparams.target = MS2TIME(20); | 1446 | local->cparams.target = MS2TIME(20); |
1447 | local->cparams.ecn = true; | 1447 | local->cparams.ecn = true; |
@@ -1643,7 +1643,7 @@ static bool __ieee80211_tx(struct ieee80211_local *local, | |||
1643 | 1643 | ||
1644 | switch (sdata->vif.type) { | 1644 | switch (sdata->vif.type) { |
1645 | case NL80211_IFTYPE_MONITOR: | 1645 | case NL80211_IFTYPE_MONITOR: |
1646 | if (sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE) { | 1646 | if (sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) { |
1647 | vif = &sdata->vif; | 1647 | vif = &sdata->vif; |
1648 | break; | 1648 | break; |
1649 | } | 1649 | } |
@@ -2263,15 +2263,9 @@ static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata, | |||
2263 | case NL80211_IFTYPE_STATION: | 2263 | case NL80211_IFTYPE_STATION: |
2264 | if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { | 2264 | if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { |
2265 | sta = sta_info_get(sdata, skb->data); | 2265 | sta = sta_info_get(sdata, skb->data); |
2266 | if (sta) { | 2266 | if (sta && test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { |
2267 | bool tdls_peer, tdls_auth; | 2267 | if (test_sta_flag(sta, |
2268 | 2268 | WLAN_STA_TDLS_PEER_AUTH)) { | |
2269 | tdls_peer = test_sta_flag(sta, | ||
2270 | WLAN_STA_TDLS_PEER); | ||
2271 | tdls_auth = test_sta_flag(sta, | ||
2272 | WLAN_STA_TDLS_PEER_AUTH); | ||
2273 | |||
2274 | if (tdls_peer && tdls_auth) { | ||
2275 | *sta_out = sta; | 2269 | *sta_out = sta; |
2276 | return 0; | 2270 | return 0; |
2277 | } | 2271 | } |
@@ -2283,8 +2277,7 @@ static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata, | |||
2283 | * after a TDLS sta is removed due to being | 2277 | * after a TDLS sta is removed due to being |
2284 | * unreachable. | 2278 | * unreachable. |
2285 | */ | 2279 | */ |
2286 | if (tdls_peer && !tdls_auth && | 2280 | if (!ieee80211_is_tdls_setup(skb)) |
2287 | !ieee80211_is_tdls_setup(skb)) | ||
2288 | return -EINVAL; | 2281 | return -EINVAL; |
2289 | } | 2282 | } |
2290 | 2283 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 42bf0b6685e8..b6865d884487 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -598,7 +598,7 @@ static void __iterate_interfaces(struct ieee80211_local *local, | |||
598 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 598 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
599 | switch (sdata->vif.type) { | 599 | switch (sdata->vif.type) { |
600 | case NL80211_IFTYPE_MONITOR: | 600 | case NL80211_IFTYPE_MONITOR: |
601 | if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) | 601 | if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE)) |
602 | continue; | 602 | continue; |
603 | break; | 603 | break; |
604 | case NL80211_IFTYPE_AP_VLAN: | 604 | case NL80211_IFTYPE_AP_VLAN: |
@@ -2555,7 +2555,6 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | |||
2555 | 2555 | ||
2556 | if (need_basic && basic_rates & BIT(i)) | 2556 | if (need_basic && basic_rates & BIT(i)) |
2557 | basic = 0x80; | 2557 | basic = 0x80; |
2558 | rate = sband->bitrates[i].bitrate; | ||
2559 | rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, | 2558 | rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, |
2560 | 5 * (1 << shift)); | 2559 | 5 * (1 << shift)); |
2561 | *pos++ = basic | (u8) rate; | 2560 | *pos++ = basic | (u8) rate; |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 2029b49a1df3..4911cd997b9a 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -1252,7 +1252,7 @@ static int __init cfg80211_init(void) | |||
1252 | if (err) | 1252 | if (err) |
1253 | goto out_fail_reg; | 1253 | goto out_fail_reg; |
1254 | 1254 | ||
1255 | cfg80211_wq = create_singlethread_workqueue("cfg80211"); | 1255 | cfg80211_wq = alloc_ordered_workqueue("cfg80211", WQ_MEM_RECLAIM); |
1256 | if (!cfg80211_wq) { | 1256 | if (!cfg80211_wq) { |
1257 | err = -ENOMEM; | 1257 | err = -ENOMEM; |
1258 | goto out_fail_wq; | 1258 | goto out_fail_wq; |
diff --git a/net/wireless/core.h b/net/wireless/core.h index eee91443924d..5555e3c13ae9 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -249,9 +249,9 @@ struct cfg80211_event { | |||
249 | }; | 249 | }; |
250 | 250 | ||
251 | struct cfg80211_cached_keys { | 251 | struct cfg80211_cached_keys { |
252 | struct key_params params[6]; | 252 | struct key_params params[4]; |
253 | u8 data[6][WLAN_MAX_KEY_LEN]; | 253 | u8 data[4][WLAN_KEY_LEN_WEP104]; |
254 | int def, defmgmt; | 254 | int def; |
255 | }; | 255 | }; |
256 | 256 | ||
257 | enum cfg80211_chan_mode { | 257 | enum cfg80211_chan_mode { |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 4a4dda53bdf1..eafdfa5798ae 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -114,6 +114,9 @@ static int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
114 | } | 114 | } |
115 | } | 115 | } |
116 | 116 | ||
117 | if (WARN_ON(connkeys && connkeys->def < 0)) | ||
118 | return -EINVAL; | ||
119 | |||
117 | if (WARN_ON(wdev->connect_keys)) | 120 | if (WARN_ON(wdev->connect_keys)) |
118 | kzfree(wdev->connect_keys); | 121 | kzfree(wdev->connect_keys); |
119 | wdev->connect_keys = connkeys; | 122 | wdev->connect_keys = connkeys; |
@@ -284,18 +287,16 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | |||
284 | if (!netif_running(wdev->netdev)) | 287 | if (!netif_running(wdev->netdev)) |
285 | return 0; | 288 | return 0; |
286 | 289 | ||
287 | if (wdev->wext.keys) { | 290 | if (wdev->wext.keys) |
288 | wdev->wext.keys->def = wdev->wext.default_key; | 291 | wdev->wext.keys->def = wdev->wext.default_key; |
289 | wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key; | ||
290 | } | ||
291 | 292 | ||
292 | wdev->wext.ibss.privacy = wdev->wext.default_key != -1; | 293 | wdev->wext.ibss.privacy = wdev->wext.default_key != -1; |
293 | 294 | ||
294 | if (wdev->wext.keys) { | 295 | if (wdev->wext.keys && wdev->wext.keys->def != -1) { |
295 | ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL); | 296 | ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL); |
296 | if (!ck) | 297 | if (!ck) |
297 | return -ENOMEM; | 298 | return -ENOMEM; |
298 | for (i = 0; i < 6; i++) | 299 | for (i = 0; i < 4; i++) |
299 | ck->params[i].key = ck->data[i]; | 300 | ck->params[i].key = ck->data[i]; |
300 | } | 301 | } |
301 | err = __cfg80211_join_ibss(rdev, wdev->netdev, | 302 | err = __cfg80211_join_ibss(rdev, wdev->netdev, |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index c284d883c349..d6abb0704db5 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -222,7 +222,7 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
222 | ASSERT_WDEV_LOCK(wdev); | 222 | ASSERT_WDEV_LOCK(wdev); |
223 | 223 | ||
224 | if (auth_type == NL80211_AUTHTYPE_SHARED_KEY) | 224 | if (auth_type == NL80211_AUTHTYPE_SHARED_KEY) |
225 | if (!key || !key_len || key_idx < 0 || key_idx > 4) | 225 | if (!key || !key_len || key_idx < 0 || key_idx > 3) |
226 | return -EINVAL; | 226 | return -EINVAL; |
227 | 227 | ||
228 | if (wdev->current_bss && | 228 | if (wdev->current_bss && |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 499785778983..887c4c114206 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -848,13 +848,21 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, | |||
848 | struct nlattr *key; | 848 | struct nlattr *key; |
849 | struct cfg80211_cached_keys *result; | 849 | struct cfg80211_cached_keys *result; |
850 | int rem, err, def = 0; | 850 | int rem, err, def = 0; |
851 | bool have_key = false; | ||
852 | |||
853 | nla_for_each_nested(key, keys, rem) { | ||
854 | have_key = true; | ||
855 | break; | ||
856 | } | ||
857 | |||
858 | if (!have_key) | ||
859 | return NULL; | ||
851 | 860 | ||
852 | result = kzalloc(sizeof(*result), GFP_KERNEL); | 861 | result = kzalloc(sizeof(*result), GFP_KERNEL); |
853 | if (!result) | 862 | if (!result) |
854 | return ERR_PTR(-ENOMEM); | 863 | return ERR_PTR(-ENOMEM); |
855 | 864 | ||
856 | result->def = -1; | 865 | result->def = -1; |
857 | result->defmgmt = -1; | ||
858 | 866 | ||
859 | nla_for_each_nested(key, keys, rem) { | 867 | nla_for_each_nested(key, keys, rem) { |
860 | memset(&parse, 0, sizeof(parse)); | 868 | memset(&parse, 0, sizeof(parse)); |
@@ -866,7 +874,7 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, | |||
866 | err = -EINVAL; | 874 | err = -EINVAL; |
867 | if (!parse.p.key) | 875 | if (!parse.p.key) |
868 | goto error; | 876 | goto error; |
869 | if (parse.idx < 0 || parse.idx > 4) | 877 | if (parse.idx < 0 || parse.idx > 3) |
870 | goto error; | 878 | goto error; |
871 | if (parse.def) { | 879 | if (parse.def) { |
872 | if (def) | 880 | if (def) |
@@ -881,16 +889,24 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, | |||
881 | parse.idx, false, NULL); | 889 | parse.idx, false, NULL); |
882 | if (err) | 890 | if (err) |
883 | goto error; | 891 | goto error; |
892 | if (parse.p.cipher != WLAN_CIPHER_SUITE_WEP40 && | ||
893 | parse.p.cipher != WLAN_CIPHER_SUITE_WEP104) { | ||
894 | err = -EINVAL; | ||
895 | goto error; | ||
896 | } | ||
884 | result->params[parse.idx].cipher = parse.p.cipher; | 897 | result->params[parse.idx].cipher = parse.p.cipher; |
885 | result->params[parse.idx].key_len = parse.p.key_len; | 898 | result->params[parse.idx].key_len = parse.p.key_len; |
886 | result->params[parse.idx].key = result->data[parse.idx]; | 899 | result->params[parse.idx].key = result->data[parse.idx]; |
887 | memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len); | 900 | memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len); |
888 | 901 | ||
889 | if (parse.p.cipher == WLAN_CIPHER_SUITE_WEP40 || | 902 | /* must be WEP key if we got here */ |
890 | parse.p.cipher == WLAN_CIPHER_SUITE_WEP104) { | 903 | if (no_ht) |
891 | if (no_ht) | 904 | *no_ht = true; |
892 | *no_ht = true; | 905 | } |
893 | } | 906 | |
907 | if (result->def < 0) { | ||
908 | err = -EINVAL; | ||
909 | goto error; | ||
894 | } | 910 | } |
895 | 911 | ||
896 | return result; | 912 | return result; |
@@ -2525,10 +2541,35 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
2525 | int if_idx = 0; | 2541 | int if_idx = 0; |
2526 | int wp_start = cb->args[0]; | 2542 | int wp_start = cb->args[0]; |
2527 | int if_start = cb->args[1]; | 2543 | int if_start = cb->args[1]; |
2544 | int filter_wiphy = -1; | ||
2528 | struct cfg80211_registered_device *rdev; | 2545 | struct cfg80211_registered_device *rdev; |
2529 | struct wireless_dev *wdev; | 2546 | struct wireless_dev *wdev; |
2530 | 2547 | ||
2531 | rtnl_lock(); | 2548 | rtnl_lock(); |
2549 | if (!cb->args[2]) { | ||
2550 | struct nl80211_dump_wiphy_state state = { | ||
2551 | .filter_wiphy = -1, | ||
2552 | }; | ||
2553 | int ret; | ||
2554 | |||
2555 | ret = nl80211_dump_wiphy_parse(skb, cb, &state); | ||
2556 | if (ret) | ||
2557 | return ret; | ||
2558 | |||
2559 | filter_wiphy = state.filter_wiphy; | ||
2560 | |||
2561 | /* | ||
2562 | * if filtering, set cb->args[2] to +1 since 0 is the default | ||
2563 | * value needed to determine that parsing is necessary. | ||
2564 | */ | ||
2565 | if (filter_wiphy >= 0) | ||
2566 | cb->args[2] = filter_wiphy + 1; | ||
2567 | else | ||
2568 | cb->args[2] = -1; | ||
2569 | } else if (cb->args[2] > 0) { | ||
2570 | filter_wiphy = cb->args[2] - 1; | ||
2571 | } | ||
2572 | |||
2532 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 2573 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
2533 | if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) | 2574 | if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) |
2534 | continue; | 2575 | continue; |
@@ -2536,6 +2577,10 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
2536 | wp_idx++; | 2577 | wp_idx++; |
2537 | continue; | 2578 | continue; |
2538 | } | 2579 | } |
2580 | |||
2581 | if (filter_wiphy >= 0 && filter_wiphy != rdev->wiphy_idx) | ||
2582 | continue; | ||
2583 | |||
2539 | if_idx = 0; | 2584 | if_idx = 0; |
2540 | 2585 | ||
2541 | list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { | 2586 | list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { |
@@ -7359,7 +7404,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
7359 | (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 || | 7404 | (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 || |
7360 | key.p.key_len != WLAN_KEY_LEN_WEP104)) | 7405 | key.p.key_len != WLAN_KEY_LEN_WEP104)) |
7361 | return -EINVAL; | 7406 | return -EINVAL; |
7362 | if (key.idx > 4) | 7407 | if (key.idx > 3) |
7363 | return -EINVAL; | 7408 | return -EINVAL; |
7364 | } else { | 7409 | } else { |
7365 | key.p.key_len = 0; | 7410 | key.p.key_len = 0; |
@@ -7977,6 +8022,8 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev, | |||
7977 | } | 8022 | } |
7978 | 8023 | ||
7979 | data = nla_nest_start(skb, attr); | 8024 | data = nla_nest_start(skb, attr); |
8025 | if (!data) | ||
8026 | goto nla_put_failure; | ||
7980 | 8027 | ||
7981 | ((void **)skb->cb)[0] = rdev; | 8028 | ((void **)skb->cb)[0] = rdev; |
7982 | ((void **)skb->cb)[1] = hdr; | 8029 | ((void **)skb->cb)[1] = hdr; |
@@ -9406,18 +9453,27 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg, | |||
9406 | if (!freqs) | 9453 | if (!freqs) |
9407 | return -ENOBUFS; | 9454 | return -ENOBUFS; |
9408 | 9455 | ||
9409 | for (i = 0; i < req->n_channels; i++) | 9456 | for (i = 0; i < req->n_channels; i++) { |
9410 | nla_put_u32(msg, i, req->channels[i]->center_freq); | 9457 | if (nla_put_u32(msg, i, req->channels[i]->center_freq)) |
9458 | return -ENOBUFS; | ||
9459 | } | ||
9411 | 9460 | ||
9412 | nla_nest_end(msg, freqs); | 9461 | nla_nest_end(msg, freqs); |
9413 | 9462 | ||
9414 | if (req->n_match_sets) { | 9463 | if (req->n_match_sets) { |
9415 | matches = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH); | 9464 | matches = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH); |
9465 | if (!matches) | ||
9466 | return -ENOBUFS; | ||
9467 | |||
9416 | for (i = 0; i < req->n_match_sets; i++) { | 9468 | for (i = 0; i < req->n_match_sets; i++) { |
9417 | match = nla_nest_start(msg, i); | 9469 | match = nla_nest_start(msg, i); |
9418 | nla_put(msg, NL80211_SCHED_SCAN_MATCH_ATTR_SSID, | 9470 | if (!match) |
9419 | req->match_sets[i].ssid.ssid_len, | 9471 | return -ENOBUFS; |
9420 | req->match_sets[i].ssid.ssid); | 9472 | |
9473 | if (nla_put(msg, NL80211_SCHED_SCAN_MATCH_ATTR_SSID, | ||
9474 | req->match_sets[i].ssid.ssid_len, | ||
9475 | req->match_sets[i].ssid.ssid)) | ||
9476 | return -ENOBUFS; | ||
9421 | nla_nest_end(msg, match); | 9477 | nla_nest_end(msg, match); |
9422 | } | 9478 | } |
9423 | nla_nest_end(msg, matches); | 9479 | nla_nest_end(msg, matches); |
@@ -9429,6 +9485,9 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg, | |||
9429 | 9485 | ||
9430 | for (i = 0; i < req->n_scan_plans; i++) { | 9486 | for (i = 0; i < req->n_scan_plans; i++) { |
9431 | scan_plan = nla_nest_start(msg, i + 1); | 9487 | scan_plan = nla_nest_start(msg, i + 1); |
9488 | if (!scan_plan) | ||
9489 | return -ENOBUFS; | ||
9490 | |||
9432 | if (!scan_plan || | 9491 | if (!scan_plan || |
9433 | nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL, | 9492 | nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL, |
9434 | req->scan_plans[i].interval) || | 9493 | req->scan_plans[i].interval) || |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0358e12be54b..b5bd58d0f731 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -352,52 +352,48 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *rdev) | |||
352 | __cfg80211_bss_expire(rdev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE); | 352 | __cfg80211_bss_expire(rdev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE); |
353 | } | 353 | } |
354 | 354 | ||
355 | const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len) | 355 | const u8 *cfg80211_find_ie_match(u8 eid, const u8 *ies, int len, |
356 | const u8 *match, int match_len, | ||
357 | int match_offset) | ||
356 | { | 358 | { |
357 | while (len > 2 && ies[0] != eid) { | 359 | /* match_offset can't be smaller than 2, unless match_len is |
360 | * zero, in which case match_offset must be zero as well. | ||
361 | */ | ||
362 | if (WARN_ON((match_len && match_offset < 2) || | ||
363 | (!match_len && match_offset))) | ||
364 | return NULL; | ||
365 | |||
366 | while (len >= 2 && len >= ies[1] + 2) { | ||
367 | if ((ies[0] == eid) && | ||
368 | (ies[1] + 2 >= match_offset + match_len) && | ||
369 | !memcmp(ies + match_offset, match, match_len)) | ||
370 | return ies; | ||
371 | |||
358 | len -= ies[1] + 2; | 372 | len -= ies[1] + 2; |
359 | ies += ies[1] + 2; | 373 | ies += ies[1] + 2; |
360 | } | 374 | } |
361 | if (len < 2) | 375 | |
362 | return NULL; | 376 | return NULL; |
363 | if (len < 2 + ies[1]) | ||
364 | return NULL; | ||
365 | return ies; | ||
366 | } | 377 | } |
367 | EXPORT_SYMBOL(cfg80211_find_ie); | 378 | EXPORT_SYMBOL(cfg80211_find_ie_match); |
368 | 379 | ||
369 | const u8 *cfg80211_find_vendor_ie(unsigned int oui, int oui_type, | 380 | const u8 *cfg80211_find_vendor_ie(unsigned int oui, int oui_type, |
370 | const u8 *ies, int len) | 381 | const u8 *ies, int len) |
371 | { | 382 | { |
372 | struct ieee80211_vendor_ie *ie; | 383 | const u8 *ie; |
373 | const u8 *pos = ies, *end = ies + len; | 384 | u8 match[] = { oui >> 16, oui >> 8, oui, oui_type }; |
374 | int ie_oui; | 385 | int match_len = (oui_type < 0) ? 3 : sizeof(match); |
375 | 386 | ||
376 | if (WARN_ON(oui_type > 0xff)) | 387 | if (WARN_ON(oui_type > 0xff)) |
377 | return NULL; | 388 | return NULL; |
378 | 389 | ||
379 | while (pos < end) { | 390 | ie = cfg80211_find_ie_match(WLAN_EID_VENDOR_SPECIFIC, ies, len, |
380 | pos = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, pos, | 391 | match, match_len, 2); |
381 | end - pos); | ||
382 | if (!pos) | ||
383 | return NULL; | ||
384 | |||
385 | ie = (struct ieee80211_vendor_ie *)pos; | ||
386 | |||
387 | /* make sure we can access ie->len */ | ||
388 | BUILD_BUG_ON(offsetof(struct ieee80211_vendor_ie, len) != 1); | ||
389 | 392 | ||
390 | if (ie->len < sizeof(*ie)) | 393 | if (ie && (ie[1] < 4)) |
391 | goto cont; | 394 | return NULL; |
392 | 395 | ||
393 | ie_oui = ie->oui[0] << 16 | ie->oui[1] << 8 | ie->oui[2]; | 396 | return ie; |
394 | if (ie_oui == oui && | ||
395 | (oui_type < 0 || ie->oui_type == oui_type)) | ||
396 | return pos; | ||
397 | cont: | ||
398 | pos += 2 + ie->len; | ||
399 | } | ||
400 | return NULL; | ||
401 | } | 397 | } |
402 | EXPORT_SYMBOL(cfg80211_find_vendor_ie); | 398 | EXPORT_SYMBOL(cfg80211_find_vendor_ie); |
403 | 399 | ||
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index add6824c44fd..c08a3b57dca1 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -1043,6 +1043,9 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
1043 | connect->crypto.ciphers_pairwise[0] = cipher; | 1043 | connect->crypto.ciphers_pairwise[0] = cipher; |
1044 | } | 1044 | } |
1045 | } | 1045 | } |
1046 | } else { | ||
1047 | if (WARN_ON(connkeys)) | ||
1048 | return -EINVAL; | ||
1046 | } | 1049 | } |
1047 | 1050 | ||
1048 | wdev->connect_keys = connkeys; | 1051 | wdev->connect_keys = connkeys; |
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index e46469bc130f..0082f4b01795 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c | |||
@@ -57,7 +57,7 @@ static ssize_t addresses_show(struct device *dev, | |||
57 | return sprintf(buf, "%pM\n", wiphy->perm_addr); | 57 | return sprintf(buf, "%pM\n", wiphy->perm_addr); |
58 | 58 | ||
59 | for (i = 0; i < wiphy->n_addresses; i++) | 59 | for (i = 0; i < wiphy->n_addresses; i++) |
60 | buf += sprintf(buf, "%pM\n", &wiphy->addresses[i].addr); | 60 | buf += sprintf(buf, "%pM\n", wiphy->addresses[i].addr); |
61 | 61 | ||
62 | return buf - start; | 62 | return buf - start; |
63 | } | 63 | } |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 0675f513e7b9..9e6e2aaa7766 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -218,7 +218,7 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | |||
218 | struct key_params *params, int key_idx, | 218 | struct key_params *params, int key_idx, |
219 | bool pairwise, const u8 *mac_addr) | 219 | bool pairwise, const u8 *mac_addr) |
220 | { | 220 | { |
221 | if (key_idx > 5) | 221 | if (key_idx < 0 || key_idx > 5) |
222 | return -EINVAL; | 222 | return -EINVAL; |
223 | 223 | ||
224 | if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | 224 | if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) |
@@ -249,7 +249,13 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | |||
249 | /* Disallow BIP (group-only) cipher as pairwise cipher */ | 249 | /* Disallow BIP (group-only) cipher as pairwise cipher */ |
250 | if (pairwise) | 250 | if (pairwise) |
251 | return -EINVAL; | 251 | return -EINVAL; |
252 | if (key_idx < 4) | ||
253 | return -EINVAL; | ||
252 | break; | 254 | break; |
255 | case WLAN_CIPHER_SUITE_WEP40: | ||
256 | case WLAN_CIPHER_SUITE_WEP104: | ||
257 | if (key_idx > 3) | ||
258 | return -EINVAL; | ||
253 | default: | 259 | default: |
254 | break; | 260 | break; |
255 | } | 261 | } |
@@ -906,7 +912,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) | |||
906 | if (!wdev->connect_keys) | 912 | if (!wdev->connect_keys) |
907 | return; | 913 | return; |
908 | 914 | ||
909 | for (i = 0; i < 6; i++) { | 915 | for (i = 0; i < 4; i++) { |
910 | if (!wdev->connect_keys->params[i].cipher) | 916 | if (!wdev->connect_keys->params[i].cipher) |
911 | continue; | 917 | continue; |
912 | if (rdev_add_key(rdev, dev, i, false, NULL, | 918 | if (rdev_add_key(rdev, dev, i, false, NULL, |
@@ -919,9 +925,6 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) | |||
919 | netdev_err(dev, "failed to set defkey %d\n", i); | 925 | netdev_err(dev, "failed to set defkey %d\n", i); |
920 | continue; | 926 | continue; |
921 | } | 927 | } |
922 | if (wdev->connect_keys->defmgmt == i) | ||
923 | if (rdev_set_default_mgmt_key(rdev, dev, i)) | ||
924 | netdev_err(dev, "failed to set mgtdef %d\n", i); | ||
925 | } | 928 | } |
926 | 929 | ||
927 | kzfree(wdev->connect_keys); | 930 | kzfree(wdev->connect_keys); |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 9f27221c8913..7b97d43b27e1 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -408,10 +408,10 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
408 | 408 | ||
409 | if (!wdev->wext.keys) { | 409 | if (!wdev->wext.keys) { |
410 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), | 410 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), |
411 | GFP_KERNEL); | 411 | GFP_KERNEL); |
412 | if (!wdev->wext.keys) | 412 | if (!wdev->wext.keys) |
413 | return -ENOMEM; | 413 | return -ENOMEM; |
414 | for (i = 0; i < 6; i++) | 414 | for (i = 0; i < 4; i++) |
415 | wdev->wext.keys->params[i].key = | 415 | wdev->wext.keys->params[i].key = |
416 | wdev->wext.keys->data[i]; | 416 | wdev->wext.keys->data[i]; |
417 | } | 417 | } |
@@ -460,7 +460,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
460 | if (err == -ENOENT) | 460 | if (err == -ENOENT) |
461 | err = 0; | 461 | err = 0; |
462 | if (!err) { | 462 | if (!err) { |
463 | if (!addr) { | 463 | if (!addr && idx < 4) { |
464 | memset(wdev->wext.keys->data[idx], 0, | 464 | memset(wdev->wext.keys->data[idx], 0, |
465 | sizeof(wdev->wext.keys->data[idx])); | 465 | sizeof(wdev->wext.keys->data[idx])); |
466 | wdev->wext.keys->params[idx].key_len = 0; | 466 | wdev->wext.keys->params[idx].key_len = 0; |
@@ -487,6 +487,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
487 | err = 0; | 487 | err = 0; |
488 | if (wdev->current_bss) | 488 | if (wdev->current_bss) |
489 | err = rdev_add_key(rdev, dev, idx, pairwise, addr, params); | 489 | err = rdev_add_key(rdev, dev, idx, pairwise, addr, params); |
490 | else if (params->cipher != WLAN_CIPHER_SUITE_WEP40 && | ||
491 | params->cipher != WLAN_CIPHER_SUITE_WEP104) | ||
492 | return -EINVAL; | ||
490 | if (err) | 493 | if (err) |
491 | return err; | 494 | return err; |
492 | 495 | ||
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index a4e8af3321d2..88f1f6931ab8 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c | |||
@@ -35,7 +35,6 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
35 | 35 | ||
36 | if (wdev->wext.keys) { | 36 | if (wdev->wext.keys) { |
37 | wdev->wext.keys->def = wdev->wext.default_key; | 37 | wdev->wext.keys->def = wdev->wext.default_key; |
38 | wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key; | ||
39 | if (wdev->wext.default_key != -1) | 38 | if (wdev->wext.default_key != -1) |
40 | wdev->wext.connect.privacy = true; | 39 | wdev->wext.connect.privacy = true; |
41 | } | 40 | } |
@@ -43,11 +42,11 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
43 | if (!wdev->wext.connect.ssid_len) | 42 | if (!wdev->wext.connect.ssid_len) |
44 | return 0; | 43 | return 0; |
45 | 44 | ||
46 | if (wdev->wext.keys) { | 45 | if (wdev->wext.keys && wdev->wext.keys->def != -1) { |
47 | ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL); | 46 | ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL); |
48 | if (!ck) | 47 | if (!ck) |
49 | return -ENOMEM; | 48 | return -ENOMEM; |
50 | for (i = 0; i < 6; i++) | 49 | for (i = 0; i < 4; i++) |
51 | ck->params[i].key = ck->data[i]; | 50 | ck->params[i].key = ck->data[i]; |
52 | } | 51 | } |
53 | 52 | ||