diff options
author | John W. Linville <linville@tuxdriver.com> | 2013-06-12 15:39:05 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-06-12 15:39:05 -0400 |
commit | 812fd645968118c35a3f4d0d18dd3f4d07221df0 (patch) | |
tree | b68ee223f22a811e9743b193872052cd264fe2d0 /net | |
parent | cb180840a0c6bff7c0787373c23cefdf20417a27 (diff) | |
parent | 940d0ac9dbe3fb9d4806e96f006286c2e476deed (diff) |
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Conflicts:
drivers/net/wireless/iwlwifi/mvm/mac80211.c
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 20 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/main.c | 3 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 38 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 5 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 7 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 98 | ||||
-rw-r--r-- | net/mac80211/rx.c | 26 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 4 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 3 | ||||
-rw-r--r-- | net/mac80211/tx.c | 6 | ||||
-rw-r--r-- | net/mac80211/util.c | 5 | ||||
-rw-r--r-- | net/wireless/core.c | 47 | ||||
-rw-r--r-- | net/wireless/core.h | 30 | ||||
-rw-r--r-- | net/wireless/ibss.c | 6 | ||||
-rw-r--r-- | net/wireless/mesh.c | 12 | ||||
-rw-r--r-- | net/wireless/mlme.c | 241 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 192 | ||||
-rw-r--r-- | net/wireless/reg.c | 2 | ||||
-rw-r--r-- | net/wireless/sme.c | 542 | ||||
-rw-r--r-- | net/wireless/trace.h | 46 | ||||
-rw-r--r-- | net/wireless/wext-sme.c | 8 |
22 files changed, 646 insertions, 698 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 30622101d3b5..64cf294c2b96 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1759,6 +1759,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, | |||
1759 | /* mcast rate setting in Mesh Node */ | 1759 | /* mcast rate setting in Mesh Node */ |
1760 | memcpy(sdata->vif.bss_conf.mcast_rate, setup->mcast_rate, | 1760 | memcpy(sdata->vif.bss_conf.mcast_rate, setup->mcast_rate, |
1761 | sizeof(setup->mcast_rate)); | 1761 | sizeof(setup->mcast_rate)); |
1762 | sdata->vif.bss_conf.basic_rates = setup->basic_rates; | ||
1762 | 1763 | ||
1763 | sdata->vif.bss_conf.beacon_int = setup->beacon_interval; | 1764 | sdata->vif.bss_conf.beacon_int = setup->beacon_interval; |
1764 | sdata->vif.bss_conf.dtim_period = setup->dtim_period; | 1765 | sdata->vif.bss_conf.dtim_period = setup->dtim_period; |
@@ -1871,6 +1872,8 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, | |||
1871 | if (_chg_mesh_attr(NL80211_MESHCONF_AWAKE_WINDOW, mask)) | 1872 | if (_chg_mesh_attr(NL80211_MESHCONF_AWAKE_WINDOW, mask)) |
1872 | conf->dot11MeshAwakeWindowDuration = | 1873 | conf->dot11MeshAwakeWindowDuration = |
1873 | nconf->dot11MeshAwakeWindowDuration; | 1874 | nconf->dot11MeshAwakeWindowDuration; |
1875 | if (_chg_mesh_attr(NL80211_MESHCONF_PLINK_TIMEOUT, mask)) | ||
1876 | conf->plink_timeout = nconf->plink_timeout; | ||
1874 | ieee80211_mbss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 1877 | ieee80211_mbss_info_change_notify(sdata, BSS_CHANGED_BEACON); |
1875 | return 0; | 1878 | return 0; |
1876 | } | 1879 | } |
@@ -2838,6 +2841,12 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
2838 | return -EOPNOTSUPP; | 2841 | return -EOPNOTSUPP; |
2839 | } | 2842 | } |
2840 | 2843 | ||
2844 | /* configurations requiring offchan cannot work if no channel has been | ||
2845 | * specified | ||
2846 | */ | ||
2847 | if (need_offchan && !chan) | ||
2848 | return -EINVAL; | ||
2849 | |||
2841 | mutex_lock(&local->mtx); | 2850 | mutex_lock(&local->mtx); |
2842 | 2851 | ||
2843 | /* Check if the operating channel is the requested channel */ | 2852 | /* Check if the operating channel is the requested channel */ |
@@ -2847,10 +2856,15 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
2847 | rcu_read_lock(); | 2856 | rcu_read_lock(); |
2848 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 2857 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
2849 | 2858 | ||
2850 | if (chanctx_conf) | 2859 | if (chanctx_conf) { |
2851 | need_offchan = chan != chanctx_conf->def.chan; | 2860 | need_offchan = chan && (chan != chanctx_conf->def.chan); |
2852 | else | 2861 | } else if (!chan) { |
2862 | ret = -EINVAL; | ||
2863 | rcu_read_unlock(); | ||
2864 | goto out_unlock; | ||
2865 | } else { | ||
2853 | need_offchan = true; | 2866 | need_offchan = true; |
2867 | } | ||
2854 | rcu_read_unlock(); | 2868 | rcu_read_unlock(); |
2855 | } | 2869 | } |
2856 | 2870 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9eed6f1d1614..7a6f1a0207ec 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -366,7 +366,7 @@ struct ieee80211_mgd_assoc_data { | |||
366 | u8 ssid_len; | 366 | u8 ssid_len; |
367 | u8 supp_rates_len; | 367 | u8 supp_rates_len; |
368 | bool wmm, uapsd; | 368 | bool wmm, uapsd; |
369 | bool have_beacon, need_beacon; | 369 | bool need_beacon; |
370 | bool synced; | 370 | bool synced; |
371 | bool timeout_started; | 371 | bool timeout_started; |
372 | 372 | ||
@@ -404,6 +404,7 @@ struct ieee80211_if_managed { | |||
404 | 404 | ||
405 | bool powersave; /* powersave requested for this iface */ | 405 | bool powersave; /* powersave requested for this iface */ |
406 | bool broken_ap; /* AP is broken -- turn off powersave */ | 406 | bool broken_ap; /* AP is broken -- turn off powersave */ |
407 | bool have_beacon; | ||
407 | u8 dtim_period; | 408 | u8 dtim_period; |
408 | enum ieee80211_smps_mode req_smps, /* requested smps mode */ | 409 | enum ieee80211_smps_mode req_smps, /* requested smps mode */ |
409 | driver_smps_mode; /* smps mode request */ | 410 | driver_smps_mode; /* smps mode request */ |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 1998f1475267..626c83c042d7 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -686,8 +686,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
686 | return -EINVAL; | 686 | return -EINVAL; |
687 | 687 | ||
688 | #ifdef CONFIG_PM | 688 | #ifdef CONFIG_PM |
689 | if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) && | 689 | if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume)) |
690 | (!local->ops->suspend || !local->ops->resume)) | ||
691 | return -EINVAL; | 690 | return -EINVAL; |
692 | #endif | 691 | #endif |
693 | 692 | ||
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index b3d1fdd46368..6c33af482df4 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -274,8 +274,7 @@ int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata, | |||
274 | *pos++ = ifmsh->mesh_auth_id; | 274 | *pos++ = ifmsh->mesh_auth_id; |
275 | /* Mesh Formation Info - number of neighbors */ | 275 | /* Mesh Formation Info - number of neighbors */ |
276 | neighbors = atomic_read(&ifmsh->estab_plinks); | 276 | neighbors = atomic_read(&ifmsh->estab_plinks); |
277 | /* Number of neighbor mesh STAs or 15 whichever is smaller */ | 277 | neighbors = min_t(int, neighbors, IEEE80211_MAX_MESH_PEERINGS); |
278 | neighbors = (neighbors > 15) ? 15 : neighbors; | ||
279 | *pos++ = neighbors << 1; | 278 | *pos++ = neighbors << 1; |
280 | /* Mesh capability */ | 279 | /* Mesh capability */ |
281 | *pos = IEEE80211_MESHCONF_CAPAB_FORWARDING; | 280 | *pos = IEEE80211_MESHCONF_CAPAB_FORWARDING; |
@@ -576,13 +575,11 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata) | |||
576 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 575 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
577 | u32 changed; | 576 | u32 changed; |
578 | 577 | ||
579 | ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); | 578 | ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ); |
580 | mesh_path_expire(sdata); | 579 | mesh_path_expire(sdata); |
581 | 580 | ||
582 | changed = mesh_accept_plinks_update(sdata); | 581 | changed = mesh_accept_plinks_update(sdata); |
583 | sdata_lock(sdata); | ||
584 | ieee80211_mbss_info_change_notify(sdata, changed); | 582 | ieee80211_mbss_info_change_notify(sdata, changed); |
585 | sdata_unlock(sdata); | ||
586 | 583 | ||
587 | mod_timer(&ifmsh->housekeeping_timer, | 584 | mod_timer(&ifmsh->housekeeping_timer, |
588 | round_jiffies(jiffies + | 585 | round_jiffies(jiffies + |
@@ -741,9 +738,6 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
741 | BSS_CHANGED_HT | | 738 | BSS_CHANGED_HT | |
742 | BSS_CHANGED_BASIC_RATES | | 739 | BSS_CHANGED_BASIC_RATES | |
743 | BSS_CHANGED_BEACON_INT; | 740 | BSS_CHANGED_BEACON_INT; |
744 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | ||
745 | struct ieee80211_supported_band *sband = | ||
746 | sdata->local->hw.wiphy->bands[band]; | ||
747 | 741 | ||
748 | local->fif_other_bss++; | 742 | local->fif_other_bss++; |
749 | /* mesh ifaces must set allmulti to forward mcast traffic */ | 743 | /* mesh ifaces must set allmulti to forward mcast traffic */ |
@@ -761,7 +755,6 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
761 | sdata->vif.bss_conf.ht_operation_mode = | 755 | sdata->vif.bss_conf.ht_operation_mode = |
762 | ifmsh->mshcfg.ht_opmode; | 756 | ifmsh->mshcfg.ht_opmode; |
763 | sdata->vif.bss_conf.enable_beacon = true; | 757 | sdata->vif.bss_conf.enable_beacon = true; |
764 | sdata->vif.bss_conf.basic_rates = ieee80211_mandatory_rates(sband); | ||
765 | 758 | ||
766 | changed |= ieee80211_mps_local_status_update(sdata); | 759 | changed |= ieee80211_mps_local_status_update(sdata); |
767 | 760 | ||
@@ -789,12 +782,10 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | |||
789 | sdata->vif.bss_conf.enable_beacon = false; | 782 | sdata->vif.bss_conf.enable_beacon = false; |
790 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | 783 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); |
791 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | 784 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
792 | sdata_lock(sdata); | ||
793 | bcn = rcu_dereference_protected(ifmsh->beacon, | 785 | bcn = rcu_dereference_protected(ifmsh->beacon, |
794 | lockdep_is_held(&sdata->wdev.mtx)); | 786 | lockdep_is_held(&sdata->wdev.mtx)); |
795 | rcu_assign_pointer(ifmsh->beacon, NULL); | 787 | rcu_assign_pointer(ifmsh->beacon, NULL); |
796 | kfree_rcu(bcn, rcu_head); | 788 | kfree_rcu(bcn, rcu_head); |
797 | sdata_unlock(sdata); | ||
798 | 789 | ||
799 | /* flush STAs and mpaths on this iface */ | 790 | /* flush STAs and mpaths on this iface */ |
800 | sta_info_flush(sdata); | 791 | sta_info_flush(sdata); |
@@ -807,14 +798,6 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | |||
807 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); | 798 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); |
808 | del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); | 799 | del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); |
809 | del_timer_sync(&sdata->u.mesh.mesh_path_timer); | 800 | del_timer_sync(&sdata->u.mesh.mesh_path_timer); |
810 | /* | ||
811 | * If the timer fired while we waited for it, it will have | ||
812 | * requeued the work. Now the work will be running again | ||
813 | * but will not rearm the timer again because it checks | ||
814 | * whether the interface is running, which, at this point, | ||
815 | * it no longer is. | ||
816 | */ | ||
817 | cancel_work_sync(&sdata->work); | ||
818 | 801 | ||
819 | local->fif_other_bss--; | 802 | local->fif_other_bss--; |
820 | atomic_dec(&local->iff_allmultis); | 803 | atomic_dec(&local->iff_allmultis); |
@@ -955,6 +938,12 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
955 | struct ieee80211_mgmt *mgmt; | 938 | struct ieee80211_mgmt *mgmt; |
956 | u16 stype; | 939 | u16 stype; |
957 | 940 | ||
941 | sdata_lock(sdata); | ||
942 | |||
943 | /* mesh already went down */ | ||
944 | if (!sdata->wdev.mesh_id_len) | ||
945 | goto out; | ||
946 | |||
958 | rx_status = IEEE80211_SKB_RXCB(skb); | 947 | rx_status = IEEE80211_SKB_RXCB(skb); |
959 | mgmt = (struct ieee80211_mgmt *) skb->data; | 948 | mgmt = (struct ieee80211_mgmt *) skb->data; |
960 | stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; | 949 | stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; |
@@ -972,12 +961,20 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
972 | ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status); | 961 | ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status); |
973 | break; | 962 | break; |
974 | } | 963 | } |
964 | out: | ||
965 | sdata_unlock(sdata); | ||
975 | } | 966 | } |
976 | 967 | ||
977 | void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) | 968 | void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) |
978 | { | 969 | { |
979 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 970 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
980 | 971 | ||
972 | sdata_lock(sdata); | ||
973 | |||
974 | /* mesh already went down */ | ||
975 | if (!sdata->wdev.mesh_id_len) | ||
976 | goto out; | ||
977 | |||
981 | if (ifmsh->preq_queue_len && | 978 | if (ifmsh->preq_queue_len && |
982 | time_after(jiffies, | 979 | time_after(jiffies, |
983 | ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval))) | 980 | ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval))) |
@@ -997,6 +994,9 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) | |||
997 | 994 | ||
998 | if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags)) | 995 | if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags)) |
999 | mesh_sync_adjust_tbtt(sdata); | 996 | mesh_sync_adjust_tbtt(sdata); |
997 | |||
998 | out: | ||
999 | sdata_unlock(sdata); | ||
1000 | } | 1000 | } |
1001 | 1001 | ||
1002 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) | 1002 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index da158774eebb..01a28bca6e9b 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -188,7 +188,6 @@ struct mesh_rmc { | |||
188 | u32 idx_mask; | 188 | u32 idx_mask; |
189 | }; | 189 | }; |
190 | 190 | ||
191 | #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) | ||
192 | #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) | 191 | #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) |
193 | 192 | ||
194 | #define MESH_PATH_EXPIRE (600 * HZ) | 193 | #define MESH_PATH_EXPIRE (600 * HZ) |
@@ -324,14 +323,14 @@ static inline | |||
324 | u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) | 323 | u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) |
325 | { | 324 | { |
326 | atomic_inc(&sdata->u.mesh.estab_plinks); | 325 | atomic_inc(&sdata->u.mesh.estab_plinks); |
327 | return mesh_accept_plinks_update(sdata); | 326 | return mesh_accept_plinks_update(sdata) | BSS_CHANGED_BEACON; |
328 | } | 327 | } |
329 | 328 | ||
330 | static inline | 329 | static inline |
331 | u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) | 330 | u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) |
332 | { | 331 | { |
333 | atomic_dec(&sdata->u.mesh.estab_plinks); | 332 | atomic_dec(&sdata->u.mesh.estab_plinks); |
334 | return mesh_accept_plinks_update(sdata); | 333 | return mesh_accept_plinks_update(sdata) | BSS_CHANGED_BEACON; |
335 | } | 334 | } |
336 | 335 | ||
337 | static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata) | 336 | static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata) |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 6c4da99bc4fb..09bebed99416 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -517,9 +517,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, | |||
517 | ieee80211_mps_frame_release(sta, elems); | 517 | ieee80211_mps_frame_release(sta, elems); |
518 | out: | 518 | out: |
519 | rcu_read_unlock(); | 519 | rcu_read_unlock(); |
520 | sdata_lock(sdata); | ||
521 | ieee80211_mbss_info_change_notify(sdata, changed); | 520 | ieee80211_mbss_info_change_notify(sdata, changed); |
522 | sdata_unlock(sdata); | ||
523 | } | 521 | } |
524 | 522 | ||
525 | static void mesh_plink_timer(unsigned long data) | 523 | static void mesh_plink_timer(unsigned long data) |
@@ -1070,9 +1068,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
1070 | 1068 | ||
1071 | rcu_read_unlock(); | 1069 | rcu_read_unlock(); |
1072 | 1070 | ||
1073 | if (changed) { | 1071 | if (changed) |
1074 | sdata_lock(sdata); | ||
1075 | ieee80211_mbss_info_change_notify(sdata, changed); | 1072 | ieee80211_mbss_info_change_notify(sdata, changed); |
1076 | sdata_unlock(sdata); | ||
1077 | } | ||
1078 | } | 1073 | } |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f44f4caa69ee..ad9bb9e10cbb 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -880,6 +880,10 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
880 | 880 | ||
881 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | | 881 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | |
882 | IEEE80211_TX_INTFL_OFFCHAN_TX_OK; | 882 | IEEE80211_TX_INTFL_OFFCHAN_TX_OK; |
883 | |||
884 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | ||
885 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
886 | |||
883 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 887 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | |
884 | IEEE80211_STA_CONNECTION_POLL)) | 888 | IEEE80211_STA_CONNECTION_POLL)) |
885 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE; | 889 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE; |
@@ -1356,7 +1360,7 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata) | |||
1356 | IEEE80211_STA_CONNECTION_POLL)) | 1360 | IEEE80211_STA_CONNECTION_POLL)) |
1357 | return false; | 1361 | return false; |
1358 | 1362 | ||
1359 | if (!sdata->vif.bss_conf.dtim_period) | 1363 | if (!mgd->have_beacon) |
1360 | return false; | 1364 | return false; |
1361 | 1365 | ||
1362 | rcu_read_lock(); | 1366 | rcu_read_lock(); |
@@ -1767,7 +1771,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
1767 | 1771 | ||
1768 | ieee80211_led_assoc(local, 1); | 1772 | ieee80211_led_assoc(local, 1); |
1769 | 1773 | ||
1770 | if (sdata->u.mgd.assoc_data->have_beacon) { | 1774 | if (sdata->u.mgd.have_beacon) { |
1771 | /* | 1775 | /* |
1772 | * If the AP is buggy we may get here with no DTIM period | 1776 | * If the AP is buggy we may get here with no DTIM period |
1773 | * known, so assume it's 1 which is the only safe assumption | 1777 | * known, so assume it's 1 which is the only safe assumption |
@@ -1775,7 +1779,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
1775 | * probably just won't work at all. | 1779 | * probably just won't work at all. |
1776 | */ | 1780 | */ |
1777 | bss_conf->dtim_period = sdata->u.mgd.dtim_period ?: 1; | 1781 | bss_conf->dtim_period = sdata->u.mgd.dtim_period ?: 1; |
1778 | bss_info_changed |= BSS_CHANGED_DTIM_PERIOD; | 1782 | bss_info_changed |= BSS_CHANGED_BEACON_INFO; |
1779 | } else { | 1783 | } else { |
1780 | bss_conf->dtim_period = 0; | 1784 | bss_conf->dtim_period = 0; |
1781 | } | 1785 | } |
@@ -1899,6 +1903,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1899 | del_timer_sync(&sdata->u.mgd.chswitch_timer); | 1903 | del_timer_sync(&sdata->u.mgd.chswitch_timer); |
1900 | 1904 | ||
1901 | sdata->vif.bss_conf.dtim_period = 0; | 1905 | sdata->vif.bss_conf.dtim_period = 0; |
1906 | ifmgd->have_beacon = false; | ||
1902 | 1907 | ||
1903 | ifmgd->flags = 0; | 1908 | ifmgd->flags = 0; |
1904 | ieee80211_vif_release_channel(sdata); | 1909 | ieee80211_vif_release_channel(sdata); |
@@ -2151,7 +2156,8 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2151 | IEEE80211_MAX_QUEUE_MAP, | 2156 | IEEE80211_MAX_QUEUE_MAP, |
2152 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2157 | IEEE80211_QUEUE_STOP_REASON_CSA); |
2153 | 2158 | ||
2154 | cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); | 2159 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, |
2160 | IEEE80211_DEAUTH_FRAME_LEN); | ||
2155 | sdata_unlock(sdata); | 2161 | sdata_unlock(sdata); |
2156 | } | 2162 | } |
2157 | 2163 | ||
@@ -2298,7 +2304,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
2298 | sdata_info(sdata, "%pM denied authentication (status %d)\n", | 2304 | sdata_info(sdata, "%pM denied authentication (status %d)\n", |
2299 | mgmt->sa, status_code); | 2305 | mgmt->sa, status_code); |
2300 | ieee80211_destroy_auth_data(sdata, false); | 2306 | ieee80211_destroy_auth_data(sdata, false); |
2301 | cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, len); | 2307 | cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); |
2302 | return; | 2308 | return; |
2303 | } | 2309 | } |
2304 | 2310 | ||
@@ -2333,7 +2339,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
2333 | * Report auth frame to user space for processing since another | 2339 | * Report auth frame to user space for processing since another |
2334 | * round of Authentication frames is still needed. | 2340 | * round of Authentication frames is still needed. |
2335 | */ | 2341 | */ |
2336 | cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, len); | 2342 | cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); |
2337 | return; | 2343 | return; |
2338 | } | 2344 | } |
2339 | 2345 | ||
@@ -2350,7 +2356,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
2350 | } | 2356 | } |
2351 | mutex_unlock(&sdata->local->sta_mtx); | 2357 | mutex_unlock(&sdata->local->sta_mtx); |
2352 | 2358 | ||
2353 | cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, len); | 2359 | cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); |
2354 | return; | 2360 | return; |
2355 | out_err: | 2361 | out_err: |
2356 | mutex_unlock(&sdata->local->sta_mtx); | 2362 | mutex_unlock(&sdata->local->sta_mtx); |
@@ -2383,7 +2389,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
2383 | 2389 | ||
2384 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); | 2390 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); |
2385 | 2391 | ||
2386 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, len); | 2392 | cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); |
2387 | } | 2393 | } |
2388 | 2394 | ||
2389 | 2395 | ||
@@ -2409,7 +2415,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2409 | 2415 | ||
2410 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); | 2416 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); |
2411 | 2417 | ||
2412 | cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, len); | 2418 | cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); |
2413 | } | 2419 | } |
2414 | 2420 | ||
2415 | static void ieee80211_get_rates(struct ieee80211_supported_band *sband, | 2421 | static void ieee80211_get_rates(struct ieee80211_supported_band *sband, |
@@ -2707,7 +2713,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
2707 | /* oops -- internal error -- send timeout for now */ | 2713 | /* oops -- internal error -- send timeout for now */ |
2708 | ieee80211_destroy_assoc_data(sdata, false); | 2714 | ieee80211_destroy_assoc_data(sdata, false); |
2709 | cfg80211_put_bss(sdata->local->hw.wiphy, bss); | 2715 | cfg80211_put_bss(sdata->local->hw.wiphy, bss); |
2710 | cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid); | 2716 | cfg80211_assoc_timeout(sdata->dev, mgmt->bssid); |
2711 | return; | 2717 | return; |
2712 | } | 2718 | } |
2713 | sdata_info(sdata, "associated\n"); | 2719 | sdata_info(sdata, "associated\n"); |
@@ -2720,7 +2726,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
2720 | ieee80211_destroy_assoc_data(sdata, true); | 2726 | ieee80211_destroy_assoc_data(sdata, true); |
2721 | } | 2727 | } |
2722 | 2728 | ||
2723 | cfg80211_send_rx_assoc(sdata->dev, bss, (u8 *)mgmt, len); | 2729 | cfg80211_rx_assoc_resp(sdata->dev, bss, (u8 *)mgmt, len); |
2724 | } | 2730 | } |
2725 | 2731 | ||
2726 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 2732 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
@@ -2732,24 +2738,9 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2732 | int freq; | 2738 | int freq; |
2733 | struct ieee80211_bss *bss; | 2739 | struct ieee80211_bss *bss; |
2734 | struct ieee80211_channel *channel; | 2740 | struct ieee80211_channel *channel; |
2735 | bool need_ps = false; | ||
2736 | 2741 | ||
2737 | sdata_assert_lock(sdata); | 2742 | sdata_assert_lock(sdata); |
2738 | 2743 | ||
2739 | if ((sdata->u.mgd.associated && | ||
2740 | ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) || | ||
2741 | (sdata->u.mgd.assoc_data && | ||
2742 | ether_addr_equal(mgmt->bssid, | ||
2743 | sdata->u.mgd.assoc_data->bss->bssid))) { | ||
2744 | /* not previously set so we may need to recalc */ | ||
2745 | need_ps = sdata->u.mgd.associated && !sdata->u.mgd.dtim_period; | ||
2746 | |||
2747 | if (elems->tim && !elems->parse_error) { | ||
2748 | const struct ieee80211_tim_ie *tim_ie = elems->tim; | ||
2749 | sdata->u.mgd.dtim_period = tim_ie->dtim_period; | ||
2750 | } | ||
2751 | } | ||
2752 | |||
2753 | if (elems->ds_params) | 2744 | if (elems->ds_params) |
2754 | freq = ieee80211_channel_to_frequency(elems->ds_params[0], | 2745 | freq = ieee80211_channel_to_frequency(elems->ds_params[0], |
2755 | rx_status->band); | 2746 | rx_status->band); |
@@ -2770,12 +2761,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2770 | !ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) | 2761 | !ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) |
2771 | return; | 2762 | return; |
2772 | 2763 | ||
2773 | if (need_ps) { | ||
2774 | mutex_lock(&local->iflist_mtx); | ||
2775 | ieee80211_recalc_ps(local, -1); | ||
2776 | mutex_unlock(&local->iflist_mtx); | ||
2777 | } | ||
2778 | |||
2779 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, | 2764 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, |
2780 | elems, true); | 2765 | elems, true); |
2781 | 2766 | ||
@@ -2889,7 +2874,11 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2889 | len - baselen, false, &elems); | 2874 | len - baselen, false, &elems); |
2890 | 2875 | ||
2891 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); | 2876 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); |
2892 | ifmgd->assoc_data->have_beacon = true; | 2877 | if (elems.tim && !elems.parse_error) { |
2878 | const struct ieee80211_tim_ie *tim_ie = elems.tim; | ||
2879 | ifmgd->dtim_period = tim_ie->dtim_period; | ||
2880 | } | ||
2881 | ifmgd->have_beacon = true; | ||
2893 | ifmgd->assoc_data->need_beacon = false; | 2882 | ifmgd->assoc_data->need_beacon = false; |
2894 | if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) { | 2883 | if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) { |
2895 | sdata->vif.bss_conf.sync_tsf = | 2884 | sdata->vif.bss_conf.sync_tsf = |
@@ -3071,7 +3060,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3071 | * If we haven't had a beacon before, tell the driver about the | 3060 | * If we haven't had a beacon before, tell the driver about the |
3072 | * DTIM period (and beacon timing if desired) now. | 3061 | * DTIM period (and beacon timing if desired) now. |
3073 | */ | 3062 | */ |
3074 | if (!bss_conf->dtim_period) { | 3063 | if (!ifmgd->have_beacon) { |
3075 | /* a few bogus AP send dtim_period = 0 or no TIM IE */ | 3064 | /* a few bogus AP send dtim_period = 0 or no TIM IE */ |
3076 | if (elems.tim) | 3065 | if (elems.tim) |
3077 | bss_conf->dtim_period = elems.tim->dtim_period ?: 1; | 3066 | bss_conf->dtim_period = elems.tim->dtim_period ?: 1; |
@@ -3090,7 +3079,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3090 | sdata->vif.bss_conf.sync_dtim_count = 0; | 3079 | sdata->vif.bss_conf.sync_dtim_count = 0; |
3091 | } | 3080 | } |
3092 | 3081 | ||
3093 | changed |= BSS_CHANGED_DTIM_PERIOD; | 3082 | changed |= BSS_CHANGED_BEACON_INFO; |
3083 | ifmgd->have_beacon = true; | ||
3084 | |||
3085 | mutex_lock(&local->iflist_mtx); | ||
3086 | ieee80211_recalc_ps(local, -1); | ||
3087 | mutex_unlock(&local->iflist_mtx); | ||
3088 | |||
3094 | ieee80211_recalc_ps_vif(sdata); | 3089 | ieee80211_recalc_ps_vif(sdata); |
3095 | } | 3090 | } |
3096 | 3091 | ||
@@ -3113,8 +3108,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3113 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 3108 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
3114 | WLAN_REASON_DEAUTH_LEAVING, | 3109 | WLAN_REASON_DEAUTH_LEAVING, |
3115 | true, deauth_buf); | 3110 | true, deauth_buf); |
3116 | cfg80211_send_deauth(sdata->dev, deauth_buf, | 3111 | cfg80211_tx_mlme_mgmt(sdata->dev, deauth_buf, |
3117 | sizeof(deauth_buf)); | 3112 | sizeof(deauth_buf)); |
3118 | return; | 3113 | return; |
3119 | } | 3114 | } |
3120 | 3115 | ||
@@ -3232,7 +3227,8 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
3232 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, | 3227 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, |
3233 | tx, frame_buf); | 3228 | tx, frame_buf); |
3234 | 3229 | ||
3235 | cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); | 3230 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, |
3231 | IEEE80211_DEAUTH_FRAME_LEN); | ||
3236 | } | 3232 | } |
3237 | 3233 | ||
3238 | static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | 3234 | static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) |
@@ -3423,15 +3419,14 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3423 | 3419 | ||
3424 | ieee80211_destroy_auth_data(sdata, false); | 3420 | ieee80211_destroy_auth_data(sdata, false); |
3425 | 3421 | ||
3426 | cfg80211_send_auth_timeout(sdata->dev, bssid); | 3422 | cfg80211_auth_timeout(sdata->dev, bssid); |
3427 | } | 3423 | } |
3428 | } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started) | 3424 | } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started) |
3429 | run_again(sdata, ifmgd->auth_data->timeout); | 3425 | run_again(sdata, ifmgd->auth_data->timeout); |
3430 | 3426 | ||
3431 | if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started && | 3427 | if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started && |
3432 | time_after(jiffies, ifmgd->assoc_data->timeout)) { | 3428 | time_after(jiffies, ifmgd->assoc_data->timeout)) { |
3433 | if ((ifmgd->assoc_data->need_beacon && | 3429 | if ((ifmgd->assoc_data->need_beacon && !ifmgd->have_beacon) || |
3434 | !ifmgd->assoc_data->have_beacon) || | ||
3435 | ieee80211_do_assoc(sdata)) { | 3430 | ieee80211_do_assoc(sdata)) { |
3436 | u8 bssid[ETH_ALEN]; | 3431 | u8 bssid[ETH_ALEN]; |
3437 | 3432 | ||
@@ -3439,7 +3434,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3439 | 3434 | ||
3440 | ieee80211_destroy_assoc_data(sdata, false); | 3435 | ieee80211_destroy_assoc_data(sdata, false); |
3441 | 3436 | ||
3442 | cfg80211_send_assoc_timeout(sdata->dev, bssid); | 3437 | cfg80211_assoc_timeout(sdata->dev, bssid); |
3443 | } | 3438 | } |
3444 | } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) | 3439 | } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) |
3445 | run_again(sdata, ifmgd->assoc_data->timeout); | 3440 | run_again(sdata, ifmgd->assoc_data->timeout); |
@@ -3988,8 +3983,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
3988 | WLAN_REASON_UNSPECIFIED, | 3983 | WLAN_REASON_UNSPECIFIED, |
3989 | false, frame_buf); | 3984 | false, frame_buf); |
3990 | 3985 | ||
3991 | cfg80211_send_deauth(sdata->dev, frame_buf, | 3986 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, |
3992 | sizeof(frame_buf)); | 3987 | sizeof(frame_buf)); |
3993 | } | 3988 | } |
3994 | 3989 | ||
3995 | sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); | 3990 | sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); |
@@ -4051,8 +4046,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4051 | WLAN_REASON_UNSPECIFIED, | 4046 | WLAN_REASON_UNSPECIFIED, |
4052 | false, frame_buf); | 4047 | false, frame_buf); |
4053 | 4048 | ||
4054 | cfg80211_send_deauth(sdata->dev, frame_buf, | 4049 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, |
4055 | sizeof(frame_buf)); | 4050 | sizeof(frame_buf)); |
4056 | } | 4051 | } |
4057 | 4052 | ||
4058 | if (ifmgd->auth_data && !ifmgd->auth_data->done) { | 4053 | if (ifmgd->auth_data && !ifmgd->auth_data->done) { |
@@ -4199,6 +4194,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4199 | 4194 | ||
4200 | ifmgd->assoc_data = assoc_data; | 4195 | ifmgd->assoc_data = assoc_data; |
4201 | ifmgd->dtim_period = 0; | 4196 | ifmgd->dtim_period = 0; |
4197 | ifmgd->have_beacon = false; | ||
4202 | 4198 | ||
4203 | err = ieee80211_prep_connection(sdata, req->bss, true); | 4199 | err = ieee80211_prep_connection(sdata, req->bss, true); |
4204 | if (err) | 4200 | if (err) |
@@ -4230,7 +4226,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4230 | ifmgd->dtim_period = tim->dtim_period; | 4226 | ifmgd->dtim_period = tim->dtim_period; |
4231 | dtim_count = tim->dtim_count; | 4227 | dtim_count = tim->dtim_count; |
4232 | } | 4228 | } |
4233 | assoc_data->have_beacon = true; | 4229 | ifmgd->have_beacon = true; |
4234 | assoc_data->timeout = jiffies; | 4230 | assoc_data->timeout = jiffies; |
4235 | assoc_data->timeout_started = true; | 4231 | assoc_data->timeout_started = true; |
4236 | 4232 | ||
@@ -4305,8 +4301,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
4305 | 4301 | ||
4306 | out: | 4302 | out: |
4307 | if (report_frame) | 4303 | if (report_frame) |
4308 | cfg80211_send_deauth(sdata->dev, frame_buf, | 4304 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, |
4309 | IEEE80211_DEAUTH_FRAME_LEN); | 4305 | IEEE80211_DEAUTH_FRAME_LEN); |
4310 | 4306 | ||
4311 | return 0; | 4307 | return 0; |
4312 | } | 4308 | } |
@@ -4336,8 +4332,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
4336 | req->reason_code, !req->local_state_change, | 4332 | req->reason_code, !req->local_state_change, |
4337 | frame_buf); | 4333 | frame_buf); |
4338 | 4334 | ||
4339 | cfg80211_send_disassoc(sdata->dev, frame_buf, | 4335 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, |
4340 | IEEE80211_DEAUTH_FRAME_LEN); | 4336 | IEEE80211_DEAUTH_FRAME_LEN); |
4341 | 4337 | ||
4342 | return 0; | 4338 | return 0; |
4343 | } | 4339 | } |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index bdd7b4a719e9..23dbcfc69b3b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1747,27 +1747,21 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) | |||
1747 | if (unlikely(!ieee80211_has_protected(fc) && | 1747 | if (unlikely(!ieee80211_has_protected(fc) && |
1748 | ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && | 1748 | ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && |
1749 | rx->key)) { | 1749 | rx->key)) { |
1750 | if (ieee80211_is_deauth(fc)) | 1750 | if (ieee80211_is_deauth(fc) || |
1751 | cfg80211_send_unprot_deauth(rx->sdata->dev, | 1751 | ieee80211_is_disassoc(fc)) |
1752 | rx->skb->data, | 1752 | cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, |
1753 | rx->skb->len); | 1753 | rx->skb->data, |
1754 | else if (ieee80211_is_disassoc(fc)) | 1754 | rx->skb->len); |
1755 | cfg80211_send_unprot_disassoc(rx->sdata->dev, | ||
1756 | rx->skb->data, | ||
1757 | rx->skb->len); | ||
1758 | return -EACCES; | 1755 | return -EACCES; |
1759 | } | 1756 | } |
1760 | /* BIP does not use Protected field, so need to check MMIE */ | 1757 | /* BIP does not use Protected field, so need to check MMIE */ |
1761 | if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) && | 1758 | if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) && |
1762 | ieee80211_get_mmie_keyidx(rx->skb) < 0)) { | 1759 | ieee80211_get_mmie_keyidx(rx->skb) < 0)) { |
1763 | if (ieee80211_is_deauth(fc)) | 1760 | if (ieee80211_is_deauth(fc) || |
1764 | cfg80211_send_unprot_deauth(rx->sdata->dev, | 1761 | ieee80211_is_disassoc(fc)) |
1765 | rx->skb->data, | 1762 | cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, |
1766 | rx->skb->len); | 1763 | rx->skb->data, |
1767 | else if (ieee80211_is_disassoc(fc)) | 1764 | rx->skb->len); |
1768 | cfg80211_send_unprot_disassoc(rx->sdata->dev, | ||
1769 | rx->skb->data, | ||
1770 | rx->skb->len); | ||
1771 | return -EACCES; | 1765 | return -EACCES; |
1772 | } | 1766 | } |
1773 | /* | 1767 | /* |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a04c5671d7fd..b4297982d34a 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -1132,6 +1132,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | |||
1132 | * ends the poll/service period. | 1132 | * ends the poll/service period. |
1133 | */ | 1133 | */ |
1134 | info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER | | 1134 | info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER | |
1135 | IEEE80211_TX_CTL_PS_RESPONSE | | ||
1135 | IEEE80211_TX_STATUS_EOSP | | 1136 | IEEE80211_TX_STATUS_EOSP | |
1136 | IEEE80211_TX_CTL_REQ_TX_STATUS; | 1137 | IEEE80211_TX_CTL_REQ_TX_STATUS; |
1137 | 1138 | ||
@@ -1269,7 +1270,8 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, | |||
1269 | * STA may still remain is PS mode after this frame | 1270 | * STA may still remain is PS mode after this frame |
1270 | * exchange. | 1271 | * exchange. |
1271 | */ | 1272 | */ |
1272 | info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; | 1273 | info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER | |
1274 | IEEE80211_TX_CTL_PS_RESPONSE; | ||
1273 | 1275 | ||
1274 | /* | 1276 | /* |
1275 | * Use MoreData flag to indicate whether there are | 1277 | * Use MoreData flag to indicate whether there are |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 41c28b977f7c..bd12fc54266c 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -297,6 +297,9 @@ struct sta_ampdu_mlme { | |||
297 | * @rcu_head: RCU head used for freeing this station struct | 297 | * @rcu_head: RCU head used for freeing this station struct |
298 | * @cur_max_bandwidth: maximum bandwidth to use for TX to the station, | 298 | * @cur_max_bandwidth: maximum bandwidth to use for TX to the station, |
299 | * taken from HT/VHT capabilities or VHT operating mode notification | 299 | * taken from HT/VHT capabilities or VHT operating mode notification |
300 | * @chains: chains ever used for RX from this station | ||
301 | * @chain_signal_last: last signal (per chain) | ||
302 | * @chain_signal_avg: signal average (per chain) | ||
300 | */ | 303 | */ |
301 | struct sta_info { | 304 | struct sta_info { |
302 | /* General information, mostly static */ | 305 | /* General information, mostly static */ |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 34be9336b5d1..4105d0ca963e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1790,12 +1790,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1790 | break; | 1790 | break; |
1791 | #ifdef CONFIG_MAC80211_MESH | 1791 | #ifdef CONFIG_MAC80211_MESH |
1792 | case NL80211_IFTYPE_MESH_POINT: | 1792 | case NL80211_IFTYPE_MESH_POINT: |
1793 | if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { | ||
1794 | /* Do not send frames with mesh_ttl == 0 */ | ||
1795 | sdata->u.mesh.mshstats.dropped_frames_ttl++; | ||
1796 | goto fail_rcu; | ||
1797 | } | ||
1798 | |||
1799 | if (!is_multicast_ether_addr(skb->data)) { | 1793 | if (!is_multicast_ether_addr(skb->data)) { |
1800 | struct sta_info *next_hop; | 1794 | struct sta_info *next_hop; |
1801 | bool mpp_lookup = true; | 1795 | bool mpp_lookup = true; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 89a83770d152..5a6c1351d1d3 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1584,8 +1584,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1584 | BSS_CHANGED_ARP_FILTER | | 1584 | BSS_CHANGED_ARP_FILTER | |
1585 | BSS_CHANGED_PS; | 1585 | BSS_CHANGED_PS; |
1586 | 1586 | ||
1587 | if (sdata->u.mgd.dtim_period) | 1587 | /* Re-send beacon info report to the driver */ |
1588 | changed |= BSS_CHANGED_DTIM_PERIOD; | 1588 | if (sdata->u.mgd.have_beacon) |
1589 | changed |= BSS_CHANGED_BEACON_INFO; | ||
1589 | 1590 | ||
1590 | sdata_lock(sdata); | 1591 | sdata_lock(sdata); |
1591 | ieee80211_bss_info_change_notify(sdata, changed); | 1592 | ieee80211_bss_info_change_notify(sdata, changed); |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 41cec1776f4f..4224e7554a76 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -301,6 +301,9 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
301 | return NULL; | 301 | return NULL; |
302 | } | 302 | } |
303 | 303 | ||
304 | /* atomic_inc_return makes it start at 1, make it start at 0 */ | ||
305 | rdev->wiphy_idx--; | ||
306 | |||
304 | /* give it a proper name */ | 307 | /* give it a proper name */ |
305 | dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); | 308 | dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); |
306 | 309 | ||
@@ -449,8 +452,13 @@ int wiphy_register(struct wiphy *wiphy) | |||
449 | u16 ifmodes = wiphy->interface_modes; | 452 | u16 ifmodes = wiphy->interface_modes; |
450 | 453 | ||
451 | #ifdef CONFIG_PM | 454 | #ifdef CONFIG_PM |
452 | if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && | 455 | if (WARN_ON(wiphy->wowlan && |
453 | !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) | 456 | (wiphy->wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && |
457 | !(wiphy->wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) | ||
458 | return -EINVAL; | ||
459 | if (WARN_ON(wiphy->wowlan && | ||
460 | !wiphy->wowlan->flags && !wiphy->wowlan->n_patterns && | ||
461 | !wiphy->wowlan->tcp)) | ||
454 | return -EINVAL; | 462 | return -EINVAL; |
455 | #endif | 463 | #endif |
456 | 464 | ||
@@ -540,25 +548,28 @@ int wiphy_register(struct wiphy *wiphy) | |||
540 | } | 548 | } |
541 | 549 | ||
542 | #ifdef CONFIG_PM | 550 | #ifdef CONFIG_PM |
543 | if (rdev->wiphy.wowlan.n_patterns) { | 551 | if (WARN_ON(rdev->wiphy.wowlan && rdev->wiphy.wowlan->n_patterns && |
544 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || | 552 | (!rdev->wiphy.wowlan->pattern_min_len || |
545 | rdev->wiphy.wowlan.pattern_min_len > | 553 | rdev->wiphy.wowlan->pattern_min_len > |
546 | rdev->wiphy.wowlan.pattern_max_len)) | 554 | rdev->wiphy.wowlan->pattern_max_len))) |
547 | return -EINVAL; | 555 | return -EINVAL; |
548 | } | ||
549 | #endif | 556 | #endif |
550 | 557 | ||
551 | /* check and set up bitrates */ | 558 | /* check and set up bitrates */ |
552 | ieee80211_set_bitrate_flags(wiphy); | 559 | ieee80211_set_bitrate_flags(wiphy); |
553 | 560 | ||
554 | rtnl_lock(); | ||
555 | 561 | ||
556 | res = device_add(&rdev->wiphy.dev); | 562 | res = device_add(&rdev->wiphy.dev); |
563 | if (res) | ||
564 | return res; | ||
565 | |||
566 | res = rfkill_register(rdev->rfkill); | ||
557 | if (res) { | 567 | if (res) { |
558 | rtnl_unlock(); | 568 | device_del(&rdev->wiphy.dev); |
559 | return res; | 569 | return res; |
560 | } | 570 | } |
561 | 571 | ||
572 | rtnl_lock(); | ||
562 | /* set up regulatory info */ | 573 | /* set up regulatory info */ |
563 | wiphy_regulatory_register(wiphy); | 574 | wiphy_regulatory_register(wiphy); |
564 | 575 | ||
@@ -585,17 +596,6 @@ int wiphy_register(struct wiphy *wiphy) | |||
585 | 596 | ||
586 | cfg80211_debugfs_rdev_add(rdev); | 597 | cfg80211_debugfs_rdev_add(rdev); |
587 | 598 | ||
588 | res = rfkill_register(rdev->rfkill); | ||
589 | if (res) { | ||
590 | device_del(&rdev->wiphy.dev); | ||
591 | |||
592 | debugfs_remove_recursive(rdev->wiphy.debugfsdir); | ||
593 | list_del_rcu(&rdev->list); | ||
594 | wiphy_regulatory_deregister(wiphy); | ||
595 | rtnl_unlock(); | ||
596 | return res; | ||
597 | } | ||
598 | |||
599 | rdev->wiphy.registered = true; | 599 | rdev->wiphy.registered = true; |
600 | rtnl_unlock(); | 600 | rtnl_unlock(); |
601 | return 0; | 601 | return 0; |
@@ -632,11 +632,11 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
632 | rtnl_unlock(); | 632 | rtnl_unlock(); |
633 | __count == 0; })); | 633 | __count == 0; })); |
634 | 634 | ||
635 | rfkill_unregister(rdev->rfkill); | ||
636 | |||
635 | rtnl_lock(); | 637 | rtnl_lock(); |
636 | rdev->wiphy.registered = false; | 638 | rdev->wiphy.registered = false; |
637 | 639 | ||
638 | rfkill_unregister(rdev->rfkill); | ||
639 | |||
640 | BUG_ON(!list_empty(&rdev->wdev_list)); | 640 | BUG_ON(!list_empty(&rdev->wdev_list)); |
641 | 641 | ||
642 | /* | 642 | /* |
@@ -817,7 +817,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
817 | pr_err("failed to add phy80211 symlink to netdev!\n"); | 817 | pr_err("failed to add phy80211 symlink to netdev!\n"); |
818 | } | 818 | } |
819 | wdev->netdev = dev; | 819 | wdev->netdev = dev; |
820 | wdev->sme_state = CFG80211_SME_IDLE; | ||
821 | #ifdef CONFIG_CFG80211_WEXT | 820 | #ifdef CONFIG_CFG80211_WEXT |
822 | wdev->wext.default_key = -1; | 821 | wdev->wext.default_key = -1; |
823 | wdev->wext.default_mgmt_key = -1; | 822 | wdev->wext.default_mgmt_key = -1; |
diff --git a/net/wireless/core.h b/net/wireless/core.h index a65eaf8a84c1..a6b45bf00f33 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -308,11 +308,6 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | |||
308 | bool local_state_change); | 308 | bool local_state_change); |
309 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | 309 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, |
310 | struct net_device *dev); | 310 | struct net_device *dev); |
311 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | ||
312 | const u8 *req_ie, size_t req_ie_len, | ||
313 | const u8 *resp_ie, size_t resp_ie_len, | ||
314 | u16 status, bool wextev, | ||
315 | struct cfg80211_bss *bss); | ||
316 | int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, | 311 | int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, |
317 | u16 frame_type, const u8 *match_data, | 312 | u16 frame_type, const u8 *match_data, |
318 | int match_len); | 313 | int match_len); |
@@ -328,12 +323,19 @@ void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | |||
328 | void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, | 323 | void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, |
329 | const struct ieee80211_vht_cap *vht_capa_mask); | 324 | const struct ieee80211_vht_cap *vht_capa_mask); |
330 | 325 | ||
331 | /* SME */ | 326 | /* SME events */ |
332 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 327 | int cfg80211_connect(struct cfg80211_registered_device *rdev, |
333 | struct net_device *dev, | 328 | struct net_device *dev, |
334 | struct cfg80211_connect_params *connect, | 329 | struct cfg80211_connect_params *connect, |
335 | struct cfg80211_cached_keys *connkeys, | 330 | struct cfg80211_cached_keys *connkeys, |
336 | const u8 *prev_bssid); | 331 | const u8 *prev_bssid); |
332 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | ||
333 | const u8 *req_ie, size_t req_ie_len, | ||
334 | const u8 *resp_ie, size_t resp_ie_len, | ||
335 | u16 status, bool wextev, | ||
336 | struct cfg80211_bss *bss); | ||
337 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | ||
338 | size_t ie_len, u16 reason, bool from_ap); | ||
337 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | 339 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, |
338 | struct net_device *dev, u16 reason, | 340 | struct net_device *dev, u16 reason, |
339 | bool wextev); | 341 | bool wextev); |
@@ -344,21 +346,21 @@ void __cfg80211_roamed(struct wireless_dev *wdev, | |||
344 | int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | 346 | int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, |
345 | struct wireless_dev *wdev); | 347 | struct wireless_dev *wdev); |
346 | 348 | ||
349 | /* SME implementation */ | ||
347 | void cfg80211_conn_work(struct work_struct *work); | 350 | void cfg80211_conn_work(struct work_struct *work); |
348 | void cfg80211_sme_failed_assoc(struct wireless_dev *wdev); | 351 | void cfg80211_sme_scan_done(struct net_device *dev); |
349 | bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); | 352 | bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status); |
353 | void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len); | ||
354 | void cfg80211_sme_disassoc(struct wireless_dev *wdev); | ||
355 | void cfg80211_sme_deauth(struct wireless_dev *wdev); | ||
356 | void cfg80211_sme_auth_timeout(struct wireless_dev *wdev); | ||
357 | void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev); | ||
350 | 358 | ||
351 | /* internal helpers */ | 359 | /* internal helpers */ |
352 | bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher); | 360 | bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher); |
353 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 361 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
354 | struct key_params *params, int key_idx, | 362 | struct key_params *params, int key_idx, |
355 | bool pairwise, const u8 *mac_addr); | 363 | bool pairwise, const u8 *mac_addr); |
356 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | ||
357 | size_t ie_len, u16 reason, bool from_ap); | ||
358 | void cfg80211_sme_scan_done(struct net_device *dev); | ||
359 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); | ||
360 | void cfg80211_sme_disassoc(struct net_device *dev, | ||
361 | struct cfg80211_internal_bss *bss); | ||
362 | void __cfg80211_scan_done(struct work_struct *wk); | 364 | void __cfg80211_scan_done(struct work_struct *wk); |
363 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); | 365 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); |
364 | void __cfg80211_sched_scan_results(struct work_struct *wk); | 366 | void __cfg80211_sched_scan_results(struct work_struct *wk); |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 5449c5a6de84..39bff7d36768 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -43,7 +43,6 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) | |||
43 | cfg80211_hold_bss(bss_from_pub(bss)); | 43 | cfg80211_hold_bss(bss_from_pub(bss)); |
44 | wdev->current_bss = bss_from_pub(bss); | 44 | wdev->current_bss = bss_from_pub(bss); |
45 | 45 | ||
46 | wdev->sme_state = CFG80211_SME_CONNECTED; | ||
47 | cfg80211_upload_connect_keys(wdev); | 46 | cfg80211_upload_connect_keys(wdev); |
48 | 47 | ||
49 | nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, | 48 | nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, |
@@ -64,8 +63,6 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) | |||
64 | 63 | ||
65 | trace_cfg80211_ibss_joined(dev, bssid); | 64 | trace_cfg80211_ibss_joined(dev, bssid); |
66 | 65 | ||
67 | CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING); | ||
68 | |||
69 | ev = kzalloc(sizeof(*ev), gfp); | 66 | ev = kzalloc(sizeof(*ev), gfp); |
70 | if (!ev) | 67 | if (!ev) |
71 | return; | 68 | return; |
@@ -120,7 +117,6 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
120 | #ifdef CONFIG_CFG80211_WEXT | 117 | #ifdef CONFIG_CFG80211_WEXT |
121 | wdev->wext.ibss.chandef = params->chandef; | 118 | wdev->wext.ibss.chandef = params->chandef; |
122 | #endif | 119 | #endif |
123 | wdev->sme_state = CFG80211_SME_CONNECTING; | ||
124 | 120 | ||
125 | err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan, | 121 | err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan, |
126 | params->channel_fixed | 122 | params->channel_fixed |
@@ -134,7 +130,6 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
134 | err = rdev_join_ibss(rdev, dev, params); | 130 | err = rdev_join_ibss(rdev, dev, params); |
135 | if (err) { | 131 | if (err) { |
136 | wdev->connect_keys = NULL; | 132 | wdev->connect_keys = NULL; |
137 | wdev->sme_state = CFG80211_SME_IDLE; | ||
138 | return err; | 133 | return err; |
139 | } | 134 | } |
140 | 135 | ||
@@ -186,7 +181,6 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) | |||
186 | } | 181 | } |
187 | 182 | ||
188 | wdev->current_bss = NULL; | 183 | wdev->current_bss = NULL; |
189 | wdev->sme_state = CFG80211_SME_IDLE; | ||
190 | wdev->ssid_len = 0; | 184 | wdev->ssid_len = 0; |
191 | #ifdef CONFIG_CFG80211_WEXT | 185 | #ifdef CONFIG_CFG80211_WEXT |
192 | if (!nowext) | 186 | if (!nowext) |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 5dfb289ab761..30c49202ee4d 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #define MESH_PATH_TO_ROOT_TIMEOUT 6000 | 18 | #define MESH_PATH_TO_ROOT_TIMEOUT 6000 |
19 | #define MESH_ROOT_INTERVAL 5000 | 19 | #define MESH_ROOT_INTERVAL 5000 |
20 | #define MESH_ROOT_CONFIRMATION_INTERVAL 2000 | 20 | #define MESH_ROOT_CONFIRMATION_INTERVAL 2000 |
21 | #define MESH_DEFAULT_PLINK_TIMEOUT 1800 /* timeout in seconds */ | ||
21 | 22 | ||
22 | /* | 23 | /* |
23 | * Minimum interval between two consecutive PREQs originated by the same | 24 | * Minimum interval between two consecutive PREQs originated by the same |
@@ -75,6 +76,7 @@ const struct mesh_config default_mesh_config = { | |||
75 | .dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL, | 76 | .dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL, |
76 | .power_mode = NL80211_MESH_POWER_ACTIVE, | 77 | .power_mode = NL80211_MESH_POWER_ACTIVE, |
77 | .dot11MeshAwakeWindowDuration = MESH_DEFAULT_AWAKE_WINDOW, | 78 | .dot11MeshAwakeWindowDuration = MESH_DEFAULT_AWAKE_WINDOW, |
79 | .plink_timeout = MESH_DEFAULT_PLINK_TIMEOUT, | ||
78 | }; | 80 | }; |
79 | 81 | ||
80 | const struct mesh_setup default_mesh_setup = { | 82 | const struct mesh_setup default_mesh_setup = { |
@@ -160,6 +162,16 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
160 | setup->chandef.center_freq1 = setup->chandef.chan->center_freq; | 162 | setup->chandef.center_freq1 = setup->chandef.chan->center_freq; |
161 | } | 163 | } |
162 | 164 | ||
165 | /* | ||
166 | * check if basic rates are available otherwise use mandatory rates as | ||
167 | * basic rates | ||
168 | */ | ||
169 | if (!setup->basic_rates) { | ||
170 | struct ieee80211_supported_band *sband = | ||
171 | rdev->wiphy.bands[setup->chandef.chan->band]; | ||
172 | setup->basic_rates = ieee80211_mandatory_rates(sband); | ||
173 | } | ||
174 | |||
163 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef)) | 175 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef)) |
164 | return -EINVAL; | 176 | return -EINVAL; |
165 | 177 | ||
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 7bde5d9c0003..a61a44bc6cf0 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -18,150 +18,107 @@ | |||
18 | #include "rdev-ops.h" | 18 | #include "rdev-ops.h" |
19 | 19 | ||
20 | 20 | ||
21 | void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) | 21 | void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, |
22 | { | ||
23 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
24 | struct wiphy *wiphy = wdev->wiphy; | ||
25 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
26 | |||
27 | trace_cfg80211_send_rx_auth(dev); | ||
28 | |||
29 | nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); | ||
30 | cfg80211_sme_rx_auth(dev, buf, len); | ||
31 | } | ||
32 | EXPORT_SYMBOL(cfg80211_send_rx_auth); | ||
33 | |||
34 | void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss, | ||
35 | const u8 *buf, size_t len) | 22 | const u8 *buf, size_t len) |
36 | { | 23 | { |
37 | u16 status_code; | ||
38 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 24 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
39 | struct wiphy *wiphy = wdev->wiphy; | 25 | struct wiphy *wiphy = wdev->wiphy; |
40 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 26 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
41 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 27 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
42 | u8 *ie = mgmt->u.assoc_resp.variable; | 28 | u8 *ie = mgmt->u.assoc_resp.variable; |
43 | int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); | 29 | int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); |
30 | u16 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | ||
44 | 31 | ||
45 | trace_cfg80211_send_rx_assoc(dev, bss); | 32 | trace_cfg80211_send_rx_assoc(dev, bss); |
46 | 33 | ||
47 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | ||
48 | |||
49 | /* | 34 | /* |
50 | * This is a bit of a hack, we don't notify userspace of | 35 | * This is a bit of a hack, we don't notify userspace of |
51 | * a (re-)association reply if we tried to send a reassoc | 36 | * a (re-)association reply if we tried to send a reassoc |
52 | * and got a reject -- we only try again with an assoc | 37 | * and got a reject -- we only try again with an assoc |
53 | * frame instead of reassoc. | 38 | * frame instead of reassoc. |
54 | */ | 39 | */ |
55 | if (status_code != WLAN_STATUS_SUCCESS && wdev->conn && | 40 | if (cfg80211_sme_rx_assoc_resp(wdev, status_code)) { |
56 | cfg80211_sme_failed_reassoc(wdev)) { | ||
57 | cfg80211_put_bss(wiphy, bss); | 41 | cfg80211_put_bss(wiphy, bss); |
58 | return; | 42 | return; |
59 | } | 43 | } |
60 | 44 | ||
61 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); | 45 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); |
62 | 46 | /* update current_bss etc., consumes the bss reference */ | |
63 | if (status_code != WLAN_STATUS_SUCCESS && wdev->conn) { | ||
64 | cfg80211_sme_failed_assoc(wdev); | ||
65 | /* | ||
66 | * do not call connect_result() now because the | ||
67 | * sme will schedule work that does it later. | ||
68 | */ | ||
69 | cfg80211_put_bss(wiphy, bss); | ||
70 | return; | ||
71 | } | ||
72 | |||
73 | if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) { | ||
74 | /* | ||
75 | * This is for the userspace SME, the CONNECTING | ||
76 | * state will be changed to CONNECTED by | ||
77 | * __cfg80211_connect_result() below. | ||
78 | */ | ||
79 | wdev->sme_state = CFG80211_SME_CONNECTING; | ||
80 | } | ||
81 | |||
82 | /* this consumes the bss reference */ | ||
83 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, | 47 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, |
84 | status_code, | 48 | status_code, |
85 | status_code == WLAN_STATUS_SUCCESS, bss); | 49 | status_code == WLAN_STATUS_SUCCESS, bss); |
86 | } | 50 | } |
87 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); | 51 | EXPORT_SYMBOL(cfg80211_rx_assoc_resp); |
88 | 52 | ||
89 | void cfg80211_send_deauth(struct net_device *dev, | 53 | static void cfg80211_process_auth(struct wireless_dev *wdev, |
90 | const u8 *buf, size_t len) | 54 | const u8 *buf, size_t len) |
91 | { | 55 | { |
92 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 56 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
93 | struct wiphy *wiphy = wdev->wiphy; | 57 | |
94 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 58 | nl80211_send_rx_auth(rdev, wdev->netdev, buf, len, GFP_KERNEL); |
59 | cfg80211_sme_rx_auth(wdev, buf, len); | ||
60 | } | ||
61 | |||
62 | static void cfg80211_process_deauth(struct wireless_dev *wdev, | ||
63 | const u8 *buf, size_t len) | ||
64 | { | ||
65 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
95 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 66 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
96 | const u8 *bssid = mgmt->bssid; | 67 | const u8 *bssid = mgmt->bssid; |
97 | bool was_current = false; | 68 | u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
69 | bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr); | ||
98 | 70 | ||
99 | trace_cfg80211_send_deauth(dev); | 71 | nl80211_send_deauth(rdev, wdev->netdev, buf, len, GFP_KERNEL); |
100 | ASSERT_WDEV_LOCK(wdev); | ||
101 | 72 | ||
102 | if (wdev->current_bss && | 73 | if (!wdev->current_bss || |
103 | ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) { | 74 | !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) |
104 | cfg80211_unhold_bss(wdev->current_bss); | 75 | return; |
105 | cfg80211_put_bss(wiphy, &wdev->current_bss->pub); | 76 | |
106 | wdev->current_bss = NULL; | 77 | __cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap); |
107 | was_current = true; | 78 | cfg80211_sme_deauth(wdev); |
108 | } | 79 | } |
109 | 80 | ||
110 | nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); | 81 | static void cfg80211_process_disassoc(struct wireless_dev *wdev, |
82 | const u8 *buf, size_t len) | ||
83 | { | ||
84 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
85 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | ||
86 | const u8 *bssid = mgmt->bssid; | ||
87 | u16 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | ||
88 | bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr); | ||
111 | 89 | ||
112 | if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) { | 90 | nl80211_send_disassoc(rdev, wdev->netdev, buf, len, GFP_KERNEL); |
113 | u16 reason_code; | ||
114 | bool from_ap; | ||
115 | 91 | ||
116 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); | 92 | if (WARN_ON(!wdev->current_bss || |
93 | !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) | ||
94 | return; | ||
117 | 95 | ||
118 | from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr); | 96 | __cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap); |
119 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); | 97 | cfg80211_sme_disassoc(wdev); |
120 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { | ||
121 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, | ||
122 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
123 | false, NULL); | ||
124 | } | ||
125 | } | 98 | } |
126 | EXPORT_SYMBOL(cfg80211_send_deauth); | ||
127 | 99 | ||
128 | void cfg80211_send_disassoc(struct net_device *dev, | 100 | void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len) |
129 | const u8 *buf, size_t len) | ||
130 | { | 101 | { |
131 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 102 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
132 | struct wiphy *wiphy = wdev->wiphy; | 103 | struct ieee80211_mgmt *mgmt = (void *)buf; |
133 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
134 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | ||
135 | const u8 *bssid = mgmt->bssid; | ||
136 | u16 reason_code; | ||
137 | bool from_ap; | ||
138 | 104 | ||
139 | trace_cfg80211_send_disassoc(dev); | ||
140 | ASSERT_WDEV_LOCK(wdev); | 105 | ASSERT_WDEV_LOCK(wdev); |
141 | 106 | ||
142 | nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL); | 107 | trace_cfg80211_rx_mlme_mgmt(dev, buf, len); |
143 | 108 | ||
144 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | 109 | if (WARN_ON(len < 2)) |
145 | return; | 110 | return; |
146 | 111 | ||
147 | if (wdev->current_bss && | 112 | if (ieee80211_is_auth(mgmt->frame_control)) |
148 | ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) { | 113 | cfg80211_process_auth(wdev, buf, len); |
149 | cfg80211_sme_disassoc(dev, wdev->current_bss); | 114 | else if (ieee80211_is_deauth(mgmt->frame_control)) |
150 | cfg80211_unhold_bss(wdev->current_bss); | 115 | cfg80211_process_deauth(wdev, buf, len); |
151 | cfg80211_put_bss(wiphy, &wdev->current_bss->pub); | 116 | else if (ieee80211_is_disassoc(mgmt->frame_control)) |
152 | wdev->current_bss = NULL; | 117 | cfg80211_process_disassoc(wdev, buf, len); |
153 | } else | ||
154 | WARN_ON(1); | ||
155 | |||
156 | |||
157 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | ||
158 | |||
159 | from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr); | ||
160 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); | ||
161 | } | 118 | } |
162 | EXPORT_SYMBOL(cfg80211_send_disassoc); | 119 | EXPORT_SYMBOL(cfg80211_rx_mlme_mgmt); |
163 | 120 | ||
164 | void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) | 121 | void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr) |
165 | { | 122 | { |
166 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 123 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
167 | struct wiphy *wiphy = wdev->wiphy; | 124 | struct wiphy *wiphy = wdev->wiphy; |
@@ -170,14 +127,11 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) | |||
170 | trace_cfg80211_send_auth_timeout(dev, addr); | 127 | trace_cfg80211_send_auth_timeout(dev, addr); |
171 | 128 | ||
172 | nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); | 129 | nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); |
173 | if (wdev->sme_state == CFG80211_SME_CONNECTING) | 130 | cfg80211_sme_auth_timeout(wdev); |
174 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | ||
175 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
176 | false, NULL); | ||
177 | } | 131 | } |
178 | EXPORT_SYMBOL(cfg80211_send_auth_timeout); | 132 | EXPORT_SYMBOL(cfg80211_auth_timeout); |
179 | 133 | ||
180 | void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) | 134 | void cfg80211_assoc_timeout(struct net_device *dev, const u8 *addr) |
181 | { | 135 | { |
182 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 136 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
183 | struct wiphy *wiphy = wdev->wiphy; | 137 | struct wiphy *wiphy = wdev->wiphy; |
@@ -186,12 +140,28 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) | |||
186 | trace_cfg80211_send_assoc_timeout(dev, addr); | 140 | trace_cfg80211_send_assoc_timeout(dev, addr); |
187 | 141 | ||
188 | nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); | 142 | nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); |
189 | if (wdev->sme_state == CFG80211_SME_CONNECTING) | 143 | cfg80211_sme_assoc_timeout(wdev); |
190 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | ||
191 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
192 | false, NULL); | ||
193 | } | 144 | } |
194 | EXPORT_SYMBOL(cfg80211_send_assoc_timeout); | 145 | EXPORT_SYMBOL(cfg80211_assoc_timeout); |
146 | |||
147 | void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len) | ||
148 | { | ||
149 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
150 | struct ieee80211_mgmt *mgmt = (void *)buf; | ||
151 | |||
152 | ASSERT_WDEV_LOCK(wdev); | ||
153 | |||
154 | trace_cfg80211_tx_mlme_mgmt(dev, buf, len); | ||
155 | |||
156 | if (WARN_ON(len < 2)) | ||
157 | return; | ||
158 | |||
159 | if (ieee80211_is_deauth(mgmt->frame_control)) | ||
160 | cfg80211_process_deauth(wdev, buf, len); | ||
161 | else | ||
162 | cfg80211_process_disassoc(wdev, buf, len); | ||
163 | } | ||
164 | EXPORT_SYMBOL(cfg80211_tx_mlme_mgmt); | ||
195 | 165 | ||
196 | void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, | 166 | void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, |
197 | enum nl80211_key_type key_type, int key_id, | 167 | enum nl80211_key_type key_type, int key_id, |
@@ -314,21 +284,12 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
314 | { | 284 | { |
315 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 285 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
316 | int err; | 286 | int err; |
317 | bool was_connected = false; | ||
318 | 287 | ||
319 | ASSERT_WDEV_LOCK(wdev); | 288 | ASSERT_WDEV_LOCK(wdev); |
320 | 289 | ||
321 | if (wdev->current_bss && req->prev_bssid && | 290 | if (wdev->current_bss && |
322 | ether_addr_equal(wdev->current_bss->pub.bssid, req->prev_bssid)) { | 291 | (!req->prev_bssid || !ether_addr_equal(wdev->current_bss->pub.bssid, |
323 | /* | 292 | req->prev_bssid))) |
324 | * Trying to reassociate: Allow this to proceed and let the old | ||
325 | * association to be dropped when the new one is completed. | ||
326 | */ | ||
327 | if (wdev->sme_state == CFG80211_SME_CONNECTED) { | ||
328 | was_connected = true; | ||
329 | wdev->sme_state = CFG80211_SME_CONNECTING; | ||
330 | } | ||
331 | } else if (wdev->current_bss) | ||
332 | return -EALREADY; | 293 | return -EALREADY; |
333 | 294 | ||
334 | cfg80211_oper_and_ht_capa(&req->ht_capa_mask, | 295 | cfg80211_oper_and_ht_capa(&req->ht_capa_mask, |
@@ -338,11 +299,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
338 | 299 | ||
339 | req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, | 300 | req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, |
340 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | 301 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); |
341 | if (!req->bss) { | 302 | if (!req->bss) |
342 | if (was_connected) | ||
343 | wdev->sme_state = CFG80211_SME_CONNECTED; | ||
344 | return -ENOENT; | 303 | return -ENOENT; |
345 | } | ||
346 | 304 | ||
347 | err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED); | 305 | err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED); |
348 | if (err) | 306 | if (err) |
@@ -351,11 +309,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
351 | err = rdev_assoc(rdev, dev, req); | 309 | err = rdev_assoc(rdev, dev, req); |
352 | 310 | ||
353 | out: | 311 | out: |
354 | if (err) { | 312 | if (err) |
355 | if (was_connected) | ||
356 | wdev->sme_state = CFG80211_SME_CONNECTED; | ||
357 | cfg80211_put_bss(&rdev->wiphy, req->bss); | 313 | cfg80211_put_bss(&rdev->wiphy, req->bss); |
358 | } | ||
359 | 314 | ||
360 | return err; | 315 | return err; |
361 | } | 316 | } |
@@ -376,8 +331,9 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | |||
376 | 331 | ||
377 | ASSERT_WDEV_LOCK(wdev); | 332 | ASSERT_WDEV_LOCK(wdev); |
378 | 333 | ||
379 | if (local_state_change && (!wdev->current_bss || | 334 | if (local_state_change && |
380 | !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) | 335 | (!wdev->current_bss || |
336 | !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) | ||
381 | return 0; | 337 | return 0; |
382 | 338 | ||
383 | return rdev_deauth(rdev, dev, &req); | 339 | return rdev_deauth(rdev, dev, &req); |
@@ -395,13 +351,11 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | |||
395 | .ie = ie, | 351 | .ie = ie, |
396 | .ie_len = ie_len, | 352 | .ie_len = ie_len, |
397 | }; | 353 | }; |
354 | int err; | ||
398 | 355 | ||
399 | ASSERT_WDEV_LOCK(wdev); | 356 | ASSERT_WDEV_LOCK(wdev); |
400 | 357 | ||
401 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | 358 | if (!wdev->current_bss) |
402 | return -ENOTCONN; | ||
403 | |||
404 | if (WARN(!wdev->current_bss, "sme_state=%d\n", wdev->sme_state)) | ||
405 | return -ENOTCONN; | 359 | return -ENOTCONN; |
406 | 360 | ||
407 | if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) | 361 | if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) |
@@ -409,7 +363,13 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | |||
409 | else | 363 | else |
410 | return -ENOTCONN; | 364 | return -ENOTCONN; |
411 | 365 | ||
412 | return rdev_disassoc(rdev, dev, &req); | 366 | err = rdev_disassoc(rdev, dev, &req); |
367 | if (err) | ||
368 | return err; | ||
369 | |||
370 | /* driver should have reported the disassoc */ | ||
371 | WARN_ON(wdev->current_bss); | ||
372 | return 0; | ||
413 | } | 373 | } |
414 | 374 | ||
415 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | 375 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, |
@@ -417,10 +377,6 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |||
417 | { | 377 | { |
418 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 378 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
419 | u8 bssid[ETH_ALEN]; | 379 | u8 bssid[ETH_ALEN]; |
420 | struct cfg80211_deauth_request req = { | ||
421 | .reason_code = WLAN_REASON_DEAUTH_LEAVING, | ||
422 | .bssid = bssid, | ||
423 | }; | ||
424 | 380 | ||
425 | ASSERT_WDEV_LOCK(wdev); | 381 | ASSERT_WDEV_LOCK(wdev); |
426 | 382 | ||
@@ -431,13 +387,8 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |||
431 | return; | 387 | return; |
432 | 388 | ||
433 | memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); | 389 | memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); |
434 | rdev_deauth(rdev, dev, &req); | 390 | cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, |
435 | 391 | WLAN_REASON_DEAUTH_LEAVING, false); | |
436 | if (wdev->current_bss) { | ||
437 | cfg80211_unhold_bss(wdev->current_bss); | ||
438 | cfg80211_put_bss(&rdev->wiphy, &wdev->current_bss->pub); | ||
439 | wdev->current_bss = NULL; | ||
440 | } | ||
441 | } | 392 | } |
442 | 393 | ||
443 | struct cfg80211_mgmt_registration { | 394 | struct cfg80211_mgmt_registration { |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 31d265f36d2c..e4028197b75d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -800,12 +800,9 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
800 | case NL80211_IFTYPE_MESH_POINT: | 800 | case NL80211_IFTYPE_MESH_POINT: |
801 | break; | 801 | break; |
802 | case NL80211_IFTYPE_ADHOC: | 802 | case NL80211_IFTYPE_ADHOC: |
803 | if (!wdev->current_bss) | ||
804 | return -ENOLINK; | ||
805 | break; | ||
806 | case NL80211_IFTYPE_STATION: | 803 | case NL80211_IFTYPE_STATION: |
807 | case NL80211_IFTYPE_P2P_CLIENT: | 804 | case NL80211_IFTYPE_P2P_CLIENT: |
808 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | 805 | if (!wdev->current_bss) |
809 | return -ENOLINK; | 806 | return -ENOLINK; |
810 | break; | 807 | break; |
811 | default: | 808 | default: |
@@ -908,7 +905,7 @@ nla_put_failure: | |||
908 | static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev, | 905 | static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev, |
909 | struct sk_buff *msg) | 906 | struct sk_buff *msg) |
910 | { | 907 | { |
911 | const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan.tcp; | 908 | const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan->tcp; |
912 | struct nlattr *nl_tcp; | 909 | struct nlattr *nl_tcp; |
913 | 910 | ||
914 | if (!tcp) | 911 | if (!tcp) |
@@ -951,37 +948,37 @@ static int nl80211_send_wowlan(struct sk_buff *msg, | |||
951 | { | 948 | { |
952 | struct nlattr *nl_wowlan; | 949 | struct nlattr *nl_wowlan; |
953 | 950 | ||
954 | if (!dev->wiphy.wowlan.flags && !dev->wiphy.wowlan.n_patterns) | 951 | if (!dev->wiphy.wowlan) |
955 | return 0; | 952 | return 0; |
956 | 953 | ||
957 | nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED); | 954 | nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED); |
958 | if (!nl_wowlan) | 955 | if (!nl_wowlan) |
959 | return -ENOBUFS; | 956 | return -ENOBUFS; |
960 | 957 | ||
961 | if (((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) && | 958 | if (((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) && |
962 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) || | 959 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) || |
963 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) && | 960 | ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) && |
964 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) || | 961 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) || |
965 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) && | 962 | ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) && |
966 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) || | 963 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) || |
967 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) && | 964 | ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) && |
968 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) || | 965 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) || |
969 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && | 966 | ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && |
970 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) || | 967 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) || |
971 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) && | 968 | ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) && |
972 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) || | 969 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) || |
973 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) && | 970 | ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) && |
974 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) || | 971 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) || |
975 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) && | 972 | ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) && |
976 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) | 973 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) |
977 | return -ENOBUFS; | 974 | return -ENOBUFS; |
978 | 975 | ||
979 | if (dev->wiphy.wowlan.n_patterns) { | 976 | if (dev->wiphy.wowlan->n_patterns) { |
980 | struct nl80211_wowlan_pattern_support pat = { | 977 | struct nl80211_wowlan_pattern_support pat = { |
981 | .max_patterns = dev->wiphy.wowlan.n_patterns, | 978 | .max_patterns = dev->wiphy.wowlan->n_patterns, |
982 | .min_pattern_len = dev->wiphy.wowlan.pattern_min_len, | 979 | .min_pattern_len = dev->wiphy.wowlan->pattern_min_len, |
983 | .max_pattern_len = dev->wiphy.wowlan.pattern_max_len, | 980 | .max_pattern_len = dev->wiphy.wowlan->pattern_max_len, |
984 | .max_pkt_offset = dev->wiphy.wowlan.max_pkt_offset, | 981 | .max_pkt_offset = dev->wiphy.wowlan->max_pkt_offset, |
985 | }; | 982 | }; |
986 | 983 | ||
987 | if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, | 984 | if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, |
@@ -1544,8 +1541,10 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
1544 | int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); | 1541 | int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); |
1545 | 1542 | ||
1546 | netdev = dev_get_by_index(sock_net(skb->sk), ifidx); | 1543 | netdev = dev_get_by_index(sock_net(skb->sk), ifidx); |
1547 | if (!netdev) | 1544 | if (!netdev) { |
1545 | rtnl_unlock(); | ||
1548 | return -ENODEV; | 1546 | return -ENODEV; |
1547 | } | ||
1549 | if (netdev->ieee80211_ptr) { | 1548 | if (netdev->ieee80211_ptr) { |
1550 | dev = wiphy_to_dev( | 1549 | dev = wiphy_to_dev( |
1551 | netdev->ieee80211_ptr->wiphy); | 1550 | netdev->ieee80211_ptr->wiphy); |
@@ -1589,6 +1588,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
1589 | !skb->len && | 1588 | !skb->len && |
1590 | cb->min_dump_alloc < 4096) { | 1589 | cb->min_dump_alloc < 4096) { |
1591 | cb->min_dump_alloc = 4096; | 1590 | cb->min_dump_alloc = 4096; |
1591 | rtnl_unlock(); | ||
1592 | return 1; | 1592 | return 1; |
1593 | } | 1593 | } |
1594 | idx--; | 1594 | idx--; |
@@ -3975,10 +3975,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3975 | params.listen_interval = | 3975 | params.listen_interval = |
3976 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); | 3976 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); |
3977 | 3977 | ||
3978 | if (info->attrs[NL80211_ATTR_STA_AID]) | 3978 | if (info->attrs[NL80211_ATTR_PEER_AID]) |
3979 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); | ||
3980 | else | ||
3981 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]); | 3979 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]); |
3980 | else | ||
3981 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); | ||
3982 | if (!params.aid || params.aid > IEEE80211_MAX_AID) | 3982 | if (!params.aid || params.aid > IEEE80211_MAX_AID) |
3983 | return -EINVAL; | 3983 | return -EINVAL; |
3984 | 3984 | ||
@@ -4030,7 +4030,8 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
4030 | params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD; | 4030 | params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD; |
4031 | 4031 | ||
4032 | /* TDLS peers cannot be added */ | 4032 | /* TDLS peers cannot be added */ |
4033 | if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) | 4033 | if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) || |
4034 | info->attrs[NL80211_ATTR_PEER_AID]) | ||
4034 | return -EINVAL; | 4035 | return -EINVAL; |
4035 | /* but don't bother the driver with it */ | 4036 | /* but don't bother the driver with it */ |
4036 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | 4037 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); |
@@ -4056,7 +4057,8 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
4056 | if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) | 4057 | if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) |
4057 | return -EINVAL; | 4058 | return -EINVAL; |
4058 | /* TDLS peers cannot be added */ | 4059 | /* TDLS peers cannot be added */ |
4059 | if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) | 4060 | if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) || |
4061 | info->attrs[NL80211_ATTR_PEER_AID]) | ||
4060 | return -EINVAL; | 4062 | return -EINVAL; |
4061 | break; | 4063 | break; |
4062 | case NL80211_IFTYPE_STATION: | 4064 | case NL80211_IFTYPE_STATION: |
@@ -4578,7 +4580,9 @@ static int nl80211_get_mesh_config(struct sk_buff *skb, | |||
4578 | nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE, | 4580 | nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE, |
4579 | cur_params.power_mode) || | 4581 | cur_params.power_mode) || |
4580 | nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW, | 4582 | nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW, |
4581 | cur_params.dot11MeshAwakeWindowDuration)) | 4583 | cur_params.dot11MeshAwakeWindowDuration) || |
4584 | nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT, | ||
4585 | cur_params.plink_timeout)) | ||
4582 | goto nla_put_failure; | 4586 | goto nla_put_failure; |
4583 | nla_nest_end(msg, pinfoattr); | 4587 | nla_nest_end(msg, pinfoattr); |
4584 | genlmsg_end(msg, hdr); | 4588 | genlmsg_end(msg, hdr); |
@@ -4619,6 +4623,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A | |||
4619 | [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 }, | 4623 | [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 }, |
4620 | [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 }, | 4624 | [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 }, |
4621 | [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 }, | 4625 | [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 }, |
4626 | [NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 }, | ||
4622 | }; | 4627 | }; |
4623 | 4628 | ||
4624 | static const struct nla_policy | 4629 | static const struct nla_policy |
@@ -4756,6 +4761,9 @@ do { \ | |||
4756 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration, | 4761 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration, |
4757 | 0, 65535, mask, | 4762 | 0, 65535, mask, |
4758 | NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16); | 4763 | NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16); |
4764 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 1, 0xffffffff, | ||
4765 | mask, NL80211_MESHCONF_PLINK_TIMEOUT, | ||
4766 | nla_get_u32); | ||
4759 | if (mask_out) | 4767 | if (mask_out) |
4760 | *mask_out = mask; | 4768 | *mask_out = mask; |
4761 | 4769 | ||
@@ -7142,6 +7150,9 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
7142 | return -EOPNOTSUPP; | 7150 | return -EOPNOTSUPP; |
7143 | 7151 | ||
7144 | switch (wdev->iftype) { | 7152 | switch (wdev->iftype) { |
7153 | case NL80211_IFTYPE_P2P_DEVICE: | ||
7154 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) | ||
7155 | return -EINVAL; | ||
7145 | case NL80211_IFTYPE_STATION: | 7156 | case NL80211_IFTYPE_STATION: |
7146 | case NL80211_IFTYPE_ADHOC: | 7157 | case NL80211_IFTYPE_ADHOC: |
7147 | case NL80211_IFTYPE_P2P_CLIENT: | 7158 | case NL80211_IFTYPE_P2P_CLIENT: |
@@ -7149,7 +7160,6 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
7149 | case NL80211_IFTYPE_AP_VLAN: | 7160 | case NL80211_IFTYPE_AP_VLAN: |
7150 | case NL80211_IFTYPE_MESH_POINT: | 7161 | case NL80211_IFTYPE_MESH_POINT: |
7151 | case NL80211_IFTYPE_P2P_GO: | 7162 | case NL80211_IFTYPE_P2P_GO: |
7152 | case NL80211_IFTYPE_P2P_DEVICE: | ||
7153 | break; | 7163 | break; |
7154 | default: | 7164 | default: |
7155 | return -EOPNOTSUPP; | 7165 | return -EOPNOTSUPP; |
@@ -7177,9 +7187,18 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
7177 | 7187 | ||
7178 | no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); | 7188 | no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); |
7179 | 7189 | ||
7180 | err = nl80211_parse_chandef(rdev, info, &chandef); | 7190 | /* get the channel if any has been specified, otherwise pass NULL to |
7181 | if (err) | 7191 | * the driver. The latter will use the current one |
7182 | return err; | 7192 | */ |
7193 | chandef.chan = NULL; | ||
7194 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
7195 | err = nl80211_parse_chandef(rdev, info, &chandef); | ||
7196 | if (err) | ||
7197 | return err; | ||
7198 | } | ||
7199 | |||
7200 | if (!chandef.chan && offchan) | ||
7201 | return -EINVAL; | ||
7183 | 7202 | ||
7184 | if (!dont_wait_for_ack) { | 7203 | if (!dont_wait_for_ack) { |
7185 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 7204 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
@@ -7484,6 +7503,23 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) | |||
7484 | setup.chandef.chan = NULL; | 7503 | setup.chandef.chan = NULL; |
7485 | } | 7504 | } |
7486 | 7505 | ||
7506 | if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { | ||
7507 | u8 *rates = nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | ||
7508 | int n_rates = | ||
7509 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | ||
7510 | struct ieee80211_supported_band *sband; | ||
7511 | |||
7512 | if (!setup.chandef.chan) | ||
7513 | return -EINVAL; | ||
7514 | |||
7515 | sband = rdev->wiphy.bands[setup.chandef.chan->band]; | ||
7516 | |||
7517 | err = ieee80211_get_ratemask(sband, rates, n_rates, | ||
7518 | &setup.basic_rates); | ||
7519 | if (err) | ||
7520 | return err; | ||
7521 | } | ||
7522 | |||
7487 | return cfg80211_join_mesh(rdev, dev, &setup, &cfg); | 7523 | return cfg80211_join_mesh(rdev, dev, &setup, &cfg); |
7488 | } | 7524 | } |
7489 | 7525 | ||
@@ -7580,8 +7616,7 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7580 | void *hdr; | 7616 | void *hdr; |
7581 | u32 size = NLMSG_DEFAULT_SIZE; | 7617 | u32 size = NLMSG_DEFAULT_SIZE; |
7582 | 7618 | ||
7583 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns && | 7619 | if (!rdev->wiphy.wowlan) |
7584 | !rdev->wiphy.wowlan.tcp) | ||
7585 | return -EOPNOTSUPP; | 7620 | return -EOPNOTSUPP; |
7586 | 7621 | ||
7587 | if (rdev->wiphy.wowlan_config && rdev->wiphy.wowlan_config->tcp) { | 7622 | if (rdev->wiphy.wowlan_config && rdev->wiphy.wowlan_config->tcp) { |
@@ -7654,7 +7689,7 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev, | |||
7654 | u32 data_size, wake_size, tokens_size = 0, wake_mask_size; | 7689 | u32 data_size, wake_size, tokens_size = 0, wake_mask_size; |
7655 | int err, port; | 7690 | int err, port; |
7656 | 7691 | ||
7657 | if (!rdev->wiphy.wowlan.tcp) | 7692 | if (!rdev->wiphy.wowlan->tcp) |
7658 | return -EINVAL; | 7693 | return -EINVAL; |
7659 | 7694 | ||
7660 | err = nla_parse(tb, MAX_NL80211_WOWLAN_TCP, | 7695 | err = nla_parse(tb, MAX_NL80211_WOWLAN_TCP, |
@@ -7674,16 +7709,16 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev, | |||
7674 | return -EINVAL; | 7709 | return -EINVAL; |
7675 | 7710 | ||
7676 | data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]); | 7711 | data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]); |
7677 | if (data_size > rdev->wiphy.wowlan.tcp->data_payload_max) | 7712 | if (data_size > rdev->wiphy.wowlan->tcp->data_payload_max) |
7678 | return -EINVAL; | 7713 | return -EINVAL; |
7679 | 7714 | ||
7680 | if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) > | 7715 | if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) > |
7681 | rdev->wiphy.wowlan.tcp->data_interval_max || | 7716 | rdev->wiphy.wowlan->tcp->data_interval_max || |
7682 | nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0) | 7717 | nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0) |
7683 | return -EINVAL; | 7718 | return -EINVAL; |
7684 | 7719 | ||
7685 | wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]); | 7720 | wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]); |
7686 | if (wake_size > rdev->wiphy.wowlan.tcp->wake_payload_max) | 7721 | if (wake_size > rdev->wiphy.wowlan->tcp->wake_payload_max) |
7687 | return -EINVAL; | 7722 | return -EINVAL; |
7688 | 7723 | ||
7689 | wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]); | 7724 | wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]); |
@@ -7698,13 +7733,13 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev, | |||
7698 | 7733 | ||
7699 | if (!tok->len || tokens_size % tok->len) | 7734 | if (!tok->len || tokens_size % tok->len) |
7700 | return -EINVAL; | 7735 | return -EINVAL; |
7701 | if (!rdev->wiphy.wowlan.tcp->tok) | 7736 | if (!rdev->wiphy.wowlan->tcp->tok) |
7702 | return -EINVAL; | 7737 | return -EINVAL; |
7703 | if (tok->len > rdev->wiphy.wowlan.tcp->tok->max_len) | 7738 | if (tok->len > rdev->wiphy.wowlan->tcp->tok->max_len) |
7704 | return -EINVAL; | 7739 | return -EINVAL; |
7705 | if (tok->len < rdev->wiphy.wowlan.tcp->tok->min_len) | 7740 | if (tok->len < rdev->wiphy.wowlan->tcp->tok->min_len) |
7706 | return -EINVAL; | 7741 | return -EINVAL; |
7707 | if (tokens_size > rdev->wiphy.wowlan.tcp->tok->bufsize) | 7742 | if (tokens_size > rdev->wiphy.wowlan->tcp->tok->bufsize) |
7708 | return -EINVAL; | 7743 | return -EINVAL; |
7709 | if (tok->offset + tok->len > data_size) | 7744 | if (tok->offset + tok->len > data_size) |
7710 | return -EINVAL; | 7745 | return -EINVAL; |
@@ -7712,7 +7747,7 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev, | |||
7712 | 7747 | ||
7713 | if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) { | 7748 | if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) { |
7714 | seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]); | 7749 | seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]); |
7715 | if (!rdev->wiphy.wowlan.tcp->seq) | 7750 | if (!rdev->wiphy.wowlan->tcp->seq) |
7716 | return -EINVAL; | 7751 | return -EINVAL; |
7717 | if (seq->len == 0 || seq->len > 4) | 7752 | if (seq->len == 0 || seq->len > 4) |
7718 | return -EINVAL; | 7753 | return -EINVAL; |
@@ -7793,12 +7828,11 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7793 | struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG]; | 7828 | struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG]; |
7794 | struct cfg80211_wowlan new_triggers = {}; | 7829 | struct cfg80211_wowlan new_triggers = {}; |
7795 | struct cfg80211_wowlan *ntrig; | 7830 | struct cfg80211_wowlan *ntrig; |
7796 | struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; | 7831 | const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan; |
7797 | int err, i; | 7832 | int err, i; |
7798 | bool prev_enabled = rdev->wiphy.wowlan_config; | 7833 | bool prev_enabled = rdev->wiphy.wowlan_config; |
7799 | 7834 | ||
7800 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns && | 7835 | if (!wowlan) |
7801 | !rdev->wiphy.wowlan.tcp) | ||
7802 | return -EOPNOTSUPP; | 7836 | return -EOPNOTSUPP; |
7803 | 7837 | ||
7804 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { | 7838 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { |
@@ -9315,31 +9349,27 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, | |||
9315 | NL80211_CMD_DISASSOCIATE, gfp); | 9349 | NL80211_CMD_DISASSOCIATE, gfp); |
9316 | } | 9350 | } |
9317 | 9351 | ||
9318 | void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf, | 9352 | void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf, |
9319 | size_t len) | 9353 | size_t len) |
9320 | { | 9354 | { |
9321 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 9355 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
9322 | struct wiphy *wiphy = wdev->wiphy; | 9356 | struct wiphy *wiphy = wdev->wiphy; |
9323 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 9357 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
9358 | const struct ieee80211_mgmt *mgmt = (void *)buf; | ||
9359 | u32 cmd; | ||
9324 | 9360 | ||
9325 | trace_cfg80211_send_unprot_deauth(dev); | 9361 | if (WARN_ON(len < 2)) |
9326 | nl80211_send_mlme_event(rdev, dev, buf, len, | 9362 | return; |
9327 | NL80211_CMD_UNPROT_DEAUTHENTICATE, GFP_ATOMIC); | ||
9328 | } | ||
9329 | EXPORT_SYMBOL(cfg80211_send_unprot_deauth); | ||
9330 | 9363 | ||
9331 | void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf, | 9364 | if (ieee80211_is_deauth(mgmt->frame_control)) |
9332 | size_t len) | 9365 | cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE; |
9333 | { | 9366 | else |
9334 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 9367 | cmd = NL80211_CMD_UNPROT_DISASSOCIATE; |
9335 | struct wiphy *wiphy = wdev->wiphy; | ||
9336 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9337 | 9368 | ||
9338 | trace_cfg80211_send_unprot_disassoc(dev); | 9369 | trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len); |
9339 | nl80211_send_mlme_event(rdev, dev, buf, len, | 9370 | nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC); |
9340 | NL80211_CMD_UNPROT_DISASSOCIATE, GFP_ATOMIC); | ||
9341 | } | 9371 | } |
9342 | EXPORT_SYMBOL(cfg80211_send_unprot_disassoc); | 9372 | EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt); |
9343 | 9373 | ||
9344 | static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, | 9374 | static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, |
9345 | struct net_device *netdev, int cmd, | 9375 | struct net_device *netdev, int cmd, |
@@ -9850,7 +9880,6 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, | |||
9850 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 9880 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
9851 | struct sk_buff *msg; | 9881 | struct sk_buff *msg; |
9852 | void *hdr; | 9882 | void *hdr; |
9853 | int err; | ||
9854 | u32 nlportid = ACCESS_ONCE(wdev->ap_unexpected_nlportid); | 9883 | u32 nlportid = ACCESS_ONCE(wdev->ap_unexpected_nlportid); |
9855 | 9884 | ||
9856 | if (!nlportid) | 9885 | if (!nlportid) |
@@ -9871,12 +9900,7 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, | |||
9871 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) | 9900 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) |
9872 | goto nla_put_failure; | 9901 | goto nla_put_failure; |
9873 | 9902 | ||
9874 | err = genlmsg_end(msg, hdr); | 9903 | genlmsg_end(msg, hdr); |
9875 | if (err < 0) { | ||
9876 | nlmsg_free(msg); | ||
9877 | return true; | ||
9878 | } | ||
9879 | |||
9880 | genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid); | 9904 | genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid); |
9881 | return true; | 9905 | return true; |
9882 | 9906 | ||
@@ -10319,10 +10343,7 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev, | |||
10319 | if (nl80211_send_chandef(msg, chandef)) | 10343 | if (nl80211_send_chandef(msg, chandef)) |
10320 | goto nla_put_failure; | 10344 | goto nla_put_failure; |
10321 | 10345 | ||
10322 | if (genlmsg_end(msg, hdr) < 0) { | 10346 | genlmsg_end(msg, hdr); |
10323 | nlmsg_free(msg); | ||
10324 | return; | ||
10325 | } | ||
10326 | 10347 | ||
10327 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 10348 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
10328 | nl80211_mlme_mcgrp.id, gfp); | 10349 | nl80211_mlme_mcgrp.id, gfp); |
@@ -10388,7 +10409,6 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, | |||
10388 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 10409 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
10389 | struct sk_buff *msg; | 10410 | struct sk_buff *msg; |
10390 | void *hdr; | 10411 | void *hdr; |
10391 | int err; | ||
10392 | 10412 | ||
10393 | trace_cfg80211_probe_status(dev, addr, cookie, acked); | 10413 | trace_cfg80211_probe_status(dev, addr, cookie, acked); |
10394 | 10414 | ||
@@ -10410,11 +10430,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, | |||
10410 | (acked && nla_put_flag(msg, NL80211_ATTR_ACK))) | 10430 | (acked && nla_put_flag(msg, NL80211_ATTR_ACK))) |
10411 | goto nla_put_failure; | 10431 | goto nla_put_failure; |
10412 | 10432 | ||
10413 | err = genlmsg_end(msg, hdr); | 10433 | genlmsg_end(msg, hdr); |
10414 | if (err < 0) { | ||
10415 | nlmsg_free(msg); | ||
10416 | return; | ||
10417 | } | ||
10418 | 10434 | ||
10419 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 10435 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
10420 | nl80211_mlme_mcgrp.id, gfp); | 10436 | nl80211_mlme_mcgrp.id, gfp); |
@@ -10480,7 +10496,7 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, | |||
10480 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 10496 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
10481 | struct sk_buff *msg; | 10497 | struct sk_buff *msg; |
10482 | void *hdr; | 10498 | void *hdr; |
10483 | int err, size = 200; | 10499 | int size = 200; |
10484 | 10500 | ||
10485 | trace_cfg80211_report_wowlan_wakeup(wdev->wiphy, wdev, wakeup); | 10501 | trace_cfg80211_report_wowlan_wakeup(wdev->wiphy, wdev, wakeup); |
10486 | 10502 | ||
@@ -10566,9 +10582,7 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, | |||
10566 | nla_nest_end(msg, reasons); | 10582 | nla_nest_end(msg, reasons); |
10567 | } | 10583 | } |
10568 | 10584 | ||
10569 | err = genlmsg_end(msg, hdr); | 10585 | genlmsg_end(msg, hdr); |
10570 | if (err < 0) | ||
10571 | goto free_msg; | ||
10572 | 10586 | ||
10573 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 10587 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
10574 | nl80211_mlme_mcgrp.id, gfp); | 10588 | nl80211_mlme_mcgrp.id, gfp); |
@@ -10588,7 +10602,6 @@ void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer, | |||
10588 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 10602 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
10589 | struct sk_buff *msg; | 10603 | struct sk_buff *msg; |
10590 | void *hdr; | 10604 | void *hdr; |
10591 | int err; | ||
10592 | 10605 | ||
10593 | trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper, | 10606 | trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper, |
10594 | reason_code); | 10607 | reason_code); |
@@ -10611,11 +10624,7 @@ void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer, | |||
10611 | nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code))) | 10624 | nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code))) |
10612 | goto nla_put_failure; | 10625 | goto nla_put_failure; |
10613 | 10626 | ||
10614 | err = genlmsg_end(msg, hdr); | 10627 | genlmsg_end(msg, hdr); |
10615 | if (err < 0) { | ||
10616 | nlmsg_free(msg); | ||
10617 | return; | ||
10618 | } | ||
10619 | 10628 | ||
10620 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 10629 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
10621 | nl80211_mlme_mcgrp.id, gfp); | 10630 | nl80211_mlme_mcgrp.id, gfp); |
@@ -10673,7 +10682,6 @@ void cfg80211_ft_event(struct net_device *netdev, | |||
10673 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 10682 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
10674 | struct sk_buff *msg; | 10683 | struct sk_buff *msg; |
10675 | void *hdr; | 10684 | void *hdr; |
10676 | int err; | ||
10677 | 10685 | ||
10678 | trace_cfg80211_ft_event(wiphy, netdev, ft_event); | 10686 | trace_cfg80211_ft_event(wiphy, netdev, ft_event); |
10679 | 10687 | ||
@@ -10699,11 +10707,7 @@ void cfg80211_ft_event(struct net_device *netdev, | |||
10699 | nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len, | 10707 | nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len, |
10700 | ft_event->ric_ies); | 10708 | ft_event->ric_ies); |
10701 | 10709 | ||
10702 | err = genlmsg_end(msg, hdr); | 10710 | genlmsg_end(msg, hdr); |
10703 | if (err < 0) { | ||
10704 | nlmsg_free(msg); | ||
10705 | return; | ||
10706 | } | ||
10707 | 10711 | ||
10708 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 10712 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
10709 | nl80211_mlme_mcgrp.id, GFP_KERNEL); | 10713 | nl80211_mlme_mcgrp.id, GFP_KERNEL); |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index e1d6749234c6..5a24c986f34b 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -1345,7 +1345,7 @@ get_reg_request_treatment(struct wiphy *wiphy, | |||
1345 | return REG_REQ_OK; | 1345 | return REG_REQ_OK; |
1346 | return REG_REQ_ALREADY_SET; | 1346 | return REG_REQ_ALREADY_SET; |
1347 | } | 1347 | } |
1348 | return 0; | 1348 | return REG_REQ_OK; |
1349 | case NL80211_REGDOM_SET_BY_DRIVER: | 1349 | case NL80211_REGDOM_SET_BY_DRIVER: |
1350 | if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) { | 1350 | if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) { |
1351 | if (regdom_changes(pending_request->alpha2)) | 1351 | if (regdom_changes(pending_request->alpha2)) |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 81be95f3be74..ae7e2cbf45cb 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -1,5 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * SME code for cfg80211's connect emulation. | 2 | * SME code for cfg80211 |
3 | * both driver SME event handling and the SME implementation | ||
4 | * (for nl80211's connect() and wext) | ||
3 | * | 5 | * |
4 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> | 6 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> |
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | 7 | * Copyright (C) 2009 Intel Corporation. All rights reserved. |
@@ -18,18 +20,24 @@ | |||
18 | #include "reg.h" | 20 | #include "reg.h" |
19 | #include "rdev-ops.h" | 21 | #include "rdev-ops.h" |
20 | 22 | ||
23 | /* | ||
24 | * Software SME in cfg80211, using auth/assoc/deauth calls to the | ||
25 | * driver. This is is for implementing nl80211's connect/disconnect | ||
26 | * and wireless extensions (if configured.) | ||
27 | */ | ||
28 | |||
21 | struct cfg80211_conn { | 29 | struct cfg80211_conn { |
22 | struct cfg80211_connect_params params; | 30 | struct cfg80211_connect_params params; |
23 | /* these are sub-states of the _CONNECTING sme_state */ | 31 | /* these are sub-states of the _CONNECTING sme_state */ |
24 | enum { | 32 | enum { |
25 | CFG80211_CONN_IDLE, | ||
26 | CFG80211_CONN_SCANNING, | 33 | CFG80211_CONN_SCANNING, |
27 | CFG80211_CONN_SCAN_AGAIN, | 34 | CFG80211_CONN_SCAN_AGAIN, |
28 | CFG80211_CONN_AUTHENTICATE_NEXT, | 35 | CFG80211_CONN_AUTHENTICATE_NEXT, |
29 | CFG80211_CONN_AUTHENTICATING, | 36 | CFG80211_CONN_AUTHENTICATING, |
30 | CFG80211_CONN_ASSOCIATE_NEXT, | 37 | CFG80211_CONN_ASSOCIATE_NEXT, |
31 | CFG80211_CONN_ASSOCIATING, | 38 | CFG80211_CONN_ASSOCIATING, |
32 | CFG80211_CONN_DEAUTH_ASSOC_FAIL, | 39 | CFG80211_CONN_DEAUTH, |
40 | CFG80211_CONN_CONNECTED, | ||
33 | } state; | 41 | } state; |
34 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; | 42 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; |
35 | u8 *ie; | 43 | u8 *ie; |
@@ -37,39 +45,16 @@ struct cfg80211_conn { | |||
37 | bool auto_auth, prev_bssid_valid; | 45 | bool auto_auth, prev_bssid_valid; |
38 | }; | 46 | }; |
39 | 47 | ||
40 | static bool cfg80211_is_all_idle(void) | 48 | static void cfg80211_sme_free(struct wireless_dev *wdev) |
41 | { | 49 | { |
42 | struct cfg80211_registered_device *rdev; | 50 | if (!wdev->conn) |
43 | struct wireless_dev *wdev; | 51 | return; |
44 | bool is_all_idle = true; | ||
45 | |||
46 | /* | ||
47 | * All devices must be idle as otherwise if you are actively | ||
48 | * scanning some new beacon hints could be learned and would | ||
49 | * count as new regulatory hints. | ||
50 | */ | ||
51 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | ||
52 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | ||
53 | wdev_lock(wdev); | ||
54 | if (wdev->sme_state != CFG80211_SME_IDLE) | ||
55 | is_all_idle = false; | ||
56 | wdev_unlock(wdev); | ||
57 | } | ||
58 | } | ||
59 | |||
60 | return is_all_idle; | ||
61 | } | ||
62 | 52 | ||
63 | static void disconnect_work(struct work_struct *work) | 53 | kfree(wdev->conn->ie); |
64 | { | 54 | kfree(wdev->conn); |
65 | rtnl_lock(); | 55 | wdev->conn = NULL; |
66 | if (cfg80211_is_all_idle()) | ||
67 | regulatory_hint_disconnect(); | ||
68 | rtnl_unlock(); | ||
69 | } | 56 | } |
70 | 57 | ||
71 | static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); | ||
72 | |||
73 | static int cfg80211_conn_scan(struct wireless_dev *wdev) | 58 | static int cfg80211_conn_scan(struct wireless_dev *wdev) |
74 | { | 59 | { |
75 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 60 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
@@ -164,6 +149,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
164 | params = &wdev->conn->params; | 149 | params = &wdev->conn->params; |
165 | 150 | ||
166 | switch (wdev->conn->state) { | 151 | switch (wdev->conn->state) { |
152 | case CFG80211_CONN_SCANNING: | ||
153 | /* didn't find it during scan ... */ | ||
154 | return -ENOENT; | ||
167 | case CFG80211_CONN_SCAN_AGAIN: | 155 | case CFG80211_CONN_SCAN_AGAIN: |
168 | return cfg80211_conn_scan(wdev); | 156 | return cfg80211_conn_scan(wdev); |
169 | case CFG80211_CONN_AUTHENTICATE_NEXT: | 157 | case CFG80211_CONN_AUTHENTICATE_NEXT: |
@@ -200,12 +188,11 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
200 | WLAN_REASON_DEAUTH_LEAVING, | 188 | WLAN_REASON_DEAUTH_LEAVING, |
201 | false); | 189 | false); |
202 | return err; | 190 | return err; |
203 | case CFG80211_CONN_DEAUTH_ASSOC_FAIL: | 191 | case CFG80211_CONN_DEAUTH: |
204 | cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, | 192 | cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, |
205 | NULL, 0, | 193 | NULL, 0, |
206 | WLAN_REASON_DEAUTH_LEAVING, false); | 194 | WLAN_REASON_DEAUTH_LEAVING, false); |
207 | /* return an error so that we call __cfg80211_connect_result() */ | 195 | return 0; |
208 | return -EINVAL; | ||
209 | default: | 196 | default: |
210 | return 0; | 197 | return 0; |
211 | } | 198 | } |
@@ -229,7 +216,8 @@ void cfg80211_conn_work(struct work_struct *work) | |||
229 | wdev_unlock(wdev); | 216 | wdev_unlock(wdev); |
230 | continue; | 217 | continue; |
231 | } | 218 | } |
232 | if (wdev->sme_state != CFG80211_SME_CONNECTING || !wdev->conn) { | 219 | if (!wdev->conn || |
220 | wdev->conn->state == CFG80211_CONN_CONNECTED) { | ||
233 | wdev_unlock(wdev); | 221 | wdev_unlock(wdev); |
234 | continue; | 222 | continue; |
235 | } | 223 | } |
@@ -237,12 +225,14 @@ void cfg80211_conn_work(struct work_struct *work) | |||
237 | memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN); | 225 | memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN); |
238 | bssid = bssid_buf; | 226 | bssid = bssid_buf; |
239 | } | 227 | } |
240 | if (cfg80211_conn_do_work(wdev)) | 228 | if (cfg80211_conn_do_work(wdev)) { |
241 | __cfg80211_connect_result( | 229 | __cfg80211_connect_result( |
242 | wdev->netdev, bssid, | 230 | wdev->netdev, bssid, |
243 | NULL, 0, NULL, 0, | 231 | NULL, 0, NULL, 0, |
244 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 232 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
245 | false, NULL); | 233 | false, NULL); |
234 | cfg80211_sme_free(wdev); | ||
235 | } | ||
246 | wdev_unlock(wdev); | 236 | wdev_unlock(wdev); |
247 | } | 237 | } |
248 | 238 | ||
@@ -286,9 +276,6 @@ static void __cfg80211_sme_scan_done(struct net_device *dev) | |||
286 | 276 | ||
287 | ASSERT_WDEV_LOCK(wdev); | 277 | ASSERT_WDEV_LOCK(wdev); |
288 | 278 | ||
289 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | ||
290 | return; | ||
291 | |||
292 | if (!wdev->conn) | 279 | if (!wdev->conn) |
293 | return; | 280 | return; |
294 | 281 | ||
@@ -297,20 +284,10 @@ static void __cfg80211_sme_scan_done(struct net_device *dev) | |||
297 | return; | 284 | return; |
298 | 285 | ||
299 | bss = cfg80211_get_conn_bss(wdev); | 286 | bss = cfg80211_get_conn_bss(wdev); |
300 | if (bss) { | 287 | if (bss) |
301 | cfg80211_put_bss(&rdev->wiphy, bss); | 288 | cfg80211_put_bss(&rdev->wiphy, bss); |
302 | } else { | 289 | else |
303 | /* not found */ | 290 | schedule_work(&rdev->conn_work); |
304 | if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) | ||
305 | schedule_work(&rdev->conn_work); | ||
306 | else | ||
307 | __cfg80211_connect_result( | ||
308 | wdev->netdev, | ||
309 | wdev->conn->params.bssid, | ||
310 | NULL, 0, NULL, 0, | ||
311 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
312 | false, NULL); | ||
313 | } | ||
314 | } | 291 | } |
315 | 292 | ||
316 | void cfg80211_sme_scan_done(struct net_device *dev) | 293 | void cfg80211_sme_scan_done(struct net_device *dev) |
@@ -322,10 +299,8 @@ void cfg80211_sme_scan_done(struct net_device *dev) | |||
322 | wdev_unlock(wdev); | 299 | wdev_unlock(wdev); |
323 | } | 300 | } |
324 | 301 | ||
325 | void cfg80211_sme_rx_auth(struct net_device *dev, | 302 | void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len) |
326 | const u8 *buf, size_t len) | ||
327 | { | 303 | { |
328 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
329 | struct wiphy *wiphy = wdev->wiphy; | 304 | struct wiphy *wiphy = wdev->wiphy; |
330 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 305 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
331 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 306 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
@@ -333,11 +308,7 @@ void cfg80211_sme_rx_auth(struct net_device *dev, | |||
333 | 308 | ||
334 | ASSERT_WDEV_LOCK(wdev); | 309 | ASSERT_WDEV_LOCK(wdev); |
335 | 310 | ||
336 | /* should only RX auth frames when connecting */ | 311 | if (!wdev->conn || wdev->conn->state == CFG80211_CONN_CONNECTED) |
337 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | ||
338 | return; | ||
339 | |||
340 | if (WARN_ON(!wdev->conn)) | ||
341 | return; | 312 | return; |
342 | 313 | ||
343 | if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG && | 314 | if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG && |
@@ -366,46 +337,226 @@ void cfg80211_sme_rx_auth(struct net_device *dev, | |||
366 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; | 337 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; |
367 | schedule_work(&rdev->conn_work); | 338 | schedule_work(&rdev->conn_work); |
368 | } else if (status_code != WLAN_STATUS_SUCCESS) { | 339 | } else if (status_code != WLAN_STATUS_SUCCESS) { |
369 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, | 340 | __cfg80211_connect_result(wdev->netdev, mgmt->bssid, |
341 | NULL, 0, NULL, 0, | ||
370 | status_code, false, NULL); | 342 | status_code, false, NULL); |
371 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING && | 343 | } else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { |
372 | wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { | ||
373 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; | 344 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; |
374 | schedule_work(&rdev->conn_work); | 345 | schedule_work(&rdev->conn_work); |
375 | } | 346 | } |
376 | } | 347 | } |
377 | 348 | ||
378 | bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev) | 349 | bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status) |
379 | { | 350 | { |
380 | struct wiphy *wiphy = wdev->wiphy; | 351 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
381 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
382 | 352 | ||
383 | if (WARN_ON(!wdev->conn)) | 353 | if (!wdev->conn) |
384 | return false; | 354 | return false; |
385 | 355 | ||
386 | if (!wdev->conn->prev_bssid_valid) | 356 | if (status == WLAN_STATUS_SUCCESS) { |
357 | wdev->conn->state = CFG80211_CONN_CONNECTED; | ||
387 | return false; | 358 | return false; |
359 | } | ||
388 | 360 | ||
389 | /* | 361 | if (wdev->conn->prev_bssid_valid) { |
390 | * Some stupid APs don't accept reassoc, so we | 362 | /* |
391 | * need to fall back to trying regular assoc. | 363 | * Some stupid APs don't accept reassoc, so we |
392 | */ | 364 | * need to fall back to trying regular assoc; |
393 | wdev->conn->prev_bssid_valid = false; | 365 | * return true so no event is sent to userspace. |
394 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; | 366 | */ |
367 | wdev->conn->prev_bssid_valid = false; | ||
368 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; | ||
369 | schedule_work(&rdev->conn_work); | ||
370 | return true; | ||
371 | } | ||
372 | |||
373 | wdev->conn->state = CFG80211_CONN_DEAUTH; | ||
395 | schedule_work(&rdev->conn_work); | 374 | schedule_work(&rdev->conn_work); |
375 | return false; | ||
376 | } | ||
396 | 377 | ||
397 | return true; | 378 | void cfg80211_sme_deauth(struct wireless_dev *wdev) |
379 | { | ||
380 | cfg80211_sme_free(wdev); | ||
398 | } | 381 | } |
399 | 382 | ||
400 | void cfg80211_sme_failed_assoc(struct wireless_dev *wdev) | 383 | void cfg80211_sme_auth_timeout(struct wireless_dev *wdev) |
401 | { | 384 | { |
402 | struct wiphy *wiphy = wdev->wiphy; | 385 | cfg80211_sme_free(wdev); |
403 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 386 | } |
404 | 387 | ||
405 | wdev->conn->state = CFG80211_CONN_DEAUTH_ASSOC_FAIL; | 388 | void cfg80211_sme_disassoc(struct wireless_dev *wdev) |
389 | { | ||
390 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
391 | |||
392 | if (!wdev->conn) | ||
393 | return; | ||
394 | |||
395 | wdev->conn->state = CFG80211_CONN_DEAUTH; | ||
406 | schedule_work(&rdev->conn_work); | 396 | schedule_work(&rdev->conn_work); |
407 | } | 397 | } |
408 | 398 | ||
399 | void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev) | ||
400 | { | ||
401 | cfg80211_sme_disassoc(wdev); | ||
402 | } | ||
403 | |||
404 | static int cfg80211_sme_connect(struct wireless_dev *wdev, | ||
405 | struct cfg80211_connect_params *connect, | ||
406 | const u8 *prev_bssid) | ||
407 | { | ||
408 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
409 | struct cfg80211_bss *bss; | ||
410 | int err; | ||
411 | |||
412 | if (!rdev->ops->auth || !rdev->ops->assoc) | ||
413 | return -EOPNOTSUPP; | ||
414 | |||
415 | if (wdev->current_bss) | ||
416 | return -EALREADY; | ||
417 | |||
418 | if (WARN_ON(wdev->conn)) | ||
419 | return -EINPROGRESS; | ||
420 | |||
421 | wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); | ||
422 | if (!wdev->conn) | ||
423 | return -ENOMEM; | ||
424 | |||
425 | /* | ||
426 | * Copy all parameters, and treat explicitly IEs, BSSID, SSID. | ||
427 | */ | ||
428 | memcpy(&wdev->conn->params, connect, sizeof(*connect)); | ||
429 | if (connect->bssid) { | ||
430 | wdev->conn->params.bssid = wdev->conn->bssid; | ||
431 | memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN); | ||
432 | } | ||
433 | |||
434 | if (connect->ie) { | ||
435 | wdev->conn->ie = kmemdup(connect->ie, connect->ie_len, | ||
436 | GFP_KERNEL); | ||
437 | wdev->conn->params.ie = wdev->conn->ie; | ||
438 | if (!wdev->conn->ie) { | ||
439 | kfree(wdev->conn); | ||
440 | wdev->conn = NULL; | ||
441 | return -ENOMEM; | ||
442 | } | ||
443 | } | ||
444 | |||
445 | if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) { | ||
446 | wdev->conn->auto_auth = true; | ||
447 | /* start with open system ... should mostly work */ | ||
448 | wdev->conn->params.auth_type = | ||
449 | NL80211_AUTHTYPE_OPEN_SYSTEM; | ||
450 | } else { | ||
451 | wdev->conn->auto_auth = false; | ||
452 | } | ||
453 | |||
454 | wdev->conn->params.ssid = wdev->ssid; | ||
455 | wdev->conn->params.ssid_len = connect->ssid_len; | ||
456 | |||
457 | /* see if we have the bss already */ | ||
458 | bss = cfg80211_get_conn_bss(wdev); | ||
459 | |||
460 | if (prev_bssid) { | ||
461 | memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN); | ||
462 | wdev->conn->prev_bssid_valid = true; | ||
463 | } | ||
464 | |||
465 | /* we're good if we have a matching bss struct */ | ||
466 | if (bss) { | ||
467 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; | ||
468 | err = cfg80211_conn_do_work(wdev); | ||
469 | cfg80211_put_bss(wdev->wiphy, bss); | ||
470 | } else { | ||
471 | /* otherwise we'll need to scan for the AP first */ | ||
472 | err = cfg80211_conn_scan(wdev); | ||
473 | |||
474 | /* | ||
475 | * If we can't scan right now, then we need to scan again | ||
476 | * after the current scan finished, since the parameters | ||
477 | * changed (unless we find a good AP anyway). | ||
478 | */ | ||
479 | if (err == -EBUSY) { | ||
480 | err = 0; | ||
481 | wdev->conn->state = CFG80211_CONN_SCAN_AGAIN; | ||
482 | } | ||
483 | } | ||
484 | |||
485 | if (err) | ||
486 | cfg80211_sme_free(wdev); | ||
487 | |||
488 | return err; | ||
489 | } | ||
490 | |||
491 | static int cfg80211_sme_disconnect(struct wireless_dev *wdev, u16 reason) | ||
492 | { | ||
493 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
494 | int err; | ||
495 | |||
496 | if (!wdev->conn) | ||
497 | return 0; | ||
498 | |||
499 | if (!rdev->ops->deauth) | ||
500 | return -EOPNOTSUPP; | ||
501 | |||
502 | if (wdev->conn->state == CFG80211_CONN_SCANNING || | ||
503 | wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) { | ||
504 | err = 0; | ||
505 | goto out; | ||
506 | } | ||
507 | |||
508 | /* wdev->conn->params.bssid must be set if > SCANNING */ | ||
509 | err = cfg80211_mlme_deauth(rdev, wdev->netdev, | ||
510 | wdev->conn->params.bssid, | ||
511 | NULL, 0, reason, false); | ||
512 | out: | ||
513 | cfg80211_sme_free(wdev); | ||
514 | return err; | ||
515 | } | ||
516 | |||
517 | /* | ||
518 | * code shared for in-device and software SME | ||
519 | */ | ||
520 | |||
521 | static bool cfg80211_is_all_idle(void) | ||
522 | { | ||
523 | struct cfg80211_registered_device *rdev; | ||
524 | struct wireless_dev *wdev; | ||
525 | bool is_all_idle = true; | ||
526 | |||
527 | /* | ||
528 | * All devices must be idle as otherwise if you are actively | ||
529 | * scanning some new beacon hints could be learned and would | ||
530 | * count as new regulatory hints. | ||
531 | */ | ||
532 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | ||
533 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | ||
534 | wdev_lock(wdev); | ||
535 | if (wdev->conn || wdev->current_bss) | ||
536 | is_all_idle = false; | ||
537 | wdev_unlock(wdev); | ||
538 | } | ||
539 | } | ||
540 | |||
541 | return is_all_idle; | ||
542 | } | ||
543 | |||
544 | static void disconnect_work(struct work_struct *work) | ||
545 | { | ||
546 | rtnl_lock(); | ||
547 | if (cfg80211_is_all_idle()) | ||
548 | regulatory_hint_disconnect(); | ||
549 | rtnl_unlock(); | ||
550 | } | ||
551 | |||
552 | static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); | ||
553 | |||
554 | |||
555 | /* | ||
556 | * API calls for drivers implementing connect/disconnect and | ||
557 | * SME event handling | ||
558 | */ | ||
559 | |||
409 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 560 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
410 | const u8 *req_ie, size_t req_ie_len, | 561 | const u8 *req_ie, size_t req_ie_len, |
411 | const u8 *resp_ie, size_t resp_ie_len, | 562 | const u8 *resp_ie, size_t resp_ie_len, |
@@ -424,9 +575,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
424 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) | 575 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) |
425 | return; | 576 | return; |
426 | 577 | ||
427 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | ||
428 | return; | ||
429 | |||
430 | nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, | 578 | nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, |
431 | bssid, req_ie, req_ie_len, | 579 | bssid, req_ie, req_ie_len, |
432 | resp_ie, resp_ie_len, | 580 | resp_ie, resp_ie_len, |
@@ -463,15 +611,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
463 | wdev->current_bss = NULL; | 611 | wdev->current_bss = NULL; |
464 | } | 612 | } |
465 | 613 | ||
466 | if (wdev->conn) | ||
467 | wdev->conn->state = CFG80211_CONN_IDLE; | ||
468 | |||
469 | if (status != WLAN_STATUS_SUCCESS) { | 614 | if (status != WLAN_STATUS_SUCCESS) { |
470 | wdev->sme_state = CFG80211_SME_IDLE; | ||
471 | if (wdev->conn) | ||
472 | kfree(wdev->conn->ie); | ||
473 | kfree(wdev->conn); | ||
474 | wdev->conn = NULL; | ||
475 | kfree(wdev->connect_keys); | 615 | kfree(wdev->connect_keys); |
476 | wdev->connect_keys = NULL; | 616 | wdev->connect_keys = NULL; |
477 | wdev->ssid_len = 0; | 617 | wdev->ssid_len = 0; |
@@ -480,21 +620,16 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
480 | } | 620 | } |
481 | 621 | ||
482 | if (!bss) | 622 | if (!bss) |
483 | bss = cfg80211_get_bss(wdev->wiphy, | 623 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, |
484 | wdev->conn ? wdev->conn->params.channel : | ||
485 | NULL, | ||
486 | bssid, | ||
487 | wdev->ssid, wdev->ssid_len, | 624 | wdev->ssid, wdev->ssid_len, |
488 | WLAN_CAPABILITY_ESS, | 625 | WLAN_CAPABILITY_ESS, |
489 | WLAN_CAPABILITY_ESS); | 626 | WLAN_CAPABILITY_ESS); |
490 | |||
491 | if (WARN_ON(!bss)) | 627 | if (WARN_ON(!bss)) |
492 | return; | 628 | return; |
493 | 629 | ||
494 | cfg80211_hold_bss(bss_from_pub(bss)); | 630 | cfg80211_hold_bss(bss_from_pub(bss)); |
495 | wdev->current_bss = bss_from_pub(bss); | 631 | wdev->current_bss = bss_from_pub(bss); |
496 | 632 | ||
497 | wdev->sme_state = CFG80211_SME_CONNECTED; | ||
498 | cfg80211_upload_connect_keys(wdev); | 633 | cfg80211_upload_connect_keys(wdev); |
499 | 634 | ||
500 | rcu_read_lock(); | 635 | rcu_read_lock(); |
@@ -530,8 +665,6 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
530 | struct cfg80211_event *ev; | 665 | struct cfg80211_event *ev; |
531 | unsigned long flags; | 666 | unsigned long flags; |
532 | 667 | ||
533 | CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING); | ||
534 | |||
535 | ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); | 668 | ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); |
536 | if (!ev) | 669 | if (!ev) |
537 | return; | 670 | return; |
@@ -572,13 +705,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev, | |||
572 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) | 705 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) |
573 | goto out; | 706 | goto out; |
574 | 707 | ||
575 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | 708 | if (WARN_ON(!wdev->current_bss)) |
576 | goto out; | ||
577 | |||
578 | /* internal error -- how did we get to CONNECTED w/o BSS? */ | ||
579 | if (WARN_ON(!wdev->current_bss)) { | ||
580 | goto out; | 709 | goto out; |
581 | } | ||
582 | 710 | ||
583 | cfg80211_unhold_bss(wdev->current_bss); | 711 | cfg80211_unhold_bss(wdev->current_bss); |
584 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); | 712 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); |
@@ -628,8 +756,6 @@ void cfg80211_roamed(struct net_device *dev, | |||
628 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 756 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
629 | struct cfg80211_bss *bss; | 757 | struct cfg80211_bss *bss; |
630 | 758 | ||
631 | CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED); | ||
632 | |||
633 | bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid, | 759 | bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid, |
634 | wdev->ssid_len, WLAN_CAPABILITY_ESS, | 760 | wdev->ssid_len, WLAN_CAPABILITY_ESS, |
635 | WLAN_CAPABILITY_ESS); | 761 | WLAN_CAPABILITY_ESS); |
@@ -651,8 +777,6 @@ void cfg80211_roamed_bss(struct net_device *dev, | |||
651 | struct cfg80211_event *ev; | 777 | struct cfg80211_event *ev; |
652 | unsigned long flags; | 778 | unsigned long flags; |
653 | 779 | ||
654 | CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED); | ||
655 | |||
656 | if (WARN_ON(!bss)) | 780 | if (WARN_ON(!bss)) |
657 | return; | 781 | return; |
658 | 782 | ||
@@ -694,25 +818,14 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
694 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) | 818 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) |
695 | return; | 819 | return; |
696 | 820 | ||
697 | if (wdev->sme_state != CFG80211_SME_CONNECTED) | ||
698 | return; | ||
699 | |||
700 | if (wdev->current_bss) { | 821 | if (wdev->current_bss) { |
701 | cfg80211_unhold_bss(wdev->current_bss); | 822 | cfg80211_unhold_bss(wdev->current_bss); |
702 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); | 823 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); |
703 | } | 824 | } |
704 | 825 | ||
705 | wdev->current_bss = NULL; | 826 | wdev->current_bss = NULL; |
706 | wdev->sme_state = CFG80211_SME_IDLE; | ||
707 | wdev->ssid_len = 0; | 827 | wdev->ssid_len = 0; |
708 | 828 | ||
709 | if (wdev->conn) { | ||
710 | kfree(wdev->conn->ie); | ||
711 | wdev->conn->ie = NULL; | ||
712 | kfree(wdev->conn); | ||
713 | wdev->conn = NULL; | ||
714 | } | ||
715 | |||
716 | nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); | 829 | nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); |
717 | 830 | ||
718 | /* | 831 | /* |
@@ -741,8 +854,6 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason, | |||
741 | struct cfg80211_event *ev; | 854 | struct cfg80211_event *ev; |
742 | unsigned long flags; | 855 | unsigned long flags; |
743 | 856 | ||
744 | CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED); | ||
745 | |||
746 | ev = kzalloc(sizeof(*ev) + ie_len, gfp); | 857 | ev = kzalloc(sizeof(*ev) + ie_len, gfp); |
747 | if (!ev) | 858 | if (!ev) |
748 | return; | 859 | return; |
@@ -760,6 +871,9 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason, | |||
760 | } | 871 | } |
761 | EXPORT_SYMBOL(cfg80211_disconnected); | 872 | EXPORT_SYMBOL(cfg80211_disconnected); |
762 | 873 | ||
874 | /* | ||
875 | * API calls for nl80211/wext compatibility code | ||
876 | */ | ||
763 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 877 | int cfg80211_connect(struct cfg80211_registered_device *rdev, |
764 | struct net_device *dev, | 878 | struct net_device *dev, |
765 | struct cfg80211_connect_params *connect, | 879 | struct cfg80211_connect_params *connect, |
@@ -767,14 +881,10 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
767 | const u8 *prev_bssid) | 881 | const u8 *prev_bssid) |
768 | { | 882 | { |
769 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 883 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
770 | struct cfg80211_bss *bss = NULL; | ||
771 | int err; | 884 | int err; |
772 | 885 | ||
773 | ASSERT_WDEV_LOCK(wdev); | 886 | ASSERT_WDEV_LOCK(wdev); |
774 | 887 | ||
775 | if (wdev->sme_state != CFG80211_SME_IDLE) | ||
776 | return -EALREADY; | ||
777 | |||
778 | if (WARN_ON(wdev->connect_keys)) { | 888 | if (WARN_ON(wdev->connect_keys)) { |
779 | kfree(wdev->connect_keys); | 889 | kfree(wdev->connect_keys); |
780 | wdev->connect_keys = NULL; | 890 | wdev->connect_keys = NULL; |
@@ -810,105 +920,22 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
810 | } | 920 | } |
811 | } | 921 | } |
812 | 922 | ||
813 | if (!rdev->ops->connect) { | 923 | wdev->connect_keys = connkeys; |
814 | if (!rdev->ops->auth || !rdev->ops->assoc) | 924 | memcpy(wdev->ssid, connect->ssid, connect->ssid_len); |
815 | return -EOPNOTSUPP; | 925 | wdev->ssid_len = connect->ssid_len; |
816 | |||
817 | if (WARN_ON(wdev->conn)) | ||
818 | return -EINPROGRESS; | ||
819 | |||
820 | wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); | ||
821 | if (!wdev->conn) | ||
822 | return -ENOMEM; | ||
823 | |||
824 | /* | ||
825 | * Copy all parameters, and treat explicitly IEs, BSSID, SSID. | ||
826 | */ | ||
827 | memcpy(&wdev->conn->params, connect, sizeof(*connect)); | ||
828 | if (connect->bssid) { | ||
829 | wdev->conn->params.bssid = wdev->conn->bssid; | ||
830 | memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN); | ||
831 | } | ||
832 | 926 | ||
833 | if (connect->ie) { | 927 | if (!rdev->ops->connect) |
834 | wdev->conn->ie = kmemdup(connect->ie, connect->ie_len, | 928 | err = cfg80211_sme_connect(wdev, connect, prev_bssid); |
835 | GFP_KERNEL); | 929 | else |
836 | wdev->conn->params.ie = wdev->conn->ie; | ||
837 | if (!wdev->conn->ie) { | ||
838 | kfree(wdev->conn); | ||
839 | wdev->conn = NULL; | ||
840 | return -ENOMEM; | ||
841 | } | ||
842 | } | ||
843 | |||
844 | if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) { | ||
845 | wdev->conn->auto_auth = true; | ||
846 | /* start with open system ... should mostly work */ | ||
847 | wdev->conn->params.auth_type = | ||
848 | NL80211_AUTHTYPE_OPEN_SYSTEM; | ||
849 | } else { | ||
850 | wdev->conn->auto_auth = false; | ||
851 | } | ||
852 | |||
853 | memcpy(wdev->ssid, connect->ssid, connect->ssid_len); | ||
854 | wdev->ssid_len = connect->ssid_len; | ||
855 | wdev->conn->params.ssid = wdev->ssid; | ||
856 | wdev->conn->params.ssid_len = connect->ssid_len; | ||
857 | |||
858 | /* see if we have the bss already */ | ||
859 | bss = cfg80211_get_conn_bss(wdev); | ||
860 | |||
861 | wdev->sme_state = CFG80211_SME_CONNECTING; | ||
862 | wdev->connect_keys = connkeys; | ||
863 | |||
864 | if (prev_bssid) { | ||
865 | memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN); | ||
866 | wdev->conn->prev_bssid_valid = true; | ||
867 | } | ||
868 | |||
869 | /* we're good if we have a matching bss struct */ | ||
870 | if (bss) { | ||
871 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; | ||
872 | err = cfg80211_conn_do_work(wdev); | ||
873 | cfg80211_put_bss(wdev->wiphy, bss); | ||
874 | } else { | ||
875 | /* otherwise we'll need to scan for the AP first */ | ||
876 | err = cfg80211_conn_scan(wdev); | ||
877 | /* | ||
878 | * If we can't scan right now, then we need to scan again | ||
879 | * after the current scan finished, since the parameters | ||
880 | * changed (unless we find a good AP anyway). | ||
881 | */ | ||
882 | if (err == -EBUSY) { | ||
883 | err = 0; | ||
884 | wdev->conn->state = CFG80211_CONN_SCAN_AGAIN; | ||
885 | } | ||
886 | } | ||
887 | if (err) { | ||
888 | kfree(wdev->conn->ie); | ||
889 | kfree(wdev->conn); | ||
890 | wdev->conn = NULL; | ||
891 | wdev->sme_state = CFG80211_SME_IDLE; | ||
892 | wdev->connect_keys = NULL; | ||
893 | wdev->ssid_len = 0; | ||
894 | } | ||
895 | |||
896 | return err; | ||
897 | } else { | ||
898 | wdev->sme_state = CFG80211_SME_CONNECTING; | ||
899 | wdev->connect_keys = connkeys; | ||
900 | err = rdev_connect(rdev, dev, connect); | 930 | err = rdev_connect(rdev, dev, connect); |
901 | if (err) { | ||
902 | wdev->connect_keys = NULL; | ||
903 | wdev->sme_state = CFG80211_SME_IDLE; | ||
904 | return err; | ||
905 | } | ||
906 | 931 | ||
907 | memcpy(wdev->ssid, connect->ssid, connect->ssid_len); | 932 | if (err) { |
908 | wdev->ssid_len = connect->ssid_len; | 933 | wdev->connect_keys = NULL; |
909 | 934 | wdev->ssid_len = 0; | |
910 | return 0; | 935 | return err; |
911 | } | 936 | } |
937 | |||
938 | return 0; | ||
912 | } | 939 | } |
913 | 940 | ||
914 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | 941 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, |
@@ -919,78 +946,17 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
919 | 946 | ||
920 | ASSERT_WDEV_LOCK(wdev); | 947 | ASSERT_WDEV_LOCK(wdev); |
921 | 948 | ||
922 | if (wdev->sme_state == CFG80211_SME_IDLE) | ||
923 | return -EINVAL; | ||
924 | |||
925 | kfree(wdev->connect_keys); | 949 | kfree(wdev->connect_keys); |
926 | wdev->connect_keys = NULL; | 950 | wdev->connect_keys = NULL; |
927 | 951 | ||
928 | if (!rdev->ops->disconnect) { | 952 | if (wdev->conn) { |
929 | if (!rdev->ops->deauth) | 953 | err = cfg80211_sme_disconnect(wdev, reason); |
930 | return -EOPNOTSUPP; | 954 | } else if (!rdev->ops->disconnect) { |
931 | 955 | cfg80211_mlme_down(rdev, dev); | |
932 | /* was it connected by userspace SME? */ | 956 | err = 0; |
933 | if (!wdev->conn) { | ||
934 | cfg80211_mlme_down(rdev, dev); | ||
935 | goto disconnect; | ||
936 | } | ||
937 | |||
938 | if (wdev->sme_state == CFG80211_SME_CONNECTING && | ||
939 | (wdev->conn->state == CFG80211_CONN_SCANNING || | ||
940 | wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) { | ||
941 | wdev->sme_state = CFG80211_SME_IDLE; | ||
942 | kfree(wdev->conn->ie); | ||
943 | kfree(wdev->conn); | ||
944 | wdev->conn = NULL; | ||
945 | wdev->ssid_len = 0; | ||
946 | return 0; | ||
947 | } | ||
948 | |||
949 | /* wdev->conn->params.bssid must be set if > SCANNING */ | ||
950 | err = cfg80211_mlme_deauth(rdev, dev, | ||
951 | wdev->conn->params.bssid, | ||
952 | NULL, 0, reason, false); | ||
953 | if (err) | ||
954 | return err; | ||
955 | } else { | 957 | } else { |
956 | err = rdev_disconnect(rdev, dev, reason); | 958 | err = rdev_disconnect(rdev, dev, reason); |
957 | if (err) | ||
958 | return err; | ||
959 | } | 959 | } |
960 | 960 | ||
961 | disconnect: | 961 | return err; |
962 | if (wdev->sme_state == CFG80211_SME_CONNECTED) | ||
963 | __cfg80211_disconnected(dev, NULL, 0, 0, false); | ||
964 | else if (wdev->sme_state == CFG80211_SME_CONNECTING) | ||
965 | __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, | ||
966 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
967 | wextev, NULL); | ||
968 | |||
969 | return 0; | ||
970 | } | ||
971 | |||
972 | void cfg80211_sme_disassoc(struct net_device *dev, | ||
973 | struct cfg80211_internal_bss *bss) | ||
974 | { | ||
975 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
976 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
977 | u8 bssid[ETH_ALEN]; | ||
978 | |||
979 | ASSERT_WDEV_LOCK(wdev); | ||
980 | |||
981 | if (!wdev->conn) | ||
982 | return; | ||
983 | |||
984 | if (wdev->conn->state == CFG80211_CONN_IDLE) | ||
985 | return; | ||
986 | |||
987 | /* | ||
988 | * Ok, so the association was made by this SME -- we don't | ||
989 | * want it any more so deauthenticate too. | ||
990 | */ | ||
991 | |||
992 | memcpy(bssid, bss->pub.bssid, ETH_ALEN); | ||
993 | |||
994 | cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, | ||
995 | WLAN_REASON_DEAUTH_LEAVING, false); | ||
996 | } | 962 | } |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 23fafeae8a10..e1534baf2ebb 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -1911,24 +1911,46 @@ TRACE_EVENT(cfg80211_send_rx_assoc, | |||
1911 | NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG) | 1911 | NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG) |
1912 | ); | 1912 | ); |
1913 | 1913 | ||
1914 | DEFINE_EVENT(netdev_evt_only, cfg80211_send_deauth, | 1914 | DECLARE_EVENT_CLASS(netdev_frame_event, |
1915 | TP_PROTO(struct net_device *netdev), | 1915 | TP_PROTO(struct net_device *netdev, const u8 *buf, int len), |
1916 | TP_ARGS(netdev) | 1916 | TP_ARGS(netdev, buf, len), |
1917 | TP_STRUCT__entry( | ||
1918 | NETDEV_ENTRY | ||
1919 | __dynamic_array(u8, frame, len) | ||
1920 | ), | ||
1921 | TP_fast_assign( | ||
1922 | NETDEV_ASSIGN; | ||
1923 | memcpy(__get_dynamic_array(frame), buf, len); | ||
1924 | ), | ||
1925 | TP_printk(NETDEV_PR_FMT ", ftype:0x%.2x", | ||
1926 | NETDEV_PR_ARG, | ||
1927 | le16_to_cpup((__le16 *)__get_dynamic_array(frame))) | ||
1917 | ); | 1928 | ); |
1918 | 1929 | ||
1919 | DEFINE_EVENT(netdev_evt_only, cfg80211_send_disassoc, | 1930 | DEFINE_EVENT(netdev_frame_event, cfg80211_rx_unprot_mlme_mgmt, |
1920 | TP_PROTO(struct net_device *netdev), | 1931 | TP_PROTO(struct net_device *netdev, const u8 *buf, int len), |
1921 | TP_ARGS(netdev) | 1932 | TP_ARGS(netdev, buf, len) |
1922 | ); | 1933 | ); |
1923 | 1934 | ||
1924 | DEFINE_EVENT(netdev_evt_only, cfg80211_send_unprot_deauth, | 1935 | DEFINE_EVENT(netdev_frame_event, cfg80211_rx_mlme_mgmt, |
1925 | TP_PROTO(struct net_device *netdev), | 1936 | TP_PROTO(struct net_device *netdev, const u8 *buf, int len), |
1926 | TP_ARGS(netdev) | 1937 | TP_ARGS(netdev, buf, len) |
1927 | ); | 1938 | ); |
1928 | 1939 | ||
1929 | DEFINE_EVENT(netdev_evt_only, cfg80211_send_unprot_disassoc, | 1940 | TRACE_EVENT(cfg80211_tx_mlme_mgmt, |
1930 | TP_PROTO(struct net_device *netdev), | 1941 | TP_PROTO(struct net_device *netdev, const u8 *buf, int len), |
1931 | TP_ARGS(netdev) | 1942 | TP_ARGS(netdev, buf, len), |
1943 | TP_STRUCT__entry( | ||
1944 | NETDEV_ENTRY | ||
1945 | __dynamic_array(u8, frame, len) | ||
1946 | ), | ||
1947 | TP_fast_assign( | ||
1948 | NETDEV_ASSIGN; | ||
1949 | memcpy(__get_dynamic_array(frame), buf, len); | ||
1950 | ), | ||
1951 | TP_printk(NETDEV_PR_FMT ", ftype:0x%.2x", | ||
1952 | NETDEV_PR_ARG, | ||
1953 | le16_to_cpup((__le16 *)__get_dynamic_array(frame))) | ||
1932 | ); | 1954 | ); |
1933 | 1955 | ||
1934 | DECLARE_EVENT_CLASS(netdev_mac_evt, | 1956 | DECLARE_EVENT_CLASS(netdev_mac_evt, |
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index a53f8404f451..14c9a2583ba0 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c | |||
@@ -89,7 +89,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | |||
89 | 89 | ||
90 | wdev_lock(wdev); | 90 | wdev_lock(wdev); |
91 | 91 | ||
92 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 92 | if (wdev->conn) { |
93 | bool event = true; | 93 | bool event = true; |
94 | 94 | ||
95 | if (wdev->wext.connect.channel == chan) { | 95 | if (wdev->wext.connect.channel == chan) { |
@@ -188,7 +188,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
188 | 188 | ||
189 | err = 0; | 189 | err = 0; |
190 | 190 | ||
191 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 191 | if (wdev->conn) { |
192 | bool event = true; | 192 | bool event = true; |
193 | 193 | ||
194 | if (wdev->wext.connect.ssid && len && | 194 | if (wdev->wext.connect.ssid && len && |
@@ -277,7 +277,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
277 | 277 | ||
278 | wdev_lock(wdev); | 278 | wdev_lock(wdev); |
279 | 279 | ||
280 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 280 | if (wdev->conn) { |
281 | err = 0; | 281 | err = 0; |
282 | /* both automatic */ | 282 | /* both automatic */ |
283 | if (!bssid && !wdev->wext.connect.bssid) | 283 | if (!bssid && !wdev->wext.connect.bssid) |
@@ -364,7 +364,7 @@ int cfg80211_wext_siwgenie(struct net_device *dev, | |||
364 | wdev->wext.ie = ie; | 364 | wdev->wext.ie = ie; |
365 | wdev->wext.ie_len = ie_len; | 365 | wdev->wext.ie_len = ie_len; |
366 | 366 | ||
367 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 367 | if (wdev->conn) { |
368 | err = cfg80211_disconnect(rdev, dev, | 368 | err = cfg80211_disconnect(rdev, dev, |
369 | WLAN_REASON_DEAUTH_LEAVING, false); | 369 | WLAN_REASON_DEAUTH_LEAVING, false); |
370 | if (err) | 370 | if (err) |