Skip to content

Commit aa982ca

Browse files
Chung-Hsien Hsupopcornmix
Chung-Hsien Hsu
authored andcommitted
brcmfmac: support external SAE authentication in station mode
Firmware has SME functionality but would like the userspace to handle SAE authentication. This patch adds support for such an external SAE authentication mechanism in station mode. Signed-off-by: Chung-Hsien Hsu <[email protected]> Signed-off-by: Chi-hsien Lin <[email protected]>
1 parent a9f603a commit aa982ca

File tree

8 files changed

+340
-18
lines changed

8 files changed

+340
-18
lines changed

drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c

Lines changed: 247 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@
9090

9191
#define BRCMF_PS_MAX_TIMEOUT_MS 2000
9292

93+
#define MGMT_AUTH_FRAME_DWELL_TIME 4000
94+
#define MGMT_AUTH_FRAME_WAIT_TIME (MGMT_AUTH_FRAME_DWELL_TIME + 100)
95+
9396
/* Dump obss definitions */
9497
#define ACS_MSRMNT_DELAY 80
9598
#define CHAN_NOISE_DUMMY (-80)
@@ -1949,14 +1952,18 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev,
19491952
s32 val = 0;
19501953
s32 err = 0;
19511954

1952-
if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1955+
if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) {
19531956
val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1954-
else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1955-
val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1956-
else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_3)
1957+
} else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) {
1958+
if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_SAE)
1959+
val = WPA3_AUTH_SAE_PSK;
1960+
else
1961+
val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1962+
} else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_3) {
19571963
val = WPA3_AUTH_SAE_PSK;
1958-
else
1964+
} else {
19591965
val = WPA_AUTH_DISABLED;
1966+
}
19601967
brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
19611968
err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", val);
19621969
if (err) {
@@ -2222,7 +2229,7 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
22222229
brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp);
22232230

22242231
skip_mfp_config:
2225-
brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
2232+
brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
22262233
err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
22272234
if (err) {
22282235
bphy_err(drvr, "could not set wpa_auth (%d)\n", err);
@@ -5534,9 +5541,12 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
55345541
s32 ie_len;
55355542
struct brcmf_fil_action_frame_le *action_frame;
55365543
struct brcmf_fil_af_params_le *af_params;
5537-
bool ack;
5544+
bool ack = false;
55385545
s32 chan_nr;
55395546
u32 freq;
5547+
struct brcmf_mf_params_le *mf_params;
5548+
u32 mf_params_len;
5549+
s32 timeout;
55405550

55415551
brcmf_dbg(TRACE, "Enter\n");
55425552

@@ -5617,6 +5627,71 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
56175627
cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
56185628
GFP_KERNEL);
56195629
kfree(af_params);
5630+
} else if (ieee80211_is_auth(mgmt->frame_control)) {
5631+
reinit_completion(&vif->mgmt_tx);
5632+
clear_bit(BRCMF_MGMT_TX_ACK, &vif->mgmt_tx_status);
5633+
clear_bit(BRCMF_MGMT_TX_NOACK, &vif->mgmt_tx_status);
5634+
clear_bit(BRCMF_MGMT_TX_OFF_CHAN_COMPLETED,
5635+
&vif->mgmt_tx_status);
5636+
5637+
mf_params_len = offsetof(struct brcmf_mf_params_le, data) +
5638+
(len - DOT11_MGMT_HDR_LEN);
5639+
mf_params = kzalloc(mf_params_len, GFP_KERNEL);
5640+
if (!mf_params) {
5641+
err = -ENOMEM;
5642+
goto exit;
5643+
}
5644+
5645+
mf_params->dwell_time = cpu_to_le32(MGMT_AUTH_FRAME_DWELL_TIME);
5646+
mf_params->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
5647+
mf_params->frame_control = mgmt->frame_control;
5648+
5649+
if (chan)
5650+
freq = chan->center_freq;
5651+
else
5652+
brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
5653+
&freq);
5654+
chan_nr = ieee80211_frequency_to_channel(freq);
5655+
mf_params->channel = cpu_to_le32(chan_nr);
5656+
memcpy(&mf_params->da[0], &mgmt->da[0], ETH_ALEN);
5657+
memcpy(&mf_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
5658+
mf_params->packet_id = cpu_to_le32(*cookie);
5659+
memcpy(mf_params->data, &buf[DOT11_MGMT_HDR_LEN],
5660+
le16_to_cpu(mf_params->len));
5661+
5662+
brcmf_dbg(TRACE, "Auth frame, cookie=%d, fc=%04x, len=%d, channel=%d\n",
5663+
le32_to_cpu(mf_params->packet_id),
5664+
le16_to_cpu(mf_params->frame_control),
5665+
le16_to_cpu(mf_params->len),
5666+
le32_to_cpu(mf_params->channel));
5667+
5668+
vif->mgmt_tx_id = le32_to_cpu(mf_params->packet_id);
5669+
set_bit(BRCMF_MGMT_TX_SEND_FRAME, &vif->mgmt_tx_status);
5670+
5671+
err = brcmf_fil_bsscfg_data_set(vif->ifp, "mgmt_frame",
5672+
mf_params, mf_params_len);
5673+
if (err) {
5674+
bphy_err(drvr, "Failed to send Auth frame: err=%d\n",
5675+
err);
5676+
goto tx_status;
5677+
}
5678+
5679+
timeout =
5680+
wait_for_completion_timeout(&vif->mgmt_tx,
5681+
MGMT_AUTH_FRAME_WAIT_TIME);
5682+
if (test_bit(BRCMF_MGMT_TX_ACK, &vif->mgmt_tx_status)) {
5683+
brcmf_dbg(TRACE, "TX Auth frame operation is success\n");
5684+
ack = true;
5685+
} else {
5686+
bphy_err(drvr, "TX Auth frame operation is failed: status=%ld)\n",
5687+
vif->mgmt_tx_status);
5688+
}
5689+
5690+
tx_status:
5691+
cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
5692+
GFP_KERNEL);
5693+
kfree(mf_params);
5694+
56205695
} else {
56215696
brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
56225697
brcmf_dbg_hex_dump(true, buf, len, "payload, len=%zu\n", len);
@@ -5940,6 +6015,40 @@ static int brcmf_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
59406015
return brcmf_set_pmk(ifp, NULL, 0);
59416016
}
59426017

