Skip to content

Commit 8c590ad

Browse files
Chung-Hsien Hsupelwell
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 15f000a commit 8c590ad

File tree

7 files changed

+341
-16
lines changed

7 files changed

+341
-16
lines changed

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

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

9090
#define BRCMF_PS_MAX_TIMEOUT_MS 2000
9191

92+
#define MGMT_AUTH_FRAME_DWELL_TIME 4000
93+
#define MGMT_AUTH_FRAME_WAIT_TIME (MGMT_AUTH_FRAME_DWELL_TIME + 100)
94+
9295
/* Dump obss definitions */
9396
#define ACS_MSRMNT_DELAY 80
9497
#define CHAN_NOISE_DUMMY (-80)
@@ -1958,14 +1961,18 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev,
19581961
s32 val = 0;
19591962
s32 err = 0;
19601963

1961-
if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1964+
if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) {
19621965
val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1963-
else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1964-
val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1965-
else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_3)
1966+
} else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) {
1967+
if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_SAE)
1968+
val = WPA3_AUTH_SAE_PSK;
1969+
else
1970+
val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1971+
} else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_3) {
19661972
val = WPA3_AUTH_SAE_PSK;
1967-
else
1973+
} else {
19681974
val = WPA_AUTH_DISABLED;
1975+
}
19691976
brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
19701977
err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", val);
19711978
if (err) {
@@ -2230,7 +2237,7 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
22302237
brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp);
22312238

22322239
skip_mfp_config:
2233-
brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
2240+
brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
22342241
err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
22352242
if (err) {
22362243
bphy_err(drvr, "could not set wpa_auth (%d)\n", err);
@@ -5525,9 +5532,12 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
55255532
s32 ie_len;
55265533
struct brcmf_fil_action_frame_le *action_frame;
55275534
struct brcmf_fil_af_params_le *af_params;
5528-
bool ack;
5535+
bool ack = false;
55295536
s32 chan_nr;
55305537
u32 freq;
5538+
struct brcmf_mf_params_le *mf_params;
5539+
u32 mf_params_len;
5540+
s32 timeout;
55315541

55325542
brcmf_dbg(TRACE, "Enter\n");
55335543

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

6009+
static int
6010+
brcmf_cfg80211_external_auth(struct wiphy *wiphy, struct net_device *dev,
6011+
struct cfg80211_external_auth_params *params)
6012+
{
6013+
struct brcmf_if *ifp;
6014+
struct brcmf_pub *drvr;
6015+
struct brcmf_auth_req_status_le auth_status;
6016+
int ret = 0;
6017+
6018+
brcmf_dbg(TRACE, "Enter\n");
6019+
6020+
ifp = netdev_priv(dev);
6021+
drvr = ifp->drvr;
6022+
if (params->status == WLAN_STATUS_SUCCESS) {
6023+
auth_status.flags = cpu_to_le16(BRCMF_EXTAUTH_SUCCESS);
6024+
} else {
6025+
bphy_err(drvr, "External authentication failed: status=%d\n",
6026+
params->status);
6027+
auth_status.flags = cpu_to_le16(BRCMF_EXTAUTH_FAIL);
6028+
}
6029+
6030+
memcpy(auth_status.peer_mac, params->bssid, ETH_ALEN);
6031+
auth_status.ssid_len = cpu_to_le32(min_t(u8, params->ssid.ssid_len,
6032+
IEEE80211_MAX_SSID_LEN));
6033+
memcpy(auth_status.ssid, params->ssid.ssid, auth_status.ssid_len);
6034+
6035+
ret = brcmf_fil_iovar_data_set(ifp, "auth_status", &auth_status,
6036+
sizeof(auth_status));
6037+
if (ret < 0)
6038+
bphy_err(drvr, "auth_status iovar failed: ret=%d\n", ret);
6039+
6040+
return ret;
6041+
}
6042+
59346043
static struct cfg80211_ops brcmf_cfg80211_ops = {
59356044
.add_virtual_intf = brcmf_cfg80211_add_iface,
59366045
.del_virtual_intf = brcmf_cfg80211_del_iface,
@@ -5978,6 +6087,7 @@ static struct cfg80211_ops brcmf_cfg80211_ops = {
59786087
.update_connect_params = brcmf_cfg80211_update_conn_params,
59796088
.set_pmk = brcmf_cfg80211_set_pmk,
59806089
.del_pmk = brcmf_cfg80211_del_pmk,
6090+
.external_auth = brcmf_cfg80211_external_auth,
59816091
};
59826092

59836093
struct cfg80211_ops *brcmf_cfg80211_get_ops(struct brcmf_mp_device *settings)
@@ -6024,6 +6134,7 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
60246134
vif->mbss = mbss;
60256135
}
60266136

6137+
init_completion(&vif->mgmt_tx);
60276138
list_add_tail(&vif->list, &cfg->vif_list);
60286139
return vif;
60296140
}
@@ -6715,6 +6826,122 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
67156826
return -EINVAL;
67166827
}
67176828

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

67657001
static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
@@ -7347,6 +7583,7 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
73477583
[NL80211_IFTYPE_STATION] = {
73487584
.tx = 0xffff,
73497585
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
7586+
BIT(IEEE80211_STYPE_AUTH >> 4) |
73507587
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
73517588
},
73527589
[NL80211_IFTYPE_P2P_CLIENT] = {
@@ -7652,6 +7889,8 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
76527889
wiphy_ext_feature_set(wiphy,
76537890
NL80211_EXT_FEATURE_SAE_OFFLOAD_AP);
76547891
}
7892+
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SAE_EXT))
7893+
wiphy->features |= NL80211_FEATURE_SAE;
76557894
wiphy->mgmt_stypes = brcmf_txrx_stypes;
76567895
wiphy->max_remain_on_channel_duration = 5000;
76577896
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;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = {
4343
{ BRCMF_FEAT_DOT11H, "802.11h" },
4444
{ BRCMF_FEAT_SAE, "sae" },
4545
{ BRCMF_FEAT_FWAUTH, "idauth" },
46+
{ BRCMF_FEAT_SAE_EXT, "sae_ext " },
4647
};
4748

4849
#ifdef DEBUG

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
* SAE: simultaneous authentication of equals
3131
* FWAUTH: Firmware authenticator
3232
* DUMP_OBSS: Firmware has capable to dump obss info to support ACS
33+
* SAE_EXT: SAE be handled by userspace supplicant
3334
* SCAN_V2: Version 2 scan params
3435
*/
3536
#define BRCMF_FEAT_LIST \
@@ -55,6 +56,7 @@
5556
BRCMF_FEAT_DEF(SAE) \
5657
BRCMF_FEAT_DEF(FWAUTH) \
5758
BRCMF_FEAT_DEF(DUMP_OBSS) \
59+
BRCMF_FEAT_DEF(SAE_EXT) \
5860
BRCMF_FEAT_DEF(SCAN_V2) \
5961
BRCMF_FEAT_DEF(PMKID_V2) \
6062
BRCMF_FEAT_DEF(PMKID_V3)

0 commit comments

Comments
 (0)