blob: 2e232b6e30cf7cf59941d48ec406c61554b7e10a [file] [log] [blame]
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001/*
Dedy Lanskyb94ee9e2017-02-23 15:53:29 +02002 * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08003 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
Vladimir Kondratieva82553bb2015-03-15 16:00:21 +020017#include <linux/etherdevice.h>
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080018#include "wil6210.h"
19#include "wmi.h"
Lior David8f1b5e02017-02-28 14:58:27 +020020#include "ftm.h"
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080021
Dedy Lanskye6d68342016-03-01 19:18:12 +020022#define WIL_MAX_ROC_DURATION_MS 5000
23
Dedy Lanskyb94ee9e2017-02-23 15:53:29 +020024bool disable_ap_sme;
Maya Erezc2256ec2017-02-08 13:18:42 +020025module_param(disable_ap_sme, bool, 0444);
Dedy Lanskyb94ee9e2017-02-23 15:53:29 +020026MODULE_PARM_DESC(disable_ap_sme, " let user space handle AP mode SME");
27
Lior Davidad9f6152017-05-03 15:11:10 +030028static bool ignore_reg_hints = true;
29module_param(ignore_reg_hints, bool, 0444);
30MODULE_PARM_DESC(ignore_reg_hints, " Ignore OTA regulatory hints (Default: true)");
31
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080032#define CHAN60G(_channel, _flags) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +020033 .band = NL80211_BAND_60GHZ, \
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -080034 .center_freq = 56160 + (2160 * (_channel)), \
35 .hw_value = (_channel), \
36 .flags = (_flags), \
37 .max_antenna_gain = 0, \
38 .max_power = 40, \
39}
40
41static struct ieee80211_channel wil_60ghz_channels[] = {
42 CHAN60G(1, 0),
43 CHAN60G(2, 0),
44 CHAN60G(3, 0),
45/* channel 4 not supported yet */
46};
47
Maya Erez603fd472017-07-19 16:03:51 +030048#ifdef CONFIG_PM
49static struct wiphy_wowlan_support wil_wowlan_support = {
50 .flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT,
51};
52#endif
53
Lior David8f1b5e02017-02-28 14:58:27 +020054/* Vendor id to be used in vendor specific command and events
55 * to user space.
56 * NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID,
57 * vendor subcmd definitions prefixed with QCA_NL80211_VENDOR_SUBCMD, and
58 * qca_wlan_vendor_attr is open source file src/common/qca-vendor.h in
59 * git://w1.fi/srv/git/hostap.git; the values here are just a copy of that
60 */
61
62#define QCA_NL80211_VENDOR_ID 0x001374
63
64enum qca_nl80211_vendor_subcmds {
65 QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA = 128,
66 QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION = 129,
67 QCA_NL80211_VENDOR_SUBCMD_FTM_ABORT_SESSION = 130,
68 QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT = 131,
69 QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE = 132,
70 QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER = 133,
71 QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS = 134,
72 QCA_NL80211_VENDOR_SUBCMD_AOA_ABORT_MEAS = 135,
73 QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT = 136,
74};
75
76/* vendor specific commands */
77static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = {
78 {
79 .info.vendor_id = QCA_NL80211_VENDOR_ID,
80 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA,
81 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
82 WIPHY_VENDOR_CMD_NEED_RUNNING,
83 .doit = wil_ftm_get_capabilities
84 },
85 {
86 .info.vendor_id = QCA_NL80211_VENDOR_ID,
87 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION,
88 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
89 WIPHY_VENDOR_CMD_NEED_RUNNING,
90 .doit = wil_ftm_start_session
91 },
92 {
93 .info.vendor_id = QCA_NL80211_VENDOR_ID,
94 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_FTM_ABORT_SESSION,
95 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
96 WIPHY_VENDOR_CMD_NEED_RUNNING,
97 .doit = wil_ftm_abort_session
98 },
99 {
100 .info.vendor_id = QCA_NL80211_VENDOR_ID,
101 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER,
102 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
103 WIPHY_VENDOR_CMD_NEED_RUNNING,
104 .doit = wil_ftm_configure_responder
105 },
106 {
107 .info.vendor_id = QCA_NL80211_VENDOR_ID,
108 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS,
109 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
110 WIPHY_VENDOR_CMD_NEED_RUNNING,
111 .doit = wil_aoa_start_measurement
112 },
113 {
114 .info.vendor_id = QCA_NL80211_VENDOR_ID,
115 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_AOA_ABORT_MEAS,
116 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
117 WIPHY_VENDOR_CMD_NEED_RUNNING,
118 .doit = wil_aoa_abort_measurement
119 },
120};
121
122/* vendor specific events */
123static const struct nl80211_vendor_cmd_info wil_nl80211_vendor_events[] = {
124 [QCA_NL80211_VENDOR_EVENT_FTM_MEAS_RESULT_INDEX] = {
125 .vendor_id = QCA_NL80211_VENDOR_ID,
126 .subcmd = QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT
127 },
128 [QCA_NL80211_VENDOR_EVENT_FTM_SESSION_DONE_INDEX] = {
129 .vendor_id = QCA_NL80211_VENDOR_ID,
130 .subcmd = QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE
131 },
132 [QCA_NL80211_VENDOR_EVENT_AOA_MEAS_RESULT_INDEX] = {
133 .vendor_id = QCA_NL80211_VENDOR_ID,
134 .subcmd = QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT
135 },
136};
137
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800138static struct ieee80211_supported_band wil_band_60ghz = {
139 .channels = wil_60ghz_channels,
140 .n_channels = ARRAY_SIZE(wil_60ghz_channels),
141 .ht_cap = {
142 .ht_supported = true,
143 .cap = 0, /* TODO */
144 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, /* TODO */
145 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, /* TODO */
146 .mcs = {
147 /* MCS 1..12 - SC PHY */
148 .rx_mask = {0xfe, 0x1f}, /* 1..12 */
149 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, /* TODO */
150 },
151 },
152};
153
154static const struct ieee80211_txrx_stypes
155wil_mgmt_stypes[NUM_NL80211_IFTYPES] = {
156 [NL80211_IFTYPE_STATION] = {
157 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
158 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
159 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
160 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
161 },
162 [NL80211_IFTYPE_AP] = {
163 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
Dedy Lanskyb94ee9e2017-02-23 15:53:29 +0200164 BIT(IEEE80211_STYPE_PROBE_RESP >> 4) |
165 BIT(IEEE80211_STYPE_ASSOC_RESP >> 4) |
166 BIT(IEEE80211_STYPE_DISASSOC >> 4),
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800167 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
Dedy Lanskyb94ee9e2017-02-23 15:53:29 +0200168 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
169 BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
170 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
171 BIT(IEEE80211_STYPE_AUTH >> 4) |
172 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
173 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4)
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800174 },
175 [NL80211_IFTYPE_P2P_CLIENT] = {
176 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
177 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
178 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
179 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
180 },
181 [NL80211_IFTYPE_P2P_GO] = {
182 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
183 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
184 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
185 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
186 },
Lior David4332cac2016-03-01 19:18:13 +0200187 [NL80211_IFTYPE_P2P_DEVICE] = {
188 .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
189 BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
190 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
191 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
192 },
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800193};
194
195static const u32 wil_cipher_suites[] = {
196 WLAN_CIPHER_SUITE_GCMP,
197};
198
Vladimir Kondratiev58527422016-03-01 19:18:07 +0200199static const char * const key_usage_str[] = {
200 [WMI_KEY_USE_PAIRWISE] = "PTK",
201 [WMI_KEY_USE_RX_GROUP] = "RX_GTK",
202 [WMI_KEY_USE_TX_GROUP] = "TX_GTK",
203};
204
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800205int wil_iftype_nl2wmi(enum nl80211_iftype type)
206{
207 static const struct {
208 enum nl80211_iftype nl;
209 enum wmi_network_type wmi;
210 } __nl2wmi[] = {
211 {NL80211_IFTYPE_ADHOC, WMI_NETTYPE_ADHOC},
212 {NL80211_IFTYPE_STATION, WMI_NETTYPE_INFRA},
213 {NL80211_IFTYPE_AP, WMI_NETTYPE_AP},
214 {NL80211_IFTYPE_P2P_CLIENT, WMI_NETTYPE_P2P},
215 {NL80211_IFTYPE_P2P_GO, WMI_NETTYPE_P2P},
216 {NL80211_IFTYPE_MONITOR, WMI_NETTYPE_ADHOC}, /* FIXME */
217 };
218 uint i;
219
220 for (i = 0; i < ARRAY_SIZE(__nl2wmi); i++) {
221 if (__nl2wmi[i].nl == type)
222 return __nl2wmi[i].wmi;
223 }
224
225 return -EOPNOTSUPP;
226}
227
Vladimir Kondratiev9eb82d42014-06-16 19:37:13 +0300228int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
229 struct station_info *sinfo)
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800230{
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800231 struct wmi_notify_req_cmd cmd = {
Vladimir Kondratiev3df2cd362014-02-27 16:20:43 +0200232 .cid = cid,
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800233 .interval_usec = 0,
234 };
Vladimir Kondratievef28afd2014-02-27 16:20:48 +0200235 struct {
Lior Davidb874dde2016-03-01 19:18:09 +0200236 struct wmi_cmd_hdr wmi;
Vladimir Kondratievef28afd2014-02-27 16:20:48 +0200237 struct wmi_notify_req_done_event evt;
238 } __packed reply;
Vladimir Kondratievc8b78b52014-02-27 16:20:49 +0200239 struct wil_net_stats *stats = &wil->sta[cid].stats;
Vladimir Kondratievef28afd2014-02-27 16:20:48 +0200240 int rc;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800241
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800242 rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
Vladimir Kondratievef28afd2014-02-27 16:20:48 +0200243 WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800244 if (rc)
245 return rc;
246
Vladimir Kondratievc8b78b52014-02-27 16:20:49 +0200247 wil_dbg_wmi(wil, "Link status for CID %d: {\n"
248 " MCS %d TSF 0x%016llx\n"
Vladimir Kondratievb8b33a32014-02-27 16:20:52 +0200249 " BF status 0x%08x SNR 0x%08x SQI %d%%\n"
Vladimir Kondratievc8b78b52014-02-27 16:20:49 +0200250 " Tx Tpt %d goodput %d Rx goodput %d\n"
251 " Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n",
252 cid, le16_to_cpu(reply.evt.bf_mcs),
253 le64_to_cpu(reply.evt.tsf), reply.evt.status,
254 le32_to_cpu(reply.evt.snr_val),
Vladimir Kondratievb8b33a32014-02-27 16:20:52 +0200255 reply.evt.sqi,
Vladimir Kondratievc8b78b52014-02-27 16:20:49 +0200256 le32_to_cpu(reply.evt.tx_tpt),
257 le32_to_cpu(reply.evt.tx_goodput),
258 le32_to_cpu(reply.evt.rx_goodput),
259 le16_to_cpu(reply.evt.my_rx_sector),
260 le16_to_cpu(reply.evt.my_tx_sector),
261 le16_to_cpu(reply.evt.other_rx_sector),
262 le16_to_cpu(reply.evt.other_tx_sector));
263
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800264 sinfo->generation = wil->sinfo_gen;
265
Johannes Berg319090b2014-11-17 14:08:11 +0100266 sinfo->filled = BIT(NL80211_STA_INFO_RX_BYTES) |
267 BIT(NL80211_STA_INFO_TX_BYTES) |
268 BIT(NL80211_STA_INFO_RX_PACKETS) |
269 BIT(NL80211_STA_INFO_TX_PACKETS) |
270 BIT(NL80211_STA_INFO_RX_BITRATE) |
271 BIT(NL80211_STA_INFO_TX_BITRATE) |
272 BIT(NL80211_STA_INFO_RX_DROP_MISC) |
273 BIT(NL80211_STA_INFO_TX_FAILED);
Vladimir Kondratievc8b78b52014-02-27 16:20:49 +0200274
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800275 sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
Vladimir Kondratievef28afd2014-02-27 16:20:48 +0200276 sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800277 sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
Vladimir Kondratievc8b78b52014-02-27 16:20:49 +0200278 sinfo->rxrate.mcs = stats->last_mcs_rx;
279 sinfo->rx_bytes = stats->rx_bytes;
280 sinfo->rx_packets = stats->rx_packets;
281 sinfo->rx_dropped_misc = stats->rx_dropped;
282 sinfo->tx_bytes = stats->tx_bytes;
283 sinfo->tx_packets = stats->tx_packets;
284 sinfo->tx_failed = stats->tx_errors;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800285
Vladimir Kondratiev9419b6a2014-12-23 09:47:14 +0200286 if (test_bit(wil_status_fwconnected, wil->status)) {
Johannes Berg319090b2014-11-17 14:08:11 +0100287 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
Vladimir Kondratievb8b33a32014-02-27 16:20:52 +0200288 sinfo->signal = reply.evt.sqi;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800289 }
290
Vladimir Kondratievef28afd2014-02-27 16:20:48 +0200291 return rc;
292}
293
294static int wil_cfg80211_get_station(struct wiphy *wiphy,
295 struct net_device *ndev,
Johannes Berg3b3a0162014-05-19 17:19:31 +0200296 const u8 *mac, struct station_info *sinfo)
Vladimir Kondratievef28afd2014-02-27 16:20:48 +0200297{
298 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
299 int rc;
300
301 int cid = wil_find_cid(wil, mac);
302
Lazar Alexei3190cc62017-02-23 14:34:14 +0200303 wil_dbg_misc(wil, "get_station: %pM CID %d\n", mac, cid);
Vladimir Kondratievef28afd2014-02-27 16:20:48 +0200304 if (cid < 0)
Vladimir Kondratievc14c5d92014-03-02 11:20:51 +0200305 return cid;
Vladimir Kondratievef28afd2014-02-27 16:20:48 +0200306
307 rc = wil_cid_fill_sinfo(wil, cid, sinfo);
308
309 return rc;
310}
311
312/*
313 * Find @idx-th active STA for station dump.
314 */
315static int wil_find_cid_by_idx(struct wil6210_priv *wil, int idx)
316{
317 int i;
318
319 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
320 if (wil->sta[i].status == wil_sta_unused)
321 continue;
322 if (idx == 0)
323 return i;
324 idx--;
325 }
326
327 return -ENOENT;
328}
329
330static int wil_cfg80211_dump_station(struct wiphy *wiphy,
331 struct net_device *dev, int idx,
332 u8 *mac, struct station_info *sinfo)
333{
334 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
335 int rc;
336 int cid = wil_find_cid_by_idx(wil, idx);
337
338 if (cid < 0)
339 return -ENOENT;
340
Vladimir Kondratieva82553bb2015-03-15 16:00:21 +0200341 ether_addr_copy(mac, wil->sta[cid].addr);
Lazar Alexei3190cc62017-02-23 14:34:14 +0200342 wil_dbg_misc(wil, "dump_station: %pM CID %d\n", mac, cid);
Vladimir Kondratievef28afd2014-02-27 16:20:48 +0200343
344 rc = wil_cid_fill_sinfo(wil, cid, sinfo);
345
346 return rc;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800347}
348
Lior David4332cac2016-03-01 19:18:13 +0200349static struct wireless_dev *
350wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name,
351 unsigned char name_assign_type,
352 enum nl80211_iftype type,
353 u32 *flags, struct vif_params *params)
354{
355 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
356 struct net_device *ndev = wil_to_ndev(wil);
357 struct wireless_dev *p2p_wdev;
358
Lazar Alexei3190cc62017-02-23 14:34:14 +0200359 wil_dbg_misc(wil, "add_iface\n");
Lior David4332cac2016-03-01 19:18:13 +0200360
361 if (type != NL80211_IFTYPE_P2P_DEVICE) {
Lazar Alexei3190cc62017-02-23 14:34:14 +0200362 wil_err(wil, "unsupported iftype %d\n", type);
Lior David4332cac2016-03-01 19:18:13 +0200363 return ERR_PTR(-EINVAL);
364 }
365
366 if (wil->p2p_wdev) {
Lazar Alexei3190cc62017-02-23 14:34:14 +0200367 wil_err(wil, "P2P_DEVICE interface already created\n");
Lior David4332cac2016-03-01 19:18:13 +0200368 return ERR_PTR(-EINVAL);
369 }
370
371 p2p_wdev = kzalloc(sizeof(*p2p_wdev), GFP_KERNEL);
372 if (!p2p_wdev)
373 return ERR_PTR(-ENOMEM);
374
375 p2p_wdev->iftype = type;
376 p2p_wdev->wiphy = wiphy;
377 /* use our primary ethernet address */
378 ether_addr_copy(p2p_wdev->address, ndev->perm_addr);
379
380 wil->p2p_wdev = p2p_wdev;
381
382 return p2p_wdev;
383}
384
385static int wil_cfg80211_del_iface(struct wiphy *wiphy,
386 struct wireless_dev *wdev)
387{
388 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
389
Lazar Alexei3190cc62017-02-23 14:34:14 +0200390 wil_dbg_misc(wil, "del_iface\n");
Lior David4332cac2016-03-01 19:18:13 +0200391
392 if (wdev != wil->p2p_wdev) {
Lazar Alexei3190cc62017-02-23 14:34:14 +0200393 wil_err(wil, "delete of incorrect interface 0x%p\n", wdev);
Lior David4332cac2016-03-01 19:18:13 +0200394 return -EINVAL;
395 }
396
397 wil_p2p_wdev_free(wil);
398
399 return 0;
400}
401
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800402static int wil_cfg80211_change_iface(struct wiphy *wiphy,
403 struct net_device *ndev,
404 enum nl80211_iftype type, u32 *flags,
405 struct vif_params *params)
406{
407 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
Lior David4332cac2016-03-01 19:18:13 +0200408 struct wireless_dev *wdev = wil_to_wdev(wil);
Dedy Lanskye6d68342016-03-01 19:18:12 +0200409 int rc;
410
Lazar Alexei3190cc62017-02-23 14:34:14 +0200411 wil_dbg_misc(wil, "change_iface: type=%d\n", type);
Dedy Lanskye6d68342016-03-01 19:18:12 +0200412
Lior David375a1732016-03-01 19:18:16 +0200413 if (netif_running(wil_to_ndev(wil)) && !wil_is_recovery_blocked(wil)) {
Dedy Lanskye6d68342016-03-01 19:18:12 +0200414 wil_dbg_misc(wil, "interface is up. resetting...\n");
415 mutex_lock(&wil->mutex);
416 __wil_down(wil);
417 rc = __wil_up(wil);
418 mutex_unlock(&wil->mutex);
419
420 if (rc)
421 return rc;
422 }
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800423
424 switch (type) {
425 case NL80211_IFTYPE_STATION:
426 case NL80211_IFTYPE_AP:
427 case NL80211_IFTYPE_P2P_CLIENT:
428 case NL80211_IFTYPE_P2P_GO:
429 break;
430 case NL80211_IFTYPE_MONITOR:
431 if (flags)
432 wil->monitor_flags = *flags;
433 else
434 wil->monitor_flags = 0;
435
436 break;
437 default:
438 return -EOPNOTSUPP;
439 }
440
441 wdev->iftype = type;
442
443 return 0;
444}
445
446static int wil_cfg80211_scan(struct wiphy *wiphy,
447 struct cfg80211_scan_request *request)
448{
449 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
Lior David4332cac2016-03-01 19:18:13 +0200450 struct wireless_dev *wdev = request->wdev;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800451 struct {
452 struct wmi_start_scan_cmd cmd;
453 u16 chnl[4];
454 } __packed cmd;
455 uint i, n;
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200456 int rc;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800457
Lazar Alexei3190cc62017-02-23 14:34:14 +0200458 wil_dbg_misc(wil, "scan: wdev=0x%p iftype=%d\n", wdev, wdev->iftype);
Dedy Lanskye6d68342016-03-01 19:18:12 +0200459
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800460 /* check we are client side */
461 switch (wdev->iftype) {
462 case NL80211_IFTYPE_STATION:
463 case NL80211_IFTYPE_P2P_CLIENT:
Lior David4332cac2016-03-01 19:18:13 +0200464 case NL80211_IFTYPE_P2P_DEVICE:
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800465 break;
466 default:
467 return -EOPNOTSUPP;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800468 }
469
470 /* FW don't support scan after connection attempt */
Vladimir Kondratiev9419b6a2014-12-23 09:47:14 +0200471 if (test_bit(wil_status_dontscan, wil->status)) {
Vladimir Kondratieve83eb2f2014-03-17 15:34:07 +0200472 wil_err(wil, "Can't scan now\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800473 return -EBUSY;
474 }
475
Lior David42ba1c222017-02-15 20:37:20 +0200476 mutex_lock(&wil->mutex);
477
478 mutex_lock(&wil->p2p_wdev_mutex);
479 if (wil->scan_request || wil->p2p.discovery_started) {
480 wil_err(wil, "Already scanning\n");
481 mutex_unlock(&wil->p2p_wdev_mutex);
482 rc = -EAGAIN;
483 goto out;
484 }
485 mutex_unlock(&wil->p2p_wdev_mutex);
486
Lior David1aaa3242017-03-27 21:10:35 +0300487 if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
Lior Davideb57a5b2016-06-08 20:07:48 +0300488 if (!wil->p2p.p2p_dev_started) {
489 wil_err(wil, "P2P search requested on stopped P2P device\n");
Lior David42ba1c222017-02-15 20:37:20 +0200490 rc = -EIO;
491 goto out;
Lior Davideb57a5b2016-06-08 20:07:48 +0300492 }
Lior David1aaa3242017-03-27 21:10:35 +0300493 /* social scan on P2P_DEVICE is handled as p2p search */
494 if (wil_p2p_is_social_scan(request)) {
495 wil->scan_request = request;
496 wil->radio_wdev = wdev;
497 rc = wil_p2p_search(wil, request);
498 if (rc) {
499 wil->radio_wdev = wil_to_wdev(wil);
500 wil->scan_request = NULL;
501 }
502 goto out;
Lior David4332cac2016-03-01 19:18:13 +0200503 }
Dedy Lanskye6d68342016-03-01 19:18:12 +0200504 }
505
Lior David280ab982016-03-01 19:18:14 +0200506 (void)wil_p2p_stop_discovery(wil);
Dedy Lanskye6d68342016-03-01 19:18:12 +0200507
Vladimir Kondratiev2a91d7d2014-06-16 19:37:11 +0300508 wil_dbg_misc(wil, "Start scan_request 0x%p\n", request);
Hamad Kadmany8e52fe32015-06-09 14:11:18 +0300509 wil_dbg_misc(wil, "SSID count: %d", request->n_ssids);
510
511 for (i = 0; i < request->n_ssids; i++) {
512 wil_dbg_misc(wil, "SSID[%d]", i);
Dedy Lanskyc198fc22017-03-27 21:14:41 +0300513 wil_hex_dump_misc("SSID ", DUMP_PREFIX_OFFSET, 16, 1,
514 request->ssids[i].ssid,
515 request->ssids[i].ssid_len, true);
Hamad Kadmany8e52fe32015-06-09 14:11:18 +0300516 }
517
518 if (request->n_ssids)
519 rc = wmi_set_ssid(wil, request->ssids[0].ssid_len,
520 request->ssids[0].ssid);
521 else
522 rc = wmi_set_ssid(wil, 0, NULL);
523
524 if (rc) {
525 wil_err(wil, "set SSID for scan request failed: %d\n", rc);
Lior David42ba1c222017-02-15 20:37:20 +0200526 goto out;
Hamad Kadmany8e52fe32015-06-09 14:11:18 +0300527 }
528
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800529 wil->scan_request = request;
Vladimir Kondratiev047e5d72014-05-27 14:45:48 +0300530 mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800531
532 memset(&cmd, 0, sizeof(cmd));
Lior David74997a52016-03-01 19:18:08 +0200533 cmd.cmd.scan_type = WMI_ACTIVE_SCAN;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800534 cmd.cmd.num_channels = 0;
535 n = min(request->n_channels, 4U);
536 for (i = 0; i < n; i++) {
537 int ch = request->channels[i]->hw_value;
Vladimir Kondratiev8fe59622014-09-10 16:34:34 +0300538
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800539 if (ch == 0) {
540 wil_err(wil,
541 "Scan requested for unknown frequency %dMhz\n",
542 request->channels[i]->center_freq);
543 continue;
544 }
545 /* 0-based channel indexes */
546 cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1;
Vladimir Kondratiev77438822013-01-28 18:31:06 +0200547 wil_dbg_misc(wil, "Scan for ch %d : %d MHz\n", ch,
Vladimir Kondratiev2057ebb2013-01-28 18:30:58 +0200548 request->channels[i]->center_freq);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800549 }
550
Vladimir Kondratiev77c91292014-09-10 16:34:47 +0300551 if (request->ie_len)
Dedy Lanskyc198fc22017-03-27 21:14:41 +0300552 wil_hex_dump_misc("Scan IE ", DUMP_PREFIX_OFFSET, 16, 1,
553 request->ie, request->ie_len, true);
Vladimir Kondratiev77c91292014-09-10 16:34:47 +0300554 else
555 wil_dbg_misc(wil, "Scan has no IE's\n");
556
Vladimir Kondratiev5421bf02015-07-30 13:52:00 +0300557 rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, request->ie);
558 if (rc)
Lior David42ba1c222017-02-15 20:37:20 +0200559 goto out_restore;
Vladimir Kondratiev77c91292014-09-10 16:34:47 +0300560
Lior David74997a52016-03-01 19:18:08 +0200561 if (wil->discovery_mode && cmd.cmd.scan_type == WMI_ACTIVE_SCAN) {
562 cmd.cmd.discovery_mode = 1;
563 wil_dbg_misc(wil, "active scan with discovery_mode=1\n");
564 }
565
Lior David4332cac2016-03-01 19:18:13 +0200566 wil->radio_wdev = wdev;
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200567 rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800568 cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200569
Lior David42ba1c222017-02-15 20:37:20 +0200570out_restore:
Vladimir Kondratieva2142082014-08-06 10:31:57 +0300571 if (rc) {
572 del_timer_sync(&wil->scan_timer);
Lior David4332cac2016-03-01 19:18:13 +0200573 wil->radio_wdev = wil_to_wdev(wil);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200574 wil->scan_request = NULL;
Vladimir Kondratieva2142082014-08-06 10:31:57 +0300575 }
Lior David42ba1c222017-02-15 20:37:20 +0200576out:
577 mutex_unlock(&wil->mutex);
Vladimir Kondratieved6f9dc2014-03-17 15:34:19 +0200578 return rc;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800579}
580
Maya Erez4cbb5852017-02-16 15:26:09 +0200581static void wil_cfg80211_abort_scan(struct wiphy *wiphy,
582 struct wireless_dev *wdev)
583{
584 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
585
586 wil_dbg_misc(wil, "wdev=0x%p iftype=%d\n", wdev, wdev->iftype);
587
588 mutex_lock(&wil->mutex);
589 mutex_lock(&wil->p2p_wdev_mutex);
590
591 if (!wil->scan_request)
592 goto out;
593
594 if (wdev != wil->scan_request->wdev) {
595 wil_dbg_misc(wil, "abort scan was called on the wrong iface\n");
596 goto out;
597 }
598
599 if (wil->radio_wdev == wil->p2p_wdev)
600 wil_p2p_stop_radio_operations(wil);
601 else
602 wil_abort_scan(wil, true);
603
604out:
605 mutex_unlock(&wil->p2p_wdev_mutex);
606 mutex_unlock(&wil->mutex);
607}
608
Vladimir Kondratievfeeac222015-02-01 10:55:15 +0200609static void wil_print_crypto(struct wil6210_priv *wil,
610 struct cfg80211_crypto_settings *c)
611{
612 int i, n;
613
614 wil_dbg_misc(wil, "WPA versions: 0x%08x cipher group 0x%08x\n",
615 c->wpa_versions, c->cipher_group);
616 wil_dbg_misc(wil, "Pairwise ciphers [%d] {\n", c->n_ciphers_pairwise);
617 n = min_t(int, c->n_ciphers_pairwise, ARRAY_SIZE(c->ciphers_pairwise));
618 for (i = 0; i < n; i++)
619 wil_dbg_misc(wil, " [%d] = 0x%08x\n", i,
620 c->ciphers_pairwise[i]);
621 wil_dbg_misc(wil, "}\n");
622 wil_dbg_misc(wil, "AKM suites [%d] {\n", c->n_akm_suites);
623 n = min_t(int, c->n_akm_suites, ARRAY_SIZE(c->akm_suites));
624 for (i = 0; i < n; i++)
625 wil_dbg_misc(wil, " [%d] = 0x%08x\n", i,
626 c->akm_suites[i]);
627 wil_dbg_misc(wil, "}\n");
628 wil_dbg_misc(wil, "Control port : %d, eth_type 0x%04x no_encrypt %d\n",
629 c->control_port, be16_to_cpu(c->control_port_ethertype),
630 c->control_port_no_encrypt);
631}
632
Vladimir Kondratiev8ca26162014-09-10 16:34:32 +0300633static void wil_print_connect_params(struct wil6210_priv *wil,
634 struct cfg80211_connect_params *sme)
635{
636 wil_info(wil, "Connecting to:\n");
637 if (sme->channel) {
638 wil_info(wil, " Channel: %d freq %d\n",
639 sme->channel->hw_value, sme->channel->center_freq);
640 }
641 if (sme->bssid)
642 wil_info(wil, " BSSID: %pM\n", sme->bssid);
643 if (sme->ssid)
644 print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET,
645 16, 1, sme->ssid, sme->ssid_len, true);
646 wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open");
Lior Davideabb03b2016-03-01 19:18:10 +0200647 wil_info(wil, " PBSS: %d\n", sme->pbss);
Vladimir Kondratievfeeac222015-02-01 10:55:15 +0200648 wil_print_crypto(wil, &sme->crypto);
Vladimir Kondratiev8ca26162014-09-10 16:34:32 +0300649}
650
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800651static int wil_cfg80211_connect(struct wiphy *wiphy,
652 struct net_device *ndev,
653 struct cfg80211_connect_params *sme)
654{
655 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
656 struct cfg80211_bss *bss;
657 struct wmi_connect_cmd conn;
658 const u8 *ssid_eid;
659 const u8 *rsn_eid;
660 int ch;
661 int rc = 0;
Lior Davideabb03b2016-03-01 19:18:10 +0200662 enum ieee80211_bss_type bss_type = IEEE80211_BSS_TYPE_ESS;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800663
Lazar Alexei3190cc62017-02-23 14:34:14 +0200664 wil_dbg_misc(wil, "connect\n");
Vladimir Kondratiev344a7022015-02-15 14:02:37 +0200665 wil_print_connect_params(wil, sme);
666
Vladimir Kondratiev9419b6a2014-12-23 09:47:14 +0200667 if (test_bit(wil_status_fwconnecting, wil->status) ||
668 test_bit(wil_status_fwconnected, wil->status))
Vladimir Kondratiev4cd9e832014-03-17 15:34:20 +0200669 return -EALREADY;
670
Vladimir Kondratiev344a7022015-02-15 14:02:37 +0200671 if (sme->ie_len > WMI_MAX_IE_LEN) {
672 wil_err(wil, "IE too large (%td bytes)\n", sme->ie_len);
673 return -ERANGE;
674 }
675
676 rsn_eid = sme->ie ?
677 cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
678 NULL;
Vladimir Kondratiev27aa6b72015-04-30 16:25:11 +0300679 if (sme->privacy && !rsn_eid)
680 wil_info(wil, "WSC connection\n");
Vladimir Kondratiev8ca26162014-09-10 16:34:32 +0300681
Lior Davideabb03b2016-03-01 19:18:10 +0200682 if (sme->pbss)
683 bss_type = IEEE80211_BSS_TYPE_PBSS;
Lior David34d50512016-01-28 10:58:25 +0200684
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800685 bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
686 sme->ssid, sme->ssid_len,
Lior Davideabb03b2016-03-01 19:18:10 +0200687 bss_type, IEEE80211_PRIVACY_ANY);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800688 if (!bss) {
689 wil_err(wil, "Unable to find BSS\n");
690 return -ENOENT;
691 }
692
693 ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
694 if (!ssid_eid) {
695 wil_err(wil, "No SSID\n");
696 rc = -ENOENT;
697 goto out;
698 }
Vladimir Kondratiev344a7022015-02-15 14:02:37 +0200699 wil->privacy = sme->privacy;
Lior Davidb1c0bbf2017-02-08 13:14:13 +0200700 wil->pbss = sme->pbss;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800701
Vladimir Kondratiev344a7022015-02-15 14:02:37 +0200702 if (wil->privacy) {
Vladimir Kondratiev230d8442015-04-30 16:25:10 +0300703 /* For secure assoc, remove old keys */
704 rc = wmi_del_cipher_key(wil, 0, bss->bssid,
705 WMI_KEY_USE_PAIRWISE);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800706 if (rc) {
Vladimir Kondratiev230d8442015-04-30 16:25:10 +0300707 wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(PTK) failed\n");
708 goto out;
709 }
710 rc = wmi_del_cipher_key(wil, 0, bss->bssid,
711 WMI_KEY_USE_RX_GROUP);
712 if (rc) {
713 wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(GTK) failed\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800714 goto out;
715 }
Vladimir Kondratievac4acdb2014-09-10 16:34:43 +0300716 }
717
718 /* WMI_SET_APPIE_CMD. ie may contain rsn info as well as other info
719 * elements. Send it also in case it's empty, to erase previously set
720 * ies in FW.
721 */
722 rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
Vladimir Kondratiev5421bf02015-07-30 13:52:00 +0300723 if (rc)
Vladimir Kondratievac4acdb2014-09-10 16:34:43 +0300724 goto out;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800725
726 /* WMI_CONNECT_CMD */
727 memset(&conn, 0, sizeof(conn));
Vladimir Kondratievacc97802013-03-13 14:12:47 +0200728 switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) {
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800729 case WLAN_CAPABILITY_DMG_TYPE_AP:
730 conn.network_type = WMI_NETTYPE_INFRA;
731 break;
732 case WLAN_CAPABILITY_DMG_TYPE_PBSS:
733 conn.network_type = WMI_NETTYPE_P2P;
734 break;
735 default:
736 wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n",
737 bss->capability);
738 goto out;
739 }
Vladimir Kondratiev344a7022015-02-15 14:02:37 +0200740 if (wil->privacy) {
Vladimir Kondratiev27aa6b72015-04-30 16:25:11 +0300741 if (rsn_eid) { /* regular secure connection */
742 conn.dot11_auth_mode = WMI_AUTH11_SHARED;
743 conn.auth_mode = WMI_AUTH_WPA2_PSK;
744 conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP;
745 conn.pairwise_crypto_len = 16;
746 conn.group_crypto_type = WMI_CRYPT_AES_GCMP;
747 conn.group_crypto_len = 16;
748 } else { /* WSC */
749 conn.dot11_auth_mode = WMI_AUTH11_WSC;
750 conn.auth_mode = WMI_AUTH_NONE;
751 }
752 } else { /* insecure connection */
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800753 conn.dot11_auth_mode = WMI_AUTH11_OPEN;
754 conn.auth_mode = WMI_AUTH_NONE;
755 }
756
757 conn.ssid_len = min_t(u8, ssid_eid[1], 32);
758 memcpy(conn.ssid, ssid_eid+2, conn.ssid_len);
759
760 ch = bss->channel->hw_value;
761 if (ch == 0) {
762 wil_err(wil, "BSS at unknown frequency %dMhz\n",
763 bss->channel->center_freq);
764 rc = -EOPNOTSUPP;
765 goto out;
766 }
767 conn.channel = ch - 1;
768
Vladimir Kondratieva82553bb2015-03-15 16:00:21 +0200769 ether_addr_copy(conn.bssid, bss->bssid);
770 ether_addr_copy(conn.dst_mac, bss->bssid);
Vladimir Kondratieve83eb2f2014-03-17 15:34:07 +0200771
Vladimir Kondratiev9419b6a2014-12-23 09:47:14 +0200772 set_bit(wil_status_fwconnecting, wil->status);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800773
774 rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn));
775 if (rc == 0) {
Dedy Lanskyc5e96c92015-01-25 10:52:43 +0200776 netif_carrier_on(ndev);
Lior David704099f2017-05-04 21:31:02 +0300777 wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
Dedy Lanskya4882782017-05-04 21:36:09 +0300778 wil->bss = bss;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800779 /* Connect can take lots of time */
780 mod_timer(&wil->connect_timer,
781 jiffies + msecs_to_jiffies(2000));
Vladimir Kondratievb338f742013-05-28 15:17:53 +0300782 } else {
Vladimir Kondratiev9419b6a2014-12-23 09:47:14 +0200783 clear_bit(wil_status_fwconnecting, wil->status);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800784 }
785
786 out:
Johannes Berg5b112d32013-02-01 01:49:58 +0100787 cfg80211_put_bss(wiphy, bss);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800788
789 return rc;
790}
791
792static int wil_cfg80211_disconnect(struct wiphy *wiphy,
793 struct net_device *ndev,
794 u16 reason_code)
795{
796 int rc;
797 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
798
Lazar Alexei3190cc62017-02-23 14:34:14 +0200799 wil_dbg_misc(wil, "disconnect: reason=%d\n", reason_code);
Vladimir Kondratievde9084e2015-03-30 11:28:52 +0300800
Vladimir Kondratiev78771d72016-01-28 19:24:03 +0200801 if (!(test_bit(wil_status_fwconnecting, wil->status) ||
802 test_bit(wil_status_fwconnected, wil->status))) {
Lazar Alexei3190cc62017-02-23 14:34:14 +0200803 wil_err(wil, "Disconnect was called while disconnected\n");
Vladimir Kondratiev78771d72016-01-28 19:24:03 +0200804 return 0;
805 }
806
Dedy Lansky0a4e9d12017-03-27 21:21:31 +0300807 wil->locally_generated_disc = true;
Vladimir Kondratiev78771d72016-01-28 19:24:03 +0200808 rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0,
809 WMI_DISCONNECT_EVENTID, NULL, 0,
810 WIL6210_DISCONNECT_TO_MS);
811 if (rc)
Lazar Alexei3190cc62017-02-23 14:34:14 +0200812 wil_err(wil, "disconnect error %d\n", rc);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800813
814 return rc;
815}
816
Lior Davidde21eba2017-02-15 20:33:10 +0200817static int wil_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
818{
819 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
820 int rc;
821
822 /* these parameters are explicitly not supported */
823 if (changed & (WIPHY_PARAM_RETRY_LONG |
824 WIPHY_PARAM_FRAG_THRESHOLD |
825 WIPHY_PARAM_RTS_THRESHOLD))
826 return -ENOTSUPP;
827
828 if (changed & WIPHY_PARAM_RETRY_SHORT) {
829 rc = wmi_set_mgmt_retry(wil, wiphy->retry_short);
830 if (rc)
831 return rc;
832 }
833
834 return 0;
835}
836
Vladimir Kondratiev0b39aaf2014-06-16 19:36:59 +0300837int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
838 struct cfg80211_mgmt_tx_params *params,
839 u64 *cookie)
Vladimir Kondratiev1647f122014-02-27 16:20:40 +0200840{
841 const u8 *buf = params->buf;
842 size_t len = params->len;
843 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
844 int rc;
Vladimir Kondratiev304464f2014-06-16 19:37:00 +0300845 bool tx_status = false;
Vladimir Kondratiev1647f122014-02-27 16:20:40 +0200846 struct ieee80211_mgmt *mgmt_frame = (void *)buf;
847 struct wmi_sw_tx_req_cmd *cmd;
848 struct {
Lior Davidb874dde2016-03-01 19:18:09 +0200849 struct wmi_cmd_hdr wmi;
Vladimir Kondratiev1647f122014-02-27 16:20:40 +0200850 struct wmi_sw_tx_complete_event evt;
851 } __packed evt;
852
Dedy Lanskye6d68342016-03-01 19:18:12 +0200853 /* Note, currently we do not support the "wait" parameter, user-space
854 * must call remain_on_channel before mgmt_tx or listen on a channel
855 * another way (AP/PCP or connected station)
856 * in addition we need to check if specified "chan" argument is
857 * different from currently "listened" channel and fail if it is.
858 */
859
Lazar Alexei3190cc62017-02-23 14:34:14 +0200860 wil_dbg_misc(wil, "mgmt_tx\n");
Dedy Lanskyc198fc22017-03-27 21:14:41 +0300861 wil_hex_dump_misc("mgmt tx frame ", DUMP_PREFIX_OFFSET, 16, 1, buf,
862 len, true);
Dedy Lanskye6d68342016-03-01 19:18:12 +0200863
Vladimir Kondratiev1647f122014-02-27 16:20:40 +0200864 cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
Vladimir Kondratiev304464f2014-06-16 19:37:00 +0300865 if (!cmd) {
866 rc = -ENOMEM;
867 goto out;
868 }
Vladimir Kondratiev1647f122014-02-27 16:20:40 +0200869
870 memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN);
871 cmd->len = cpu_to_le16(len);
872 memcpy(cmd->payload, buf, len);
873
874 rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len,
875 WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
876 if (rc == 0)
Vladimir Kondratiev304464f2014-06-16 19:37:00 +0300877 tx_status = !evt.evt.status;
Vladimir Kondratiev1647f122014-02-27 16:20:40 +0200878
879 kfree(cmd);
Vladimir Kondratiev304464f2014-06-16 19:37:00 +0300880 out:
881 cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len,
882 tx_status, GFP_KERNEL);
Vladimir Kondratiev1647f122014-02-27 16:20:40 +0200883 return rc;
884}
885
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800886static int wil_cfg80211_set_channel(struct wiphy *wiphy,
887 struct cfg80211_chan_def *chandef)
888{
889 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
Lior David4332cac2016-03-01 19:18:13 +0200890 struct wireless_dev *wdev = wil_to_wdev(wil);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -0800891
892 wdev->preset_chandef = *chandef;
893
894 return 0;
895}
896
Vladimir Kondratiev230d8442015-04-30 16:25:10 +0300897static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil,
898 bool pairwise)
899{
Lior David4332cac2016-03-01 19:18:13 +0200900 struct wireless_dev *wdev = wil_to_wdev(wil);
Vladimir Kondratiev230d8442015-04-30 16:25:10 +0300901 enum wmi_key_usage rc;
Vladimir Kondratiev230d8442015-04-30 16:25:10 +0300902
903 if (pairwise) {
904 rc = WMI_KEY_USE_PAIRWISE;
905 } else {
906 switch (wdev->iftype) {
907 case NL80211_IFTYPE_STATION:
Dedy Lanskye6d68342016-03-01 19:18:12 +0200908 case NL80211_IFTYPE_P2P_CLIENT:
Vladimir Kondratiev230d8442015-04-30 16:25:10 +0300909 rc = WMI_KEY_USE_RX_GROUP;
910 break;
911 case NL80211_IFTYPE_AP:
Dedy Lanskye6d68342016-03-01 19:18:12 +0200912 case NL80211_IFTYPE_P2P_GO:
Vladimir Kondratiev230d8442015-04-30 16:25:10 +0300913 rc = WMI_KEY_USE_TX_GROUP;
914 break;
915 default:
916 /* TODO: Rx GTK or Tx GTK? */
917 wil_err(wil, "Can't determine GTK type\n");
918 rc = WMI_KEY_USE_RX_GROUP;
919 break;
920 }
921 }
Lazar Alexei3190cc62017-02-23 14:34:14 +0200922 wil_dbg_misc(wil, "detect_key_usage: -> %s\n", key_usage_str[rc]);
Vladimir Kondratiev230d8442015-04-30 16:25:10 +0300923
924 return rc;
925}
926
Maya Erez74b6ac52016-08-18 16:52:12 +0300927static struct wil_sta_info *
928wil_find_sta_by_key_usage(struct wil6210_priv *wil,
929 enum wmi_key_usage key_usage, const u8 *mac_addr)
Vladimir Kondratiev58527422016-03-01 19:18:07 +0200930{
931 int cid = -EINVAL;
Vladimir Kondratiev58527422016-03-01 19:18:07 +0200932
933 if (key_usage == WMI_KEY_USE_TX_GROUP)
934 return NULL; /* not needed */
935
936 /* supplicant provides Rx group key in STA mode with NULL MAC address */
937 if (mac_addr)
938 cid = wil_find_cid(wil, mac_addr);
939 else if (key_usage == WMI_KEY_USE_RX_GROUP)
940 cid = wil_find_cid_by_idx(wil, 0);
941 if (cid < 0) {
Maya Erez74b6ac52016-08-18 16:52:12 +0300942 wil_err(wil, "No CID for %pM %s\n", mac_addr,
943 key_usage_str[key_usage]);
Vladimir Kondratiev58527422016-03-01 19:18:07 +0200944 return ERR_PTR(cid);
945 }
946
Maya Erez74b6ac52016-08-18 16:52:12 +0300947 return &wil->sta[cid];
948}
Vladimir Kondratiev58527422016-03-01 19:18:07 +0200949
Maya Erez74b6ac52016-08-18 16:52:12 +0300950static void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage,
951 struct wil_sta_info *cs,
952 struct key_params *params)
953{
954 struct wil_tid_crypto_rx_single *cc;
955 int tid;
956
957 if (!cs)
958 return;
959
960 switch (key_usage) {
961 case WMI_KEY_USE_PAIRWISE:
962 for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
963 cc = &cs->tid_crypto_rx[tid].key_id[key_index];
964 if (params->seq)
965 memcpy(cc->pn, params->seq,
966 IEEE80211_GCMP_PN_LEN);
967 else
968 memset(cc->pn, 0, IEEE80211_GCMP_PN_LEN);
969 cc->key_set = true;
970 }
971 break;
972 case WMI_KEY_USE_RX_GROUP:
973 cc = &cs->group_crypto_rx.key_id[key_index];
974 if (params->seq)
975 memcpy(cc->pn, params->seq, IEEE80211_GCMP_PN_LEN);
976 else
977 memset(cc->pn, 0, IEEE80211_GCMP_PN_LEN);
978 cc->key_set = true;
979 break;
980 default:
981 break;
982 }
983}
984
985static void wil_del_rx_key(u8 key_index, enum wmi_key_usage key_usage,
986 struct wil_sta_info *cs)
987{
988 struct wil_tid_crypto_rx_single *cc;
989 int tid;
990
991 if (!cs)
992 return;
993
994 switch (key_usage) {
995 case WMI_KEY_USE_PAIRWISE:
996 for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
997 cc = &cs->tid_crypto_rx[tid].key_id[key_index];
998 cc->key_set = false;
999 }
1000 break;
1001 case WMI_KEY_USE_RX_GROUP:
1002 cc = &cs->group_crypto_rx.key_id[key_index];
1003 cc->key_set = false;
1004 break;
1005 default:
1006 break;
1007 }
Vladimir Kondratiev58527422016-03-01 19:18:07 +02001008}
1009
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001010static int wil_cfg80211_add_key(struct wiphy *wiphy,
1011 struct net_device *ndev,
1012 u8 key_index, bool pairwise,
1013 const u8 *mac_addr,
1014 struct key_params *params)
1015{
Vladimir Kondratiev58527422016-03-01 19:18:07 +02001016 int rc;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001017 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
Vladimir Kondratiev230d8442015-04-30 16:25:10 +03001018 enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);
Maya Erez74b6ac52016-08-18 16:52:12 +03001019 struct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, key_usage,
1020 mac_addr);
1021
1022 if (!params) {
1023 wil_err(wil, "NULL params\n");
1024 return -EINVAL;
1025 }
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001026
Lazar Alexei3190cc62017-02-23 14:34:14 +02001027 wil_dbg_misc(wil, "add_key: %pM %s[%d] PN %*phN\n",
Vladimir Kondratiev58527422016-03-01 19:18:07 +02001028 mac_addr, key_usage_str[key_usage], key_index,
1029 params->seq_len, params->seq);
Vladimir Kondratievdb8adcb2015-03-30 11:28:51 +03001030
Maya Erez74b6ac52016-08-18 16:52:12 +03001031 if (IS_ERR(cs)) {
Lazar Alexei3190cc62017-02-23 14:34:14 +02001032 wil_err(wil, "Not connected, %pM %s[%d] PN %*phN\n",
1033 mac_addr, key_usage_str[key_usage], key_index,
Vladimir Kondratiev58527422016-03-01 19:18:07 +02001034 params->seq_len, params->seq);
1035 return -EINVAL;
1036 }
1037
Maya Erez74b6ac52016-08-18 16:52:12 +03001038 wil_del_rx_key(key_index, key_usage, cs);
Vladimir Kondratiev58527422016-03-01 19:18:07 +02001039
1040 if (params->seq && params->seq_len != IEEE80211_GCMP_PN_LEN) {
1041 wil_err(wil,
Lazar Alexei3190cc62017-02-23 14:34:14 +02001042 "Wrong PN len %d, %pM %s[%d] PN %*phN\n",
1043 params->seq_len, mac_addr,
Vladimir Kondratiev58527422016-03-01 19:18:07 +02001044 key_usage_str[key_usage], key_index,
1045 params->seq_len, params->seq);
1046 return -EINVAL;
1047 }
1048
1049 rc = wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len,
1050 params->key, key_usage);
Maya Erez74b6ac52016-08-18 16:52:12 +03001051 if (!rc)
1052 wil_set_crypto_rx(key_index, key_usage, cs, params);
Vladimir Kondratiev58527422016-03-01 19:18:07 +02001053
1054 return rc;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001055}
1056
1057static int wil_cfg80211_del_key(struct wiphy *wiphy,
1058 struct net_device *ndev,
1059 u8 key_index, bool pairwise,
1060 const u8 *mac_addr)
1061{
1062 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
Vladimir Kondratiev230d8442015-04-30 16:25:10 +03001063 enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);
Maya Erez74b6ac52016-08-18 16:52:12 +03001064 struct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, key_usage,
1065 mac_addr);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001066
Lazar Alexei3190cc62017-02-23 14:34:14 +02001067 wil_dbg_misc(wil, "del_key: %pM %s[%d]\n", mac_addr,
Vladimir Kondratiev58527422016-03-01 19:18:07 +02001068 key_usage_str[key_usage], key_index);
1069
Maya Erez74b6ac52016-08-18 16:52:12 +03001070 if (IS_ERR(cs))
Lazar Alexei3190cc62017-02-23 14:34:14 +02001071 wil_info(wil, "Not connected, %pM %s[%d]\n",
Vladimir Kondratiev58527422016-03-01 19:18:07 +02001072 mac_addr, key_usage_str[key_usage], key_index);
1073
Maya Erez74b6ac52016-08-18 16:52:12 +03001074 if (!IS_ERR_OR_NULL(cs))
1075 wil_del_rx_key(key_index, key_usage, cs);
Vladimir Kondratievdb8adcb2015-03-30 11:28:51 +03001076
Vladimir Kondratiev230d8442015-04-30 16:25:10 +03001077 return wmi_del_cipher_key(wil, key_index, mac_addr, key_usage);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001078}
1079
1080/* Need to be present or wiphy_new() will WARN */
1081static int wil_cfg80211_set_default_key(struct wiphy *wiphy,
1082 struct net_device *ndev,
1083 u8 key_index, bool unicast,
1084 bool multicast)
1085{
Lior David280ab982016-03-01 19:18:14 +02001086 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
1087
Lazar Alexei3190cc62017-02-23 14:34:14 +02001088 wil_dbg_misc(wil, "set_default_key: entered\n");
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001089 return 0;
1090}
1091
Vladimir Kondratiev1647f122014-02-27 16:20:40 +02001092static int wil_remain_on_channel(struct wiphy *wiphy,
1093 struct wireless_dev *wdev,
1094 struct ieee80211_channel *chan,
1095 unsigned int duration,
1096 u64 *cookie)
1097{
1098 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
1099 int rc;
1100
Lazar Alexei3190cc62017-02-23 14:34:14 +02001101 wil_dbg_misc(wil,
1102 "remain_on_channel: center_freq=%d, duration=%d iftype=%d\n",
1103 chan->center_freq, duration, wdev->iftype);
Vladimir Kondratiev1647f122014-02-27 16:20:40 +02001104
Lior David42ba1c222017-02-15 20:37:20 +02001105 rc = wil_p2p_listen(wil, wdev, duration, chan, cookie);
1106 return rc;
Vladimir Kondratiev1647f122014-02-27 16:20:40 +02001107}
1108
1109static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
1110 struct wireless_dev *wdev,
1111 u64 cookie)
1112{
1113 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
Vladimir Kondratiev1647f122014-02-27 16:20:40 +02001114
Lazar Alexei3190cc62017-02-23 14:34:14 +02001115 wil_dbg_misc(wil, "cancel_remain_on_channel\n");
Vladimir Kondratiev1647f122014-02-27 16:20:40 +02001116
Lior David280ab982016-03-01 19:18:14 +02001117 return wil_p2p_cancel_listen(wil, cookie);
Vladimir Kondratiev1647f122014-02-27 16:20:40 +02001118}
1119
Lior Davidc100c882016-01-17 12:39:07 +02001120/**
1121 * find a specific IE in a list of IEs
1122 * return a pointer to the beginning of IE in the list
1123 * or NULL if not found
1124 */
1125static const u8 *_wil_cfg80211_find_ie(const u8 *ies, u16 ies_len, const u8 *ie,
1126 u16 ie_len)
1127{
1128 struct ieee80211_vendor_ie *vie;
1129 u32 oui;
1130
1131 /* IE tag at offset 0, length at offset 1 */
1132 if (ie_len < 2 || 2 + ie[1] > ie_len)
1133 return NULL;
1134
1135 if (ie[0] != WLAN_EID_VENDOR_SPECIFIC)
1136 return cfg80211_find_ie(ie[0], ies, ies_len);
1137
1138 /* make sure there is room for 3 bytes OUI + 1 byte OUI type */
1139 if (ie[1] < 4)
1140 return NULL;
1141 vie = (struct ieee80211_vendor_ie *)ie;
1142 oui = vie->oui[0] << 16 | vie->oui[1] << 8 | vie->oui[2];
1143 return cfg80211_find_vendor_ie(oui, vie->oui_type, ies,
1144 ies_len);
1145}
1146
1147/**
1148 * merge the IEs in two lists into a single list.
1149 * do not include IEs from the second list which exist in the first list.
1150 * add only vendor specific IEs from second list to keep
1151 * the merged list sorted (since vendor-specific IE has the
1152 * highest tag number)
1153 * caller must free the allocated memory for merged IEs
1154 */
1155static int _wil_cfg80211_merge_extra_ies(const u8 *ies1, u16 ies1_len,
1156 const u8 *ies2, u16 ies2_len,
1157 u8 **merged_ies, u16 *merged_len)
1158{
1159 u8 *buf, *dpos;
1160 const u8 *spos;
1161
1162 if (ies1_len == 0 && ies2_len == 0) {
1163 *merged_ies = NULL;
1164 *merged_len = 0;
1165 return 0;
1166 }
1167
1168 buf = kmalloc(ies1_len + ies2_len, GFP_KERNEL);
1169 if (!buf)
1170 return -ENOMEM;
1171 memcpy(buf, ies1, ies1_len);
1172 dpos = buf + ies1_len;
1173 spos = ies2;
1174 while (spos + 1 < ies2 + ies2_len) {
1175 /* IE tag at offset 0, length at offset 1 */
1176 u16 ielen = 2 + spos[1];
1177
1178 if (spos + ielen > ies2 + ies2_len)
1179 break;
1180 if (spos[0] == WLAN_EID_VENDOR_SPECIFIC &&
1181 !_wil_cfg80211_find_ie(ies1, ies1_len, spos, ielen)) {
1182 memcpy(dpos, spos, ielen);
1183 dpos += ielen;
1184 }
1185 spos += ielen;
1186 }
1187
1188 *merged_ies = buf;
1189 *merged_len = dpos - buf;
1190 return 0;
1191}
1192
Vladimir Kondratievca959772014-06-16 19:37:01 +03001193static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
1194{
Dedy Lanskyc198fc22017-03-27 21:14:41 +03001195 wil_hex_dump_misc("head ", DUMP_PREFIX_OFFSET, 16, 1,
1196 b->head, b->head_len, true);
1197 wil_hex_dump_misc("tail ", DUMP_PREFIX_OFFSET, 16, 1,
1198 b->tail, b->tail_len, true);
1199 wil_hex_dump_misc("BCON IE ", DUMP_PREFIX_OFFSET, 16, 1,
1200 b->beacon_ies, b->beacon_ies_len, true);
1201 wil_hex_dump_misc("PROBE ", DUMP_PREFIX_OFFSET, 16, 1,
1202 b->probe_resp, b->probe_resp_len, true);
1203 wil_hex_dump_misc("PROBE IE ", DUMP_PREFIX_OFFSET, 16, 1,
1204 b->proberesp_ies, b->proberesp_ies_len, true);
1205 wil_hex_dump_misc("ASSOC IE ", DUMP_PREFIX_OFFSET, 16, 1,
1206 b->assocresp_ies, b->assocresp_ies_len, true);
Vladimir Kondratievca959772014-06-16 19:37:01 +03001207}
1208
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001209/* internal functions for device reset and starting AP */
1210static int _wil_cfg80211_set_ies(struct wiphy *wiphy,
Vladimir Kondratievcab5abb2015-07-30 13:51:59 +03001211 struct cfg80211_beacon_data *bcon)
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001212{
1213 int rc;
1214 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
Lior Davidc100c882016-01-17 12:39:07 +02001215 u16 len = 0, proberesp_len = 0;
1216 u8 *ies = NULL, *proberesp = NULL;
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001217
Lior Davidc100c882016-01-17 12:39:07 +02001218 if (bcon->probe_resp) {
1219 struct ieee80211_mgmt *f =
1220 (struct ieee80211_mgmt *)bcon->probe_resp;
1221 size_t hlen = offsetof(struct ieee80211_mgmt,
1222 u.probe_resp.variable);
1223 proberesp = f->u.probe_resp.variable;
1224 proberesp_len = bcon->probe_resp_len - hlen;
1225 }
1226 rc = _wil_cfg80211_merge_extra_ies(proberesp,
1227 proberesp_len,
1228 bcon->proberesp_ies,
1229 bcon->proberesp_ies_len,
1230 &ies, &len);
1231
Vladimir Kondratiev5421bf02015-07-30 13:52:00 +03001232 if (rc)
Lior Davidc100c882016-01-17 12:39:07 +02001233 goto out;
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001234
Lior Davidc100c882016-01-17 12:39:07 +02001235 rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, len, ies);
1236 if (rc)
1237 goto out;
1238
1239 if (bcon->assocresp_ies)
1240 rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP,
1241 bcon->assocresp_ies_len, bcon->assocresp_ies);
1242 else
1243 rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, len, ies);
Vladimir Kondratievcab5abb2015-07-30 13:51:59 +03001244#if 0 /* to use beacon IE's, remove this #if 0 */
Vladimir Kondratiev5421bf02015-07-30 13:52:00 +03001245 if (rc)
Lior Davidc100c882016-01-17 12:39:07 +02001246 goto out;
Vladimir Kondratiev5421bf02015-07-30 13:52:00 +03001247
1248 rc = wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->tail_len, bcon->tail);
Vladimir Kondratievcab5abb2015-07-30 13:51:59 +03001249#endif
Lior Davidc100c882016-01-17 12:39:07 +02001250out:
1251 kfree(ies);
Vladimir Kondratiev5421bf02015-07-30 13:52:00 +03001252 return rc;
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001253}
1254
1255static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
1256 struct net_device *ndev,
1257 const u8 *ssid, size_t ssid_len, u32 privacy,
1258 int bi, u8 chan,
Vladimir Kondratievcab5abb2015-07-30 13:51:59 +03001259 struct cfg80211_beacon_data *bcon,
Lior Davideabb03b2016-03-01 19:18:10 +02001260 u8 hidden_ssid, u32 pbss)
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001261{
1262 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
1263 int rc;
1264 struct wireless_dev *wdev = ndev->ieee80211_ptr;
1265 u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
Lior Davidb4944f22016-03-01 19:18:17 +02001266 u8 is_go = (wdev->iftype == NL80211_IFTYPE_P2P_GO);
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001267
Lior Davideabb03b2016-03-01 19:18:10 +02001268 if (pbss)
1269 wmi_nettype = WMI_NETTYPE_P2P;
1270
Lazar Alexei3190cc62017-02-23 14:34:14 +02001271 wil_dbg_misc(wil, "start_ap: is_go=%d\n", is_go);
Lior Davidb4944f22016-03-01 19:18:17 +02001272 if (is_go && !pbss) {
Lazar Alexei3190cc62017-02-23 14:34:14 +02001273 wil_err(wil, "P2P GO must be in PBSS\n");
Lior Davidb4944f22016-03-01 19:18:17 +02001274 return -ENOTSUPP;
1275 }
1276
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001277 wil_set_recovery_state(wil, fw_recovery_idle);
1278
1279 mutex_lock(&wil->mutex);
1280
1281 __wil_down(wil);
1282 rc = __wil_up(wil);
1283 if (rc)
1284 goto out;
1285
1286 rc = wmi_set_ssid(wil, ssid_len, ssid);
1287 if (rc)
1288 goto out;
1289
Vladimir Kondratievcab5abb2015-07-30 13:51:59 +03001290 rc = _wil_cfg80211_set_ies(wiphy, bcon);
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001291 if (rc)
1292 goto out;
1293
1294 wil->privacy = privacy;
1295 wil->channel = chan;
1296 wil->hidden_ssid = hidden_ssid;
Lior Davideabb03b2016-03-01 19:18:10 +02001297 wil->pbss = pbss;
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001298
1299 netif_carrier_on(ndev);
Lior David704099f2017-05-04 21:31:02 +03001300 wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001301
Lior Davidb4944f22016-03-01 19:18:17 +02001302 rc = wmi_pcp_start(wil, bi, wmi_nettype, chan, hidden_ssid, is_go);
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001303 if (rc)
1304 goto err_pcp_start;
1305
1306 rc = wil_bcast_init(wil);
1307 if (rc)
1308 goto err_bcast;
1309
1310 goto out; /* success */
1311
1312err_bcast:
1313 wmi_pcp_stop(wil);
1314err_pcp_start:
1315 netif_carrier_off(ndev);
Lior David704099f2017-05-04 21:31:02 +03001316 wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001317out:
1318 mutex_unlock(&wil->mutex);
1319 return rc;
1320}
1321
Vladimir Kondratiev1bd922f2014-09-10 16:34:44 +03001322static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
1323 struct net_device *ndev,
1324 struct cfg80211_beacon_data *bcon)
1325{
1326 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
1327 int rc;
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001328 u32 privacy = 0;
Vladimir Kondratiev1bd922f2014-09-10 16:34:44 +03001329
Lazar Alexei3190cc62017-02-23 14:34:14 +02001330 wil_dbg_misc(wil, "change_beacon\n");
Vladimir Kondratiev1e7e5a02015-04-30 16:25:08 +03001331 wil_print_bcon_data(bcon);
1332
Lior Davidc5a157e2016-01-17 12:39:06 +02001333 if (bcon->tail &&
1334 cfg80211_find_ie(WLAN_EID_RSN, bcon->tail,
1335 bcon->tail_len))
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001336 privacy = 1;
1337
1338 /* in case privacy has changed, need to restart the AP */
1339 if (wil->privacy != privacy) {
1340 struct wireless_dev *wdev = ndev->ieee80211_ptr;
1341
1342 wil_dbg_misc(wil, "privacy changed %d=>%d. Restarting AP\n",
1343 wil->privacy, privacy);
1344
1345 rc = _wil_cfg80211_start_ap(wiphy, ndev, wdev->ssid,
1346 wdev->ssid_len, privacy,
1347 wdev->beacon_interval,
Vladimir Kondratievcab5abb2015-07-30 13:51:59 +03001348 wil->channel, bcon,
Lior Davideabb03b2016-03-01 19:18:10 +02001349 wil->hidden_ssid,
1350 wil->pbss);
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001351 } else {
Vladimir Kondratievcab5abb2015-07-30 13:51:59 +03001352 rc = _wil_cfg80211_set_ies(wiphy, bcon);
Vladimir Kondratiev1bd922f2014-09-10 16:34:44 +03001353 }
1354
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001355 return rc;
Vladimir Kondratiev1bd922f2014-09-10 16:34:44 +03001356}
1357
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001358static int wil_cfg80211_start_ap(struct wiphy *wiphy,
1359 struct net_device *ndev,
1360 struct cfg80211_ap_settings *info)
1361{
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001362 int rc;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001363 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001364 struct ieee80211_channel *channel = info->chandef.chan;
1365 struct cfg80211_beacon_data *bcon = &info->beacon;
Vladimir Kondratievca959772014-06-16 19:37:01 +03001366 struct cfg80211_crypto_settings *crypto = &info->crypto;
Hamad Kadmany8e52fe32015-06-09 14:11:18 +03001367 u8 hidden_ssid;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001368
Lazar Alexei3190cc62017-02-23 14:34:14 +02001369 wil_dbg_misc(wil, "start_ap\n");
Vladimir Kondratievca959772014-06-16 19:37:01 +03001370
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001371 if (!channel) {
1372 wil_err(wil, "AP: No channel???\n");
1373 return -EINVAL;
1374 }
1375
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001376 switch (info->hidden_ssid) {
1377 case NL80211_HIDDEN_SSID_NOT_IN_USE:
1378 hidden_ssid = WMI_HIDDEN_SSID_DISABLED;
1379 break;
1380
1381 case NL80211_HIDDEN_SSID_ZERO_LEN:
1382 hidden_ssid = WMI_HIDDEN_SSID_SEND_EMPTY;
1383 break;
1384
1385 case NL80211_HIDDEN_SSID_ZERO_CONTENTS:
1386 hidden_ssid = WMI_HIDDEN_SSID_CLEAR;
1387 break;
1388
1389 default:
1390 wil_err(wil, "AP: Invalid hidden SSID %d\n", info->hidden_ssid);
1391 return -EOPNOTSUPP;
1392 }
Vladimir Kondratiev77438822013-01-28 18:31:06 +02001393 wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value,
Vladimir Kondratiev2057ebb2013-01-28 18:30:58 +02001394 channel->center_freq, info->privacy ? "secure" : "open");
Vladimir Kondratievca959772014-06-16 19:37:01 +03001395 wil_dbg_misc(wil, "Privacy: %d auth_type %d\n",
1396 info->privacy, info->auth_type);
Hamad Kadmany8e52fe32015-06-09 14:11:18 +03001397 wil_dbg_misc(wil, "Hidden SSID mode: %d\n",
1398 info->hidden_ssid);
Vladimir Kondratievca959772014-06-16 19:37:01 +03001399 wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval,
1400 info->dtim_period);
Lior Davideabb03b2016-03-01 19:18:10 +02001401 wil_dbg_misc(wil, "PBSS %d\n", info->pbss);
Dedy Lanskyc198fc22017-03-27 21:14:41 +03001402 wil_hex_dump_misc("SSID ", DUMP_PREFIX_OFFSET, 16, 1,
1403 info->ssid, info->ssid_len, true);
Vladimir Kondratievca959772014-06-16 19:37:01 +03001404 wil_print_bcon_data(bcon);
1405 wil_print_crypto(wil, crypto);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001406
Vladimir Kondratiev33190eb2015-06-15 17:42:32 +03001407 rc = _wil_cfg80211_start_ap(wiphy, ndev,
1408 info->ssid, info->ssid_len, info->privacy,
1409 info->beacon_interval, channel->hw_value,
Lior Davideabb03b2016-03-01 19:18:10 +02001410 bcon, hidden_ssid, info->pbss);
Vladimir Kondratievc33407a2014-10-01 15:05:24 +03001411
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001412 return rc;
1413}
1414
1415static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
1416 struct net_device *ndev)
1417{
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001418 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001419
Lazar Alexei3190cc62017-02-23 14:34:14 +02001420 wil_dbg_misc(wil, "stop_ap\n");
Vladimir Kondratievca959772014-06-16 19:37:01 +03001421
Dedy Lanskyc5e96c92015-01-25 10:52:43 +02001422 netif_carrier_off(ndev);
Lior David704099f2017-05-04 21:31:02 +03001423 wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
Vladimir Kondratievc33407a2014-10-01 15:05:24 +03001424 wil_set_recovery_state(wil, fw_recovery_idle);
1425
Hamad Kadmany13d2ddf2017-04-13 14:38:45 +03001426 set_bit(wil_status_resetting, wil->status);
1427
Vladimir Kondratiev9c3bde52014-03-17 15:34:21 +02001428 mutex_lock(&wil->mutex);
1429
Dedy Lansky32a20d42015-01-25 10:52:44 +02001430 wmi_pcp_stop(wil);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001431
Vladimir Kondratiev73d839a2014-09-10 16:34:50 +03001432 __wil_down(wil);
Vladimir Kondratiev73d839a2014-09-10 16:34:50 +03001433
Vladimir Kondratiev9c3bde52014-03-17 15:34:21 +02001434 mutex_unlock(&wil->mutex);
Vladimir Kondratiev73d839a2014-09-10 16:34:50 +03001435
Dedy Lansky32a20d42015-01-25 10:52:44 +02001436 return 0;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001437}
1438
Dedy Lanskyb94ee9e2017-02-23 15:53:29 +02001439static int wil_cfg80211_add_station(struct wiphy *wiphy,
1440 struct net_device *dev,
1441 const u8 *mac,
1442 struct station_parameters *params)
1443{
1444 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
1445
1446 wil_dbg_misc(wil, "add station %pM aid %d\n", mac, params->aid);
1447
1448 if (!disable_ap_sme) {
1449 wil_err(wil, "not supported with AP SME enabled\n");
1450 return -EOPNOTSUPP;
1451 }
1452
1453 if (params->aid > WIL_MAX_DMG_AID) {
1454 wil_err(wil, "invalid aid\n");
1455 return -EINVAL;
1456 }
1457
1458 return wmi_new_sta(wil, mac, params->aid);
1459}
1460
Vladimir Kondratiev4d55a0a2014-02-27 16:20:54 +02001461static int wil_cfg80211_del_station(struct wiphy *wiphy,
Jouni Malinen89c771e2014-10-10 20:52:40 +03001462 struct net_device *dev,
1463 struct station_del_parameters *params)
Vladimir Kondratiev4d55a0a2014-02-27 16:20:54 +02001464{
1465 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
Vladimir Kondratiev097638a2014-03-17 15:34:25 +02001466
Lazar Alexei3190cc62017-02-23 14:34:14 +02001467 wil_dbg_misc(wil, "del_station: %pM, reason=%d\n", params->mac,
Vladimir Kondratievde9084e2015-03-30 11:28:52 +03001468 params->reason_code);
1469
Vladimir Kondratiev097638a2014-03-17 15:34:25 +02001470 mutex_lock(&wil->mutex);
Vladimir Kondratiev4821e6d2014-12-01 15:33:15 +02001471 wil6210_disconnect(wil, params->mac, params->reason_code, false);
Vladimir Kondratiev097638a2014-03-17 15:34:25 +02001472 mutex_unlock(&wil->mutex);
1473
Vladimir Kondratiev4d55a0a2014-02-27 16:20:54 +02001474 return 0;
1475}
1476
Dedy Lanskyb94ee9e2017-02-23 15:53:29 +02001477static int wil_cfg80211_change_station(struct wiphy *wiphy,
1478 struct net_device *dev,
1479 const u8 *mac,
1480 struct station_parameters *params)
1481{
1482 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
1483 int authorize;
1484 int cid, i;
1485 struct vring_tx_data *txdata = NULL;
1486
1487 wil_dbg_misc(wil, "change station %pM mask 0x%x set 0x%x\n", mac,
1488 params->sta_flags_mask, params->sta_flags_set);
1489
1490 if (!disable_ap_sme) {
1491 wil_dbg_misc(wil, "not supported with AP SME enabled\n");
1492 return -EOPNOTSUPP;
1493 }
1494
1495 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
1496 return 0;
1497
1498 cid = wil_find_cid(wil, mac);
1499 if (cid < 0) {
1500 wil_err(wil, "station not found\n");
1501 return -ENOLINK;
1502 }
1503
1504 for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++)
1505 if (wil->vring2cid_tid[i][0] == cid) {
1506 txdata = &wil->vring_tx_data[i];
1507 break;
1508 }
1509
1510 if (!txdata) {
1511 wil_err(wil, "vring data not found\n");
1512 return -ENOLINK;
1513 }
1514
1515 authorize = params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED);
1516 txdata->dot1x_open = authorize ? 1 : 0;
1517 wil_dbg_misc(wil, "cid %d vring %d authorize %d\n", cid, i,
1518 txdata->dot1x_open);
1519
1520 return 0;
1521}
1522
Vladimir Kondratiev40822a92015-01-25 10:52:50 +02001523/* probe_client handling */
1524static void wil_probe_client_handle(struct wil6210_priv *wil,
1525 struct wil_probe_client_req *req)
1526{
1527 struct net_device *ndev = wil_to_ndev(wil);
1528 struct wil_sta_info *sta = &wil->sta[req->cid];
1529 /* assume STA is alive if it is still connected,
1530 * else FW will disconnect it
1531 */
1532 bool alive = (sta->status == wil_sta_connected);
1533
1534 cfg80211_probe_status(ndev, sta->addr, req->cookie, alive, GFP_KERNEL);
1535}
1536
1537static struct list_head *next_probe_client(struct wil6210_priv *wil)
1538{
1539 struct list_head *ret = NULL;
1540
1541 mutex_lock(&wil->probe_client_mutex);
1542
1543 if (!list_empty(&wil->probe_client_pending)) {
1544 ret = wil->probe_client_pending.next;
1545 list_del(ret);
1546 }
1547
1548 mutex_unlock(&wil->probe_client_mutex);
1549
1550 return ret;
1551}
1552
1553void wil_probe_client_worker(struct work_struct *work)
1554{
1555 struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
1556 probe_client_worker);
1557 struct wil_probe_client_req *req;
1558 struct list_head *lh;
1559
1560 while ((lh = next_probe_client(wil)) != NULL) {
1561 req = list_entry(lh, struct wil_probe_client_req, list);
1562
1563 wil_probe_client_handle(wil, req);
1564 kfree(req);
1565 }
1566}
1567
1568void wil_probe_client_flush(struct wil6210_priv *wil)
1569{
1570 struct wil_probe_client_req *req, *t;
1571
Lazar Alexei3190cc62017-02-23 14:34:14 +02001572 wil_dbg_misc(wil, "probe_client_flush\n");
Vladimir Kondratiev40822a92015-01-25 10:52:50 +02001573
1574 mutex_lock(&wil->probe_client_mutex);
1575
1576 list_for_each_entry_safe(req, t, &wil->probe_client_pending, list) {
1577 list_del(&req->list);
1578 kfree(req);
1579 }
1580
1581 mutex_unlock(&wil->probe_client_mutex);
1582}
1583
1584static int wil_cfg80211_probe_client(struct wiphy *wiphy,
1585 struct net_device *dev,
1586 const u8 *peer, u64 *cookie)
1587{
1588 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
1589 struct wil_probe_client_req *req;
1590 int cid = wil_find_cid(wil, peer);
1591
Lazar Alexei3190cc62017-02-23 14:34:14 +02001592 wil_dbg_misc(wil, "probe_client: %pM => CID %d\n", peer, cid);
Vladimir Kondratiev40822a92015-01-25 10:52:50 +02001593
1594 if (cid < 0)
1595 return -ENOLINK;
1596
1597 req = kzalloc(sizeof(*req), GFP_KERNEL);
1598 if (!req)
1599 return -ENOMEM;
1600
1601 req->cid = cid;
1602 req->cookie = cid;
1603
1604 mutex_lock(&wil->probe_client_mutex);
1605 list_add_tail(&req->list, &wil->probe_client_pending);
1606 mutex_unlock(&wil->probe_client_mutex);
1607
1608 *cookie = req->cookie;
1609 queue_work(wil->wq_service, &wil->probe_client_worker);
1610 return 0;
1611}
1612
Vladimir Kondratiev02beaf12015-03-08 15:42:03 +02001613static int wil_cfg80211_change_bss(struct wiphy *wiphy,
1614 struct net_device *dev,
1615 struct bss_parameters *params)
1616{
1617 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
1618
1619 if (params->ap_isolate >= 0) {
Lazar Alexei3190cc62017-02-23 14:34:14 +02001620 wil_dbg_misc(wil, "change_bss: ap_isolate %d => %d\n",
Vladimir Kondratiev02beaf12015-03-08 15:42:03 +02001621 wil->ap_isolate, params->ap_isolate);
1622 wil->ap_isolate = params->ap_isolate;
1623 }
1624
1625 return 0;
1626}
1627
Lior David4332cac2016-03-01 19:18:13 +02001628static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy,
1629 struct wireless_dev *wdev)
1630{
1631 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
1632
Lazar Alexei3190cc62017-02-23 14:34:14 +02001633 wil_dbg_misc(wil, "start_p2p_device: entered\n");
Lior Davideb57a5b2016-06-08 20:07:48 +03001634 wil->p2p.p2p_dev_started = 1;
Lior David4332cac2016-03-01 19:18:13 +02001635 return 0;
1636}
1637
1638static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy,
1639 struct wireless_dev *wdev)
1640{
1641 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
Maya Erezd35c2b62016-08-18 16:52:14 +03001642 struct wil_p2p_info *p2p = &wil->p2p;
1643
1644 if (!p2p->p2p_dev_started)
1645 return;
Lior David4332cac2016-03-01 19:18:13 +02001646
Lazar Alexei3190cc62017-02-23 14:34:14 +02001647 wil_dbg_misc(wil, "stop_p2p_device: entered\n");
Lior Davideb57a5b2016-06-08 20:07:48 +03001648 mutex_lock(&wil->mutex);
Maya Erez4cbb5852017-02-16 15:26:09 +02001649 mutex_lock(&wil->p2p_wdev_mutex);
Maya Erezd35c2b62016-08-18 16:52:14 +03001650 wil_p2p_stop_radio_operations(wil);
1651 p2p->p2p_dev_started = 0;
Maya Erez4cbb5852017-02-16 15:26:09 +02001652 mutex_unlock(&wil->p2p_wdev_mutex);
Lior Davideb57a5b2016-06-08 20:07:48 +03001653 mutex_unlock(&wil->mutex);
Lior David4332cac2016-03-01 19:18:13 +02001654}
1655
Maya Ereze77727f2016-12-06 12:21:17 +02001656static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy,
1657 struct net_device *dev,
1658 bool enabled, int timeout)
1659{
1660 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
1661 enum wmi_ps_profile_type ps_profile;
Maya Ereze77727f2016-12-06 12:21:17 +02001662
1663 wil_dbg_misc(wil, "enabled=%d, timeout=%d\n",
1664 enabled, timeout);
1665
1666 if (enabled)
1667 ps_profile = WMI_PS_PROFILE_TYPE_DEFAULT;
1668 else
1669 ps_profile = WMI_PS_PROFILE_TYPE_PS_DISABLED;
1670
Lazar Alexei472bec22017-05-04 22:41:44 +03001671 return wil_ps_update(wil, ps_profile);
Maya Ereze77727f2016-12-06 12:21:17 +02001672}
1673
Maya Ereze3309bf2017-05-15 16:57:46 +03001674static int wil_cfg80211_suspend(struct wiphy *wiphy,
1675 struct cfg80211_wowlan *wow)
1676{
1677 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
1678 int rc;
1679
1680 /* Setting the wakeup trigger based on wow is TBD */
1681
1682 if (test_bit(wil_status_suspended, wil->status)) {
1683 wil_dbg_pm(wil, "trying to suspend while suspended\n");
1684 return 0;
1685 }
1686
1687 rc = wil_can_suspend(wil, false);
1688 if (rc)
1689 goto out;
1690
1691 wil_dbg_pm(wil, "suspending\n");
1692
1693 wil_p2p_stop_discovery(wil);
1694
1695 wil_abort_scan(wil, true);
1696
1697out:
1698 return rc;
1699}
1700
1701static int wil_cfg80211_resume(struct wiphy *wiphy)
1702{
1703 struct wil6210_priv *wil = wiphy_to_wil(wiphy);
1704
1705 wil_dbg_pm(wil, "resuming\n");
1706
1707 return 0;
1708}
1709
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001710static struct cfg80211_ops wil_cfg80211_ops = {
Lior David4332cac2016-03-01 19:18:13 +02001711 .add_virtual_intf = wil_cfg80211_add_iface,
1712 .del_virtual_intf = wil_cfg80211_del_iface,
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001713 .scan = wil_cfg80211_scan,
Maya Erez4cbb5852017-02-16 15:26:09 +02001714 .abort_scan = wil_cfg80211_abort_scan,
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001715 .connect = wil_cfg80211_connect,
1716 .disconnect = wil_cfg80211_disconnect,
Lior Davidde21eba2017-02-15 20:33:10 +02001717 .set_wiphy_params = wil_cfg80211_set_wiphy_params,
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001718 .change_virtual_intf = wil_cfg80211_change_iface,
1719 .get_station = wil_cfg80211_get_station,
Vladimir Kondratievef28afd2014-02-27 16:20:48 +02001720 .dump_station = wil_cfg80211_dump_station,
Vladimir Kondratiev1647f122014-02-27 16:20:40 +02001721 .remain_on_channel = wil_remain_on_channel,
1722 .cancel_remain_on_channel = wil_cancel_remain_on_channel,
1723 .mgmt_tx = wil_cfg80211_mgmt_tx,
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001724 .set_monitor_channel = wil_cfg80211_set_channel,
1725 .add_key = wil_cfg80211_add_key,
1726 .del_key = wil_cfg80211_del_key,
1727 .set_default_key = wil_cfg80211_set_default_key,
1728 /* AP mode */
Vladimir Kondratiev1bd922f2014-09-10 16:34:44 +03001729 .change_beacon = wil_cfg80211_change_beacon,
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001730 .start_ap = wil_cfg80211_start_ap,
1731 .stop_ap = wil_cfg80211_stop_ap,
Dedy Lanskyb94ee9e2017-02-23 15:53:29 +02001732 .add_station = wil_cfg80211_add_station,
Vladimir Kondratiev4d55a0a2014-02-27 16:20:54 +02001733 .del_station = wil_cfg80211_del_station,
Dedy Lanskyb94ee9e2017-02-23 15:53:29 +02001734 .change_station = wil_cfg80211_change_station,
Vladimir Kondratiev40822a92015-01-25 10:52:50 +02001735 .probe_client = wil_cfg80211_probe_client,
Vladimir Kondratiev02beaf12015-03-08 15:42:03 +02001736 .change_bss = wil_cfg80211_change_bss,
Lior David4332cac2016-03-01 19:18:13 +02001737 /* P2P device */
1738 .start_p2p_device = wil_cfg80211_start_p2p_device,
1739 .stop_p2p_device = wil_cfg80211_stop_p2p_device,
Maya Ereze77727f2016-12-06 12:21:17 +02001740 .set_power_mgmt = wil_cfg80211_set_power_mgmt,
Maya Ereze3309bf2017-05-15 16:57:46 +03001741 .suspend = wil_cfg80211_suspend,
1742 .resume = wil_cfg80211_resume,
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001743};
1744
1745static void wil_wiphy_init(struct wiphy *wiphy)
1746{
Hamad Kadmany8e52fe32015-06-09 14:11:18 +03001747 wiphy->max_scan_ssids = 1;
Vladimir Kondratiev77c91292014-09-10 16:34:47 +03001748 wiphy->max_scan_ie_len = WMI_MAX_IE_LEN;
Dedy Lanskye6d68342016-03-01 19:18:12 +02001749 wiphy->max_remain_on_channel_duration = WIL_MAX_ROC_DURATION_MS;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001750 wiphy->max_num_pmkids = 0 /* TODO: */;
1751 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
1752 BIT(NL80211_IFTYPE_AP) |
Dedy Lanskye6d68342016-03-01 19:18:12 +02001753 BIT(NL80211_IFTYPE_P2P_CLIENT) |
1754 BIT(NL80211_IFTYPE_P2P_GO) |
Lior David4332cac2016-03-01 19:18:13 +02001755 BIT(NL80211_IFTYPE_P2P_DEVICE) |
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001756 BIT(NL80211_IFTYPE_MONITOR);
Dedy Lanskyb94ee9e2017-02-23 15:53:29 +02001757 wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
Maya Ereze77727f2016-12-06 12:21:17 +02001758 WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
1759 WIPHY_FLAG_PS_ON_BY_DEFAULT;
Dedy Lanskyb94ee9e2017-02-23 15:53:29 +02001760 if (!disable_ap_sme)
1761 wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
Vladimir Kondratiev9cf10d62014-09-10 16:34:36 +03001762 dev_dbg(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
1763 __func__, wiphy->flags);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001764 wiphy->probe_resp_offload =
1765 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
1766 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
1767 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
1768
Johannes Berg57fbcce2016-04-12 15:56:15 +02001769 wiphy->bands[NL80211_BAND_60GHZ] = &wil_band_60ghz;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001770
1771 /* TODO: figure this out */
Vladimir Kondratievb8b33a32014-02-27 16:20:52 +02001772 wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001773
1774 wiphy->cipher_suites = wil_cipher_suites;
1775 wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites);
1776 wiphy->mgmt_stypes = wil_mgmt_stypes;
Vladimir Kondratiev713c8a22015-01-25 10:52:49 +02001777 wiphy->features |= NL80211_FEATURE_SK_TX_STATUS;
Lior David8f1b5e02017-02-28 14:58:27 +02001778
1779 wiphy->n_vendor_commands = ARRAY_SIZE(wil_nl80211_vendor_commands);
1780 wiphy->vendor_commands = wil_nl80211_vendor_commands;
1781 wiphy->vendor_events = wil_nl80211_vendor_events;
1782 wiphy->n_vendor_events = ARRAY_SIZE(wil_nl80211_vendor_events);
Lior Davidad9f6152017-05-03 15:11:10 +03001783
1784 if (ignore_reg_hints) {
1785 wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
1786 wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
1787 }
Maya Erez603fd472017-07-19 16:03:51 +03001788
1789#ifdef CONFIG_PM
1790 wiphy->wowlan = &wil_wowlan_support;
1791#endif
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001792}
1793
1794struct wireless_dev *wil_cfg80211_init(struct device *dev)
1795{
1796 int rc = 0;
1797 struct wireless_dev *wdev;
1798
Vladimir Kondratiev9cf10d62014-09-10 16:34:36 +03001799 dev_dbg(dev, "%s()\n", __func__);
1800
Vladimir Kondratiev8fe59622014-09-10 16:34:34 +03001801 wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001802 if (!wdev)
1803 return ERR_PTR(-ENOMEM);
1804
1805 wdev->wiphy = wiphy_new(&wil_cfg80211_ops,
1806 sizeof(struct wil6210_priv));
1807 if (!wdev->wiphy) {
1808 rc = -ENOMEM;
1809 goto out;
1810 }
1811
1812 set_wiphy_dev(wdev->wiphy, dev);
1813 wil_wiphy_init(wdev->wiphy);
1814
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001815 return wdev;
1816
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001817out:
1818 kfree(wdev);
1819
1820 return ERR_PTR(rc);
1821}
1822
1823void wil_wdev_free(struct wil6210_priv *wil)
1824{
1825 struct wireless_dev *wdev = wil_to_wdev(wil);
1826
Vladimir Kondratiev9cf10d62014-09-10 16:34:36 +03001827 dev_dbg(wil_to_dev(wil), "%s()\n", __func__);
1828
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001829 if (!wdev)
1830 return;
1831
Vladimir Kondratiev2be7d222012-12-20 13:13:19 -08001832 wiphy_free(wdev->wiphy);
1833 kfree(wdev);
1834}
Lior David4332cac2016-03-01 19:18:13 +02001835
1836void wil_p2p_wdev_free(struct wil6210_priv *wil)
1837{
1838 struct wireless_dev *p2p_wdev;
1839
1840 mutex_lock(&wil->p2p_wdev_mutex);
1841 p2p_wdev = wil->p2p_wdev;
Maya Erezd35c2b62016-08-18 16:52:14 +03001842 wil->p2p_wdev = NULL;
1843 wil->radio_wdev = wil_to_wdev(wil);
1844 mutex_unlock(&wil->p2p_wdev_mutex);
Lior David4332cac2016-03-01 19:18:13 +02001845 if (p2p_wdev) {
Lior David4332cac2016-03-01 19:18:13 +02001846 cfg80211_unregister_wdev(p2p_wdev);
1847 kfree(p2p_wdev);
1848 }
Lior David4332cac2016-03-01 19:18:13 +02001849}