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(¶ms, 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, ¶ms);
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, ¶ms->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 ¶ms->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 ¶ms->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, ¶ms->he_obss_pd,
1144*4882a593Smuzhiyun sizeof(struct ieee80211_he_obss_pd));
1145*4882a593Smuzhiyun memcpy(&sdata->vif.bss_conf.he_bss_color, ¶ms->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, ¶ms->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 ¶ms->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 ¶ms->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(¶ms->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, ¶ms->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(¶ms->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(¶ms->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, ¶ms->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, ¶ms->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