aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/agg-tx.c42
-rw-r--r--net/mac80211/debugfs_sta.c4
-rw-r--r--net/mac80211/main.c6
-rw-r--r--net/mac80211/mlme.c21
-rw-r--r--net/mac80211/rx.c9
-rw-r--r--net/mac80211/sta_info.c8
-rw-r--r--net/mac80211/status.c8
-rw-r--r--net/mac80211/util.c5
-rw-r--r--net/wireless/nl80211.c13
-rw-r--r--net/wireless/reg.c48
-rw-r--r--net/wireless/scan.c13
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
58static 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 */
59static struct regulatory_request *last_request; 68static struct regulatory_request *last_request = &core_request_world;
60 69
61/* To trigger userspace events */ 70/* To trigger userspace events */
62static struct platform_device *reg_pdev; 71static struct platform_device *reg_pdev;
@@ -148,7 +157,7 @@ static char user_alpha2[2];
148module_param(ieee80211_regdom, charp, 0444); 157module_param(ieee80211_regdom, charp, 0444);
149MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); 158MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
150 159
151static void reset_regdomains(void) 160static 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
1407new_request: 1423new_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(&reg_mutex); 1790 mutex_lock(&reg_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(&reg_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(&reg_mutex); 2280 mutex_lock(&reg_mutex);
2261 2281
2262 reset_regdomains(); 2282 reset_regdomains(true);
2263 2283
2264 kfree(last_request); 2284 dev_set_uevent_suppress(&reg_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
275static bool is_bss(struct cfg80211_bss *a, 278static bool is_bss(struct cfg80211_bss *a,