diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/mac80211/cfg.c | 92 | ||||
| -rw-r--r-- | net/mac80211/chan.c | 5 | ||||
| -rw-r--r-- | net/mac80211/debugfs.c | 55 | ||||
| -rw-r--r-- | net/mac80211/driver-ops.h | 27 | ||||
| -rw-r--r-- | net/mac80211/ibss.c | 608 | ||||
| -rw-r--r-- | net/mac80211/ieee80211_i.h | 30 | ||||
| -rw-r--r-- | net/mac80211/iface.c | 4 | ||||
| -rw-r--r-- | net/mac80211/key.c | 2 | ||||
| -rw-r--r-- | net/mac80211/mlme.c | 334 | ||||
| -rw-r--r-- | net/mac80211/rc80211_minstrel.c | 14 | ||||
| -rw-r--r-- | net/mac80211/rc80211_minstrel_ht.c | 23 | ||||
| -rw-r--r-- | net/mac80211/rc80211_pid_debugfs.c | 26 | ||||
| -rw-r--r-- | net/mac80211/rx.c | 39 | ||||
| -rw-r--r-- | net/mac80211/scan.c | 3 | ||||
| -rw-r--r-- | net/mac80211/spectmgmt.c | 162 | ||||
| -rw-r--r-- | net/mac80211/trace.h | 35 | ||||
| -rw-r--r-- | net/mac80211/tx.c | 39 | ||||
| -rw-r--r-- | net/mac80211/util.c | 162 | ||||
| -rw-r--r-- | net/mac80211/vht.c | 4 | ||||
| -rw-r--r-- | net/wireless/chan.c | 1 | ||||
| -rw-r--r-- | net/wireless/core.h | 9 | ||||
| -rw-r--r-- | net/wireless/debugfs.c | 24 | ||||
| -rw-r--r-- | net/wireless/genregdb.awk | 6 | ||||
| -rw-r--r-- | net/wireless/nl80211.c | 52 | ||||
| -rw-r--r-- | net/wireless/reg.c | 14 | ||||
| -rw-r--r-- | net/wireless/util.c | 9 |
26 files changed, 1237 insertions, 542 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 2e7855a1b10d..ac28af74a414 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
| @@ -2865,30 +2865,43 @@ void ieee80211_csa_finalize_work(struct work_struct *work) | |||
| 2865 | if (!ieee80211_sdata_running(sdata)) | 2865 | if (!ieee80211_sdata_running(sdata)) |
| 2866 | return; | 2866 | return; |
| 2867 | 2867 | ||
| 2868 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP)) | ||
| 2869 | return; | ||
| 2870 | |||
| 2871 | sdata->radar_required = sdata->csa_radar_required; | 2868 | sdata->radar_required = sdata->csa_radar_required; |
| 2872 | err = ieee80211_vif_change_channel(sdata, &local->csa_chandef, | 2869 | err = ieee80211_vif_change_channel(sdata, &local->csa_chandef, |
| 2873 | &changed); | 2870 | &changed); |
| 2874 | if (WARN_ON(err < 0)) | 2871 | if (WARN_ON(err < 0)) |
| 2875 | return; | 2872 | return; |
| 2876 | 2873 | ||
| 2877 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); | 2874 | if (!local->use_chanctx) { |
| 2878 | if (err < 0) | 2875 | local->_oper_chandef = local->csa_chandef; |
| 2879 | return; | 2876 | ieee80211_hw_config(local, 0); |
| 2877 | } | ||
| 2880 | 2878 | ||
| 2881 | changed |= err; | 2879 | ieee80211_bss_info_change_notify(sdata, changed); |
| 2882 | kfree(sdata->u.ap.next_beacon); | 2880 | |
| 2883 | sdata->u.ap.next_beacon = NULL; | 2881 | switch (sdata->vif.type) { |
| 2882 | case NL80211_IFTYPE_AP: | ||
| 2883 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); | ||
| 2884 | if (err < 0) | ||
| 2885 | return; | ||
| 2886 | changed |= err; | ||
| 2887 | kfree(sdata->u.ap.next_beacon); | ||
| 2888 | sdata->u.ap.next_beacon = NULL; | ||
| 2889 | |||
| 2890 | ieee80211_bss_info_change_notify(sdata, err); | ||
| 2891 | break; | ||
| 2892 | case NL80211_IFTYPE_ADHOC: | ||
| 2893 | ieee80211_ibss_finish_csa(sdata); | ||
| 2894 | break; | ||
| 2895 | default: | ||
| 2896 | WARN_ON(1); | ||
| 2897 | return; | ||
| 2898 | } | ||
| 2884 | sdata->vif.csa_active = false; | 2899 | sdata->vif.csa_active = false; |
| 2885 | 2900 | ||
| 2886 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 2901 | ieee80211_wake_queues_by_reason(&sdata->local->hw, |
| 2887 | IEEE80211_MAX_QUEUE_MAP, | 2902 | IEEE80211_MAX_QUEUE_MAP, |
| 2888 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2903 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| 2889 | 2904 | ||
| 2890 | ieee80211_bss_info_change_notify(sdata, changed); | ||
| 2891 | |||
| 2892 | cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef); | 2905 | cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef); |
| 2893 | } | 2906 | } |
| 2894 | 2907 | ||
| @@ -2936,20 +2949,56 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
| 2936 | if (sdata->vif.csa_active) | 2949 | if (sdata->vif.csa_active) |
| 2937 | return -EBUSY; | 2950 | return -EBUSY; |
| 2938 | 2951 | ||
| 2939 | /* only handle AP for now. */ | ||
| 2940 | switch (sdata->vif.type) { | 2952 | switch (sdata->vif.type) { |
| 2941 | case NL80211_IFTYPE_AP: | 2953 | case NL80211_IFTYPE_AP: |
| 2954 | sdata->csa_counter_offset_beacon = | ||
| 2955 | params->counter_offset_beacon; | ||
| 2956 | sdata->csa_counter_offset_presp = params->counter_offset_presp; | ||
| 2957 | sdata->u.ap.next_beacon = | ||
| 2958 | cfg80211_beacon_dup(¶ms->beacon_after); | ||
| 2959 | if (!sdata->u.ap.next_beacon) | ||
| 2960 | return -ENOMEM; | ||
| 2961 | |||
| 2962 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa); | ||
| 2963 | if (err < 0) { | ||
| 2964 | kfree(sdata->u.ap.next_beacon); | ||
| 2965 | return err; | ||
| 2966 | } | ||
| 2967 | break; | ||
| 2968 | case NL80211_IFTYPE_ADHOC: | ||
| 2969 | if (!sdata->vif.bss_conf.ibss_joined) | ||
| 2970 | return -EINVAL; | ||
| 2971 | |||
| 2972 | if (params->chandef.width != sdata->u.ibss.chandef.width) | ||
| 2973 | return -EINVAL; | ||
| 2974 | |||
| 2975 | switch (params->chandef.width) { | ||
| 2976 | case NL80211_CHAN_WIDTH_40: | ||
| 2977 | if (cfg80211_get_chandef_type(¶ms->chandef) != | ||
| 2978 | cfg80211_get_chandef_type(&sdata->u.ibss.chandef)) | ||
| 2979 | return -EINVAL; | ||
| 2980 | case NL80211_CHAN_WIDTH_5: | ||
| 2981 | case NL80211_CHAN_WIDTH_10: | ||
| 2982 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
| 2983 | case NL80211_CHAN_WIDTH_20: | ||
| 2984 | break; | ||
| 2985 | default: | ||
| 2986 | return -EINVAL; | ||
| 2987 | } | ||
| 2988 | |||
| 2989 | /* changes into another band are not supported */ | ||
| 2990 | if (sdata->u.ibss.chandef.chan->band != | ||
| 2991 | params->chandef.chan->band) | ||
| 2992 | return -EINVAL; | ||
| 2993 | |||
| 2994 | err = ieee80211_ibss_csa_beacon(sdata, params); | ||
| 2995 | if (err < 0) | ||
| 2996 | return err; | ||
| 2942 | break; | 2997 | break; |
| 2943 | default: | 2998 | default: |
| 2944 | return -EOPNOTSUPP; | 2999 | return -EOPNOTSUPP; |
| 2945 | } | 3000 | } |
| 2946 | 3001 | ||
| 2947 | sdata->u.ap.next_beacon = cfg80211_beacon_dup(¶ms->beacon_after); | ||
| 2948 | if (!sdata->u.ap.next_beacon) | ||
| 2949 | return -ENOMEM; | ||
| 2950 | |||
| 2951 | sdata->csa_counter_offset_beacon = params->counter_offset_beacon; | ||
| 2952 | sdata->csa_counter_offset_presp = params->counter_offset_presp; | ||
| 2953 | sdata->csa_radar_required = params->radar_required; | 3002 | sdata->csa_radar_required = params->radar_required; |
| 2954 | 3003 | ||
| 2955 | if (params->block_tx) | 3004 | if (params->block_tx) |
| @@ -2957,10 +3006,6 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
| 2957 | IEEE80211_MAX_QUEUE_MAP, | 3006 | IEEE80211_MAX_QUEUE_MAP, |
| 2958 | IEEE80211_QUEUE_STOP_REASON_CSA); | 3007 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| 2959 | 3008 | ||
| 2960 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa); | ||
| 2961 | if (err < 0) | ||
| 2962 | return err; | ||
| 2963 | |||
| 2964 | local->csa_chandef = params->chandef; | 3009 | local->csa_chandef = params->chandef; |
| 2965 | sdata->vif.csa_active = true; | 3010 | sdata->vif.csa_active = true; |
| 2966 | 3011 | ||
| @@ -3014,7 +3059,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
| 3014 | need_offchan = true; | 3059 | need_offchan = true; |
| 3015 | if (!ieee80211_is_action(mgmt->frame_control) || | 3060 | if (!ieee80211_is_action(mgmt->frame_control) || |
| 3016 | mgmt->u.action.category == WLAN_CATEGORY_PUBLIC || | 3061 | mgmt->u.action.category == WLAN_CATEGORY_PUBLIC || |
| 3017 | mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED) | 3062 | mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED || |
| 3063 | mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) | ||
| 3018 | break; | 3064 | break; |
| 3019 | rcu_read_lock(); | 3065 | rcu_read_lock(); |
| 3020 | sta = sta_info_get(sdata, mgmt->da); | 3066 | sta = sta_info_get(sdata, mgmt->da); |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 3a4764b2869e..03ba6b5c5373 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
| @@ -453,11 +453,6 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | |||
| 453 | chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL; | 453 | chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL; |
| 454 | drv_change_chanctx(local, ctx, chanctx_changed); | 454 | drv_change_chanctx(local, ctx, chanctx_changed); |
| 455 | 455 | ||
| 456 | if (!local->use_chanctx) { | ||
| 457 | local->_oper_chandef = *chandef; | ||
| 458 | ieee80211_hw_config(local, 0); | ||
| 459 | } | ||
| 460 | |||
| 461 | ieee80211_recalc_chanctx_chantype(local, ctx); | 456 | ieee80211_recalc_chanctx_chantype(local, ctx); |
| 462 | ieee80211_recalc_smps_chanctx(local, ctx); | 457 | ieee80211_recalc_smps_chanctx(local, ctx); |
| 463 | ieee80211_recalc_radar_chanctx(local, ctx); | 458 | ieee80211_recalc_radar_chanctx(local, ctx); |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index b0e32d628114..5c090e41d9bb 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
| @@ -103,54 +103,57 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf, | |||
| 103 | if (!buf) | 103 | if (!buf) |
| 104 | return 0; | 104 | return 0; |
| 105 | 105 | ||
| 106 | sf += snprintf(buf, mxln - sf, "0x%x\n", local->hw.flags); | 106 | sf += scnprintf(buf, mxln - sf, "0x%x\n", local->hw.flags); |
| 107 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) | 107 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) |
| 108 | sf += snprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n"); | 108 | sf += scnprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n"); |
| 109 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | 109 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) |
| 110 | sf += snprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n"); | 110 | sf += scnprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n"); |
| 111 | if (local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) | 111 | if (local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) |
| 112 | sf += snprintf(buf + sf, mxln - sf, | 112 | sf += scnprintf(buf + sf, mxln - sf, |
| 113 | "HOST_BCAST_PS_BUFFERING\n"); | 113 | "HOST_BCAST_PS_BUFFERING\n"); |
| 114 | if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE) | 114 | if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE) |
| 115 | sf += snprintf(buf + sf, mxln - sf, | 115 | sf += scnprintf(buf + sf, mxln - sf, |
| 116 | "2GHZ_SHORT_SLOT_INCAPABLE\n"); | 116 | "2GHZ_SHORT_SLOT_INCAPABLE\n"); |
| 117 | if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE) | 117 | if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE) |
| 118 | sf += snprintf(buf + sf, mxln - sf, | 118 | sf += scnprintf(buf + sf, mxln - sf, |
| 119 | "2GHZ_SHORT_PREAMBLE_INCAPABLE\n"); | 119 | "2GHZ_SHORT_PREAMBLE_INCAPABLE\n"); |
| 120 | if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | 120 | if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) |
| 121 | sf += snprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n"); | 121 | sf += scnprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n"); |
| 122 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | 122 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) |
| 123 | sf += snprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n"); | 123 | sf += scnprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n"); |
| 124 | if (local->hw.flags & IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC) | 124 | if (local->hw.flags & IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC) |
| 125 | sf += snprintf(buf + sf, mxln - sf, "NEED_DTIM_BEFORE_ASSOC\n"); | 125 | sf += scnprintf(buf + sf, mxln - sf, |
| 126 | "NEED_DTIM_BEFORE_ASSOC\n"); | ||
| 126 | if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT) | 127 | if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT) |
| 127 | sf += snprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n"); | 128 | sf += scnprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n"); |
| 128 | if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) | 129 | if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) |
| 129 | sf += snprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n"); | 130 | sf += scnprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n"); |
| 130 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS) | 131 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS) |
| 131 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n"); | 132 | sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n"); |
| 132 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | 133 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) |
| 133 | sf += snprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n"); | 134 | sf += scnprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n"); |
| 134 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | 135 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) |
| 135 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n"); | 136 | sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n"); |
| 136 | if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE) | 137 | if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE) |
| 137 | sf += snprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n"); | 138 | sf += scnprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n"); |
| 138 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) | 139 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) |
| 139 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n"); | 140 | sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n"); |
| 140 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) | 141 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) |
| 141 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_SMPS\n"); | 142 | sf += scnprintf(buf + sf, mxln - sf, |
| 143 | "SUPPORTS_DYNAMIC_SMPS\n"); | ||
| 142 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) | 144 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) |
| 143 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n"); | 145 | sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n"); |
| 144 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | 146 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) |
| 145 | sf += snprintf(buf + sf, mxln - sf, "REPORTS_TX_ACK_STATUS\n"); | 147 | sf += scnprintf(buf + sf, mxln - sf, |
| 148 | "REPORTS_TX_ACK_STATUS\n"); | ||
| 146 | if (local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | 149 | if (local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) |
| 147 | sf += snprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n"); | 150 | sf += scnprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n"); |
| 148 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK) | 151 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK) |
| 149 | sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n"); | 152 | sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n"); |
| 150 | if (local->hw.flags & IEEE80211_HW_AP_LINK_PS) | 153 | if (local->hw.flags & IEEE80211_HW_AP_LINK_PS) |
| 151 | sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n"); | 154 | sf += scnprintf(buf + sf, mxln - sf, "AP_LINK_PS\n"); |
| 152 | if (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW) | 155 | if (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW) |
| 153 | sf += snprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n"); | 156 | sf += scnprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n"); |
| 154 | 157 | ||
| 155 | rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); | 158 | rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); |
| 156 | kfree(buf); | 159 | kfree(buf); |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index b3ea11f3d526..5d03c47c0a4c 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
| @@ -1085,4 +1085,31 @@ drv_channel_switch_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 1085 | } | 1085 | } |
| 1086 | } | 1086 | } |
| 1087 | 1087 | ||
| 1088 | static inline int drv_join_ibss(struct ieee80211_local *local, | ||
| 1089 | struct ieee80211_sub_if_data *sdata) | ||
| 1090 | { | ||
| 1091 | int ret = 0; | ||
| 1092 | |||
| 1093 | might_sleep(); | ||
| 1094 | check_sdata_in_driver(sdata); | ||
| 1095 | |||
| 1096 | trace_drv_join_ibss(local, sdata, &sdata->vif.bss_conf); | ||
| 1097 | if (local->ops->join_ibss) | ||
| 1098 | ret = local->ops->join_ibss(&local->hw, &sdata->vif); | ||
| 1099 | trace_drv_return_int(local, ret); | ||
| 1100 | return ret; | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | static inline void drv_leave_ibss(struct ieee80211_local *local, | ||
| 1104 | struct ieee80211_sub_if_data *sdata) | ||
| 1105 | { | ||
| 1106 | might_sleep(); | ||
| 1107 | check_sdata_in_driver(sdata); | ||
| 1108 | |||
| 1109 | trace_drv_leave_ibss(local, sdata); | ||
| 1110 | if (local->ops->leave_ibss) | ||
| 1111 | local->ops->leave_ibss(&local->hw, &sdata->vif); | ||
| 1112 | trace_drv_return_void(local); | ||
| 1113 | } | ||
| 1114 | |||
| 1088 | #endif /* __MAC80211_DRIVER_OPS */ | 1115 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index a12afe77bb26..21a0b8835cb3 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
| @@ -39,7 +39,8 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, | |||
| 39 | const int beacon_int, const u32 basic_rates, | 39 | const int beacon_int, const u32 basic_rates, |
| 40 | const u16 capability, u64 tsf, | 40 | const u16 capability, u64 tsf, |
| 41 | struct cfg80211_chan_def *chandef, | 41 | struct cfg80211_chan_def *chandef, |
| 42 | bool *have_higher_than_11mbit) | 42 | bool *have_higher_than_11mbit, |
| 43 | struct cfg80211_csa_settings *csa_settings) | ||
| 43 | { | 44 | { |
| 44 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 45 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
| 45 | struct ieee80211_local *local = sdata->local; | 46 | struct ieee80211_local *local = sdata->local; |
| @@ -59,6 +60,7 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, | |||
| 59 | 2 + 8 /* max Supported Rates */ + | 60 | 2 + 8 /* max Supported Rates */ + |
| 60 | 3 /* max DS params */ + | 61 | 3 /* max DS params */ + |
| 61 | 4 /* IBSS params */ + | 62 | 4 /* IBSS params */ + |
| 63 | 5 /* Channel Switch Announcement */ + | ||
| 62 | 2 + (IEEE80211_MAX_SUPP_RATES - 8) + | 64 | 2 + (IEEE80211_MAX_SUPP_RATES - 8) + |
| 63 | 2 + sizeof(struct ieee80211_ht_cap) + | 65 | 2 + sizeof(struct ieee80211_ht_cap) + |
| 64 | 2 + sizeof(struct ieee80211_ht_operation) + | 66 | 2 + sizeof(struct ieee80211_ht_operation) + |
| @@ -135,6 +137,16 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, | |||
| 135 | *pos++ = 0; | 137 | *pos++ = 0; |
| 136 | *pos++ = 0; | 138 | *pos++ = 0; |
| 137 | 139 | ||
| 140 | if (csa_settings) { | ||
| 141 | *pos++ = WLAN_EID_CHANNEL_SWITCH; | ||
| 142 | *pos++ = 3; | ||
| 143 | *pos++ = csa_settings->block_tx ? 1 : 0; | ||
| 144 | *pos++ = ieee80211_frequency_to_channel( | ||
| 145 | csa_settings->chandef.chan->center_freq); | ||
| 146 | sdata->csa_counter_offset_beacon = (pos - presp->head); | ||
| 147 | *pos++ = csa_settings->count; | ||
| 148 | } | ||
| 149 | |||
| 138 | /* put the remaining rates in WLAN_EID_EXT_SUPP_RATES */ | 150 | /* put the remaining rates in WLAN_EID_EXT_SUPP_RATES */ |
| 139 | if (rates_n > 8) { | 151 | if (rates_n > 8) { |
| 140 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 152 | *pos++ = WLAN_EID_EXT_SUPP_RATES; |
| @@ -217,6 +229,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 217 | struct beacon_data *presp; | 229 | struct beacon_data *presp; |
| 218 | enum nl80211_bss_scan_width scan_width; | 230 | enum nl80211_bss_scan_width scan_width; |
| 219 | bool have_higher_than_11mbit; | 231 | bool have_higher_than_11mbit; |
| 232 | int err; | ||
| 220 | 233 | ||
| 221 | sdata_assert_lock(sdata); | 234 | sdata_assert_lock(sdata); |
| 222 | 235 | ||
| @@ -235,6 +248,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 235 | ieee80211_bss_info_change_notify(sdata, | 248 | ieee80211_bss_info_change_notify(sdata, |
| 236 | BSS_CHANGED_IBSS | | 249 | BSS_CHANGED_IBSS | |
| 237 | BSS_CHANGED_BEACON_ENABLED); | 250 | BSS_CHANGED_BEACON_ENABLED); |
| 251 | drv_leave_ibss(local, sdata); | ||
| 238 | } | 252 | } |
| 239 | 253 | ||
| 240 | presp = rcu_dereference_protected(ifibss->presp, | 254 | presp = rcu_dereference_protected(ifibss->presp, |
| @@ -276,7 +290,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 276 | 290 | ||
| 277 | presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates, | 291 | presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates, |
| 278 | capability, tsf, &chandef, | 292 | capability, tsf, &chandef, |
| 279 | &have_higher_than_11mbit); | 293 | &have_higher_than_11mbit, NULL); |
| 280 | if (!presp) | 294 | if (!presp) |
| 281 | return; | 295 | return; |
| 282 | 296 | ||
| @@ -317,11 +331,26 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 317 | else | 331 | else |
| 318 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | 332 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; |
| 319 | 333 | ||
| 334 | ieee80211_set_wmm_default(sdata, true); | ||
| 335 | |||
| 320 | sdata->vif.bss_conf.ibss_joined = true; | 336 | sdata->vif.bss_conf.ibss_joined = true; |
| 321 | sdata->vif.bss_conf.ibss_creator = creator; | 337 | sdata->vif.bss_conf.ibss_creator = creator; |
| 322 | ieee80211_bss_info_change_notify(sdata, bss_change); | ||
| 323 | 338 | ||
| 324 | ieee80211_set_wmm_default(sdata, true); | 339 | err = drv_join_ibss(local, sdata); |
| 340 | if (err) { | ||
| 341 | sdata->vif.bss_conf.ibss_joined = false; | ||
| 342 | sdata->vif.bss_conf.ibss_creator = false; | ||
| 343 | sdata->vif.bss_conf.enable_beacon = false; | ||
| 344 | sdata->vif.bss_conf.ssid_len = 0; | ||
| 345 | RCU_INIT_POINTER(ifibss->presp, NULL); | ||
| 346 | kfree_rcu(presp, rcu_head); | ||
| 347 | ieee80211_vif_release_channel(sdata); | ||
| 348 | sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n", | ||
| 349 | err); | ||
| 350 | return; | ||
| 351 | } | ||
| 352 | |||
| 353 | ieee80211_bss_info_change_notify(sdata, bss_change); | ||
| 325 | 354 | ||
| 326 | ifibss->state = IEEE80211_IBSS_MLME_JOINED; | 355 | ifibss->state = IEEE80211_IBSS_MLME_JOINED; |
| 327 | mod_timer(&ifibss->timer, | 356 | mod_timer(&ifibss->timer, |
| @@ -416,6 +445,169 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 416 | tsf, false); | 445 | tsf, false); |
| 417 | } | 446 | } |
| 418 | 447 | ||
| 448 | static int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, | ||
| 449 | struct cfg80211_csa_settings *csa_settings) | ||
| 450 | { | ||
| 451 | struct sk_buff *skb; | ||
| 452 | struct ieee80211_mgmt *mgmt; | ||
| 453 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
| 454 | struct ieee80211_local *local = sdata->local; | ||
| 455 | int freq; | ||
| 456 | int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.chan_switch) + | ||
| 457 | sizeof(mgmt->u.action.u.chan_switch); | ||
| 458 | u8 *pos; | ||
| 459 | |||
| 460 | skb = dev_alloc_skb(local->tx_headroom + hdr_len + | ||
| 461 | 5 + /* channel switch announcement element */ | ||
| 462 | 3); /* secondary channel offset element */ | ||
| 463 | if (!skb) | ||
| 464 | return -1; | ||
| 465 | |||
| 466 | skb_reserve(skb, local->tx_headroom); | ||
| 467 | mgmt = (struct ieee80211_mgmt *)skb_put(skb, hdr_len); | ||
| 468 | memset(mgmt, 0, hdr_len); | ||
| 469 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
| 470 | IEEE80211_STYPE_ACTION); | ||
| 471 | |||
| 472 | eth_broadcast_addr(mgmt->da); | ||
| 473 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
| 474 | memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); | ||
| 475 | mgmt->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT; | ||
| 476 | mgmt->u.action.u.chan_switch.action_code = WLAN_ACTION_SPCT_CHL_SWITCH; | ||
| 477 | pos = skb_put(skb, 5); | ||
| 478 | *pos++ = WLAN_EID_CHANNEL_SWITCH; /* EID */ | ||
| 479 | *pos++ = 3; /* IE length */ | ||
| 480 | *pos++ = csa_settings->block_tx ? 1 : 0; /* CSA mode */ | ||
| 481 | freq = csa_settings->chandef.chan->center_freq; | ||
| 482 | *pos++ = ieee80211_frequency_to_channel(freq); /* channel */ | ||
| 483 | *pos++ = csa_settings->count; /* count */ | ||
| 484 | |||
| 485 | if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_40) { | ||
| 486 | enum nl80211_channel_type ch_type; | ||
| 487 | |||
| 488 | skb_put(skb, 3); | ||
| 489 | *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */ | ||
| 490 | *pos++ = 1; /* IE length */ | ||
| 491 | ch_type = cfg80211_get_chandef_type(&csa_settings->chandef); | ||
| 492 | if (ch_type == NL80211_CHAN_HT40PLUS) | ||
| 493 | *pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | ||
| 494 | else | ||
| 495 | *pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW; | ||
| 496 | } | ||
| 497 | |||
| 498 | ieee80211_tx_skb(sdata, skb); | ||
| 499 | return 0; | ||
| 500 | } | ||
| 501 | |||
| 502 | int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, | ||
| 503 | struct cfg80211_csa_settings *csa_settings) | ||
| 504 | { | ||
| 505 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
| 506 | struct beacon_data *presp, *old_presp; | ||
| 507 | struct cfg80211_bss *cbss; | ||
| 508 | const struct cfg80211_bss_ies *ies; | ||
| 509 | u16 capability; | ||
| 510 | u64 tsf; | ||
| 511 | int ret = 0; | ||
| 512 | |||
| 513 | sdata_assert_lock(sdata); | ||
| 514 | |||
| 515 | capability = WLAN_CAPABILITY_IBSS; | ||
| 516 | |||
| 517 | if (ifibss->privacy) | ||
| 518 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
| 519 | |||
| 520 | cbss = cfg80211_get_bss(sdata->local->hw.wiphy, ifibss->chandef.chan, | ||
| 521 | ifibss->bssid, ifibss->ssid, | ||
| 522 | ifibss->ssid_len, WLAN_CAPABILITY_IBSS | | ||
| 523 | WLAN_CAPABILITY_PRIVACY, | ||
| 524 | capability); | ||
| 525 | |||
| 526 | if (WARN_ON(!cbss)) { | ||
| 527 | ret = -EINVAL; | ||
| 528 | goto out; | ||
| 529 | } | ||
| 530 | |||
| 531 | rcu_read_lock(); | ||
| 532 | ies = rcu_dereference(cbss->ies); | ||
| 533 | tsf = ies->tsf; | ||
| 534 | rcu_read_unlock(); | ||
| 535 | cfg80211_put_bss(sdata->local->hw.wiphy, cbss); | ||
| 536 | |||
| 537 | old_presp = rcu_dereference_protected(ifibss->presp, | ||
| 538 | lockdep_is_held(&sdata->wdev.mtx)); | ||
| 539 | |||
| 540 | presp = ieee80211_ibss_build_presp(sdata, | ||
| 541 | sdata->vif.bss_conf.beacon_int, | ||
| 542 | sdata->vif.bss_conf.basic_rates, | ||
| 543 | capability, tsf, &ifibss->chandef, | ||
| 544 | NULL, csa_settings); | ||
| 545 | if (!presp) { | ||
| 546 | ret = -ENOMEM; | ||
| 547 | goto out; | ||
| 548 | } | ||
| 549 | |||
| 550 | rcu_assign_pointer(ifibss->presp, presp); | ||
| 551 | if (old_presp) | ||
| 552 | kfree_rcu(old_presp, rcu_head); | ||
| 553 | |||
| 554 | /* it might not send the beacon for a while. send an action frame | ||
| 555 | * immediately to announce the channel switch. | ||
| 556 | */ | ||
| 557 | if (csa_settings) | ||
| 558 | ieee80211_send_action_csa(sdata, csa_settings); | ||
| 559 | |||
| 560 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
| 561 | out: | ||
| 562 | return ret; | ||
| 563 | } | ||
| 564 | |||
| 565 | int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) | ||
| 566 | { | ||
| 567 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
| 568 | struct cfg80211_bss *cbss; | ||
| 569 | int err; | ||
| 570 | u16 capability; | ||
| 571 | |||
| 572 | sdata_lock(sdata); | ||
| 573 | /* update cfg80211 bss information with the new channel */ | ||
| 574 | if (!is_zero_ether_addr(ifibss->bssid)) { | ||
| 575 | capability = WLAN_CAPABILITY_IBSS; | ||
| 576 | |||
| 577 | if (ifibss->privacy) | ||
| 578 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
| 579 | |||
| 580 | cbss = cfg80211_get_bss(sdata->local->hw.wiphy, | ||
| 581 | ifibss->chandef.chan, | ||
| 582 | ifibss->bssid, ifibss->ssid, | ||
| 583 | ifibss->ssid_len, WLAN_CAPABILITY_IBSS | | ||
| 584 | WLAN_CAPABILITY_PRIVACY, | ||
| 585 | capability); | ||
| 586 | /* XXX: should not really modify cfg80211 data */ | ||
| 587 | if (cbss) { | ||
| 588 | cbss->channel = sdata->local->csa_chandef.chan; | ||
| 589 | cfg80211_put_bss(sdata->local->hw.wiphy, cbss); | ||
| 590 | } | ||
| 591 | } | ||
| 592 | |||
| 593 | ifibss->chandef = sdata->local->csa_chandef; | ||
| 594 | |||
| 595 | /* generate the beacon */ | ||
| 596 | err = ieee80211_ibss_csa_beacon(sdata, NULL); | ||
| 597 | sdata_unlock(sdata); | ||
| 598 | if (err < 0) | ||
| 599 | return err; | ||
| 600 | |||
| 601 | return 0; | ||
| 602 | } | ||
| 603 | |||
| 604 | void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata) | ||
| 605 | { | ||
| 606 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
| 607 | |||
| 608 | cancel_work_sync(&ifibss->csa_connection_drop_work); | ||
| 609 | } | ||
| 610 | |||
| 419 | static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta) | 611 | static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta) |
| 420 | __acquires(RCU) | 612 | __acquires(RCU) |
| 421 | { | 613 | { |
| @@ -499,6 +691,295 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid, | |||
| 499 | return ieee80211_ibss_finish_sta(sta); | 691 | return ieee80211_ibss_finish_sta(sta); |
| 500 | } | 692 | } |
| 501 | 693 | ||
| 694 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | ||
| 695 | { | ||
| 696 | struct ieee80211_local *local = sdata->local; | ||
| 697 | int active = 0; | ||
| 698 | struct sta_info *sta; | ||
| 699 | |||
| 700 | sdata_assert_lock(sdata); | ||
| 701 | |||
| 702 | rcu_read_lock(); | ||
| 703 | |||
| 704 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
| 705 | if (sta->sdata == sdata && | ||
| 706 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, | ||
| 707 | jiffies)) { | ||
| 708 | active++; | ||
| 709 | break; | ||
| 710 | } | ||
| 711 | } | ||
| 712 | |||
| 713 | rcu_read_unlock(); | ||
| 714 | |||
| 715 | return active; | ||
| 716 | } | ||
| 717 | |||
| 718 | static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) | ||
| 719 | { | ||
| 720 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
| 721 | struct ieee80211_local *local = sdata->local; | ||
| 722 | struct cfg80211_bss *cbss; | ||
| 723 | struct beacon_data *presp; | ||
| 724 | struct sta_info *sta; | ||
| 725 | int active_ibss; | ||
| 726 | u16 capability; | ||
| 727 | |||
| 728 | active_ibss = ieee80211_sta_active_ibss(sdata); | ||
| 729 | |||
| 730 | if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) { | ||
| 731 | capability = WLAN_CAPABILITY_IBSS; | ||
| 732 | |||
| 733 | if (ifibss->privacy) | ||
| 734 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
| 735 | |||
| 736 | cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan, | ||
| 737 | ifibss->bssid, ifibss->ssid, | ||
| 738 | ifibss->ssid_len, WLAN_CAPABILITY_IBSS | | ||
| 739 | WLAN_CAPABILITY_PRIVACY, | ||
| 740 | capability); | ||
| 741 | |||
| 742 | if (cbss) { | ||
| 743 | cfg80211_unlink_bss(local->hw.wiphy, cbss); | ||
| 744 | cfg80211_put_bss(sdata->local->hw.wiphy, cbss); | ||
| 745 | } | ||
| 746 | } | ||
| 747 | |||
| 748 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; | ||
| 749 | |||
| 750 | sta_info_flush(sdata); | ||
| 751 | |||
| 752 | spin_lock_bh(&ifibss->incomplete_lock); | ||
| 753 | while (!list_empty(&ifibss->incomplete_stations)) { | ||
| 754 | sta = list_first_entry(&ifibss->incomplete_stations, | ||
| 755 | struct sta_info, list); | ||
| 756 | list_del(&sta->list); | ||
| 757 | spin_unlock_bh(&ifibss->incomplete_lock); | ||
| 758 | |||
| 759 | sta_info_free(local, sta); | ||
| 760 | spin_lock_bh(&ifibss->incomplete_lock); | ||
| 761 | } | ||
| 762 | spin_unlock_bh(&ifibss->incomplete_lock); | ||
| 763 | |||
| 764 | netif_carrier_off(sdata->dev); | ||
| 765 | |||
| 766 | sdata->vif.bss_conf.ibss_joined = false; | ||
| 767 | sdata->vif.bss_conf.ibss_creator = false; | ||
| 768 | sdata->vif.bss_conf.enable_beacon = false; | ||
| 769 | sdata->vif.bss_conf.ssid_len = 0; | ||
| 770 | |||
| 771 | /* remove beacon */ | ||
| 772 | presp = rcu_dereference_protected(ifibss->presp, | ||
| 773 | lockdep_is_held(&sdata->wdev.mtx)); | ||
| 774 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); | ||
| 775 | if (presp) | ||
| 776 | kfree_rcu(presp, rcu_head); | ||
| 777 | |||
| 778 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | ||
| 779 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | | ||
| 780 | BSS_CHANGED_IBSS); | ||
| 781 | drv_leave_ibss(local, sdata); | ||
| 782 | ieee80211_vif_release_channel(sdata); | ||
| 783 | } | ||
| 784 | |||
| 785 | static void ieee80211_csa_connection_drop_work(struct work_struct *work) | ||
| 786 | { | ||
| 787 | struct ieee80211_sub_if_data *sdata = | ||
| 788 | container_of(work, struct ieee80211_sub_if_data, | ||
| 789 | u.ibss.csa_connection_drop_work); | ||
| 790 | |||
| 791 | ieee80211_ibss_disconnect(sdata); | ||
| 792 | synchronize_rcu(); | ||
| 793 | skb_queue_purge(&sdata->skb_queue); | ||
| 794 | |||
| 795 | /* trigger a scan to find another IBSS network to join */ | ||
| 796 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); | ||
| 797 | } | ||
| 798 | |||
| 799 | static bool | ||
| 800 | ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, | ||
| 801 | struct ieee802_11_elems *elems, | ||
| 802 | bool beacon) | ||
| 803 | { | ||
| 804 | struct cfg80211_csa_settings params; | ||
| 805 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
| 806 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 807 | struct ieee80211_chanctx *chanctx; | ||
| 808 | enum nl80211_channel_type ch_type; | ||
| 809 | int err, num_chanctx; | ||
| 810 | u32 sta_flags; | ||
| 811 | u8 mode; | ||
| 812 | |||
| 813 | if (sdata->vif.csa_active) | ||
| 814 | return true; | ||
| 815 | |||
| 816 | if (!sdata->vif.bss_conf.ibss_joined) | ||
| 817 | return false; | ||
| 818 | |||
| 819 | sta_flags = IEEE80211_STA_DISABLE_VHT; | ||
| 820 | switch (ifibss->chandef.width) { | ||
| 821 | case NL80211_CHAN_WIDTH_5: | ||
| 822 | case NL80211_CHAN_WIDTH_10: | ||
| 823 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
| 824 | sta_flags |= IEEE80211_STA_DISABLE_HT; | ||
| 825 | /* fall through */ | ||
| 826 | case NL80211_CHAN_WIDTH_20: | ||
| 827 | sta_flags |= IEEE80211_STA_DISABLE_40MHZ; | ||
| 828 | break; | ||
| 829 | default: | ||
| 830 | break; | ||
| 831 | } | ||
| 832 | |||
| 833 | memset(¶ms, 0, sizeof(params)); | ||
| 834 | err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, | ||
| 835 | ifibss->chandef.chan->band, | ||
| 836 | sta_flags, ifibss->bssid, | ||
| 837 | ¶ms.count, &mode, | ||
| 838 | ¶ms.chandef); | ||
| 839 | |||
| 840 | /* can't switch to destination channel, fail */ | ||
| 841 | if (err < 0) | ||
| 842 | goto disconnect; | ||
| 843 | |||
| 844 | /* did not contain a CSA */ | ||
| 845 | if (err) | ||
| 846 | return false; | ||
| 847 | |||
| 848 | if (ifibss->chandef.chan->band != params.chandef.chan->band) | ||
| 849 | goto disconnect; | ||
| 850 | |||
| 851 | switch (ifibss->chandef.width) { | ||
| 852 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
| 853 | case NL80211_CHAN_WIDTH_20: | ||
| 854 | case NL80211_CHAN_WIDTH_40: | ||
| 855 | /* keep our current HT mode (HT20/HT40+/HT40-), even if | ||
| 856 | * another mode has been announced. The mode is not adopted | ||
| 857 | * within the beacon while doing CSA and we should therefore | ||
| 858 | * keep the mode which we announce. | ||
| 859 | */ | ||
| 860 | ch_type = cfg80211_get_chandef_type(&ifibss->chandef); | ||
| 861 | cfg80211_chandef_create(¶ms.chandef, params.chandef.chan, | ||
| 862 | ch_type); | ||
| 863 | break; | ||
| 864 | case NL80211_CHAN_WIDTH_5: | ||
| 865 | case NL80211_CHAN_WIDTH_10: | ||
| 866 | if (params.chandef.width != ifibss->chandef.width) { | ||
| 867 | sdata_info(sdata, | ||
| 868 | "IBSS %pM received channel switch from incompatible channel width (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", | ||
| 869 | ifibss->bssid, | ||
| 870 | params.chandef.chan->center_freq, | ||
| 871 | params.chandef.width, | ||
| 872 | params.chandef.center_freq1, | ||
| 873 | params.chandef.center_freq2); | ||
| 874 | goto disconnect; | ||
| 875 | } | ||
| 876 | break; | ||
| 877 | default: | ||
| 878 | /* should not happen, sta_flags should prevent VHT modes. */ | ||
| 879 | WARN_ON(1); | ||
| 880 | goto disconnect; | ||
| 881 | } | ||
| 882 | |||
| 883 | if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, ¶ms.chandef, | ||
| 884 | IEEE80211_CHAN_DISABLED)) { | ||
| 885 | sdata_info(sdata, | ||
| 886 | "IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", | ||
| 887 | ifibss->bssid, | ||
| 888 | params.chandef.chan->center_freq, | ||
| 889 | params.chandef.width, | ||
| 890 | params.chandef.center_freq1, | ||
| 891 | params.chandef.center_freq2); | ||
| 892 | goto disconnect; | ||
| 893 | } | ||
| 894 | |||
| 895 | err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, | ||
| 896 | ¶ms.chandef); | ||
| 897 | if (err < 0) | ||
| 898 | goto disconnect; | ||
| 899 | if (err) { | ||
| 900 | params.radar_required = true; | ||
| 901 | |||
| 902 | /* TODO: IBSS-DFS not (yet) supported, disconnect. */ | ||
| 903 | goto disconnect; | ||
| 904 | } | ||
| 905 | |||
| 906 | rcu_read_lock(); | ||
| 907 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 908 | if (!chanctx_conf) { | ||
| 909 | rcu_read_unlock(); | ||
| 910 | goto disconnect; | ||
| 911 | } | ||
| 912 | |||
| 913 | /* don't handle for multi-VIF cases */ | ||
| 914 | chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); | ||
| 915 | if (chanctx->refcount > 1) { | ||
| 916 | rcu_read_unlock(); | ||
| 917 | goto disconnect; | ||
| 918 | } | ||
| 919 | num_chanctx = 0; | ||
| 920 | list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list) | ||
| 921 | num_chanctx++; | ||
| 922 | |||
| 923 | if (num_chanctx > 1) { | ||
| 924 | rcu_read_unlock(); | ||
| 925 | goto disconnect; | ||
| 926 | } | ||
| 927 | rcu_read_unlock(); | ||
| 928 | |||
| 929 | /* all checks done, now perform the channel switch. */ | ||
| 930 | ibss_dbg(sdata, | ||
| 931 | "received channel switch announcement to go to channel %d MHz\n", | ||
| 932 | params.chandef.chan->center_freq); | ||
| 933 | |||
| 934 | params.block_tx = !!mode; | ||
| 935 | |||
| 936 | ieee80211_ibss_csa_beacon(sdata, ¶ms); | ||
| 937 | sdata->csa_radar_required = params.radar_required; | ||
| 938 | |||
| 939 | if (params.block_tx) | ||
| 940 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||
| 941 | IEEE80211_MAX_QUEUE_MAP, | ||
| 942 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
| 943 | |||
| 944 | sdata->local->csa_chandef = params.chandef; | ||
| 945 | sdata->vif.csa_active = true; | ||
| 946 | |||
| 947 | ieee80211_bss_info_change_notify(sdata, err); | ||
| 948 | drv_channel_switch_beacon(sdata, ¶ms.chandef); | ||
| 949 | |||
| 950 | return true; | ||
| 951 | disconnect: | ||
| 952 | ibss_dbg(sdata, "Can't handle channel switch, disconnect\n"); | ||
| 953 | ieee80211_queue_work(&sdata->local->hw, | ||
| 954 | &ifibss->csa_connection_drop_work); | ||
| 955 | |||
| 956 | return true; | ||
| 957 | } | ||
| 958 | |||
| 959 | static void | ||
| 960 | ieee80211_rx_mgmt_spectrum_mgmt(struct ieee80211_sub_if_data *sdata, | ||
| 961 | struct ieee80211_mgmt *mgmt, size_t len, | ||
| 962 | struct ieee80211_rx_status *rx_status, | ||
| 963 | struct ieee802_11_elems *elems) | ||
| 964 | { | ||
| 965 | int required_len; | ||
| 966 | |||
| 967 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | ||
| 968 | return; | ||
| 969 | |||
| 970 | /* CSA is the only action we handle for now */ | ||
| 971 | if (mgmt->u.action.u.measurement.action_code != | ||
| 972 | WLAN_ACTION_SPCT_CHL_SWITCH) | ||
| 973 | return; | ||
| 974 | |||
| 975 | required_len = IEEE80211_MIN_ACTION_SIZE + | ||
| 976 | sizeof(mgmt->u.action.u.chan_switch); | ||
| 977 | if (len < required_len) | ||
| 978 | return; | ||
| 979 | |||
| 980 | ieee80211_ibss_process_chanswitch(sdata, elems, false); | ||
| 981 | } | ||
| 982 | |||
| 502 | static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, | 983 | static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, |
| 503 | struct ieee80211_mgmt *mgmt, | 984 | struct ieee80211_mgmt *mgmt, |
| 504 | size_t len) | 985 | size_t len) |
| @@ -661,10 +1142,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 661 | 1142 | ||
| 662 | /* check if we need to merge IBSS */ | 1143 | /* check if we need to merge IBSS */ |
| 663 | 1144 | ||
| 664 | /* we use a fixed BSSID */ | ||
| 665 | if (sdata->u.ibss.fixed_bssid) | ||
| 666 | goto put_bss; | ||
| 667 | |||
| 668 | /* not an IBSS */ | 1145 | /* not an IBSS */ |
| 669 | if (!(cbss->capability & WLAN_CAPABILITY_IBSS)) | 1146 | if (!(cbss->capability & WLAN_CAPABILITY_IBSS)) |
| 670 | goto put_bss; | 1147 | goto put_bss; |
| @@ -680,10 +1157,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 680 | sdata->u.ibss.ssid_len)) | 1157 | sdata->u.ibss.ssid_len)) |
| 681 | goto put_bss; | 1158 | goto put_bss; |
| 682 | 1159 | ||
| 1160 | /* process channel switch */ | ||
| 1161 | if (ieee80211_ibss_process_chanswitch(sdata, elems, true)) | ||
| 1162 | goto put_bss; | ||
| 1163 | |||
| 683 | /* same BSSID */ | 1164 | /* same BSSID */ |
| 684 | if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid)) | 1165 | if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid)) |
| 685 | goto put_bss; | 1166 | goto put_bss; |
| 686 | 1167 | ||
| 1168 | /* we use a fixed BSSID */ | ||
| 1169 | if (sdata->u.ibss.fixed_bssid) | ||
| 1170 | goto put_bss; | ||
| 1171 | |||
| 687 | if (ieee80211_have_rx_timestamp(rx_status)) { | 1172 | if (ieee80211_have_rx_timestamp(rx_status)) { |
| 688 | /* time when timestamp field was received */ | 1173 | /* time when timestamp field was received */ |
| 689 | rx_timestamp = | 1174 | rx_timestamp = |
| @@ -775,30 +1260,6 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |||
| 775 | ieee80211_queue_work(&local->hw, &sdata->work); | 1260 | ieee80211_queue_work(&local->hw, &sdata->work); |
| 776 | } | 1261 | } |
| 777 | 1262 | ||
| 778 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | ||
| 779 | { | ||
| 780 | struct ieee80211_local *local = sdata->local; | ||
| 781 | int active = 0; | ||
| 782 | struct sta_info *sta; | ||
| 783 | |||
| 784 | sdata_assert_lock(sdata); | ||
| 785 | |||
| 786 | rcu_read_lock(); | ||
| 787 | |||
| 788 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
| 789 | if (sta->sdata == sdata && | ||
| 790 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, | ||
| 791 | jiffies)) { | ||
| 792 | active++; | ||
| 793 | break; | ||
| 794 | } | ||
| 795 | } | ||
| 796 | |||
| 797 | rcu_read_unlock(); | ||
| 798 | |||
| 799 | return active; | ||
| 800 | } | ||
| 801 | |||
| 802 | static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata) | 1263 | static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata) |
| 803 | { | 1264 | { |
| 804 | struct ieee80211_local *local = sdata->local; | 1265 | struct ieee80211_local *local = sdata->local; |
| @@ -1076,6 +1537,8 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 1076 | struct ieee80211_rx_status *rx_status; | 1537 | struct ieee80211_rx_status *rx_status; |
| 1077 | struct ieee80211_mgmt *mgmt; | 1538 | struct ieee80211_mgmt *mgmt; |
| 1078 | u16 fc; | 1539 | u16 fc; |
| 1540 | struct ieee802_11_elems elems; | ||
| 1541 | int ies_len; | ||
| 1079 | 1542 | ||
| 1080 | rx_status = IEEE80211_SKB_RXCB(skb); | 1543 | rx_status = IEEE80211_SKB_RXCB(skb); |
| 1081 | mgmt = (struct ieee80211_mgmt *) skb->data; | 1544 | mgmt = (struct ieee80211_mgmt *) skb->data; |
| @@ -1101,6 +1564,27 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 1101 | case IEEE80211_STYPE_DEAUTH: | 1564 | case IEEE80211_STYPE_DEAUTH: |
| 1102 | ieee80211_rx_mgmt_deauth_ibss(sdata, mgmt, skb->len); | 1565 | ieee80211_rx_mgmt_deauth_ibss(sdata, mgmt, skb->len); |
| 1103 | break; | 1566 | break; |
| 1567 | case IEEE80211_STYPE_ACTION: | ||
| 1568 | switch (mgmt->u.action.category) { | ||
| 1569 | case WLAN_CATEGORY_SPECTRUM_MGMT: | ||
| 1570 | ies_len = skb->len - | ||
| 1571 | offsetof(struct ieee80211_mgmt, | ||
| 1572 | u.action.u.chan_switch.variable); | ||
| 1573 | |||
| 1574 | if (ies_len < 0) | ||
| 1575 | break; | ||
| 1576 | |||
| 1577 | ieee802_11_parse_elems( | ||
| 1578 | mgmt->u.action.u.chan_switch.variable, | ||
| 1579 | ies_len, true, &elems); | ||
| 1580 | |||
| 1581 | if (elems.parse_error) | ||
| 1582 | break; | ||
| 1583 | |||
| 1584 | ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len, | ||
| 1585 | rx_status, &elems); | ||
| 1586 | break; | ||
| 1587 | } | ||
| 1104 | } | 1588 | } |
| 1105 | 1589 | ||
| 1106 | mgmt_out: | 1590 | mgmt_out: |
| @@ -1167,6 +1651,8 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
| 1167 | (unsigned long) sdata); | 1651 | (unsigned long) sdata); |
| 1168 | INIT_LIST_HEAD(&ifibss->incomplete_stations); | 1652 | INIT_LIST_HEAD(&ifibss->incomplete_stations); |
| 1169 | spin_lock_init(&ifibss->incomplete_lock); | 1653 | spin_lock_init(&ifibss->incomplete_lock); |
| 1654 | INIT_WORK(&ifibss->csa_connection_drop_work, | ||
| 1655 | ieee80211_csa_connection_drop_work); | ||
| 1170 | } | 1656 | } |
| 1171 | 1657 | ||
| 1172 | /* scan finished notification */ | 1658 | /* scan finished notification */ |
| @@ -1265,73 +1751,19 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
| 1265 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | 1751 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) |
| 1266 | { | 1752 | { |
| 1267 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 1753 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
| 1268 | struct ieee80211_local *local = sdata->local; | ||
| 1269 | struct cfg80211_bss *cbss; | ||
| 1270 | u16 capability; | ||
| 1271 | int active_ibss; | ||
| 1272 | struct sta_info *sta; | ||
| 1273 | struct beacon_data *presp; | ||
| 1274 | |||
| 1275 | active_ibss = ieee80211_sta_active_ibss(sdata); | ||
| 1276 | |||
| 1277 | if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) { | ||
| 1278 | capability = WLAN_CAPABILITY_IBSS; | ||
| 1279 | |||
| 1280 | if (ifibss->privacy) | ||
| 1281 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
| 1282 | |||
| 1283 | cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan, | ||
| 1284 | ifibss->bssid, ifibss->ssid, | ||
| 1285 | ifibss->ssid_len, WLAN_CAPABILITY_IBSS | | ||
| 1286 | WLAN_CAPABILITY_PRIVACY, | ||
| 1287 | capability); | ||
| 1288 | 1754 | ||
| 1289 | if (cbss) { | 1755 | ieee80211_ibss_disconnect(sdata); |
| 1290 | cfg80211_unlink_bss(local->hw.wiphy, cbss); | ||
| 1291 | cfg80211_put_bss(local->hw.wiphy, cbss); | ||
| 1292 | } | ||
| 1293 | } | ||
| 1294 | |||
| 1295 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; | ||
| 1296 | memset(ifibss->bssid, 0, ETH_ALEN); | ||
| 1297 | ifibss->ssid_len = 0; | 1756 | ifibss->ssid_len = 0; |
| 1298 | 1757 | memset(ifibss->bssid, 0, ETH_ALEN); | |
| 1299 | sta_info_flush(sdata); | ||
| 1300 | |||
| 1301 | spin_lock_bh(&ifibss->incomplete_lock); | ||
| 1302 | while (!list_empty(&ifibss->incomplete_stations)) { | ||
| 1303 | sta = list_first_entry(&ifibss->incomplete_stations, | ||
| 1304 | struct sta_info, list); | ||
| 1305 | list_del(&sta->list); | ||
| 1306 | spin_unlock_bh(&ifibss->incomplete_lock); | ||
| 1307 | |||
| 1308 | sta_info_free(local, sta); | ||
| 1309 | spin_lock_bh(&ifibss->incomplete_lock); | ||
| 1310 | } | ||
| 1311 | spin_unlock_bh(&ifibss->incomplete_lock); | ||
| 1312 | |||
| 1313 | netif_carrier_off(sdata->dev); | ||
| 1314 | 1758 | ||
| 1315 | /* remove beacon */ | 1759 | /* remove beacon */ |
| 1316 | kfree(sdata->u.ibss.ie); | 1760 | kfree(sdata->u.ibss.ie); |
| 1317 | presp = rcu_dereference_protected(ifibss->presp, | ||
| 1318 | lockdep_is_held(&sdata->wdev.mtx)); | ||
| 1319 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); | ||
| 1320 | 1761 | ||
| 1321 | /* on the next join, re-program HT parameters */ | 1762 | /* on the next join, re-program HT parameters */ |
| 1322 | memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa)); | 1763 | memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa)); |
| 1323 | memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask)); | 1764 | memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask)); |
| 1324 | 1765 | ||
| 1325 | sdata->vif.bss_conf.ibss_joined = false; | ||
| 1326 | sdata->vif.bss_conf.ibss_creator = false; | ||
| 1327 | sdata->vif.bss_conf.enable_beacon = false; | ||
| 1328 | sdata->vif.bss_conf.ssid_len = 0; | ||
| 1329 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | ||
| 1330 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | | ||
| 1331 | BSS_CHANGED_IBSS); | ||
| 1332 | ieee80211_vif_release_channel(sdata); | ||
| 1333 | synchronize_rcu(); | 1766 | synchronize_rcu(); |
| 1334 | kfree(presp); | ||
| 1335 | 1767 | ||
| 1336 | skb_queue_purge(&sdata->skb_queue); | 1768 | skb_queue_purge(&sdata->skb_queue); |
| 1337 | 1769 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b6186517ec56..3a87c8976a32 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
| @@ -322,7 +322,6 @@ struct ieee80211_roc_work { | |||
| 322 | 322 | ||
| 323 | /* flags used in struct ieee80211_if_managed.flags */ | 323 | /* flags used in struct ieee80211_if_managed.flags */ |
| 324 | enum ieee80211_sta_flags { | 324 | enum ieee80211_sta_flags { |
| 325 | IEEE80211_STA_BEACON_POLL = BIT(0), | ||
| 326 | IEEE80211_STA_CONNECTION_POLL = BIT(1), | 325 | IEEE80211_STA_CONNECTION_POLL = BIT(1), |
| 327 | IEEE80211_STA_CONTROL_PORT = BIT(2), | 326 | IEEE80211_STA_CONTROL_PORT = BIT(2), |
| 328 | IEEE80211_STA_DISABLE_HT = BIT(4), | 327 | IEEE80211_STA_DISABLE_HT = BIT(4), |
| @@ -487,6 +486,7 @@ struct ieee80211_if_managed { | |||
| 487 | 486 | ||
| 488 | struct ieee80211_if_ibss { | 487 | struct ieee80211_if_ibss { |
| 489 | struct timer_list timer; | 488 | struct timer_list timer; |
| 489 | struct work_struct csa_connection_drop_work; | ||
| 490 | 490 | ||
| 491 | unsigned long last_scan_completed; | 491 | unsigned long last_scan_completed; |
| 492 | 492 | ||
| @@ -1330,6 +1330,10 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); | |||
| 1330 | void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata); | 1330 | void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata); |
| 1331 | void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1331 | void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
| 1332 | struct sk_buff *skb); | 1332 | struct sk_buff *skb); |
| 1333 | int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, | ||
| 1334 | struct cfg80211_csa_settings *csa_settings); | ||
| 1335 | int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata); | ||
| 1336 | void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata); | ||
| 1333 | 1337 | ||
| 1334 | /* mesh code */ | 1338 | /* mesh code */ |
| 1335 | void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata); | 1339 | void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata); |
| @@ -1481,6 +1485,29 @@ void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, | |||
| 1481 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1485 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
| 1482 | struct ieee80211_mgmt *mgmt, | 1486 | struct ieee80211_mgmt *mgmt, |
| 1483 | size_t len); | 1487 | size_t len); |
| 1488 | /** | ||
| 1489 | * ieee80211_parse_ch_switch_ie - parses channel switch IEs | ||
| 1490 | * @sdata: the sdata of the interface which has received the frame | ||
| 1491 | * @elems: parsed 802.11 elements received with the frame | ||
| 1492 | * @beacon: indicates if the frame was a beacon or probe response | ||
| 1493 | * @current_band: indicates the current band | ||
| 1494 | * @sta_flags: contains information about own capabilities and restrictions | ||
| 1495 | * to decide which channel switch announcements can be accepted. Only the | ||
| 1496 | * following subset of &enum ieee80211_sta_flags are evaluated: | ||
| 1497 | * %IEEE80211_STA_DISABLE_HT, %IEEE80211_STA_DISABLE_VHT, | ||
| 1498 | * %IEEE80211_STA_DISABLE_40MHZ, %IEEE80211_STA_DISABLE_80P80MHZ, | ||
| 1499 | * %IEEE80211_STA_DISABLE_160MHZ. | ||
| 1500 | * @count: to be filled with the counter until the switch (on success only) | ||
| 1501 | * @bssid: the currently connected bssid (for reporting) | ||
| 1502 | * @mode: to be filled with CSA mode (on success only) | ||
| 1503 | * @new_chandef: to be filled with destination chandef (on success only) | ||
| 1504 | * Return: 0 on success, <0 on error and >0 if there is nothing to parse. | ||
| 1505 | */ | ||
| 1506 | int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, | ||
| 1507 | struct ieee802_11_elems *elems, bool beacon, | ||
| 1508 | enum ieee80211_band current_band, | ||
| 1509 | u32 sta_flags, u8 *bssid, u8 *count, u8 *mode, | ||
| 1510 | struct cfg80211_chan_def *new_chandef); | ||
| 1484 | 1511 | ||
| 1485 | /* Suspend/resume and hw reconfiguration */ | 1512 | /* Suspend/resume and hw reconfiguration */ |
| 1486 | int ieee80211_reconfig(struct ieee80211_local *local); | 1513 | int ieee80211_reconfig(struct ieee80211_local *local); |
| @@ -1654,6 +1681,7 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | |||
| 1654 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, | 1681 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, |
| 1655 | const struct ieee80211_ht_operation *ht_oper, | 1682 | const struct ieee80211_ht_operation *ht_oper, |
| 1656 | struct cfg80211_chan_def *chandef); | 1683 | struct cfg80211_chan_def *chandef); |
| 1684 | u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c); | ||
| 1657 | 1685 | ||
| 1658 | int __must_check | 1686 | int __must_check |
| 1659 | ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | 1687 | ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index fcecd633514e..e48f103b9ade 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -766,6 +766,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 766 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 766 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
| 767 | ieee80211_mgd_stop(sdata); | 767 | ieee80211_mgd_stop(sdata); |
| 768 | 768 | ||
| 769 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
| 770 | ieee80211_ibss_stop(sdata); | ||
| 771 | |||
| 772 | |||
| 769 | /* | 773 | /* |
| 770 | * Remove all stations associated with this interface. | 774 | * Remove all stations associated with this interface. |
| 771 | * | 775 | * |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 620677e897bd..3e51dd7d98b3 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
| @@ -879,7 +879,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, | |||
| 879 | keyconf->keylen, keyconf->key, | 879 | keyconf->keylen, keyconf->key, |
| 880 | 0, NULL); | 880 | 0, NULL); |
| 881 | if (IS_ERR(key)) | 881 | if (IS_ERR(key)) |
| 882 | return ERR_PTR(PTR_ERR(key)); | 882 | return ERR_CAST(key); |
| 883 | 883 | ||
| 884 | if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED) | 884 | if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED) |
| 885 | key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; | 885 | key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 86e4ad56b573..91cc8281e266 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
| @@ -145,66 +145,6 @@ static int ecw2cw(int ecw) | |||
| 145 | return (1 << ecw) - 1; | 145 | return (1 << ecw) - 1; |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | static u32 chandef_downgrade(struct cfg80211_chan_def *c) | ||
| 149 | { | ||
| 150 | u32 ret; | ||
| 151 | int tmp; | ||
| 152 | |||
| 153 | switch (c->width) { | ||
| 154 | case NL80211_CHAN_WIDTH_20: | ||
| 155 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 156 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 157 | break; | ||
| 158 | case NL80211_CHAN_WIDTH_40: | ||
| 159 | c->width = NL80211_CHAN_WIDTH_20; | ||
| 160 | c->center_freq1 = c->chan->center_freq; | ||
| 161 | ret = IEEE80211_STA_DISABLE_40MHZ | | ||
| 162 | IEEE80211_STA_DISABLE_VHT; | ||
| 163 | break; | ||
| 164 | case NL80211_CHAN_WIDTH_80: | ||
| 165 | tmp = (30 + c->chan->center_freq - c->center_freq1)/20; | ||
| 166 | /* n_P40 */ | ||
| 167 | tmp /= 2; | ||
| 168 | /* freq_P40 */ | ||
| 169 | c->center_freq1 = c->center_freq1 - 20 + 40 * tmp; | ||
| 170 | c->width = NL80211_CHAN_WIDTH_40; | ||
| 171 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 172 | break; | ||
| 173 | case NL80211_CHAN_WIDTH_80P80: | ||
| 174 | c->center_freq2 = 0; | ||
| 175 | c->width = NL80211_CHAN_WIDTH_80; | ||
| 176 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
| 177 | IEEE80211_STA_DISABLE_160MHZ; | ||
| 178 | break; | ||
| 179 | case NL80211_CHAN_WIDTH_160: | ||
| 180 | /* n_P20 */ | ||
| 181 | tmp = (70 + c->chan->center_freq - c->center_freq1)/20; | ||
| 182 | /* n_P80 */ | ||
| 183 | tmp /= 4; | ||
| 184 | c->center_freq1 = c->center_freq1 - 40 + 80 * tmp; | ||
| 185 | c->width = NL80211_CHAN_WIDTH_80; | ||
| 186 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
| 187 | IEEE80211_STA_DISABLE_160MHZ; | ||
| 188 | break; | ||
| 189 | default: | ||
| 190 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
| 191 | WARN_ON_ONCE(1); | ||
| 192 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 193 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 194 | break; | ||
| 195 | case NL80211_CHAN_WIDTH_5: | ||
| 196 | case NL80211_CHAN_WIDTH_10: | ||
| 197 | WARN_ON_ONCE(1); | ||
| 198 | /* keep c->width */ | ||
| 199 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 200 | break; | ||
| 201 | } | ||
| 202 | |||
| 203 | WARN_ON_ONCE(!cfg80211_chandef_valid(c)); | ||
| 204 | |||
| 205 | return ret; | ||
| 206 | } | ||
| 207 | |||
| 208 | static u32 | 148 | static u32 |
| 209 | ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | 149 | ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, |
| 210 | struct ieee80211_supported_band *sband, | 150 | struct ieee80211_supported_band *sband, |
| @@ -352,7 +292,7 @@ out: | |||
| 352 | break; | 292 | break; |
| 353 | } | 293 | } |
| 354 | 294 | ||
| 355 | ret |= chandef_downgrade(chandef); | 295 | ret |= ieee80211_chandef_downgrade(chandef); |
| 356 | } | 296 | } |
| 357 | 297 | ||
| 358 | if (chandef->width != vht_chandef.width && !tracking) | 298 | if (chandef->width != vht_chandef.width && !tracking) |
| @@ -406,13 +346,13 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, | |||
| 406 | */ | 346 | */ |
| 407 | if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ && | 347 | if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ && |
| 408 | chandef.width == NL80211_CHAN_WIDTH_80P80) | 348 | chandef.width == NL80211_CHAN_WIDTH_80P80) |
| 409 | flags |= chandef_downgrade(&chandef); | 349 | flags |= ieee80211_chandef_downgrade(&chandef); |
| 410 | if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ && | 350 | if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ && |
| 411 | chandef.width == NL80211_CHAN_WIDTH_160) | 351 | chandef.width == NL80211_CHAN_WIDTH_160) |
| 412 | flags |= chandef_downgrade(&chandef); | 352 | flags |= ieee80211_chandef_downgrade(&chandef); |
| 413 | if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ && | 353 | if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ && |
| 414 | chandef.width > NL80211_CHAN_WIDTH_20) | 354 | chandef.width > NL80211_CHAN_WIDTH_20) |
| 415 | flags |= chandef_downgrade(&chandef); | 355 | flags |= ieee80211_chandef_downgrade(&chandef); |
| 416 | 356 | ||
| 417 | if (cfg80211_chandef_identical(&chandef, &sdata->vif.bss_conf.chandef)) | 357 | if (cfg80211_chandef_identical(&chandef, &sdata->vif.bss_conf.chandef)) |
| 418 | return 0; | 358 | return 0; |
| @@ -893,8 +833,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
| 893 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | 833 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) |
| 894 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | 834 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; |
| 895 | 835 | ||
| 896 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 836 | if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) |
| 897 | IEEE80211_STA_CONNECTION_POLL)) | ||
| 898 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE; | 837 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE; |
| 899 | 838 | ||
| 900 | ieee80211_tx_skb(sdata, skb); | 839 | ieee80211_tx_skb(sdata, skb); |
| @@ -937,6 +876,8 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
| 937 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); | 876 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); |
| 938 | struct ieee80211_local *local = sdata->local; | 877 | struct ieee80211_local *local = sdata->local; |
| 939 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 878 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 879 | u32 changed = 0; | ||
| 880 | int ret; | ||
| 940 | 881 | ||
| 941 | if (!ieee80211_sdata_running(sdata)) | 882 | if (!ieee80211_sdata_running(sdata)) |
| 942 | return; | 883 | return; |
| @@ -945,24 +886,39 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
| 945 | if (!ifmgd->associated) | 886 | if (!ifmgd->associated) |
| 946 | goto out; | 887 | goto out; |
| 947 | 888 | ||
| 948 | local->_oper_chandef = local->csa_chandef; | 889 | ret = ieee80211_vif_change_channel(sdata, &local->csa_chandef, |
| 890 | &changed); | ||
| 891 | if (ret) { | ||
| 892 | sdata_info(sdata, | ||
| 893 | "vif channel switch failed, disconnecting\n"); | ||
| 894 | ieee80211_queue_work(&sdata->local->hw, | ||
| 895 | &ifmgd->csa_connection_drop_work); | ||
| 896 | goto out; | ||
| 897 | } | ||
| 949 | 898 | ||
| 950 | if (!local->ops->channel_switch) { | 899 | if (!local->use_chanctx) { |
| 951 | /* call "hw_config" only if doing sw channel switch */ | 900 | local->_oper_chandef = local->csa_chandef; |
| 952 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 901 | /* Call "hw_config" only if doing sw channel switch. |
| 953 | } else { | 902 | * Otherwise update the channel directly |
| 954 | /* update the device channel directly */ | 903 | */ |
| 955 | local->hw.conf.chandef = local->_oper_chandef; | 904 | if (!local->ops->channel_switch) |
| 905 | ieee80211_hw_config(local, 0); | ||
| 906 | else | ||
| 907 | local->hw.conf.chandef = local->_oper_chandef; | ||
| 956 | } | 908 | } |
| 957 | 909 | ||
| 958 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 910 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
| 959 | ifmgd->associated->channel = local->_oper_chandef.chan; | 911 | ifmgd->associated->channel = local->csa_chandef.chan; |
| 960 | 912 | ||
| 961 | /* XXX: wait for a beacon first? */ | 913 | /* XXX: wait for a beacon first? */ |
| 962 | ieee80211_wake_queues_by_reason(&local->hw, | 914 | ieee80211_wake_queues_by_reason(&local->hw, |
| 963 | IEEE80211_MAX_QUEUE_MAP, | 915 | IEEE80211_MAX_QUEUE_MAP, |
| 964 | IEEE80211_QUEUE_STOP_REASON_CSA); | 916 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| 917 | |||
| 918 | ieee80211_bss_info_change_notify(sdata, changed); | ||
| 919 | |||
| 965 | out: | 920 | out: |
| 921 | sdata->vif.csa_active = false; | ||
| 966 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | 922 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; |
| 967 | sdata_unlock(sdata); | 923 | sdata_unlock(sdata); |
| 968 | } | 924 | } |
| @@ -1000,20 +956,12 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 1000 | struct ieee80211_local *local = sdata->local; | 956 | struct ieee80211_local *local = sdata->local; |
| 1001 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 957 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 1002 | struct cfg80211_bss *cbss = ifmgd->associated; | 958 | struct cfg80211_bss *cbss = ifmgd->associated; |
| 1003 | struct ieee80211_bss *bss; | ||
| 1004 | struct ieee80211_chanctx *chanctx; | 959 | struct ieee80211_chanctx *chanctx; |
| 1005 | enum ieee80211_band new_band; | 960 | enum ieee80211_band current_band; |
| 1006 | int new_freq; | ||
| 1007 | u8 new_chan_no; | ||
| 1008 | u8 count; | 961 | u8 count; |
| 1009 | u8 mode; | 962 | u8 mode; |
| 1010 | struct ieee80211_channel *new_chan; | ||
| 1011 | struct cfg80211_chan_def new_chandef = {}; | 963 | struct cfg80211_chan_def new_chandef = {}; |
| 1012 | struct cfg80211_chan_def new_vht_chandef = {}; | 964 | int res; |
| 1013 | const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; | ||
| 1014 | const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; | ||
| 1015 | const struct ieee80211_ht_operation *ht_oper; | ||
| 1016 | int secondary_channel_offset = -1; | ||
| 1017 | 965 | ||
| 1018 | sdata_assert_lock(sdata); | 966 | sdata_assert_lock(sdata); |
| 1019 | 967 | ||
| @@ -1027,162 +975,23 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 1027 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) | 975 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) |
| 1028 | return; | 976 | return; |
| 1029 | 977 | ||
| 1030 | sec_chan_offs = elems->sec_chan_offs; | 978 | current_band = cbss->channel->band; |
| 1031 | wide_bw_chansw_ie = elems->wide_bw_chansw_ie; | 979 | res = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, current_band, |
| 1032 | ht_oper = elems->ht_operation; | 980 | ifmgd->flags, |
| 1033 | 981 | ifmgd->associated->bssid, &count, | |
| 1034 | if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT | | 982 | &mode, &new_chandef); |
| 1035 | IEEE80211_STA_DISABLE_40MHZ)) { | 983 | if (res < 0) |
| 1036 | sec_chan_offs = NULL; | ||
| 1037 | wide_bw_chansw_ie = NULL; | ||
| 1038 | /* only used for bandwidth here */ | ||
| 1039 | ht_oper = NULL; | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) | ||
| 1043 | wide_bw_chansw_ie = NULL; | ||
| 1044 | |||
| 1045 | if (elems->ext_chansw_ie) { | ||
| 1046 | if (!ieee80211_operating_class_to_band( | ||
| 1047 | elems->ext_chansw_ie->new_operating_class, | ||
| 1048 | &new_band)) { | ||
| 1049 | sdata_info(sdata, | ||
| 1050 | "cannot understand ECSA IE operating class %d, disconnecting\n", | ||
| 1051 | elems->ext_chansw_ie->new_operating_class); | ||
| 1052 | ieee80211_queue_work(&local->hw, | ||
| 1053 | &ifmgd->csa_connection_drop_work); | ||
| 1054 | } | ||
| 1055 | new_chan_no = elems->ext_chansw_ie->new_ch_num; | ||
| 1056 | count = elems->ext_chansw_ie->count; | ||
| 1057 | mode = elems->ext_chansw_ie->mode; | ||
| 1058 | } else if (elems->ch_switch_ie) { | ||
| 1059 | new_band = cbss->channel->band; | ||
| 1060 | new_chan_no = elems->ch_switch_ie->new_ch_num; | ||
| 1061 | count = elems->ch_switch_ie->count; | ||
| 1062 | mode = elems->ch_switch_ie->mode; | ||
| 1063 | } else { | ||
| 1064 | /* nothing here we understand */ | ||
| 1065 | return; | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | bss = (void *)cbss->priv; | ||
| 1069 | |||
| 1070 | new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band); | ||
| 1071 | new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | ||
| 1072 | if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) { | ||
| 1073 | sdata_info(sdata, | ||
| 1074 | "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", | ||
| 1075 | ifmgd->associated->bssid, new_freq); | ||
| 1076 | ieee80211_queue_work(&local->hw, | 984 | ieee80211_queue_work(&local->hw, |
| 1077 | &ifmgd->csa_connection_drop_work); | 985 | &ifmgd->csa_connection_drop_work); |
| 986 | if (res) | ||
| 1078 | return; | 987 | return; |
| 1079 | } | ||
| 1080 | |||
| 1081 | if (!beacon && sec_chan_offs) { | ||
| 1082 | secondary_channel_offset = sec_chan_offs->sec_chan_offs; | ||
| 1083 | } else if (beacon && ht_oper) { | ||
| 1084 | secondary_channel_offset = | ||
| 1085 | ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET; | ||
| 1086 | } else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | ||
| 1087 | /* | ||
| 1088 | * If it's not a beacon, HT is enabled and the IE not present, | ||
| 1089 | * it's 20 MHz, 802.11-2012 8.5.2.6: | ||
| 1090 | * This element [the Secondary Channel Offset Element] is | ||
| 1091 | * present when switching to a 40 MHz channel. It may be | ||
| 1092 | * present when switching to a 20 MHz channel (in which | ||
| 1093 | * case the secondary channel offset is set to SCN). | ||
| 1094 | */ | ||
| 1095 | secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | switch (secondary_channel_offset) { | ||
| 1099 | default: | ||
| 1100 | /* secondary_channel_offset was present but is invalid */ | ||
| 1101 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | ||
| 1102 | cfg80211_chandef_create(&new_chandef, new_chan, | ||
| 1103 | NL80211_CHAN_HT20); | ||
| 1104 | break; | ||
| 1105 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
| 1106 | cfg80211_chandef_create(&new_chandef, new_chan, | ||
| 1107 | NL80211_CHAN_HT40PLUS); | ||
| 1108 | break; | ||
| 1109 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
| 1110 | cfg80211_chandef_create(&new_chandef, new_chan, | ||
| 1111 | NL80211_CHAN_HT40MINUS); | ||
| 1112 | break; | ||
| 1113 | case -1: | ||
| 1114 | cfg80211_chandef_create(&new_chandef, new_chan, | ||
| 1115 | NL80211_CHAN_NO_HT); | ||
| 1116 | /* keep width for 5/10 MHz channels */ | ||
| 1117 | switch (sdata->vif.bss_conf.chandef.width) { | ||
| 1118 | case NL80211_CHAN_WIDTH_5: | ||
| 1119 | case NL80211_CHAN_WIDTH_10: | ||
| 1120 | new_chandef.width = sdata->vif.bss_conf.chandef.width; | ||
| 1121 | break; | ||
| 1122 | default: | ||
| 1123 | break; | ||
| 1124 | } | ||
| 1125 | break; | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | if (wide_bw_chansw_ie) { | ||
| 1129 | new_vht_chandef.chan = new_chan; | ||
| 1130 | new_vht_chandef.center_freq1 = | ||
| 1131 | ieee80211_channel_to_frequency( | ||
| 1132 | wide_bw_chansw_ie->new_center_freq_seg0, | ||
| 1133 | new_band); | ||
| 1134 | |||
| 1135 | switch (wide_bw_chansw_ie->new_channel_width) { | ||
| 1136 | default: | ||
| 1137 | /* hmmm, ignore VHT and use HT if present */ | ||
| 1138 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | ||
| 1139 | new_vht_chandef.chan = NULL; | ||
| 1140 | break; | ||
| 1141 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | ||
| 1142 | new_vht_chandef.width = NL80211_CHAN_WIDTH_80; | ||
| 1143 | break; | ||
| 1144 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | ||
| 1145 | new_vht_chandef.width = NL80211_CHAN_WIDTH_160; | ||
| 1146 | break; | ||
| 1147 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | ||
| 1148 | /* field is otherwise reserved */ | ||
| 1149 | new_vht_chandef.center_freq2 = | ||
| 1150 | ieee80211_channel_to_frequency( | ||
| 1151 | wide_bw_chansw_ie->new_center_freq_seg1, | ||
| 1152 | new_band); | ||
| 1153 | new_vht_chandef.width = NL80211_CHAN_WIDTH_80P80; | ||
| 1154 | break; | ||
| 1155 | } | ||
| 1156 | if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ && | ||
| 1157 | new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80) | ||
| 1158 | chandef_downgrade(&new_vht_chandef); | ||
| 1159 | if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ && | ||
| 1160 | new_vht_chandef.width == NL80211_CHAN_WIDTH_160) | ||
| 1161 | chandef_downgrade(&new_vht_chandef); | ||
| 1162 | if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ && | ||
| 1163 | new_vht_chandef.width > NL80211_CHAN_WIDTH_20) | ||
| 1164 | chandef_downgrade(&new_vht_chandef); | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | /* if VHT data is there validate & use it */ | ||
| 1168 | if (new_vht_chandef.chan) { | ||
| 1169 | if (!cfg80211_chandef_compatible(&new_vht_chandef, | ||
| 1170 | &new_chandef)) { | ||
| 1171 | sdata_info(sdata, | ||
| 1172 | "AP %pM CSA has inconsistent channel data, disconnecting\n", | ||
| 1173 | ifmgd->associated->bssid); | ||
| 1174 | ieee80211_queue_work(&local->hw, | ||
| 1175 | &ifmgd->csa_connection_drop_work); | ||
| 1176 | return; | ||
| 1177 | } | ||
| 1178 | new_chandef = new_vht_chandef; | ||
| 1179 | } | ||
| 1180 | 988 | ||
| 1181 | if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef, | 989 | if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef, |
| 1182 | IEEE80211_CHAN_DISABLED)) { | 990 | IEEE80211_CHAN_DISABLED)) { |
| 1183 | sdata_info(sdata, | 991 | sdata_info(sdata, |
| 1184 | "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", | 992 | "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", |
| 1185 | ifmgd->associated->bssid, new_freq, | 993 | ifmgd->associated->bssid, |
| 994 | new_chandef.chan->center_freq, | ||
| 1186 | new_chandef.width, new_chandef.center_freq1, | 995 | new_chandef.width, new_chandef.center_freq1, |
| 1187 | new_chandef.center_freq2); | 996 | new_chandef.center_freq2); |
| 1188 | ieee80211_queue_work(&local->hw, | 997 | ieee80211_queue_work(&local->hw, |
| @@ -1191,17 +1000,28 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 1191 | } | 1000 | } |
| 1192 | 1001 | ||
| 1193 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | 1002 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; |
| 1003 | sdata->vif.csa_active = true; | ||
| 1194 | 1004 | ||
| 1005 | mutex_lock(&local->chanctx_mtx); | ||
| 1195 | if (local->use_chanctx) { | 1006 | if (local->use_chanctx) { |
| 1196 | sdata_info(sdata, | 1007 | u32 num_chanctx = 0; |
| 1197 | "not handling channel switch with channel contexts\n"); | 1008 | list_for_each_entry(chanctx, &local->chanctx_list, list) |
| 1198 | ieee80211_queue_work(&local->hw, | 1009 | num_chanctx++; |
| 1199 | &ifmgd->csa_connection_drop_work); | 1010 | |
| 1200 | return; | 1011 | if (num_chanctx > 1 || |
| 1012 | !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) { | ||
| 1013 | sdata_info(sdata, | ||
| 1014 | "not handling chan-switch with channel contexts\n"); | ||
| 1015 | ieee80211_queue_work(&local->hw, | ||
| 1016 | &ifmgd->csa_connection_drop_work); | ||
| 1017 | mutex_unlock(&local->chanctx_mtx); | ||
| 1018 | return; | ||
| 1019 | } | ||
| 1201 | } | 1020 | } |
| 1202 | 1021 | ||
| 1203 | mutex_lock(&local->chanctx_mtx); | ||
| 1204 | if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) { | 1022 | if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) { |
| 1023 | ieee80211_queue_work(&local->hw, | ||
| 1024 | &ifmgd->csa_connection_drop_work); | ||
| 1205 | mutex_unlock(&local->chanctx_mtx); | 1025 | mutex_unlock(&local->chanctx_mtx); |
| 1206 | return; | 1026 | return; |
| 1207 | } | 1027 | } |
| @@ -1374,8 +1194,7 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata) | |||
| 1374 | if (!mgd->associated) | 1194 | if (!mgd->associated) |
| 1375 | return false; | 1195 | return false; |
| 1376 | 1196 | ||
| 1377 | if (mgd->flags & (IEEE80211_STA_BEACON_POLL | | 1197 | if (mgd->flags & IEEE80211_STA_CONNECTION_POLL) |
| 1378 | IEEE80211_STA_CONNECTION_POLL)) | ||
| 1379 | return false; | 1198 | return false; |
| 1380 | 1199 | ||
| 1381 | if (!mgd->have_beacon) | 1200 | if (!mgd->have_beacon) |
| @@ -1691,8 +1510,7 @@ static void __ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata) | |||
| 1691 | { | 1510 | { |
| 1692 | lockdep_assert_held(&sdata->local->mtx); | 1511 | lockdep_assert_held(&sdata->local->mtx); |
| 1693 | 1512 | ||
| 1694 | sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | | 1513 | sdata->u.mgd.flags &= ~IEEE80211_STA_CONNECTION_POLL; |
| 1695 | IEEE80211_STA_BEACON_POLL); | ||
| 1696 | ieee80211_run_deferred_scan(sdata->local); | 1514 | ieee80211_run_deferred_scan(sdata->local); |
| 1697 | } | 1515 | } |
| 1698 | 1516 | ||
| @@ -1954,11 +1772,8 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata) | |||
| 1954 | struct ieee80211_local *local = sdata->local; | 1772 | struct ieee80211_local *local = sdata->local; |
| 1955 | 1773 | ||
| 1956 | mutex_lock(&local->mtx); | 1774 | mutex_lock(&local->mtx); |
| 1957 | if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 1775 | if (!(ifmgd->flags & IEEE80211_STA_CONNECTION_POLL)) |
| 1958 | IEEE80211_STA_CONNECTION_POLL))) { | 1776 | goto out; |
| 1959 | mutex_unlock(&local->mtx); | ||
| 1960 | return; | ||
| 1961 | } | ||
| 1962 | 1777 | ||
| 1963 | __ieee80211_stop_poll(sdata); | 1778 | __ieee80211_stop_poll(sdata); |
| 1964 | 1779 | ||
| @@ -2094,15 +1909,9 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | |||
| 2094 | * because otherwise we would reset the timer every time and | 1909 | * because otherwise we would reset the timer every time and |
| 2095 | * never check whether we received a probe response! | 1910 | * never check whether we received a probe response! |
| 2096 | */ | 1911 | */ |
| 2097 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 1912 | if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) |
| 2098 | IEEE80211_STA_CONNECTION_POLL)) | ||
| 2099 | already = true; | 1913 | already = true; |
| 2100 | 1914 | ||
| 2101 | if (beacon) | ||
| 2102 | ifmgd->flags |= IEEE80211_STA_BEACON_POLL; | ||
| 2103 | else | ||
| 2104 | ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL; | ||
| 2105 | |||
| 2106 | mutex_unlock(&sdata->local->mtx); | 1915 | mutex_unlock(&sdata->local->mtx); |
| 2107 | 1916 | ||
| 2108 | if (already) | 1917 | if (already) |
| @@ -2174,6 +1983,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
| 2174 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | 1983 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
| 2175 | true, frame_buf); | 1984 | true, frame_buf); |
| 2176 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | 1985 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; |
| 1986 | sdata->vif.csa_active = false; | ||
| 2177 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 1987 | ieee80211_wake_queues_by_reason(&sdata->local->hw, |
| 2178 | IEEE80211_MAX_QUEUE_MAP, | 1988 | IEEE80211_MAX_QUEUE_MAP, |
| 2179 | IEEE80211_QUEUE_STOP_REASON_CSA); | 1989 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| @@ -3061,17 +2871,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 3061 | } | 2871 | } |
| 3062 | } | 2872 | } |
| 3063 | 2873 | ||
| 3064 | if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) { | 2874 | if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) { |
| 3065 | mlme_dbg_ratelimited(sdata, | 2875 | mlme_dbg_ratelimited(sdata, |
| 3066 | "cancelling AP probe due to a received beacon\n"); | 2876 | "cancelling AP probe due to a received beacon\n"); |
| 3067 | mutex_lock(&local->mtx); | 2877 | ieee80211_reset_ap_probe(sdata); |
| 3068 | ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL; | ||
| 3069 | ieee80211_run_deferred_scan(local); | ||
| 3070 | mutex_unlock(&local->mtx); | ||
| 3071 | |||
| 3072 | mutex_lock(&local->iflist_mtx); | ||
| 3073 | ieee80211_recalc_ps(local, -1); | ||
| 3074 | mutex_unlock(&local->iflist_mtx); | ||
| 3075 | } | 2878 | } |
| 3076 | 2879 | ||
| 3077 | /* | 2880 | /* |
| @@ -3543,8 +3346,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
| 3543 | } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) | 3346 | } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) |
| 3544 | run_again(sdata, ifmgd->assoc_data->timeout); | 3347 | run_again(sdata, ifmgd->assoc_data->timeout); |
| 3545 | 3348 | ||
| 3546 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 3349 | if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL && |
| 3547 | IEEE80211_STA_CONNECTION_POLL) && | ||
| 3548 | ifmgd->associated) { | 3350 | ifmgd->associated) { |
| 3549 | u8 bssid[ETH_ALEN]; | 3351 | u8 bssid[ETH_ALEN]; |
| 3550 | int max_tries; | 3352 | int max_tries; |
| @@ -3876,7 +3678,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
| 3876 | return ret; | 3678 | return ret; |
| 3877 | 3679 | ||
| 3878 | while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { | 3680 | while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { |
| 3879 | ifmgd->flags |= chandef_downgrade(&chandef); | 3681 | ifmgd->flags |= ieee80211_chandef_downgrade(&chandef); |
| 3880 | ret = ieee80211_vif_use_channel(sdata, &chandef, | 3682 | ret = ieee80211_vif_use_channel(sdata, &chandef, |
| 3881 | IEEE80211_CHANCTX_SHARED); | 3683 | IEEE80211_CHANCTX_SHARED); |
| 3882 | } | 3684 | } |
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 8b5f7ef7c0c9..7fa1b36e6202 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
| @@ -203,6 +203,15 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | |||
| 203 | memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate)); | 203 | memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate)); |
| 204 | mi->max_prob_rate = tmp_prob_rate; | 204 | mi->max_prob_rate = tmp_prob_rate; |
| 205 | 205 | ||
| 206 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 207 | /* use fixed index if set */ | ||
| 208 | if (mp->fixed_rate_idx != -1) { | ||
| 209 | mi->max_tp_rate[0] = mp->fixed_rate_idx; | ||
| 210 | mi->max_tp_rate[1] = mp->fixed_rate_idx; | ||
| 211 | mi->max_prob_rate = mp->fixed_rate_idx; | ||
| 212 | } | ||
| 213 | #endif | ||
| 214 | |||
| 206 | /* Reset update timer */ | 215 | /* Reset update timer */ |
| 207 | mi->stats_update = jiffies; | 216 | mi->stats_update = jiffies; |
| 208 | 217 | ||
| @@ -310,6 +319,11 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, | |||
| 310 | /* increase sum packet counter */ | 319 | /* increase sum packet counter */ |
| 311 | mi->packet_count++; | 320 | mi->packet_count++; |
| 312 | 321 | ||
| 322 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 323 | if (mp->fixed_rate_idx != -1) | ||
| 324 | return; | ||
| 325 | #endif | ||
| 326 | |||
| 313 | delta = (mi->packet_count * sampling_ratio / 100) - | 327 | delta = (mi->packet_count * sampling_ratio / 100) - |
| 314 | (mi->sample_count + mi->sample_deferred / 2); | 328 | (mi->sample_count + mi->sample_deferred / 2); |
| 315 | 329 | ||
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 7c323f27ba23..5d60779a0c1b 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
| @@ -365,6 +365,14 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
| 365 | } | 365 | } |
| 366 | } | 366 | } |
| 367 | 367 | ||
| 368 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 369 | /* use fixed index if set */ | ||
| 370 | if (mp->fixed_rate_idx != -1) { | ||
| 371 | mi->max_tp_rate = mp->fixed_rate_idx; | ||
| 372 | mi->max_tp_rate2 = mp->fixed_rate_idx; | ||
| 373 | mi->max_prob_rate = mp->fixed_rate_idx; | ||
| 374 | } | ||
| 375 | #endif | ||
| 368 | 376 | ||
| 369 | mi->stats_update = jiffies; | 377 | mi->stats_update = jiffies; |
| 370 | } | 378 | } |
| @@ -774,6 +782,11 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
| 774 | info->flags |= mi->tx_flags; | 782 | info->flags |= mi->tx_flags; |
| 775 | minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble); | 783 | minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble); |
| 776 | 784 | ||
| 785 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 786 | if (mp->fixed_rate_idx != -1) | ||
| 787 | return; | ||
| 788 | #endif | ||
| 789 | |||
| 777 | /* Don't use EAPOL frames for sampling on non-mrr hw */ | 790 | /* Don't use EAPOL frames for sampling on non-mrr hw */ |
| 778 | if (mp->hw->max_rates == 1 && | 791 | if (mp->hw->max_rates == 1 && |
| 779 | (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) | 792 | (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) |
| @@ -781,16 +794,6 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
| 781 | else | 794 | else |
| 782 | sample_idx = minstrel_get_sample_rate(mp, mi); | 795 | sample_idx = minstrel_get_sample_rate(mp, mi); |
| 783 | 796 | ||
| 784 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 785 | /* use fixed index if set */ | ||
| 786 | if (mp->fixed_rate_idx != -1) { | ||
| 787 | mi->max_tp_rate = mp->fixed_rate_idx; | ||
| 788 | mi->max_tp_rate2 = mp->fixed_rate_idx; | ||
| 789 | mi->max_prob_rate = mp->fixed_rate_idx; | ||
| 790 | sample_idx = -1; | ||
| 791 | } | ||
| 792 | #endif | ||
| 793 | |||
| 794 | mi->total_packets++; | 797 | mi->total_packets++; |
| 795 | 798 | ||
| 796 | /* wraparound */ | 799 | /* wraparound */ |
diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c index c97a0657c043..6ff134650a84 100644 --- a/net/mac80211/rc80211_pid_debugfs.c +++ b/net/mac80211/rc80211_pid_debugfs.c | |||
| @@ -167,29 +167,29 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf, | |||
| 167 | * provide large enough buffers. */ | 167 | * provide large enough buffers. */ |
| 168 | length = length < RC_PID_PRINT_BUF_SIZE ? | 168 | length = length < RC_PID_PRINT_BUF_SIZE ? |
| 169 | length : RC_PID_PRINT_BUF_SIZE; | 169 | length : RC_PID_PRINT_BUF_SIZE; |
| 170 | p = snprintf(pb, length, "%u %lu ", ev->id, ev->timestamp); | 170 | p = scnprintf(pb, length, "%u %lu ", ev->id, ev->timestamp); |
| 171 | switch (ev->type) { | 171 | switch (ev->type) { |
| 172 | case RC_PID_EVENT_TYPE_TX_STATUS: | 172 | case RC_PID_EVENT_TYPE_TX_STATUS: |
| 173 | p += snprintf(pb + p, length - p, "tx_status %u %u", | 173 | p += scnprintf(pb + p, length - p, "tx_status %u %u", |
| 174 | !(ev->data.flags & IEEE80211_TX_STAT_ACK), | 174 | !(ev->data.flags & IEEE80211_TX_STAT_ACK), |
| 175 | ev->data.tx_status.status.rates[0].idx); | 175 | ev->data.tx_status.status.rates[0].idx); |
| 176 | break; | 176 | break; |
| 177 | case RC_PID_EVENT_TYPE_RATE_CHANGE: | 177 | case RC_PID_EVENT_TYPE_RATE_CHANGE: |
| 178 | p += snprintf(pb + p, length - p, "rate_change %d %d", | 178 | p += scnprintf(pb + p, length - p, "rate_change %d %d", |
| 179 | ev->data.index, ev->data.rate); | 179 | ev->data.index, ev->data.rate); |
| 180 | break; | 180 | break; |
| 181 | case RC_PID_EVENT_TYPE_TX_RATE: | 181 | case RC_PID_EVENT_TYPE_TX_RATE: |
| 182 | p += snprintf(pb + p, length - p, "tx_rate %d %d", | 182 | p += scnprintf(pb + p, length - p, "tx_rate %d %d", |
| 183 | ev->data.index, ev->data.rate); | 183 | ev->data.index, ev->data.rate); |
| 184 | break; | 184 | break; |
| 185 | case RC_PID_EVENT_TYPE_PF_SAMPLE: | 185 | case RC_PID_EVENT_TYPE_PF_SAMPLE: |
| 186 | p += snprintf(pb + p, length - p, | 186 | p += scnprintf(pb + p, length - p, |
| 187 | "pf_sample %d %d %d %d", | 187 | "pf_sample %d %d %d %d", |
| 188 | ev->data.pf_sample, ev->data.prop_err, | 188 | ev->data.pf_sample, ev->data.prop_err, |
| 189 | ev->data.int_err, ev->data.der_err); | 189 | ev->data.int_err, ev->data.der_err); |
| 190 | break; | 190 | break; |
| 191 | } | 191 | } |
| 192 | p += snprintf(pb + p, length - p, "\n"); | 192 | p += scnprintf(pb + p, length - p, "\n"); |
| 193 | 193 | ||
| 194 | spin_unlock_irqrestore(&events->lock, status); | 194 | spin_unlock_irqrestore(&events->lock, status); |
| 195 | 195 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 674eac1f996c..0011ac815097 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
| @@ -995,8 +995,9 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
| 995 | rx->sta->num_duplicates++; | 995 | rx->sta->num_duplicates++; |
| 996 | } | 996 | } |
| 997 | return RX_DROP_UNUSABLE; | 997 | return RX_DROP_UNUSABLE; |
| 998 | } else | 998 | } else if (!(status->flag & RX_FLAG_AMSDU_MORE)) { |
| 999 | rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl; | 999 | rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl; |
| 1000 | } | ||
| 1000 | } | 1001 | } |
| 1001 | 1002 | ||
| 1002 | if (unlikely(rx->skb->len < 16)) { | 1003 | if (unlikely(rx->skb->len < 16)) { |
| @@ -2402,7 +2403,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 2402 | return RX_DROP_UNUSABLE; | 2403 | return RX_DROP_UNUSABLE; |
| 2403 | 2404 | ||
| 2404 | if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC && | 2405 | if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC && |
| 2405 | mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED) | 2406 | mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED && |
| 2407 | mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT) | ||
| 2406 | return RX_DROP_UNUSABLE; | 2408 | return RX_DROP_UNUSABLE; |
| 2407 | 2409 | ||
| 2408 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) | 2410 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) |
| @@ -2566,31 +2568,46 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 2566 | 2568 | ||
| 2567 | goto queue; | 2569 | goto queue; |
| 2568 | case WLAN_CATEGORY_SPECTRUM_MGMT: | 2570 | case WLAN_CATEGORY_SPECTRUM_MGMT: |
| 2569 | if (status->band != IEEE80211_BAND_5GHZ) | ||
| 2570 | break; | ||
| 2571 | |||
| 2572 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
| 2573 | break; | ||
| 2574 | |||
| 2575 | /* verify action_code is present */ | 2571 | /* verify action_code is present */ |
| 2576 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | 2572 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) |
| 2577 | break; | 2573 | break; |
| 2578 | 2574 | ||
| 2579 | switch (mgmt->u.action.u.measurement.action_code) { | 2575 | switch (mgmt->u.action.u.measurement.action_code) { |
| 2580 | case WLAN_ACTION_SPCT_MSR_REQ: | 2576 | case WLAN_ACTION_SPCT_MSR_REQ: |
| 2577 | if (status->band != IEEE80211_BAND_5GHZ) | ||
| 2578 | break; | ||
| 2579 | |||
| 2581 | if (len < (IEEE80211_MIN_ACTION_SIZE + | 2580 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
| 2582 | sizeof(mgmt->u.action.u.measurement))) | 2581 | sizeof(mgmt->u.action.u.measurement))) |
| 2583 | break; | 2582 | break; |
| 2583 | |||
| 2584 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
| 2585 | break; | ||
| 2586 | |||
| 2584 | ieee80211_process_measurement_req(sdata, mgmt, len); | 2587 | ieee80211_process_measurement_req(sdata, mgmt, len); |
| 2585 | goto handled; | 2588 | goto handled; |
| 2586 | case WLAN_ACTION_SPCT_CHL_SWITCH: | 2589 | case WLAN_ACTION_SPCT_CHL_SWITCH: { |
| 2587 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 2590 | u8 *bssid; |
| 2591 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
| 2592 | sizeof(mgmt->u.action.u.chan_switch))) | ||
| 2593 | break; | ||
| 2594 | |||
| 2595 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | ||
| 2596 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
| 2588 | break; | 2597 | break; |
| 2589 | 2598 | ||
| 2590 | if (!ether_addr_equal(mgmt->bssid, sdata->u.mgd.bssid)) | 2599 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
| 2600 | bssid = sdata->u.mgd.bssid; | ||
| 2601 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
| 2602 | bssid = sdata->u.ibss.bssid; | ||
| 2603 | else | ||
| 2604 | break; | ||
| 2605 | |||
| 2606 | if (!ether_addr_equal(mgmt->bssid, bssid)) | ||
| 2591 | break; | 2607 | break; |
| 2592 | 2608 | ||
| 2593 | goto queue; | 2609 | goto queue; |
| 2610 | } | ||
| 2594 | } | 2611 | } |
| 2595 | break; | 2612 | break; |
| 2596 | case WLAN_CATEGORY_SA_QUERY: | 2613 | case WLAN_CATEGORY_SA_QUERY: |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 08afe74b98f4..ecb57b0bf74a 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
| @@ -391,8 +391,7 @@ static bool ieee80211_can_scan(struct ieee80211_local *local, | |||
| 391 | return false; | 391 | return false; |
| 392 | 392 | ||
| 393 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 393 | if (sdata->vif.type == NL80211_IFTYPE_STATION && |
| 394 | sdata->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | | 394 | sdata->u.mgd.flags & IEEE80211_STA_CONNECTION_POLL) |
| 395 | IEEE80211_STA_CONNECTION_POLL)) | ||
| 396 | return false; | 395 | return false; |
| 397 | 396 | ||
| 398 | return true; | 397 | return true; |
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 578eea3fc04d..921597e279a3 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c | |||
| @@ -21,6 +21,168 @@ | |||
| 21 | #include "sta_info.h" | 21 | #include "sta_info.h" |
| 22 | #include "wme.h" | 22 | #include "wme.h" |
| 23 | 23 | ||
| 24 | int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, | ||
| 25 | struct ieee802_11_elems *elems, bool beacon, | ||
| 26 | enum ieee80211_band current_band, | ||
| 27 | u32 sta_flags, u8 *bssid, u8 *count, u8 *mode, | ||
| 28 | struct cfg80211_chan_def *new_chandef) | ||
| 29 | { | ||
| 30 | enum ieee80211_band new_band; | ||
| 31 | int new_freq; | ||
| 32 | u8 new_chan_no; | ||
| 33 | struct ieee80211_channel *new_chan; | ||
| 34 | struct cfg80211_chan_def new_vht_chandef = {}; | ||
| 35 | const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; | ||
| 36 | const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; | ||
| 37 | const struct ieee80211_ht_operation *ht_oper; | ||
| 38 | int secondary_channel_offset = -1; | ||
| 39 | |||
| 40 | sec_chan_offs = elems->sec_chan_offs; | ||
| 41 | wide_bw_chansw_ie = elems->wide_bw_chansw_ie; | ||
| 42 | ht_oper = elems->ht_operation; | ||
| 43 | |||
| 44 | if (sta_flags & (IEEE80211_STA_DISABLE_HT | | ||
| 45 | IEEE80211_STA_DISABLE_40MHZ)) { | ||
| 46 | sec_chan_offs = NULL; | ||
| 47 | wide_bw_chansw_ie = NULL; | ||
| 48 | /* only used for bandwidth here */ | ||
| 49 | ht_oper = NULL; | ||
| 50 | } | ||
| 51 | |||
| 52 | if (sta_flags & IEEE80211_STA_DISABLE_VHT) | ||
| 53 | wide_bw_chansw_ie = NULL; | ||
| 54 | |||
| 55 | if (elems->ext_chansw_ie) { | ||
| 56 | if (!ieee80211_operating_class_to_band( | ||
| 57 | elems->ext_chansw_ie->new_operating_class, | ||
| 58 | &new_band)) { | ||
| 59 | sdata_info(sdata, | ||
| 60 | "cannot understand ECSA IE operating class %d, disconnecting\n", | ||
| 61 | elems->ext_chansw_ie->new_operating_class); | ||
| 62 | return -EINVAL; | ||
| 63 | } | ||
| 64 | new_chan_no = elems->ext_chansw_ie->new_ch_num; | ||
| 65 | *count = elems->ext_chansw_ie->count; | ||
| 66 | *mode = elems->ext_chansw_ie->mode; | ||
| 67 | } else if (elems->ch_switch_ie) { | ||
| 68 | new_band = current_band; | ||
| 69 | new_chan_no = elems->ch_switch_ie->new_ch_num; | ||
| 70 | *count = elems->ch_switch_ie->count; | ||
| 71 | *mode = elems->ch_switch_ie->mode; | ||
| 72 | } else { | ||
| 73 | /* nothing here we understand */ | ||
| 74 | return 1; | ||
| 75 | } | ||
| 76 | |||
| 77 | new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band); | ||
| 78 | new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | ||
| 79 | if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) { | ||
| 80 | sdata_info(sdata, | ||
| 81 | "BSS %pM switches to unsupported channel (%d MHz), disconnecting\n", | ||
| 82 | bssid, new_freq); | ||
| 83 | return -EINVAL; | ||
| 84 | } | ||
| 85 | |||
| 86 | if (!beacon && sec_chan_offs) { | ||
| 87 | secondary_channel_offset = sec_chan_offs->sec_chan_offs; | ||
| 88 | } else if (beacon && ht_oper) { | ||
| 89 | secondary_channel_offset = | ||
| 90 | ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET; | ||
| 91 | } else if (!(sta_flags & IEEE80211_STA_DISABLE_HT)) { | ||
| 92 | /* If it's not a beacon, HT is enabled and the IE not present, | ||
| 93 | * it's 20 MHz, 802.11-2012 8.5.2.6: | ||
| 94 | * This element [the Secondary Channel Offset Element] is | ||
| 95 | * present when switching to a 40 MHz channel. It may be | ||
| 96 | * present when switching to a 20 MHz channel (in which | ||
| 97 | * case the secondary channel offset is set to SCN). | ||
| 98 | */ | ||
| 99 | secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||
| 100 | } | ||
| 101 | |||
| 102 | switch (secondary_channel_offset) { | ||
| 103 | default: | ||
| 104 | /* secondary_channel_offset was present but is invalid */ | ||
| 105 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | ||
| 106 | cfg80211_chandef_create(new_chandef, new_chan, | ||
| 107 | NL80211_CHAN_HT20); | ||
| 108 | break; | ||
| 109 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
| 110 | cfg80211_chandef_create(new_chandef, new_chan, | ||
| 111 | NL80211_CHAN_HT40PLUS); | ||
| 112 | break; | ||
| 113 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
| 114 | cfg80211_chandef_create(new_chandef, new_chan, | ||
| 115 | NL80211_CHAN_HT40MINUS); | ||
| 116 | break; | ||
| 117 | case -1: | ||
| 118 | cfg80211_chandef_create(new_chandef, new_chan, | ||
| 119 | NL80211_CHAN_NO_HT); | ||
| 120 | /* keep width for 5/10 MHz channels */ | ||
| 121 | switch (sdata->vif.bss_conf.chandef.width) { | ||
| 122 | case NL80211_CHAN_WIDTH_5: | ||
| 123 | case NL80211_CHAN_WIDTH_10: | ||
| 124 | new_chandef->width = sdata->vif.bss_conf.chandef.width; | ||
| 125 | break; | ||
| 126 | default: | ||
| 127 | break; | ||
| 128 | } | ||
| 129 | break; | ||
| 130 | } | ||
| 131 | |||
| 132 | if (wide_bw_chansw_ie) { | ||
| 133 | new_vht_chandef.chan = new_chan; | ||
| 134 | new_vht_chandef.center_freq1 = | ||
| 135 | ieee80211_channel_to_frequency( | ||
| 136 | wide_bw_chansw_ie->new_center_freq_seg0, | ||
| 137 | new_band); | ||
| 138 | |||
| 139 | switch (wide_bw_chansw_ie->new_channel_width) { | ||
| 140 | default: | ||
| 141 | /* hmmm, ignore VHT and use HT if present */ | ||
| 142 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | ||
| 143 | new_vht_chandef.chan = NULL; | ||
| 144 | break; | ||
| 145 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | ||
| 146 | new_vht_chandef.width = NL80211_CHAN_WIDTH_80; | ||
| 147 | break; | ||
| 148 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | ||
| 149 | new_vht_chandef.width = NL80211_CHAN_WIDTH_160; | ||
| 150 | break; | ||
| 151 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | ||
| 152 | /* field is otherwise reserved */ | ||
| 153 | new_vht_chandef.center_freq2 = | ||
| 154 | ieee80211_channel_to_frequency( | ||
| 155 | wide_bw_chansw_ie->new_center_freq_seg1, | ||
| 156 | new_band); | ||
| 157 | new_vht_chandef.width = NL80211_CHAN_WIDTH_80P80; | ||
| 158 | break; | ||
| 159 | } | ||
| 160 | if (sta_flags & IEEE80211_STA_DISABLE_80P80MHZ && | ||
| 161 | new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80) | ||
| 162 | ieee80211_chandef_downgrade(&new_vht_chandef); | ||
| 163 | if (sta_flags & IEEE80211_STA_DISABLE_160MHZ && | ||
| 164 | new_vht_chandef.width == NL80211_CHAN_WIDTH_160) | ||
| 165 | ieee80211_chandef_downgrade(&new_vht_chandef); | ||
| 166 | if (sta_flags & IEEE80211_STA_DISABLE_40MHZ && | ||
| 167 | new_vht_chandef.width > NL80211_CHAN_WIDTH_20) | ||
| 168 | ieee80211_chandef_downgrade(&new_vht_chandef); | ||
| 169 | } | ||
| 170 | |||
| 171 | /* if VHT data is there validate & use it */ | ||
| 172 | if (new_vht_chandef.chan) { | ||
| 173 | if (!cfg80211_chandef_compatible(&new_vht_chandef, | ||
| 174 | new_chandef)) { | ||
| 175 | sdata_info(sdata, | ||
| 176 | "BSS %pM: CSA has inconsistent channel data, disconnecting\n", | ||
| 177 | bssid); | ||
| 178 | return -EINVAL; | ||
| 179 | } | ||
| 180 | *new_chandef = new_vht_chandef; | ||
| 181 | } | ||
| 182 | |||
| 183 | return 0; | ||
| 184 | } | ||
| 185 | |||
| 24 | static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_data *sdata, | 186 | static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_data *sdata, |
| 25 | struct ieee80211_msrment_ie *request_ie, | 187 | struct ieee80211_msrment_ie *request_ie, |
| 26 | const u8 *da, const u8 *bssid, | 188 | const u8 *da, const u8 *bssid, |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 3fb9dd6d02fc..d4cee98533fd 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
| @@ -1475,6 +1475,41 @@ DEFINE_EVENT(local_sdata_evt, drv_ipv6_addr_change, | |||
| 1475 | ); | 1475 | ); |
| 1476 | #endif | 1476 | #endif |
| 1477 | 1477 | ||
| 1478 | TRACE_EVENT(drv_join_ibss, | ||
| 1479 | TP_PROTO(struct ieee80211_local *local, | ||
| 1480 | struct ieee80211_sub_if_data *sdata, | ||
| 1481 | struct ieee80211_bss_conf *info), | ||
| 1482 | |||
| 1483 | TP_ARGS(local, sdata, info), | ||
| 1484 | |||
| 1485 | TP_STRUCT__entry( | ||
| 1486 | LOCAL_ENTRY | ||
| 1487 | VIF_ENTRY | ||
| 1488 | __field(u8, dtimper) | ||
| 1489 | __field(u16, bcnint) | ||
| 1490 | __dynamic_array(u8, ssid, info->ssid_len); | ||
| 1491 | ), | ||
| 1492 | |||
| 1493 | TP_fast_assign( | ||
| 1494 | LOCAL_ASSIGN; | ||
| 1495 | VIF_ASSIGN; | ||
| 1496 | __entry->dtimper = info->dtim_period; | ||
| 1497 | __entry->bcnint = info->beacon_int; | ||
| 1498 | memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); | ||
| 1499 | ), | ||
| 1500 | |||
| 1501 | TP_printk( | ||
| 1502 | LOCAL_PR_FMT VIF_PR_FMT, | ||
| 1503 | LOCAL_PR_ARG, VIF_PR_ARG | ||
| 1504 | ) | ||
| 1505 | ); | ||
| 1506 | |||
| 1507 | DEFINE_EVENT(local_sdata_evt, drv_leave_ibss, | ||
| 1508 | TP_PROTO(struct ieee80211_local *local, | ||
| 1509 | struct ieee80211_sub_if_data *sdata), | ||
| 1510 | TP_ARGS(local, sdata) | ||
| 1511 | ); | ||
| 1512 | |||
| 1478 | /* | 1513 | /* |
| 1479 | * Tracing for API calls that drivers call. | 1514 | * Tracing for API calls that drivers call. |
| 1480 | */ | 1515 | */ |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3456c0486b48..4fcbf634b548 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
| @@ -1981,7 +1981,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1981 | * EAPOL frames from the local station. | 1981 | * EAPOL frames from the local station. |
| 1982 | */ | 1982 | */ |
| 1983 | if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) && | 1983 | if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) && |
| 1984 | !is_multicast_ether_addr(hdr.addr1) && !authorized && | 1984 | !multicast && !authorized && |
| 1985 | (cpu_to_be16(ethertype) != sdata->control_port_protocol || | 1985 | (cpu_to_be16(ethertype) != sdata->control_port_protocol || |
| 1986 | !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { | 1986 | !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { |
| 1987 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1987 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
| @@ -2357,15 +2357,31 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata, | |||
| 2357 | struct probe_resp *resp; | 2357 | struct probe_resp *resp; |
| 2358 | int counter_offset_beacon = sdata->csa_counter_offset_beacon; | 2358 | int counter_offset_beacon = sdata->csa_counter_offset_beacon; |
| 2359 | int counter_offset_presp = sdata->csa_counter_offset_presp; | 2359 | int counter_offset_presp = sdata->csa_counter_offset_presp; |
| 2360 | u8 *beacon_data; | ||
| 2361 | size_t beacon_data_len; | ||
| 2362 | |||
| 2363 | switch (sdata->vif.type) { | ||
| 2364 | case NL80211_IFTYPE_AP: | ||
| 2365 | beacon_data = beacon->tail; | ||
| 2366 | beacon_data_len = beacon->tail_len; | ||
| 2367 | break; | ||
| 2368 | case NL80211_IFTYPE_ADHOC: | ||
| 2369 | beacon_data = beacon->head; | ||
| 2370 | beacon_data_len = beacon->head_len; | ||
| 2371 | break; | ||
| 2372 | default: | ||
| 2373 | return; | ||
| 2374 | } | ||
| 2375 | if (WARN_ON(counter_offset_beacon >= beacon_data_len)) | ||
| 2376 | return; | ||
| 2360 | 2377 | ||
| 2361 | /* warn if the driver did not check for/react to csa completeness */ | 2378 | /* warn if the driver did not check for/react to csa completeness */ |
| 2362 | if (WARN_ON(((u8 *)beacon->tail)[counter_offset_beacon] == 0)) | 2379 | if (WARN_ON(beacon_data[counter_offset_beacon] == 0)) |
| 2363 | return; | 2380 | return; |
| 2364 | 2381 | ||
| 2365 | ((u8 *)beacon->tail)[counter_offset_beacon]--; | 2382 | beacon_data[counter_offset_beacon]--; |
| 2366 | 2383 | ||
| 2367 | if (sdata->vif.type == NL80211_IFTYPE_AP && | 2384 | if (sdata->vif.type == NL80211_IFTYPE_AP && counter_offset_presp) { |
| 2368 | counter_offset_presp) { | ||
| 2369 | rcu_read_lock(); | 2385 | rcu_read_lock(); |
| 2370 | resp = rcu_dereference(sdata->u.ap.probe_resp); | 2386 | resp = rcu_dereference(sdata->u.ap.probe_resp); |
| 2371 | 2387 | ||
| @@ -2400,6 +2416,15 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) | |||
| 2400 | goto out; | 2416 | goto out; |
| 2401 | beacon_data = beacon->tail; | 2417 | beacon_data = beacon->tail; |
| 2402 | beacon_data_len = beacon->tail_len; | 2418 | beacon_data_len = beacon->tail_len; |
| 2419 | } else if (vif->type == NL80211_IFTYPE_ADHOC) { | ||
| 2420 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
| 2421 | |||
| 2422 | beacon = rcu_dereference(ifibss->presp); | ||
| 2423 | if (!beacon) | ||
| 2424 | goto out; | ||
| 2425 | |||
| 2426 | beacon_data = beacon->head; | ||
| 2427 | beacon_data_len = beacon->head_len; | ||
| 2403 | } else { | 2428 | } else { |
| 2404 | WARN_ON(1); | 2429 | WARN_ON(1); |
| 2405 | goto out; | 2430 | goto out; |
| @@ -2484,6 +2509,10 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2484 | if (!presp) | 2509 | if (!presp) |
| 2485 | goto out; | 2510 | goto out; |
| 2486 | 2511 | ||
| 2512 | if (sdata->vif.csa_active) | ||
| 2513 | ieee80211_update_csa(sdata, presp); | ||
| 2514 | |||
| 2515 | |||
| 2487 | skb = dev_alloc_skb(local->tx_headroom + presp->head_len); | 2516 | skb = dev_alloc_skb(local->tx_headroom + presp->head_len); |
| 2488 | if (!skb) | 2517 | if (!skb) |
| 2489 | goto out; | 2518 | goto out; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 9c3200bcfc02..1220f5afdb7e 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
| @@ -567,18 +567,15 @@ void ieee80211_flush_queues(struct ieee80211_local *local, | |||
| 567 | IEEE80211_QUEUE_STOP_REASON_FLUSH); | 567 | IEEE80211_QUEUE_STOP_REASON_FLUSH); |
| 568 | } | 568 | } |
| 569 | 569 | ||
| 570 | void ieee80211_iterate_active_interfaces( | 570 | static void __iterate_active_interfaces(struct ieee80211_local *local, |
| 571 | struct ieee80211_hw *hw, u32 iter_flags, | 571 | u32 iter_flags, |
| 572 | void (*iterator)(void *data, u8 *mac, | 572 | void (*iterator)(void *data, u8 *mac, |
| 573 | struct ieee80211_vif *vif), | 573 | struct ieee80211_vif *vif), |
| 574 | void *data) | 574 | void *data) |
| 575 | { | 575 | { |
| 576 | struct ieee80211_local *local = hw_to_local(hw); | ||
| 577 | struct ieee80211_sub_if_data *sdata; | 576 | struct ieee80211_sub_if_data *sdata; |
| 578 | 577 | ||
| 579 | mutex_lock(&local->iflist_mtx); | 578 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
| 580 | |||
| 581 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 582 | switch (sdata->vif.type) { | 579 | switch (sdata->vif.type) { |
| 583 | case NL80211_IFTYPE_MONITOR: | 580 | case NL80211_IFTYPE_MONITOR: |
| 584 | if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) | 581 | if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) |
| @@ -597,13 +594,25 @@ void ieee80211_iterate_active_interfaces( | |||
| 597 | &sdata->vif); | 594 | &sdata->vif); |
| 598 | } | 595 | } |
| 599 | 596 | ||
| 600 | sdata = rcu_dereference_protected(local->monitor_sdata, | 597 | sdata = rcu_dereference_check(local->monitor_sdata, |
| 601 | lockdep_is_held(&local->iflist_mtx)); | 598 | lockdep_is_held(&local->iflist_mtx) || |
| 599 | lockdep_rtnl_is_held()); | ||
| 602 | if (sdata && | 600 | if (sdata && |
| 603 | (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || | 601 | (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || |
| 604 | sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | 602 | sdata->flags & IEEE80211_SDATA_IN_DRIVER)) |
| 605 | iterator(data, sdata->vif.addr, &sdata->vif); | 603 | iterator(data, sdata->vif.addr, &sdata->vif); |
| 604 | } | ||
| 605 | |||
| 606 | void ieee80211_iterate_active_interfaces( | ||
| 607 | struct ieee80211_hw *hw, u32 iter_flags, | ||
| 608 | void (*iterator)(void *data, u8 *mac, | ||
| 609 | struct ieee80211_vif *vif), | ||
| 610 | void *data) | ||
| 611 | { | ||
| 612 | struct ieee80211_local *local = hw_to_local(hw); | ||
| 606 | 613 | ||
| 614 | mutex_lock(&local->iflist_mtx); | ||
| 615 | __iterate_active_interfaces(local, iter_flags, iterator, data); | ||
| 607 | mutex_unlock(&local->iflist_mtx); | 616 | mutex_unlock(&local->iflist_mtx); |
| 608 | } | 617 | } |
| 609 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); | 618 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); |
| @@ -615,38 +624,26 @@ void ieee80211_iterate_active_interfaces_atomic( | |||
| 615 | void *data) | 624 | void *data) |
| 616 | { | 625 | { |
| 617 | struct ieee80211_local *local = hw_to_local(hw); | 626 | struct ieee80211_local *local = hw_to_local(hw); |
| 618 | struct ieee80211_sub_if_data *sdata; | ||
| 619 | 627 | ||
| 620 | rcu_read_lock(); | 628 | rcu_read_lock(); |
| 629 | __iterate_active_interfaces(local, iter_flags, iterator, data); | ||
| 630 | rcu_read_unlock(); | ||
| 631 | } | ||
| 632 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); | ||
| 621 | 633 | ||
| 622 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 634 | void ieee80211_iterate_active_interfaces_rtnl( |
| 623 | switch (sdata->vif.type) { | 635 | struct ieee80211_hw *hw, u32 iter_flags, |
| 624 | case NL80211_IFTYPE_MONITOR: | 636 | void (*iterator)(void *data, u8 *mac, |
| 625 | if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) | 637 | struct ieee80211_vif *vif), |
| 626 | continue; | 638 | void *data) |
| 627 | break; | 639 | { |
| 628 | case NL80211_IFTYPE_AP_VLAN: | 640 | struct ieee80211_local *local = hw_to_local(hw); |
| 629 | continue; | ||
| 630 | default: | ||
| 631 | break; | ||
| 632 | } | ||
| 633 | if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) && | ||
| 634 | !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
| 635 | continue; | ||
| 636 | if (ieee80211_sdata_running(sdata)) | ||
| 637 | iterator(data, sdata->vif.addr, | ||
| 638 | &sdata->vif); | ||
| 639 | } | ||
| 640 | 641 | ||
| 641 | sdata = rcu_dereference(local->monitor_sdata); | 642 | ASSERT_RTNL(); |
| 642 | if (sdata && | ||
| 643 | (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || | ||
| 644 | sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
| 645 | iterator(data, sdata->vif.addr, &sdata->vif); | ||
| 646 | 643 | ||
| 647 | rcu_read_unlock(); | 644 | __iterate_active_interfaces(local, iter_flags, iterator, data); |
| 648 | } | 645 | } |
| 649 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); | 646 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); |
| 650 | 647 | ||
| 651 | /* | 648 | /* |
| 652 | * Nothing should have been stuffed into the workqueue during | 649 | * Nothing should have been stuffed into the workqueue during |
| @@ -1007,14 +1004,21 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
| 1007 | */ | 1004 | */ |
| 1008 | enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION); | 1005 | enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION); |
| 1009 | 1006 | ||
| 1010 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 1007 | /* Set defaults according to 802.11-2007 Table 7-37 */ |
| 1011 | /* Set defaults according to 802.11-2007 Table 7-37 */ | 1008 | aCWmax = 1023; |
| 1012 | aCWmax = 1023; | 1009 | if (use_11b) |
| 1013 | if (use_11b) | 1010 | aCWmin = 31; |
| 1014 | aCWmin = 31; | 1011 | else |
| 1015 | else | 1012 | aCWmin = 15; |
| 1016 | aCWmin = 15; | 1013 | |
| 1014 | /* Confiure old 802.11b/g medium access rules. */ | ||
| 1015 | qparam.cw_max = aCWmax; | ||
| 1016 | qparam.cw_min = aCWmin; | ||
| 1017 | qparam.txop = 0; | ||
| 1018 | qparam.aifs = 2; | ||
| 1017 | 1019 | ||
| 1020 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
| 1021 | /* Update if QoS is enabled. */ | ||
| 1018 | if (enable_qos) { | 1022 | if (enable_qos) { |
| 1019 | switch (ac) { | 1023 | switch (ac) { |
| 1020 | case IEEE80211_AC_BK: | 1024 | case IEEE80211_AC_BK: |
| @@ -1050,12 +1054,6 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
| 1050 | qparam.aifs = 2; | 1054 | qparam.aifs = 2; |
| 1051 | break; | 1055 | break; |
| 1052 | } | 1056 | } |
| 1053 | } else { | ||
| 1054 | /* Confiure old 802.11b/g medium access rules. */ | ||
| 1055 | qparam.cw_max = aCWmax; | ||
| 1056 | qparam.cw_min = aCWmin; | ||
| 1057 | qparam.txop = 0; | ||
| 1058 | qparam.aifs = 2; | ||
| 1059 | } | 1057 | } |
| 1060 | 1058 | ||
| 1061 | qparam.uapsd = false; | 1059 | qparam.uapsd = false; |
| @@ -1084,8 +1082,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
| 1084 | struct ieee80211_mgmt *mgmt; | 1082 | struct ieee80211_mgmt *mgmt; |
| 1085 | int err; | 1083 | int err; |
| 1086 | 1084 | ||
| 1087 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 1085 | /* 24 + 6 = header + auth_algo + auth_transaction + status_code */ |
| 1088 | sizeof(*mgmt) + 6 + extra_len); | 1086 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24 + 6 + extra_len); |
| 1089 | if (!skb) | 1087 | if (!skb) |
| 1090 | return; | 1088 | return; |
| 1091 | 1089 | ||
| @@ -2292,3 +2290,63 @@ void ieee80211_radar_detected(struct ieee80211_hw *hw) | |||
| 2292 | ieee80211_queue_work(hw, &local->radar_detected_work); | 2290 | ieee80211_queue_work(hw, &local->radar_detected_work); |
| 2293 | } | 2291 | } |
| 2294 | EXPORT_SYMBOL(ieee80211_radar_detected); | 2292 | EXPORT_SYMBOL(ieee80211_radar_detected); |
| 2293 | |||
| 2294 | u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c) | ||
| 2295 | { | ||
| 2296 | u32 ret; | ||
| 2297 | int tmp; | ||
| 2298 | |||
| 2299 | switch (c->width) { | ||
| 2300 | case NL80211_CHAN_WIDTH_20: | ||
| 2301 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 2302 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 2303 | break; | ||
| 2304 | case NL80211_CHAN_WIDTH_40: | ||
| 2305 | c->width = NL80211_CHAN_WIDTH_20; | ||
| 2306 | c->center_freq1 = c->chan->center_freq; | ||
| 2307 | ret = IEEE80211_STA_DISABLE_40MHZ | | ||
| 2308 | IEEE80211_STA_DISABLE_VHT; | ||
| 2309 | break; | ||
| 2310 | case NL80211_CHAN_WIDTH_80: | ||
| 2311 | tmp = (30 + c->chan->center_freq - c->center_freq1)/20; | ||
| 2312 | /* n_P40 */ | ||
| 2313 | tmp /= 2; | ||
| 2314 | /* freq_P40 */ | ||
| 2315 | c->center_freq1 = c->center_freq1 - 20 + 40 * tmp; | ||
| 2316 | c->width = NL80211_CHAN_WIDTH_40; | ||
| 2317 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 2318 | break; | ||
| 2319 | case NL80211_CHAN_WIDTH_80P80: | ||
| 2320 | c->center_freq2 = 0; | ||
| 2321 | c->width = NL80211_CHAN_WIDTH_80; | ||
| 2322 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
| 2323 | IEEE80211_STA_DISABLE_160MHZ; | ||
| 2324 | break; | ||
| 2325 | case NL80211_CHAN_WIDTH_160: | ||
| 2326 | /* n_P20 */ | ||
| 2327 | tmp = (70 + c->chan->center_freq - c->center_freq1)/20; | ||
| 2328 | /* n_P80 */ | ||
| 2329 | tmp /= 4; | ||
| 2330 | c->center_freq1 = c->center_freq1 - 40 + 80 * tmp; | ||
| 2331 | c->width = NL80211_CHAN_WIDTH_80; | ||
| 2332 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
| 2333 | IEEE80211_STA_DISABLE_160MHZ; | ||
| 2334 | break; | ||
| 2335 | default: | ||
| 2336 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
| 2337 | WARN_ON_ONCE(1); | ||
| 2338 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 2339 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 2340 | break; | ||
| 2341 | case NL80211_CHAN_WIDTH_5: | ||
| 2342 | case NL80211_CHAN_WIDTH_10: | ||
| 2343 | WARN_ON_ONCE(1); | ||
| 2344 | /* keep c->width */ | ||
| 2345 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 2346 | break; | ||
| 2347 | } | ||
| 2348 | |||
| 2349 | WARN_ON_ONCE(!cfg80211_chandef_valid(c)); | ||
| 2350 | |||
| 2351 | return ret; | ||
| 2352 | } | ||
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 97c289414e32..de0112785aae 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
| @@ -185,13 +185,13 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
| 185 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) { | 185 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) { |
| 186 | vht_cap->cap |= cap_info & | 186 | vht_cap->cap |= cap_info & |
| 187 | (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | | 187 | (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | |
| 188 | IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX | | ||
| 189 | IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX); | 188 | IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX); |
| 190 | } | 189 | } |
| 191 | 190 | ||
| 192 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) | 191 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) |
| 193 | vht_cap->cap |= cap_info & | 192 | vht_cap->cap |= cap_info & |
| 194 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; | 193 | (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | |
| 194 | IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX); | ||
| 195 | 195 | ||
| 196 | if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) | 196 | if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) |
| 197 | vht_cap->cap |= cap_info & | 197 | vht_cap->cap |= cap_info & |
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 50f6195c8b70..16f3c3a7b2c1 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
| @@ -328,6 +328,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy, | |||
| 328 | return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2, | 328 | return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2, |
| 329 | width); | 329 | width); |
| 330 | } | 330 | } |
| 331 | EXPORT_SYMBOL(cfg80211_chandef_dfs_required); | ||
| 331 | 332 | ||
| 332 | static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, | 333 | static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, |
| 333 | u32 center_freq, u32 bandwidth, | 334 | u32 center_freq, u32 bandwidth, |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 9ad43c619c54..b43efac4efca 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
| @@ -382,15 +382,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, | |||
| 382 | enum cfg80211_chan_mode chanmode, | 382 | enum cfg80211_chan_mode chanmode, |
| 383 | u8 radar_detect); | 383 | u8 radar_detect); |
| 384 | 384 | ||
| 385 | /** | ||
| 386 | * cfg80211_chandef_dfs_required - checks if radar detection is required | ||
| 387 | * @wiphy: the wiphy to validate against | ||
| 388 | * @chandef: the channel definition to check | ||
| 389 | * Return: 1 if radar detection is required, 0 if it is not, < 0 on error | ||
| 390 | */ | ||
| 391 | int cfg80211_chandef_dfs_required(struct wiphy *wiphy, | ||
| 392 | const struct cfg80211_chan_def *c); | ||
| 393 | |||
| 394 | void cfg80211_set_dfs_state(struct wiphy *wiphy, | 385 | void cfg80211_set_dfs_state(struct wiphy *wiphy, |
| 395 | const struct cfg80211_chan_def *chandef, | 386 | const struct cfg80211_chan_def *chandef, |
| 396 | enum nl80211_dfs_state dfs_state); | 387 | enum nl80211_dfs_state dfs_state); |
diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c index 90d050036624..454157717efa 100644 --- a/net/wireless/debugfs.c +++ b/net/wireless/debugfs.c | |||
| @@ -47,17 +47,19 @@ static int ht_print_chan(struct ieee80211_channel *chan, | |||
| 47 | return 0; | 47 | return 0; |
| 48 | 48 | ||
| 49 | if (chan->flags & IEEE80211_CHAN_DISABLED) | 49 | if (chan->flags & IEEE80211_CHAN_DISABLED) |
| 50 | return snprintf(buf + offset, | 50 | return scnprintf(buf + offset, |
| 51 | buf_size - offset, | 51 | buf_size - offset, |
| 52 | "%d Disabled\n", | 52 | "%d Disabled\n", |
| 53 | chan->center_freq); | 53 | chan->center_freq); |
| 54 | 54 | ||
| 55 | return snprintf(buf + offset, | 55 | return scnprintf(buf + offset, |
| 56 | buf_size - offset, | 56 | buf_size - offset, |
| 57 | "%d HT40 %c%c\n", | 57 | "%d HT40 %c%c\n", |
| 58 | chan->center_freq, | 58 | chan->center_freq, |
| 59 | (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) ? ' ' : '-', | 59 | (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) ? |
| 60 | (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) ? ' ' : '+'); | 60 | ' ' : '-', |
| 61 | (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) ? | ||
| 62 | ' ' : '+'); | ||
| 61 | } | 63 | } |
| 62 | 64 | ||
| 63 | static ssize_t ht40allow_map_read(struct file *file, | 65 | static ssize_t ht40allow_map_read(struct file *file, |
diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk index 9392f8cbb901..42ed274e81f4 100644 --- a/net/wireless/genregdb.awk +++ b/net/wireless/genregdb.awk | |||
| @@ -46,6 +46,12 @@ BEGIN { | |||
| 46 | sub(/:/, "", country) | 46 | sub(/:/, "", country) |
| 47 | printf "static const struct ieee80211_regdomain regdom_%s = {\n", country | 47 | printf "static const struct ieee80211_regdomain regdom_%s = {\n", country |
| 48 | printf "\t.alpha2 = \"%s\",\n", country | 48 | printf "\t.alpha2 = \"%s\",\n", country |
| 49 | if ($NF ~ /DFS-ETSI/) | ||
| 50 | printf "\t.dfs_region = NL80211_DFS_ETSI,\n" | ||
| 51 | else if ($NF ~ /DFS-FCC/) | ||
| 52 | printf "\t.dfs_region = NL80211_DFS_FCC,\n" | ||
| 53 | else if ($NF ~ /DFS-JP/) | ||
| 54 | printf "\t.dfs_region = NL80211_DFS_JP,\n" | ||
| 49 | printf "\t.reg_rules = {\n" | 55 | printf "\t.reg_rules = {\n" |
| 50 | active = 1 | 56 | active = 1 |
| 51 | regdb = regdb "\t®dom_" country ",\n" | 57 | regdb = regdb "\t®dom_" country ",\n" |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 626dc3b5fd8d..cbbef88a8ebd 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
| @@ -5591,6 +5591,9 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
| 5591 | if (err) | 5591 | if (err) |
| 5592 | return err; | 5592 | return err; |
| 5593 | 5593 | ||
| 5594 | if (netif_carrier_ok(dev)) | ||
| 5595 | return -EBUSY; | ||
| 5596 | |||
| 5594 | if (wdev->cac_started) | 5597 | if (wdev->cac_started) |
| 5595 | return -EBUSY; | 5598 | return -EBUSY; |
| 5596 | 5599 | ||
| @@ -5634,15 +5637,26 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | |||
| 5634 | static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1]; | 5637 | static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1]; |
| 5635 | u8 radar_detect_width = 0; | 5638 | u8 radar_detect_width = 0; |
| 5636 | int err; | 5639 | int err; |
| 5640 | bool need_new_beacon = false; | ||
| 5637 | 5641 | ||
| 5638 | if (!rdev->ops->channel_switch || | 5642 | if (!rdev->ops->channel_switch || |
| 5639 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)) | 5643 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)) |
| 5640 | return -EOPNOTSUPP; | 5644 | return -EOPNOTSUPP; |
| 5641 | 5645 | ||
| 5642 | /* may add IBSS support later */ | 5646 | switch (dev->ieee80211_ptr->iftype) { |
| 5643 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 5647 | case NL80211_IFTYPE_AP: |
| 5644 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 5648 | case NL80211_IFTYPE_P2P_GO: |
| 5649 | need_new_beacon = true; | ||
| 5650 | |||
| 5651 | /* useless if AP is not running */ | ||
| 5652 | if (!wdev->beacon_interval) | ||
| 5653 | return -EINVAL; | ||
| 5654 | break; | ||
| 5655 | case NL80211_IFTYPE_ADHOC: | ||
| 5656 | break; | ||
| 5657 | default: | ||
| 5645 | return -EOPNOTSUPP; | 5658 | return -EOPNOTSUPP; |
| 5659 | } | ||
| 5646 | 5660 | ||
| 5647 | memset(¶ms, 0, sizeof(params)); | 5661 | memset(¶ms, 0, sizeof(params)); |
| 5648 | 5662 | ||
| @@ -5651,15 +5665,16 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | |||
| 5651 | return -EINVAL; | 5665 | return -EINVAL; |
| 5652 | 5666 | ||
| 5653 | /* only important for AP, IBSS and mesh create IEs internally */ | 5667 | /* only important for AP, IBSS and mesh create IEs internally */ |
| 5654 | if (!info->attrs[NL80211_ATTR_CSA_IES]) | 5668 | if (need_new_beacon && |
| 5655 | return -EINVAL; | 5669 | (!info->attrs[NL80211_ATTR_CSA_IES] || |
| 5656 | 5670 | !info->attrs[NL80211_ATTR_CSA_C_OFF_BEACON])) | |
| 5657 | /* useless if AP is not running */ | ||
| 5658 | if (!wdev->beacon_interval) | ||
| 5659 | return -EINVAL; | 5671 | return -EINVAL; |
| 5660 | 5672 | ||
| 5661 | params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]); | 5673 | params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]); |
| 5662 | 5674 | ||
| 5675 | if (!need_new_beacon) | ||
| 5676 | goto skip_beacons; | ||
| 5677 | |||
| 5663 | err = nl80211_parse_beacon(info->attrs, ¶ms.beacon_after); | 5678 | err = nl80211_parse_beacon(info->attrs, ¶ms.beacon_after); |
| 5664 | if (err) | 5679 | if (err) |
| 5665 | return err; | 5680 | return err; |
| @@ -5699,6 +5714,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | |||
| 5699 | return -EINVAL; | 5714 | return -EINVAL; |
| 5700 | } | 5715 | } |
| 5701 | 5716 | ||
| 5717 | skip_beacons: | ||
| 5702 | err = nl80211_parse_chandef(rdev, info, ¶ms.chandef); | 5718 | err = nl80211_parse_chandef(rdev, info, ¶ms.chandef); |
| 5703 | if (err) | 5719 | if (err) |
| 5704 | return err; | 5720 | return err; |
| @@ -5706,12 +5722,17 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | |||
| 5706 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) | 5722 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) |
| 5707 | return -EINVAL; | 5723 | return -EINVAL; |
| 5708 | 5724 | ||
| 5709 | err = cfg80211_chandef_dfs_required(wdev->wiphy, ¶ms.chandef); | 5725 | /* DFS channels are only supported for AP/P2P GO ... for now. */ |
| 5710 | if (err < 0) { | 5726 | if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP || |
| 5711 | return err; | 5727 | dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) { |
| 5712 | } else if (err) { | 5728 | err = cfg80211_chandef_dfs_required(wdev->wiphy, |
| 5713 | radar_detect_width = BIT(params.chandef.width); | 5729 | ¶ms.chandef); |
| 5714 | params.radar_required = true; | 5730 | if (err < 0) { |
| 5731 | return err; | ||
| 5732 | } else if (err) { | ||
| 5733 | radar_detect_width = BIT(params.chandef.width); | ||
| 5734 | params.radar_required = true; | ||
| 5735 | } | ||
| 5715 | } | 5736 | } |
| 5716 | 5737 | ||
| 5717 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | 5738 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, |
| @@ -10740,7 +10761,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev, | |||
| 10740 | wdev_lock(wdev); | 10761 | wdev_lock(wdev); |
| 10741 | 10762 | ||
| 10742 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | 10763 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && |
| 10743 | wdev->iftype != NL80211_IFTYPE_P2P_GO)) | 10764 | wdev->iftype != NL80211_IFTYPE_P2P_GO && |
| 10765 | wdev->iftype != NL80211_IFTYPE_ADHOC)) | ||
| 10744 | goto out; | 10766 | goto out; |
| 10745 | 10767 | ||
| 10746 | wdev->channel = chandef->chan; | 10768 | wdev->channel = chandef->chan; |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index de06d5d1287f..d62cb1e91475 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
| @@ -172,11 +172,21 @@ static const struct ieee80211_regdomain world_regdom = { | |||
| 172 | NL80211_RRF_NO_IBSS | | 172 | NL80211_RRF_NO_IBSS | |
| 173 | NL80211_RRF_NO_OFDM), | 173 | NL80211_RRF_NO_OFDM), |
| 174 | /* IEEE 802.11a, channel 36..48 */ | 174 | /* IEEE 802.11a, channel 36..48 */ |
| 175 | REG_RULE(5180-10, 5240+10, 80, 6, 20, | 175 | REG_RULE(5180-10, 5240+10, 160, 6, 20, |
| 176 | NL80211_RRF_PASSIVE_SCAN | | 176 | NL80211_RRF_PASSIVE_SCAN | |
| 177 | NL80211_RRF_NO_IBSS), | 177 | NL80211_RRF_NO_IBSS), |
| 178 | 178 | ||
| 179 | /* NB: 5260 MHz - 5700 MHz requires DFS */ | 179 | /* IEEE 802.11a, channel 52..64 - DFS required */ |
| 180 | REG_RULE(5260-10, 5320+10, 160, 6, 20, | ||
| 181 | NL80211_RRF_PASSIVE_SCAN | | ||
| 182 | NL80211_RRF_NO_IBSS | | ||
| 183 | NL80211_RRF_DFS), | ||
| 184 | |||
| 185 | /* IEEE 802.11a, channel 100..144 - DFS required */ | ||
| 186 | REG_RULE(5500-10, 5720+10, 160, 6, 20, | ||
| 187 | NL80211_RRF_PASSIVE_SCAN | | ||
| 188 | NL80211_RRF_NO_IBSS | | ||
| 189 | NL80211_RRF_DFS), | ||
| 180 | 190 | ||
| 181 | /* IEEE 802.11a, channel 149..165 */ | 191 | /* IEEE 802.11a, channel 149..165 */ |
| 182 | REG_RULE(5745-10, 5825+10, 80, 6, 20, | 192 | REG_RULE(5745-10, 5825+10, 80, 6, 20, |
diff --git a/net/wireless/util.c b/net/wireless/util.c index ce090c1c5e4f..3c8be6104ba4 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <net/cfg80211.h> | 10 | #include <net/cfg80211.h> |
| 11 | #include <net/ip.h> | 11 | #include <net/ip.h> |
| 12 | #include <net/dsfield.h> | 12 | #include <net/dsfield.h> |
| 13 | #include <linux/if_vlan.h> | ||
| 13 | #include "core.h" | 14 | #include "core.h" |
| 14 | #include "rdev-ops.h" | 15 | #include "rdev-ops.h" |
| 15 | 16 | ||
| @@ -691,6 +692,7 @@ EXPORT_SYMBOL(ieee80211_amsdu_to_8023s); | |||
| 691 | unsigned int cfg80211_classify8021d(struct sk_buff *skb) | 692 | unsigned int cfg80211_classify8021d(struct sk_buff *skb) |
| 692 | { | 693 | { |
| 693 | unsigned int dscp; | 694 | unsigned int dscp; |
| 695 | unsigned char vlan_priority; | ||
| 694 | 696 | ||
| 695 | /* skb->priority values from 256->263 are magic values to | 697 | /* skb->priority values from 256->263 are magic values to |
| 696 | * directly indicate a specific 802.1d priority. This is used | 698 | * directly indicate a specific 802.1d priority. This is used |
| @@ -700,6 +702,13 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb) | |||
| 700 | if (skb->priority >= 256 && skb->priority <= 263) | 702 | if (skb->priority >= 256 && skb->priority <= 263) |
| 701 | return skb->priority - 256; | 703 | return skb->priority - 256; |
| 702 | 704 | ||
| 705 | if (vlan_tx_tag_present(skb)) { | ||
| 706 | vlan_priority = (vlan_tx_tag_get(skb) & VLAN_PRIO_MASK) | ||
| 707 | >> VLAN_PRIO_SHIFT; | ||
| 708 | if (vlan_priority > 0) | ||
| 709 | return vlan_priority; | ||
| 710 | } | ||
| 711 | |||
| 703 | switch (skb->protocol) { | 712 | switch (skb->protocol) { |
| 704 | case htons(ETH_P_IP): | 713 | case htons(ETH_P_IP): |
| 705 | dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc; | 714 | dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc; |
