xref: /OK3568_Linux_fs/kernel/net/mac80211/cfg.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * mac80211 configuration hooks for cfg80211
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2006-2010	Johannes Berg <johannes@sipsolutions.net>
6*4882a593Smuzhiyun  * Copyright 2013-2015  Intel Mobile Communications GmbH
7*4882a593Smuzhiyun  * Copyright (C) 2015-2017 Intel Deutschland GmbH
8*4882a593Smuzhiyun  * Copyright (C) 2018-2020 Intel Corporation
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/ieee80211.h>
12*4882a593Smuzhiyun #include <linux/nl80211.h>
13*4882a593Smuzhiyun #include <linux/rtnetlink.h>
14*4882a593Smuzhiyun #include <linux/slab.h>
15*4882a593Smuzhiyun #include <net/net_namespace.h>
16*4882a593Smuzhiyun #include <linux/rcupdate.h>
17*4882a593Smuzhiyun #include <linux/fips.h>
18*4882a593Smuzhiyun #include <linux/if_ether.h>
19*4882a593Smuzhiyun #include <net/cfg80211.h>
20*4882a593Smuzhiyun #include "ieee80211_i.h"
21*4882a593Smuzhiyun #include "driver-ops.h"
22*4882a593Smuzhiyun #include "rate.h"
23*4882a593Smuzhiyun #include "mesh.h"
24*4882a593Smuzhiyun #include "wme.h"
25*4882a593Smuzhiyun 
ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data * sdata,struct vif_params * params)26*4882a593Smuzhiyun static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata,
27*4882a593Smuzhiyun 					 struct vif_params *params)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun 	bool mu_mimo_groups = false;
30*4882a593Smuzhiyun 	bool mu_mimo_follow = false;
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	if (params->vht_mumimo_groups) {
33*4882a593Smuzhiyun 		u64 membership;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 		BUILD_BUG_ON(sizeof(membership) != WLAN_MEMBERSHIP_LEN);
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 		memcpy(sdata->vif.bss_conf.mu_group.membership,
38*4882a593Smuzhiyun 		       params->vht_mumimo_groups, WLAN_MEMBERSHIP_LEN);
39*4882a593Smuzhiyun 		memcpy(sdata->vif.bss_conf.mu_group.position,
40*4882a593Smuzhiyun 		       params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN,
41*4882a593Smuzhiyun 		       WLAN_USER_POSITION_LEN);
42*4882a593Smuzhiyun 		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_MU_GROUPS);
43*4882a593Smuzhiyun 		/* don't care about endianness - just check for 0 */
44*4882a593Smuzhiyun 		memcpy(&membership, params->vht_mumimo_groups,
45*4882a593Smuzhiyun 		       WLAN_MEMBERSHIP_LEN);
46*4882a593Smuzhiyun 		mu_mimo_groups = membership != 0;
47*4882a593Smuzhiyun 	}
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	if (params->vht_mumimo_follow_addr) {
50*4882a593Smuzhiyun 		mu_mimo_follow =
51*4882a593Smuzhiyun 			is_valid_ether_addr(params->vht_mumimo_follow_addr);
52*4882a593Smuzhiyun 		ether_addr_copy(sdata->u.mntr.mu_follow_addr,
53*4882a593Smuzhiyun 				params->vht_mumimo_follow_addr);
54*4882a593Smuzhiyun 	}
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	sdata->vif.mu_mimo_owner = mu_mimo_groups || mu_mimo_follow;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun 
ieee80211_set_mon_options(struct ieee80211_sub_if_data * sdata,struct vif_params * params)59*4882a593Smuzhiyun static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,
60*4882a593Smuzhiyun 				     struct vif_params *params)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
63*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *monitor_sdata;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	/* check flags first */
66*4882a593Smuzhiyun 	if (params->flags && ieee80211_sdata_running(sdata)) {
67*4882a593Smuzhiyun 		u32 mask = MONITOR_FLAG_COOK_FRAMES | MONITOR_FLAG_ACTIVE;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 		/*
70*4882a593Smuzhiyun 		 * Prohibit MONITOR_FLAG_COOK_FRAMES and
71*4882a593Smuzhiyun 		 * MONITOR_FLAG_ACTIVE to be changed while the
72*4882a593Smuzhiyun 		 * interface is up.
73*4882a593Smuzhiyun 		 * Else we would need to add a lot of cruft
74*4882a593Smuzhiyun 		 * to update everything:
75*4882a593Smuzhiyun 		 *	cooked_mntrs, monitor and all fif_* counters
76*4882a593Smuzhiyun 		 *	reconfigure hardware
77*4882a593Smuzhiyun 		 */
78*4882a593Smuzhiyun 		if ((params->flags & mask) != (sdata->u.mntr.flags & mask))
79*4882a593Smuzhiyun 			return -EBUSY;
80*4882a593Smuzhiyun 	}
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	/* also validate MU-MIMO change */
83*4882a593Smuzhiyun 	monitor_sdata = rtnl_dereference(local->monitor_sdata);
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	if (!monitor_sdata &&
86*4882a593Smuzhiyun 	    (params->vht_mumimo_groups || params->vht_mumimo_follow_addr))
87*4882a593Smuzhiyun 		return -EOPNOTSUPP;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	/* apply all changes now - no failures allowed */
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	if (monitor_sdata)
92*4882a593Smuzhiyun 		ieee80211_set_mu_mimo_follow(monitor_sdata, params);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	if (params->flags) {
95*4882a593Smuzhiyun 		if (ieee80211_sdata_running(sdata)) {
96*4882a593Smuzhiyun 			ieee80211_adjust_monitor_flags(sdata, -1);
97*4882a593Smuzhiyun 			sdata->u.mntr.flags = params->flags;
98*4882a593Smuzhiyun 			ieee80211_adjust_monitor_flags(sdata, 1);
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 			ieee80211_configure_filter(local);
101*4882a593Smuzhiyun 		} else {
102*4882a593Smuzhiyun 			/*
103*4882a593Smuzhiyun 			 * Because the interface is down, ieee80211_do_stop
104*4882a593Smuzhiyun 			 * and ieee80211_do_open take care of "everything"
105*4882a593Smuzhiyun 			 * mentioned in the comment above.
106*4882a593Smuzhiyun 			 */
107*4882a593Smuzhiyun 			sdata->u.mntr.flags = params->flags;
108*4882a593Smuzhiyun 		}
109*4882a593Smuzhiyun 	}
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	return 0;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
ieee80211_add_iface(struct wiphy * wiphy,const char * name,unsigned char name_assign_type,enum nl80211_iftype type,struct vif_params * params)114*4882a593Smuzhiyun static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy,
115*4882a593Smuzhiyun 						const char *name,
116*4882a593Smuzhiyun 						unsigned char name_assign_type,
117*4882a593Smuzhiyun 						enum nl80211_iftype type,
118*4882a593Smuzhiyun 						struct vif_params *params)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
121*4882a593Smuzhiyun 	struct wireless_dev *wdev;
122*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
123*4882a593Smuzhiyun 	int err;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	err = ieee80211_if_add(local, name, name_assign_type, &wdev, type, params);
126*4882a593Smuzhiyun 	if (err)
127*4882a593Smuzhiyun 		return ERR_PTR(err);
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	if (type == NL80211_IFTYPE_MONITOR) {
132*4882a593Smuzhiyun 		err = ieee80211_set_mon_options(sdata, params);
133*4882a593Smuzhiyun 		if (err) {
134*4882a593Smuzhiyun 			ieee80211_if_remove(sdata);
135*4882a593Smuzhiyun 			return NULL;
136*4882a593Smuzhiyun 		}
137*4882a593Smuzhiyun 	}
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	return wdev;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
ieee80211_del_iface(struct wiphy * wiphy,struct wireless_dev * wdev)142*4882a593Smuzhiyun static int ieee80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	ieee80211_if_remove(IEEE80211_WDEV_TO_SUB_IF(wdev));
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	return 0;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun 
ieee80211_change_iface(struct wiphy * wiphy,struct net_device * dev,enum nl80211_iftype type,struct vif_params * params)149*4882a593Smuzhiyun static int ieee80211_change_iface(struct wiphy *wiphy,
150*4882a593Smuzhiyun 				  struct net_device *dev,
151*4882a593Smuzhiyun 				  enum nl80211_iftype type,
152*4882a593Smuzhiyun 				  struct vif_params *params)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
155*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
156*4882a593Smuzhiyun 	struct sta_info *sta;
157*4882a593Smuzhiyun 	int ret;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	ret = ieee80211_if_change_type(sdata, type);
160*4882a593Smuzhiyun 	if (ret)
161*4882a593Smuzhiyun 		return ret;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	if (type == NL80211_IFTYPE_AP_VLAN && params->use_4addr == 0) {
164*4882a593Smuzhiyun 		RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
165*4882a593Smuzhiyun 		ieee80211_check_fast_rx_iface(sdata);
166*4882a593Smuzhiyun 	} else if (type == NL80211_IFTYPE_STATION && params->use_4addr >= 0) {
167*4882a593Smuzhiyun 		struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 		if (params->use_4addr == ifmgd->use_4addr)
170*4882a593Smuzhiyun 			return 0;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 		sdata->u.mgd.use_4addr = params->use_4addr;
173*4882a593Smuzhiyun 		if (!ifmgd->associated)
174*4882a593Smuzhiyun 			return 0;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 		mutex_lock(&local->sta_mtx);
177*4882a593Smuzhiyun 		sta = sta_info_get(sdata, ifmgd->bssid);
178*4882a593Smuzhiyun 		if (sta)
179*4882a593Smuzhiyun 			drv_sta_set_4addr(local, sdata, &sta->sta,
180*4882a593Smuzhiyun 					  params->use_4addr);
181*4882a593Smuzhiyun 		mutex_unlock(&local->sta_mtx);
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 		if (params->use_4addr)
184*4882a593Smuzhiyun 			ieee80211_send_4addr_nullfunc(local, sdata);
185*4882a593Smuzhiyun 	}
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
188*4882a593Smuzhiyun 		ret = ieee80211_set_mon_options(sdata, params);
189*4882a593Smuzhiyun 		if (ret)
190*4882a593Smuzhiyun 			return ret;
191*4882a593Smuzhiyun 	}
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	return 0;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun 
ieee80211_start_p2p_device(struct wiphy * wiphy,struct wireless_dev * wdev)196*4882a593Smuzhiyun static int ieee80211_start_p2p_device(struct wiphy *wiphy,
197*4882a593Smuzhiyun 				      struct wireless_dev *wdev)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
200*4882a593Smuzhiyun 	int ret;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	mutex_lock(&sdata->local->chanctx_mtx);
203*4882a593Smuzhiyun 	ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
204*4882a593Smuzhiyun 	mutex_unlock(&sdata->local->chanctx_mtx);
205*4882a593Smuzhiyun 	if (ret < 0)
206*4882a593Smuzhiyun 		return ret;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	return ieee80211_do_open(wdev, true);
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun 
ieee80211_stop_p2p_device(struct wiphy * wiphy,struct wireless_dev * wdev)211*4882a593Smuzhiyun static void ieee80211_stop_p2p_device(struct wiphy *wiphy,
212*4882a593Smuzhiyun 				      struct wireless_dev *wdev)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun 	ieee80211_sdata_stop(IEEE80211_WDEV_TO_SUB_IF(wdev));
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
ieee80211_start_nan(struct wiphy * wiphy,struct wireless_dev * wdev,struct cfg80211_nan_conf * conf)217*4882a593Smuzhiyun static int ieee80211_start_nan(struct wiphy *wiphy,
218*4882a593Smuzhiyun 			       struct wireless_dev *wdev,
219*4882a593Smuzhiyun 			       struct cfg80211_nan_conf *conf)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
222*4882a593Smuzhiyun 	int ret;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	mutex_lock(&sdata->local->chanctx_mtx);
225*4882a593Smuzhiyun 	ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
226*4882a593Smuzhiyun 	mutex_unlock(&sdata->local->chanctx_mtx);
227*4882a593Smuzhiyun 	if (ret < 0)
228*4882a593Smuzhiyun 		return ret;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	ret = ieee80211_do_open(wdev, true);
231*4882a593Smuzhiyun 	if (ret)
232*4882a593Smuzhiyun 		return ret;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	ret = drv_start_nan(sdata->local, sdata, conf);
235*4882a593Smuzhiyun 	if (ret)
236*4882a593Smuzhiyun 		ieee80211_sdata_stop(sdata);
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	sdata->u.nan.conf = *conf;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	return ret;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun 
ieee80211_stop_nan(struct wiphy * wiphy,struct wireless_dev * wdev)243*4882a593Smuzhiyun static void ieee80211_stop_nan(struct wiphy *wiphy,
244*4882a593Smuzhiyun 			       struct wireless_dev *wdev)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	drv_stop_nan(sdata->local, sdata);
249*4882a593Smuzhiyun 	ieee80211_sdata_stop(sdata);
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
ieee80211_nan_change_conf(struct wiphy * wiphy,struct wireless_dev * wdev,struct cfg80211_nan_conf * conf,u32 changes)252*4882a593Smuzhiyun static int ieee80211_nan_change_conf(struct wiphy *wiphy,
253*4882a593Smuzhiyun 				     struct wireless_dev *wdev,
254*4882a593Smuzhiyun 				     struct cfg80211_nan_conf *conf,
255*4882a593Smuzhiyun 				     u32 changes)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
258*4882a593Smuzhiyun 	struct cfg80211_nan_conf new_conf;
259*4882a593Smuzhiyun 	int ret = 0;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	if (sdata->vif.type != NL80211_IFTYPE_NAN)
262*4882a593Smuzhiyun 		return -EOPNOTSUPP;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	if (!ieee80211_sdata_running(sdata))
265*4882a593Smuzhiyun 		return -ENETDOWN;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	new_conf = sdata->u.nan.conf;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	if (changes & CFG80211_NAN_CONF_CHANGED_PREF)
270*4882a593Smuzhiyun 		new_conf.master_pref = conf->master_pref;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	if (changes & CFG80211_NAN_CONF_CHANGED_BANDS)
273*4882a593Smuzhiyun 		new_conf.bands = conf->bands;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	ret = drv_nan_change_conf(sdata->local, sdata, &new_conf, changes);
276*4882a593Smuzhiyun 	if (!ret)
277*4882a593Smuzhiyun 		sdata->u.nan.conf = new_conf;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	return ret;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun 
ieee80211_add_nan_func(struct wiphy * wiphy,struct wireless_dev * wdev,struct cfg80211_nan_func * nan_func)282*4882a593Smuzhiyun static int ieee80211_add_nan_func(struct wiphy *wiphy,
283*4882a593Smuzhiyun 				  struct wireless_dev *wdev,
284*4882a593Smuzhiyun 				  struct cfg80211_nan_func *nan_func)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
287*4882a593Smuzhiyun 	int ret;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	if (sdata->vif.type != NL80211_IFTYPE_NAN)
290*4882a593Smuzhiyun 		return -EOPNOTSUPP;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	if (!ieee80211_sdata_running(sdata))
293*4882a593Smuzhiyun 		return -ENETDOWN;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	spin_lock_bh(&sdata->u.nan.func_lock);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	ret = idr_alloc(&sdata->u.nan.function_inst_ids,
298*4882a593Smuzhiyun 			nan_func, 1, sdata->local->hw.max_nan_de_entries + 1,
299*4882a593Smuzhiyun 			GFP_ATOMIC);
300*4882a593Smuzhiyun 	spin_unlock_bh(&sdata->u.nan.func_lock);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	if (ret < 0)
303*4882a593Smuzhiyun 		return ret;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	nan_func->instance_id = ret;
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	WARN_ON(nan_func->instance_id == 0);
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	ret = drv_add_nan_func(sdata->local, sdata, nan_func);
310*4882a593Smuzhiyun 	if (ret) {
311*4882a593Smuzhiyun 		spin_lock_bh(&sdata->u.nan.func_lock);
312*4882a593Smuzhiyun 		idr_remove(&sdata->u.nan.function_inst_ids,
313*4882a593Smuzhiyun 			   nan_func->instance_id);
314*4882a593Smuzhiyun 		spin_unlock_bh(&sdata->u.nan.func_lock);
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	return ret;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun static struct cfg80211_nan_func *
ieee80211_find_nan_func_by_cookie(struct ieee80211_sub_if_data * sdata,u64 cookie)321*4882a593Smuzhiyun ieee80211_find_nan_func_by_cookie(struct ieee80211_sub_if_data *sdata,
322*4882a593Smuzhiyun 				  u64 cookie)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun 	struct cfg80211_nan_func *func;
325*4882a593Smuzhiyun 	int id;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	lockdep_assert_held(&sdata->u.nan.func_lock);
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, id) {
330*4882a593Smuzhiyun 		if (func->cookie == cookie)
331*4882a593Smuzhiyun 			return func;
332*4882a593Smuzhiyun 	}
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	return NULL;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun 
ieee80211_del_nan_func(struct wiphy * wiphy,struct wireless_dev * wdev,u64 cookie)337*4882a593Smuzhiyun static void ieee80211_del_nan_func(struct wiphy *wiphy,
338*4882a593Smuzhiyun 				  struct wireless_dev *wdev, u64 cookie)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
341*4882a593Smuzhiyun 	struct cfg80211_nan_func *func;
342*4882a593Smuzhiyun 	u8 instance_id = 0;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	if (sdata->vif.type != NL80211_IFTYPE_NAN ||
345*4882a593Smuzhiyun 	    !ieee80211_sdata_running(sdata))
346*4882a593Smuzhiyun 		return;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	spin_lock_bh(&sdata->u.nan.func_lock);
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	func = ieee80211_find_nan_func_by_cookie(sdata, cookie);
351*4882a593Smuzhiyun 	if (func)
352*4882a593Smuzhiyun 		instance_id = func->instance_id;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	spin_unlock_bh(&sdata->u.nan.func_lock);
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	if (instance_id)
357*4882a593Smuzhiyun 		drv_del_nan_func(sdata->local, sdata, instance_id);
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun 
ieee80211_set_noack_map(struct wiphy * wiphy,struct net_device * dev,u16 noack_map)360*4882a593Smuzhiyun static int ieee80211_set_noack_map(struct wiphy *wiphy,
361*4882a593Smuzhiyun 				  struct net_device *dev,
362*4882a593Smuzhiyun 				  u16 noack_map)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	sdata->noack_map = noack_map;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	ieee80211_check_fast_xmit_iface(sdata);
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	return 0;
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun 
ieee80211_set_tx(struct ieee80211_sub_if_data * sdata,const u8 * mac_addr,u8 key_idx)373*4882a593Smuzhiyun static int ieee80211_set_tx(struct ieee80211_sub_if_data *sdata,
374*4882a593Smuzhiyun 			    const u8 *mac_addr, u8 key_idx)
375*4882a593Smuzhiyun {
376*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
377*4882a593Smuzhiyun 	struct ieee80211_key *key;
378*4882a593Smuzhiyun 	struct sta_info *sta;
379*4882a593Smuzhiyun 	int ret = -EINVAL;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	if (!wiphy_ext_feature_isset(local->hw.wiphy,
382*4882a593Smuzhiyun 				     NL80211_EXT_FEATURE_EXT_KEY_ID))
383*4882a593Smuzhiyun 		return -EINVAL;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	sta = sta_info_get_bss(sdata, mac_addr);
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	if (!sta)
388*4882a593Smuzhiyun 		return -EINVAL;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	if (sta->ptk_idx == key_idx)
391*4882a593Smuzhiyun 		return 0;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	mutex_lock(&local->key_mtx);
394*4882a593Smuzhiyun 	key = key_mtx_dereference(local, sta->ptk[key_idx]);
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	if (key && key->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX)
397*4882a593Smuzhiyun 		ret = ieee80211_set_tx_key(key);
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	mutex_unlock(&local->key_mtx);
400*4882a593Smuzhiyun 	return ret;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun 
ieee80211_add_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool pairwise,const u8 * mac_addr,struct key_params * params)403*4882a593Smuzhiyun static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
404*4882a593Smuzhiyun 			     u8 key_idx, bool pairwise, const u8 *mac_addr,
405*4882a593Smuzhiyun 			     struct key_params *params)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
408*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
409*4882a593Smuzhiyun 	struct sta_info *sta = NULL;
410*4882a593Smuzhiyun 	const struct ieee80211_cipher_scheme *cs = NULL;
411*4882a593Smuzhiyun 	struct ieee80211_key *key;
412*4882a593Smuzhiyun 	int err;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	if (!ieee80211_sdata_running(sdata))
415*4882a593Smuzhiyun 		return -ENETDOWN;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	if (pairwise && params->mode == NL80211_KEY_SET_TX)
418*4882a593Smuzhiyun 		return ieee80211_set_tx(sdata, mac_addr, key_idx);
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	/* reject WEP and TKIP keys if WEP failed to initialize */
421*4882a593Smuzhiyun 	switch (params->cipher) {
422*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_WEP40:
423*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_TKIP:
424*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_WEP104:
425*4882a593Smuzhiyun 		if (WARN_ON_ONCE(fips_enabled))
426*4882a593Smuzhiyun 			return -EINVAL;
427*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_CCMP:
428*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_CCMP_256:
429*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_AES_CMAC:
430*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
431*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
432*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
433*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_GCMP:
434*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_GCMP_256:
435*4882a593Smuzhiyun 		break;
436*4882a593Smuzhiyun 	default:
437*4882a593Smuzhiyun 		cs = ieee80211_cs_get(local, params->cipher, sdata->vif.type);
438*4882a593Smuzhiyun 		break;
439*4882a593Smuzhiyun 	}
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len,
442*4882a593Smuzhiyun 				  params->key, params->seq_len, params->seq,
443*4882a593Smuzhiyun 				  cs);
444*4882a593Smuzhiyun 	if (IS_ERR(key))
445*4882a593Smuzhiyun 		return PTR_ERR(key);
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	if (pairwise)
448*4882a593Smuzhiyun 		key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	if (params->mode == NL80211_KEY_NO_TX)
451*4882a593Smuzhiyun 		key->conf.flags |= IEEE80211_KEY_FLAG_NO_AUTO_TX;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	mutex_lock(&local->sta_mtx);
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	if (mac_addr) {
456*4882a593Smuzhiyun 		sta = sta_info_get_bss(sdata, mac_addr);
457*4882a593Smuzhiyun 		/*
458*4882a593Smuzhiyun 		 * The ASSOC test makes sure the driver is ready to
459*4882a593Smuzhiyun 		 * receive the key. When wpa_supplicant has roamed
460*4882a593Smuzhiyun 		 * using FT, it attempts to set the key before
461*4882a593Smuzhiyun 		 * association has completed, this rejects that attempt
462*4882a593Smuzhiyun 		 * so it will set the key again after association.
463*4882a593Smuzhiyun 		 *
464*4882a593Smuzhiyun 		 * TODO: accept the key if we have a station entry and
465*4882a593Smuzhiyun 		 *       add it to the device after the station.
466*4882a593Smuzhiyun 		 */
467*4882a593Smuzhiyun 		if (!sta || !test_sta_flag(sta, WLAN_STA_ASSOC)) {
468*4882a593Smuzhiyun 			ieee80211_key_free_unused(key);
469*4882a593Smuzhiyun 			err = -ENOENT;
470*4882a593Smuzhiyun 			goto out_unlock;
471*4882a593Smuzhiyun 		}
472*4882a593Smuzhiyun 	}
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	switch (sdata->vif.type) {
475*4882a593Smuzhiyun 	case NL80211_IFTYPE_STATION:
476*4882a593Smuzhiyun 		if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED)
477*4882a593Smuzhiyun 			key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT;
478*4882a593Smuzhiyun 		break;
479*4882a593Smuzhiyun 	case NL80211_IFTYPE_AP:
480*4882a593Smuzhiyun 	case NL80211_IFTYPE_AP_VLAN:
481*4882a593Smuzhiyun 		/* Keys without a station are used for TX only */
482*4882a593Smuzhiyun 		if (sta && test_sta_flag(sta, WLAN_STA_MFP))
483*4882a593Smuzhiyun 			key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT;
484*4882a593Smuzhiyun 		break;
485*4882a593Smuzhiyun 	case NL80211_IFTYPE_ADHOC:
486*4882a593Smuzhiyun 		/* no MFP (yet) */
487*4882a593Smuzhiyun 		break;
488*4882a593Smuzhiyun 	case NL80211_IFTYPE_MESH_POINT:
489*4882a593Smuzhiyun #ifdef CONFIG_MAC80211_MESH
490*4882a593Smuzhiyun 		if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)
491*4882a593Smuzhiyun 			key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT;
492*4882a593Smuzhiyun 		break;
493*4882a593Smuzhiyun #endif
494*4882a593Smuzhiyun 	case NL80211_IFTYPE_WDS:
495*4882a593Smuzhiyun 	case NL80211_IFTYPE_MONITOR:
496*4882a593Smuzhiyun 	case NL80211_IFTYPE_P2P_DEVICE:
497*4882a593Smuzhiyun 	case NL80211_IFTYPE_NAN:
498*4882a593Smuzhiyun 	case NL80211_IFTYPE_UNSPECIFIED:
499*4882a593Smuzhiyun 	case NUM_NL80211_IFTYPES:
500*4882a593Smuzhiyun 	case NL80211_IFTYPE_P2P_CLIENT:
501*4882a593Smuzhiyun 	case NL80211_IFTYPE_P2P_GO:
502*4882a593Smuzhiyun 	case NL80211_IFTYPE_OCB:
503*4882a593Smuzhiyun 		/* shouldn't happen */
504*4882a593Smuzhiyun 		WARN_ON_ONCE(1);
505*4882a593Smuzhiyun 		break;
506*4882a593Smuzhiyun 	}
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 	if (sta)
509*4882a593Smuzhiyun 		sta->cipher_scheme = cs;
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	err = ieee80211_key_link(key, sdata, sta);
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun  out_unlock:
514*4882a593Smuzhiyun 	mutex_unlock(&local->sta_mtx);
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	return err;
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun 
ieee80211_del_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool pairwise,const u8 * mac_addr)519*4882a593Smuzhiyun static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
520*4882a593Smuzhiyun 			     u8 key_idx, bool pairwise, const u8 *mac_addr)
521*4882a593Smuzhiyun {
522*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
523*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
524*4882a593Smuzhiyun 	struct sta_info *sta;
525*4882a593Smuzhiyun 	struct ieee80211_key *key = NULL;
526*4882a593Smuzhiyun 	int ret;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	mutex_lock(&local->sta_mtx);
529*4882a593Smuzhiyun 	mutex_lock(&local->key_mtx);
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	if (mac_addr) {
532*4882a593Smuzhiyun 		ret = -ENOENT;
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 		sta = sta_info_get_bss(sdata, mac_addr);
535*4882a593Smuzhiyun 		if (!sta)
536*4882a593Smuzhiyun 			goto out_unlock;
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 		if (pairwise)
539*4882a593Smuzhiyun 			key = key_mtx_dereference(local, sta->ptk[key_idx]);
540*4882a593Smuzhiyun 		else
541*4882a593Smuzhiyun 			key = key_mtx_dereference(local, sta->gtk[key_idx]);
542*4882a593Smuzhiyun 	} else
543*4882a593Smuzhiyun 		key = key_mtx_dereference(local, sdata->keys[key_idx]);
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	if (!key) {
546*4882a593Smuzhiyun 		ret = -ENOENT;
547*4882a593Smuzhiyun 		goto out_unlock;
548*4882a593Smuzhiyun 	}
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	ieee80211_key_free(key, sdata->vif.type == NL80211_IFTYPE_STATION);
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	ret = 0;
553*4882a593Smuzhiyun  out_unlock:
554*4882a593Smuzhiyun 	mutex_unlock(&local->key_mtx);
555*4882a593Smuzhiyun 	mutex_unlock(&local->sta_mtx);
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	return ret;
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun 
ieee80211_get_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool pairwise,const u8 * mac_addr,void * cookie,void (* callback)(void * cookie,struct key_params * params))560*4882a593Smuzhiyun static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
561*4882a593Smuzhiyun 			     u8 key_idx, bool pairwise, const u8 *mac_addr,
562*4882a593Smuzhiyun 			     void *cookie,
563*4882a593Smuzhiyun 			     void (*callback)(void *cookie,
564*4882a593Smuzhiyun 					      struct key_params *params))
565*4882a593Smuzhiyun {
566*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
567*4882a593Smuzhiyun 	struct sta_info *sta = NULL;
568*4882a593Smuzhiyun 	u8 seq[6] = {0};
569*4882a593Smuzhiyun 	struct key_params params;
570*4882a593Smuzhiyun 	struct ieee80211_key *key = NULL;
571*4882a593Smuzhiyun 	u64 pn64;
572*4882a593Smuzhiyun 	u32 iv32;
573*4882a593Smuzhiyun 	u16 iv16;
574*4882a593Smuzhiyun 	int err = -ENOENT;
575*4882a593Smuzhiyun 	struct ieee80211_key_seq kseq = {};
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	rcu_read_lock();
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	if (mac_addr) {
582*4882a593Smuzhiyun 		sta = sta_info_get_bss(sdata, mac_addr);
583*4882a593Smuzhiyun 		if (!sta)
584*4882a593Smuzhiyun 			goto out;
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 		if (pairwise && key_idx < NUM_DEFAULT_KEYS)
587*4882a593Smuzhiyun 			key = rcu_dereference(sta->ptk[key_idx]);
588*4882a593Smuzhiyun 		else if (!pairwise &&
589*4882a593Smuzhiyun 			 key_idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
590*4882a593Smuzhiyun 			 NUM_DEFAULT_BEACON_KEYS)
591*4882a593Smuzhiyun 			key = rcu_dereference(sta->gtk[key_idx]);
592*4882a593Smuzhiyun 	} else
593*4882a593Smuzhiyun 		key = rcu_dereference(sdata->keys[key_idx]);
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	if (!key)
596*4882a593Smuzhiyun 		goto out;
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	memset(&params, 0, sizeof(params));
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	params.cipher = key->conf.cipher;
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	switch (key->conf.cipher) {
603*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_TKIP:
604*4882a593Smuzhiyun 		pn64 = atomic64_read(&key->conf.tx_pn);
605*4882a593Smuzhiyun 		iv32 = TKIP_PN_TO_IV32(pn64);
606*4882a593Smuzhiyun 		iv16 = TKIP_PN_TO_IV16(pn64);
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 		if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
609*4882a593Smuzhiyun 		    !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
610*4882a593Smuzhiyun 			drv_get_key_seq(sdata->local, key, &kseq);
611*4882a593Smuzhiyun 			iv32 = kseq.tkip.iv32;
612*4882a593Smuzhiyun 			iv16 = kseq.tkip.iv16;
613*4882a593Smuzhiyun 		}
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 		seq[0] = iv16 & 0xff;
616*4882a593Smuzhiyun 		seq[1] = (iv16 >> 8) & 0xff;
617*4882a593Smuzhiyun 		seq[2] = iv32 & 0xff;
618*4882a593Smuzhiyun 		seq[3] = (iv32 >> 8) & 0xff;
619*4882a593Smuzhiyun 		seq[4] = (iv32 >> 16) & 0xff;
620*4882a593Smuzhiyun 		seq[5] = (iv32 >> 24) & 0xff;
621*4882a593Smuzhiyun 		params.seq = seq;
622*4882a593Smuzhiyun 		params.seq_len = 6;
623*4882a593Smuzhiyun 		break;
624*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_CCMP:
625*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_CCMP_256:
626*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_AES_CMAC:
627*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
628*4882a593Smuzhiyun 		BUILD_BUG_ON(offsetof(typeof(kseq), ccmp) !=
629*4882a593Smuzhiyun 			     offsetof(typeof(kseq), aes_cmac));
630*4882a593Smuzhiyun 		fallthrough;
631*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
632*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
633*4882a593Smuzhiyun 		BUILD_BUG_ON(offsetof(typeof(kseq), ccmp) !=
634*4882a593Smuzhiyun 			     offsetof(typeof(kseq), aes_gmac));
635*4882a593Smuzhiyun 		fallthrough;
636*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_GCMP:
637*4882a593Smuzhiyun 	case WLAN_CIPHER_SUITE_GCMP_256:
638*4882a593Smuzhiyun 		BUILD_BUG_ON(offsetof(typeof(kseq), ccmp) !=
639*4882a593Smuzhiyun 			     offsetof(typeof(kseq), gcmp));
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 		if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
642*4882a593Smuzhiyun 		    !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
643*4882a593Smuzhiyun 			drv_get_key_seq(sdata->local, key, &kseq);
644*4882a593Smuzhiyun 			memcpy(seq, kseq.ccmp.pn, 6);
645*4882a593Smuzhiyun 		} else {
646*4882a593Smuzhiyun 			pn64 = atomic64_read(&key->conf.tx_pn);
647*4882a593Smuzhiyun 			seq[0] = pn64;
648*4882a593Smuzhiyun 			seq[1] = pn64 >> 8;
649*4882a593Smuzhiyun 			seq[2] = pn64 >> 16;
650*4882a593Smuzhiyun 			seq[3] = pn64 >> 24;
651*4882a593Smuzhiyun 			seq[4] = pn64 >> 32;
652*4882a593Smuzhiyun 			seq[5] = pn64 >> 40;
653*4882a593Smuzhiyun 		}
654*4882a593Smuzhiyun 		params.seq = seq;
655*4882a593Smuzhiyun 		params.seq_len = 6;
656*4882a593Smuzhiyun 		break;
657*4882a593Smuzhiyun 	default:
658*4882a593Smuzhiyun 		if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
659*4882a593Smuzhiyun 			break;
660*4882a593Smuzhiyun 		if (WARN_ON(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))
661*4882a593Smuzhiyun 			break;
662*4882a593Smuzhiyun 		drv_get_key_seq(sdata->local, key, &kseq);
663*4882a593Smuzhiyun 		params.seq = kseq.hw.seq;
664*4882a593Smuzhiyun 		params.seq_len = kseq.hw.seq_len;
665*4882a593Smuzhiyun 		break;
666*4882a593Smuzhiyun 	}
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	params.key = key->conf.key;
669*4882a593Smuzhiyun 	params.key_len = key->conf.keylen;
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	callback(cookie, &params);
672*4882a593Smuzhiyun 	err = 0;
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun  out:
675*4882a593Smuzhiyun 	rcu_read_unlock();
676*4882a593Smuzhiyun 	return err;
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun 
ieee80211_config_default_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool uni,bool multi)679*4882a593Smuzhiyun static int ieee80211_config_default_key(struct wiphy *wiphy,
680*4882a593Smuzhiyun 					struct net_device *dev,
681*4882a593Smuzhiyun 					u8 key_idx, bool uni,
682*4882a593Smuzhiyun 					bool multi)
683*4882a593Smuzhiyun {
684*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	ieee80211_set_default_key(sdata, key_idx, uni, multi);
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	return 0;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun 
ieee80211_config_default_mgmt_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx)691*4882a593Smuzhiyun static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy,
692*4882a593Smuzhiyun 					     struct net_device *dev,
693*4882a593Smuzhiyun 					     u8 key_idx)
694*4882a593Smuzhiyun {
695*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun 	ieee80211_set_default_mgmt_key(sdata, key_idx);
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	return 0;
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun 
ieee80211_config_default_beacon_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx)702*4882a593Smuzhiyun static int ieee80211_config_default_beacon_key(struct wiphy *wiphy,
703*4882a593Smuzhiyun 					       struct net_device *dev,
704*4882a593Smuzhiyun 					       u8 key_idx)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	ieee80211_set_default_beacon_key(sdata, key_idx);
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	return 0;
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun 
sta_set_rate_info_tx(struct sta_info * sta,const struct ieee80211_tx_rate * rate,struct rate_info * rinfo)713*4882a593Smuzhiyun void sta_set_rate_info_tx(struct sta_info *sta,
714*4882a593Smuzhiyun 			  const struct ieee80211_tx_rate *rate,
715*4882a593Smuzhiyun 			  struct rate_info *rinfo)
716*4882a593Smuzhiyun {
717*4882a593Smuzhiyun 	rinfo->flags = 0;
718*4882a593Smuzhiyun 	if (rate->flags & IEEE80211_TX_RC_MCS) {
719*4882a593Smuzhiyun 		rinfo->flags |= RATE_INFO_FLAGS_MCS;
720*4882a593Smuzhiyun 		rinfo->mcs = rate->idx;
721*4882a593Smuzhiyun 	} else if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
722*4882a593Smuzhiyun 		rinfo->flags |= RATE_INFO_FLAGS_VHT_MCS;
723*4882a593Smuzhiyun 		rinfo->mcs = ieee80211_rate_get_vht_mcs(rate);
724*4882a593Smuzhiyun 		rinfo->nss = ieee80211_rate_get_vht_nss(rate);
725*4882a593Smuzhiyun 	} else {
726*4882a593Smuzhiyun 		struct ieee80211_supported_band *sband;
727*4882a593Smuzhiyun 		int shift = ieee80211_vif_get_shift(&sta->sdata->vif);
728*4882a593Smuzhiyun 		u16 brate;
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 		sband = ieee80211_get_sband(sta->sdata);
731*4882a593Smuzhiyun 		WARN_ON_ONCE(sband && !sband->bitrates);
732*4882a593Smuzhiyun 		if (sband && sband->bitrates) {
733*4882a593Smuzhiyun 			brate = sband->bitrates[rate->idx].bitrate;
734*4882a593Smuzhiyun 			rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
735*4882a593Smuzhiyun 		}
736*4882a593Smuzhiyun 	}
737*4882a593Smuzhiyun 	if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
738*4882a593Smuzhiyun 		rinfo->bw = RATE_INFO_BW_40;
739*4882a593Smuzhiyun 	else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
740*4882a593Smuzhiyun 		rinfo->bw = RATE_INFO_BW_80;
741*4882a593Smuzhiyun 	else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
742*4882a593Smuzhiyun 		rinfo->bw = RATE_INFO_BW_160;
743*4882a593Smuzhiyun 	else
744*4882a593Smuzhiyun 		rinfo->bw = RATE_INFO_BW_20;
745*4882a593Smuzhiyun 	if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
746*4882a593Smuzhiyun 		rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
747*4882a593Smuzhiyun }
748*4882a593Smuzhiyun 
ieee80211_dump_station(struct wiphy * wiphy,struct net_device * dev,int idx,u8 * mac,struct station_info * sinfo)749*4882a593Smuzhiyun static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
750*4882a593Smuzhiyun 				  int idx, u8 *mac, struct station_info *sinfo)
751*4882a593Smuzhiyun {
752*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
753*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
754*4882a593Smuzhiyun 	struct sta_info *sta;
755*4882a593Smuzhiyun 	int ret = -ENOENT;
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	mutex_lock(&local->sta_mtx);
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	sta = sta_info_get_by_idx(sdata, idx);
760*4882a593Smuzhiyun 	if (sta) {
761*4882a593Smuzhiyun 		ret = 0;
762*4882a593Smuzhiyun 		memcpy(mac, sta->sta.addr, ETH_ALEN);
763*4882a593Smuzhiyun 		sta_set_sinfo(sta, sinfo, true);
764*4882a593Smuzhiyun 	}
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	mutex_unlock(&local->sta_mtx);
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 	return ret;
769*4882a593Smuzhiyun }
770*4882a593Smuzhiyun 
ieee80211_dump_survey(struct wiphy * wiphy,struct net_device * dev,int idx,struct survey_info * survey)771*4882a593Smuzhiyun static int ieee80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
772*4882a593Smuzhiyun 				 int idx, struct survey_info *survey)
773*4882a593Smuzhiyun {
774*4882a593Smuzhiyun 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	return drv_get_survey(local, idx, survey);
777*4882a593Smuzhiyun }
778*4882a593Smuzhiyun 
ieee80211_get_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_info * sinfo)779*4882a593Smuzhiyun static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
780*4882a593Smuzhiyun 				 const u8 *mac, struct station_info *sinfo)
781*4882a593Smuzhiyun {
782*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
783*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
784*4882a593Smuzhiyun 	struct sta_info *sta;
785*4882a593Smuzhiyun 	int ret = -ENOENT;
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 	mutex_lock(&local->sta_mtx);
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 	sta = sta_info_get_bss(sdata, mac);
790*4882a593Smuzhiyun 	if (sta) {
791*4882a593Smuzhiyun 		ret = 0;
792*4882a593Smuzhiyun 		sta_set_sinfo(sta, sinfo, true);
793*4882a593Smuzhiyun 	}
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	mutex_unlock(&local->sta_mtx);
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	return ret;
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun 
ieee80211_set_monitor_channel(struct wiphy * wiphy,struct cfg80211_chan_def * chandef)800*4882a593Smuzhiyun static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
801*4882a593Smuzhiyun 					 struct cfg80211_chan_def *chandef)
802*4882a593Smuzhiyun {
803*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
804*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
805*4882a593Smuzhiyun 	int ret = 0;
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 	if (cfg80211_chandef_identical(&local->monitor_chandef, chandef))
808*4882a593Smuzhiyun 		return 0;
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	mutex_lock(&local->mtx);
811*4882a593Smuzhiyun 	if (local->use_chanctx) {
812*4882a593Smuzhiyun 		sdata = rtnl_dereference(local->monitor_sdata);
813*4882a593Smuzhiyun 		if (sdata) {
814*4882a593Smuzhiyun 			ieee80211_vif_release_channel(sdata);
815*4882a593Smuzhiyun 			ret = ieee80211_vif_use_channel(sdata, chandef,
816*4882a593Smuzhiyun 					IEEE80211_CHANCTX_EXCLUSIVE);
817*4882a593Smuzhiyun 		}
818*4882a593Smuzhiyun 	} else if (local->open_count == local->monitors) {
819*4882a593Smuzhiyun 		local->_oper_chandef = *chandef;
820*4882a593Smuzhiyun 		ieee80211_hw_config(local, 0);
821*4882a593Smuzhiyun 	}
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun 	if (ret == 0)
824*4882a593Smuzhiyun 		local->monitor_chandef = *chandef;
825*4882a593Smuzhiyun 	mutex_unlock(&local->mtx);
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun 	return ret;
828*4882a593Smuzhiyun }
829*4882a593Smuzhiyun 
ieee80211_set_probe_resp(struct ieee80211_sub_if_data * sdata,const u8 * resp,size_t resp_len,const struct ieee80211_csa_settings * csa)830*4882a593Smuzhiyun static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
831*4882a593Smuzhiyun 				    const u8 *resp, size_t resp_len,
832*4882a593Smuzhiyun 				    const struct ieee80211_csa_settings *csa)
833*4882a593Smuzhiyun {
834*4882a593Smuzhiyun 	struct probe_resp *new, *old;
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 	if (!resp || !resp_len)
837*4882a593Smuzhiyun 		return 1;
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 	old = sdata_dereference(sdata->u.ap.probe_resp, sdata);
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 	new = kzalloc(sizeof(struct probe_resp) + resp_len, GFP_KERNEL);
842*4882a593Smuzhiyun 	if (!new)
843*4882a593Smuzhiyun 		return -ENOMEM;
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 	new->len = resp_len;
846*4882a593Smuzhiyun 	memcpy(new->data, resp, resp_len);
847*4882a593Smuzhiyun 
848*4882a593Smuzhiyun 	if (csa)
849*4882a593Smuzhiyun 		memcpy(new->cntdwn_counter_offsets, csa->counter_offsets_presp,
850*4882a593Smuzhiyun 		       csa->n_counter_offsets_presp *
851*4882a593Smuzhiyun 		       sizeof(new->cntdwn_counter_offsets[0]));
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 	rcu_assign_pointer(sdata->u.ap.probe_resp, new);
854*4882a593Smuzhiyun 	if (old)
855*4882a593Smuzhiyun 		kfree_rcu(old, rcu_head);
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	return 0;
858*4882a593Smuzhiyun }
859*4882a593Smuzhiyun 
ieee80211_set_fils_discovery(struct ieee80211_sub_if_data * sdata,struct cfg80211_fils_discovery * params)860*4882a593Smuzhiyun static int ieee80211_set_fils_discovery(struct ieee80211_sub_if_data *sdata,
861*4882a593Smuzhiyun 					struct cfg80211_fils_discovery *params)
862*4882a593Smuzhiyun {
863*4882a593Smuzhiyun 	struct fils_discovery_data *new, *old = NULL;
864*4882a593Smuzhiyun 	struct ieee80211_fils_discovery *fd;
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun 	if (!params->tmpl || !params->tmpl_len)
867*4882a593Smuzhiyun 		return -EINVAL;
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 	fd = &sdata->vif.bss_conf.fils_discovery;
870*4882a593Smuzhiyun 	fd->min_interval = params->min_interval;
871*4882a593Smuzhiyun 	fd->max_interval = params->max_interval;
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun 	old = sdata_dereference(sdata->u.ap.fils_discovery, sdata);
874*4882a593Smuzhiyun 	new = kzalloc(sizeof(*new) + params->tmpl_len, GFP_KERNEL);
875*4882a593Smuzhiyun 	if (!new)
876*4882a593Smuzhiyun 		return -ENOMEM;
877*4882a593Smuzhiyun 	new->len = params->tmpl_len;
878*4882a593Smuzhiyun 	memcpy(new->data, params->tmpl, params->tmpl_len);
879*4882a593Smuzhiyun 	rcu_assign_pointer(sdata->u.ap.fils_discovery, new);
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 	if (old)
882*4882a593Smuzhiyun 		kfree_rcu(old, rcu_head);
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 	return 0;
885*4882a593Smuzhiyun }
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun static int
ieee80211_set_unsol_bcast_probe_resp(struct ieee80211_sub_if_data * sdata,struct cfg80211_unsol_bcast_probe_resp * params)888*4882a593Smuzhiyun ieee80211_set_unsol_bcast_probe_resp(struct ieee80211_sub_if_data *sdata,
889*4882a593Smuzhiyun 				     struct cfg80211_unsol_bcast_probe_resp *params)
890*4882a593Smuzhiyun {
891*4882a593Smuzhiyun 	struct unsol_bcast_probe_resp_data *new, *old = NULL;
892*4882a593Smuzhiyun 
893*4882a593Smuzhiyun 	if (!params->tmpl || !params->tmpl_len)
894*4882a593Smuzhiyun 		return -EINVAL;
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 	old = sdata_dereference(sdata->u.ap.unsol_bcast_probe_resp, sdata);
897*4882a593Smuzhiyun 	new = kzalloc(sizeof(*new) + params->tmpl_len, GFP_KERNEL);
898*4882a593Smuzhiyun 	if (!new)
899*4882a593Smuzhiyun 		return -ENOMEM;
900*4882a593Smuzhiyun 	new->len = params->tmpl_len;
901*4882a593Smuzhiyun 	memcpy(new->data, params->tmpl, params->tmpl_len);
902*4882a593Smuzhiyun 	rcu_assign_pointer(sdata->u.ap.unsol_bcast_probe_resp, new);
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 	if (old)
905*4882a593Smuzhiyun 		kfree_rcu(old, rcu_head);
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	sdata->vif.bss_conf.unsol_bcast_probe_resp_interval =
908*4882a593Smuzhiyun 							params->interval;
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 	return 0;
911*4882a593Smuzhiyun }
912*4882a593Smuzhiyun 
ieee80211_set_ftm_responder_params(struct ieee80211_sub_if_data * sdata,const u8 * lci,size_t lci_len,const u8 * civicloc,size_t civicloc_len)913*4882a593Smuzhiyun static int ieee80211_set_ftm_responder_params(
914*4882a593Smuzhiyun 				struct ieee80211_sub_if_data *sdata,
915*4882a593Smuzhiyun 				const u8 *lci, size_t lci_len,
916*4882a593Smuzhiyun 				const u8 *civicloc, size_t civicloc_len)
917*4882a593Smuzhiyun {
918*4882a593Smuzhiyun 	struct ieee80211_ftm_responder_params *new, *old;
919*4882a593Smuzhiyun 	struct ieee80211_bss_conf *bss_conf;
920*4882a593Smuzhiyun 	u8 *pos;
921*4882a593Smuzhiyun 	int len;
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	if (!lci_len && !civicloc_len)
924*4882a593Smuzhiyun 		return 0;
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	bss_conf = &sdata->vif.bss_conf;
927*4882a593Smuzhiyun 	old = bss_conf->ftmr_params;
928*4882a593Smuzhiyun 	len = lci_len + civicloc_len;
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 	new = kzalloc(sizeof(*new) + len, GFP_KERNEL);
931*4882a593Smuzhiyun 	if (!new)
932*4882a593Smuzhiyun 		return -ENOMEM;
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 	pos = (u8 *)(new + 1);
935*4882a593Smuzhiyun 	if (lci_len) {
936*4882a593Smuzhiyun 		new->lci_len = lci_len;
937*4882a593Smuzhiyun 		new->lci = pos;
938*4882a593Smuzhiyun 		memcpy(pos, lci, lci_len);
939*4882a593Smuzhiyun 		pos += lci_len;
940*4882a593Smuzhiyun 	}
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun 	if (civicloc_len) {
943*4882a593Smuzhiyun 		new->civicloc_len = civicloc_len;
944*4882a593Smuzhiyun 		new->civicloc = pos;
945*4882a593Smuzhiyun 		memcpy(pos, civicloc, civicloc_len);
946*4882a593Smuzhiyun 		pos += civicloc_len;
947*4882a593Smuzhiyun 	}
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun 	bss_conf->ftmr_params = new;
950*4882a593Smuzhiyun 	kfree(old);
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun 	return 0;
953*4882a593Smuzhiyun }
954*4882a593Smuzhiyun 
ieee80211_assign_beacon(struct ieee80211_sub_if_data * sdata,struct cfg80211_beacon_data * params,const struct ieee80211_csa_settings * csa)955*4882a593Smuzhiyun static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
956*4882a593Smuzhiyun 				   struct cfg80211_beacon_data *params,
957*4882a593Smuzhiyun 				   const struct ieee80211_csa_settings *csa)
958*4882a593Smuzhiyun {
959*4882a593Smuzhiyun 	struct beacon_data *new, *old;
960*4882a593Smuzhiyun 	int new_head_len, new_tail_len;
961*4882a593Smuzhiyun 	int size, err;
962*4882a593Smuzhiyun 	u32 changed = BSS_CHANGED_BEACON;
963*4882a593Smuzhiyun 
964*4882a593Smuzhiyun 	old = sdata_dereference(sdata->u.ap.beacon, sdata);
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun 	/* Need to have a beacon head if we don't have one yet */
968*4882a593Smuzhiyun 	if (!params->head && !old)
969*4882a593Smuzhiyun 		return -EINVAL;
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 	/* new or old head? */
972*4882a593Smuzhiyun 	if (params->head)
973*4882a593Smuzhiyun 		new_head_len = params->head_len;
974*4882a593Smuzhiyun 	else
975*4882a593Smuzhiyun 		new_head_len = old->head_len;
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun 	/* new or old tail? */
978*4882a593Smuzhiyun 	if (params->tail || !old)
979*4882a593Smuzhiyun 		/* params->tail_len will be zero for !params->tail */
980*4882a593Smuzhiyun 		new_tail_len = params->tail_len;
981*4882a593Smuzhiyun 	else
982*4882a593Smuzhiyun 		new_tail_len = old->tail_len;
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun 	size = sizeof(*new) + new_head_len + new_tail_len;
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun 	new = kzalloc(size, GFP_KERNEL);
987*4882a593Smuzhiyun 	if (!new)
988*4882a593Smuzhiyun 		return -ENOMEM;
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 	/* start filling the new info now */
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun 	/*
993*4882a593Smuzhiyun 	 * pointers go into the block we allocated,
994*4882a593Smuzhiyun 	 * memory is | beacon_data | head | tail |
995*4882a593Smuzhiyun 	 */
996*4882a593Smuzhiyun 	new->head = ((u8 *) new) + sizeof(*new);
997*4882a593Smuzhiyun 	new->tail = new->head + new_head_len;
998*4882a593Smuzhiyun 	new->head_len = new_head_len;
999*4882a593Smuzhiyun 	new->tail_len = new_tail_len;
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 	if (csa) {
1002*4882a593Smuzhiyun 		new->cntdwn_current_counter = csa->count;
1003*4882a593Smuzhiyun 		memcpy(new->cntdwn_counter_offsets, csa->counter_offsets_beacon,
1004*4882a593Smuzhiyun 		       csa->n_counter_offsets_beacon *
1005*4882a593Smuzhiyun 		       sizeof(new->cntdwn_counter_offsets[0]));
1006*4882a593Smuzhiyun 	}
1007*4882a593Smuzhiyun 
1008*4882a593Smuzhiyun 	/* copy in head */
1009*4882a593Smuzhiyun 	if (params->head)
1010*4882a593Smuzhiyun 		memcpy(new->head, params->head, new_head_len);
1011*4882a593Smuzhiyun 	else
1012*4882a593Smuzhiyun 		memcpy(new->head, old->head, new_head_len);
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 	/* copy in optional tail */
1015*4882a593Smuzhiyun 	if (params->tail)
1016*4882a593Smuzhiyun 		memcpy(new->tail, params->tail, new_tail_len);
1017*4882a593Smuzhiyun 	else
1018*4882a593Smuzhiyun 		if (old)
1019*4882a593Smuzhiyun 			memcpy(new->tail, old->tail, new_tail_len);
1020*4882a593Smuzhiyun 
1021*4882a593Smuzhiyun 	err = ieee80211_set_probe_resp(sdata, params->probe_resp,
1022*4882a593Smuzhiyun 				       params->probe_resp_len, csa);
1023*4882a593Smuzhiyun 	if (err < 0) {
1024*4882a593Smuzhiyun 		kfree(new);
1025*4882a593Smuzhiyun 		return err;
1026*4882a593Smuzhiyun 	}
1027*4882a593Smuzhiyun 	if (err == 0)
1028*4882a593Smuzhiyun 		changed |= BSS_CHANGED_AP_PROBE_RESP;
1029*4882a593Smuzhiyun 
1030*4882a593Smuzhiyun 	if (params->ftm_responder != -1) {
1031*4882a593Smuzhiyun 		sdata->vif.bss_conf.ftm_responder = params->ftm_responder;
1032*4882a593Smuzhiyun 		err = ieee80211_set_ftm_responder_params(sdata,
1033*4882a593Smuzhiyun 							 params->lci,
1034*4882a593Smuzhiyun 							 params->lci_len,
1035*4882a593Smuzhiyun 							 params->civicloc,
1036*4882a593Smuzhiyun 							 params->civicloc_len);
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun 		if (err < 0) {
1039*4882a593Smuzhiyun 			kfree(new);
1040*4882a593Smuzhiyun 			return err;
1041*4882a593Smuzhiyun 		}
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun 		changed |= BSS_CHANGED_FTM_RESPONDER;
1044*4882a593Smuzhiyun 	}
1045*4882a593Smuzhiyun 
1046*4882a593Smuzhiyun 	rcu_assign_pointer(sdata->u.ap.beacon, new);
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 	if (old)
1049*4882a593Smuzhiyun 		kfree_rcu(old, rcu_head);
1050*4882a593Smuzhiyun 
1051*4882a593Smuzhiyun 	return changed;
1052*4882a593Smuzhiyun }
1053*4882a593Smuzhiyun 
ieee80211_start_ap(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_ap_settings * params)1054*4882a593Smuzhiyun static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
1055*4882a593Smuzhiyun 			      struct cfg80211_ap_settings *params)
1056*4882a593Smuzhiyun {
1057*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1058*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
1059*4882a593Smuzhiyun 	struct beacon_data *old;
1060*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *vlan;
1061*4882a593Smuzhiyun 	u32 changed = BSS_CHANGED_BEACON_INT |
1062*4882a593Smuzhiyun 		      BSS_CHANGED_BEACON_ENABLED |
1063*4882a593Smuzhiyun 		      BSS_CHANGED_BEACON |
1064*4882a593Smuzhiyun 		      BSS_CHANGED_SSID |
1065*4882a593Smuzhiyun 		      BSS_CHANGED_P2P_PS |
1066*4882a593Smuzhiyun 		      BSS_CHANGED_TXPOWER |
1067*4882a593Smuzhiyun 		      BSS_CHANGED_TWT;
1068*4882a593Smuzhiyun 	int i, err;
1069*4882a593Smuzhiyun 	int prev_beacon_int;
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun 	old = sdata_dereference(sdata->u.ap.beacon, sdata);
1072*4882a593Smuzhiyun 	if (old)
1073*4882a593Smuzhiyun 		return -EALREADY;
1074*4882a593Smuzhiyun 
1075*4882a593Smuzhiyun 	if (params->smps_mode != NL80211_SMPS_OFF)
1076*4882a593Smuzhiyun 		return -ENOTSUPP;
1077*4882a593Smuzhiyun 
1078*4882a593Smuzhiyun 	sdata->smps_mode = IEEE80211_SMPS_OFF;
1079*4882a593Smuzhiyun 
1080*4882a593Smuzhiyun 	sdata->needed_rx_chains = sdata->local->rx_chains;
1081*4882a593Smuzhiyun 
1082*4882a593Smuzhiyun 	prev_beacon_int = sdata->vif.bss_conf.beacon_int;
1083*4882a593Smuzhiyun 	sdata->vif.bss_conf.beacon_int = params->beacon_interval;
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun 	if (params->he_cap && params->he_oper) {
1086*4882a593Smuzhiyun 		sdata->vif.bss_conf.he_support = true;
1087*4882a593Smuzhiyun 		sdata->vif.bss_conf.htc_trig_based_pkt_ext =
1088*4882a593Smuzhiyun 			le32_get_bits(params->he_oper->he_oper_params,
1089*4882a593Smuzhiyun 			      IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK);
1090*4882a593Smuzhiyun 		sdata->vif.bss_conf.frame_time_rts_th =
1091*4882a593Smuzhiyun 			le32_get_bits(params->he_oper->he_oper_params,
1092*4882a593Smuzhiyun 			      IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK);
1093*4882a593Smuzhiyun 		changed |= BSS_CHANGED_HE_OBSS_PD;
1094*4882a593Smuzhiyun 
1095*4882a593Smuzhiyun 		if (params->he_bss_color.enabled)
1096*4882a593Smuzhiyun 			changed |= BSS_CHANGED_HE_BSS_COLOR;
1097*4882a593Smuzhiyun 	}
1098*4882a593Smuzhiyun 
1099*4882a593Smuzhiyun 	mutex_lock(&local->mtx);
1100*4882a593Smuzhiyun 	err = ieee80211_vif_use_channel(sdata, &params->chandef,
1101*4882a593Smuzhiyun 					IEEE80211_CHANCTX_SHARED);
1102*4882a593Smuzhiyun 	if (!err)
1103*4882a593Smuzhiyun 		ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
1104*4882a593Smuzhiyun 	mutex_unlock(&local->mtx);
1105*4882a593Smuzhiyun 	if (err) {
1106*4882a593Smuzhiyun 		sdata->vif.bss_conf.beacon_int = prev_beacon_int;
1107*4882a593Smuzhiyun 		return err;
1108*4882a593Smuzhiyun 	}
1109*4882a593Smuzhiyun 
1110*4882a593Smuzhiyun 	/*
1111*4882a593Smuzhiyun 	 * Apply control port protocol, this allows us to
1112*4882a593Smuzhiyun 	 * not encrypt dynamic WEP control frames.
1113*4882a593Smuzhiyun 	 */
1114*4882a593Smuzhiyun 	sdata->control_port_protocol = params->crypto.control_port_ethertype;
1115*4882a593Smuzhiyun 	sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt;
1116*4882a593Smuzhiyun 	sdata->control_port_over_nl80211 =
1117*4882a593Smuzhiyun 				params->crypto.control_port_over_nl80211;
1118*4882a593Smuzhiyun 	sdata->control_port_no_preauth =
1119*4882a593Smuzhiyun 				params->crypto.control_port_no_preauth;
1120*4882a593Smuzhiyun 	sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local,
1121*4882a593Smuzhiyun 							&params->crypto,
1122*4882a593Smuzhiyun 							sdata->vif.type);
1123*4882a593Smuzhiyun 
1124*4882a593Smuzhiyun 	list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
1125*4882a593Smuzhiyun 		vlan->control_port_protocol =
1126*4882a593Smuzhiyun 			params->crypto.control_port_ethertype;
1127*4882a593Smuzhiyun 		vlan->control_port_no_encrypt =
1128*4882a593Smuzhiyun 			params->crypto.control_port_no_encrypt;
1129*4882a593Smuzhiyun 		vlan->control_port_over_nl80211 =
1130*4882a593Smuzhiyun 			params->crypto.control_port_over_nl80211;
1131*4882a593Smuzhiyun 		vlan->control_port_no_preauth =
1132*4882a593Smuzhiyun 			params->crypto.control_port_no_preauth;
1133*4882a593Smuzhiyun 		vlan->encrypt_headroom =
1134*4882a593Smuzhiyun 			ieee80211_cs_headroom(sdata->local,
1135*4882a593Smuzhiyun 					      &params->crypto,
1136*4882a593Smuzhiyun 					      vlan->vif.type);
1137*4882a593Smuzhiyun 	}
1138*4882a593Smuzhiyun 
1139*4882a593Smuzhiyun 	sdata->vif.bss_conf.dtim_period = params->dtim_period;
1140*4882a593Smuzhiyun 	sdata->vif.bss_conf.enable_beacon = true;
1141*4882a593Smuzhiyun 	sdata->vif.bss_conf.allow_p2p_go_ps = sdata->vif.p2p;
1142*4882a593Smuzhiyun 	sdata->vif.bss_conf.twt_responder = params->twt_responder;
1143*4882a593Smuzhiyun 	memcpy(&sdata->vif.bss_conf.he_obss_pd, &params->he_obss_pd,
1144*4882a593Smuzhiyun 	       sizeof(struct ieee80211_he_obss_pd));
1145*4882a593Smuzhiyun 	memcpy(&sdata->vif.bss_conf.he_bss_color, &params->he_bss_color,
1146*4882a593Smuzhiyun 	       sizeof(struct ieee80211_he_bss_color));
1147*4882a593Smuzhiyun 	sdata->vif.bss_conf.s1g = params->chandef.chan->band ==
1148*4882a593Smuzhiyun 				  NL80211_BAND_S1GHZ;
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun 	sdata->vif.bss_conf.ssid_len = params->ssid_len;
1151*4882a593Smuzhiyun 	if (params->ssid_len)
1152*4882a593Smuzhiyun 		memcpy(sdata->vif.bss_conf.ssid, params->ssid,
1153*4882a593Smuzhiyun 		       params->ssid_len);
1154*4882a593Smuzhiyun 	sdata->vif.bss_conf.hidden_ssid =
1155*4882a593Smuzhiyun 		(params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
1156*4882a593Smuzhiyun 
1157*4882a593Smuzhiyun 	memset(&sdata->vif.bss_conf.p2p_noa_attr, 0,
1158*4882a593Smuzhiyun 	       sizeof(sdata->vif.bss_conf.p2p_noa_attr));
1159*4882a593Smuzhiyun 	sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow =
1160*4882a593Smuzhiyun 		params->p2p_ctwindow & IEEE80211_P2P_OPPPS_CTWINDOW_MASK;
1161*4882a593Smuzhiyun 	if (params->p2p_opp_ps)
1162*4882a593Smuzhiyun 		sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |=
1163*4882a593Smuzhiyun 					IEEE80211_P2P_OPPPS_ENABLE_BIT;
1164*4882a593Smuzhiyun 
1165*4882a593Smuzhiyun 	sdata->beacon_rate_set = false;
1166*4882a593Smuzhiyun 	if (wiphy_ext_feature_isset(local->hw.wiphy,
1167*4882a593Smuzhiyun 				    NL80211_EXT_FEATURE_BEACON_RATE_LEGACY)) {
1168*4882a593Smuzhiyun 		for (i = 0; i < NUM_NL80211_BANDS; i++) {
1169*4882a593Smuzhiyun 			sdata->beacon_rateidx_mask[i] =
1170*4882a593Smuzhiyun 				params->beacon_rate.control[i].legacy;
1171*4882a593Smuzhiyun 			if (sdata->beacon_rateidx_mask[i])
1172*4882a593Smuzhiyun 				sdata->beacon_rate_set = true;
1173*4882a593Smuzhiyun 		}
1174*4882a593Smuzhiyun 	}
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun 	if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL))
1177*4882a593Smuzhiyun 		sdata->vif.bss_conf.beacon_tx_rate = params->beacon_rate;
1178*4882a593Smuzhiyun 
1179*4882a593Smuzhiyun 	err = ieee80211_assign_beacon(sdata, &params->beacon, NULL);
1180*4882a593Smuzhiyun 	if (err < 0)
1181*4882a593Smuzhiyun 		goto error;
1182*4882a593Smuzhiyun 	changed |= err;
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun 	if (params->fils_discovery.max_interval) {
1185*4882a593Smuzhiyun 		err = ieee80211_set_fils_discovery(sdata,
1186*4882a593Smuzhiyun 						   &params->fils_discovery);
1187*4882a593Smuzhiyun 		if (err < 0)
1188*4882a593Smuzhiyun 			goto error;
1189*4882a593Smuzhiyun 		changed |= BSS_CHANGED_FILS_DISCOVERY;
1190*4882a593Smuzhiyun 	}
1191*4882a593Smuzhiyun 
1192*4882a593Smuzhiyun 	if (params->unsol_bcast_probe_resp.interval) {
1193*4882a593Smuzhiyun 		err = ieee80211_set_unsol_bcast_probe_resp(sdata,
1194*4882a593Smuzhiyun 							   &params->unsol_bcast_probe_resp);
1195*4882a593Smuzhiyun 		if (err < 0)
1196*4882a593Smuzhiyun 			goto error;
1197*4882a593Smuzhiyun 		changed |= BSS_CHANGED_UNSOL_BCAST_PROBE_RESP;
1198*4882a593Smuzhiyun 	}
1199*4882a593Smuzhiyun 
1200*4882a593Smuzhiyun 	err = drv_start_ap(sdata->local, sdata);
1201*4882a593Smuzhiyun 	if (err) {
1202*4882a593Smuzhiyun 		old = sdata_dereference(sdata->u.ap.beacon, sdata);
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun 		if (old)
1205*4882a593Smuzhiyun 			kfree_rcu(old, rcu_head);
1206*4882a593Smuzhiyun 		RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
1207*4882a593Smuzhiyun 		goto error;
1208*4882a593Smuzhiyun 	}
1209*4882a593Smuzhiyun 
1210*4882a593Smuzhiyun 	ieee80211_recalc_dtim(local, sdata);
1211*4882a593Smuzhiyun 	ieee80211_bss_info_change_notify(sdata, changed);
1212*4882a593Smuzhiyun 
1213*4882a593Smuzhiyun 	netif_carrier_on(dev);
1214*4882a593Smuzhiyun 	list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
1215*4882a593Smuzhiyun 		netif_carrier_on(vlan->dev);
1216*4882a593Smuzhiyun 
1217*4882a593Smuzhiyun 	return 0;
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun error:
1220*4882a593Smuzhiyun 	mutex_lock(&local->mtx);
1221*4882a593Smuzhiyun 	ieee80211_vif_release_channel(sdata);
1222*4882a593Smuzhiyun 	mutex_unlock(&local->mtx);
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun 	return err;
1225*4882a593Smuzhiyun }
1226*4882a593Smuzhiyun 
ieee80211_change_beacon(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_beacon_data * params)1227*4882a593Smuzhiyun static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
1228*4882a593Smuzhiyun 				   struct cfg80211_beacon_data *params)
1229*4882a593Smuzhiyun {
1230*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
1231*4882a593Smuzhiyun 	struct beacon_data *old;
1232*4882a593Smuzhiyun 	int err;
1233*4882a593Smuzhiyun 
1234*4882a593Smuzhiyun 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1235*4882a593Smuzhiyun 	sdata_assert_lock(sdata);
1236*4882a593Smuzhiyun 
1237*4882a593Smuzhiyun 	/* don't allow changing the beacon while CSA is in place - offset
1238*4882a593Smuzhiyun 	 * of channel switch counter may change
1239*4882a593Smuzhiyun 	 */
1240*4882a593Smuzhiyun 	if (sdata->vif.csa_active)
1241*4882a593Smuzhiyun 		return -EBUSY;
1242*4882a593Smuzhiyun 
1243*4882a593Smuzhiyun 	old = sdata_dereference(sdata->u.ap.beacon, sdata);
1244*4882a593Smuzhiyun 	if (!old)
1245*4882a593Smuzhiyun 		return -ENOENT;
1246*4882a593Smuzhiyun 
1247*4882a593Smuzhiyun 	err = ieee80211_assign_beacon(sdata, params, NULL);
1248*4882a593Smuzhiyun 	if (err < 0)
1249*4882a593Smuzhiyun 		return err;
1250*4882a593Smuzhiyun 	ieee80211_bss_info_change_notify(sdata, err);
1251*4882a593Smuzhiyun 	return 0;
1252*4882a593Smuzhiyun }
1253*4882a593Smuzhiyun 
ieee80211_stop_ap(struct wiphy * wiphy,struct net_device * dev)1254*4882a593Smuzhiyun static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
1255*4882a593Smuzhiyun {
1256*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1257*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *vlan;
1258*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
1259*4882a593Smuzhiyun 	struct beacon_data *old_beacon;
1260*4882a593Smuzhiyun 	struct probe_resp *old_probe_resp;
1261*4882a593Smuzhiyun 	struct fils_discovery_data *old_fils_discovery;
1262*4882a593Smuzhiyun 	struct unsol_bcast_probe_resp_data *old_unsol_bcast_probe_resp;
1263*4882a593Smuzhiyun 	struct cfg80211_chan_def chandef;
1264*4882a593Smuzhiyun 
1265*4882a593Smuzhiyun 	sdata_assert_lock(sdata);
1266*4882a593Smuzhiyun 
1267*4882a593Smuzhiyun 	old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata);
1268*4882a593Smuzhiyun 	if (!old_beacon)
1269*4882a593Smuzhiyun 		return -ENOENT;
1270*4882a593Smuzhiyun 	old_probe_resp = sdata_dereference(sdata->u.ap.probe_resp, sdata);
1271*4882a593Smuzhiyun 	old_fils_discovery = sdata_dereference(sdata->u.ap.fils_discovery,
1272*4882a593Smuzhiyun 					       sdata);
1273*4882a593Smuzhiyun 	old_unsol_bcast_probe_resp =
1274*4882a593Smuzhiyun 		sdata_dereference(sdata->u.ap.unsol_bcast_probe_resp,
1275*4882a593Smuzhiyun 				  sdata);
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun 	/* abort any running channel switch */
1278*4882a593Smuzhiyun 	mutex_lock(&local->mtx);
1279*4882a593Smuzhiyun 	sdata->vif.csa_active = false;
1280*4882a593Smuzhiyun 	if (sdata->csa_block_tx) {
1281*4882a593Smuzhiyun 		ieee80211_wake_vif_queues(local, sdata,
1282*4882a593Smuzhiyun 					  IEEE80211_QUEUE_STOP_REASON_CSA);
1283*4882a593Smuzhiyun 		sdata->csa_block_tx = false;
1284*4882a593Smuzhiyun 	}
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun 	mutex_unlock(&local->mtx);
1287*4882a593Smuzhiyun 
1288*4882a593Smuzhiyun 	kfree(sdata->u.ap.next_beacon);
1289*4882a593Smuzhiyun 	sdata->u.ap.next_beacon = NULL;
1290*4882a593Smuzhiyun 
1291*4882a593Smuzhiyun 	/* turn off carrier for this interface and dependent VLANs */
1292*4882a593Smuzhiyun 	list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
1293*4882a593Smuzhiyun 		netif_carrier_off(vlan->dev);
1294*4882a593Smuzhiyun 	netif_carrier_off(dev);
1295*4882a593Smuzhiyun 
1296*4882a593Smuzhiyun 	/* remove beacon and probe response */
1297*4882a593Smuzhiyun 	RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
1298*4882a593Smuzhiyun 	RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL);
1299*4882a593Smuzhiyun 	RCU_INIT_POINTER(sdata->u.ap.fils_discovery, NULL);
1300*4882a593Smuzhiyun 	RCU_INIT_POINTER(sdata->u.ap.unsol_bcast_probe_resp, NULL);
1301*4882a593Smuzhiyun 	kfree_rcu(old_beacon, rcu_head);
1302*4882a593Smuzhiyun 	if (old_probe_resp)
1303*4882a593Smuzhiyun 		kfree_rcu(old_probe_resp, rcu_head);
1304*4882a593Smuzhiyun 	if (old_fils_discovery)
1305*4882a593Smuzhiyun 		kfree_rcu(old_fils_discovery, rcu_head);
1306*4882a593Smuzhiyun 	if (old_unsol_bcast_probe_resp)
1307*4882a593Smuzhiyun 		kfree_rcu(old_unsol_bcast_probe_resp, rcu_head);
1308*4882a593Smuzhiyun 
1309*4882a593Smuzhiyun 	kfree(sdata->vif.bss_conf.ftmr_params);
1310*4882a593Smuzhiyun 	sdata->vif.bss_conf.ftmr_params = NULL;
1311*4882a593Smuzhiyun 
1312*4882a593Smuzhiyun 	__sta_info_flush(sdata, true);
1313*4882a593Smuzhiyun 	ieee80211_free_keys(sdata, true);
1314*4882a593Smuzhiyun 
1315*4882a593Smuzhiyun 	sdata->vif.bss_conf.enable_beacon = false;
1316*4882a593Smuzhiyun 	sdata->beacon_rate_set = false;
1317*4882a593Smuzhiyun 	sdata->vif.bss_conf.ssid_len = 0;
1318*4882a593Smuzhiyun 	clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
1319*4882a593Smuzhiyun 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
1320*4882a593Smuzhiyun 
1321*4882a593Smuzhiyun 	if (sdata->wdev.cac_started) {
1322*4882a593Smuzhiyun 		chandef = sdata->vif.bss_conf.chandef;
1323*4882a593Smuzhiyun 		cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
1324*4882a593Smuzhiyun 		cfg80211_cac_event(sdata->dev, &chandef,
1325*4882a593Smuzhiyun 				   NL80211_RADAR_CAC_ABORTED,
1326*4882a593Smuzhiyun 				   GFP_KERNEL);
1327*4882a593Smuzhiyun 	}
1328*4882a593Smuzhiyun 
1329*4882a593Smuzhiyun 	drv_stop_ap(sdata->local, sdata);
1330*4882a593Smuzhiyun 
1331*4882a593Smuzhiyun 	/* free all potentially still buffered bcast frames */
1332*4882a593Smuzhiyun 	local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
1333*4882a593Smuzhiyun 	ieee80211_purge_tx_queue(&local->hw, &sdata->u.ap.ps.bc_buf);
1334*4882a593Smuzhiyun 
1335*4882a593Smuzhiyun 	mutex_lock(&local->mtx);
1336*4882a593Smuzhiyun 	ieee80211_vif_copy_chanctx_to_vlans(sdata, true);
1337*4882a593Smuzhiyun 	ieee80211_vif_release_channel(sdata);
1338*4882a593Smuzhiyun 	mutex_unlock(&local->mtx);
1339*4882a593Smuzhiyun 
1340*4882a593Smuzhiyun 	return 0;
1341*4882a593Smuzhiyun }
1342*4882a593Smuzhiyun 
sta_apply_auth_flags(struct ieee80211_local * local,struct sta_info * sta,u32 mask,u32 set)1343*4882a593Smuzhiyun static int sta_apply_auth_flags(struct ieee80211_local *local,
1344*4882a593Smuzhiyun 				struct sta_info *sta,
1345*4882a593Smuzhiyun 				u32 mask, u32 set)
1346*4882a593Smuzhiyun {
1347*4882a593Smuzhiyun 	int ret;
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun 	if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
1350*4882a593Smuzhiyun 	    set & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
1351*4882a593Smuzhiyun 	    !test_sta_flag(sta, WLAN_STA_AUTH)) {
1352*4882a593Smuzhiyun 		ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
1353*4882a593Smuzhiyun 		if (ret)
1354*4882a593Smuzhiyun 			return ret;
1355*4882a593Smuzhiyun 	}
1356*4882a593Smuzhiyun 
1357*4882a593Smuzhiyun 	if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
1358*4882a593Smuzhiyun 	    set & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
1359*4882a593Smuzhiyun 	    !test_sta_flag(sta, WLAN_STA_ASSOC)) {
1360*4882a593Smuzhiyun 		/*
1361*4882a593Smuzhiyun 		 * When peer becomes associated, init rate control as
1362*4882a593Smuzhiyun 		 * well. Some drivers require rate control initialized
1363*4882a593Smuzhiyun 		 * before drv_sta_state() is called.
1364*4882a593Smuzhiyun 		 */
1365*4882a593Smuzhiyun 		if (!test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
1366*4882a593Smuzhiyun 			rate_control_rate_init(sta);
1367*4882a593Smuzhiyun 
1368*4882a593Smuzhiyun 		ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
1369*4882a593Smuzhiyun 		if (ret)
1370*4882a593Smuzhiyun 			return ret;
1371*4882a593Smuzhiyun 	}
1372*4882a593Smuzhiyun 
1373*4882a593Smuzhiyun 	if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
1374*4882a593Smuzhiyun 		if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
1375*4882a593Smuzhiyun 			ret = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
1376*4882a593Smuzhiyun 		else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
1377*4882a593Smuzhiyun 			ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
1378*4882a593Smuzhiyun 		else
1379*4882a593Smuzhiyun 			ret = 0;
1380*4882a593Smuzhiyun 		if (ret)
1381*4882a593Smuzhiyun 			return ret;
1382*4882a593Smuzhiyun 	}
1383*4882a593Smuzhiyun 
1384*4882a593Smuzhiyun 	if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
1385*4882a593Smuzhiyun 	    !(set & BIT(NL80211_STA_FLAG_ASSOCIATED)) &&
1386*4882a593Smuzhiyun 	    test_sta_flag(sta, WLAN_STA_ASSOC)) {
1387*4882a593Smuzhiyun 		ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
1388*4882a593Smuzhiyun 		if (ret)
1389*4882a593Smuzhiyun 			return ret;
1390*4882a593Smuzhiyun 	}
1391*4882a593Smuzhiyun 
1392*4882a593Smuzhiyun 	if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
1393*4882a593Smuzhiyun 	    !(set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) &&
1394*4882a593Smuzhiyun 	    test_sta_flag(sta, WLAN_STA_AUTH)) {
1395*4882a593Smuzhiyun 		ret = sta_info_move_state(sta, IEEE80211_STA_NONE);
1396*4882a593Smuzhiyun 		if (ret)
1397*4882a593Smuzhiyun 			return ret;
1398*4882a593Smuzhiyun 	}
1399*4882a593Smuzhiyun 
1400*4882a593Smuzhiyun 	return 0;
1401*4882a593Smuzhiyun }
1402*4882a593Smuzhiyun 
sta_apply_mesh_params(struct ieee80211_local * local,struct sta_info * sta,struct station_parameters * params)1403*4882a593Smuzhiyun static void sta_apply_mesh_params(struct ieee80211_local *local,
1404*4882a593Smuzhiyun 				  struct sta_info *sta,
1405*4882a593Smuzhiyun 				  struct station_parameters *params)
1406*4882a593Smuzhiyun {
1407*4882a593Smuzhiyun #ifdef CONFIG_MAC80211_MESH
1408*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = sta->sdata;
1409*4882a593Smuzhiyun 	u32 changed = 0;
1410*4882a593Smuzhiyun 
1411*4882a593Smuzhiyun 	if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) {
1412*4882a593Smuzhiyun 		switch (params->plink_state) {
1413*4882a593Smuzhiyun 		case NL80211_PLINK_ESTAB:
1414*4882a593Smuzhiyun 			if (sta->mesh->plink_state != NL80211_PLINK_ESTAB)
1415*4882a593Smuzhiyun 				changed = mesh_plink_inc_estab_count(sdata);
1416*4882a593Smuzhiyun 			sta->mesh->plink_state = params->plink_state;
1417*4882a593Smuzhiyun 			sta->mesh->aid = params->peer_aid;
1418*4882a593Smuzhiyun 
1419*4882a593Smuzhiyun 			ieee80211_mps_sta_status_update(sta);
1420*4882a593Smuzhiyun 			changed |= ieee80211_mps_set_sta_local_pm(sta,
1421*4882a593Smuzhiyun 				      sdata->u.mesh.mshcfg.power_mode);
1422*4882a593Smuzhiyun 
1423*4882a593Smuzhiyun 			ewma_mesh_tx_rate_avg_init(&sta->mesh->tx_rate_avg);
1424*4882a593Smuzhiyun 			/* init at low value */
1425*4882a593Smuzhiyun 			ewma_mesh_tx_rate_avg_add(&sta->mesh->tx_rate_avg, 10);
1426*4882a593Smuzhiyun 
1427*4882a593Smuzhiyun 			break;
1428*4882a593Smuzhiyun 		case NL80211_PLINK_LISTEN:
1429*4882a593Smuzhiyun 		case NL80211_PLINK_BLOCKED:
1430*4882a593Smuzhiyun 		case NL80211_PLINK_OPN_SNT:
1431*4882a593Smuzhiyun 		case NL80211_PLINK_OPN_RCVD:
1432*4882a593Smuzhiyun 		case NL80211_PLINK_CNF_RCVD:
1433*4882a593Smuzhiyun 		case NL80211_PLINK_HOLDING:
1434*4882a593Smuzhiyun 			if (sta->mesh->plink_state == NL80211_PLINK_ESTAB)
1435*4882a593Smuzhiyun 				changed = mesh_plink_dec_estab_count(sdata);
1436*4882a593Smuzhiyun 			sta->mesh->plink_state = params->plink_state;
1437*4882a593Smuzhiyun 
1438*4882a593Smuzhiyun 			ieee80211_mps_sta_status_update(sta);
1439*4882a593Smuzhiyun 			changed |= ieee80211_mps_set_sta_local_pm(sta,
1440*4882a593Smuzhiyun 					NL80211_MESH_POWER_UNKNOWN);
1441*4882a593Smuzhiyun 			break;
1442*4882a593Smuzhiyun 		default:
1443*4882a593Smuzhiyun 			/*  nothing  */
1444*4882a593Smuzhiyun 			break;
1445*4882a593Smuzhiyun 		}
1446*4882a593Smuzhiyun 	}
1447*4882a593Smuzhiyun 
1448*4882a593Smuzhiyun 	switch (params->plink_action) {
1449*4882a593Smuzhiyun 	case NL80211_PLINK_ACTION_NO_ACTION:
1450*4882a593Smuzhiyun 		/* nothing */
1451*4882a593Smuzhiyun 		break;
1452*4882a593Smuzhiyun 	case NL80211_PLINK_ACTION_OPEN:
1453*4882a593Smuzhiyun 		changed |= mesh_plink_open(sta);
1454*4882a593Smuzhiyun 		break;
1455*4882a593Smuzhiyun 	case NL80211_PLINK_ACTION_BLOCK:
1456*4882a593Smuzhiyun 		changed |= mesh_plink_block(sta);
1457*4882a593Smuzhiyun 		break;
1458*4882a593Smuzhiyun 	}
1459*4882a593Smuzhiyun 
1460*4882a593Smuzhiyun 	if (params->local_pm)
1461*4882a593Smuzhiyun 		changed |= ieee80211_mps_set_sta_local_pm(sta,
1462*4882a593Smuzhiyun 							  params->local_pm);
1463*4882a593Smuzhiyun 
1464*4882a593Smuzhiyun 	ieee80211_mbss_info_change_notify(sdata, changed);
1465*4882a593Smuzhiyun #endif
1466*4882a593Smuzhiyun }
1467*4882a593Smuzhiyun 
sta_apply_parameters(struct ieee80211_local * local,struct sta_info * sta,struct station_parameters * params)1468*4882a593Smuzhiyun static int sta_apply_parameters(struct ieee80211_local *local,
1469*4882a593Smuzhiyun 				struct sta_info *sta,
1470*4882a593Smuzhiyun 				struct station_parameters *params)
1471*4882a593Smuzhiyun {
1472*4882a593Smuzhiyun 	int ret = 0;
1473*4882a593Smuzhiyun 	struct ieee80211_supported_band *sband;
1474*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = sta->sdata;
1475*4882a593Smuzhiyun 	u32 mask, set;
1476*4882a593Smuzhiyun 
1477*4882a593Smuzhiyun 	sband = ieee80211_get_sband(sdata);
1478*4882a593Smuzhiyun 	if (!sband)
1479*4882a593Smuzhiyun 		return -EINVAL;
1480*4882a593Smuzhiyun 
1481*4882a593Smuzhiyun 	mask = params->sta_flags_mask;
1482*4882a593Smuzhiyun 	set = params->sta_flags_set;
1483*4882a593Smuzhiyun 
1484*4882a593Smuzhiyun 	if (ieee80211_vif_is_mesh(&sdata->vif)) {
1485*4882a593Smuzhiyun 		/*
1486*4882a593Smuzhiyun 		 * In mesh mode, ASSOCIATED isn't part of the nl80211
1487*4882a593Smuzhiyun 		 * API but must follow AUTHENTICATED for driver state.
1488*4882a593Smuzhiyun 		 */
1489*4882a593Smuzhiyun 		if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED))
1490*4882a593Smuzhiyun 			mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
1491*4882a593Smuzhiyun 		if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
1492*4882a593Smuzhiyun 			set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
1493*4882a593Smuzhiyun 	} else if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
1494*4882a593Smuzhiyun 		/*
1495*4882a593Smuzhiyun 		 * TDLS -- everything follows authorized, but
1496*4882a593Smuzhiyun 		 * only becoming authorized is possible, not
1497*4882a593Smuzhiyun 		 * going back
1498*4882a593Smuzhiyun 		 */
1499*4882a593Smuzhiyun 		if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
1500*4882a593Smuzhiyun 			set |= BIT(NL80211_STA_FLAG_AUTHENTICATED) |
1501*4882a593Smuzhiyun 			       BIT(NL80211_STA_FLAG_ASSOCIATED);
1502*4882a593Smuzhiyun 			mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED) |
1503*4882a593Smuzhiyun 				BIT(NL80211_STA_FLAG_ASSOCIATED);
1504*4882a593Smuzhiyun 		}
1505*4882a593Smuzhiyun 	}
1506*4882a593Smuzhiyun 
1507*4882a593Smuzhiyun 	if (mask & BIT(NL80211_STA_FLAG_WME) &&
1508*4882a593Smuzhiyun 	    local->hw.queues >= IEEE80211_NUM_ACS)
1509*4882a593Smuzhiyun 		sta->sta.wme = set & BIT(NL80211_STA_FLAG_WME);
1510*4882a593Smuzhiyun 
1511*4882a593Smuzhiyun 	/* auth flags will be set later for TDLS,
1512*4882a593Smuzhiyun 	 * and for unassociated stations that move to assocaited */
1513*4882a593Smuzhiyun 	if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
1514*4882a593Smuzhiyun 	    !((mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) &&
1515*4882a593Smuzhiyun 	      (set & BIT(NL80211_STA_FLAG_ASSOCIATED)))) {
1516*4882a593Smuzhiyun 		ret = sta_apply_auth_flags(local, sta, mask, set);
1517*4882a593Smuzhiyun 		if (ret)
1518*4882a593Smuzhiyun 			return ret;
1519*4882a593Smuzhiyun 	}
1520*4882a593Smuzhiyun 
1521*4882a593Smuzhiyun 	if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
1522*4882a593Smuzhiyun 		if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE))
1523*4882a593Smuzhiyun 			set_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE);
1524*4882a593Smuzhiyun 		else
1525*4882a593Smuzhiyun 			clear_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE);
1526*4882a593Smuzhiyun 	}
1527*4882a593Smuzhiyun 
1528*4882a593Smuzhiyun 	if (mask & BIT(NL80211_STA_FLAG_MFP)) {
1529*4882a593Smuzhiyun 		sta->sta.mfp = !!(set & BIT(NL80211_STA_FLAG_MFP));
1530*4882a593Smuzhiyun 		if (set & BIT(NL80211_STA_FLAG_MFP))
1531*4882a593Smuzhiyun 			set_sta_flag(sta, WLAN_STA_MFP);
1532*4882a593Smuzhiyun 		else
1533*4882a593Smuzhiyun 			clear_sta_flag(sta, WLAN_STA_MFP);
1534*4882a593Smuzhiyun 	}
1535*4882a593Smuzhiyun 
1536*4882a593Smuzhiyun 	if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
1537*4882a593Smuzhiyun 		if (set & BIT(NL80211_STA_FLAG_TDLS_PEER))
1538*4882a593Smuzhiyun 			set_sta_flag(sta, WLAN_STA_TDLS_PEER);
1539*4882a593Smuzhiyun 		else
1540*4882a593Smuzhiyun 			clear_sta_flag(sta, WLAN_STA_TDLS_PEER);
1541*4882a593Smuzhiyun 	}
1542*4882a593Smuzhiyun 
1543*4882a593Smuzhiyun 	/* mark TDLS channel switch support, if the AP allows it */
1544*4882a593Smuzhiyun 	if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
1545*4882a593Smuzhiyun 	    !sdata->u.mgd.tdls_chan_switch_prohibited &&
1546*4882a593Smuzhiyun 	    params->ext_capab_len >= 4 &&
1547*4882a593Smuzhiyun 	    params->ext_capab[3] & WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH)
1548*4882a593Smuzhiyun 		set_sta_flag(sta, WLAN_STA_TDLS_CHAN_SWITCH);
1549*4882a593Smuzhiyun 
1550*4882a593Smuzhiyun 	if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
1551*4882a593Smuzhiyun 	    !sdata->u.mgd.tdls_wider_bw_prohibited &&
1552*4882a593Smuzhiyun 	    ieee80211_hw_check(&local->hw, TDLS_WIDER_BW) &&
1553*4882a593Smuzhiyun 	    params->ext_capab_len >= 8 &&
1554*4882a593Smuzhiyun 	    params->ext_capab[7] & WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED)
1555*4882a593Smuzhiyun 		set_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW);
1556*4882a593Smuzhiyun 
1557*4882a593Smuzhiyun 	if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) {
1558*4882a593Smuzhiyun 		sta->sta.uapsd_queues = params->uapsd_queues;
1559*4882a593Smuzhiyun 		sta->sta.max_sp = params->max_sp;
1560*4882a593Smuzhiyun 	}
1561*4882a593Smuzhiyun 
1562*4882a593Smuzhiyun 	/* The sender might not have sent the last bit, consider it to be 0 */
1563*4882a593Smuzhiyun 	if (params->ext_capab_len >= 8) {
1564*4882a593Smuzhiyun 		u8 val = (params->ext_capab[7] &
1565*4882a593Smuzhiyun 			  WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB) >> 7;
1566*4882a593Smuzhiyun 
1567*4882a593Smuzhiyun 		/* we did get all the bits, take the MSB as well */
1568*4882a593Smuzhiyun 		if (params->ext_capab_len >= 9) {
1569*4882a593Smuzhiyun 			u8 val_msb = params->ext_capab[8] &
1570*4882a593Smuzhiyun 				WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB;
1571*4882a593Smuzhiyun 			val_msb <<= 1;
1572*4882a593Smuzhiyun 			val |= val_msb;
1573*4882a593Smuzhiyun 		}
1574*4882a593Smuzhiyun 
1575*4882a593Smuzhiyun 		switch (val) {
1576*4882a593Smuzhiyun 		case 1:
1577*4882a593Smuzhiyun 			sta->sta.max_amsdu_subframes = 32;
1578*4882a593Smuzhiyun 			break;
1579*4882a593Smuzhiyun 		case 2:
1580*4882a593Smuzhiyun 			sta->sta.max_amsdu_subframes = 16;
1581*4882a593Smuzhiyun 			break;
1582*4882a593Smuzhiyun 		case 3:
1583*4882a593Smuzhiyun 			sta->sta.max_amsdu_subframes = 8;
1584*4882a593Smuzhiyun 			break;
1585*4882a593Smuzhiyun 		default:
1586*4882a593Smuzhiyun 			sta->sta.max_amsdu_subframes = 0;
1587*4882a593Smuzhiyun 		}
1588*4882a593Smuzhiyun 	}
1589*4882a593Smuzhiyun 
1590*4882a593Smuzhiyun 	/*
1591*4882a593Smuzhiyun 	 * cfg80211 validates this (1-2007) and allows setting the AID
1592*4882a593Smuzhiyun 	 * only when creating a new station entry
1593*4882a593Smuzhiyun 	 */
1594*4882a593Smuzhiyun 	if (params->aid)
1595*4882a593Smuzhiyun 		sta->sta.aid = params->aid;
1596*4882a593Smuzhiyun 
1597*4882a593Smuzhiyun 	/*
1598*4882a593Smuzhiyun 	 * Some of the following updates would be racy if called on an
1599*4882a593Smuzhiyun 	 * existing station, via ieee80211_change_station(). However,
1600*4882a593Smuzhiyun 	 * all such changes are rejected by cfg80211 except for updates
1601*4882a593Smuzhiyun 	 * changing the supported rates on an existing but not yet used
1602*4882a593Smuzhiyun 	 * TDLS peer.
1603*4882a593Smuzhiyun 	 */
1604*4882a593Smuzhiyun 
1605*4882a593Smuzhiyun 	if (params->listen_interval >= 0)
1606*4882a593Smuzhiyun 		sta->listen_interval = params->listen_interval;
1607*4882a593Smuzhiyun 
1608*4882a593Smuzhiyun 	if (params->sta_modify_mask & STATION_PARAM_APPLY_STA_TXPOWER) {
1609*4882a593Smuzhiyun 		sta->sta.txpwr.type = params->txpwr.type;
1610*4882a593Smuzhiyun 		if (params->txpwr.type == NL80211_TX_POWER_LIMITED)
1611*4882a593Smuzhiyun 			sta->sta.txpwr.power = params->txpwr.power;
1612*4882a593Smuzhiyun 		ret = drv_sta_set_txpwr(local, sdata, sta);
1613*4882a593Smuzhiyun 		if (ret)
1614*4882a593Smuzhiyun 			return ret;
1615*4882a593Smuzhiyun 	}
1616*4882a593Smuzhiyun 
1617*4882a593Smuzhiyun 	if (params->supported_rates && params->supported_rates_len) {
1618*4882a593Smuzhiyun 		ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef,
1619*4882a593Smuzhiyun 					 sband, params->supported_rates,
1620*4882a593Smuzhiyun 					 params->supported_rates_len,
1621*4882a593Smuzhiyun 					 &sta->sta.supp_rates[sband->band]);
1622*4882a593Smuzhiyun 	}
1623*4882a593Smuzhiyun 
1624*4882a593Smuzhiyun 	if (params->ht_capa)
1625*4882a593Smuzhiyun 		ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
1626*4882a593Smuzhiyun 						  params->ht_capa, sta);
1627*4882a593Smuzhiyun 
1628*4882a593Smuzhiyun 	/* VHT can override some HT caps such as the A-MSDU max length */
1629*4882a593Smuzhiyun 	if (params->vht_capa)
1630*4882a593Smuzhiyun 		ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
1631*4882a593Smuzhiyun 						    params->vht_capa, sta);
1632*4882a593Smuzhiyun 
1633*4882a593Smuzhiyun 	if (params->he_capa)
1634*4882a593Smuzhiyun 		ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
1635*4882a593Smuzhiyun 						  (void *)params->he_capa,
1636*4882a593Smuzhiyun 						  params->he_capa_len,
1637*4882a593Smuzhiyun 						  (void *)params->he_6ghz_capa,
1638*4882a593Smuzhiyun 						  sta);
1639*4882a593Smuzhiyun 
1640*4882a593Smuzhiyun 	if (params->opmode_notif_used) {
1641*4882a593Smuzhiyun 		/* returned value is only needed for rc update, but the
1642*4882a593Smuzhiyun 		 * rc isn't initialized here yet, so ignore it
1643*4882a593Smuzhiyun 		 */
1644*4882a593Smuzhiyun 		__ieee80211_vht_handle_opmode(sdata, sta, params->opmode_notif,
1645*4882a593Smuzhiyun 					      sband->band);
1646*4882a593Smuzhiyun 	}
1647*4882a593Smuzhiyun 
1648*4882a593Smuzhiyun 	if (params->support_p2p_ps >= 0)
1649*4882a593Smuzhiyun 		sta->sta.support_p2p_ps = params->support_p2p_ps;
1650*4882a593Smuzhiyun 
1651*4882a593Smuzhiyun 	if (ieee80211_vif_is_mesh(&sdata->vif))
1652*4882a593Smuzhiyun 		sta_apply_mesh_params(local, sta, params);
1653*4882a593Smuzhiyun 
1654*4882a593Smuzhiyun 	if (params->airtime_weight)
1655*4882a593Smuzhiyun 		sta->airtime_weight = params->airtime_weight;
1656*4882a593Smuzhiyun 
1657*4882a593Smuzhiyun 	/* set the STA state after all sta info from usermode has been set */
1658*4882a593Smuzhiyun 	if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) ||
1659*4882a593Smuzhiyun 	    set & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
1660*4882a593Smuzhiyun 		ret = sta_apply_auth_flags(local, sta, mask, set);
1661*4882a593Smuzhiyun 		if (ret)
1662*4882a593Smuzhiyun 			return ret;
1663*4882a593Smuzhiyun 	}
1664*4882a593Smuzhiyun 
1665*4882a593Smuzhiyun 	return 0;
1666*4882a593Smuzhiyun }
1667*4882a593Smuzhiyun 
ieee80211_add_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_parameters * params)1668*4882a593Smuzhiyun static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
1669*4882a593Smuzhiyun 				 const u8 *mac,
1670*4882a593Smuzhiyun 				 struct station_parameters *params)
1671*4882a593Smuzhiyun {
1672*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
1673*4882a593Smuzhiyun 	struct sta_info *sta;
1674*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
1675*4882a593Smuzhiyun 	int err;
1676*4882a593Smuzhiyun 
1677*4882a593Smuzhiyun 	if (params->vlan) {
1678*4882a593Smuzhiyun 		sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
1679*4882a593Smuzhiyun 
1680*4882a593Smuzhiyun 		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
1681*4882a593Smuzhiyun 		    sdata->vif.type != NL80211_IFTYPE_AP)
1682*4882a593Smuzhiyun 			return -EINVAL;
1683*4882a593Smuzhiyun 	} else
1684*4882a593Smuzhiyun 		sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1685*4882a593Smuzhiyun 
1686*4882a593Smuzhiyun 	if (ether_addr_equal(mac, sdata->vif.addr))
1687*4882a593Smuzhiyun 		return -EINVAL;
1688*4882a593Smuzhiyun 
1689*4882a593Smuzhiyun 	if (!is_valid_ether_addr(mac))
1690*4882a593Smuzhiyun 		return -EINVAL;
1691*4882a593Smuzhiyun 
1692*4882a593Smuzhiyun 	if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER) &&
1693*4882a593Smuzhiyun 	    sdata->vif.type == NL80211_IFTYPE_STATION &&
1694*4882a593Smuzhiyun 	    !sdata->u.mgd.associated)
1695*4882a593Smuzhiyun 		return -EINVAL;
1696*4882a593Smuzhiyun 
1697*4882a593Smuzhiyun 	sta = sta_info_alloc(sdata, mac, GFP_KERNEL);
1698*4882a593Smuzhiyun 	if (!sta)
1699*4882a593Smuzhiyun 		return -ENOMEM;
1700*4882a593Smuzhiyun 
1701*4882a593Smuzhiyun 	if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
1702*4882a593Smuzhiyun 		sta->sta.tdls = true;
1703*4882a593Smuzhiyun 
1704*4882a593Smuzhiyun 	err = sta_apply_parameters(local, sta, params);
1705*4882a593Smuzhiyun 	if (err) {
1706*4882a593Smuzhiyun 		sta_info_free(local, sta);
1707*4882a593Smuzhiyun 		return err;
1708*4882a593Smuzhiyun 	}
1709*4882a593Smuzhiyun 
1710*4882a593Smuzhiyun 	/*
1711*4882a593Smuzhiyun 	 * for TDLS and for unassociated station, rate control should be
1712*4882a593Smuzhiyun 	 * initialized only when rates are known and station is marked
1713*4882a593Smuzhiyun 	 * authorized/associated
1714*4882a593Smuzhiyun 	 */
1715*4882a593Smuzhiyun 	if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
1716*4882a593Smuzhiyun 	    test_sta_flag(sta, WLAN_STA_ASSOC))
1717*4882a593Smuzhiyun 		rate_control_rate_init(sta);
1718*4882a593Smuzhiyun 
1719*4882a593Smuzhiyun 	err = sta_info_insert_rcu(sta);
1720*4882a593Smuzhiyun 	if (err) {
1721*4882a593Smuzhiyun 		rcu_read_unlock();
1722*4882a593Smuzhiyun 		return err;
1723*4882a593Smuzhiyun 	}
1724*4882a593Smuzhiyun 
1725*4882a593Smuzhiyun 	rcu_read_unlock();
1726*4882a593Smuzhiyun 
1727*4882a593Smuzhiyun 	return 0;
1728*4882a593Smuzhiyun }
1729*4882a593Smuzhiyun 
ieee80211_del_station(struct wiphy * wiphy,struct net_device * dev,struct station_del_parameters * params)1730*4882a593Smuzhiyun static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
1731*4882a593Smuzhiyun 				 struct station_del_parameters *params)
1732*4882a593Smuzhiyun {
1733*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
1734*4882a593Smuzhiyun 
1735*4882a593Smuzhiyun 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1736*4882a593Smuzhiyun 
1737*4882a593Smuzhiyun 	if (params->mac)
1738*4882a593Smuzhiyun 		return sta_info_destroy_addr_bss(sdata, params->mac);
1739*4882a593Smuzhiyun 
1740*4882a593Smuzhiyun 	sta_info_flush(sdata);
1741*4882a593Smuzhiyun 	return 0;
1742*4882a593Smuzhiyun }
1743*4882a593Smuzhiyun 
ieee80211_change_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_parameters * params)1744*4882a593Smuzhiyun static int ieee80211_change_station(struct wiphy *wiphy,
1745*4882a593Smuzhiyun 				    struct net_device *dev, const u8 *mac,
1746*4882a593Smuzhiyun 				    struct station_parameters *params)
1747*4882a593Smuzhiyun {
1748*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1749*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
1750*4882a593Smuzhiyun 	struct sta_info *sta;
1751*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *vlansdata;
1752*4882a593Smuzhiyun 	enum cfg80211_station_type statype;
1753*4882a593Smuzhiyun 	int err;
1754*4882a593Smuzhiyun 
1755*4882a593Smuzhiyun 	mutex_lock(&local->sta_mtx);
1756*4882a593Smuzhiyun 
1757*4882a593Smuzhiyun 	sta = sta_info_get_bss(sdata, mac);
1758*4882a593Smuzhiyun 	if (!sta) {
1759*4882a593Smuzhiyun 		err = -ENOENT;
1760*4882a593Smuzhiyun 		goto out_err;
1761*4882a593Smuzhiyun 	}
1762*4882a593Smuzhiyun 
1763*4882a593Smuzhiyun 	switch (sdata->vif.type) {
1764*4882a593Smuzhiyun 	case NL80211_IFTYPE_MESH_POINT:
1765*4882a593Smuzhiyun 		if (sdata->u.mesh.user_mpm)
1766*4882a593Smuzhiyun 			statype = CFG80211_STA_MESH_PEER_USER;
1767*4882a593Smuzhiyun 		else
1768*4882a593Smuzhiyun 			statype = CFG80211_STA_MESH_PEER_KERNEL;
1769*4882a593Smuzhiyun 		break;
1770*4882a593Smuzhiyun 	case NL80211_IFTYPE_ADHOC:
1771*4882a593Smuzhiyun 		statype = CFG80211_STA_IBSS;
1772*4882a593Smuzhiyun 		break;
1773*4882a593Smuzhiyun 	case NL80211_IFTYPE_STATION:
1774*4882a593Smuzhiyun 		if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
1775*4882a593Smuzhiyun 			statype = CFG80211_STA_AP_STA;
1776*4882a593Smuzhiyun 			break;
1777*4882a593Smuzhiyun 		}
1778*4882a593Smuzhiyun 		if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
1779*4882a593Smuzhiyun 			statype = CFG80211_STA_TDLS_PEER_ACTIVE;
1780*4882a593Smuzhiyun 		else
1781*4882a593Smuzhiyun 			statype = CFG80211_STA_TDLS_PEER_SETUP;
1782*4882a593Smuzhiyun 		break;
1783*4882a593Smuzhiyun 	case NL80211_IFTYPE_AP:
1784*4882a593Smuzhiyun 	case NL80211_IFTYPE_AP_VLAN:
1785*4882a593Smuzhiyun 		if (test_sta_flag(sta, WLAN_STA_ASSOC))
1786*4882a593Smuzhiyun 			statype = CFG80211_STA_AP_CLIENT;
1787*4882a593Smuzhiyun 		else
1788*4882a593Smuzhiyun 			statype = CFG80211_STA_AP_CLIENT_UNASSOC;
1789*4882a593Smuzhiyun 		break;
1790*4882a593Smuzhiyun 	default:
1791*4882a593Smuzhiyun 		err = -EOPNOTSUPP;
1792*4882a593Smuzhiyun 		goto out_err;
1793*4882a593Smuzhiyun 	}
1794*4882a593Smuzhiyun 
1795*4882a593Smuzhiyun 	err = cfg80211_check_station_change(wiphy, params, statype);
1796*4882a593Smuzhiyun 	if (err)
1797*4882a593Smuzhiyun 		goto out_err;
1798*4882a593Smuzhiyun 
1799*4882a593Smuzhiyun 	if (params->vlan && params->vlan != sta->sdata->dev) {
1800*4882a593Smuzhiyun 		vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
1801*4882a593Smuzhiyun 
1802*4882a593Smuzhiyun 		if (params->vlan->ieee80211_ptr->use_4addr) {
1803*4882a593Smuzhiyun 			if (vlansdata->u.vlan.sta) {
1804*4882a593Smuzhiyun 				err = -EBUSY;
1805*4882a593Smuzhiyun 				goto out_err;
1806*4882a593Smuzhiyun 			}
1807*4882a593Smuzhiyun 
1808*4882a593Smuzhiyun 			rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
1809*4882a593Smuzhiyun 			__ieee80211_check_fast_rx_iface(vlansdata);
1810*4882a593Smuzhiyun 			drv_sta_set_4addr(local, sta->sdata, &sta->sta, true);
1811*4882a593Smuzhiyun 		}
1812*4882a593Smuzhiyun 
1813*4882a593Smuzhiyun 		if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
1814*4882a593Smuzhiyun 		    sta->sdata->u.vlan.sta) {
1815*4882a593Smuzhiyun 			ieee80211_clear_fast_rx(sta);
1816*4882a593Smuzhiyun 			RCU_INIT_POINTER(sta->sdata->u.vlan.sta, NULL);
1817*4882a593Smuzhiyun 		}
1818*4882a593Smuzhiyun 
1819*4882a593Smuzhiyun 		if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
1820*4882a593Smuzhiyun 			ieee80211_vif_dec_num_mcast(sta->sdata);
1821*4882a593Smuzhiyun 
1822*4882a593Smuzhiyun 		sta->sdata = vlansdata;
1823*4882a593Smuzhiyun 		ieee80211_check_fast_xmit(sta);
1824*4882a593Smuzhiyun 
1825*4882a593Smuzhiyun 		if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
1826*4882a593Smuzhiyun 			ieee80211_vif_inc_num_mcast(sta->sdata);
1827*4882a593Smuzhiyun 			cfg80211_send_layer2_update(sta->sdata->dev,
1828*4882a593Smuzhiyun 						    sta->sta.addr);
1829*4882a593Smuzhiyun 		}
1830*4882a593Smuzhiyun 	}
1831*4882a593Smuzhiyun 
1832*4882a593Smuzhiyun 	err = sta_apply_parameters(local, sta, params);
1833*4882a593Smuzhiyun 	if (err)
1834*4882a593Smuzhiyun 		goto out_err;
1835*4882a593Smuzhiyun 
1836*4882a593Smuzhiyun 	mutex_unlock(&local->sta_mtx);
1837*4882a593Smuzhiyun 
1838*4882a593Smuzhiyun 	if (sdata->vif.type == NL80211_IFTYPE_STATION &&
1839*4882a593Smuzhiyun 	    params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
1840*4882a593Smuzhiyun 		ieee80211_recalc_ps(local);
1841*4882a593Smuzhiyun 		ieee80211_recalc_ps_vif(sdata);
1842*4882a593Smuzhiyun 	}
1843*4882a593Smuzhiyun 
1844*4882a593Smuzhiyun 	return 0;
1845*4882a593Smuzhiyun out_err:
1846*4882a593Smuzhiyun 	mutex_unlock(&local->sta_mtx);
1847*4882a593Smuzhiyun 	return err;
1848*4882a593Smuzhiyun }
1849*4882a593Smuzhiyun 
1850*4882a593Smuzhiyun #ifdef CONFIG_MAC80211_MESH
ieee80211_add_mpath(struct wiphy * wiphy,struct net_device * dev,const u8 * dst,const u8 * next_hop)1851*4882a593Smuzhiyun static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
1852*4882a593Smuzhiyun 			       const u8 *dst, const u8 *next_hop)
1853*4882a593Smuzhiyun {
1854*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
1855*4882a593Smuzhiyun 	struct mesh_path *mpath;
1856*4882a593Smuzhiyun 	struct sta_info *sta;
1857*4882a593Smuzhiyun 
1858*4882a593Smuzhiyun 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1859*4882a593Smuzhiyun 
1860*4882a593Smuzhiyun 	rcu_read_lock();
1861*4882a593Smuzhiyun 	sta = sta_info_get(sdata, next_hop);
1862*4882a593Smuzhiyun 	if (!sta) {
1863*4882a593Smuzhiyun 		rcu_read_unlock();
1864*4882a593Smuzhiyun 		return -ENOENT;
1865*4882a593Smuzhiyun 	}
1866*4882a593Smuzhiyun 
1867*4882a593Smuzhiyun 	mpath = mesh_path_add(sdata, dst);
1868*4882a593Smuzhiyun 	if (IS_ERR(mpath)) {
1869*4882a593Smuzhiyun 		rcu_read_unlock();
1870*4882a593Smuzhiyun 		return PTR_ERR(mpath);
1871*4882a593Smuzhiyun 	}
1872*4882a593Smuzhiyun 
1873*4882a593Smuzhiyun 	mesh_path_fix_nexthop(mpath, sta);
1874*4882a593Smuzhiyun 
1875*4882a593Smuzhiyun 	rcu_read_unlock();
1876*4882a593Smuzhiyun 	return 0;
1877*4882a593Smuzhiyun }
1878*4882a593Smuzhiyun 
ieee80211_del_mpath(struct wiphy * wiphy,struct net_device * dev,const u8 * dst)1879*4882a593Smuzhiyun static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
1880*4882a593Smuzhiyun 			       const u8 *dst)
1881*4882a593Smuzhiyun {
1882*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1883*4882a593Smuzhiyun 
1884*4882a593Smuzhiyun 	if (dst)
1885*4882a593Smuzhiyun 		return mesh_path_del(sdata, dst);
1886*4882a593Smuzhiyun 
1887*4882a593Smuzhiyun 	mesh_path_flush_by_iface(sdata);
1888*4882a593Smuzhiyun 	return 0;
1889*4882a593Smuzhiyun }
1890*4882a593Smuzhiyun 
ieee80211_change_mpath(struct wiphy * wiphy,struct net_device * dev,const u8 * dst,const u8 * next_hop)1891*4882a593Smuzhiyun static int ieee80211_change_mpath(struct wiphy *wiphy, struct net_device *dev,
1892*4882a593Smuzhiyun 				  const u8 *dst, const u8 *next_hop)
1893*4882a593Smuzhiyun {
1894*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
1895*4882a593Smuzhiyun 	struct mesh_path *mpath;
1896*4882a593Smuzhiyun 	struct sta_info *sta;
1897*4882a593Smuzhiyun 
1898*4882a593Smuzhiyun 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1899*4882a593Smuzhiyun 
1900*4882a593Smuzhiyun 	rcu_read_lock();
1901*4882a593Smuzhiyun 
1902*4882a593Smuzhiyun 	sta = sta_info_get(sdata, next_hop);
1903*4882a593Smuzhiyun 	if (!sta) {
1904*4882a593Smuzhiyun 		rcu_read_unlock();
1905*4882a593Smuzhiyun 		return -ENOENT;
1906*4882a593Smuzhiyun 	}
1907*4882a593Smuzhiyun 
1908*4882a593Smuzhiyun 	mpath = mesh_path_lookup(sdata, dst);
1909*4882a593Smuzhiyun 	if (!mpath) {
1910*4882a593Smuzhiyun 		rcu_read_unlock();
1911*4882a593Smuzhiyun 		return -ENOENT;
1912*4882a593Smuzhiyun 	}
1913*4882a593Smuzhiyun 
1914*4882a593Smuzhiyun 	mesh_path_fix_nexthop(mpath, sta);
1915*4882a593Smuzhiyun 
1916*4882a593Smuzhiyun 	rcu_read_unlock();
1917*4882a593Smuzhiyun 	return 0;
1918*4882a593Smuzhiyun }
1919*4882a593Smuzhiyun 
mpath_set_pinfo(struct mesh_path * mpath,u8 * next_hop,struct mpath_info * pinfo)1920*4882a593Smuzhiyun static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop,
1921*4882a593Smuzhiyun 			    struct mpath_info *pinfo)
1922*4882a593Smuzhiyun {
1923*4882a593Smuzhiyun 	struct sta_info *next_hop_sta = rcu_dereference(mpath->next_hop);
1924*4882a593Smuzhiyun 
1925*4882a593Smuzhiyun 	if (next_hop_sta)
1926*4882a593Smuzhiyun 		memcpy(next_hop, next_hop_sta->sta.addr, ETH_ALEN);
1927*4882a593Smuzhiyun 	else
1928*4882a593Smuzhiyun 		eth_zero_addr(next_hop);
1929*4882a593Smuzhiyun 
1930*4882a593Smuzhiyun 	memset(pinfo, 0, sizeof(*pinfo));
1931*4882a593Smuzhiyun 
1932*4882a593Smuzhiyun 	pinfo->generation = mpath->sdata->u.mesh.mesh_paths_generation;
1933*4882a593Smuzhiyun 
1934*4882a593Smuzhiyun 	pinfo->filled = MPATH_INFO_FRAME_QLEN |
1935*4882a593Smuzhiyun 			MPATH_INFO_SN |
1936*4882a593Smuzhiyun 			MPATH_INFO_METRIC |
1937*4882a593Smuzhiyun 			MPATH_INFO_EXPTIME |
1938*4882a593Smuzhiyun 			MPATH_INFO_DISCOVERY_TIMEOUT |
1939*4882a593Smuzhiyun 			MPATH_INFO_DISCOVERY_RETRIES |
1940*4882a593Smuzhiyun 			MPATH_INFO_FLAGS |
1941*4882a593Smuzhiyun 			MPATH_INFO_HOP_COUNT |
1942*4882a593Smuzhiyun 			MPATH_INFO_PATH_CHANGE;
1943*4882a593Smuzhiyun 
1944*4882a593Smuzhiyun 	pinfo->frame_qlen = mpath->frame_queue.qlen;
1945*4882a593Smuzhiyun 	pinfo->sn = mpath->sn;
1946*4882a593Smuzhiyun 	pinfo->metric = mpath->metric;
1947*4882a593Smuzhiyun 	if (time_before(jiffies, mpath->exp_time))
1948*4882a593Smuzhiyun 		pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies);
1949*4882a593Smuzhiyun 	pinfo->discovery_timeout =
1950*4882a593Smuzhiyun 			jiffies_to_msecs(mpath->discovery_timeout);
1951*4882a593Smuzhiyun 	pinfo->discovery_retries = mpath->discovery_retries;
1952*4882a593Smuzhiyun 	if (mpath->flags & MESH_PATH_ACTIVE)
1953*4882a593Smuzhiyun 		pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE;
1954*4882a593Smuzhiyun 	if (mpath->flags & MESH_PATH_RESOLVING)
1955*4882a593Smuzhiyun 		pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING;
1956*4882a593Smuzhiyun 	if (mpath->flags & MESH_PATH_SN_VALID)
1957*4882a593Smuzhiyun 		pinfo->flags |= NL80211_MPATH_FLAG_SN_VALID;
1958*4882a593Smuzhiyun 	if (mpath->flags & MESH_PATH_FIXED)
1959*4882a593Smuzhiyun 		pinfo->flags |= NL80211_MPATH_FLAG_FIXED;
1960*4882a593Smuzhiyun 	if (mpath->flags & MESH_PATH_RESOLVED)
1961*4882a593Smuzhiyun 		pinfo->flags |= NL80211_MPATH_FLAG_RESOLVED;
1962*4882a593Smuzhiyun 	pinfo->hop_count = mpath->hop_count;
1963*4882a593Smuzhiyun 	pinfo->path_change_count = mpath->path_change_count;
1964*4882a593Smuzhiyun }
1965*4882a593Smuzhiyun 
ieee80211_get_mpath(struct wiphy * wiphy,struct net_device * dev,u8 * dst,u8 * next_hop,struct mpath_info * pinfo)1966*4882a593Smuzhiyun static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
1967*4882a593Smuzhiyun 			       u8 *dst, u8 *next_hop, struct mpath_info *pinfo)
1968*4882a593Smuzhiyun 
1969*4882a593Smuzhiyun {
1970*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
1971*4882a593Smuzhiyun 	struct mesh_path *mpath;
1972*4882a593Smuzhiyun 
1973*4882a593Smuzhiyun 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1974*4882a593Smuzhiyun 
1975*4882a593Smuzhiyun 	rcu_read_lock();
1976*4882a593Smuzhiyun 	mpath = mesh_path_lookup(sdata, dst);
1977*4882a593Smuzhiyun 	if (!mpath) {
1978*4882a593Smuzhiyun 		rcu_read_unlock();
1979*4882a593Smuzhiyun 		return -ENOENT;
1980*4882a593Smuzhiyun 	}
1981*4882a593Smuzhiyun 	memcpy(dst, mpath->dst, ETH_ALEN);
1982*4882a593Smuzhiyun 	mpath_set_pinfo(mpath, next_hop, pinfo);
1983*4882a593Smuzhiyun 	rcu_read_unlock();
1984*4882a593Smuzhiyun 	return 0;
1985*4882a593Smuzhiyun }
1986*4882a593Smuzhiyun 
ieee80211_dump_mpath(struct wiphy * wiphy,struct net_device * dev,int idx,u8 * dst,u8 * next_hop,struct mpath_info * pinfo)1987*4882a593Smuzhiyun static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
1988*4882a593Smuzhiyun 				int idx, u8 *dst, u8 *next_hop,
1989*4882a593Smuzhiyun 				struct mpath_info *pinfo)
1990*4882a593Smuzhiyun {
1991*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
1992*4882a593Smuzhiyun 	struct mesh_path *mpath;
1993*4882a593Smuzhiyun 
1994*4882a593Smuzhiyun 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1995*4882a593Smuzhiyun 
1996*4882a593Smuzhiyun 	rcu_read_lock();
1997*4882a593Smuzhiyun 	mpath = mesh_path_lookup_by_idx(sdata, idx);
1998*4882a593Smuzhiyun 	if (!mpath) {
1999*4882a593Smuzhiyun 		rcu_read_unlock();
2000*4882a593Smuzhiyun 		return -ENOENT;
2001*4882a593Smuzhiyun 	}
2002*4882a593Smuzhiyun 	memcpy(dst, mpath->dst, ETH_ALEN);
2003*4882a593Smuzhiyun 	mpath_set_pinfo(mpath, next_hop, pinfo);
2004*4882a593Smuzhiyun 	rcu_read_unlock();
2005*4882a593Smuzhiyun 	return 0;
2006*4882a593Smuzhiyun }
2007*4882a593Smuzhiyun 
mpp_set_pinfo(struct mesh_path * mpath,u8 * mpp,struct mpath_info * pinfo)2008*4882a593Smuzhiyun static void mpp_set_pinfo(struct mesh_path *mpath, u8 *mpp,
2009*4882a593Smuzhiyun 			  struct mpath_info *pinfo)
2010*4882a593Smuzhiyun {
2011*4882a593Smuzhiyun 	memset(pinfo, 0, sizeof(*pinfo));
2012*4882a593Smuzhiyun 	memcpy(mpp, mpath->mpp, ETH_ALEN);
2013*4882a593Smuzhiyun 
2014*4882a593Smuzhiyun 	pinfo->generation = mpath->sdata->u.mesh.mpp_paths_generation;
2015*4882a593Smuzhiyun }
2016*4882a593Smuzhiyun 
ieee80211_get_mpp(struct wiphy * wiphy,struct net_device * dev,u8 * dst,u8 * mpp,struct mpath_info * pinfo)2017*4882a593Smuzhiyun static int ieee80211_get_mpp(struct wiphy *wiphy, struct net_device *dev,
2018*4882a593Smuzhiyun 			     u8 *dst, u8 *mpp, struct mpath_info *pinfo)
2019*4882a593Smuzhiyun 
2020*4882a593Smuzhiyun {
2021*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
2022*4882a593Smuzhiyun 	struct mesh_path *mpath;
2023*4882a593Smuzhiyun 
2024*4882a593Smuzhiyun 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2025*4882a593Smuzhiyun 
2026*4882a593Smuzhiyun 	rcu_read_lock();
2027*4882a593Smuzhiyun 	mpath = mpp_path_lookup(sdata, dst);
2028*4882a593Smuzhiyun 	if (!mpath) {
2029*4882a593Smuzhiyun 		rcu_read_unlock();
2030*4882a593Smuzhiyun 		return -ENOENT;
2031*4882a593Smuzhiyun 	}
2032*4882a593Smuzhiyun 	memcpy(dst, mpath->dst, ETH_ALEN);
2033*4882a593Smuzhiyun 	mpp_set_pinfo(mpath, mpp, pinfo);
2034*4882a593Smuzhiyun 	rcu_read_unlock();
2035*4882a593Smuzhiyun 	return 0;
2036*4882a593Smuzhiyun }
2037*4882a593Smuzhiyun 
ieee80211_dump_mpp(struct wiphy * wiphy,struct net_device * dev,int idx,u8 * dst,u8 * mpp,struct mpath_info * pinfo)2038*4882a593Smuzhiyun static int ieee80211_dump_mpp(struct wiphy *wiphy, struct net_device *dev,
2039*4882a593Smuzhiyun 			      int idx, u8 *dst, u8 *mpp,
2040*4882a593Smuzhiyun 			      struct mpath_info *pinfo)
2041*4882a593Smuzhiyun {
2042*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
2043*4882a593Smuzhiyun 	struct mesh_path *mpath;
2044*4882a593Smuzhiyun 
2045*4882a593Smuzhiyun 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2046*4882a593Smuzhiyun 
2047*4882a593Smuzhiyun 	rcu_read_lock();
2048*4882a593Smuzhiyun 	mpath = mpp_path_lookup_by_idx(sdata, idx);
2049*4882a593Smuzhiyun 	if (!mpath) {
2050*4882a593Smuzhiyun 		rcu_read_unlock();
2051*4882a593Smuzhiyun 		return -ENOENT;
2052*4882a593Smuzhiyun 	}
2053*4882a593Smuzhiyun 	memcpy(dst, mpath->dst, ETH_ALEN);
2054*4882a593Smuzhiyun 	mpp_set_pinfo(mpath, mpp, pinfo);
2055*4882a593Smuzhiyun 	rcu_read_unlock();
2056*4882a593Smuzhiyun 	return 0;
2057*4882a593Smuzhiyun }
2058*4882a593Smuzhiyun 
ieee80211_get_mesh_config(struct wiphy * wiphy,struct net_device * dev,struct mesh_config * conf)2059*4882a593Smuzhiyun static int ieee80211_get_mesh_config(struct wiphy *wiphy,
2060*4882a593Smuzhiyun 				struct net_device *dev,
2061*4882a593Smuzhiyun 				struct mesh_config *conf)
2062*4882a593Smuzhiyun {
2063*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
2064*4882a593Smuzhiyun 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2065*4882a593Smuzhiyun 
2066*4882a593Smuzhiyun 	memcpy(conf, &(sdata->u.mesh.mshcfg), sizeof(struct mesh_config));
2067*4882a593Smuzhiyun 	return 0;
2068*4882a593Smuzhiyun }
2069*4882a593Smuzhiyun 
_chg_mesh_attr(enum nl80211_meshconf_params parm,u32 mask)2070*4882a593Smuzhiyun static inline bool _chg_mesh_attr(enum nl80211_meshconf_params parm, u32 mask)
2071*4882a593Smuzhiyun {
2072*4882a593Smuzhiyun 	return (mask >> (parm-1)) & 0x1;
2073*4882a593Smuzhiyun }
2074*4882a593Smuzhiyun 
copy_mesh_setup(struct ieee80211_if_mesh * ifmsh,const struct mesh_setup * setup)2075*4882a593Smuzhiyun static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
2076*4882a593Smuzhiyun 		const struct mesh_setup *setup)
2077*4882a593Smuzhiyun {
2078*4882a593Smuzhiyun 	u8 *new_ie;
2079*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = container_of(ifmsh,
2080*4882a593Smuzhiyun 					struct ieee80211_sub_if_data, u.mesh);
2081*4882a593Smuzhiyun 	int i;
2082*4882a593Smuzhiyun 
2083*4882a593Smuzhiyun 	/* allocate information elements */
2084*4882a593Smuzhiyun 	new_ie = NULL;
2085*4882a593Smuzhiyun 
2086*4882a593Smuzhiyun 	if (setup->ie_len) {
2087*4882a593Smuzhiyun 		new_ie = kmemdup(setup->ie, setup->ie_len,
2088*4882a593Smuzhiyun 				GFP_KERNEL);
2089*4882a593Smuzhiyun 		if (!new_ie)
2090*4882a593Smuzhiyun 			return -ENOMEM;
2091*4882a593Smuzhiyun 	}
2092*4882a593Smuzhiyun 	ifmsh->ie_len = setup->ie_len;
2093*4882a593Smuzhiyun 	ifmsh->ie = new_ie;
2094*4882a593Smuzhiyun 
2095*4882a593Smuzhiyun 	/* now copy the rest of the setup parameters */
2096*4882a593Smuzhiyun 	ifmsh->mesh_id_len = setup->mesh_id_len;
2097*4882a593Smuzhiyun 	memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len);
2098*4882a593Smuzhiyun 	ifmsh->mesh_sp_id = setup->sync_method;
2099*4882a593Smuzhiyun 	ifmsh->mesh_pp_id = setup->path_sel_proto;
2100*4882a593Smuzhiyun 	ifmsh->mesh_pm_id = setup->path_metric;
2101*4882a593Smuzhiyun 	ifmsh->user_mpm = setup->user_mpm;
2102*4882a593Smuzhiyun 	ifmsh->mesh_auth_id = setup->auth_id;
2103*4882a593Smuzhiyun 	ifmsh->security = IEEE80211_MESH_SEC_NONE;
2104*4882a593Smuzhiyun 	ifmsh->userspace_handles_dfs = setup->userspace_handles_dfs;
2105*4882a593Smuzhiyun 	if (setup->is_authenticated)
2106*4882a593Smuzhiyun 		ifmsh->security |= IEEE80211_MESH_SEC_AUTHED;
2107*4882a593Smuzhiyun 	if (setup->is_secure)
2108*4882a593Smuzhiyun 		ifmsh->security |= IEEE80211_MESH_SEC_SECURED;
2109*4882a593Smuzhiyun 
2110*4882a593Smuzhiyun 	/* mcast rate setting in Mesh Node */
2111*4882a593Smuzhiyun 	memcpy(sdata->vif.bss_conf.mcast_rate, setup->mcast_rate,
2112*4882a593Smuzhiyun 						sizeof(setup->mcast_rate));
2113*4882a593Smuzhiyun 	sdata->vif.bss_conf.basic_rates = setup->basic_rates;
2114*4882a593Smuzhiyun 
2115*4882a593Smuzhiyun 	sdata->vif.bss_conf.beacon_int = setup->beacon_interval;
2116*4882a593Smuzhiyun 	sdata->vif.bss_conf.dtim_period = setup->dtim_period;
2117*4882a593Smuzhiyun 
2118*4882a593Smuzhiyun 	sdata->beacon_rate_set = false;
2119*4882a593Smuzhiyun 	if (wiphy_ext_feature_isset(sdata->local->hw.wiphy,
2120*4882a593Smuzhiyun 				    NL80211_EXT_FEATURE_BEACON_RATE_LEGACY)) {
2121*4882a593Smuzhiyun 		for (i = 0; i < NUM_NL80211_BANDS; i++) {
2122*4882a593Smuzhiyun 			sdata->beacon_rateidx_mask[i] =
2123*4882a593Smuzhiyun 				setup->beacon_rate.control[i].legacy;
2124*4882a593Smuzhiyun 			if (sdata->beacon_rateidx_mask[i])
2125*4882a593Smuzhiyun 				sdata->beacon_rate_set = true;
2126*4882a593Smuzhiyun 		}
2127*4882a593Smuzhiyun 	}
2128*4882a593Smuzhiyun 
2129*4882a593Smuzhiyun 	return 0;
2130*4882a593Smuzhiyun }
2131*4882a593Smuzhiyun 
ieee80211_update_mesh_config(struct wiphy * wiphy,struct net_device * dev,u32 mask,const struct mesh_config * nconf)2132*4882a593Smuzhiyun static int ieee80211_update_mesh_config(struct wiphy *wiphy,
2133*4882a593Smuzhiyun 					struct net_device *dev, u32 mask,
2134*4882a593Smuzhiyun 					const struct mesh_config *nconf)
2135*4882a593Smuzhiyun {
2136*4882a593Smuzhiyun 	struct mesh_config *conf;
2137*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
2138*4882a593Smuzhiyun 	struct ieee80211_if_mesh *ifmsh;
2139*4882a593Smuzhiyun 
2140*4882a593Smuzhiyun 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2141*4882a593Smuzhiyun 	ifmsh = &sdata->u.mesh;
2142*4882a593Smuzhiyun 
2143*4882a593Smuzhiyun 	/* Set the config options which we are interested in setting */
2144*4882a593Smuzhiyun 	conf = &(sdata->u.mesh.mshcfg);
2145*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_RETRY_TIMEOUT, mask))
2146*4882a593Smuzhiyun 		conf->dot11MeshRetryTimeout = nconf->dot11MeshRetryTimeout;
2147*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_CONFIRM_TIMEOUT, mask))
2148*4882a593Smuzhiyun 		conf->dot11MeshConfirmTimeout = nconf->dot11MeshConfirmTimeout;
2149*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_HOLDING_TIMEOUT, mask))
2150*4882a593Smuzhiyun 		conf->dot11MeshHoldingTimeout = nconf->dot11MeshHoldingTimeout;
2151*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_MAX_PEER_LINKS, mask))
2152*4882a593Smuzhiyun 		conf->dot11MeshMaxPeerLinks = nconf->dot11MeshMaxPeerLinks;
2153*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_MAX_RETRIES, mask))
2154*4882a593Smuzhiyun 		conf->dot11MeshMaxRetries = nconf->dot11MeshMaxRetries;
2155*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask))
2156*4882a593Smuzhiyun 		conf->dot11MeshTTL = nconf->dot11MeshTTL;
2157*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask))
2158*4882a593Smuzhiyun 		conf->element_ttl = nconf->element_ttl;
2159*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) {
2160*4882a593Smuzhiyun 		if (ifmsh->user_mpm)
2161*4882a593Smuzhiyun 			return -EBUSY;
2162*4882a593Smuzhiyun 		conf->auto_open_plinks = nconf->auto_open_plinks;
2163*4882a593Smuzhiyun 	}
2164*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask))
2165*4882a593Smuzhiyun 		conf->dot11MeshNbrOffsetMaxNeighbor =
2166*4882a593Smuzhiyun 			nconf->dot11MeshNbrOffsetMaxNeighbor;
2167*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask))
2168*4882a593Smuzhiyun 		conf->dot11MeshHWMPmaxPREQretries =
2169*4882a593Smuzhiyun 			nconf->dot11MeshHWMPmaxPREQretries;
2170*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_PATH_REFRESH_TIME, mask))
2171*4882a593Smuzhiyun 		conf->path_refresh_time = nconf->path_refresh_time;
2172*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, mask))
2173*4882a593Smuzhiyun 		conf->min_discovery_timeout = nconf->min_discovery_timeout;
2174*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, mask))
2175*4882a593Smuzhiyun 		conf->dot11MeshHWMPactivePathTimeout =
2176*4882a593Smuzhiyun 			nconf->dot11MeshHWMPactivePathTimeout;
2177*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, mask))
2178*4882a593Smuzhiyun 		conf->dot11MeshHWMPpreqMinInterval =
2179*4882a593Smuzhiyun 			nconf->dot11MeshHWMPpreqMinInterval;
2180*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, mask))
2181*4882a593Smuzhiyun 		conf->dot11MeshHWMPperrMinInterval =
2182*4882a593Smuzhiyun 			nconf->dot11MeshHWMPperrMinInterval;
2183*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
2184*4882a593Smuzhiyun 			   mask))
2185*4882a593Smuzhiyun 		conf->dot11MeshHWMPnetDiameterTraversalTime =
2186*4882a593Smuzhiyun 			nconf->dot11MeshHWMPnetDiameterTraversalTime;
2187*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ROOTMODE, mask)) {
2188*4882a593Smuzhiyun 		conf->dot11MeshHWMPRootMode = nconf->dot11MeshHWMPRootMode;
2189*4882a593Smuzhiyun 		ieee80211_mesh_root_setup(ifmsh);
2190*4882a593Smuzhiyun 	}
2191*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_GATE_ANNOUNCEMENTS, mask)) {
2192*4882a593Smuzhiyun 		/* our current gate announcement implementation rides on root
2193*4882a593Smuzhiyun 		 * announcements, so require this ifmsh to also be a root node
2194*4882a593Smuzhiyun 		 * */
2195*4882a593Smuzhiyun 		if (nconf->dot11MeshGateAnnouncementProtocol &&
2196*4882a593Smuzhiyun 		    !(conf->dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT)) {
2197*4882a593Smuzhiyun 			conf->dot11MeshHWMPRootMode = IEEE80211_PROACTIVE_RANN;
2198*4882a593Smuzhiyun 			ieee80211_mesh_root_setup(ifmsh);
2199*4882a593Smuzhiyun 		}
2200*4882a593Smuzhiyun 		conf->dot11MeshGateAnnouncementProtocol =
2201*4882a593Smuzhiyun 			nconf->dot11MeshGateAnnouncementProtocol;
2202*4882a593Smuzhiyun 	}
2203*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask))
2204*4882a593Smuzhiyun 		conf->dot11MeshHWMPRannInterval =
2205*4882a593Smuzhiyun 			nconf->dot11MeshHWMPRannInterval;
2206*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_FORWARDING, mask))
2207*4882a593Smuzhiyun 		conf->dot11MeshForwarding = nconf->dot11MeshForwarding;
2208*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_RSSI_THRESHOLD, mask)) {
2209*4882a593Smuzhiyun 		/* our RSSI threshold implementation is supported only for
2210*4882a593Smuzhiyun 		 * devices that report signal in dBm.
2211*4882a593Smuzhiyun 		 */
2212*4882a593Smuzhiyun 		if (!ieee80211_hw_check(&sdata->local->hw, SIGNAL_DBM))
2213*4882a593Smuzhiyun 			return -ENOTSUPP;
2214*4882a593Smuzhiyun 		conf->rssi_threshold = nconf->rssi_threshold;
2215*4882a593Smuzhiyun 	}
2216*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_HT_OPMODE, mask)) {
2217*4882a593Smuzhiyun 		conf->ht_opmode = nconf->ht_opmode;
2218*4882a593Smuzhiyun 		sdata->vif.bss_conf.ht_operation_mode = nconf->ht_opmode;
2219*4882a593Smuzhiyun 		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
2220*4882a593Smuzhiyun 	}
2221*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, mask))
2222*4882a593Smuzhiyun 		conf->dot11MeshHWMPactivePathToRootTimeout =
2223*4882a593Smuzhiyun 			nconf->dot11MeshHWMPactivePathToRootTimeout;
2224*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ROOT_INTERVAL, mask))
2225*4882a593Smuzhiyun 		conf->dot11MeshHWMProotInterval =
2226*4882a593Smuzhiyun 			nconf->dot11MeshHWMProotInterval;
2227*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, mask))
2228*4882a593Smuzhiyun 		conf->dot11MeshHWMPconfirmationInterval =
2229*4882a593Smuzhiyun 			nconf->dot11MeshHWMPconfirmationInterval;
2230*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_POWER_MODE, mask)) {
2231*4882a593Smuzhiyun 		conf->power_mode = nconf->power_mode;
2232*4882a593Smuzhiyun 		ieee80211_mps_local_status_update(sdata);
2233*4882a593Smuzhiyun 	}
2234*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_AWAKE_WINDOW, mask))
2235*4882a593Smuzhiyun 		conf->dot11MeshAwakeWindowDuration =
2236*4882a593Smuzhiyun 			nconf->dot11MeshAwakeWindowDuration;
2237*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_PLINK_TIMEOUT, mask))
2238*4882a593Smuzhiyun 		conf->plink_timeout = nconf->plink_timeout;
2239*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_CONNECTED_TO_GATE, mask))
2240*4882a593Smuzhiyun 		conf->dot11MeshConnectedToMeshGate =
2241*4882a593Smuzhiyun 			nconf->dot11MeshConnectedToMeshGate;
2242*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_NOLEARN, mask))
2243*4882a593Smuzhiyun 		conf->dot11MeshNolearn = nconf->dot11MeshNolearn;
2244*4882a593Smuzhiyun 	if (_chg_mesh_attr(NL80211_MESHCONF_CONNECTED_TO_AS, mask))
2245*4882a593Smuzhiyun 		conf->dot11MeshConnectedToAuthServer =
2246*4882a593Smuzhiyun 			nconf->dot11MeshConnectedToAuthServer;
2247*4882a593Smuzhiyun 	ieee80211_mbss_info_change_notify(sdata, BSS_CHANGED_BEACON);
2248*4882a593Smuzhiyun 	return 0;
2249*4882a593Smuzhiyun }
2250*4882a593Smuzhiyun 
ieee80211_join_mesh(struct wiphy * wiphy,struct net_device * dev,const struct mesh_config * conf,const struct mesh_setup * setup)2251*4882a593Smuzhiyun static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
2252*4882a593Smuzhiyun 			       const struct mesh_config *conf,
2253*4882a593Smuzhiyun 			       const struct mesh_setup *setup)
2254*4882a593Smuzhiyun {
2255*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2256*4882a593Smuzhiyun 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
2257*4882a593Smuzhiyun 	int err;
2258*4882a593Smuzhiyun 
2259*4882a593Smuzhiyun 	memcpy(&ifmsh->mshcfg, conf, sizeof(struct mesh_config));
2260*4882a593Smuzhiyun 	err = copy_mesh_setup(ifmsh, setup);
2261*4882a593Smuzhiyun 	if (err)
2262*4882a593Smuzhiyun 		return err;
2263*4882a593Smuzhiyun 
2264*4882a593Smuzhiyun 	sdata->control_port_over_nl80211 = setup->control_port_over_nl80211;
2265*4882a593Smuzhiyun 
2266*4882a593Smuzhiyun 	/* can mesh use other SMPS modes? */
2267*4882a593Smuzhiyun 	sdata->smps_mode = IEEE80211_SMPS_OFF;
2268*4882a593Smuzhiyun 	sdata->needed_rx_chains = sdata->local->rx_chains;
2269*4882a593Smuzhiyun 
2270*4882a593Smuzhiyun 	mutex_lock(&sdata->local->mtx);
2271*4882a593Smuzhiyun 	err = ieee80211_vif_use_channel(sdata, &setup->chandef,
2272*4882a593Smuzhiyun 					IEEE80211_CHANCTX_SHARED);
2273*4882a593Smuzhiyun 	mutex_unlock(&sdata->local->mtx);
2274*4882a593Smuzhiyun 	if (err)
2275*4882a593Smuzhiyun 		return err;
2276*4882a593Smuzhiyun 
2277*4882a593Smuzhiyun 	return ieee80211_start_mesh(sdata);
2278*4882a593Smuzhiyun }
2279*4882a593Smuzhiyun 
ieee80211_leave_mesh(struct wiphy * wiphy,struct net_device * dev)2280*4882a593Smuzhiyun static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
2281*4882a593Smuzhiyun {
2282*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2283*4882a593Smuzhiyun 
2284*4882a593Smuzhiyun 	ieee80211_stop_mesh(sdata);
2285*4882a593Smuzhiyun 	mutex_lock(&sdata->local->mtx);
2286*4882a593Smuzhiyun 	ieee80211_vif_release_channel(sdata);
2287*4882a593Smuzhiyun 	kfree(sdata->u.mesh.ie);
2288*4882a593Smuzhiyun 	mutex_unlock(&sdata->local->mtx);
2289*4882a593Smuzhiyun 
2290*4882a593Smuzhiyun 	return 0;
2291*4882a593Smuzhiyun }
2292*4882a593Smuzhiyun #endif
2293*4882a593Smuzhiyun 
ieee80211_change_bss(struct wiphy * wiphy,struct net_device * dev,struct bss_parameters * params)2294*4882a593Smuzhiyun static int ieee80211_change_bss(struct wiphy *wiphy,
2295*4882a593Smuzhiyun 				struct net_device *dev,
2296*4882a593Smuzhiyun 				struct bss_parameters *params)
2297*4882a593Smuzhiyun {
2298*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2299*4882a593Smuzhiyun 	struct ieee80211_supported_band *sband;
2300*4882a593Smuzhiyun 	u32 changed = 0;
2301*4882a593Smuzhiyun 
2302*4882a593Smuzhiyun 	if (!sdata_dereference(sdata->u.ap.beacon, sdata))
2303*4882a593Smuzhiyun 		return -ENOENT;
2304*4882a593Smuzhiyun 
2305*4882a593Smuzhiyun 	sband = ieee80211_get_sband(sdata);
2306*4882a593Smuzhiyun 	if (!sband)
2307*4882a593Smuzhiyun 		return -EINVAL;
2308*4882a593Smuzhiyun 
2309*4882a593Smuzhiyun 	if (params->use_cts_prot >= 0) {
2310*4882a593Smuzhiyun 		sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
2311*4882a593Smuzhiyun 		changed |= BSS_CHANGED_ERP_CTS_PROT;
2312*4882a593Smuzhiyun 	}
2313*4882a593Smuzhiyun 	if (params->use_short_preamble >= 0) {
2314*4882a593Smuzhiyun 		sdata->vif.bss_conf.use_short_preamble =
2315*4882a593Smuzhiyun 			params->use_short_preamble;
2316*4882a593Smuzhiyun 		changed |= BSS_CHANGED_ERP_PREAMBLE;
2317*4882a593Smuzhiyun 	}
2318*4882a593Smuzhiyun 
2319*4882a593Smuzhiyun 	if (!sdata->vif.bss_conf.use_short_slot &&
2320*4882a593Smuzhiyun 	    (sband->band == NL80211_BAND_5GHZ ||
2321*4882a593Smuzhiyun 	     sband->band == NL80211_BAND_6GHZ)) {
2322*4882a593Smuzhiyun 		sdata->vif.bss_conf.use_short_slot = true;
2323*4882a593Smuzhiyun 		changed |= BSS_CHANGED_ERP_SLOT;
2324*4882a593Smuzhiyun 	}
2325*4882a593Smuzhiyun 
2326*4882a593Smuzhiyun 	if (params->use_short_slot_time >= 0) {
2327*4882a593Smuzhiyun 		sdata->vif.bss_conf.use_short_slot =
2328*4882a593Smuzhiyun 			params->use_short_slot_time;
2329*4882a593Smuzhiyun 		changed |= BSS_CHANGED_ERP_SLOT;
2330*4882a593Smuzhiyun 	}
2331*4882a593Smuzhiyun 
2332*4882a593Smuzhiyun 	if (params->basic_rates) {
2333*4882a593Smuzhiyun 		ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef,
2334*4882a593Smuzhiyun 					 wiphy->bands[sband->band],
2335*4882a593Smuzhiyun 					 params->basic_rates,
2336*4882a593Smuzhiyun 					 params->basic_rates_len,
2337*4882a593Smuzhiyun 					 &sdata->vif.bss_conf.basic_rates);
2338*4882a593Smuzhiyun 		changed |= BSS_CHANGED_BASIC_RATES;
2339*4882a593Smuzhiyun 		ieee80211_check_rate_mask(sdata);
2340*4882a593Smuzhiyun 	}
2341*4882a593Smuzhiyun 
2342*4882a593Smuzhiyun 	if (params->ap_isolate >= 0) {
2343*4882a593Smuzhiyun 		if (params->ap_isolate)
2344*4882a593Smuzhiyun 			sdata->flags |= IEEE80211_SDATA_DONT_BRIDGE_PACKETS;
2345*4882a593Smuzhiyun 		else
2346*4882a593Smuzhiyun 			sdata->flags &= ~IEEE80211_SDATA_DONT_BRIDGE_PACKETS;
2347*4882a593Smuzhiyun 		ieee80211_check_fast_rx_iface(sdata);
2348*4882a593Smuzhiyun 	}
2349*4882a593Smuzhiyun 
2350*4882a593Smuzhiyun 	if (params->ht_opmode >= 0) {
2351*4882a593Smuzhiyun 		sdata->vif.bss_conf.ht_operation_mode =
2352*4882a593Smuzhiyun 			(u16) params->ht_opmode;
2353*4882a593Smuzhiyun 		changed |= BSS_CHANGED_HT;
2354*4882a593Smuzhiyun 	}
2355*4882a593Smuzhiyun 
2356*4882a593Smuzhiyun 	if (params->p2p_ctwindow >= 0) {
2357*4882a593Smuzhiyun 		sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow &=
2358*4882a593Smuzhiyun 					~IEEE80211_P2P_OPPPS_CTWINDOW_MASK;
2359*4882a593Smuzhiyun 		sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |=
2360*4882a593Smuzhiyun 			params->p2p_ctwindow & IEEE80211_P2P_OPPPS_CTWINDOW_MASK;
2361*4882a593Smuzhiyun 		changed |= BSS_CHANGED_P2P_PS;
2362*4882a593Smuzhiyun 	}
2363*4882a593Smuzhiyun 
2364*4882a593Smuzhiyun 	if (params->p2p_opp_ps > 0) {
2365*4882a593Smuzhiyun 		sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |=
2366*4882a593Smuzhiyun 					IEEE80211_P2P_OPPPS_ENABLE_BIT;
2367*4882a593Smuzhiyun 		changed |= BSS_CHANGED_P2P_PS;
2368*4882a593Smuzhiyun 	} else if (params->p2p_opp_ps == 0) {
2369*4882a593Smuzhiyun 		sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow &=
2370*4882a593Smuzhiyun 					~IEEE80211_P2P_OPPPS_ENABLE_BIT;
2371*4882a593Smuzhiyun 		changed |= BSS_CHANGED_P2P_PS;
2372*4882a593Smuzhiyun 	}
2373*4882a593Smuzhiyun 
2374*4882a593Smuzhiyun 	ieee80211_bss_info_change_notify(sdata, changed);
2375*4882a593Smuzhiyun 
2376*4882a593Smuzhiyun 	return 0;
2377*4882a593Smuzhiyun }
2378*4882a593Smuzhiyun 
ieee80211_set_txq_params(struct wiphy * wiphy,struct net_device * dev,struct ieee80211_txq_params * params)2379*4882a593Smuzhiyun static int ieee80211_set_txq_params(struct wiphy *wiphy,
2380*4882a593Smuzhiyun 				    struct net_device *dev,
2381*4882a593Smuzhiyun 				    struct ieee80211_txq_params *params)
2382*4882a593Smuzhiyun {
2383*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
2384*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2385*4882a593Smuzhiyun 	struct ieee80211_tx_queue_params p;
2386*4882a593Smuzhiyun 
2387*4882a593Smuzhiyun 	if (!local->ops->conf_tx)
2388*4882a593Smuzhiyun 		return -EOPNOTSUPP;
2389*4882a593Smuzhiyun 
2390*4882a593Smuzhiyun 	if (local->hw.queues < IEEE80211_NUM_ACS)
2391*4882a593Smuzhiyun 		return -EOPNOTSUPP;
2392*4882a593Smuzhiyun 
2393*4882a593Smuzhiyun 	memset(&p, 0, sizeof(p));
2394*4882a593Smuzhiyun 	p.aifs = params->aifs;
2395*4882a593Smuzhiyun 	p.cw_max = params->cwmax;
2396*4882a593Smuzhiyun 	p.cw_min = params->cwmin;
2397*4882a593Smuzhiyun 	p.txop = params->txop;
2398*4882a593Smuzhiyun 
2399*4882a593Smuzhiyun 	/*
2400*4882a593Smuzhiyun 	 * Setting tx queue params disables u-apsd because it's only
2401*4882a593Smuzhiyun 	 * called in master mode.
2402*4882a593Smuzhiyun 	 */
2403*4882a593Smuzhiyun 	p.uapsd = false;
2404*4882a593Smuzhiyun 
2405*4882a593Smuzhiyun 	ieee80211_regulatory_limit_wmm_params(sdata, &p, params->ac);
2406*4882a593Smuzhiyun 
2407*4882a593Smuzhiyun 	sdata->tx_conf[params->ac] = p;
2408*4882a593Smuzhiyun 	if (drv_conf_tx(local, sdata, params->ac, &p)) {
2409*4882a593Smuzhiyun 		wiphy_debug(local->hw.wiphy,
2410*4882a593Smuzhiyun 			    "failed to set TX queue parameters for AC %d\n",
2411*4882a593Smuzhiyun 			    params->ac);
2412*4882a593Smuzhiyun 		return -EINVAL;
2413*4882a593Smuzhiyun 	}
2414*4882a593Smuzhiyun 
2415*4882a593Smuzhiyun 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
2416*4882a593Smuzhiyun 
2417*4882a593Smuzhiyun 	return 0;
2418*4882a593Smuzhiyun }
2419*4882a593Smuzhiyun 
2420*4882a593Smuzhiyun #ifdef CONFIG_PM
ieee80211_suspend(struct wiphy * wiphy,struct cfg80211_wowlan * wowlan)2421*4882a593Smuzhiyun static int ieee80211_suspend(struct wiphy *wiphy,
2422*4882a593Smuzhiyun 			     struct cfg80211_wowlan *wowlan)
2423*4882a593Smuzhiyun {
2424*4882a593Smuzhiyun 	return __ieee80211_suspend(wiphy_priv(wiphy), wowlan);
2425*4882a593Smuzhiyun }
2426*4882a593Smuzhiyun 
ieee80211_resume(struct wiphy * wiphy)2427*4882a593Smuzhiyun static int ieee80211_resume(struct wiphy *wiphy)
2428*4882a593Smuzhiyun {
2429*4882a593Smuzhiyun 	return __ieee80211_resume(wiphy_priv(wiphy));
2430*4882a593Smuzhiyun }
2431*4882a593Smuzhiyun #else
2432*4882a593Smuzhiyun #define ieee80211_suspend NULL
2433*4882a593Smuzhiyun #define ieee80211_resume NULL
2434*4882a593Smuzhiyun #endif
2435*4882a593Smuzhiyun 
ieee80211_scan(struct wiphy * wiphy,struct cfg80211_scan_request * req)2436*4882a593Smuzhiyun static int ieee80211_scan(struct wiphy *wiphy,
2437*4882a593Smuzhiyun 			  struct cfg80211_scan_request *req)
2438*4882a593Smuzhiyun {
2439*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
2440*4882a593Smuzhiyun 
2441*4882a593Smuzhiyun 	sdata = IEEE80211_WDEV_TO_SUB_IF(req->wdev);
2442*4882a593Smuzhiyun 
2443*4882a593Smuzhiyun 	switch (ieee80211_vif_type_p2p(&sdata->vif)) {
2444*4882a593Smuzhiyun 	case NL80211_IFTYPE_STATION:
2445*4882a593Smuzhiyun 	case NL80211_IFTYPE_ADHOC:
2446*4882a593Smuzhiyun 	case NL80211_IFTYPE_MESH_POINT:
2447*4882a593Smuzhiyun 	case NL80211_IFTYPE_P2P_CLIENT:
2448*4882a593Smuzhiyun 	case NL80211_IFTYPE_P2P_DEVICE:
2449*4882a593Smuzhiyun 		break;
2450*4882a593Smuzhiyun 	case NL80211_IFTYPE_P2P_GO:
2451*4882a593Smuzhiyun 		if (sdata->local->ops->hw_scan)
2452*4882a593Smuzhiyun 			break;
2453*4882a593Smuzhiyun 		/*
2454*4882a593Smuzhiyun 		 * FIXME: implement NoA while scanning in software,
2455*4882a593Smuzhiyun 		 * for now fall through to allow scanning only when
2456*4882a593Smuzhiyun 		 * beaconing hasn't been configured yet
2457*4882a593Smuzhiyun 		 */
2458*4882a593Smuzhiyun 		fallthrough;
2459*4882a593Smuzhiyun 	case NL80211_IFTYPE_AP:
2460*4882a593Smuzhiyun 		/*
2461*4882a593Smuzhiyun 		 * If the scan has been forced (and the driver supports
2462*4882a593Smuzhiyun 		 * forcing), don't care about being beaconing already.
2463*4882a593Smuzhiyun 		 * This will create problems to the attached stations (e.g. all
2464*4882a593Smuzhiyun 		 * the  frames sent while scanning on other channel will be
2465*4882a593Smuzhiyun 		 * lost)
2466*4882a593Smuzhiyun 		 */
2467*4882a593Smuzhiyun 		if (sdata->u.ap.beacon &&
2468*4882a593Smuzhiyun 		    (!(wiphy->features & NL80211_FEATURE_AP_SCAN) ||
2469*4882a593Smuzhiyun 		     !(req->flags & NL80211_SCAN_FLAG_AP)))
2470*4882a593Smuzhiyun 			return -EOPNOTSUPP;
2471*4882a593Smuzhiyun 		break;
2472*4882a593Smuzhiyun 	case NL80211_IFTYPE_NAN:
2473*4882a593Smuzhiyun 	default:
2474*4882a593Smuzhiyun 		return -EOPNOTSUPP;
2475*4882a593Smuzhiyun 	}
2476*4882a593Smuzhiyun 
2477*4882a593Smuzhiyun 	return ieee80211_request_scan(sdata, req);
2478*4882a593Smuzhiyun }
2479*4882a593Smuzhiyun 
ieee80211_abort_scan(struct wiphy * wiphy,struct wireless_dev * wdev)2480*4882a593Smuzhiyun static void ieee80211_abort_scan(struct wiphy *wiphy, struct wireless_dev *wdev)
2481*4882a593Smuzhiyun {
2482*4882a593Smuzhiyun 	ieee80211_scan_cancel(wiphy_priv(wiphy));
2483*4882a593Smuzhiyun }
2484*4882a593Smuzhiyun 
2485*4882a593Smuzhiyun static int
ieee80211_sched_scan_start(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_sched_scan_request * req)2486*4882a593Smuzhiyun ieee80211_sched_scan_start(struct wiphy *wiphy,
2487*4882a593Smuzhiyun 			   struct net_device *dev,
2488*4882a593Smuzhiyun 			   struct cfg80211_sched_scan_request *req)
2489*4882a593Smuzhiyun {
2490*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2491*4882a593Smuzhiyun 
2492*4882a593Smuzhiyun 	if (!sdata->local->ops->sched_scan_start)
2493*4882a593Smuzhiyun 		return -EOPNOTSUPP;
2494*4882a593Smuzhiyun 
2495*4882a593Smuzhiyun 	return ieee80211_request_sched_scan_start(sdata, req);
2496*4882a593Smuzhiyun }
2497*4882a593Smuzhiyun 
2498*4882a593Smuzhiyun static int
ieee80211_sched_scan_stop(struct wiphy * wiphy,struct net_device * dev,u64 reqid)2499*4882a593Smuzhiyun ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev,
2500*4882a593Smuzhiyun 			  u64 reqid)
2501*4882a593Smuzhiyun {
2502*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
2503*4882a593Smuzhiyun 
2504*4882a593Smuzhiyun 	if (!local->ops->sched_scan_stop)
2505*4882a593Smuzhiyun 		return -EOPNOTSUPP;
2506*4882a593Smuzhiyun 
2507*4882a593Smuzhiyun 	return ieee80211_request_sched_scan_stop(local);
2508*4882a593Smuzhiyun }
2509*4882a593Smuzhiyun 
ieee80211_auth(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_auth_request * req)2510*4882a593Smuzhiyun static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
2511*4882a593Smuzhiyun 			  struct cfg80211_auth_request *req)
2512*4882a593Smuzhiyun {
2513*4882a593Smuzhiyun 	return ieee80211_mgd_auth(IEEE80211_DEV_TO_SUB_IF(dev), req);
2514*4882a593Smuzhiyun }
2515*4882a593Smuzhiyun 
ieee80211_assoc(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_assoc_request * req)2516*4882a593Smuzhiyun static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
2517*4882a593Smuzhiyun 			   struct cfg80211_assoc_request *req)
2518*4882a593Smuzhiyun {
2519*4882a593Smuzhiyun 	return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
2520*4882a593Smuzhiyun }
2521*4882a593Smuzhiyun 
ieee80211_deauth(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_deauth_request * req)2522*4882a593Smuzhiyun static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev,
2523*4882a593Smuzhiyun 			    struct cfg80211_deauth_request *req)
2524*4882a593Smuzhiyun {
2525*4882a593Smuzhiyun 	return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), req);
2526*4882a593Smuzhiyun }
2527*4882a593Smuzhiyun 
ieee80211_disassoc(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_disassoc_request * req)2528*4882a593Smuzhiyun static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
2529*4882a593Smuzhiyun 			      struct cfg80211_disassoc_request *req)
2530*4882a593Smuzhiyun {
2531*4882a593Smuzhiyun 	return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
2532*4882a593Smuzhiyun }
2533*4882a593Smuzhiyun 
ieee80211_join_ibss(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_ibss_params * params)2534*4882a593Smuzhiyun static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
2535*4882a593Smuzhiyun 			       struct cfg80211_ibss_params *params)
2536*4882a593Smuzhiyun {
2537*4882a593Smuzhiyun 	return ieee80211_ibss_join(IEEE80211_DEV_TO_SUB_IF(dev), params);
2538*4882a593Smuzhiyun }
2539*4882a593Smuzhiyun 
ieee80211_leave_ibss(struct wiphy * wiphy,struct net_device * dev)2540*4882a593Smuzhiyun static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
2541*4882a593Smuzhiyun {
2542*4882a593Smuzhiyun 	return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev));
2543*4882a593Smuzhiyun }
2544*4882a593Smuzhiyun 
ieee80211_join_ocb(struct wiphy * wiphy,struct net_device * dev,struct ocb_setup * setup)2545*4882a593Smuzhiyun static int ieee80211_join_ocb(struct wiphy *wiphy, struct net_device *dev,
2546*4882a593Smuzhiyun 			      struct ocb_setup *setup)
2547*4882a593Smuzhiyun {
2548*4882a593Smuzhiyun 	return ieee80211_ocb_join(IEEE80211_DEV_TO_SUB_IF(dev), setup);
2549*4882a593Smuzhiyun }
2550*4882a593Smuzhiyun 
ieee80211_leave_ocb(struct wiphy * wiphy,struct net_device * dev)2551*4882a593Smuzhiyun static int ieee80211_leave_ocb(struct wiphy *wiphy, struct net_device *dev)
2552*4882a593Smuzhiyun {
2553*4882a593Smuzhiyun 	return ieee80211_ocb_leave(IEEE80211_DEV_TO_SUB_IF(dev));
2554*4882a593Smuzhiyun }
2555*4882a593Smuzhiyun 
ieee80211_set_mcast_rate(struct wiphy * wiphy,struct net_device * dev,int rate[NUM_NL80211_BANDS])2556*4882a593Smuzhiyun static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev,
2557*4882a593Smuzhiyun 				    int rate[NUM_NL80211_BANDS])
2558*4882a593Smuzhiyun {
2559*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2560*4882a593Smuzhiyun 
2561*4882a593Smuzhiyun 	memcpy(sdata->vif.bss_conf.mcast_rate, rate,
2562*4882a593Smuzhiyun 	       sizeof(int) * NUM_NL80211_BANDS);
2563*4882a593Smuzhiyun 
2564*4882a593Smuzhiyun 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_MCAST_RATE);
2565*4882a593Smuzhiyun 
2566*4882a593Smuzhiyun 	return 0;
2567*4882a593Smuzhiyun }
2568*4882a593Smuzhiyun 
ieee80211_set_wiphy_params(struct wiphy * wiphy,u32 changed)2569*4882a593Smuzhiyun static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
2570*4882a593Smuzhiyun {
2571*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
2572*4882a593Smuzhiyun 	int err;
2573*4882a593Smuzhiyun 
2574*4882a593Smuzhiyun 	if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
2575*4882a593Smuzhiyun 		ieee80211_check_fast_xmit_all(local);
2576*4882a593Smuzhiyun 
2577*4882a593Smuzhiyun 		err = drv_set_frag_threshold(local, wiphy->frag_threshold);
2578*4882a593Smuzhiyun 
2579*4882a593Smuzhiyun 		if (err) {
2580*4882a593Smuzhiyun 			ieee80211_check_fast_xmit_all(local);
2581*4882a593Smuzhiyun 			return err;
2582*4882a593Smuzhiyun 		}
2583*4882a593Smuzhiyun 	}
2584*4882a593Smuzhiyun 
2585*4882a593Smuzhiyun 	if ((changed & WIPHY_PARAM_COVERAGE_CLASS) ||
2586*4882a593Smuzhiyun 	    (changed & WIPHY_PARAM_DYN_ACK)) {
2587*4882a593Smuzhiyun 		s16 coverage_class;
2588*4882a593Smuzhiyun 
2589*4882a593Smuzhiyun 		coverage_class = changed & WIPHY_PARAM_COVERAGE_CLASS ?
2590*4882a593Smuzhiyun 					wiphy->coverage_class : -1;
2591*4882a593Smuzhiyun 		err = drv_set_coverage_class(local, coverage_class);
2592*4882a593Smuzhiyun 
2593*4882a593Smuzhiyun 		if (err)
2594*4882a593Smuzhiyun 			return err;
2595*4882a593Smuzhiyun 	}
2596*4882a593Smuzhiyun 
2597*4882a593Smuzhiyun 	if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
2598*4882a593Smuzhiyun 		err = drv_set_rts_threshold(local, wiphy->rts_threshold);
2599*4882a593Smuzhiyun 
2600*4882a593Smuzhiyun 		if (err)
2601*4882a593Smuzhiyun 			return err;
2602*4882a593Smuzhiyun 	}
2603*4882a593Smuzhiyun 
2604*4882a593Smuzhiyun 	if (changed & WIPHY_PARAM_RETRY_SHORT) {
2605*4882a593Smuzhiyun 		if (wiphy->retry_short > IEEE80211_MAX_TX_RETRY)
2606*4882a593Smuzhiyun 			return -EINVAL;
2607*4882a593Smuzhiyun 		local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
2608*4882a593Smuzhiyun 	}
2609*4882a593Smuzhiyun 	if (changed & WIPHY_PARAM_RETRY_LONG) {
2610*4882a593Smuzhiyun 		if (wiphy->retry_long > IEEE80211_MAX_TX_RETRY)
2611*4882a593Smuzhiyun 			return -EINVAL;
2612*4882a593Smuzhiyun 		local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
2613*4882a593Smuzhiyun 	}
2614*4882a593Smuzhiyun 	if (changed &
2615*4882a593Smuzhiyun 	    (WIPHY_PARAM_RETRY_SHORT | WIPHY_PARAM_RETRY_LONG))
2616*4882a593Smuzhiyun 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS);
2617*4882a593Smuzhiyun 
2618*4882a593Smuzhiyun 	if (changed & (WIPHY_PARAM_TXQ_LIMIT |
2619*4882a593Smuzhiyun 		       WIPHY_PARAM_TXQ_MEMORY_LIMIT |
2620*4882a593Smuzhiyun 		       WIPHY_PARAM_TXQ_QUANTUM))
2621*4882a593Smuzhiyun 		ieee80211_txq_set_params(local);
2622*4882a593Smuzhiyun 
2623*4882a593Smuzhiyun 	return 0;
2624*4882a593Smuzhiyun }
2625*4882a593Smuzhiyun 
ieee80211_set_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,enum nl80211_tx_power_setting type,int mbm)2626*4882a593Smuzhiyun static int ieee80211_set_tx_power(struct wiphy *wiphy,
2627*4882a593Smuzhiyun 				  struct wireless_dev *wdev,
2628*4882a593Smuzhiyun 				  enum nl80211_tx_power_setting type, int mbm)
2629*4882a593Smuzhiyun {
2630*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
2631*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
2632*4882a593Smuzhiyun 	enum nl80211_tx_power_setting txp_type = type;
2633*4882a593Smuzhiyun 	bool update_txp_type = false;
2634*4882a593Smuzhiyun 	bool has_monitor = false;
2635*4882a593Smuzhiyun 
2636*4882a593Smuzhiyun 	if (wdev) {
2637*4882a593Smuzhiyun 		sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
2638*4882a593Smuzhiyun 
2639*4882a593Smuzhiyun 		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
2640*4882a593Smuzhiyun 			sdata = rtnl_dereference(local->monitor_sdata);
2641*4882a593Smuzhiyun 			if (!sdata)
2642*4882a593Smuzhiyun 				return -EOPNOTSUPP;
2643*4882a593Smuzhiyun 		}
2644*4882a593Smuzhiyun 
2645*4882a593Smuzhiyun 		switch (type) {
2646*4882a593Smuzhiyun 		case NL80211_TX_POWER_AUTOMATIC:
2647*4882a593Smuzhiyun 			sdata->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
2648*4882a593Smuzhiyun 			txp_type = NL80211_TX_POWER_LIMITED;
2649*4882a593Smuzhiyun 			break;
2650*4882a593Smuzhiyun 		case NL80211_TX_POWER_LIMITED:
2651*4882a593Smuzhiyun 		case NL80211_TX_POWER_FIXED:
2652*4882a593Smuzhiyun 			if (mbm < 0 || (mbm % 100))
2653*4882a593Smuzhiyun 				return -EOPNOTSUPP;
2654*4882a593Smuzhiyun 			sdata->user_power_level = MBM_TO_DBM(mbm);
2655*4882a593Smuzhiyun 			break;
2656*4882a593Smuzhiyun 		}
2657*4882a593Smuzhiyun 
2658*4882a593Smuzhiyun 		if (txp_type != sdata->vif.bss_conf.txpower_type) {
2659*4882a593Smuzhiyun 			update_txp_type = true;
2660*4882a593Smuzhiyun 			sdata->vif.bss_conf.txpower_type = txp_type;
2661*4882a593Smuzhiyun 		}
2662*4882a593Smuzhiyun 
2663*4882a593Smuzhiyun 		ieee80211_recalc_txpower(sdata, update_txp_type);
2664*4882a593Smuzhiyun 
2665*4882a593Smuzhiyun 		return 0;
2666*4882a593Smuzhiyun 	}
2667*4882a593Smuzhiyun 
2668*4882a593Smuzhiyun 	switch (type) {
2669*4882a593Smuzhiyun 	case NL80211_TX_POWER_AUTOMATIC:
2670*4882a593Smuzhiyun 		local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
2671*4882a593Smuzhiyun 		txp_type = NL80211_TX_POWER_LIMITED;
2672*4882a593Smuzhiyun 		break;
2673*4882a593Smuzhiyun 	case NL80211_TX_POWER_LIMITED:
2674*4882a593Smuzhiyun 	case NL80211_TX_POWER_FIXED:
2675*4882a593Smuzhiyun 		if (mbm < 0 || (mbm % 100))
2676*4882a593Smuzhiyun 			return -EOPNOTSUPP;
2677*4882a593Smuzhiyun 		local->user_power_level = MBM_TO_DBM(mbm);
2678*4882a593Smuzhiyun 		break;
2679*4882a593Smuzhiyun 	}
2680*4882a593Smuzhiyun 
2681*4882a593Smuzhiyun 	mutex_lock(&local->iflist_mtx);
2682*4882a593Smuzhiyun 	list_for_each_entry(sdata, &local->interfaces, list) {
2683*4882a593Smuzhiyun 		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
2684*4882a593Smuzhiyun 			has_monitor = true;
2685*4882a593Smuzhiyun 			continue;
2686*4882a593Smuzhiyun 		}
2687*4882a593Smuzhiyun 		sdata->user_power_level = local->user_power_level;
2688*4882a593Smuzhiyun 		if (txp_type != sdata->vif.bss_conf.txpower_type)
2689*4882a593Smuzhiyun 			update_txp_type = true;
2690*4882a593Smuzhiyun 		sdata->vif.bss_conf.txpower_type = txp_type;
2691*4882a593Smuzhiyun 	}
2692*4882a593Smuzhiyun 	list_for_each_entry(sdata, &local->interfaces, list) {
2693*4882a593Smuzhiyun 		if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
2694*4882a593Smuzhiyun 			continue;
2695*4882a593Smuzhiyun 		ieee80211_recalc_txpower(sdata, update_txp_type);
2696*4882a593Smuzhiyun 	}
2697*4882a593Smuzhiyun 	mutex_unlock(&local->iflist_mtx);
2698*4882a593Smuzhiyun 
2699*4882a593Smuzhiyun 	if (has_monitor) {
2700*4882a593Smuzhiyun 		sdata = rtnl_dereference(local->monitor_sdata);
2701*4882a593Smuzhiyun 		if (sdata) {
2702*4882a593Smuzhiyun 			sdata->user_power_level = local->user_power_level;
2703*4882a593Smuzhiyun 			if (txp_type != sdata->vif.bss_conf.txpower_type)
2704*4882a593Smuzhiyun 				update_txp_type = true;
2705*4882a593Smuzhiyun 			sdata->vif.bss_conf.txpower_type = txp_type;
2706*4882a593Smuzhiyun 
2707*4882a593Smuzhiyun 			ieee80211_recalc_txpower(sdata, update_txp_type);
2708*4882a593Smuzhiyun 		}
2709*4882a593Smuzhiyun 	}
2710*4882a593Smuzhiyun 
2711*4882a593Smuzhiyun 	return 0;
2712*4882a593Smuzhiyun }
2713*4882a593Smuzhiyun 
ieee80211_get_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,int * dbm)2714*4882a593Smuzhiyun static int ieee80211_get_tx_power(struct wiphy *wiphy,
2715*4882a593Smuzhiyun 				  struct wireless_dev *wdev,
2716*4882a593Smuzhiyun 				  int *dbm)
2717*4882a593Smuzhiyun {
2718*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
2719*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
2720*4882a593Smuzhiyun 
2721*4882a593Smuzhiyun 	if (local->ops->get_txpower)
2722*4882a593Smuzhiyun 		return drv_get_txpower(local, sdata, dbm);
2723*4882a593Smuzhiyun 
2724*4882a593Smuzhiyun 	if (!local->use_chanctx)
2725*4882a593Smuzhiyun 		*dbm = local->hw.conf.power_level;
2726*4882a593Smuzhiyun 	else
2727*4882a593Smuzhiyun 		*dbm = sdata->vif.bss_conf.txpower;
2728*4882a593Smuzhiyun 
2729*4882a593Smuzhiyun 	return 0;
2730*4882a593Smuzhiyun }
2731*4882a593Smuzhiyun 
ieee80211_set_wds_peer(struct wiphy * wiphy,struct net_device * dev,const u8 * addr)2732*4882a593Smuzhiyun static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
2733*4882a593Smuzhiyun 				  const u8 *addr)
2734*4882a593Smuzhiyun {
2735*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2736*4882a593Smuzhiyun 
2737*4882a593Smuzhiyun 	memcpy(&sdata->u.wds.remote_addr, addr, ETH_ALEN);
2738*4882a593Smuzhiyun 
2739*4882a593Smuzhiyun 	return 0;
2740*4882a593Smuzhiyun }
2741*4882a593Smuzhiyun 
ieee80211_rfkill_poll(struct wiphy * wiphy)2742*4882a593Smuzhiyun static void ieee80211_rfkill_poll(struct wiphy *wiphy)
2743*4882a593Smuzhiyun {
2744*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
2745*4882a593Smuzhiyun 
2746*4882a593Smuzhiyun 	drv_rfkill_poll(local);
2747*4882a593Smuzhiyun }
2748*4882a593Smuzhiyun 
2749*4882a593Smuzhiyun #ifdef CONFIG_NL80211_TESTMODE
ieee80211_testmode_cmd(struct wiphy * wiphy,struct wireless_dev * wdev,void * data,int len)2750*4882a593Smuzhiyun static int ieee80211_testmode_cmd(struct wiphy *wiphy,
2751*4882a593Smuzhiyun 				  struct wireless_dev *wdev,
2752*4882a593Smuzhiyun 				  void *data, int len)
2753*4882a593Smuzhiyun {
2754*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
2755*4882a593Smuzhiyun 	struct ieee80211_vif *vif = NULL;
2756*4882a593Smuzhiyun 
2757*4882a593Smuzhiyun 	if (!local->ops->testmode_cmd)
2758*4882a593Smuzhiyun 		return -EOPNOTSUPP;
2759*4882a593Smuzhiyun 
2760*4882a593Smuzhiyun 	if (wdev) {
2761*4882a593Smuzhiyun 		struct ieee80211_sub_if_data *sdata;
2762*4882a593Smuzhiyun 
2763*4882a593Smuzhiyun 		sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
2764*4882a593Smuzhiyun 		if (sdata->flags & IEEE80211_SDATA_IN_DRIVER)
2765*4882a593Smuzhiyun 			vif = &sdata->vif;
2766*4882a593Smuzhiyun 	}
2767*4882a593Smuzhiyun 
2768*4882a593Smuzhiyun 	return local->ops->testmode_cmd(&local->hw, vif, data, len);
2769*4882a593Smuzhiyun }
2770*4882a593Smuzhiyun 
ieee80211_testmode_dump(struct wiphy * wiphy,struct sk_buff * skb,struct netlink_callback * cb,void * data,int len)2771*4882a593Smuzhiyun static int ieee80211_testmode_dump(struct wiphy *wiphy,
2772*4882a593Smuzhiyun 				   struct sk_buff *skb,
2773*4882a593Smuzhiyun 				   struct netlink_callback *cb,
2774*4882a593Smuzhiyun 				   void *data, int len)
2775*4882a593Smuzhiyun {
2776*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
2777*4882a593Smuzhiyun 
2778*4882a593Smuzhiyun 	if (!local->ops->testmode_dump)
2779*4882a593Smuzhiyun 		return -EOPNOTSUPP;
2780*4882a593Smuzhiyun 
2781*4882a593Smuzhiyun 	return local->ops->testmode_dump(&local->hw, skb, cb, data, len);
2782*4882a593Smuzhiyun }
2783*4882a593Smuzhiyun #endif
2784*4882a593Smuzhiyun 
__ieee80211_request_smps_mgd(struct ieee80211_sub_if_data * sdata,enum ieee80211_smps_mode smps_mode)2785*4882a593Smuzhiyun int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
2786*4882a593Smuzhiyun 				 enum ieee80211_smps_mode smps_mode)
2787*4882a593Smuzhiyun {
2788*4882a593Smuzhiyun 	const u8 *ap;
2789*4882a593Smuzhiyun 	enum ieee80211_smps_mode old_req;
2790*4882a593Smuzhiyun 	int err;
2791*4882a593Smuzhiyun 	struct sta_info *sta;
2792*4882a593Smuzhiyun 	bool tdls_peer_found = false;
2793*4882a593Smuzhiyun 
2794*4882a593Smuzhiyun 	lockdep_assert_held(&sdata->wdev.mtx);
2795*4882a593Smuzhiyun 
2796*4882a593Smuzhiyun 	if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION))
2797*4882a593Smuzhiyun 		return -EINVAL;
2798*4882a593Smuzhiyun 
2799*4882a593Smuzhiyun 	old_req = sdata->u.mgd.req_smps;
2800*4882a593Smuzhiyun 	sdata->u.mgd.req_smps = smps_mode;
2801*4882a593Smuzhiyun 
2802*4882a593Smuzhiyun 	if (old_req == smps_mode &&
2803*4882a593Smuzhiyun 	    smps_mode != IEEE80211_SMPS_AUTOMATIC)
2804*4882a593Smuzhiyun 		return 0;
2805*4882a593Smuzhiyun 
2806*4882a593Smuzhiyun 	/*
2807*4882a593Smuzhiyun 	 * If not associated, or current association is not an HT
2808*4882a593Smuzhiyun 	 * association, there's no need to do anything, just store
2809*4882a593Smuzhiyun 	 * the new value until we associate.
2810*4882a593Smuzhiyun 	 */
2811*4882a593Smuzhiyun 	if (!sdata->u.mgd.associated ||
2812*4882a593Smuzhiyun 	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
2813*4882a593Smuzhiyun 		return 0;
2814*4882a593Smuzhiyun 
2815*4882a593Smuzhiyun 	ap = sdata->u.mgd.associated->bssid;
2816*4882a593Smuzhiyun 
2817*4882a593Smuzhiyun 	rcu_read_lock();
2818*4882a593Smuzhiyun 	list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
2819*4882a593Smuzhiyun 		if (!sta->sta.tdls || sta->sdata != sdata || !sta->uploaded ||
2820*4882a593Smuzhiyun 		    !test_sta_flag(sta, WLAN_STA_AUTHORIZED))
2821*4882a593Smuzhiyun 			continue;
2822*4882a593Smuzhiyun 
2823*4882a593Smuzhiyun 		tdls_peer_found = true;
2824*4882a593Smuzhiyun 		break;
2825*4882a593Smuzhiyun 	}
2826*4882a593Smuzhiyun 	rcu_read_unlock();
2827*4882a593Smuzhiyun 
2828*4882a593Smuzhiyun 	if (smps_mode == IEEE80211_SMPS_AUTOMATIC) {
2829*4882a593Smuzhiyun 		if (tdls_peer_found || !sdata->u.mgd.powersave)
2830*4882a593Smuzhiyun 			smps_mode = IEEE80211_SMPS_OFF;
2831*4882a593Smuzhiyun 		else
2832*4882a593Smuzhiyun 			smps_mode = IEEE80211_SMPS_DYNAMIC;
2833*4882a593Smuzhiyun 	}
2834*4882a593Smuzhiyun 
2835*4882a593Smuzhiyun 	/* send SM PS frame to AP */
2836*4882a593Smuzhiyun 	err = ieee80211_send_smps_action(sdata, smps_mode,
2837*4882a593Smuzhiyun 					 ap, ap);
2838*4882a593Smuzhiyun 	if (err)
2839*4882a593Smuzhiyun 		sdata->u.mgd.req_smps = old_req;
2840*4882a593Smuzhiyun 	else if (smps_mode != IEEE80211_SMPS_OFF && tdls_peer_found)
2841*4882a593Smuzhiyun 		ieee80211_teardown_tdls_peers(sdata);
2842*4882a593Smuzhiyun 
2843*4882a593Smuzhiyun 	return err;
2844*4882a593Smuzhiyun }
2845*4882a593Smuzhiyun 
ieee80211_set_power_mgmt(struct wiphy * wiphy,struct net_device * dev,bool enabled,int timeout)2846*4882a593Smuzhiyun static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
2847*4882a593Smuzhiyun 				    bool enabled, int timeout)
2848*4882a593Smuzhiyun {
2849*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2850*4882a593Smuzhiyun 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
2851*4882a593Smuzhiyun 
2852*4882a593Smuzhiyun 	if (sdata->vif.type != NL80211_IFTYPE_STATION)
2853*4882a593Smuzhiyun 		return -EOPNOTSUPP;
2854*4882a593Smuzhiyun 
2855*4882a593Smuzhiyun 	if (!ieee80211_hw_check(&local->hw, SUPPORTS_PS))
2856*4882a593Smuzhiyun 		return -EOPNOTSUPP;
2857*4882a593Smuzhiyun 
2858*4882a593Smuzhiyun 	if (enabled == sdata->u.mgd.powersave &&
2859*4882a593Smuzhiyun 	    timeout == local->dynamic_ps_forced_timeout)
2860*4882a593Smuzhiyun 		return 0;
2861*4882a593Smuzhiyun 
2862*4882a593Smuzhiyun 	sdata->u.mgd.powersave = enabled;
2863*4882a593Smuzhiyun 	local->dynamic_ps_forced_timeout = timeout;
2864*4882a593Smuzhiyun 
2865*4882a593Smuzhiyun 	/* no change, but if automatic follow powersave */
2866*4882a593Smuzhiyun 	sdata_lock(sdata);
2867*4882a593Smuzhiyun 	__ieee80211_request_smps_mgd(sdata, sdata->u.mgd.req_smps);
2868*4882a593Smuzhiyun 	sdata_unlock(sdata);
2869*4882a593Smuzhiyun 
2870*4882a593Smuzhiyun 	if (ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS))
2871*4882a593Smuzhiyun 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
2872*4882a593Smuzhiyun 
2873*4882a593Smuzhiyun 	ieee80211_recalc_ps(local);
2874*4882a593Smuzhiyun 	ieee80211_recalc_ps_vif(sdata);
2875*4882a593Smuzhiyun 	ieee80211_check_fast_rx_iface(sdata);
2876*4882a593Smuzhiyun 
2877*4882a593Smuzhiyun 	return 0;
2878*4882a593Smuzhiyun }
2879*4882a593Smuzhiyun 
ieee80211_set_cqm_rssi_config(struct wiphy * wiphy,struct net_device * dev,s32 rssi_thold,u32 rssi_hyst)2880*4882a593Smuzhiyun static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
2881*4882a593Smuzhiyun 					 struct net_device *dev,
2882*4882a593Smuzhiyun 					 s32 rssi_thold, u32 rssi_hyst)
2883*4882a593Smuzhiyun {
2884*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2885*4882a593Smuzhiyun 	struct ieee80211_vif *vif = &sdata->vif;
2886*4882a593Smuzhiyun 	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
2887*4882a593Smuzhiyun 
2888*4882a593Smuzhiyun 	if (rssi_thold == bss_conf->cqm_rssi_thold &&
2889*4882a593Smuzhiyun 	    rssi_hyst == bss_conf->cqm_rssi_hyst)
2890*4882a593Smuzhiyun 		return 0;
2891*4882a593Smuzhiyun 
2892*4882a593Smuzhiyun 	if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER &&
2893*4882a593Smuzhiyun 	    !(sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI))
2894*4882a593Smuzhiyun 		return -EOPNOTSUPP;
2895*4882a593Smuzhiyun 
2896*4882a593Smuzhiyun 	bss_conf->cqm_rssi_thold = rssi_thold;
2897*4882a593Smuzhiyun 	bss_conf->cqm_rssi_hyst = rssi_hyst;
2898*4882a593Smuzhiyun 	bss_conf->cqm_rssi_low = 0;
2899*4882a593Smuzhiyun 	bss_conf->cqm_rssi_high = 0;
2900*4882a593Smuzhiyun 	sdata->u.mgd.last_cqm_event_signal = 0;
2901*4882a593Smuzhiyun 
2902*4882a593Smuzhiyun 	/* tell the driver upon association, unless already associated */
2903*4882a593Smuzhiyun 	if (sdata->u.mgd.associated &&
2904*4882a593Smuzhiyun 	    sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)
2905*4882a593Smuzhiyun 		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM);
2906*4882a593Smuzhiyun 
2907*4882a593Smuzhiyun 	return 0;
2908*4882a593Smuzhiyun }
2909*4882a593Smuzhiyun 
ieee80211_set_cqm_rssi_range_config(struct wiphy * wiphy,struct net_device * dev,s32 rssi_low,s32 rssi_high)2910*4882a593Smuzhiyun static int ieee80211_set_cqm_rssi_range_config(struct wiphy *wiphy,
2911*4882a593Smuzhiyun 					       struct net_device *dev,
2912*4882a593Smuzhiyun 					       s32 rssi_low, s32 rssi_high)
2913*4882a593Smuzhiyun {
2914*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2915*4882a593Smuzhiyun 	struct ieee80211_vif *vif = &sdata->vif;
2916*4882a593Smuzhiyun 	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
2917*4882a593Smuzhiyun 
2918*4882a593Smuzhiyun 	if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)
2919*4882a593Smuzhiyun 		return -EOPNOTSUPP;
2920*4882a593Smuzhiyun 
2921*4882a593Smuzhiyun 	bss_conf->cqm_rssi_low = rssi_low;
2922*4882a593Smuzhiyun 	bss_conf->cqm_rssi_high = rssi_high;
2923*4882a593Smuzhiyun 	bss_conf->cqm_rssi_thold = 0;
2924*4882a593Smuzhiyun 	bss_conf->cqm_rssi_hyst = 0;
2925*4882a593Smuzhiyun 	sdata->u.mgd.last_cqm_event_signal = 0;
2926*4882a593Smuzhiyun 
2927*4882a593Smuzhiyun 	/* tell the driver upon association, unless already associated */
2928*4882a593Smuzhiyun 	if (sdata->u.mgd.associated &&
2929*4882a593Smuzhiyun 	    sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)
2930*4882a593Smuzhiyun 		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM);
2931*4882a593Smuzhiyun 
2932*4882a593Smuzhiyun 	return 0;
2933*4882a593Smuzhiyun }
2934*4882a593Smuzhiyun 
ieee80211_set_bitrate_mask(struct wiphy * wiphy,struct net_device * dev,const u8 * addr,const struct cfg80211_bitrate_mask * mask)2935*4882a593Smuzhiyun static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
2936*4882a593Smuzhiyun 				      struct net_device *dev,
2937*4882a593Smuzhiyun 				      const u8 *addr,
2938*4882a593Smuzhiyun 				      const struct cfg80211_bitrate_mask *mask)
2939*4882a593Smuzhiyun {
2940*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2941*4882a593Smuzhiyun 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
2942*4882a593Smuzhiyun 	int i, ret;
2943*4882a593Smuzhiyun 
2944*4882a593Smuzhiyun 	if (!ieee80211_sdata_running(sdata))
2945*4882a593Smuzhiyun 		return -ENETDOWN;
2946*4882a593Smuzhiyun 
2947*4882a593Smuzhiyun 	/*
2948*4882a593Smuzhiyun 	 * If active validate the setting and reject it if it doesn't leave
2949*4882a593Smuzhiyun 	 * at least one basic rate usable, since we really have to be able
2950*4882a593Smuzhiyun 	 * to send something, and if we're an AP we have to be able to do
2951*4882a593Smuzhiyun 	 * so at a basic rate so that all clients can receive it.
2952*4882a593Smuzhiyun 	 */
2953*4882a593Smuzhiyun 	if (rcu_access_pointer(sdata->vif.chanctx_conf) &&
2954*4882a593Smuzhiyun 	    sdata->vif.bss_conf.chandef.chan) {
2955*4882a593Smuzhiyun 		u32 basic_rates = sdata->vif.bss_conf.basic_rates;
2956*4882a593Smuzhiyun 		enum nl80211_band band = sdata->vif.bss_conf.chandef.chan->band;
2957*4882a593Smuzhiyun 
2958*4882a593Smuzhiyun 		if (!(mask->control[band].legacy & basic_rates))
2959*4882a593Smuzhiyun 			return -EINVAL;
2960*4882a593Smuzhiyun 	}
2961*4882a593Smuzhiyun 
2962*4882a593Smuzhiyun 	if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) {
2963*4882a593Smuzhiyun 		ret = drv_set_bitrate_mask(local, sdata, mask);
2964*4882a593Smuzhiyun 		if (ret)
2965*4882a593Smuzhiyun 			return ret;
2966*4882a593Smuzhiyun 	}
2967*4882a593Smuzhiyun 
2968*4882a593Smuzhiyun 	for (i = 0; i < NUM_NL80211_BANDS; i++) {
2969*4882a593Smuzhiyun 		struct ieee80211_supported_band *sband = wiphy->bands[i];
2970*4882a593Smuzhiyun 		int j;
2971*4882a593Smuzhiyun 
2972*4882a593Smuzhiyun 		sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
2973*4882a593Smuzhiyun 		memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].ht_mcs,
2974*4882a593Smuzhiyun 		       sizeof(mask->control[i].ht_mcs));
2975*4882a593Smuzhiyun 		memcpy(sdata->rc_rateidx_vht_mcs_mask[i],
2976*4882a593Smuzhiyun 		       mask->control[i].vht_mcs,
2977*4882a593Smuzhiyun 		       sizeof(mask->control[i].vht_mcs));
2978*4882a593Smuzhiyun 
2979*4882a593Smuzhiyun 		sdata->rc_has_mcs_mask[i] = false;
2980*4882a593Smuzhiyun 		sdata->rc_has_vht_mcs_mask[i] = false;
2981*4882a593Smuzhiyun 		if (!sband)
2982*4882a593Smuzhiyun 			continue;
2983*4882a593Smuzhiyun 
2984*4882a593Smuzhiyun 		for (j = 0; j < IEEE80211_HT_MCS_MASK_LEN; j++) {
2985*4882a593Smuzhiyun 			if (sdata->rc_rateidx_mcs_mask[i][j] != 0xff) {
2986*4882a593Smuzhiyun 				sdata->rc_has_mcs_mask[i] = true;
2987*4882a593Smuzhiyun 				break;
2988*4882a593Smuzhiyun 			}
2989*4882a593Smuzhiyun 		}
2990*4882a593Smuzhiyun 
2991*4882a593Smuzhiyun 		for (j = 0; j < NL80211_VHT_NSS_MAX; j++) {
2992*4882a593Smuzhiyun 			if (sdata->rc_rateidx_vht_mcs_mask[i][j] != 0xffff) {
2993*4882a593Smuzhiyun 				sdata->rc_has_vht_mcs_mask[i] = true;
2994*4882a593Smuzhiyun 				break;
2995*4882a593Smuzhiyun 			}
2996*4882a593Smuzhiyun 		}
2997*4882a593Smuzhiyun 	}
2998*4882a593Smuzhiyun 
2999*4882a593Smuzhiyun 	return 0;
3000*4882a593Smuzhiyun }
3001*4882a593Smuzhiyun 
ieee80211_start_radar_detection(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_chan_def * chandef,u32 cac_time_ms)3002*4882a593Smuzhiyun static int ieee80211_start_radar_detection(struct wiphy *wiphy,
3003*4882a593Smuzhiyun 					   struct net_device *dev,
3004*4882a593Smuzhiyun 					   struct cfg80211_chan_def *chandef,
3005*4882a593Smuzhiyun 					   u32 cac_time_ms)
3006*4882a593Smuzhiyun {
3007*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3008*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
3009*4882a593Smuzhiyun 	int err;
3010*4882a593Smuzhiyun 
3011*4882a593Smuzhiyun 	mutex_lock(&local->mtx);
3012*4882a593Smuzhiyun 	if (!list_empty(&local->roc_list) || local->scanning) {
3013*4882a593Smuzhiyun 		err = -EBUSY;
3014*4882a593Smuzhiyun 		goto out_unlock;
3015*4882a593Smuzhiyun 	}
3016*4882a593Smuzhiyun 
3017*4882a593Smuzhiyun 	/* whatever, but channel contexts should not complain about that one */
3018*4882a593Smuzhiyun 	sdata->smps_mode = IEEE80211_SMPS_OFF;
3019*4882a593Smuzhiyun 	sdata->needed_rx_chains = local->rx_chains;
3020*4882a593Smuzhiyun 
3021*4882a593Smuzhiyun 	err = ieee80211_vif_use_channel(sdata, chandef,
3022*4882a593Smuzhiyun 					IEEE80211_CHANCTX_SHARED);
3023*4882a593Smuzhiyun 	if (err)
3024*4882a593Smuzhiyun 		goto out_unlock;
3025*4882a593Smuzhiyun 
3026*4882a593Smuzhiyun 	ieee80211_queue_delayed_work(&sdata->local->hw,
3027*4882a593Smuzhiyun 				     &sdata->dfs_cac_timer_work,
3028*4882a593Smuzhiyun 				     msecs_to_jiffies(cac_time_ms));
3029*4882a593Smuzhiyun 
3030*4882a593Smuzhiyun  out_unlock:
3031*4882a593Smuzhiyun 	mutex_unlock(&local->mtx);
3032*4882a593Smuzhiyun 	return err;
3033*4882a593Smuzhiyun }
3034*4882a593Smuzhiyun 
ieee80211_end_cac(struct wiphy * wiphy,struct net_device * dev)3035*4882a593Smuzhiyun static void ieee80211_end_cac(struct wiphy *wiphy,
3036*4882a593Smuzhiyun 			      struct net_device *dev)
3037*4882a593Smuzhiyun {
3038*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3039*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
3040*4882a593Smuzhiyun 
3041*4882a593Smuzhiyun 	mutex_lock(&local->mtx);
3042*4882a593Smuzhiyun 	list_for_each_entry(sdata, &local->interfaces, list) {
3043*4882a593Smuzhiyun 		/* it might be waiting for the local->mtx, but then
3044*4882a593Smuzhiyun 		 * by the time it gets it, sdata->wdev.cac_started
3045*4882a593Smuzhiyun 		 * will no longer be true
3046*4882a593Smuzhiyun 		 */
3047*4882a593Smuzhiyun 		cancel_delayed_work(&sdata->dfs_cac_timer_work);
3048*4882a593Smuzhiyun 
3049*4882a593Smuzhiyun 		if (sdata->wdev.cac_started) {
3050*4882a593Smuzhiyun 			ieee80211_vif_release_channel(sdata);
3051*4882a593Smuzhiyun 			sdata->wdev.cac_started = false;
3052*4882a593Smuzhiyun 		}
3053*4882a593Smuzhiyun 	}
3054*4882a593Smuzhiyun 	mutex_unlock(&local->mtx);
3055*4882a593Smuzhiyun }
3056*4882a593Smuzhiyun 
3057*4882a593Smuzhiyun static struct cfg80211_beacon_data *
cfg80211_beacon_dup(struct cfg80211_beacon_data * beacon)3058*4882a593Smuzhiyun cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon)
3059*4882a593Smuzhiyun {
3060*4882a593Smuzhiyun 	struct cfg80211_beacon_data *new_beacon;
3061*4882a593Smuzhiyun 	u8 *pos;
3062*4882a593Smuzhiyun 	int len;
3063*4882a593Smuzhiyun 
3064*4882a593Smuzhiyun 	len = beacon->head_len + beacon->tail_len + beacon->beacon_ies_len +
3065*4882a593Smuzhiyun 	      beacon->proberesp_ies_len + beacon->assocresp_ies_len +
3066*4882a593Smuzhiyun 	      beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len;
3067*4882a593Smuzhiyun 
3068*4882a593Smuzhiyun 	new_beacon = kzalloc(sizeof(*new_beacon) + len, GFP_KERNEL);
3069*4882a593Smuzhiyun 	if (!new_beacon)
3070*4882a593Smuzhiyun 		return NULL;
3071*4882a593Smuzhiyun 
3072*4882a593Smuzhiyun 	pos = (u8 *)(new_beacon + 1);
3073*4882a593Smuzhiyun 	if (beacon->head_len) {
3074*4882a593Smuzhiyun 		new_beacon->head_len = beacon->head_len;
3075*4882a593Smuzhiyun 		new_beacon->head = pos;
3076*4882a593Smuzhiyun 		memcpy(pos, beacon->head, beacon->head_len);
3077*4882a593Smuzhiyun 		pos += beacon->head_len;
3078*4882a593Smuzhiyun 	}
3079*4882a593Smuzhiyun 	if (beacon->tail_len) {
3080*4882a593Smuzhiyun 		new_beacon->tail_len = beacon->tail_len;
3081*4882a593Smuzhiyun 		new_beacon->tail = pos;
3082*4882a593Smuzhiyun 		memcpy(pos, beacon->tail, beacon->tail_len);
3083*4882a593Smuzhiyun 		pos += beacon->tail_len;
3084*4882a593Smuzhiyun 	}
3085*4882a593Smuzhiyun 	if (beacon->beacon_ies_len) {
3086*4882a593Smuzhiyun 		new_beacon->beacon_ies_len = beacon->beacon_ies_len;
3087*4882a593Smuzhiyun 		new_beacon->beacon_ies = pos;
3088*4882a593Smuzhiyun 		memcpy(pos, beacon->beacon_ies, beacon->beacon_ies_len);
3089*4882a593Smuzhiyun 		pos += beacon->beacon_ies_len;
3090*4882a593Smuzhiyun 	}
3091*4882a593Smuzhiyun 	if (beacon->proberesp_ies_len) {
3092*4882a593Smuzhiyun 		new_beacon->proberesp_ies_len = beacon->proberesp_ies_len;
3093*4882a593Smuzhiyun 		new_beacon->proberesp_ies = pos;
3094*4882a593Smuzhiyun 		memcpy(pos, beacon->proberesp_ies, beacon->proberesp_ies_len);
3095*4882a593Smuzhiyun 		pos += beacon->proberesp_ies_len;
3096*4882a593Smuzhiyun 	}
3097*4882a593Smuzhiyun 	if (beacon->assocresp_ies_len) {
3098*4882a593Smuzhiyun 		new_beacon->assocresp_ies_len = beacon->assocresp_ies_len;
3099*4882a593Smuzhiyun 		new_beacon->assocresp_ies = pos;
3100*4882a593Smuzhiyun 		memcpy(pos, beacon->assocresp_ies, beacon->assocresp_ies_len);
3101*4882a593Smuzhiyun 		pos += beacon->assocresp_ies_len;
3102*4882a593Smuzhiyun 	}
3103*4882a593Smuzhiyun 	if (beacon->probe_resp_len) {
3104*4882a593Smuzhiyun 		new_beacon->probe_resp_len = beacon->probe_resp_len;
3105*4882a593Smuzhiyun 		new_beacon->probe_resp = pos;
3106*4882a593Smuzhiyun 		memcpy(pos, beacon->probe_resp, beacon->probe_resp_len);
3107*4882a593Smuzhiyun 		pos += beacon->probe_resp_len;
3108*4882a593Smuzhiyun 	}
3109*4882a593Smuzhiyun 
3110*4882a593Smuzhiyun 	/* might copy -1, meaning no changes requested */
3111*4882a593Smuzhiyun 	new_beacon->ftm_responder = beacon->ftm_responder;
3112*4882a593Smuzhiyun 	if (beacon->lci) {
3113*4882a593Smuzhiyun 		new_beacon->lci_len = beacon->lci_len;
3114*4882a593Smuzhiyun 		new_beacon->lci = pos;
3115*4882a593Smuzhiyun 		memcpy(pos, beacon->lci, beacon->lci_len);
3116*4882a593Smuzhiyun 		pos += beacon->lci_len;
3117*4882a593Smuzhiyun 	}
3118*4882a593Smuzhiyun 	if (beacon->civicloc) {
3119*4882a593Smuzhiyun 		new_beacon->civicloc_len = beacon->civicloc_len;
3120*4882a593Smuzhiyun 		new_beacon->civicloc = pos;
3121*4882a593Smuzhiyun 		memcpy(pos, beacon->civicloc, beacon->civicloc_len);
3122*4882a593Smuzhiyun 		pos += beacon->civicloc_len;
3123*4882a593Smuzhiyun 	}
3124*4882a593Smuzhiyun 
3125*4882a593Smuzhiyun 	return new_beacon;
3126*4882a593Smuzhiyun }
3127*4882a593Smuzhiyun 
ieee80211_csa_finish(struct ieee80211_vif * vif)3128*4882a593Smuzhiyun void ieee80211_csa_finish(struct ieee80211_vif *vif)
3129*4882a593Smuzhiyun {
3130*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
3131*4882a593Smuzhiyun 
3132*4882a593Smuzhiyun 	ieee80211_queue_work(&sdata->local->hw,
3133*4882a593Smuzhiyun 			     &sdata->csa_finalize_work);
3134*4882a593Smuzhiyun }
3135*4882a593Smuzhiyun EXPORT_SYMBOL(ieee80211_csa_finish);
3136*4882a593Smuzhiyun 
ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data * sdata,u32 * changed)3137*4882a593Smuzhiyun static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata,
3138*4882a593Smuzhiyun 					  u32 *changed)
3139*4882a593Smuzhiyun {
3140*4882a593Smuzhiyun 	int err;
3141*4882a593Smuzhiyun 
3142*4882a593Smuzhiyun 	switch (sdata->vif.type) {
3143*4882a593Smuzhiyun 	case NL80211_IFTYPE_AP:
3144*4882a593Smuzhiyun 		err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon,
3145*4882a593Smuzhiyun 					      NULL);
3146*4882a593Smuzhiyun 		kfree(sdata->u.ap.next_beacon);
3147*4882a593Smuzhiyun 		sdata->u.ap.next_beacon = NULL;
3148*4882a593Smuzhiyun 
3149*4882a593Smuzhiyun 		if (err < 0)
3150*4882a593Smuzhiyun 			return err;
3151*4882a593Smuzhiyun 		*changed |= err;
3152*4882a593Smuzhiyun 		break;
3153*4882a593Smuzhiyun 	case NL80211_IFTYPE_ADHOC:
3154*4882a593Smuzhiyun 		err = ieee80211_ibss_finish_csa(sdata);
3155*4882a593Smuzhiyun 		if (err < 0)
3156*4882a593Smuzhiyun 			return err;
3157*4882a593Smuzhiyun 		*changed |= err;
3158*4882a593Smuzhiyun 		break;
3159*4882a593Smuzhiyun #ifdef CONFIG_MAC80211_MESH
3160*4882a593Smuzhiyun 	case NL80211_IFTYPE_MESH_POINT:
3161*4882a593Smuzhiyun 		err = ieee80211_mesh_finish_csa(sdata);
3162*4882a593Smuzhiyun 		if (err < 0)
3163*4882a593Smuzhiyun 			return err;
3164*4882a593Smuzhiyun 		*changed |= err;
3165*4882a593Smuzhiyun 		break;
3166*4882a593Smuzhiyun #endif
3167*4882a593Smuzhiyun 	default:
3168*4882a593Smuzhiyun 		WARN_ON(1);
3169*4882a593Smuzhiyun 		return -EINVAL;
3170*4882a593Smuzhiyun 	}
3171*4882a593Smuzhiyun 
3172*4882a593Smuzhiyun 	return 0;
3173*4882a593Smuzhiyun }
3174*4882a593Smuzhiyun 
__ieee80211_csa_finalize(struct ieee80211_sub_if_data * sdata)3175*4882a593Smuzhiyun static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
3176*4882a593Smuzhiyun {
3177*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
3178*4882a593Smuzhiyun 	u32 changed = 0;
3179*4882a593Smuzhiyun 	int err;
3180*4882a593Smuzhiyun 
3181*4882a593Smuzhiyun 	sdata_assert_lock(sdata);
3182*4882a593Smuzhiyun 	lockdep_assert_held(&local->mtx);
3183*4882a593Smuzhiyun 	lockdep_assert_held(&local->chanctx_mtx);
3184*4882a593Smuzhiyun 
3185*4882a593Smuzhiyun 	/*
3186*4882a593Smuzhiyun 	 * using reservation isn't immediate as it may be deferred until later
3187*4882a593Smuzhiyun 	 * with multi-vif. once reservation is complete it will re-schedule the
3188*4882a593Smuzhiyun 	 * work with no reserved_chanctx so verify chandef to check if it
3189*4882a593Smuzhiyun 	 * completed successfully
3190*4882a593Smuzhiyun 	 */
3191*4882a593Smuzhiyun 
3192*4882a593Smuzhiyun 	if (sdata->reserved_chanctx) {
3193*4882a593Smuzhiyun 		/*
3194*4882a593Smuzhiyun 		 * with multi-vif csa driver may call ieee80211_csa_finish()
3195*4882a593Smuzhiyun 		 * many times while waiting for other interfaces to use their
3196*4882a593Smuzhiyun 		 * reservations
3197*4882a593Smuzhiyun 		 */
3198*4882a593Smuzhiyun 		if (sdata->reserved_ready)
3199*4882a593Smuzhiyun 			return 0;
3200*4882a593Smuzhiyun 
3201*4882a593Smuzhiyun 		return ieee80211_vif_use_reserved_context(sdata);
3202*4882a593Smuzhiyun 	}
3203*4882a593Smuzhiyun 
3204*4882a593Smuzhiyun 	if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
3205*4882a593Smuzhiyun 					&sdata->csa_chandef))
3206*4882a593Smuzhiyun 		return -EINVAL;
3207*4882a593Smuzhiyun 
3208*4882a593Smuzhiyun 	sdata->vif.csa_active = false;
3209*4882a593Smuzhiyun 
3210*4882a593Smuzhiyun 	err = ieee80211_set_after_csa_beacon(sdata, &changed);
3211*4882a593Smuzhiyun 	if (err)
3212*4882a593Smuzhiyun 		return err;
3213*4882a593Smuzhiyun 
3214*4882a593Smuzhiyun 	ieee80211_bss_info_change_notify(sdata, changed);
3215*4882a593Smuzhiyun 
3216*4882a593Smuzhiyun 	if (sdata->csa_block_tx) {
3217*4882a593Smuzhiyun 		ieee80211_wake_vif_queues(local, sdata,
3218*4882a593Smuzhiyun 					  IEEE80211_QUEUE_STOP_REASON_CSA);
3219*4882a593Smuzhiyun 		sdata->csa_block_tx = false;
3220*4882a593Smuzhiyun 	}
3221*4882a593Smuzhiyun 
3222*4882a593Smuzhiyun 	err = drv_post_channel_switch(sdata);
3223*4882a593Smuzhiyun 	if (err)
3224*4882a593Smuzhiyun 		return err;
3225*4882a593Smuzhiyun 
3226*4882a593Smuzhiyun 	cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
3227*4882a593Smuzhiyun 
3228*4882a593Smuzhiyun 	return 0;
3229*4882a593Smuzhiyun }
3230*4882a593Smuzhiyun 
ieee80211_csa_finalize(struct ieee80211_sub_if_data * sdata)3231*4882a593Smuzhiyun static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
3232*4882a593Smuzhiyun {
3233*4882a593Smuzhiyun 	if (__ieee80211_csa_finalize(sdata)) {
3234*4882a593Smuzhiyun 		sdata_info(sdata, "failed to finalize CSA, disconnecting\n");
3235*4882a593Smuzhiyun 		cfg80211_stop_iface(sdata->local->hw.wiphy, &sdata->wdev,
3236*4882a593Smuzhiyun 				    GFP_KERNEL);
3237*4882a593Smuzhiyun 	}
3238*4882a593Smuzhiyun }
3239*4882a593Smuzhiyun 
ieee80211_csa_finalize_work(struct work_struct * work)3240*4882a593Smuzhiyun void ieee80211_csa_finalize_work(struct work_struct *work)
3241*4882a593Smuzhiyun {
3242*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata =
3243*4882a593Smuzhiyun 		container_of(work, struct ieee80211_sub_if_data,
3244*4882a593Smuzhiyun 			     csa_finalize_work);
3245*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
3246*4882a593Smuzhiyun 
3247*4882a593Smuzhiyun 	sdata_lock(sdata);
3248*4882a593Smuzhiyun 	mutex_lock(&local->mtx);
3249*4882a593Smuzhiyun 	mutex_lock(&local->chanctx_mtx);
3250*4882a593Smuzhiyun 
3251*4882a593Smuzhiyun 	/* AP might have been stopped while waiting for the lock. */
3252*4882a593Smuzhiyun 	if (!sdata->vif.csa_active)
3253*4882a593Smuzhiyun 		goto unlock;
3254*4882a593Smuzhiyun 
3255*4882a593Smuzhiyun 	if (!ieee80211_sdata_running(sdata))
3256*4882a593Smuzhiyun 		goto unlock;
3257*4882a593Smuzhiyun 
3258*4882a593Smuzhiyun 	ieee80211_csa_finalize(sdata);
3259*4882a593Smuzhiyun 
3260*4882a593Smuzhiyun unlock:
3261*4882a593Smuzhiyun 	mutex_unlock(&local->chanctx_mtx);
3262*4882a593Smuzhiyun 	mutex_unlock(&local->mtx);
3263*4882a593Smuzhiyun 	sdata_unlock(sdata);
3264*4882a593Smuzhiyun }
3265*4882a593Smuzhiyun 
ieee80211_set_csa_beacon(struct ieee80211_sub_if_data * sdata,struct cfg80211_csa_settings * params,u32 * changed)3266*4882a593Smuzhiyun static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
3267*4882a593Smuzhiyun 				    struct cfg80211_csa_settings *params,
3268*4882a593Smuzhiyun 				    u32 *changed)
3269*4882a593Smuzhiyun {
3270*4882a593Smuzhiyun 	struct ieee80211_csa_settings csa = {};
3271*4882a593Smuzhiyun 	int err;
3272*4882a593Smuzhiyun 
3273*4882a593Smuzhiyun 	switch (sdata->vif.type) {
3274*4882a593Smuzhiyun 	case NL80211_IFTYPE_AP:
3275*4882a593Smuzhiyun 		sdata->u.ap.next_beacon =
3276*4882a593Smuzhiyun 			cfg80211_beacon_dup(&params->beacon_after);
3277*4882a593Smuzhiyun 		if (!sdata->u.ap.next_beacon)
3278*4882a593Smuzhiyun 			return -ENOMEM;
3279*4882a593Smuzhiyun 
3280*4882a593Smuzhiyun 		/*
3281*4882a593Smuzhiyun 		 * With a count of 0, we don't have to wait for any
3282*4882a593Smuzhiyun 		 * TBTT before switching, so complete the CSA
3283*4882a593Smuzhiyun 		 * immediately.  In theory, with a count == 1 we
3284*4882a593Smuzhiyun 		 * should delay the switch until just before the next
3285*4882a593Smuzhiyun 		 * TBTT, but that would complicate things so we switch
3286*4882a593Smuzhiyun 		 * immediately too.  If we would delay the switch
3287*4882a593Smuzhiyun 		 * until the next TBTT, we would have to set the probe
3288*4882a593Smuzhiyun 		 * response here.
3289*4882a593Smuzhiyun 		 *
3290*4882a593Smuzhiyun 		 * TODO: A channel switch with count <= 1 without
3291*4882a593Smuzhiyun 		 * sending a CSA action frame is kind of useless,
3292*4882a593Smuzhiyun 		 * because the clients won't know we're changing
3293*4882a593Smuzhiyun 		 * channels.  The action frame must be implemented
3294*4882a593Smuzhiyun 		 * either here or in the userspace.
3295*4882a593Smuzhiyun 		 */
3296*4882a593Smuzhiyun 		if (params->count <= 1)
3297*4882a593Smuzhiyun 			break;
3298*4882a593Smuzhiyun 
3299*4882a593Smuzhiyun 		if ((params->n_counter_offsets_beacon >
3300*4882a593Smuzhiyun 		     IEEE80211_MAX_CNTDWN_COUNTERS_NUM) ||
3301*4882a593Smuzhiyun 		    (params->n_counter_offsets_presp >
3302*4882a593Smuzhiyun 		     IEEE80211_MAX_CNTDWN_COUNTERS_NUM))
3303*4882a593Smuzhiyun 			return -EINVAL;
3304*4882a593Smuzhiyun 
3305*4882a593Smuzhiyun 		csa.counter_offsets_beacon = params->counter_offsets_beacon;
3306*4882a593Smuzhiyun 		csa.counter_offsets_presp = params->counter_offsets_presp;
3307*4882a593Smuzhiyun 		csa.n_counter_offsets_beacon = params->n_counter_offsets_beacon;
3308*4882a593Smuzhiyun 		csa.n_counter_offsets_presp = params->n_counter_offsets_presp;
3309*4882a593Smuzhiyun 		csa.count = params->count;
3310*4882a593Smuzhiyun 
3311*4882a593Smuzhiyun 		err = ieee80211_assign_beacon(sdata, &params->beacon_csa, &csa);
3312*4882a593Smuzhiyun 		if (err < 0) {
3313*4882a593Smuzhiyun 			kfree(sdata->u.ap.next_beacon);
3314*4882a593Smuzhiyun 			return err;
3315*4882a593Smuzhiyun 		}
3316*4882a593Smuzhiyun 		*changed |= err;
3317*4882a593Smuzhiyun 
3318*4882a593Smuzhiyun 		break;
3319*4882a593Smuzhiyun 	case NL80211_IFTYPE_ADHOC:
3320*4882a593Smuzhiyun 		if (!sdata->vif.bss_conf.ibss_joined)
3321*4882a593Smuzhiyun 			return -EINVAL;
3322*4882a593Smuzhiyun 
3323*4882a593Smuzhiyun 		if (params->chandef.width != sdata->u.ibss.chandef.width)
3324*4882a593Smuzhiyun 			return -EINVAL;
3325*4882a593Smuzhiyun 
3326*4882a593Smuzhiyun 		switch (params->chandef.width) {
3327*4882a593Smuzhiyun 		case NL80211_CHAN_WIDTH_40:
3328*4882a593Smuzhiyun 			if (cfg80211_get_chandef_type(&params->chandef) !=
3329*4882a593Smuzhiyun 			    cfg80211_get_chandef_type(&sdata->u.ibss.chandef))
3330*4882a593Smuzhiyun 				return -EINVAL;
3331*4882a593Smuzhiyun 		case NL80211_CHAN_WIDTH_5:
3332*4882a593Smuzhiyun 		case NL80211_CHAN_WIDTH_10:
3333*4882a593Smuzhiyun 		case NL80211_CHAN_WIDTH_20_NOHT:
3334*4882a593Smuzhiyun 		case NL80211_CHAN_WIDTH_20:
3335*4882a593Smuzhiyun 			break;
3336*4882a593Smuzhiyun 		default:
3337*4882a593Smuzhiyun 			return -EINVAL;
3338*4882a593Smuzhiyun 		}
3339*4882a593Smuzhiyun 
3340*4882a593Smuzhiyun 		/* changes into another band are not supported */
3341*4882a593Smuzhiyun 		if (sdata->u.ibss.chandef.chan->band !=
3342*4882a593Smuzhiyun 		    params->chandef.chan->band)
3343*4882a593Smuzhiyun 			return -EINVAL;
3344*4882a593Smuzhiyun 
3345*4882a593Smuzhiyun 		/* see comments in the NL80211_IFTYPE_AP block */
3346*4882a593Smuzhiyun 		if (params->count > 1) {
3347*4882a593Smuzhiyun 			err = ieee80211_ibss_csa_beacon(sdata, params);
3348*4882a593Smuzhiyun 			if (err < 0)
3349*4882a593Smuzhiyun 				return err;
3350*4882a593Smuzhiyun 			*changed |= err;
3351*4882a593Smuzhiyun 		}
3352*4882a593Smuzhiyun 
3353*4882a593Smuzhiyun 		ieee80211_send_action_csa(sdata, params);
3354*4882a593Smuzhiyun 
3355*4882a593Smuzhiyun 		break;
3356*4882a593Smuzhiyun #ifdef CONFIG_MAC80211_MESH
3357*4882a593Smuzhiyun 	case NL80211_IFTYPE_MESH_POINT: {
3358*4882a593Smuzhiyun 		struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
3359*4882a593Smuzhiyun 
3360*4882a593Smuzhiyun 		/* changes into another band are not supported */
3361*4882a593Smuzhiyun 		if (sdata->vif.bss_conf.chandef.chan->band !=
3362*4882a593Smuzhiyun 		    params->chandef.chan->band)
3363*4882a593Smuzhiyun 			return -EINVAL;
3364*4882a593Smuzhiyun 
3365*4882a593Smuzhiyun 		if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_NONE) {
3366*4882a593Smuzhiyun 			ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_INIT;
3367*4882a593Smuzhiyun 			if (!ifmsh->pre_value)
3368*4882a593Smuzhiyun 				ifmsh->pre_value = 1;
3369*4882a593Smuzhiyun 			else
3370*4882a593Smuzhiyun 				ifmsh->pre_value++;
3371*4882a593Smuzhiyun 		}
3372*4882a593Smuzhiyun 
3373*4882a593Smuzhiyun 		/* see comments in the NL80211_IFTYPE_AP block */
3374*4882a593Smuzhiyun 		if (params->count > 1) {
3375*4882a593Smuzhiyun 			err = ieee80211_mesh_csa_beacon(sdata, params);
3376*4882a593Smuzhiyun 			if (err < 0) {
3377*4882a593Smuzhiyun 				ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
3378*4882a593Smuzhiyun 				return err;
3379*4882a593Smuzhiyun 			}
3380*4882a593Smuzhiyun 			*changed |= err;
3381*4882a593Smuzhiyun 		}
3382*4882a593Smuzhiyun 
3383*4882a593Smuzhiyun 		if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT)
3384*4882a593Smuzhiyun 			ieee80211_send_action_csa(sdata, params);
3385*4882a593Smuzhiyun 
3386*4882a593Smuzhiyun 		break;
3387*4882a593Smuzhiyun 		}
3388*4882a593Smuzhiyun #endif
3389*4882a593Smuzhiyun 	default:
3390*4882a593Smuzhiyun 		return -EOPNOTSUPP;
3391*4882a593Smuzhiyun 	}
3392*4882a593Smuzhiyun 
3393*4882a593Smuzhiyun 	return 0;
3394*4882a593Smuzhiyun }
3395*4882a593Smuzhiyun 
3396*4882a593Smuzhiyun static int
__ieee80211_channel_switch(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_csa_settings * params)3397*4882a593Smuzhiyun __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
3398*4882a593Smuzhiyun 			   struct cfg80211_csa_settings *params)
3399*4882a593Smuzhiyun {
3400*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3401*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
3402*4882a593Smuzhiyun 	struct ieee80211_channel_switch ch_switch;
3403*4882a593Smuzhiyun 	struct ieee80211_chanctx_conf *conf;
3404*4882a593Smuzhiyun 	struct ieee80211_chanctx *chanctx;
3405*4882a593Smuzhiyun 	u32 changed = 0;
3406*4882a593Smuzhiyun 	int err;
3407*4882a593Smuzhiyun 
3408*4882a593Smuzhiyun 	sdata_assert_lock(sdata);
3409*4882a593Smuzhiyun 	lockdep_assert_held(&local->mtx);
3410*4882a593Smuzhiyun 
3411*4882a593Smuzhiyun 	if (!list_empty(&local->roc_list) || local->scanning)
3412*4882a593Smuzhiyun 		return -EBUSY;
3413*4882a593Smuzhiyun 
3414*4882a593Smuzhiyun 	if (sdata->wdev.cac_started)
3415*4882a593Smuzhiyun 		return -EBUSY;
3416*4882a593Smuzhiyun 
3417*4882a593Smuzhiyun 	if (cfg80211_chandef_identical(&params->chandef,
3418*4882a593Smuzhiyun 				       &sdata->vif.bss_conf.chandef))
3419*4882a593Smuzhiyun 		return -EINVAL;
3420*4882a593Smuzhiyun 
3421*4882a593Smuzhiyun 	/* don't allow another channel switch if one is already active. */
3422*4882a593Smuzhiyun 	if (sdata->vif.csa_active)
3423*4882a593Smuzhiyun 		return -EBUSY;
3424*4882a593Smuzhiyun 
3425*4882a593Smuzhiyun 	mutex_lock(&local->chanctx_mtx);
3426*4882a593Smuzhiyun 	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
3427*4882a593Smuzhiyun 					 lockdep_is_held(&local->chanctx_mtx));
3428*4882a593Smuzhiyun 	if (!conf) {
3429*4882a593Smuzhiyun 		err = -EBUSY;
3430*4882a593Smuzhiyun 		goto out;
3431*4882a593Smuzhiyun 	}
3432*4882a593Smuzhiyun 
3433*4882a593Smuzhiyun 	if (params->chandef.chan->freq_offset) {
3434*4882a593Smuzhiyun 		/* this may work, but is untested */
3435*4882a593Smuzhiyun 		err = -EOPNOTSUPP;
3436*4882a593Smuzhiyun 		goto out;
3437*4882a593Smuzhiyun 	}
3438*4882a593Smuzhiyun 
3439*4882a593Smuzhiyun 	chanctx = container_of(conf, struct ieee80211_chanctx, conf);
3440*4882a593Smuzhiyun 
3441*4882a593Smuzhiyun 	ch_switch.timestamp = 0;
3442*4882a593Smuzhiyun 	ch_switch.device_timestamp = 0;
3443*4882a593Smuzhiyun 	ch_switch.block_tx = params->block_tx;
3444*4882a593Smuzhiyun 	ch_switch.chandef = params->chandef;
3445*4882a593Smuzhiyun 	ch_switch.count = params->count;
3446*4882a593Smuzhiyun 
3447*4882a593Smuzhiyun 	err = drv_pre_channel_switch(sdata, &ch_switch);
3448*4882a593Smuzhiyun 	if (err)
3449*4882a593Smuzhiyun 		goto out;
3450*4882a593Smuzhiyun 
3451*4882a593Smuzhiyun 	err = ieee80211_vif_reserve_chanctx(sdata, &params->chandef,
3452*4882a593Smuzhiyun 					    chanctx->mode,
3453*4882a593Smuzhiyun 					    params->radar_required);
3454*4882a593Smuzhiyun 	if (err)
3455*4882a593Smuzhiyun 		goto out;
3456*4882a593Smuzhiyun 
3457*4882a593Smuzhiyun 	/* if reservation is invalid then this will fail */
3458*4882a593Smuzhiyun 	err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0);
3459*4882a593Smuzhiyun 	if (err) {
3460*4882a593Smuzhiyun 		ieee80211_vif_unreserve_chanctx(sdata);
3461*4882a593Smuzhiyun 		goto out;
3462*4882a593Smuzhiyun 	}
3463*4882a593Smuzhiyun 
3464*4882a593Smuzhiyun 	err = ieee80211_set_csa_beacon(sdata, params, &changed);
3465*4882a593Smuzhiyun 	if (err) {
3466*4882a593Smuzhiyun 		ieee80211_vif_unreserve_chanctx(sdata);
3467*4882a593Smuzhiyun 		goto out;
3468*4882a593Smuzhiyun 	}
3469*4882a593Smuzhiyun 
3470*4882a593Smuzhiyun 	sdata->csa_chandef = params->chandef;
3471*4882a593Smuzhiyun 	sdata->csa_block_tx = params->block_tx;
3472*4882a593Smuzhiyun 	sdata->vif.csa_active = true;
3473*4882a593Smuzhiyun 
3474*4882a593Smuzhiyun 	if (sdata->csa_block_tx)
3475*4882a593Smuzhiyun 		ieee80211_stop_vif_queues(local, sdata,
3476*4882a593Smuzhiyun 					  IEEE80211_QUEUE_STOP_REASON_CSA);
3477*4882a593Smuzhiyun 
3478*4882a593Smuzhiyun 	cfg80211_ch_switch_started_notify(sdata->dev, &sdata->csa_chandef,
3479*4882a593Smuzhiyun 					  params->count);
3480*4882a593Smuzhiyun 
3481*4882a593Smuzhiyun 	if (changed) {
3482*4882a593Smuzhiyun 		ieee80211_bss_info_change_notify(sdata, changed);
3483*4882a593Smuzhiyun 		drv_channel_switch_beacon(sdata, &params->chandef);
3484*4882a593Smuzhiyun 	} else {
3485*4882a593Smuzhiyun 		/* if the beacon didn't change, we can finalize immediately */
3486*4882a593Smuzhiyun 		ieee80211_csa_finalize(sdata);
3487*4882a593Smuzhiyun 	}
3488*4882a593Smuzhiyun 
3489*4882a593Smuzhiyun out:
3490*4882a593Smuzhiyun 	mutex_unlock(&local->chanctx_mtx);
3491*4882a593Smuzhiyun 	return err;
3492*4882a593Smuzhiyun }
3493*4882a593Smuzhiyun 
ieee80211_channel_switch(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_csa_settings * params)3494*4882a593Smuzhiyun int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
3495*4882a593Smuzhiyun 			     struct cfg80211_csa_settings *params)
3496*4882a593Smuzhiyun {
3497*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3498*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
3499*4882a593Smuzhiyun 	int err;
3500*4882a593Smuzhiyun 
3501*4882a593Smuzhiyun 	mutex_lock(&local->mtx);
3502*4882a593Smuzhiyun 	err = __ieee80211_channel_switch(wiphy, dev, params);
3503*4882a593Smuzhiyun 	mutex_unlock(&local->mtx);
3504*4882a593Smuzhiyun 
3505*4882a593Smuzhiyun 	return err;
3506*4882a593Smuzhiyun }
3507*4882a593Smuzhiyun 
ieee80211_mgmt_tx_cookie(struct ieee80211_local * local)3508*4882a593Smuzhiyun u64 ieee80211_mgmt_tx_cookie(struct ieee80211_local *local)
3509*4882a593Smuzhiyun {
3510*4882a593Smuzhiyun 	lockdep_assert_held(&local->mtx);
3511*4882a593Smuzhiyun 
3512*4882a593Smuzhiyun 	local->roc_cookie_counter++;
3513*4882a593Smuzhiyun 
3514*4882a593Smuzhiyun 	/* wow, you wrapped 64 bits ... more likely a bug */
3515*4882a593Smuzhiyun 	if (WARN_ON(local->roc_cookie_counter == 0))
3516*4882a593Smuzhiyun 		local->roc_cookie_counter++;
3517*4882a593Smuzhiyun 
3518*4882a593Smuzhiyun 	return local->roc_cookie_counter;
3519*4882a593Smuzhiyun }
3520*4882a593Smuzhiyun 
ieee80211_attach_ack_skb(struct ieee80211_local * local,struct sk_buff * skb,u64 * cookie,gfp_t gfp)3521*4882a593Smuzhiyun int ieee80211_attach_ack_skb(struct ieee80211_local *local, struct sk_buff *skb,
3522*4882a593Smuzhiyun 			     u64 *cookie, gfp_t gfp)
3523*4882a593Smuzhiyun {
3524*4882a593Smuzhiyun 	unsigned long spin_flags;
3525*4882a593Smuzhiyun 	struct sk_buff *ack_skb;
3526*4882a593Smuzhiyun 	int id;
3527*4882a593Smuzhiyun 
3528*4882a593Smuzhiyun 	ack_skb = skb_copy(skb, gfp);
3529*4882a593Smuzhiyun 	if (!ack_skb)
3530*4882a593Smuzhiyun 		return -ENOMEM;
3531*4882a593Smuzhiyun 
3532*4882a593Smuzhiyun 	spin_lock_irqsave(&local->ack_status_lock, spin_flags);
3533*4882a593Smuzhiyun 	id = idr_alloc(&local->ack_status_frames, ack_skb,
3534*4882a593Smuzhiyun 		       1, 0x2000, GFP_ATOMIC);
3535*4882a593Smuzhiyun 	spin_unlock_irqrestore(&local->ack_status_lock, spin_flags);
3536*4882a593Smuzhiyun 
3537*4882a593Smuzhiyun 	if (id < 0) {
3538*4882a593Smuzhiyun 		kfree_skb(ack_skb);
3539*4882a593Smuzhiyun 		return -ENOMEM;
3540*4882a593Smuzhiyun 	}
3541*4882a593Smuzhiyun 
3542*4882a593Smuzhiyun 	IEEE80211_SKB_CB(skb)->ack_frame_id = id;
3543*4882a593Smuzhiyun 
3544*4882a593Smuzhiyun 	*cookie = ieee80211_mgmt_tx_cookie(local);
3545*4882a593Smuzhiyun 	IEEE80211_SKB_CB(ack_skb)->ack.cookie = *cookie;
3546*4882a593Smuzhiyun 
3547*4882a593Smuzhiyun 	return 0;
3548*4882a593Smuzhiyun }
3549*4882a593Smuzhiyun 
3550*4882a593Smuzhiyun static void
ieee80211_update_mgmt_frame_registrations(struct wiphy * wiphy,struct wireless_dev * wdev,struct mgmt_frame_regs * upd)3551*4882a593Smuzhiyun ieee80211_update_mgmt_frame_registrations(struct wiphy *wiphy,
3552*4882a593Smuzhiyun 					  struct wireless_dev *wdev,
3553*4882a593Smuzhiyun 					  struct mgmt_frame_regs *upd)
3554*4882a593Smuzhiyun {
3555*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
3556*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
3557*4882a593Smuzhiyun 	u32 preq_mask = BIT(IEEE80211_STYPE_PROBE_REQ >> 4);
3558*4882a593Smuzhiyun 	u32 action_mask = BIT(IEEE80211_STYPE_ACTION >> 4);
3559*4882a593Smuzhiyun 	bool global_change, intf_change;
3560*4882a593Smuzhiyun 
3561*4882a593Smuzhiyun 	global_change =
3562*4882a593Smuzhiyun 		(local->probe_req_reg != !!(upd->global_stypes & preq_mask)) ||
3563*4882a593Smuzhiyun 		(local->rx_mcast_action_reg !=
3564*4882a593Smuzhiyun 		 !!(upd->global_mcast_stypes & action_mask));
3565*4882a593Smuzhiyun 	local->probe_req_reg = upd->global_stypes & preq_mask;
3566*4882a593Smuzhiyun 	local->rx_mcast_action_reg = upd->global_mcast_stypes & action_mask;
3567*4882a593Smuzhiyun 
3568*4882a593Smuzhiyun 	intf_change = (sdata->vif.probe_req_reg !=
3569*4882a593Smuzhiyun 		       !!(upd->interface_stypes & preq_mask)) ||
3570*4882a593Smuzhiyun 		(sdata->vif.rx_mcast_action_reg !=
3571*4882a593Smuzhiyun 		 !!(upd->interface_mcast_stypes & action_mask));
3572*4882a593Smuzhiyun 	sdata->vif.probe_req_reg = upd->interface_stypes & preq_mask;
3573*4882a593Smuzhiyun 	sdata->vif.rx_mcast_action_reg =
3574*4882a593Smuzhiyun 		upd->interface_mcast_stypes & action_mask;
3575*4882a593Smuzhiyun 
3576*4882a593Smuzhiyun 	if (!local->open_count)
3577*4882a593Smuzhiyun 		return;
3578*4882a593Smuzhiyun 
3579*4882a593Smuzhiyun 	if (intf_change && ieee80211_sdata_running(sdata))
3580*4882a593Smuzhiyun 		drv_config_iface_filter(local, sdata,
3581*4882a593Smuzhiyun 					sdata->vif.probe_req_reg ?
3582*4882a593Smuzhiyun 						FIF_PROBE_REQ : 0,
3583*4882a593Smuzhiyun 					FIF_PROBE_REQ);
3584*4882a593Smuzhiyun 
3585*4882a593Smuzhiyun 	if (global_change)
3586*4882a593Smuzhiyun 		ieee80211_configure_filter(local);
3587*4882a593Smuzhiyun }
3588*4882a593Smuzhiyun 
ieee80211_set_antenna(struct wiphy * wiphy,u32 tx_ant,u32 rx_ant)3589*4882a593Smuzhiyun static int ieee80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant)
3590*4882a593Smuzhiyun {
3591*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
3592*4882a593Smuzhiyun 
3593*4882a593Smuzhiyun 	if (local->started)
3594*4882a593Smuzhiyun 		return -EOPNOTSUPP;
3595*4882a593Smuzhiyun 
3596*4882a593Smuzhiyun 	return drv_set_antenna(local, tx_ant, rx_ant);
3597*4882a593Smuzhiyun }
3598*4882a593Smuzhiyun 
ieee80211_get_antenna(struct wiphy * wiphy,u32 * tx_ant,u32 * rx_ant)3599*4882a593Smuzhiyun static int ieee80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant)
3600*4882a593Smuzhiyun {
3601*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
3602*4882a593Smuzhiyun 
3603*4882a593Smuzhiyun 	return drv_get_antenna(local, tx_ant, rx_ant);
3604*4882a593Smuzhiyun }
3605*4882a593Smuzhiyun 
ieee80211_set_rekey_data(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_gtk_rekey_data * data)3606*4882a593Smuzhiyun static int ieee80211_set_rekey_data(struct wiphy *wiphy,
3607*4882a593Smuzhiyun 				    struct net_device *dev,
3608*4882a593Smuzhiyun 				    struct cfg80211_gtk_rekey_data *data)
3609*4882a593Smuzhiyun {
3610*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
3611*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3612*4882a593Smuzhiyun 
3613*4882a593Smuzhiyun 	if (!local->ops->set_rekey_data)
3614*4882a593Smuzhiyun 		return -EOPNOTSUPP;
3615*4882a593Smuzhiyun 
3616*4882a593Smuzhiyun 	drv_set_rekey_data(local, sdata, data);
3617*4882a593Smuzhiyun 
3618*4882a593Smuzhiyun 	return 0;
3619*4882a593Smuzhiyun }
3620*4882a593Smuzhiyun 
ieee80211_probe_client(struct wiphy * wiphy,struct net_device * dev,const u8 * peer,u64 * cookie)3621*4882a593Smuzhiyun static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
3622*4882a593Smuzhiyun 				  const u8 *peer, u64 *cookie)
3623*4882a593Smuzhiyun {
3624*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3625*4882a593Smuzhiyun 	struct ieee80211_local *local = sdata->local;
3626*4882a593Smuzhiyun 	struct ieee80211_qos_hdr *nullfunc;
3627*4882a593Smuzhiyun 	struct sk_buff *skb;
3628*4882a593Smuzhiyun 	int size = sizeof(*nullfunc);
3629*4882a593Smuzhiyun 	__le16 fc;
3630*4882a593Smuzhiyun 	bool qos;
3631*4882a593Smuzhiyun 	struct ieee80211_tx_info *info;
3632*4882a593Smuzhiyun 	struct sta_info *sta;
3633*4882a593Smuzhiyun 	struct ieee80211_chanctx_conf *chanctx_conf;
3634*4882a593Smuzhiyun 	enum nl80211_band band;
3635*4882a593Smuzhiyun 	int ret;
3636*4882a593Smuzhiyun 
3637*4882a593Smuzhiyun 	/* the lock is needed to assign the cookie later */
3638*4882a593Smuzhiyun 	mutex_lock(&local->mtx);
3639*4882a593Smuzhiyun 
3640*4882a593Smuzhiyun 	rcu_read_lock();
3641*4882a593Smuzhiyun 	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
3642*4882a593Smuzhiyun 	if (WARN_ON(!chanctx_conf)) {
3643*4882a593Smuzhiyun 		ret = -EINVAL;
3644*4882a593Smuzhiyun 		goto unlock;
3645*4882a593Smuzhiyun 	}
3646*4882a593Smuzhiyun 	band = chanctx_conf->def.chan->band;
3647*4882a593Smuzhiyun 	sta = sta_info_get_bss(sdata, peer);
3648*4882a593Smuzhiyun 	if (sta) {
3649*4882a593Smuzhiyun 		qos = sta->sta.wme;
3650*4882a593Smuzhiyun 	} else {
3651*4882a593Smuzhiyun 		ret = -ENOLINK;
3652*4882a593Smuzhiyun 		goto unlock;
3653*4882a593Smuzhiyun 	}
3654*4882a593Smuzhiyun 
3655*4882a593Smuzhiyun 	if (qos) {
3656*4882a593Smuzhiyun 		fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
3657*4882a593Smuzhiyun 				 IEEE80211_STYPE_QOS_NULLFUNC |
3658*4882a593Smuzhiyun 				 IEEE80211_FCTL_FROMDS);
3659*4882a593Smuzhiyun 	} else {
3660*4882a593Smuzhiyun 		size -= 2;
3661*4882a593Smuzhiyun 		fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
3662*4882a593Smuzhiyun 				 IEEE80211_STYPE_NULLFUNC |
3663*4882a593Smuzhiyun 				 IEEE80211_FCTL_FROMDS);
3664*4882a593Smuzhiyun 	}
3665*4882a593Smuzhiyun 
3666*4882a593Smuzhiyun 	skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
3667*4882a593Smuzhiyun 	if (!skb) {
3668*4882a593Smuzhiyun 		ret = -ENOMEM;
3669*4882a593Smuzhiyun 		goto unlock;
3670*4882a593Smuzhiyun 	}
3671*4882a593Smuzhiyun 
3672*4882a593Smuzhiyun 	skb->dev = dev;
3673*4882a593Smuzhiyun 
3674*4882a593Smuzhiyun 	skb_reserve(skb, local->hw.extra_tx_headroom);
3675*4882a593Smuzhiyun 
3676*4882a593Smuzhiyun 	nullfunc = skb_put(skb, size);
3677*4882a593Smuzhiyun 	nullfunc->frame_control = fc;
3678*4882a593Smuzhiyun 	nullfunc->duration_id = 0;
3679*4882a593Smuzhiyun 	memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
3680*4882a593Smuzhiyun 	memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
3681*4882a593Smuzhiyun 	memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
3682*4882a593Smuzhiyun 	nullfunc->seq_ctrl = 0;
3683*4882a593Smuzhiyun 
3684*4882a593Smuzhiyun 	info = IEEE80211_SKB_CB(skb);
3685*4882a593Smuzhiyun 
3686*4882a593Smuzhiyun 	info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
3687*4882a593Smuzhiyun 		       IEEE80211_TX_INTFL_NL80211_FRAME_TX;
3688*4882a593Smuzhiyun 	info->band = band;
3689*4882a593Smuzhiyun 
3690*4882a593Smuzhiyun 	skb_set_queue_mapping(skb, IEEE80211_AC_VO);
3691*4882a593Smuzhiyun 	skb->priority = 7;
3692*4882a593Smuzhiyun 	if (qos)
3693*4882a593Smuzhiyun 		nullfunc->qos_ctrl = cpu_to_le16(7);
3694*4882a593Smuzhiyun 
3695*4882a593Smuzhiyun 	ret = ieee80211_attach_ack_skb(local, skb, cookie, GFP_ATOMIC);
3696*4882a593Smuzhiyun 	if (ret) {
3697*4882a593Smuzhiyun 		kfree_skb(skb);
3698*4882a593Smuzhiyun 		goto unlock;
3699*4882a593Smuzhiyun 	}
3700*4882a593Smuzhiyun 
3701*4882a593Smuzhiyun 	local_bh_disable();
3702*4882a593Smuzhiyun 	ieee80211_xmit(sdata, sta, skb);
3703*4882a593Smuzhiyun 	local_bh_enable();
3704*4882a593Smuzhiyun 
3705*4882a593Smuzhiyun 	ret = 0;
3706*4882a593Smuzhiyun unlock:
3707*4882a593Smuzhiyun 	rcu_read_unlock();
3708*4882a593Smuzhiyun 	mutex_unlock(&local->mtx);
3709*4882a593Smuzhiyun 
3710*4882a593Smuzhiyun 	return ret;
3711*4882a593Smuzhiyun }
3712*4882a593Smuzhiyun 
ieee80211_cfg_get_channel(struct wiphy * wiphy,struct wireless_dev * wdev,struct cfg80211_chan_def * chandef)3713*4882a593Smuzhiyun static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
3714*4882a593Smuzhiyun 				     struct wireless_dev *wdev,
3715*4882a593Smuzhiyun 				     struct cfg80211_chan_def *chandef)
3716*4882a593Smuzhiyun {
3717*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
3718*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
3719*4882a593Smuzhiyun 	struct ieee80211_chanctx_conf *chanctx_conf;
3720*4882a593Smuzhiyun 	int ret = -ENODATA;
3721*4882a593Smuzhiyun 
3722*4882a593Smuzhiyun 	rcu_read_lock();
3723*4882a593Smuzhiyun 	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
3724*4882a593Smuzhiyun 	if (chanctx_conf) {
3725*4882a593Smuzhiyun 		*chandef = sdata->vif.bss_conf.chandef;
3726*4882a593Smuzhiyun 		ret = 0;
3727*4882a593Smuzhiyun 	} else if (local->open_count > 0 &&
3728*4882a593Smuzhiyun 		   local->open_count == local->monitors &&
3729*4882a593Smuzhiyun 		   sdata->vif.type == NL80211_IFTYPE_MONITOR) {
3730*4882a593Smuzhiyun 		if (local->use_chanctx)
3731*4882a593Smuzhiyun 			*chandef = local->monitor_chandef;
3732*4882a593Smuzhiyun 		else
3733*4882a593Smuzhiyun 			*chandef = local->_oper_chandef;
3734*4882a593Smuzhiyun 		ret = 0;
3735*4882a593Smuzhiyun 	}
3736*4882a593Smuzhiyun 	rcu_read_unlock();
3737*4882a593Smuzhiyun 
3738*4882a593Smuzhiyun 	return ret;
3739*4882a593Smuzhiyun }
3740*4882a593Smuzhiyun 
3741*4882a593Smuzhiyun #ifdef CONFIG_PM
ieee80211_set_wakeup(struct wiphy * wiphy,bool enabled)3742*4882a593Smuzhiyun static void ieee80211_set_wakeup(struct wiphy *wiphy, bool enabled)
3743*4882a593Smuzhiyun {
3744*4882a593Smuzhiyun 	drv_set_wakeup(wiphy_priv(wiphy), enabled);
3745*4882a593Smuzhiyun }
3746*4882a593Smuzhiyun #endif
3747*4882a593Smuzhiyun 
ieee80211_set_qos_map(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_qos_map * qos_map)3748*4882a593Smuzhiyun static int ieee80211_set_qos_map(struct wiphy *wiphy,
3749*4882a593Smuzhiyun 				 struct net_device *dev,
3750*4882a593Smuzhiyun 				 struct cfg80211_qos_map *qos_map)
3751*4882a593Smuzhiyun {
3752*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3753*4882a593Smuzhiyun 	struct mac80211_qos_map *new_qos_map, *old_qos_map;
3754*4882a593Smuzhiyun 
3755*4882a593Smuzhiyun 	if (qos_map) {
3756*4882a593Smuzhiyun 		new_qos_map = kzalloc(sizeof(*new_qos_map), GFP_KERNEL);
3757*4882a593Smuzhiyun 		if (!new_qos_map)
3758*4882a593Smuzhiyun 			return -ENOMEM;
3759*4882a593Smuzhiyun 		memcpy(&new_qos_map->qos_map, qos_map, sizeof(*qos_map));
3760*4882a593Smuzhiyun 	} else {
3761*4882a593Smuzhiyun 		/* A NULL qos_map was passed to disable QoS mapping */
3762*4882a593Smuzhiyun 		new_qos_map = NULL;
3763*4882a593Smuzhiyun 	}
3764*4882a593Smuzhiyun 
3765*4882a593Smuzhiyun 	old_qos_map = sdata_dereference(sdata->qos_map, sdata);
3766*4882a593Smuzhiyun 	rcu_assign_pointer(sdata->qos_map, new_qos_map);
3767*4882a593Smuzhiyun 	if (old_qos_map)
3768*4882a593Smuzhiyun 		kfree_rcu(old_qos_map, rcu_head);
3769*4882a593Smuzhiyun 
3770*4882a593Smuzhiyun 	return 0;
3771*4882a593Smuzhiyun }
3772*4882a593Smuzhiyun 
ieee80211_set_ap_chanwidth(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_chan_def * chandef)3773*4882a593Smuzhiyun static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy,
3774*4882a593Smuzhiyun 				      struct net_device *dev,
3775*4882a593Smuzhiyun 				      struct cfg80211_chan_def *chandef)
3776*4882a593Smuzhiyun {
3777*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3778*4882a593Smuzhiyun 	int ret;
3779*4882a593Smuzhiyun 	u32 changed = 0;
3780*4882a593Smuzhiyun 
3781*4882a593Smuzhiyun 	ret = ieee80211_vif_change_bandwidth(sdata, chandef, &changed);
3782*4882a593Smuzhiyun 	if (ret == 0)
3783*4882a593Smuzhiyun 		ieee80211_bss_info_change_notify(sdata, changed);
3784*4882a593Smuzhiyun 
3785*4882a593Smuzhiyun 	return ret;
3786*4882a593Smuzhiyun }
3787*4882a593Smuzhiyun 
ieee80211_add_tx_ts(struct wiphy * wiphy,struct net_device * dev,u8 tsid,const u8 * peer,u8 up,u16 admitted_time)3788*4882a593Smuzhiyun static int ieee80211_add_tx_ts(struct wiphy *wiphy, struct net_device *dev,
3789*4882a593Smuzhiyun 			       u8 tsid, const u8 *peer, u8 up,
3790*4882a593Smuzhiyun 			       u16 admitted_time)
3791*4882a593Smuzhiyun {
3792*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3793*4882a593Smuzhiyun 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
3794*4882a593Smuzhiyun 	int ac = ieee802_1d_to_ac[up];
3795*4882a593Smuzhiyun 
3796*4882a593Smuzhiyun 	if (sdata->vif.type != NL80211_IFTYPE_STATION)
3797*4882a593Smuzhiyun 		return -EOPNOTSUPP;
3798*4882a593Smuzhiyun 
3799*4882a593Smuzhiyun 	if (!(sdata->wmm_acm & BIT(up)))
3800*4882a593Smuzhiyun 		return -EINVAL;
3801*4882a593Smuzhiyun 
3802*4882a593Smuzhiyun 	if (ifmgd->tx_tspec[ac].admitted_time)
3803*4882a593Smuzhiyun 		return -EBUSY;
3804*4882a593Smuzhiyun 
3805*4882a593Smuzhiyun 	if (admitted_time) {
3806*4882a593Smuzhiyun 		ifmgd->tx_tspec[ac].admitted_time = 32 * admitted_time;
3807*4882a593Smuzhiyun 		ifmgd->tx_tspec[ac].tsid = tsid;
3808*4882a593Smuzhiyun 		ifmgd->tx_tspec[ac].up = up;
3809*4882a593Smuzhiyun 	}
3810*4882a593Smuzhiyun 
3811*4882a593Smuzhiyun 	return 0;
3812*4882a593Smuzhiyun }
3813*4882a593Smuzhiyun 
ieee80211_del_tx_ts(struct wiphy * wiphy,struct net_device * dev,u8 tsid,const u8 * peer)3814*4882a593Smuzhiyun static int ieee80211_del_tx_ts(struct wiphy *wiphy, struct net_device *dev,
3815*4882a593Smuzhiyun 			       u8 tsid, const u8 *peer)
3816*4882a593Smuzhiyun {
3817*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3818*4882a593Smuzhiyun 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
3819*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
3820*4882a593Smuzhiyun 	int ac;
3821*4882a593Smuzhiyun 
3822*4882a593Smuzhiyun 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
3823*4882a593Smuzhiyun 		struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
3824*4882a593Smuzhiyun 
3825*4882a593Smuzhiyun 		/* skip unused entries */
3826*4882a593Smuzhiyun 		if (!tx_tspec->admitted_time)
3827*4882a593Smuzhiyun 			continue;
3828*4882a593Smuzhiyun 
3829*4882a593Smuzhiyun 		if (tx_tspec->tsid != tsid)
3830*4882a593Smuzhiyun 			continue;
3831*4882a593Smuzhiyun 
3832*4882a593Smuzhiyun 		/* due to this new packets will be reassigned to non-ACM ACs */
3833*4882a593Smuzhiyun 		tx_tspec->up = -1;
3834*4882a593Smuzhiyun 
3835*4882a593Smuzhiyun 		/* Make sure that all packets have been sent to avoid to
3836*4882a593Smuzhiyun 		 * restore the QoS params on packets that are still on the
3837*4882a593Smuzhiyun 		 * queues.
3838*4882a593Smuzhiyun 		 */
3839*4882a593Smuzhiyun 		synchronize_net();
3840*4882a593Smuzhiyun 		ieee80211_flush_queues(local, sdata, false);
3841*4882a593Smuzhiyun 
3842*4882a593Smuzhiyun 		/* restore the normal QoS parameters
3843*4882a593Smuzhiyun 		 * (unconditionally to avoid races)
3844*4882a593Smuzhiyun 		 */
3845*4882a593Smuzhiyun 		tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE;
3846*4882a593Smuzhiyun 		tx_tspec->downgraded = false;
3847*4882a593Smuzhiyun 		ieee80211_sta_handle_tspec_ac_params(sdata);
3848*4882a593Smuzhiyun 
3849*4882a593Smuzhiyun 		/* finally clear all the data */
3850*4882a593Smuzhiyun 		memset(tx_tspec, 0, sizeof(*tx_tspec));
3851*4882a593Smuzhiyun 
3852*4882a593Smuzhiyun 		return 0;
3853*4882a593Smuzhiyun 	}
3854*4882a593Smuzhiyun 
3855*4882a593Smuzhiyun 	return -ENOENT;
3856*4882a593Smuzhiyun }
3857*4882a593Smuzhiyun 
ieee80211_nan_func_terminated(struct ieee80211_vif * vif,u8 inst_id,enum nl80211_nan_func_term_reason reason,gfp_t gfp)3858*4882a593Smuzhiyun void ieee80211_nan_func_terminated(struct ieee80211_vif *vif,
3859*4882a593Smuzhiyun 				   u8 inst_id,
3860*4882a593Smuzhiyun 				   enum nl80211_nan_func_term_reason reason,
3861*4882a593Smuzhiyun 				   gfp_t gfp)
3862*4882a593Smuzhiyun {
3863*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
3864*4882a593Smuzhiyun 	struct cfg80211_nan_func *func;
3865*4882a593Smuzhiyun 	u64 cookie;
3866*4882a593Smuzhiyun 
3867*4882a593Smuzhiyun 	if (WARN_ON(vif->type != NL80211_IFTYPE_NAN))
3868*4882a593Smuzhiyun 		return;
3869*4882a593Smuzhiyun 
3870*4882a593Smuzhiyun 	spin_lock_bh(&sdata->u.nan.func_lock);
3871*4882a593Smuzhiyun 
3872*4882a593Smuzhiyun 	func = idr_find(&sdata->u.nan.function_inst_ids, inst_id);
3873*4882a593Smuzhiyun 	if (WARN_ON(!func)) {
3874*4882a593Smuzhiyun 		spin_unlock_bh(&sdata->u.nan.func_lock);
3875*4882a593Smuzhiyun 		return;
3876*4882a593Smuzhiyun 	}
3877*4882a593Smuzhiyun 
3878*4882a593Smuzhiyun 	cookie = func->cookie;
3879*4882a593Smuzhiyun 	idr_remove(&sdata->u.nan.function_inst_ids, inst_id);
3880*4882a593Smuzhiyun 
3881*4882a593Smuzhiyun 	spin_unlock_bh(&sdata->u.nan.func_lock);
3882*4882a593Smuzhiyun 
3883*4882a593Smuzhiyun 	cfg80211_free_nan_func(func);
3884*4882a593Smuzhiyun 
3885*4882a593Smuzhiyun 	cfg80211_nan_func_terminated(ieee80211_vif_to_wdev(vif), inst_id,
3886*4882a593Smuzhiyun 				     reason, cookie, gfp);
3887*4882a593Smuzhiyun }
3888*4882a593Smuzhiyun EXPORT_SYMBOL(ieee80211_nan_func_terminated);
3889*4882a593Smuzhiyun 
ieee80211_nan_func_match(struct ieee80211_vif * vif,struct cfg80211_nan_match_params * match,gfp_t gfp)3890*4882a593Smuzhiyun void ieee80211_nan_func_match(struct ieee80211_vif *vif,
3891*4882a593Smuzhiyun 			      struct cfg80211_nan_match_params *match,
3892*4882a593Smuzhiyun 			      gfp_t gfp)
3893*4882a593Smuzhiyun {
3894*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
3895*4882a593Smuzhiyun 	struct cfg80211_nan_func *func;
3896*4882a593Smuzhiyun 
3897*4882a593Smuzhiyun 	if (WARN_ON(vif->type != NL80211_IFTYPE_NAN))
3898*4882a593Smuzhiyun 		return;
3899*4882a593Smuzhiyun 
3900*4882a593Smuzhiyun 	spin_lock_bh(&sdata->u.nan.func_lock);
3901*4882a593Smuzhiyun 
3902*4882a593Smuzhiyun 	func = idr_find(&sdata->u.nan.function_inst_ids,  match->inst_id);
3903*4882a593Smuzhiyun 	if (WARN_ON(!func)) {
3904*4882a593Smuzhiyun 		spin_unlock_bh(&sdata->u.nan.func_lock);
3905*4882a593Smuzhiyun 		return;
3906*4882a593Smuzhiyun 	}
3907*4882a593Smuzhiyun 	match->cookie = func->cookie;
3908*4882a593Smuzhiyun 
3909*4882a593Smuzhiyun 	spin_unlock_bh(&sdata->u.nan.func_lock);
3910*4882a593Smuzhiyun 
3911*4882a593Smuzhiyun 	cfg80211_nan_match(ieee80211_vif_to_wdev(vif), match, gfp);
3912*4882a593Smuzhiyun }
3913*4882a593Smuzhiyun EXPORT_SYMBOL(ieee80211_nan_func_match);
3914*4882a593Smuzhiyun 
ieee80211_set_multicast_to_unicast(struct wiphy * wiphy,struct net_device * dev,const bool enabled)3915*4882a593Smuzhiyun static int ieee80211_set_multicast_to_unicast(struct wiphy *wiphy,
3916*4882a593Smuzhiyun 					      struct net_device *dev,
3917*4882a593Smuzhiyun 					      const bool enabled)
3918*4882a593Smuzhiyun {
3919*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3920*4882a593Smuzhiyun 
3921*4882a593Smuzhiyun 	sdata->u.ap.multicast_to_unicast = enabled;
3922*4882a593Smuzhiyun 
3923*4882a593Smuzhiyun 	return 0;
3924*4882a593Smuzhiyun }
3925*4882a593Smuzhiyun 
ieee80211_fill_txq_stats(struct cfg80211_txq_stats * txqstats,struct txq_info * txqi)3926*4882a593Smuzhiyun void ieee80211_fill_txq_stats(struct cfg80211_txq_stats *txqstats,
3927*4882a593Smuzhiyun 			      struct txq_info *txqi)
3928*4882a593Smuzhiyun {
3929*4882a593Smuzhiyun 	if (!(txqstats->filled & BIT(NL80211_TXQ_STATS_BACKLOG_BYTES))) {
3930*4882a593Smuzhiyun 		txqstats->filled |= BIT(NL80211_TXQ_STATS_BACKLOG_BYTES);
3931*4882a593Smuzhiyun 		txqstats->backlog_bytes = txqi->tin.backlog_bytes;
3932*4882a593Smuzhiyun 	}
3933*4882a593Smuzhiyun 
3934*4882a593Smuzhiyun 	if (!(txqstats->filled & BIT(NL80211_TXQ_STATS_BACKLOG_PACKETS))) {
3935*4882a593Smuzhiyun 		txqstats->filled |= BIT(NL80211_TXQ_STATS_BACKLOG_PACKETS);
3936*4882a593Smuzhiyun 		txqstats->backlog_packets = txqi->tin.backlog_packets;
3937*4882a593Smuzhiyun 	}
3938*4882a593Smuzhiyun 
3939*4882a593Smuzhiyun 	if (!(txqstats->filled & BIT(NL80211_TXQ_STATS_FLOWS))) {
3940*4882a593Smuzhiyun 		txqstats->filled |= BIT(NL80211_TXQ_STATS_FLOWS);
3941*4882a593Smuzhiyun 		txqstats->flows = txqi->tin.flows;
3942*4882a593Smuzhiyun 	}
3943*4882a593Smuzhiyun 
3944*4882a593Smuzhiyun 	if (!(txqstats->filled & BIT(NL80211_TXQ_STATS_DROPS))) {
3945*4882a593Smuzhiyun 		txqstats->filled |= BIT(NL80211_TXQ_STATS_DROPS);
3946*4882a593Smuzhiyun 		txqstats->drops = txqi->cstats.drop_count;
3947*4882a593Smuzhiyun 	}
3948*4882a593Smuzhiyun 
3949*4882a593Smuzhiyun 	if (!(txqstats->filled & BIT(NL80211_TXQ_STATS_ECN_MARKS))) {
3950*4882a593Smuzhiyun 		txqstats->filled |= BIT(NL80211_TXQ_STATS_ECN_MARKS);
3951*4882a593Smuzhiyun 		txqstats->ecn_marks = txqi->cstats.ecn_mark;
3952*4882a593Smuzhiyun 	}
3953*4882a593Smuzhiyun 
3954*4882a593Smuzhiyun 	if (!(txqstats->filled & BIT(NL80211_TXQ_STATS_OVERLIMIT))) {
3955*4882a593Smuzhiyun 		txqstats->filled |= BIT(NL80211_TXQ_STATS_OVERLIMIT);
3956*4882a593Smuzhiyun 		txqstats->overlimit = txqi->tin.overlimit;
3957*4882a593Smuzhiyun 	}
3958*4882a593Smuzhiyun 
3959*4882a593Smuzhiyun 	if (!(txqstats->filled & BIT(NL80211_TXQ_STATS_COLLISIONS))) {
3960*4882a593Smuzhiyun 		txqstats->filled |= BIT(NL80211_TXQ_STATS_COLLISIONS);
3961*4882a593Smuzhiyun 		txqstats->collisions = txqi->tin.collisions;
3962*4882a593Smuzhiyun 	}
3963*4882a593Smuzhiyun 
3964*4882a593Smuzhiyun 	if (!(txqstats->filled & BIT(NL80211_TXQ_STATS_TX_BYTES))) {
3965*4882a593Smuzhiyun 		txqstats->filled |= BIT(NL80211_TXQ_STATS_TX_BYTES);
3966*4882a593Smuzhiyun 		txqstats->tx_bytes = txqi->tin.tx_bytes;
3967*4882a593Smuzhiyun 	}
3968*4882a593Smuzhiyun 
3969*4882a593Smuzhiyun 	if (!(txqstats->filled & BIT(NL80211_TXQ_STATS_TX_PACKETS))) {
3970*4882a593Smuzhiyun 		txqstats->filled |= BIT(NL80211_TXQ_STATS_TX_PACKETS);
3971*4882a593Smuzhiyun 		txqstats->tx_packets = txqi->tin.tx_packets;
3972*4882a593Smuzhiyun 	}
3973*4882a593Smuzhiyun }
3974*4882a593Smuzhiyun 
ieee80211_get_txq_stats(struct wiphy * wiphy,struct wireless_dev * wdev,struct cfg80211_txq_stats * txqstats)3975*4882a593Smuzhiyun static int ieee80211_get_txq_stats(struct wiphy *wiphy,
3976*4882a593Smuzhiyun 				   struct wireless_dev *wdev,
3977*4882a593Smuzhiyun 				   struct cfg80211_txq_stats *txqstats)
3978*4882a593Smuzhiyun {
3979*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
3980*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata;
3981*4882a593Smuzhiyun 	int ret = 0;
3982*4882a593Smuzhiyun 
3983*4882a593Smuzhiyun 	if (!local->ops->wake_tx_queue)
3984*4882a593Smuzhiyun 		return 1;
3985*4882a593Smuzhiyun 
3986*4882a593Smuzhiyun 	spin_lock_bh(&local->fq.lock);
3987*4882a593Smuzhiyun 	rcu_read_lock();
3988*4882a593Smuzhiyun 
3989*4882a593Smuzhiyun 	if (wdev) {
3990*4882a593Smuzhiyun 		sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
3991*4882a593Smuzhiyun 		if (!sdata->vif.txq) {
3992*4882a593Smuzhiyun 			ret = 1;
3993*4882a593Smuzhiyun 			goto out;
3994*4882a593Smuzhiyun 		}
3995*4882a593Smuzhiyun 		ieee80211_fill_txq_stats(txqstats, to_txq_info(sdata->vif.txq));
3996*4882a593Smuzhiyun 	} else {
3997*4882a593Smuzhiyun 		/* phy stats */
3998*4882a593Smuzhiyun 		txqstats->filled |= BIT(NL80211_TXQ_STATS_BACKLOG_PACKETS) |
3999*4882a593Smuzhiyun 				    BIT(NL80211_TXQ_STATS_BACKLOG_BYTES) |
4000*4882a593Smuzhiyun 				    BIT(NL80211_TXQ_STATS_OVERLIMIT) |
4001*4882a593Smuzhiyun 				    BIT(NL80211_TXQ_STATS_OVERMEMORY) |
4002*4882a593Smuzhiyun 				    BIT(NL80211_TXQ_STATS_COLLISIONS) |
4003*4882a593Smuzhiyun 				    BIT(NL80211_TXQ_STATS_MAX_FLOWS);
4004*4882a593Smuzhiyun 		txqstats->backlog_packets = local->fq.backlog;
4005*4882a593Smuzhiyun 		txqstats->backlog_bytes = local->fq.memory_usage;
4006*4882a593Smuzhiyun 		txqstats->overlimit = local->fq.overlimit;
4007*4882a593Smuzhiyun 		txqstats->overmemory = local->fq.overmemory;
4008*4882a593Smuzhiyun 		txqstats->collisions = local->fq.collisions;
4009*4882a593Smuzhiyun 		txqstats->max_flows = local->fq.flows_cnt;
4010*4882a593Smuzhiyun 	}
4011*4882a593Smuzhiyun 
4012*4882a593Smuzhiyun out:
4013*4882a593Smuzhiyun 	rcu_read_unlock();
4014*4882a593Smuzhiyun 	spin_unlock_bh(&local->fq.lock);
4015*4882a593Smuzhiyun 
4016*4882a593Smuzhiyun 	return ret;
4017*4882a593Smuzhiyun }
4018*4882a593Smuzhiyun 
4019*4882a593Smuzhiyun static int
ieee80211_get_ftm_responder_stats(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_ftm_responder_stats * ftm_stats)4020*4882a593Smuzhiyun ieee80211_get_ftm_responder_stats(struct wiphy *wiphy,
4021*4882a593Smuzhiyun 				  struct net_device *dev,
4022*4882a593Smuzhiyun 				  struct cfg80211_ftm_responder_stats *ftm_stats)
4023*4882a593Smuzhiyun {
4024*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
4025*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
4026*4882a593Smuzhiyun 
4027*4882a593Smuzhiyun 	return drv_get_ftm_responder_stats(local, sdata, ftm_stats);
4028*4882a593Smuzhiyun }
4029*4882a593Smuzhiyun 
4030*4882a593Smuzhiyun static int
ieee80211_start_pmsr(struct wiphy * wiphy,struct wireless_dev * dev,struct cfg80211_pmsr_request * request)4031*4882a593Smuzhiyun ieee80211_start_pmsr(struct wiphy *wiphy, struct wireless_dev *dev,
4032*4882a593Smuzhiyun 		     struct cfg80211_pmsr_request *request)
4033*4882a593Smuzhiyun {
4034*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
4035*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(dev);
4036*4882a593Smuzhiyun 
4037*4882a593Smuzhiyun 	return drv_start_pmsr(local, sdata, request);
4038*4882a593Smuzhiyun }
4039*4882a593Smuzhiyun 
4040*4882a593Smuzhiyun static void
ieee80211_abort_pmsr(struct wiphy * wiphy,struct wireless_dev * dev,struct cfg80211_pmsr_request * request)4041*4882a593Smuzhiyun ieee80211_abort_pmsr(struct wiphy *wiphy, struct wireless_dev *dev,
4042*4882a593Smuzhiyun 		     struct cfg80211_pmsr_request *request)
4043*4882a593Smuzhiyun {
4044*4882a593Smuzhiyun 	struct ieee80211_local *local = wiphy_priv(wiphy);
4045*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(dev);
4046*4882a593Smuzhiyun 
4047*4882a593Smuzhiyun 	return drv_abort_pmsr(local, sdata, request);
4048*4882a593Smuzhiyun }
4049*4882a593Smuzhiyun 
ieee80211_set_tid_config(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_tid_config * tid_conf)4050*4882a593Smuzhiyun static int ieee80211_set_tid_config(struct wiphy *wiphy,
4051*4882a593Smuzhiyun 				    struct net_device *dev,
4052*4882a593Smuzhiyun 				    struct cfg80211_tid_config *tid_conf)
4053*4882a593Smuzhiyun {
4054*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
4055*4882a593Smuzhiyun 	struct sta_info *sta;
4056*4882a593Smuzhiyun 	int ret;
4057*4882a593Smuzhiyun 
4058*4882a593Smuzhiyun 	if (!sdata->local->ops->set_tid_config)
4059*4882a593Smuzhiyun 		return -EOPNOTSUPP;
4060*4882a593Smuzhiyun 
4061*4882a593Smuzhiyun 	if (!tid_conf->peer)
4062*4882a593Smuzhiyun 		return drv_set_tid_config(sdata->local, sdata, NULL, tid_conf);
4063*4882a593Smuzhiyun 
4064*4882a593Smuzhiyun 	mutex_lock(&sdata->local->sta_mtx);
4065*4882a593Smuzhiyun 	sta = sta_info_get_bss(sdata, tid_conf->peer);
4066*4882a593Smuzhiyun 	if (!sta) {
4067*4882a593Smuzhiyun 		mutex_unlock(&sdata->local->sta_mtx);
4068*4882a593Smuzhiyun 		return -ENOENT;
4069*4882a593Smuzhiyun 	}
4070*4882a593Smuzhiyun 
4071*4882a593Smuzhiyun 	ret = drv_set_tid_config(sdata->local, sdata, &sta->sta, tid_conf);
4072*4882a593Smuzhiyun 	mutex_unlock(&sdata->local->sta_mtx);
4073*4882a593Smuzhiyun 
4074*4882a593Smuzhiyun 	return ret;
4075*4882a593Smuzhiyun }
4076*4882a593Smuzhiyun 
ieee80211_reset_tid_config(struct wiphy * wiphy,struct net_device * dev,const u8 * peer,u8 tids)4077*4882a593Smuzhiyun static int ieee80211_reset_tid_config(struct wiphy *wiphy,
4078*4882a593Smuzhiyun 				      struct net_device *dev,
4079*4882a593Smuzhiyun 				      const u8 *peer, u8 tids)
4080*4882a593Smuzhiyun {
4081*4882a593Smuzhiyun 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
4082*4882a593Smuzhiyun 	struct sta_info *sta;
4083*4882a593Smuzhiyun 	int ret;
4084*4882a593Smuzhiyun 
4085*4882a593Smuzhiyun 	if (!sdata->local->ops->reset_tid_config)
4086*4882a593Smuzhiyun 		return -EOPNOTSUPP;
4087*4882a593Smuzhiyun 
4088*4882a593Smuzhiyun 	if (!peer)
4089*4882a593Smuzhiyun 		return drv_reset_tid_config(sdata->local, sdata, NULL, tids);
4090*4882a593Smuzhiyun 
4091*4882a593Smuzhiyun 	mutex_lock(&sdata->local->sta_mtx);
4092*4882a593Smuzhiyun 	sta = sta_info_get_bss(sdata, peer);
4093*4882a593Smuzhiyun 	if (!sta) {
4094*4882a593Smuzhiyun 		mutex_unlock(&sdata->local->sta_mtx);
4095*4882a593Smuzhiyun 		return -ENOENT;
4096*4882a593Smuzhiyun 	}
4097*4882a593Smuzhiyun 
4098*4882a593Smuzhiyun 	ret = drv_reset_tid_config(sdata->local, sdata, &sta->sta, tids);
4099*4882a593Smuzhiyun 	mutex_unlock(&sdata->local->sta_mtx);
4100*4882a593Smuzhiyun 
4101*4882a593Smuzhiyun 	return ret;
4102*4882a593Smuzhiyun }
4103*4882a593Smuzhiyun 
4104*4882a593Smuzhiyun const struct cfg80211_ops mac80211_config_ops = {
4105*4882a593Smuzhiyun 	.add_virtual_intf = ieee80211_add_iface,
4106*4882a593Smuzhiyun 	.del_virtual_intf = ieee80211_del_iface,
4107*4882a593Smuzhiyun 	.change_virtual_intf = ieee80211_change_iface,
4108*4882a593Smuzhiyun 	.start_p2p_device = ieee80211_start_p2p_device,
4109*4882a593Smuzhiyun 	.stop_p2p_device = ieee80211_stop_p2p_device,
4110*4882a593Smuzhiyun 	.add_key = ieee80211_add_key,
4111*4882a593Smuzhiyun 	.del_key = ieee80211_del_key,
4112*4882a593Smuzhiyun 	.get_key = ieee80211_get_key,
4113*4882a593Smuzhiyun 	.set_default_key = ieee80211_config_default_key,
4114*4882a593Smuzhiyun 	.set_default_mgmt_key = ieee80211_config_default_mgmt_key,
4115*4882a593Smuzhiyun 	.set_default_beacon_key = ieee80211_config_default_beacon_key,
4116*4882a593Smuzhiyun 	.start_ap = ieee80211_start_ap,
4117*4882a593Smuzhiyun 	.change_beacon = ieee80211_change_beacon,
4118*4882a593Smuzhiyun 	.stop_ap = ieee80211_stop_ap,
4119*4882a593Smuzhiyun 	.add_station = ieee80211_add_station,
4120*4882a593Smuzhiyun 	.del_station = ieee80211_del_station,
4121*4882a593Smuzhiyun 	.change_station = ieee80211_change_station,
4122*4882a593Smuzhiyun 	.get_station = ieee80211_get_station,
4123*4882a593Smuzhiyun 	.dump_station = ieee80211_dump_station,
4124*4882a593Smuzhiyun 	.dump_survey = ieee80211_dump_survey,
4125*4882a593Smuzhiyun #ifdef CONFIG_MAC80211_MESH
4126*4882a593Smuzhiyun 	.add_mpath = ieee80211_add_mpath,
4127*4882a593Smuzhiyun 	.del_mpath = ieee80211_del_mpath,
4128*4882a593Smuzhiyun 	.change_mpath = ieee80211_change_mpath,
4129*4882a593Smuzhiyun 	.get_mpath = ieee80211_get_mpath,
4130*4882a593Smuzhiyun 	.dump_mpath = ieee80211_dump_mpath,
4131*4882a593Smuzhiyun 	.get_mpp = ieee80211_get_mpp,
4132*4882a593Smuzhiyun 	.dump_mpp = ieee80211_dump_mpp,
4133*4882a593Smuzhiyun 	.update_mesh_config = ieee80211_update_mesh_config,
4134*4882a593Smuzhiyun 	.get_mesh_config = ieee80211_get_mesh_config,
4135*4882a593Smuzhiyun 	.join_mesh = ieee80211_join_mesh,
4136*4882a593Smuzhiyun 	.leave_mesh = ieee80211_leave_mesh,
4137*4882a593Smuzhiyun #endif
4138*4882a593Smuzhiyun 	.join_ocb = ieee80211_join_ocb,
4139*4882a593Smuzhiyun 	.leave_ocb = ieee80211_leave_ocb,
4140*4882a593Smuzhiyun 	.change_bss = ieee80211_change_bss,
4141*4882a593Smuzhiyun 	.set_txq_params = ieee80211_set_txq_params,
4142*4882a593Smuzhiyun 	.set_monitor_channel = ieee80211_set_monitor_channel,
4143*4882a593Smuzhiyun 	.suspend = ieee80211_suspend,
4144*4882a593Smuzhiyun 	.resume = ieee80211_resume,
4145*4882a593Smuzhiyun 	.scan = ieee80211_scan,
4146*4882a593Smuzhiyun 	.abort_scan = ieee80211_abort_scan,
4147*4882a593Smuzhiyun 	.sched_scan_start = ieee80211_sched_scan_start,
4148*4882a593Smuzhiyun 	.sched_scan_stop = ieee80211_sched_scan_stop,
4149*4882a593Smuzhiyun 	.auth = ieee80211_auth,
4150*4882a593Smuzhiyun 	.assoc = ieee80211_assoc,
4151*4882a593Smuzhiyun 	.deauth = ieee80211_deauth,
4152*4882a593Smuzhiyun 	.disassoc = ieee80211_disassoc,
4153*4882a593Smuzhiyun 	.join_ibss = ieee80211_join_ibss,
4154*4882a593Smuzhiyun 	.leave_ibss = ieee80211_leave_ibss,
4155*4882a593Smuzhiyun 	.set_mcast_rate = ieee80211_set_mcast_rate,
4156*4882a593Smuzhiyun 	.set_wiphy_params = ieee80211_set_wiphy_params,
4157*4882a593Smuzhiyun 	.set_tx_power = ieee80211_set_tx_power,
4158*4882a593Smuzhiyun 	.get_tx_power = ieee80211_get_tx_power,
4159*4882a593Smuzhiyun 	.set_wds_peer = ieee80211_set_wds_peer,
4160*4882a593Smuzhiyun 	.rfkill_poll = ieee80211_rfkill_poll,
4161*4882a593Smuzhiyun 	CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
4162*4882a593Smuzhiyun 	CFG80211_TESTMODE_DUMP(ieee80211_testmode_dump)
4163*4882a593Smuzhiyun 	.set_power_mgmt = ieee80211_set_power_mgmt,
4164*4882a593Smuzhiyun 	.set_bitrate_mask = ieee80211_set_bitrate_mask,
4165*4882a593Smuzhiyun 	.remain_on_channel = ieee80211_remain_on_channel,
4166*4882a593Smuzhiyun 	.cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
4167*4882a593Smuzhiyun 	.mgmt_tx = ieee80211_mgmt_tx,
4168*4882a593Smuzhiyun 	.mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,
4169*4882a593Smuzhiyun 	.set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
4170*4882a593Smuzhiyun 	.set_cqm_rssi_range_config = ieee80211_set_cqm_rssi_range_config,
4171*4882a593Smuzhiyun 	.update_mgmt_frame_registrations =
4172*4882a593Smuzhiyun 		ieee80211_update_mgmt_frame_registrations,
4173*4882a593Smuzhiyun 	.set_antenna = ieee80211_set_antenna,
4174*4882a593Smuzhiyun 	.get_antenna = ieee80211_get_antenna,
4175*4882a593Smuzhiyun 	.set_rekey_data = ieee80211_set_rekey_data,
4176*4882a593Smuzhiyun 	.tdls_oper = ieee80211_tdls_oper,
4177*4882a593Smuzhiyun 	.tdls_mgmt = ieee80211_tdls_mgmt,
4178*4882a593Smuzhiyun 	.tdls_channel_switch = ieee80211_tdls_channel_switch,
4179*4882a593Smuzhiyun 	.tdls_cancel_channel_switch = ieee80211_tdls_cancel_channel_switch,
4180*4882a593Smuzhiyun 	.probe_client = ieee80211_probe_client,
4181*4882a593Smuzhiyun 	.set_noack_map = ieee80211_set_noack_map,
4182*4882a593Smuzhiyun #ifdef CONFIG_PM
4183*4882a593Smuzhiyun 	.set_wakeup = ieee80211_set_wakeup,
4184*4882a593Smuzhiyun #endif
4185*4882a593Smuzhiyun 	.get_channel = ieee80211_cfg_get_channel,
4186*4882a593Smuzhiyun 	.start_radar_detection = ieee80211_start_radar_detection,
4187*4882a593Smuzhiyun 	.end_cac = ieee80211_end_cac,
4188*4882a593Smuzhiyun 	.channel_switch = ieee80211_channel_switch,
4189*4882a593Smuzhiyun 	.set_qos_map = ieee80211_set_qos_map,
4190*4882a593Smuzhiyun 	.set_ap_chanwidth = ieee80211_set_ap_chanwidth,
4191*4882a593Smuzhiyun 	.add_tx_ts = ieee80211_add_tx_ts,
4192*4882a593Smuzhiyun 	.del_tx_ts = ieee80211_del_tx_ts,
4193*4882a593Smuzhiyun 	.start_nan = ieee80211_start_nan,
4194*4882a593Smuzhiyun 	.stop_nan = ieee80211_stop_nan,
4195*4882a593Smuzhiyun 	.nan_change_conf = ieee80211_nan_change_conf,
4196*4882a593Smuzhiyun 	.add_nan_func = ieee80211_add_nan_func,
4197*4882a593Smuzhiyun 	.del_nan_func = ieee80211_del_nan_func,
4198*4882a593Smuzhiyun 	.set_multicast_to_unicast = ieee80211_set_multicast_to_unicast,
4199*4882a593Smuzhiyun 	.tx_control_port = ieee80211_tx_control_port,
4200*4882a593Smuzhiyun 	.get_txq_stats = ieee80211_get_txq_stats,
4201*4882a593Smuzhiyun 	.get_ftm_responder_stats = ieee80211_get_ftm_responder_stats,
4202*4882a593Smuzhiyun 	.start_pmsr = ieee80211_start_pmsr,
4203*4882a593Smuzhiyun 	.abort_pmsr = ieee80211_abort_pmsr,
4204*4882a593Smuzhiyun 	.probe_mesh_link = ieee80211_probe_mesh_link,
4205*4882a593Smuzhiyun 	.set_tid_config = ieee80211_set_tid_config,
4206*4882a593Smuzhiyun 	.reset_tid_config = ieee80211_reset_tid_config,
4207*4882a593Smuzhiyun };
4208