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(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
brcmf_cyw_activate_events(struct brcmf_if * ifp)80 static 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
102 static
brcmf_cyw_mgmt_tx(struct wiphy * wiphy,struct wireless_dev * wdev,struct cfg80211_mgmt_tx_params * params,u64 * cookie)103 int 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
190 tx_status:
191 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
192 GFP_KERNEL);
193 free:
194 kfree(mf_params);
195 return err;
196 }
197
198 static int
brcmf_cyw_external_auth(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_external_auth_params * params)199 brcmf_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
brcmf_cyw_get_cfg80211_ops(struct brcmf_pub * drvr)233 static 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
239 static s32
brcmf_cyw_notify_ext_auth_req(struct brcmf_if * ifp,const struct brcmf_event_msg * e,void * data)240 brcmf_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(¶ms, 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, ¶ms, 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
274 static s32
brcmf_notify_auth_frame_rx(struct brcmf_if * ifp,const struct brcmf_event_msg * e,void * data)275 brcmf_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
327 static s32
brcmf_notify_mgmt_tx_status(struct brcmf_if * ifp,const struct brcmf_event_msg * e,void * data)328 brcmf_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
brcmf_cyw_register_event_handlers(struct brcmf_pub * drvr)355 static 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
367 const 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 };
374