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 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 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 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 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 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 if (params->pmkid) 210 memcpy(auth_status.pmkid, params->pmkid, 211 WLAN_PMKID_LEN); 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 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 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 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 if (mgmt_frame_len < offsetof(struct ieee80211_mgmt, u)) { 298 bphy_err(drvr, "Event %s (%d) frame too small. Ignore\n", 299 brcmf_fweh_event_name(e->event_code), e->event_code); 300 return -EINVAL; 301 } 302 303 wdev = &ifp->vif->wdev; 304 WARN_ON(!wdev); 305 306 ch.chspec = be16_to_cpu(rxframe->chanspec); 307 cfg->d11inf.decchspec(&ch); 308 309 mgmt_frame = kzalloc(mgmt_frame_len, GFP_KERNEL); 310 if (!mgmt_frame) 311 return -ENOMEM; 312 313 mgmt_frame->frame_control = cpu_to_le16(IEEE80211_STYPE_AUTH); 314 memcpy(mgmt_frame->da, ifp->mac_addr, ETH_ALEN); 315 memcpy(mgmt_frame->sa, e->addr, ETH_ALEN); 316 brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mgmt_frame->bssid, 317 ETH_ALEN); 318 frame += offsetof(struct ieee80211_mgmt, u); 319 memcpy(&mgmt_frame->u, frame, 320 mgmt_frame_len - offsetof(struct ieee80211_mgmt, u)); 321 322 freq = ieee80211_channel_to_frequency(ch.control_ch_num, 323 ch.band == BRCMU_CHAN_BAND_2G ? 324 NL80211_BAND_2GHZ : 325 NL80211_BAND_5GHZ); 326 327 cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 328 NL80211_RXMGMT_FLAG_EXTERNAL_AUTH); 329 kfree(mgmt_frame); 330 return 0; 331 } 332 333 static s32 334 brcmf_notify_mgmt_tx_status(struct brcmf_if *ifp, 335 const struct brcmf_event_msg *e, void *data) 336 { 337 struct brcmf_cfg80211_vif *vif = ifp->vif; 338 u32 *packet_id = (u32 *)data; 339 340 brcmf_dbg(INFO, "Enter: event %s (%d), status=%d\n", 341 brcmf_fweh_event_name(e->event_code), e->event_code, 342 e->status); 343 344 if (!test_bit(BRCMF_MGMT_TX_SEND_FRAME, &vif->mgmt_tx_status) || 345 (*packet_id != vif->mgmt_tx_id)) 346 return 0; 347 348 if (e->event_code == BRCMF_E_MGMT_FRAME_TXSTATUS) { 349 if (e->status == BRCMF_E_STATUS_SUCCESS) 350 set_bit(BRCMF_MGMT_TX_ACK, &vif->mgmt_tx_status); 351 else 352 set_bit(BRCMF_MGMT_TX_NOACK, &vif->mgmt_tx_status); 353 } else { 354 set_bit(BRCMF_MGMT_TX_OFF_CHAN_COMPLETED, &vif->mgmt_tx_status); 355 } 356 357 complete(&vif->mgmt_tx); 358 return 0; 359 } 360 361 static void brcmf_cyw_register_event_handlers(struct brcmf_pub *drvr) 362 { 363 brcmf_fweh_register(drvr, BRCMF_E_EXT_AUTH_REQ, 364 brcmf_cyw_notify_ext_auth_req); 365 brcmf_fweh_register(drvr, BRCMF_E_EXT_AUTH_FRAME_RX, 366 brcmf_notify_auth_frame_rx); 367 brcmf_fweh_register(drvr, BRCMF_E_MGMT_FRAME_TXSTATUS, 368 brcmf_notify_mgmt_tx_status); 369 brcmf_fweh_register(drvr, BRCMF_E_MGMT_FRAME_OFFCHAN_DONE, 370 brcmf_notify_mgmt_tx_status); 371 } 372 373 static int brcmf_cyw_configure_sae_pwe(struct brcmf_if *ifp, u32 sae_pwe) 374 { 375 return brcmf_fil_iovar_int_set(ifp, "extsae_pwe", sae_pwe); 376 } 377 378 const struct brcmf_fwvid_ops brcmf_cyw_ops = { 379 .set_sae_password = brcmf_cyw_set_sae_pwd, 380 .alloc_fweh_info = brcmf_cyw_alloc_fweh_info, 381 .activate_events = brcmf_cyw_activate_events, 382 .get_cfg80211_ops = brcmf_cyw_get_cfg80211_ops, 383 .register_event_handlers = brcmf_cyw_register_event_handlers, 384 .configure_sae_pwe = brcmf_cyw_configure_sae_pwe, 385 }; 386