Commit a0f07959 authored by Hante Meuleman's avatar Hante Meuleman Committed by John W. Linville
Browse files

brcmfmac: Update AP mode for GO creation.



With this update it is possible to create an P2P go. Handle the
p2p go role in creation and the update beacon from cfg80211. Also
store primary bss in global struct. Needed to map cfg device
back to primary device.
Reviewed-by: default avatarArend Van Spriel <arend@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: default avatarHante Meuleman <meuleman@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 89286dc9
......@@ -39,4 +39,9 @@ struct brcmf_fil_chan_info_le {
__le32 scan_channel;
};
struct brcmf_fil_bss_enable_le {
__le32 bsscfg_idx;
__le32 enable;
};
#endif /* FWIL_TYPES_H_ */
......@@ -691,15 +691,17 @@ void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp)
*
* @cfg: driver private data for cfg80211 interface.
*/
void brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
void brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg,
struct brcmf_cfg80211_vif *vif)
{
struct brcmf_p2p_info *p2p;
p2p = &cfg->p2p;
p2p->cfg = cfg;
brcmf_p2p_set_firmware(p2p);
p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = vif;
brcmf_p2p_generate_bss_mac(p2p);
brcmf_p2p_set_firmware(p2p);
}
/**
......
......@@ -102,7 +102,8 @@ struct brcmf_p2p_info {
struct ieee80211_channel remain_on_channel;
};
void brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg);
void brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg,
struct brcmf_cfg80211_vif *vif);
void brcmf_p2p_detach(struct brcmf_p2p_info *p2p);
struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
enum nl80211_iftype type, u32 *flags,
......
......@@ -3624,10 +3624,38 @@ s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
return 0;
}
static s32
brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
struct cfg80211_beacon_data *beacon)
{
s32 err;
/* Set Beacon IEs to FW */
err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
beacon->tail, beacon->tail_len);
if (err) {
brcmf_err("Set Beacon IE Failed\n");
return err;
}
brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
/* Set Probe Response IEs to FW */
err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
beacon->proberesp_ies,
beacon->proberesp_ies_len);
if (err)
brcmf_err("Set Probe Resp IE Failed\n");
else
brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
return err;
}
static s32
brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_ap_settings *settings)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
s32 ie_offset;
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_tlv *ssid_ie;
......@@ -3636,6 +3664,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
struct brcmf_tlv *rsn_ie;
struct brcmf_vs_tlv *wpa_ie;
struct brcmf_join_params join_params;
enum nl80211_iftype dev_role;
struct brcmf_fil_bss_enable_le bss_enable;
brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
cfg80211_get_chandef_type(&settings->chandef),
......@@ -3645,9 +3675,21 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
settings->ssid, settings->ssid_len, settings->auth_type,
settings->inactivity_timeout);
if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) {
brcmf_err("Not in AP creation mode\n");
return -EPERM;
if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
brcmf_dbg(TRACE, "Role = AP\n");
dev_role = NL80211_IFTYPE_AP;
if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING,
&ifp->vif->sme_state)) {
brcmf_err("Not in AP creation mode\n");
return -EPERM;
}
} else {
brcmf_dbg(TRACE, "Role = P2P GO\n");
dev_role = NL80211_IFTYPE_P2P_GO;
if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) {
ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
ndev = ifp->ndev;
}
}
memset(&ssid_le, 0, sizeof(ssid_le));
......@@ -3669,21 +3711,6 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
}
brcmf_set_mpc(ndev, 0);
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
if (err < 0) {
brcmf_err("BRCMF_C_DOWN error %d\n", err);
goto exit;
}
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
if (err < 0) {
brcmf_err("SET INFRA error %d\n", err);
goto exit;
}
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
if (err < 0) {
brcmf_err("setting AP mode failed %d\n", err);
goto exit;
}
/* find the RSN_IE */
rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
......@@ -3711,25 +3738,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
brcmf_configure_opensecurity(ifp);
}
/* Set Beacon IEs to FW */
err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
BRCMF_VNDR_IE_BEACON_FLAG,
settings->beacon.tail,
settings->beacon.tail_len);
if (err)
brcmf_err("Set Beacon IE Failed\n");
else
brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
/* Set Probe Response IEs to FW */
err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
BRCMF_VNDR_IE_PRBRSP_FLAG,
settings->beacon.proberesp_ies,
settings->beacon.proberesp_ies_len);
if (err)
brcmf_err("Set Probe Resp IE Failed\n");
else
brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
if (settings->beacon_interval) {
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
......@@ -3747,23 +3757,62 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
goto exit;
}
}
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
if (err < 0) {
brcmf_err("BRCMF_C_UP error (%d)\n", err);
goto exit;
if (dev_role == NL80211_IFTYPE_AP) {
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
if (err < 0) {
brcmf_err("BRCMF_C_DOWN error %d\n", err);
goto exit;
}
brcmf_fil_iovar_int_set(ifp, "apsta", 0);
}
memset(&join_params, 0, sizeof(join_params));
/* join parameters starts with ssid */
memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
/* create softap */
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
&join_params, sizeof(join_params));
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
if (err < 0) {
brcmf_err("SET SSID error (%d)\n", err);
brcmf_err("SET INFRA error %d\n", err);
goto exit;
}
if (dev_role == NL80211_IFTYPE_AP) {
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
if (err < 0) {
brcmf_err("setting AP mode failed %d\n", err);
goto exit;
}
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
if (err < 0) {
brcmf_err("BRCMF_C_UP error (%d)\n", err);
goto exit;
}
memset(&join_params, 0, sizeof(join_params));
/* join parameters starts with ssid */
memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
/* create softap */
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
&join_params, sizeof(join_params));
if (err < 0) {
brcmf_err("SET SSID error (%d)\n", err);
goto exit;
}
brcmf_dbg(TRACE, "AP mode configuration complete\n");
} else {
err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
sizeof(ssid_le));
if (err < 0) {
brcmf_err("setting ssid failed %d\n", err);
goto exit;
}
bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
bss_enable.enable = cpu_to_le32(1);
err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
sizeof(bss_enable));
if (err < 0) {
brcmf_err("bss_enable config failed %d\n", err);
goto exit;
}
brcmf_dbg(TRACE, "GO mode configuration complete\n");
}
clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
......@@ -3802,10 +3851,41 @@ exit:
return err;
}
static s32
brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_beacon_data *info)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
s32 err;
brcmf_dbg(TRACE, "Enter\n");
if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
brcmf_dbg(TRACE, "Role = AP\n");
if (!test_bit(BRCMF_VIF_STATUS_AP_CREATED,
&ifp->vif->sme_state)) {
brcmf_err("AP was not yet created\n");
return -EPERM;
}
} else {
brcmf_dbg(TRACE, "Role = P2P GO\n");
if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) {
ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
ndev = ifp->ndev;
}
}
err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
return err;
}
static int
brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
u8 *mac)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_scb_val_le scbval;
struct brcmf_if *ifp = netdev_priv(ndev);
s32 err;
......@@ -3815,6 +3895,8 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
brcmf_dbg(TRACE, "Enter %pM\n", mac);
if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
if (!check_vif_up(ifp->vif))
return -EIO;
......@@ -3824,7 +3906,12 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
&scbval, sizeof(scbval));
if (err)
brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
/*
* Wait for the deauth event to come, supplicant will do the
* delete iface immediately and we will have problem in sending
* deauth frame if we delete the bss in firmware
*/
brcmf_delay(400);
brcmf_dbg(TRACE, "Exit\n");
return err;
}
......@@ -3857,6 +3944,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
const struct ieee80211_mgmt *mgmt;
struct brcmf_if *ifp;
struct brcmf_cfg80211_vif *vif;
s32 err = 0;
s32 ie_offset;
......@@ -3868,41 +3956,41 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
mgmt = (const struct ieee80211_mgmt *)buf;
if (ieee80211_is_mgmt(mgmt->frame_control)) {
if (ieee80211_is_probe_resp(mgmt->frame_control)) {
/* Right now the only reason to get a probe response */
/* is for p2p listen response from wpa_supplicant. */
/* Unfortunately the wpa_supplicant sends it on the */
/* primary ndev, while dongle wants it on the p2p */
/* vif. Since this is only reason for a probe */
/* response to be sent, the vif is taken from cfg. */
/* If ever desired to send proberesp for non p2p */
/* response then data should be checked for */
/* "DIRECT-". Note in future supplicant will take */
/* dedicated p2p wdev to do this and then this 'hack'*/
/* is not needed anymore. */
ie_offset = DOT11_MGMT_HDR_LEN +
DOT11_BCN_PRB_FIXED_LEN;
ie_len = len - ie_offset;
if (!ieee80211_is_mgmt(mgmt->frame_control)) {
brcmf_err("Driver only allows MGMT packet type\n");
return -EPERM;
}
if (ieee80211_is_probe_resp(mgmt->frame_control)) {
/* Right now the only reason to get a probe response */
/* is for p2p listen response or for p2p GO from */
/* wpa_supplicant. Unfortunately the probe is send */
/* on primary ndev, while dongle wants it on the p2p */
/* vif. Since this is only reason for a probe */
/* response to be sent, the vif is taken from cfg. */
/* If ever desired to send proberesp for non p2p */
/* response then data should be checked for */
/* "DIRECT-". Note in future supplicant will take */
/* dedicated p2p wdev to do this and then this 'hack'*/
/* is not needed anymore. */
ie_offset = DOT11_MGMT_HDR_LEN +
DOT11_BCN_PRB_FIXED_LEN;
ie_len = len - ie_offset;
ifp = netdev_priv(wdev->netdev);
vif = ifp->vif;
if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
if (vif == NULL) {
brcmf_err("No p2p device available for probe response\n");
err = -ENODEV;
goto exit;
}
err = brcmf_vif_set_mgmt_ie(vif,
BRCMF_VNDR_IE_PRBRSP_FLAG,
&buf[ie_offset],
ie_len);
cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
GFP_KERNEL);
goto exit;
}
err = brcmf_vif_set_mgmt_ie(vif,
BRCMF_VNDR_IE_PRBRSP_FLAG,
&buf[ie_offset],
ie_len);
cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
GFP_KERNEL);
} else {
brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
}
brcmf_dbg(TRACE, "Unhandled, is_mgmt %d, fc=%04x!!!!!\n",
ieee80211_is_mgmt(mgmt->frame_control), mgmt->frame_control);
exit:
return err;
}
......@@ -3946,8 +4034,8 @@ static s32 brcmf_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
"Enter: event %d reason %d\n", e->event_code, e->reason);
/* Firmware sends us two proberesponses for each idx one. At the */
/* moment only bsscfgidx 0 is passed up to supplicant */
if (e->bsscfgidx)
/* moment anything but bsscfgidx 0 is passed up to supplicant */
if (e->bsscfgidx == 0)
return 0;
/* Check if wpa_supplicant has registered for this frame */
......@@ -3999,6 +4087,7 @@ static struct cfg80211_ops wl_cfg80211_ops = {
.flush_pmksa = brcmf_cfg80211_flush_pmksa,
.start_ap = brcmf_cfg80211_start_ap,
.stop_ap = brcmf_cfg80211_stop_ap,
.change_beacon = brcmf_cfg80211_change_beacon,
.del_station = brcmf_cfg80211_del_station,
.sched_scan_start = brcmf_cfg80211_sched_scan_start,
.sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
......@@ -4727,7 +4816,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
brcmf_err("Failed to init iwm_priv (%d)\n", err);
goto cfg80211_attach_out;
}
brcmf_p2p_attach(cfg);
brcmf_p2p_attach(cfg, vif);
ifp->vif = vif;
return cfg;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment