diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/agg-tx.c | 42 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.c | 4 | ||||
-rw-r--r-- | net/mac80211/main.c | 6 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 21 | ||||
-rw-r--r-- | net/mac80211/rx.c | 9 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 8 | ||||
-rw-r--r-- | net/mac80211/status.c | 8 | ||||
-rw-r--r-- | net/mac80211/util.c | 5 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 13 | ||||
-rw-r--r-- | net/wireless/reg.c | 48 | ||||
-rw-r--r-- | net/wireless/scan.c | 13 |
11 files changed, 136 insertions, 41 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 2ac033989e01..331472ce038c 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -160,6 +160,12 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
160 | return -ENOENT; | 160 | return -ENOENT; |
161 | } | 161 | } |
162 | 162 | ||
163 | /* if we're already stopping ignore any new requests to stop */ | ||
164 | if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | ||
165 | spin_unlock_bh(&sta->lock); | ||
166 | return -EALREADY; | ||
167 | } | ||
168 | |||
163 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { | 169 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { |
164 | /* not even started yet! */ | 170 | /* not even started yet! */ |
165 | ieee80211_assign_tid_tx(sta, tid, NULL); | 171 | ieee80211_assign_tid_tx(sta, tid, NULL); |
@@ -168,6 +174,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
168 | return 0; | 174 | return 0; |
169 | } | 175 | } |
170 | 176 | ||
177 | set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); | ||
178 | |||
171 | spin_unlock_bh(&sta->lock); | 179 | spin_unlock_bh(&sta->lock); |
172 | 180 | ||
173 | #ifdef CONFIG_MAC80211_HT_DEBUG | 181 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -175,8 +183,6 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
175 | sta->sta.addr, tid); | 183 | sta->sta.addr, tid); |
176 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 184 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
177 | 185 | ||
178 | set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); | ||
179 | |||
180 | del_timer_sync(&tid_tx->addba_resp_timer); | 186 | del_timer_sync(&tid_tx->addba_resp_timer); |
181 | 187 | ||
182 | /* | 188 | /* |
@@ -186,6 +192,20 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
186 | */ | 192 | */ |
187 | clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); | 193 | clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); |
188 | 194 | ||
195 | /* | ||
196 | * There might be a few packets being processed right now (on | ||
197 | * another CPU) that have already gotten past the aggregation | ||
198 | * check when it was still OPERATIONAL and consequently have | ||
199 | * IEEE80211_TX_CTL_AMPDU set. In that case, this code might | ||
200 | * call into the driver at the same time or even before the | ||
201 | * TX paths calls into it, which could confuse the driver. | ||
202 | * | ||
203 | * Wait for all currently running TX paths to finish before | ||
204 | * telling the driver. New packets will not go through since | ||
205 | * the aggregation session is no longer OPERATIONAL. | ||
206 | */ | ||
207 | synchronize_net(); | ||
208 | |||
189 | tid_tx->stop_initiator = initiator; | 209 | tid_tx->stop_initiator = initiator; |
190 | tid_tx->tx_stop = tx; | 210 | tid_tx->tx_stop = tx; |
191 | 211 | ||
@@ -756,11 +776,27 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
756 | goto out; | 776 | goto out; |
757 | } | 777 | } |
758 | 778 | ||
759 | del_timer(&tid_tx->addba_resp_timer); | 779 | del_timer_sync(&tid_tx->addba_resp_timer); |
760 | 780 | ||
761 | #ifdef CONFIG_MAC80211_HT_DEBUG | 781 | #ifdef CONFIG_MAC80211_HT_DEBUG |
762 | printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); | 782 | printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); |
763 | #endif | 783 | #endif |
784 | |||
785 | /* | ||
786 | * addba_resp_timer may have fired before we got here, and | ||
787 | * caused WANT_STOP to be set. If the stop then was already | ||
788 | * processed further, STOPPING might be set. | ||
789 | */ | ||
790 | if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) || | ||
791 | test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | ||
792 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
793 | printk(KERN_DEBUG | ||
794 | "got addBA resp for tid %d but we already gave up\n", | ||
795 | tid); | ||
796 | #endif | ||
797 | goto out; | ||
798 | } | ||
799 | |||
764 | /* | 800 | /* |
765 | * IEEE 802.11-2007 7.3.1.14: | 801 | * IEEE 802.11-2007 7.3.1.14: |
766 | * In an ADDBA Response frame, when the Status Code field | 802 | * In an ADDBA Response frame, when the Status Code field |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index c5f341798c16..3110cbdc501b 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -274,9 +274,9 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, | |||
274 | 274 | ||
275 | PRINT_HT_CAP((htc->cap & BIT(10)), "HT Delayed Block Ack"); | 275 | PRINT_HT_CAP((htc->cap & BIT(10)), "HT Delayed Block Ack"); |
276 | 276 | ||
277 | PRINT_HT_CAP((htc->cap & BIT(11)), "Max AMSDU length: " | ||
278 | "3839 bytes"); | ||
279 | PRINT_HT_CAP(!(htc->cap & BIT(11)), "Max AMSDU length: " | 277 | PRINT_HT_CAP(!(htc->cap & BIT(11)), "Max AMSDU length: " |
278 | "3839 bytes"); | ||
279 | PRINT_HT_CAP((htc->cap & BIT(11)), "Max AMSDU length: " | ||
280 | "7935 bytes"); | 280 | "7935 bytes"); |
281 | 281 | ||
282 | /* | 282 | /* |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d999bf3b84e1..cae443563ec9 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -757,6 +757,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
757 | if (!local->int_scan_req) | 757 | if (!local->int_scan_req) |
758 | return -ENOMEM; | 758 | return -ENOMEM; |
759 | 759 | ||
760 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
761 | if (!local->hw.wiphy->bands[band]) | ||
762 | continue; | ||
763 | local->int_scan_req->rates[band] = (u32) -1; | ||
764 | } | ||
765 | |||
760 | /* if low-level driver supports AP, we also support VLAN */ | 766 | /* if low-level driver supports AP, we also support VLAN */ |
761 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { | 767 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { |
762 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); | 768 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 17258feaab9b..40db011da580 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1485,6 +1485,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1485 | int i, j, err; | 1485 | int i, j, err; |
1486 | bool have_higher_than_11mbit = false; | 1486 | bool have_higher_than_11mbit = false; |
1487 | u16 ap_ht_cap_flags; | 1487 | u16 ap_ht_cap_flags; |
1488 | int min_rate = INT_MAX, min_rate_index = -1; | ||
1488 | 1489 | ||
1489 | /* AssocResp and ReassocResp have identical structure */ | 1490 | /* AssocResp and ReassocResp have identical structure */ |
1490 | 1491 | ||
@@ -1551,6 +1552,10 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1551 | rates |= BIT(j); | 1552 | rates |= BIT(j); |
1552 | if (is_basic) | 1553 | if (is_basic) |
1553 | basic_rates |= BIT(j); | 1554 | basic_rates |= BIT(j); |
1555 | if (rate < min_rate) { | ||
1556 | min_rate = rate; | ||
1557 | min_rate_index = j; | ||
1558 | } | ||
1554 | break; | 1559 | break; |
1555 | } | 1560 | } |
1556 | } | 1561 | } |
@@ -1568,11 +1573,25 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1568 | rates |= BIT(j); | 1573 | rates |= BIT(j); |
1569 | if (is_basic) | 1574 | if (is_basic) |
1570 | basic_rates |= BIT(j); | 1575 | basic_rates |= BIT(j); |
1576 | if (rate < min_rate) { | ||
1577 | min_rate = rate; | ||
1578 | min_rate_index = j; | ||
1579 | } | ||
1571 | break; | 1580 | break; |
1572 | } | 1581 | } |
1573 | } | 1582 | } |
1574 | } | 1583 | } |
1575 | 1584 | ||
1585 | /* | ||
1586 | * some buggy APs don't advertise basic_rates. use the lowest | ||
1587 | * supported rate instead. | ||
1588 | */ | ||
1589 | if (unlikely(!basic_rates) && min_rate_index >= 0) { | ||
1590 | printk(KERN_DEBUG "%s: No basic rates in AssocResp. " | ||
1591 | "Using min supported rate instead.\n", sdata->name); | ||
1592 | basic_rates = BIT(min_rate_index); | ||
1593 | } | ||
1594 | |||
1576 | sta->sta.supp_rates[wk->chan->band] = rates; | 1595 | sta->sta.supp_rates[wk->chan->band] = rates; |
1577 | sdata->vif.bss_conf.basic_rates = basic_rates; | 1596 | sdata->vif.bss_conf.basic_rates = basic_rates; |
1578 | 1597 | ||
@@ -2267,6 +2286,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | |||
2267 | 2286 | ||
2268 | cancel_work_sync(&ifmgd->request_smps_work); | 2287 | cancel_work_sync(&ifmgd->request_smps_work); |
2269 | 2288 | ||
2289 | cancel_work_sync(&ifmgd->monitor_work); | ||
2270 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); | 2290 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); |
2271 | if (del_timer_sync(&ifmgd->timer)) | 2291 | if (del_timer_sync(&ifmgd->timer)) |
2272 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | 2292 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); |
@@ -2275,7 +2295,6 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | |||
2275 | if (del_timer_sync(&ifmgd->chswitch_timer)) | 2295 | if (del_timer_sync(&ifmgd->chswitch_timer)) |
2276 | set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); | 2296 | set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); |
2277 | 2297 | ||
2278 | cancel_work_sync(&ifmgd->monitor_work); | ||
2279 | /* these will just be re-established on connection */ | 2298 | /* these will just be re-established on connection */ |
2280 | del_timer_sync(&ifmgd->conn_mon_timer); | 2299 | del_timer_sync(&ifmgd->conn_mon_timer); |
2281 | del_timer_sync(&ifmgd->bcn_mon_timer); | 2300 | del_timer_sync(&ifmgd->bcn_mon_timer); |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b867bd55de7a..097b42d286e2 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -140,8 +140,9 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
140 | pos++; | 140 | pos++; |
141 | 141 | ||
142 | /* IEEE80211_RADIOTAP_RATE */ | 142 | /* IEEE80211_RADIOTAP_RATE */ |
143 | if (status->flag & RX_FLAG_HT) { | 143 | if (!rate || status->flag & RX_FLAG_HT) { |
144 | /* | 144 | /* |
145 | * Without rate information don't add it. If we have, | ||
145 | * MCS information is a separate field in radiotap, | 146 | * MCS information is a separate field in radiotap, |
146 | * added below. The byte here is needed as padding | 147 | * added below. The byte here is needed as padding |
147 | * for the channel though, so initialise it to 0. | 148 | * for the channel though, so initialise it to 0. |
@@ -162,12 +163,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
162 | else if (status->flag & RX_FLAG_HT) | 163 | else if (status->flag & RX_FLAG_HT) |
163 | put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ, | 164 | put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ, |
164 | pos); | 165 | pos); |
165 | else if (rate->flags & IEEE80211_RATE_ERP_G) | 166 | else if (rate && rate->flags & IEEE80211_RATE_ERP_G) |
166 | put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, | 167 | put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, |
167 | pos); | 168 | pos); |
168 | else | 169 | else if (rate) |
169 | put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, | 170 | put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, |
170 | pos); | 171 | pos); |
172 | else | ||
173 | put_unaligned_le16(IEEE80211_CHAN_2GHZ, pos); | ||
171 | pos += 2; | 174 | pos += 2; |
172 | 175 | ||
173 | /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ | 176 | /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ce962d2c8782..8eaa746ec7a2 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -1354,12 +1354,12 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, | |||
1354 | * Use MoreData flag to indicate whether there are | 1354 | * Use MoreData flag to indicate whether there are |
1355 | * more buffered frames for this STA | 1355 | * more buffered frames for this STA |
1356 | */ | 1356 | */ |
1357 | if (!more_data) | 1357 | if (more_data || !skb_queue_empty(&frames)) |
1358 | hdr->frame_control &= | ||
1359 | cpu_to_le16(~IEEE80211_FCTL_MOREDATA); | ||
1360 | else | ||
1361 | hdr->frame_control |= | 1358 | hdr->frame_control |= |
1362 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); | 1359 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); |
1360 | else | ||
1361 | hdr->frame_control &= | ||
1362 | cpu_to_le16(~IEEE80211_FCTL_MOREDATA); | ||
1363 | 1363 | ||
1364 | if (ieee80211_is_data_qos(hdr->frame_control) || | 1364 | if (ieee80211_is_data_qos(hdr->frame_control) || |
1365 | ieee80211_is_qos_nullfunc(hdr->frame_control)) | 1365 | ieee80211_is_qos_nullfunc(hdr->frame_control)) |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index df643cedf9b9..5533a74e9bb3 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -259,7 +259,7 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band | |||
259 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 259 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
260 | struct ieee80211_radiotap_header *rthdr; | 260 | struct ieee80211_radiotap_header *rthdr; |
261 | unsigned char *pos; | 261 | unsigned char *pos; |
262 | __le16 txflags; | 262 | u16 txflags; |
263 | 263 | ||
264 | rthdr = (struct ieee80211_radiotap_header *) skb_push(skb, rtap_len); | 264 | rthdr = (struct ieee80211_radiotap_header *) skb_push(skb, rtap_len); |
265 | 265 | ||
@@ -289,13 +289,13 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band | |||
289 | txflags = 0; | 289 | txflags = 0; |
290 | if (!(info->flags & IEEE80211_TX_STAT_ACK) && | 290 | if (!(info->flags & IEEE80211_TX_STAT_ACK) && |
291 | !is_multicast_ether_addr(hdr->addr1)) | 291 | !is_multicast_ether_addr(hdr->addr1)) |
292 | txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); | 292 | txflags |= IEEE80211_RADIOTAP_F_TX_FAIL; |
293 | 293 | ||
294 | if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || | 294 | if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || |
295 | (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) | 295 | (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) |
296 | txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); | 296 | txflags |= IEEE80211_RADIOTAP_F_TX_CTS; |
297 | else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) | 297 | else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) |
298 | txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); | 298 | txflags |= IEEE80211_RADIOTAP_F_TX_RTS; |
299 | 299 | ||
300 | put_unaligned_le16(txflags, pos); | 300 | put_unaligned_le16(txflags, pos); |
301 | pos += 2; | 301 | pos += 2; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7439d26bf5f9..6719bce4a081 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -880,6 +880,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
880 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, | 880 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, |
881 | ssid, ssid_len, | 881 | ssid, ssid_len, |
882 | buf, buf_len); | 882 | buf, buf_len); |
883 | if (!skb) | ||
884 | goto out; | ||
883 | 885 | ||
884 | if (dst) { | 886 | if (dst) { |
885 | mgmt = (struct ieee80211_mgmt *) skb->data; | 887 | mgmt = (struct ieee80211_mgmt *) skb->data; |
@@ -888,6 +890,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
888 | } | 890 | } |
889 | 891 | ||
890 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 892 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
893 | |||
894 | out: | ||
891 | kfree(buf); | 895 | kfree(buf); |
892 | 896 | ||
893 | return skb; | 897 | return skb; |
@@ -1034,7 +1038,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1034 | struct ieee80211_sub_if_data, | 1038 | struct ieee80211_sub_if_data, |
1035 | u.ap); | 1039 | u.ap); |
1036 | 1040 | ||
1037 | memset(&sta->sta.drv_priv, 0, hw->sta_data_size); | ||
1038 | WARN_ON(drv_sta_add(local, sdata, &sta->sta)); | 1041 | WARN_ON(drv_sta_add(local, sdata, &sta->sta)); |
1039 | } | 1042 | } |
1040 | } | 1043 | } |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 48260c2d092a..ffafda5022c2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -89,8 +89,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
89 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, | 89 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, |
90 | [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, | 90 | [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, |
91 | 91 | ||
92 | [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, | 92 | [NL80211_ATTR_MAC] = { .len = ETH_ALEN }, |
93 | [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN }, | 93 | [NL80211_ATTR_PREV_BSSID] = { .len = ETH_ALEN }, |
94 | 94 | ||
95 | [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, | 95 | [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, |
96 | [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, | 96 | [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, |
@@ -132,8 +132,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
132 | [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED }, | 132 | [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED }, |
133 | [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG }, | 133 | [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG }, |
134 | 134 | ||
135 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, | 135 | [NL80211_ATTR_HT_CAPABILITY] = { .len = NL80211_HT_CAPABILITY_LEN }, |
136 | .len = NL80211_HT_CAPABILITY_LEN }, | ||
137 | 136 | ||
138 | [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, | 137 | [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, |
139 | [NL80211_ATTR_IE] = { .type = NLA_BINARY, | 138 | [NL80211_ATTR_IE] = { .type = NLA_BINARY, |
@@ -1253,6 +1252,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1253 | goto bad_res; | 1252 | goto bad_res; |
1254 | } | 1253 | } |
1255 | 1254 | ||
1255 | if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
1256 | netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | ||
1257 | result = -EINVAL; | ||
1258 | goto bad_res; | ||
1259 | } | ||
1260 | |||
1256 | nla_for_each_nested(nl_txq_params, | 1261 | nla_for_each_nested(nl_txq_params, |
1257 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], | 1262 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], |
1258 | rem_txq_params) { | 1263 | rem_txq_params) { |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2520a1b7e7db..074c1122ce42 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -55,8 +55,17 @@ | |||
55 | #define REG_DBG_PRINT(args...) | 55 | #define REG_DBG_PRINT(args...) |
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | static struct regulatory_request core_request_world = { | ||
59 | .initiator = NL80211_REGDOM_SET_BY_CORE, | ||
60 | .alpha2[0] = '0', | ||
61 | .alpha2[1] = '0', | ||
62 | .intersect = false, | ||
63 | .processed = true, | ||
64 | .country_ie_env = ENVIRON_ANY, | ||
65 | }; | ||
66 | |||
58 | /* Receipt of information from last regulatory request */ | 67 | /* Receipt of information from last regulatory request */ |
59 | static struct regulatory_request *last_request; | 68 | static struct regulatory_request *last_request = &core_request_world; |
60 | 69 | ||
61 | /* To trigger userspace events */ | 70 | /* To trigger userspace events */ |
62 | static struct platform_device *reg_pdev; | 71 | static struct platform_device *reg_pdev; |
@@ -148,7 +157,7 @@ static char user_alpha2[2]; | |||
148 | module_param(ieee80211_regdom, charp, 0444); | 157 | module_param(ieee80211_regdom, charp, 0444); |
149 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); | 158 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); |
150 | 159 | ||
151 | static void reset_regdomains(void) | 160 | static void reset_regdomains(bool full_reset) |
152 | { | 161 | { |
153 | /* avoid freeing static information or freeing something twice */ | 162 | /* avoid freeing static information or freeing something twice */ |
154 | if (cfg80211_regdomain == cfg80211_world_regdom) | 163 | if (cfg80211_regdomain == cfg80211_world_regdom) |
@@ -163,6 +172,13 @@ static void reset_regdomains(void) | |||
163 | 172 | ||
164 | cfg80211_world_regdom = &world_regdom; | 173 | cfg80211_world_regdom = &world_regdom; |
165 | cfg80211_regdomain = NULL; | 174 | cfg80211_regdomain = NULL; |
175 | |||
176 | if (!full_reset) | ||
177 | return; | ||
178 | |||
179 | if (last_request != &core_request_world) | ||
180 | kfree(last_request); | ||
181 | last_request = &core_request_world; | ||
166 | } | 182 | } |
167 | 183 | ||
168 | /* | 184 | /* |
@@ -173,7 +189,7 @@ static void update_world_regdomain(const struct ieee80211_regdomain *rd) | |||
173 | { | 189 | { |
174 | BUG_ON(!last_request); | 190 | BUG_ON(!last_request); |
175 | 191 | ||
176 | reset_regdomains(); | 192 | reset_regdomains(false); |
177 | 193 | ||
178 | cfg80211_world_regdom = rd; | 194 | cfg80211_world_regdom = rd; |
179 | cfg80211_regdomain = rd; | 195 | cfg80211_regdomain = rd; |
@@ -1405,7 +1421,8 @@ static int __regulatory_hint(struct wiphy *wiphy, | |||
1405 | } | 1421 | } |
1406 | 1422 | ||
1407 | new_request: | 1423 | new_request: |
1408 | kfree(last_request); | 1424 | if (last_request != &core_request_world) |
1425 | kfree(last_request); | ||
1409 | 1426 | ||
1410 | last_request = pending_request; | 1427 | last_request = pending_request; |
1411 | last_request->intersect = intersect; | 1428 | last_request->intersect = intersect; |
@@ -1575,9 +1592,6 @@ static int regulatory_hint_core(const char *alpha2) | |||
1575 | { | 1592 | { |
1576 | struct regulatory_request *request; | 1593 | struct regulatory_request *request; |
1577 | 1594 | ||
1578 | kfree(last_request); | ||
1579 | last_request = NULL; | ||
1580 | |||
1581 | request = kzalloc(sizeof(struct regulatory_request), | 1595 | request = kzalloc(sizeof(struct regulatory_request), |
1582 | GFP_KERNEL); | 1596 | GFP_KERNEL); |
1583 | if (!request) | 1597 | if (!request) |
@@ -1775,7 +1789,7 @@ static void restore_regulatory_settings(bool reset_user) | |||
1775 | mutex_lock(&cfg80211_mutex); | 1789 | mutex_lock(&cfg80211_mutex); |
1776 | mutex_lock(®_mutex); | 1790 | mutex_lock(®_mutex); |
1777 | 1791 | ||
1778 | reset_regdomains(); | 1792 | reset_regdomains(true); |
1779 | restore_alpha2(alpha2, reset_user); | 1793 | restore_alpha2(alpha2, reset_user); |
1780 | 1794 | ||
1781 | /* | 1795 | /* |
@@ -2035,12 +2049,18 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
2035 | } | 2049 | } |
2036 | 2050 | ||
2037 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | 2051 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); |
2052 | if (!request_wiphy && | ||
2053 | (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER || | ||
2054 | last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) { | ||
2055 | schedule_delayed_work(®_timeout, 0); | ||
2056 | return -ENODEV; | ||
2057 | } | ||
2038 | 2058 | ||
2039 | if (!last_request->intersect) { | 2059 | if (!last_request->intersect) { |
2040 | int r; | 2060 | int r; |
2041 | 2061 | ||
2042 | if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) { | 2062 | if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) { |
2043 | reset_regdomains(); | 2063 | reset_regdomains(false); |
2044 | cfg80211_regdomain = rd; | 2064 | cfg80211_regdomain = rd; |
2045 | return 0; | 2065 | return 0; |
2046 | } | 2066 | } |
@@ -2061,7 +2081,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
2061 | if (r) | 2081 | if (r) |
2062 | return r; | 2082 | return r; |
2063 | 2083 | ||
2064 | reset_regdomains(); | 2084 | reset_regdomains(false); |
2065 | cfg80211_regdomain = rd; | 2085 | cfg80211_regdomain = rd; |
2066 | return 0; | 2086 | return 0; |
2067 | } | 2087 | } |
@@ -2086,7 +2106,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
2086 | 2106 | ||
2087 | rd = NULL; | 2107 | rd = NULL; |
2088 | 2108 | ||
2089 | reset_regdomains(); | 2109 | reset_regdomains(false); |
2090 | cfg80211_regdomain = intersected_rd; | 2110 | cfg80211_regdomain = intersected_rd; |
2091 | 2111 | ||
2092 | return 0; | 2112 | return 0; |
@@ -2106,7 +2126,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
2106 | kfree(rd); | 2126 | kfree(rd); |
2107 | rd = NULL; | 2127 | rd = NULL; |
2108 | 2128 | ||
2109 | reset_regdomains(); | 2129 | reset_regdomains(false); |
2110 | cfg80211_regdomain = intersected_rd; | 2130 | cfg80211_regdomain = intersected_rd; |
2111 | 2131 | ||
2112 | return 0; | 2132 | return 0; |
@@ -2259,9 +2279,9 @@ void /* __init_or_exit */ regulatory_exit(void) | |||
2259 | mutex_lock(&cfg80211_mutex); | 2279 | mutex_lock(&cfg80211_mutex); |
2260 | mutex_lock(®_mutex); | 2280 | mutex_lock(®_mutex); |
2261 | 2281 | ||
2262 | reset_regdomains(); | 2282 | reset_regdomains(true); |
2263 | 2283 | ||
2264 | kfree(last_request); | 2284 | dev_set_uevent_suppress(®_pdev->dev, true); |
2265 | 2285 | ||
2266 | platform_device_unregister(reg_pdev); | 2286 | platform_device_unregister(reg_pdev); |
2267 | 2287 | ||
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0fb142410404..dc23b31594e0 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -259,17 +259,20 @@ static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2) | |||
259 | { | 259 | { |
260 | const u8 *ie1 = cfg80211_find_ie(num, ies1, len1); | 260 | const u8 *ie1 = cfg80211_find_ie(num, ies1, len1); |
261 | const u8 *ie2 = cfg80211_find_ie(num, ies2, len2); | 261 | const u8 *ie2 = cfg80211_find_ie(num, ies2, len2); |
262 | int r; | ||
263 | 262 | ||
263 | /* equal if both missing */ | ||
264 | if (!ie1 && !ie2) | 264 | if (!ie1 && !ie2) |
265 | return 0; | 265 | return 0; |
266 | if (!ie1 || !ie2) | 266 | /* sort missing IE before (left of) present IE */ |
267 | if (!ie1) | ||
267 | return -1; | 268 | return -1; |
269 | if (!ie2) | ||
270 | return 1; | ||
268 | 271 | ||
269 | r = memcmp(ie1 + 2, ie2 + 2, min(ie1[1], ie2[1])); | 272 | /* sort by length first, then by contents */ |
270 | if (r == 0 && ie1[1] != ie2[1]) | 273 | if (ie1[1] != ie2[1]) |
271 | return ie2[1] - ie1[1]; | 274 | return ie2[1] - ie1[1]; |
272 | return r; | 275 | return memcmp(ie1 + 2, ie2 + 2, ie1[1]); |
273 | } | 276 | } |
274 | 277 | ||
275 | static bool is_bss(struct cfg80211_bss *a, | 278 | static bool is_bss(struct cfg80211_bss *a, |