xref: /linux/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1 // SPDX-License-Identifier: ISC
2 /*
3  * Copyright (c) 2022 Broadcom Corporation
4  */
5 #include <linux/errno.h>
6 #include <linux/types.h>
7 #include <core.h>
8 #include <bus.h>
9 #include <fwvid.h>
10 #include <fwil.h>
11 #include <fweh.h>
12 
13 #include "vops.h"
14 #include "fwil_types.h"
15 
16 /* event definitions */
17 #define BRCMF_CYW_E_EXT_AUTH_REQ	187
18 #define BRCMF_CYW_E_EXT_AUTH_FRAME_RX	188
19 #define BRCMF_CYW_E_MGMT_FRAME_TXS	189
20 #define BRCMF_CYW_E_MGMT_FRAME_TXS_OC	190
21 #define BRCMF_CYW_E_LAST		197
22 
23 #define MGMT_AUTH_FRAME_DWELL_TIME	4000
24 #define MGMT_AUTH_FRAME_WAIT_TIME	(MGMT_AUTH_FRAME_DWELL_TIME + 100)
25 
brcmf_cyw_set_sae_pwd(struct brcmf_if * ifp,struct cfg80211_crypto_settings * crypto)26 static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp,
27 				 struct cfg80211_crypto_settings *crypto)
28 {
29 	struct brcmf_pub *drvr = ifp->drvr;
30 	struct brcmf_wsec_sae_pwd_le sae_pwd;
31 	u16 pwd_len = crypto->sae_pwd_len;
32 	int err;
33 
34 	if (pwd_len > BRCMF_WSEC_MAX_SAE_PASSWORD_LEN) {
35 		bphy_err(drvr, "sae_password must be less than %d\n",
36 			 BRCMF_WSEC_MAX_SAE_PASSWORD_LEN);
37 		return -EINVAL;
38 	}
39 
40 	sae_pwd.key_len = cpu_to_le16(pwd_len);
41 	memcpy(sae_pwd.key, crypto->sae_pwd, pwd_len);
42 
43 	err = brcmf_fil_iovar_data_set(ifp, "sae_password", &sae_pwd,
44 				       sizeof(sae_pwd));
45 	if (err < 0)
46 		bphy_err(drvr, "failed to set SAE password in firmware (len=%u)\n",
47 			 pwd_len);
48 
49 	return err;
50 }
51 
52 static const struct brcmf_fweh_event_map brcmf_cyw_event_map = {
53 	.items = {
54 		{ BRCMF_E_EXT_AUTH_REQ, BRCMF_CYW_E_EXT_AUTH_REQ },
55 		{ BRCMF_E_EXT_AUTH_FRAME_RX, BRCMF_CYW_E_EXT_AUTH_FRAME_RX },
56 		{ BRCMF_E_MGMT_FRAME_TXSTATUS, BRCMF_CYW_E_MGMT_FRAME_TXS },
57 		{
58 			BRCMF_E_MGMT_FRAME_OFFCHAN_DONE,
59 			BRCMF_CYW_E_MGMT_FRAME_TXS_OC
60 		},
61 	},
62 	.n_items = 4
63 };
64 
brcmf_cyw_alloc_fweh_info(struct brcmf_pub * drvr)65 static int brcmf_cyw_alloc_fweh_info(struct brcmf_pub *drvr)
66 {
67 	struct brcmf_fweh_info *fweh;
68 
69 	fweh = kzalloc_flex(*fweh, evt_handler, BRCMF_CYW_E_LAST);
70 	if (!fweh)
71 		return -ENOMEM;
72 
73 	fweh->num_event_codes = BRCMF_CYW_E_LAST;
74 	fweh->event_map = &brcmf_cyw_event_map;
75 	drvr->fweh = fweh;
76 	return 0;
77 }
78 
brcmf_cyw_activate_events(struct brcmf_if * ifp)79 static int brcmf_cyw_activate_events(struct brcmf_if *ifp)
80 {
81 	struct brcmf_fweh_info *fweh = ifp->drvr->fweh;
82 	struct brcmf_eventmsgs_ext *eventmask_msg;
83 	u32 msglen;
84 	int err;
85 
86 	msglen = sizeof(*eventmask_msg) + fweh->event_mask_len;
87 	eventmask_msg = kzalloc(msglen, GFP_KERNEL);
88 	if (!eventmask_msg)
89 		return -ENOMEM;
90 	eventmask_msg->ver = EVENTMSGS_VER;
91 	eventmask_msg->command = CYW_EVENTMSGS_SET_MASK;
92 	eventmask_msg->len = fweh->event_mask_len;
93 	memcpy(eventmask_msg->mask, fweh->event_mask, fweh->event_mask_len);
94 
95 	err = brcmf_fil_iovar_data_set(ifp, "event_msgs_ext", eventmask_msg,
96 				       msglen);
97 	kfree(eventmask_msg);
98 	return err;
99 }
100 
101 static
brcmf_cyw_mgmt_tx(struct wiphy * wiphy,struct wireless_dev * wdev,struct cfg80211_mgmt_tx_params * params,u64 cookie)102 int brcmf_cyw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
103 		      struct cfg80211_mgmt_tx_params *params, u64 cookie)
104 {
105 	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
106 	struct ieee80211_channel *chan = params->chan;
107 	struct brcmf_pub *drvr = cfg->pub;
108 	const u8 *buf = params->buf;
109 	size_t len = params->len;
110 	const struct ieee80211_mgmt *mgmt;
111 	struct brcmf_cfg80211_vif *vif;
112 	s32 err = 0;
113 	bool ack = false;
114 	__le16 hw_ch;
115 	struct brcmf_mf_params_le *mf_params;
116 	u32 mf_params_len;
117 	s32 ready;
118 
119 	brcmf_dbg(TRACE, "Enter\n");
120 
121 	mgmt = (const struct ieee80211_mgmt *)buf;
122 
123 	if (!ieee80211_is_auth(mgmt->frame_control))
124 		return brcmf_cfg80211_mgmt_tx(wiphy, wdev, params, cookie);
125 
126 	vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
127 
128 	reinit_completion(&vif->mgmt_tx);
129 	clear_bit(BRCMF_MGMT_TX_ACK, &vif->mgmt_tx_status);
130 	clear_bit(BRCMF_MGMT_TX_NOACK, &vif->mgmt_tx_status);
131 	clear_bit(BRCMF_MGMT_TX_OFF_CHAN_COMPLETED,
132 		  &vif->mgmt_tx_status);
133 	mf_params_len = offsetof(struct brcmf_mf_params_le, data) +
134 			(len - DOT11_MGMT_HDR_LEN);
135 	mf_params = kzalloc(mf_params_len, GFP_KERNEL);
136 	if (!mf_params)
137 		return -ENOMEM;
138 
139 	mf_params->dwell_time = cpu_to_le32(MGMT_AUTH_FRAME_DWELL_TIME);
140 	mf_params->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
141 	mf_params->frame_control = mgmt->frame_control;
142 
143 	if (chan) {
144 		hw_ch = cpu_to_le16(chan->hw_value);
145 	} else {
146 		err = brcmf_fil_cmd_data_get(vif->ifp, BRCMF_C_GET_CHANNEL,
147 					     &hw_ch, sizeof(hw_ch));
148 		if (err) {
149 			bphy_err(drvr, "unable to get current hw channel\n");
150 			goto free;
151 		}
152 	}
153 	mf_params->channel = hw_ch;
154 
155 	memcpy(&mf_params->da[0], &mgmt->da[0], ETH_ALEN);
156 	memcpy(&mf_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
157 	mf_params->packet_id = cpu_to_le32(cookie);
158 	memcpy(mf_params->data, &buf[DOT11_MGMT_HDR_LEN],
159 	       le16_to_cpu(mf_params->len));
160 
161 	brcmf_dbg(TRACE, "Auth frame, cookie=%d, fc=%04x, len=%d, channel=%d\n",
162 		  le32_to_cpu(mf_params->packet_id),
163 		  le16_to_cpu(mf_params->frame_control),
164 		  le16_to_cpu(mf_params->len),
165 		  le16_to_cpu(mf_params->channel));
166 
167 	vif->mgmt_tx_id = le32_to_cpu(mf_params->packet_id);
168 	set_bit(BRCMF_MGMT_TX_SEND_FRAME, &vif->mgmt_tx_status);
169 
170 	err = brcmf_fil_bsscfg_data_set(vif->ifp, "mgmt_frame",
171 					mf_params, mf_params_len);
172 	if (err) {
173 		bphy_err(drvr, "Failed to send Auth frame: err=%d\n",
174 			 err);
175 		goto tx_status;
176 	}
177 
178 	ready = wait_for_completion_timeout(&vif->mgmt_tx,
179 					    MGMT_AUTH_FRAME_WAIT_TIME);
180 	if (test_bit(BRCMF_MGMT_TX_ACK, &vif->mgmt_tx_status)) {
181 		brcmf_dbg(TRACE, "TX Auth frame operation is success\n");
182 		ack = true;
183 	} else {
184 		bphy_err(drvr, "TX Auth frame operation is %s: status=%ld)\n",
185 			 ready ? "failed" : "timedout", vif->mgmt_tx_status);
186 	}
187 
188 tx_status:
189 	cfg80211_mgmt_tx_status(wdev, cookie, buf, len, ack, GFP_KERNEL);
190 free:
191 	kfree(mf_params);
192 	return err;
193 }
194 
195 static int
brcmf_cyw_external_auth(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_external_auth_params * params)196 brcmf_cyw_external_auth(struct wiphy *wiphy, struct net_device *dev,
197 			struct cfg80211_external_auth_params *params)
198 {
199 	struct brcmf_if *ifp;
200 	struct brcmf_pub *drvr;
201 	struct brcmf_auth_req_status_le auth_status;
202 	int ret = 0;
203 
204 	brcmf_dbg(TRACE, "Enter\n");
205 
206 	ifp = netdev_priv(dev);
207 	drvr = ifp->drvr;
208 	if (params->status == WLAN_STATUS_SUCCESS) {
209 		auth_status.flags = cpu_to_le16(BRCMF_EXTAUTH_SUCCESS);
210 	} else {
211 		bphy_err(drvr, "External authentication failed: status=%d\n",
212 			 params->status);
213 		auth_status.flags = cpu_to_le16(BRCMF_EXTAUTH_FAIL);
214 	}
215 
216 	memcpy(auth_status.peer_mac, params->bssid, ETH_ALEN);
217 	params->ssid.ssid_len = min_t(u8, params->ssid.ssid_len,
218 				      IEEE80211_MAX_SSID_LEN);
219 	auth_status.ssid_len = cpu_to_le32(params->ssid.ssid_len);
220 	memcpy(auth_status.ssid, params->ssid.ssid, params->ssid.ssid_len);
221 
222 	ret = brcmf_fil_iovar_data_set(ifp, "auth_status", &auth_status,
223 				       sizeof(auth_status));
224 	if (ret < 0)
225 		bphy_err(drvr, "auth_status iovar failed: ret=%d\n", ret);
226 
227 	return ret;
228 }
229 
brcmf_cyw_get_cfg80211_ops(struct brcmf_pub * drvr)230 static void brcmf_cyw_get_cfg80211_ops(struct brcmf_pub *drvr)
231 {
232 	drvr->ops->mgmt_tx = brcmf_cyw_mgmt_tx;
233 	drvr->ops->external_auth = brcmf_cyw_external_auth;
234 }
235 
236 static s32
brcmf_cyw_notify_ext_auth_req(struct brcmf_if * ifp,const struct brcmf_event_msg * e,void * data)237 brcmf_cyw_notify_ext_auth_req(struct brcmf_if *ifp,
238 			      const struct brcmf_event_msg *e, void *data)
239 {
240 	struct brcmf_pub *drvr = ifp->drvr;
241 	struct cfg80211_external_auth_params params;
242 	struct brcmf_auth_req_status_le *auth_req =
243 		(struct brcmf_auth_req_status_le *)data;
244 	s32 err = 0;
245 
246 	brcmf_dbg(INFO, "Enter: event %s (%d) received\n",
247 		  brcmf_fweh_event_name(e->event_code), e->event_code);
248 
249 	if (e->datalen < sizeof(*auth_req)) {
250 		bphy_err(drvr, "Event %s (%d) data too small. Ignore\n",
251 			 brcmf_fweh_event_name(e->event_code), e->event_code);
252 		return -EINVAL;
253 	}
254 
255 	memset(&params, 0, sizeof(params));
256 	params.action = NL80211_EXTERNAL_AUTH_START;
257 	params.key_mgmt_suite = WLAN_AKM_SUITE_SAE;
258 	params.status = WLAN_STATUS_SUCCESS;
259 	params.ssid.ssid_len = min_t(u32, 32, le32_to_cpu(auth_req->ssid_len));
260 	memcpy(params.ssid.ssid, auth_req->ssid, params.ssid.ssid_len);
261 	memcpy(params.bssid, auth_req->peer_mac, ETH_ALEN);
262 
263 	err = cfg80211_external_auth_request(ifp->ndev, &params, GFP_KERNEL);
264 	if (err)
265 		bphy_err(drvr, "Ext Auth request to supplicant failed (%d)\n",
266 			 err);
267 
268 	return err;
269 }
270 
271 static s32
brcmf_notify_auth_frame_rx(struct brcmf_if * ifp,const struct brcmf_event_msg * e,void * data)272 brcmf_notify_auth_frame_rx(struct brcmf_if *ifp,
273 			   const struct brcmf_event_msg *e, void *data)
274 {
275 	struct brcmf_pub *drvr = ifp->drvr;
276 	struct brcmf_cfg80211_info *cfg = drvr->config;
277 	struct wireless_dev *wdev;
278 	u32 mgmt_frame_len = e->datalen - sizeof(struct brcmf_rx_mgmt_data);
279 	struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
280 	u8 *frame = (u8 *)(rxframe + 1);
281 	struct brcmu_chan ch;
282 	struct ieee80211_mgmt *mgmt_frame;
283 	s32 freq;
284 
285 	brcmf_dbg(INFO, "Enter: event %s (%d) received\n",
286 		  brcmf_fweh_event_name(e->event_code), e->event_code);
287 
288 	if (e->datalen < sizeof(*rxframe)) {
289 		bphy_err(drvr, "Event %s (%d) data too small. Ignore\n",
290 			 brcmf_fweh_event_name(e->event_code), e->event_code);
291 		return -EINVAL;
292 	}
293 
294 	if (mgmt_frame_len < offsetof(struct ieee80211_mgmt, u)) {
295 		bphy_err(drvr, "Event %s (%d) frame too small. Ignore\n",
296 			 brcmf_fweh_event_name(e->event_code), e->event_code);
297 		return -EINVAL;
298 	}
299 
300 	wdev = &ifp->vif->wdev;
301 	WARN_ON(!wdev);
302 
303 	ch.chspec = be16_to_cpu(rxframe->chanspec);
304 	cfg->d11inf.decchspec(&ch);
305 
306 	mgmt_frame = kzalloc(mgmt_frame_len, GFP_KERNEL);
307 	if (!mgmt_frame)
308 		return -ENOMEM;
309 
310 	mgmt_frame->frame_control = cpu_to_le16(IEEE80211_STYPE_AUTH);
311 	memcpy(mgmt_frame->da, ifp->mac_addr, ETH_ALEN);
312 	memcpy(mgmt_frame->sa, e->addr, ETH_ALEN);
313 	brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mgmt_frame->bssid,
314 			       ETH_ALEN);
315 	frame += offsetof(struct ieee80211_mgmt, u);
316 	memcpy(&mgmt_frame->u, frame,
317 	       mgmt_frame_len - offsetof(struct ieee80211_mgmt, u));
318 
319 	freq = ieee80211_channel_to_frequency(ch.control_ch_num,
320 					      ch.band == BRCMU_CHAN_BAND_2G ?
321 					      NL80211_BAND_2GHZ :
322 					      NL80211_BAND_5GHZ);
323 
324 	cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len,
325 			 NL80211_RXMGMT_FLAG_EXTERNAL_AUTH);
326 	kfree(mgmt_frame);
327 	return 0;
328 }
329 
330 static s32
brcmf_notify_mgmt_tx_status(struct brcmf_if * ifp,const struct brcmf_event_msg * e,void * data)331 brcmf_notify_mgmt_tx_status(struct brcmf_if *ifp,
332 			    const struct brcmf_event_msg *e, void *data)
333 {
334 	struct brcmf_cfg80211_vif *vif = ifp->vif;
335 	u32 *packet_id = (u32 *)data;
336 
337 	brcmf_dbg(INFO, "Enter: event %s (%d), status=%d\n",
338 		  brcmf_fweh_event_name(e->event_code), e->event_code,
339 		  e->status);
340 
341 	if (!test_bit(BRCMF_MGMT_TX_SEND_FRAME, &vif->mgmt_tx_status) ||
342 	    (*packet_id != vif->mgmt_tx_id))
343 		return 0;
344 
345 	if (e->event_code == BRCMF_E_MGMT_FRAME_TXSTATUS) {
346 		if (e->status == BRCMF_E_STATUS_SUCCESS)
347 			set_bit(BRCMF_MGMT_TX_ACK, &vif->mgmt_tx_status);
348 		else
349 			set_bit(BRCMF_MGMT_TX_NOACK, &vif->mgmt_tx_status);
350 	} else {
351 		set_bit(BRCMF_MGMT_TX_OFF_CHAN_COMPLETED, &vif->mgmt_tx_status);
352 	}
353 
354 	complete(&vif->mgmt_tx);
355 	return 0;
356 }
357 
brcmf_cyw_register_event_handlers(struct brcmf_pub * drvr)358 static void brcmf_cyw_register_event_handlers(struct brcmf_pub *drvr)
359 {
360 	brcmf_fweh_register(drvr, BRCMF_E_EXT_AUTH_REQ,
361 			    brcmf_cyw_notify_ext_auth_req);
362 	brcmf_fweh_register(drvr, BRCMF_E_EXT_AUTH_FRAME_RX,
363 			    brcmf_notify_auth_frame_rx);
364 	brcmf_fweh_register(drvr, BRCMF_E_MGMT_FRAME_TXSTATUS,
365 			    brcmf_notify_mgmt_tx_status);
366 	brcmf_fweh_register(drvr, BRCMF_E_MGMT_FRAME_OFFCHAN_DONE,
367 			    brcmf_notify_mgmt_tx_status);
368 }
369 
370 const struct brcmf_fwvid_ops brcmf_cyw_ops = {
371 	.set_sae_password = brcmf_cyw_set_sae_pwd,
372 	.alloc_fweh_info = brcmf_cyw_alloc_fweh_info,
373 	.activate_events = brcmf_cyw_activate_events,
374 	.get_cfg80211_ops = brcmf_cyw_get_cfg80211_ops,
375 	.register_event_handlers = brcmf_cyw_register_event_handlers,
376 };
377