6018+
static int
6019+
brcmf_cfg80211_external_auth(struct wiphy *wiphy, struct net_device *dev,
6020+
struct cfg80211_external_auth_params *params)
6021+
{
6022+
struct brcmf_if *ifp;
6023+
struct brcmf_pub *drvr;
6024+
struct brcmf_auth_req_status_le auth_status;
6025+
int ret = 0;
6026+
6027+
brcmf_dbg(TRACE, "Enter\n");
6028+
6029+
ifp = netdev_priv(dev);
6030+
drvr = ifp->drvr;
6031+
if (params->status == WLAN_STATUS_SUCCESS) {
6032+
auth_status.flags = cpu_to_le16(BRCMF_EXTAUTH_SUCCESS);
6033+
} else {
6034+
bphy_err(drvr, "External authentication failed: status=%d\n",
6035+
params->status);
6036+
auth_status.flags = cpu_to_le16(BRCMF_EXTAUTH_FAIL);
6037+
}
6038+
6039+
memcpy(auth_status.peer_mac, params->bssid, ETH_ALEN);
6040+
auth_status.ssid_len = cpu_to_le32(min_t(u8, params->ssid.ssid_len,
6041+
IEEE80211_MAX_SSID_LEN));
6042+
memcpy(auth_status.ssid, params->ssid.ssid, auth_status.ssid_len);
6043+
6044+
ret = brcmf_fil_iovar_data_set(ifp, "auth_status", &auth_status,
6045+
sizeof(auth_status));
6046+
if (ret < 0)
6047+
bphy_err(drvr, "auth_status iovar failed: ret=%d\n", ret);
6048+
6049+
return ret;
6050+
}
6051+
59436052
static struct cfg80211_ops brcmf_cfg80211_ops = {
59446053
.add_virtual_intf = brcmf_cfg80211_add_iface,
59456054
.del_virtual_intf = brcmf_cfg80211_del_iface,
@@ -5987,6 +6096,7 @@ static struct cfg80211_ops brcmf_cfg80211_ops = {
59876096
.update_connect_params = brcmf_cfg80211_update_conn_params,
59886097
.set_pmk = brcmf_cfg80211_set_pmk,
59896098
.del_pmk = brcmf_cfg80211_del_pmk,
6099+
.external_auth = brcmf_cfg80211_external_auth,
59906100
};
59916101

59926102
struct cfg80211_ops *brcmf_cfg80211_get_ops(struct brcmf_mp_device *settings)
@@ -6033,6 +6143,7 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
60336143
vif->mbss = mbss;
60346144
}
60356145

6146+
init_completion(&vif->mgmt_tx);
60366147
list_add_tail(&vif->list, &cfg->vif_list);
60376148
return vif;
60386149
}
@@ -6724,6 +6835,122 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
67246835
return -EINVAL;
67256836
}
67266837

