File Index
Files and directories
Sign in
FILE

core.c

File preview with syntax highlighting.

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