diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 6 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 6 | ||||
-rw-r--r-- | net/mac80211/iface.c | 44 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 160 | ||||
-rw-r--r-- | net/mac80211/rate.c | 11 | ||||
-rw-r--r-- | net/mac80211/rx.c | 3 | ||||
-rw-r--r-- | net/mac80211/tkip.c | 4 | ||||
-rw-r--r-- | net/mac80211/util.c | 11 |
8 files changed, 207 insertions, 38 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 1a89c80e6407..4fdb306e42e0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1057,6 +1057,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1057 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | 1057 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); |
1058 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | 1058 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
1059 | 1059 | ||
1060 | if (sdata->wdev.cac_started) { | ||
1061 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); | ||
1062 | cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED, | ||
1063 | GFP_KERNEL); | ||
1064 | } | ||
1065 | |||
1060 | drv_stop_ap(sdata->local, sdata); | 1066 | drv_stop_ap(sdata->local, sdata); |
1061 | 1067 | ||
1062 | /* free all potentially still buffered bcast frames */ | 1068 | /* free all potentially still buffered bcast frames */ |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 158e6eb188d3..9ca8e3278cc0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -1267,6 +1267,7 @@ void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata); | |||
1267 | void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata); | 1267 | void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata); |
1268 | void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata, | 1268 | void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata, |
1269 | __le16 fc, bool acked); | 1269 | __le16 fc, bool acked); |
1270 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); | ||
1270 | 1271 | ||
1271 | /* IBSS code */ | 1272 | /* IBSS code */ |
1272 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); | 1273 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); |
@@ -1496,10 +1497,11 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, | |||
1496 | ieee80211_tx_skb_tid(sdata, skb, 7); | 1497 | ieee80211_tx_skb_tid(sdata, skb, 7); |
1497 | } | 1498 | } |
1498 | 1499 | ||
1499 | u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, bool action, | 1500 | u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, |
1500 | struct ieee802_11_elems *elems, | 1501 | struct ieee802_11_elems *elems, |
1501 | u64 filter, u32 crc); | 1502 | u64 filter, u32 crc); |
1502 | static inline void ieee802_11_parse_elems(u8 *start, size_t len, bool action, | 1503 | static inline void ieee802_11_parse_elems(const u8 *start, size_t len, |
1504 | bool action, | ||
1503 | struct ieee802_11_elems *elems) | 1505 | struct ieee802_11_elems *elems) |
1504 | { | 1506 | { |
1505 | ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0); | 1507 | ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 60f1ce5e5e52..98d20c0f6fed 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -159,9 +159,10 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | |||
159 | return 0; | 159 | return 0; |
160 | } | 160 | } |
161 | 161 | ||
162 | static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr) | 162 | static int ieee80211_verify_mac(struct ieee80211_sub_if_data *sdata, u8 *addr) |
163 | { | 163 | { |
164 | struct ieee80211_sub_if_data *sdata; | 164 | struct ieee80211_local *local = sdata->local; |
165 | struct ieee80211_sub_if_data *iter; | ||
165 | u64 new, mask, tmp; | 166 | u64 new, mask, tmp; |
166 | u8 *m; | 167 | u8 *m; |
167 | int ret = 0; | 168 | int ret = 0; |
@@ -181,11 +182,14 @@ static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr) | |||
181 | 182 | ||
182 | 183 | ||
183 | mutex_lock(&local->iflist_mtx); | 184 | mutex_lock(&local->iflist_mtx); |
184 | list_for_each_entry(sdata, &local->interfaces, list) { | 185 | list_for_each_entry(iter, &local->interfaces, list) { |
185 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR) | 186 | if (iter == sdata) |
187 | continue; | ||
188 | |||
189 | if (iter->vif.type == NL80211_IFTYPE_MONITOR) | ||
186 | continue; | 190 | continue; |
187 | 191 | ||
188 | m = sdata->vif.addr; | 192 | m = iter->vif.addr; |
189 | tmp = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | | 193 | tmp = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | |
190 | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | | 194 | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | |
191 | ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); | 195 | ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); |
@@ -209,7 +213,7 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr) | |||
209 | if (ieee80211_sdata_running(sdata)) | 213 | if (ieee80211_sdata_running(sdata)) |
210 | return -EBUSY; | 214 | return -EBUSY; |
211 | 215 | ||
212 | ret = ieee80211_verify_mac(sdata->local, sa->sa_data); | 216 | ret = ieee80211_verify_mac(sdata, sa->sa_data); |
213 | if (ret) | 217 | if (ret) |
214 | return ret; | 218 | return ret; |
215 | 219 | ||
@@ -474,6 +478,9 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
474 | master->control_port_protocol; | 478 | master->control_port_protocol; |
475 | sdata->control_port_no_encrypt = | 479 | sdata->control_port_no_encrypt = |
476 | master->control_port_no_encrypt; | 480 | master->control_port_no_encrypt; |
481 | sdata->vif.cab_queue = master->vif.cab_queue; | ||
482 | memcpy(sdata->vif.hw_queue, master->vif.hw_queue, | ||
483 | sizeof(sdata->vif.hw_queue)); | ||
477 | break; | 484 | break; |
478 | } | 485 | } |
479 | case NL80211_IFTYPE_AP: | 486 | case NL80211_IFTYPE_AP: |
@@ -653,7 +660,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
653 | 660 | ||
654 | ieee80211_recalc_ps(local, -1); | 661 | ieee80211_recalc_ps(local, -1); |
655 | 662 | ||
656 | if (dev) { | 663 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || |
664 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { | ||
665 | /* XXX: for AP_VLAN, actually track AP queues */ | ||
666 | netif_tx_start_all_queues(dev); | ||
667 | } else if (dev) { | ||
657 | unsigned long flags; | 668 | unsigned long flags; |
658 | int n_acs = IEEE80211_NUM_ACS; | 669 | int n_acs = IEEE80211_NUM_ACS; |
659 | int ac; | 670 | int ac; |
@@ -1479,7 +1490,17 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | |||
1479 | break; | 1490 | break; |
1480 | } | 1491 | } |
1481 | 1492 | ||
1493 | /* | ||
1494 | * Pick address of existing interface in case user changed | ||
1495 | * MAC address manually, default to perm_addr. | ||
1496 | */ | ||
1482 | m = local->hw.wiphy->perm_addr; | 1497 | m = local->hw.wiphy->perm_addr; |
1498 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1499 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR) | ||
1500 | continue; | ||
1501 | m = sdata->vif.addr; | ||
1502 | break; | ||
1503 | } | ||
1483 | start = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | | 1504 | start = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | |
1484 | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | | 1505 | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | |
1485 | ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); | 1506 | ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); |
@@ -1696,6 +1717,15 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) | |||
1696 | 1717 | ||
1697 | ASSERT_RTNL(); | 1718 | ASSERT_RTNL(); |
1698 | 1719 | ||
1720 | /* | ||
1721 | * Close all AP_VLAN interfaces first, as otherwise they | ||
1722 | * might be closed while the AP interface they belong to | ||
1723 | * is closed, causing unregister_netdevice_many() to crash. | ||
1724 | */ | ||
1725 | list_for_each_entry(sdata, &local->interfaces, list) | ||
1726 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
1727 | dev_close(sdata->dev); | ||
1728 | |||
1699 | mutex_lock(&local->iflist_mtx); | 1729 | mutex_lock(&local->iflist_mtx); |
1700 | list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { | 1730 | list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { |
1701 | list_del(&sdata->list); | 1731 | list_del(&sdata->list); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 29620bfc7a69..741448b30825 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1015,7 +1015,8 @@ static void ieee80211_chswitch_timer(unsigned long data) | |||
1015 | 1015 | ||
1016 | static void | 1016 | static void |
1017 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 1017 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
1018 | u64 timestamp, struct ieee802_11_elems *elems) | 1018 | u64 timestamp, struct ieee802_11_elems *elems, |
1019 | bool beacon) | ||
1019 | { | 1020 | { |
1020 | struct ieee80211_local *local = sdata->local; | 1021 | struct ieee80211_local *local = sdata->local; |
1021 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1022 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
@@ -1032,6 +1033,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1032 | struct cfg80211_chan_def new_vht_chandef = {}; | 1033 | struct cfg80211_chan_def new_vht_chandef = {}; |
1033 | const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; | 1034 | const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; |
1034 | const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; | 1035 | const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; |
1036 | const struct ieee80211_ht_operation *ht_oper; | ||
1035 | int secondary_channel_offset = -1; | 1037 | int secondary_channel_offset = -1; |
1036 | 1038 | ||
1037 | ASSERT_MGD_MTX(ifmgd); | 1039 | ASSERT_MGD_MTX(ifmgd); |
@@ -1048,11 +1050,14 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1048 | 1050 | ||
1049 | sec_chan_offs = elems->sec_chan_offs; | 1051 | sec_chan_offs = elems->sec_chan_offs; |
1050 | wide_bw_chansw_ie = elems->wide_bw_chansw_ie; | 1052 | wide_bw_chansw_ie = elems->wide_bw_chansw_ie; |
1053 | ht_oper = elems->ht_operation; | ||
1051 | 1054 | ||
1052 | if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT | | 1055 | if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT | |
1053 | IEEE80211_STA_DISABLE_40MHZ)) { | 1056 | IEEE80211_STA_DISABLE_40MHZ)) { |
1054 | sec_chan_offs = NULL; | 1057 | sec_chan_offs = NULL; |
1055 | wide_bw_chansw_ie = NULL; | 1058 | wide_bw_chansw_ie = NULL; |
1059 | /* only used for bandwidth here */ | ||
1060 | ht_oper = NULL; | ||
1056 | } | 1061 | } |
1057 | 1062 | ||
1058 | if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) | 1063 | if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) |
@@ -1094,10 +1099,20 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1094 | return; | 1099 | return; |
1095 | } | 1100 | } |
1096 | 1101 | ||
1097 | if (sec_chan_offs) { | 1102 | if (!beacon && sec_chan_offs) { |
1098 | secondary_channel_offset = sec_chan_offs->sec_chan_offs; | 1103 | secondary_channel_offset = sec_chan_offs->sec_chan_offs; |
1104 | } else if (beacon && ht_oper) { | ||
1105 | secondary_channel_offset = | ||
1106 | ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET; | ||
1099 | } else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | 1107 | } else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { |
1100 | /* if HT is enabled and the IE not present, it's still HT */ | 1108 | /* |
1109 | * If it's not a beacon, HT is enabled and the IE not present, | ||
1110 | * it's 20 MHz, 802.11-2012 8.5.2.6: | ||
1111 | * This element [the Secondary Channel Offset Element] is | ||
1112 | * present when switching to a 40 MHz channel. It may be | ||
1113 | * present when switching to a 20 MHz channel (in which | ||
1114 | * case the secondary channel offset is set to SCN). | ||
1115 | */ | ||
1101 | secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; | 1116 | secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; |
1102 | } | 1117 | } |
1103 | 1118 | ||
@@ -2507,8 +2522,11 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2507 | u16 capab_info, aid; | 2522 | u16 capab_info, aid; |
2508 | struct ieee802_11_elems elems; | 2523 | struct ieee802_11_elems elems; |
2509 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 2524 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
2525 | const struct cfg80211_bss_ies *bss_ies = NULL; | ||
2526 | struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; | ||
2510 | u32 changed = 0; | 2527 | u32 changed = 0; |
2511 | int err; | 2528 | int err; |
2529 | bool ret; | ||
2512 | 2530 | ||
2513 | /* AssocResp and ReassocResp have identical structure */ | 2531 | /* AssocResp and ReassocResp have identical structure */ |
2514 | 2532 | ||
@@ -2540,21 +2558,86 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2540 | ifmgd->aid = aid; | 2558 | ifmgd->aid = aid; |
2541 | 2559 | ||
2542 | /* | 2560 | /* |
2561 | * Some APs are erroneously not including some information in their | ||
2562 | * (re)association response frames. Try to recover by using the data | ||
2563 | * from the beacon or probe response. This seems to afflict mobile | ||
2564 | * 2G/3G/4G wifi routers, reported models include the "Onda PN51T", | ||
2565 | * "Vodafone PocketWiFi 2", "ZTE MF60" and a similar T-Mobile device. | ||
2566 | */ | ||
2567 | if ((assoc_data->wmm && !elems.wmm_param) || | ||
2568 | (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && | ||
2569 | (!elems.ht_cap_elem || !elems.ht_operation)) || | ||
2570 | (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && | ||
2571 | (!elems.vht_cap_elem || !elems.vht_operation))) { | ||
2572 | const struct cfg80211_bss_ies *ies; | ||
2573 | struct ieee802_11_elems bss_elems; | ||
2574 | |||
2575 | rcu_read_lock(); | ||
2576 | ies = rcu_dereference(cbss->ies); | ||
2577 | if (ies) | ||
2578 | bss_ies = kmemdup(ies, sizeof(*ies) + ies->len, | ||
2579 | GFP_ATOMIC); | ||
2580 | rcu_read_unlock(); | ||
2581 | if (!bss_ies) | ||
2582 | return false; | ||
2583 | |||
2584 | ieee802_11_parse_elems(bss_ies->data, bss_ies->len, | ||
2585 | false, &bss_elems); | ||
2586 | if (assoc_data->wmm && | ||
2587 | !elems.wmm_param && bss_elems.wmm_param) { | ||
2588 | elems.wmm_param = bss_elems.wmm_param; | ||
2589 | sdata_info(sdata, | ||
2590 | "AP bug: WMM param missing from AssocResp\n"); | ||
2591 | } | ||
2592 | |||
2593 | /* | ||
2594 | * Also check if we requested HT/VHT, otherwise the AP doesn't | ||
2595 | * have to include the IEs in the (re)association response. | ||
2596 | */ | ||
2597 | if (!elems.ht_cap_elem && bss_elems.ht_cap_elem && | ||
2598 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | ||
2599 | elems.ht_cap_elem = bss_elems.ht_cap_elem; | ||
2600 | sdata_info(sdata, | ||
2601 | "AP bug: HT capability missing from AssocResp\n"); | ||
2602 | } | ||
2603 | if (!elems.ht_operation && bss_elems.ht_operation && | ||
2604 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | ||
2605 | elems.ht_operation = bss_elems.ht_operation; | ||
2606 | sdata_info(sdata, | ||
2607 | "AP bug: HT operation missing from AssocResp\n"); | ||
2608 | } | ||
2609 | if (!elems.vht_cap_elem && bss_elems.vht_cap_elem && | ||
2610 | !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { | ||
2611 | elems.vht_cap_elem = bss_elems.vht_cap_elem; | ||
2612 | sdata_info(sdata, | ||
2613 | "AP bug: VHT capa missing from AssocResp\n"); | ||
2614 | } | ||
2615 | if (!elems.vht_operation && bss_elems.vht_operation && | ||
2616 | !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { | ||
2617 | elems.vht_operation = bss_elems.vht_operation; | ||
2618 | sdata_info(sdata, | ||
2619 | "AP bug: VHT operation missing from AssocResp\n"); | ||
2620 | } | ||
2621 | } | ||
2622 | |||
2623 | /* | ||
2543 | * We previously checked these in the beacon/probe response, so | 2624 | * We previously checked these in the beacon/probe response, so |
2544 | * they should be present here. This is just a safety net. | 2625 | * they should be present here. This is just a safety net. |
2545 | */ | 2626 | */ |
2546 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && | 2627 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && |
2547 | (!elems.wmm_param || !elems.ht_cap_elem || !elems.ht_operation)) { | 2628 | (!elems.wmm_param || !elems.ht_cap_elem || !elems.ht_operation)) { |
2548 | sdata_info(sdata, | 2629 | sdata_info(sdata, |
2549 | "HT AP is missing WMM params or HT capability/operation in AssocResp\n"); | 2630 | "HT AP is missing WMM params or HT capability/operation\n"); |
2550 | return false; | 2631 | ret = false; |
2632 | goto out; | ||
2551 | } | 2633 | } |
2552 | 2634 | ||
2553 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && | 2635 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && |
2554 | (!elems.vht_cap_elem || !elems.vht_operation)) { | 2636 | (!elems.vht_cap_elem || !elems.vht_operation)) { |
2555 | sdata_info(sdata, | 2637 | sdata_info(sdata, |
2556 | "VHT AP is missing VHT capability/operation in AssocResp\n"); | 2638 | "VHT AP is missing VHT capability/operation\n"); |
2557 | return false; | 2639 | ret = false; |
2640 | goto out; | ||
2558 | } | 2641 | } |
2559 | 2642 | ||
2560 | mutex_lock(&sdata->local->sta_mtx); | 2643 | mutex_lock(&sdata->local->sta_mtx); |
@@ -2565,7 +2648,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2565 | sta = sta_info_get(sdata, cbss->bssid); | 2648 | sta = sta_info_get(sdata, cbss->bssid); |
2566 | if (WARN_ON(!sta)) { | 2649 | if (WARN_ON(!sta)) { |
2567 | mutex_unlock(&sdata->local->sta_mtx); | 2650 | mutex_unlock(&sdata->local->sta_mtx); |
2568 | return false; | 2651 | ret = false; |
2652 | goto out; | ||
2569 | } | 2653 | } |
2570 | 2654 | ||
2571 | sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; | 2655 | sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; |
@@ -2618,7 +2702,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2618 | sta->sta.addr); | 2702 | sta->sta.addr); |
2619 | WARN_ON(__sta_info_destroy(sta)); | 2703 | WARN_ON(__sta_info_destroy(sta)); |
2620 | mutex_unlock(&sdata->local->sta_mtx); | 2704 | mutex_unlock(&sdata->local->sta_mtx); |
2621 | return false; | 2705 | ret = false; |
2706 | goto out; | ||
2622 | } | 2707 | } |
2623 | 2708 | ||
2624 | mutex_unlock(&sdata->local->sta_mtx); | 2709 | mutex_unlock(&sdata->local->sta_mtx); |
@@ -2658,7 +2743,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2658 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); | 2743 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); |
2659 | ieee80211_sta_reset_beacon_monitor(sdata); | 2744 | ieee80211_sta_reset_beacon_monitor(sdata); |
2660 | 2745 | ||
2661 | return true; | 2746 | ret = true; |
2747 | out: | ||
2748 | kfree(bss_ies); | ||
2749 | return ret; | ||
2662 | } | 2750 | } |
2663 | 2751 | ||
2664 | static enum rx_mgmt_action __must_check | 2752 | static enum rx_mgmt_action __must_check |
@@ -2796,7 +2884,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2796 | mutex_unlock(&local->iflist_mtx); | 2884 | mutex_unlock(&local->iflist_mtx); |
2797 | } | 2885 | } |
2798 | 2886 | ||
2799 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, elems); | 2887 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, |
2888 | elems, true); | ||
2800 | 2889 | ||
2801 | } | 2890 | } |
2802 | 2891 | ||
@@ -3210,7 +3299,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
3210 | 3299 | ||
3211 | ieee80211_sta_process_chanswitch(sdata, | 3300 | ieee80211_sta_process_chanswitch(sdata, |
3212 | rx_status->mactime, | 3301 | rx_status->mactime, |
3213 | &elems); | 3302 | &elems, false); |
3214 | } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { | 3303 | } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { |
3215 | ies_len = skb->len - | 3304 | ies_len = skb->len - |
3216 | offsetof(struct ieee80211_mgmt, | 3305 | offsetof(struct ieee80211_mgmt, |
@@ -3232,7 +3321,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
3232 | 3321 | ||
3233 | ieee80211_sta_process_chanswitch(sdata, | 3322 | ieee80211_sta_process_chanswitch(sdata, |
3234 | rx_status->mactime, | 3323 | rx_status->mactime, |
3235 | &elems); | 3324 | &elems, false); |
3236 | } | 3325 | } |
3237 | break; | 3326 | break; |
3238 | } | 3327 | } |
@@ -3305,10 +3394,6 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
3305 | if (WARN_ON_ONCE(!auth_data)) | 3394 | if (WARN_ON_ONCE(!auth_data)) |
3306 | return -EINVAL; | 3395 | return -EINVAL; |
3307 | 3396 | ||
3308 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | ||
3309 | tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS | | ||
3310 | IEEE80211_TX_INTFL_MLME_CONN_TX; | ||
3311 | |||
3312 | auth_data->tries++; | 3397 | auth_data->tries++; |
3313 | 3398 | ||
3314 | if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { | 3399 | if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { |
@@ -3342,6 +3427,10 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
3342 | auth_data->expected_transaction = trans; | 3427 | auth_data->expected_transaction = trans; |
3343 | } | 3428 | } |
3344 | 3429 | ||
3430 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | ||
3431 | tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS | | ||
3432 | IEEE80211_TX_INTFL_MLME_CONN_TX; | ||
3433 | |||
3345 | ieee80211_send_auth(sdata, trans, auth_data->algorithm, status, | 3434 | ieee80211_send_auth(sdata, trans, auth_data->algorithm, status, |
3346 | auth_data->data, auth_data->data_len, | 3435 | auth_data->data, auth_data->data_len, |
3347 | auth_data->bss->bssid, | 3436 | auth_data->bss->bssid, |
@@ -3365,12 +3454,12 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
3365 | * will not answer to direct packet in unassociated state. | 3454 | * will not answer to direct packet in unassociated state. |
3366 | */ | 3455 | */ |
3367 | ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], | 3456 | ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], |
3368 | NULL, 0, (u32) -1, true, tx_flags, | 3457 | NULL, 0, (u32) -1, true, 0, |
3369 | auth_data->bss->channel, false); | 3458 | auth_data->bss->channel, false); |
3370 | rcu_read_unlock(); | 3459 | rcu_read_unlock(); |
3371 | } | 3460 | } |
3372 | 3461 | ||
3373 | if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { | 3462 | if (tx_flags == 0) { |
3374 | auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | 3463 | auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; |
3375 | ifmgd->auth_data->timeout_started = true; | 3464 | ifmgd->auth_data->timeout_started = true; |
3376 | run_again(ifmgd, auth_data->timeout); | 3465 | run_again(ifmgd, auth_data->timeout); |
@@ -3623,6 +3712,31 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | |||
3623 | } | 3712 | } |
3624 | } | 3713 | } |
3625 | 3714 | ||
3715 | #ifdef CONFIG_PM | ||
3716 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | ||
3717 | { | ||
3718 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3719 | |||
3720 | mutex_lock(&ifmgd->mtx); | ||
3721 | if (!ifmgd->associated) { | ||
3722 | mutex_unlock(&ifmgd->mtx); | ||
3723 | return; | ||
3724 | } | ||
3725 | |||
3726 | if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) { | ||
3727 | sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME; | ||
3728 | mlme_dbg(sdata, "driver requested disconnect after resume\n"); | ||
3729 | ieee80211_sta_connection_lost(sdata, | ||
3730 | ifmgd->associated->bssid, | ||
3731 | WLAN_REASON_UNSPECIFIED, | ||
3732 | true); | ||
3733 | mutex_unlock(&ifmgd->mtx); | ||
3734 | return; | ||
3735 | } | ||
3736 | mutex_unlock(&ifmgd->mtx); | ||
3737 | } | ||
3738 | #endif | ||
3739 | |||
3626 | /* interface setup */ | 3740 | /* interface setup */ |
3627 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | 3741 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) |
3628 | { | 3742 | { |
@@ -4329,7 +4443,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
4329 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 4443 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
4330 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 4444 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
4331 | bool tx = !req->local_state_change; | 4445 | bool tx = !req->local_state_change; |
4332 | bool sent_frame = false; | 4446 | bool report_frame = false; |
4333 | 4447 | ||
4334 | mutex_lock(&ifmgd->mtx); | 4448 | mutex_lock(&ifmgd->mtx); |
4335 | 4449 | ||
@@ -4346,7 +4460,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
4346 | ieee80211_destroy_auth_data(sdata, false); | 4460 | ieee80211_destroy_auth_data(sdata, false); |
4347 | mutex_unlock(&ifmgd->mtx); | 4461 | mutex_unlock(&ifmgd->mtx); |
4348 | 4462 | ||
4349 | sent_frame = tx; | 4463 | report_frame = true; |
4350 | goto out; | 4464 | goto out; |
4351 | } | 4465 | } |
4352 | 4466 | ||
@@ -4354,12 +4468,12 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
4354 | ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { | 4468 | ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { |
4355 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 4469 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
4356 | req->reason_code, tx, frame_buf); | 4470 | req->reason_code, tx, frame_buf); |
4357 | sent_frame = tx; | 4471 | report_frame = true; |
4358 | } | 4472 | } |
4359 | mutex_unlock(&ifmgd->mtx); | 4473 | mutex_unlock(&ifmgd->mtx); |
4360 | 4474 | ||
4361 | out: | 4475 | out: |
4362 | if (sent_frame) | 4476 | if (report_frame) |
4363 | __cfg80211_send_deauth(sdata->dev, frame_buf, | 4477 | __cfg80211_send_deauth(sdata->dev, frame_buf, |
4364 | IEEE80211_DEAUTH_FRAME_LEN); | 4478 | IEEE80211_DEAUTH_FRAME_LEN); |
4365 | 4479 | ||
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 0d51877efdb7..a02bef35b134 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -615,7 +615,7 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata, | |||
615 | if (rates[i].idx < 0) | 615 | if (rates[i].idx < 0) |
616 | break; | 616 | break; |
617 | 617 | ||
618 | rate_idx_match_mask(&rates[i], sband, mask, chan_width, | 618 | rate_idx_match_mask(&rates[i], sband, chan_width, mask, |
619 | mcs_mask); | 619 | mcs_mask); |
620 | } | 620 | } |
621 | } | 621 | } |
@@ -688,8 +688,15 @@ int rate_control_set_rates(struct ieee80211_hw *hw, | |||
688 | struct ieee80211_sta *pubsta, | 688 | struct ieee80211_sta *pubsta, |
689 | struct ieee80211_sta_rates *rates) | 689 | struct ieee80211_sta_rates *rates) |
690 | { | 690 | { |
691 | struct ieee80211_sta_rates *old = rcu_dereference(pubsta->rates); | 691 | struct ieee80211_sta_rates *old; |
692 | 692 | ||
693 | /* | ||
694 | * mac80211 guarantees that this function will not be called | ||
695 | * concurrently, so the following RCU access is safe, even without | ||
696 | * extra locking. This can not be checked easily, so we just set | ||
697 | * the condition to true. | ||
698 | */ | ||
699 | old = rcu_dereference_protected(pubsta->rates, true); | ||
693 | rcu_assign_pointer(pubsta->rates, rates); | 700 | rcu_assign_pointer(pubsta->rates, rates); |
694 | if (old) | 701 | if (old) |
695 | kfree_rcu(old, rcu_head); | 702 | kfree_rcu(old, rcu_head); |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c8447af76ead..8e2952620256 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -3036,6 +3036,9 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
3036 | * and location updates. Note that mac80211 | 3036 | * and location updates. Note that mac80211 |
3037 | * itself never looks at these frames. | 3037 | * itself never looks at these frames. |
3038 | */ | 3038 | */ |
3039 | if (!multicast && | ||
3040 | !ether_addr_equal(sdata->vif.addr, hdr->addr1)) | ||
3041 | return 0; | ||
3039 | if (ieee80211_is_public_action(hdr, skb->len)) | 3042 | if (ieee80211_is_public_action(hdr, skb->len)) |
3040 | return 1; | 3043 | return 1; |
3041 | if (!ieee80211_is_beacon(hdr->frame_control)) | 3044 | if (!ieee80211_is_beacon(hdr->frame_control)) |
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 3ed801d90f1e..124b1fdc20d0 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c | |||
@@ -208,10 +208,10 @@ void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf, | |||
208 | u32 iv32 = get_unaligned_le32(&data[4]); | 208 | u32 iv32 = get_unaligned_le32(&data[4]); |
209 | u16 iv16 = data[2] | (data[0] << 8); | 209 | u16 iv16 = data[2] | (data[0] << 8); |
210 | 210 | ||
211 | spin_lock_bh(&key->u.tkip.txlock); | 211 | spin_lock(&key->u.tkip.txlock); |
212 | ieee80211_compute_tkip_p1k(key, iv32); | 212 | ieee80211_compute_tkip_p1k(key, iv32); |
213 | tkip_mixing_phase2(tk, ctx, iv16, p2k); | 213 | tkip_mixing_phase2(tk, ctx, iv16, p2k); |
214 | spin_unlock_bh(&key->u.tkip.txlock); | 214 | spin_unlock(&key->u.tkip.txlock); |
215 | } | 215 | } |
216 | EXPORT_SYMBOL(ieee80211_get_tkip_p2k); | 216 | EXPORT_SYMBOL(ieee80211_get_tkip_p2k); |
217 | 217 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 3f87fa468b1f..72e6292955bb 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -661,12 +661,12 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, | |||
661 | } | 661 | } |
662 | EXPORT_SYMBOL(ieee80211_queue_delayed_work); | 662 | EXPORT_SYMBOL(ieee80211_queue_delayed_work); |
663 | 663 | ||
664 | u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, bool action, | 664 | u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, |
665 | struct ieee802_11_elems *elems, | 665 | struct ieee802_11_elems *elems, |
666 | u64 filter, u32 crc) | 666 | u64 filter, u32 crc) |
667 | { | 667 | { |
668 | size_t left = len; | 668 | size_t left = len; |
669 | u8 *pos = start; | 669 | const u8 *pos = start; |
670 | bool calc_crc = filter != 0; | 670 | bool calc_crc = filter != 0; |
671 | DECLARE_BITMAP(seen_elems, 256); | 671 | DECLARE_BITMAP(seen_elems, 256); |
672 | const u8 *ie; | 672 | const u8 *ie; |
@@ -1740,6 +1740,13 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1740 | mb(); | 1740 | mb(); |
1741 | local->resuming = false; | 1741 | local->resuming = false; |
1742 | 1742 | ||
1743 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1744 | if (!ieee80211_sdata_running(sdata)) | ||
1745 | continue; | ||
1746 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | ||
1747 | ieee80211_sta_restart(sdata); | ||
1748 | } | ||
1749 | |||
1743 | mod_timer(&local->sta_cleanup, jiffies + 1); | 1750 | mod_timer(&local->sta_cleanup, jiffies + 1); |
1744 | #else | 1751 | #else |
1745 | WARN_ON(1); | 1752 | WARN_ON(1); |