6838+
static s32
6839+
brcmf_notify_ext_auth_request(struct brcmf_if *ifp,
6840+
const struct brcmf_event_msg *e, void *data)
6841+
{
6842+
struct brcmf_pub *drvr = ifp->drvr;
6843+
struct cfg80211_external_auth_params params;
6844+
struct brcmf_auth_req_status_le *auth_req =
6845+
(struct brcmf_auth_req_status_le *)data;
6846+
s32 err = 0;
6847+
6848+
brcmf_dbg(INFO, "Enter: event %s (%d) received\n",
6849+
brcmf_fweh_event_name(e->event_code), e->event_code);
6850+
6851+
if (e->datalen < sizeof(*auth_req)) {
6852+
bphy_err(drvr, "Event %s (%d) data too small. Ignore\n",
6853+
brcmf_fweh_event_name(e->event_code), e->event_code);
6854+
return -EINVAL;
6855+
}
6856+
6857+
memset(&params, 0, sizeof(params));
6858+
params.action = NL80211_EXTERNAL_AUTH_START;
6859+
params.key_mgmt_suite = ntohl(WLAN_AKM_SUITE_SAE);
6860+
params.status = WLAN_STATUS_SUCCESS;
6861+
params.ssid.ssid_len = min_t(u32, 32, le32_to_cpu(auth_req->ssid_len));
6862+
memcpy(params.ssid.ssid, auth_req->ssid, params.ssid.ssid_len);
6863+
memcpy(params.bssid, auth_req->peer_mac, ETH_ALEN);
6864+
6865+
err = cfg80211_external_auth_request(ifp->ndev, &params, GFP_ATOMIC);
6866+
if (err)
6867+
bphy_err(drvr, "Ext Auth request to supplicant failed (%d)\n",
6868+
err);
6869+
6870+
return err;
6871+
}
6872+
6873+
static s32
6874+
brcmf_notify_auth_frame_rx(struct brcmf_if *ifp,
6875+
const struct brcmf_event_msg *e, void *data)
6876+
{
6877+
struct brcmf_pub *drvr = ifp->drvr;
6878+
struct brcmf_cfg80211_info *cfg = drvr->config;
6879+
struct wireless_dev *wdev;
6880+
u32 mgmt_frame_len = e->datalen - sizeof(struct brcmf_rx_mgmt_data);
6881+
struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
6882+
u8 *frame = (u8 *)(rxframe + 1);
6883+
struct brcmu_chan ch;
6884+
struct ieee80211_mgmt *mgmt_frame;
6885+
s32 freq;
6886+
6887+
brcmf_dbg(INFO, "Enter: event %s (%d) received\n",
6888+
brcmf_fweh_event_name(e->event_code), e->event_code);
6889+
6890+
if (e->datalen < sizeof(*rxframe)) {
6891+
bphy_err(drvr, "Event %s (%d) data too small. Ignore\n",
6892+
brcmf_fweh_event_name(e->event_code), e->event_code);
6893+
return -EINVAL;
6894+
}
6895+
6896+
wdev = &ifp->vif->wdev;
6897+
WARN_ON(!wdev);
6898+
6899+
ch.chspec = be16_to_cpu(rxframe->chanspec);
6900+
cfg->d11inf.decchspec(&ch);
6901+
6902+
mgmt_frame = kzalloc(mgmt_frame_len, GFP_KERNEL);
6903+
if (!mgmt_frame)
6904+
return -ENOMEM;
6905+
6906+
mgmt_frame->frame_control = cpu_to_le16(IEEE80211_STYPE_AUTH);
6907+
memcpy(mgmt_frame->da, ifp->mac_addr, ETH_ALEN);
6908+
memcpy(mgmt_frame->sa, e->addr, ETH_ALEN);
6909+
brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mgmt_frame->bssid,
6910+
ETH_ALEN);
6911+
frame += offsetof(struct ieee80211_mgmt, u);
6912+
memcpy(&mgmt_frame->u, frame,
6913+
mgmt_frame_len - offsetof(struct ieee80211_mgmt, u));
6914+
6915+
freq = ieee80211_channel_to_frequency(ch.control_ch_num,
6916+
ch.band == BRCMU_CHAN_BAND_2G ?
6917+
NL80211_BAND_2GHZ :
6918+
NL80211_BAND_5GHZ);
6919+
6920+
cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len,
6921+
NL80211_RXMGMT_FLAG_EXTERNAL_AUTH);
6922+
kfree(mgmt_frame);
6923+
return 0;
6924+
}
6925+
6926+
static s32
6927+
brcmf_notify_mgmt_tx_status(struct brcmf_if *ifp,
6928+
const struct brcmf_event_msg *e, void *data)
6929+
{
6930+
struct brcmf_cfg80211_vif *vif = ifp->vif;
6931+
u32 *packet_id = (u32 *)data;
6932+
6933+
brcmf_dbg(INFO, "Enter: event %s (%d), status=%d\n",
6934+
brcmf_fweh_event_name(e->event_code), e->event_code,
6935+
e->status);
6936+
6937+
if (!test_bit(BRCMF_MGMT_TX_SEND_FRAME, &vif->mgmt_tx_status) ||
6938+
(*packet_id != vif->mgmt_tx_id))
6939+
return 0;
6940+
6941+
if (e->event_code == BRCMF_E_MGMT_FRAME_TXSTATUS) {
6942+
if (e->status == BRCMF_E_STATUS_SUCCESS)
6943+
set_bit(BRCMF_MGMT_TX_ACK, &vif->mgmt_tx_status);
6944+
else
6945+
set_bit(BRCMF_MGMT_TX_NOACK, &vif->mgmt_tx_status);
6946+
} else {
6947+
set_bit(BRCMF_MGMT_TX_OFF_CHAN_COMPLETED, &vif->mgmt_tx_status);
6948+
}
6949+
6950+
complete(&vif->mgmt_tx);
6951+
return 0;
6952+
}
6953+
67276954
static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
67286955
{
67296956
conf->frag_threshold = (u32)-1;
@@ -6768,7 +6995,16 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
67686995
brcmf_p2p_notify_action_tx_complete);
67696996
brcmf_fweh_register(cfg->pub, BRCMF_E_PSK_SUP,
67706997
brcmf_notify_connect_status);
6771-
brcmf_fweh_register(cfg->pub, BRCMF_E_RSSI, brcmf_notify_rssi);
6998+
brcmf_fweh_register(cfg->pub, BRCMF_E_RSSI,
6999+
brcmf_notify_rssi);
7000+
brcmf_fweh_register(cfg->pub, BRCMF_E_EXT_AUTH_REQ,
7001+
brcmf_notify_ext_auth_request);
7002+
brcmf_fweh_register(cfg->pub, BRCMF_E_EXT_AUTH_FRAME_RX,
7003+
brcmf_notify_auth_frame_rx);
7004+
brcmf_fweh_register(cfg->pub, BRCMF_E_MGMT_FRAME_TXSTATUS,
7005+
brcmf_notify_mgmt_tx_status);
7006+
brcmf_fweh_register(cfg->pub, BRCMF_E_MGMT_FRAME_OFF_CHAN_COMPLETE,
7007+
brcmf_notify_mgmt_tx_status);
67727008
}
67737009

67747010
static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
@@ -7355,6 +7591,7 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
73557591
[NL80211_IFTYPE_STATION] = {
73567592
.tx = 0xffff,
73577593
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
7594+
BIT(IEEE80211_STYPE_AUTH >> 4) |
73587595
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
73597596
},
73607597
[NL80211_IFTYPE_P2P_CLIENT] = {
@@ -7662,6 +7899,8 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
76627899
wiphy_ext_feature_set(wiphy,
76637900
NL80211_EXT_FEATURE_SAE_OFFLOAD_AP);
76647901
}
7902+
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SAE_EXT))
7903+
wiphy->features |= NL80211_FEATURE_SAE;
76657904
wiphy->mgmt_stypes = brcmf_txrx_stypes;
76667905
wiphy->max_remain_on_channel_duration = 5000;
76677906
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {

drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,21 @@ enum brcmf_vif_status {
178178
BRCMF_VIF_STATUS_ASSOC_SUCCESS,
179179
};
180180

181+
/**
182+
* enum brcmf_mgmt_tx_status - mgmt frame tx status
183+
*
184+
* @BRCMF_MGMT_TX_ACK: mgmt frame acked
185+
* @BRCMF_MGMT_TX_NOACK: mgmt frame not acked
186+
* @BRCMF_MGMT_TX_OFF_CHAN_COMPLETED: off-channel complete
187+
* @BRCMF_MGMT_TX_SEND_FRAME: mgmt frame tx is in progres
188+
*/
189+
enum brcmf_mgmt_tx_status {
190+
BRCMF_MGMT_TX_ACK,
191+
BRCMF_MGMT_TX_NOACK,
192+
BRCMF_MGMT_TX_OFF_CHAN_COMPLETED,
193+
BRCMF_MGMT_TX_SEND_FRAME
194+
};
195+
181196
/**
182197
* struct vif_saved_ie - holds saved IEs for a virtual interface.
183198
*
@@ -224,6 +239,9 @@ struct brcmf_cfg80211_vif {
224239
unsigned long sme_state;
225240
struct vif_saved_ie saved_ie;
226241
struct list_head list;
242+
struct completion mgmt_tx;
243+
unsigned long mgmt_tx_status;
244+
u32 mgmt_tx_id;
227245
u16 mgmt_rx_reg;
228246
bool mbss;
229247
int is_11d;

0 commit comments

Comments
 (0)