Commit 7a5c1f64 authored by Hante Meuleman's avatar Hante Meuleman Committed by John W. Linville

brcmfmac: add p2p change vif routines.

Add support for changing existing interface into p2p go
interface.
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 7ee2d926
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "dhd_bus.h" #include "dhd_bus.h"
#include "dhd_proto.h" #include "dhd_proto.h"
#include "dhd_dbg.h" #include "dhd_dbg.h"
#include "fwil_types.h"
#include "p2p.h" #include "p2p.h"
#include "wl_cfg80211.h" #include "wl_cfg80211.h"
#include "fwil.h" #include "fwil.h"
......
...@@ -718,24 +718,105 @@ void brcmf_p2p_detach(struct brcmf_p2p_info *p2p) ...@@ -718,24 +718,105 @@ void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
memset(p2p, 0, sizeof(*p2p)); memset(p2p, 0, sizeof(*p2p));
} }
static int brcmf_p2p_request_p2p_if(struct brcmf_if *ifp, u8 ea[ETH_ALEN], /**
enum brcmf_fil_p2p_if_types iftype) * brcmf_p2p_get_current_chanspec() - Get current operation channel.
*
* @p2p: P2P specific data.
* @chanspec: chanspec to be returned.
*/
static void brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info *p2p,
u16 *chanspec)
{ {
struct brcmf_fil_p2p_if_le if_request; struct brcmf_if *ifp;
struct brcmf_fil_chan_info_le ci; struct brcmf_fil_chan_info_le ci;
u16 chanspec = 11 & WL_CHANSPEC_CHAN_MASK; s32 err;
int err;
ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
*chanspec = 11 & WL_CHANSPEC_CHAN_MASK;
/* we need a default channel */
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL, &ci, sizeof(ci)); err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL, &ci, sizeof(ci));
if (!err) { if (!err) {
chanspec = le32_to_cpu(ci.hw_channel) & WL_CHANSPEC_CHAN_MASK; *chanspec = le32_to_cpu(ci.hw_channel) & WL_CHANSPEC_CHAN_MASK;
if (chanspec < CH_MAX_2G_CHANNEL) if (*chanspec < CH_MAX_2G_CHANNEL)
chanspec |= WL_CHANSPEC_BAND_2G; *chanspec |= WL_CHANSPEC_BAND_2G;
else else
chanspec |= WL_CHANSPEC_BAND_5G; *chanspec |= WL_CHANSPEC_BAND_5G;
}
*chanspec |= WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
}
/**
* Change a P2P Role.
* Parameters:
* @mac: MAC address of the BSS to change a role
* Returns 0 if success.
*/
int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
enum brcmf_fil_p2p_if_types if_type)
{
struct brcmf_p2p_info *p2p = &cfg->p2p;
struct brcmf_cfg80211_vif *vif;
struct brcmf_fil_p2p_if_le if_request;
s32 err;
u16 chanspec;
brcmf_dbg(TRACE, "Enter\n");
vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
if (!vif) {
brcmf_err("vif for P2PAPI_BSSCFG_PRIMARY does not exist\n");
return -EPERM;
}
brcmf_notify_escan_complete(cfg, vif->ifp->ndev, true, true);
vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;
if (!vif) {
brcmf_err("vif for P2PAPI_BSSCFG_CONNECTION does not exist\n");
return -EPERM;
} }
chanspec |= WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; brcmf_set_mpc(vif->ifp->ndev, 0);
/* In concurrency case, STA may be already associated in a particular */
/* channel. so retrieve the current channel of primary interface and */
/* then start the virtual interface on that. */
brcmf_p2p_get_current_chanspec(p2p, &chanspec);
if_request.type = cpu_to_le16((u16)if_type);
if_request.chspec = cpu_to_le16(chanspec);
memcpy(if_request.addr, p2p->int_addr, sizeof(if_request.addr));
brcmf_cfg80211_arm_vif_event(cfg, vif);
err = brcmf_fil_iovar_data_set(vif->ifp, "p2p_ifupd", &if_request,
sizeof(if_request));
if (err) {
brcmf_err("p2p_ifupd FAILED, err=%d\n", err);
brcmf_cfg80211_arm_vif_event(cfg, NULL);
return err;
}
err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_CHANGE,
msecs_to_jiffies(1500));
brcmf_cfg80211_arm_vif_event(cfg, NULL);
if (!err) {
brcmf_err("No BRCMF_E_IF_CHANGE event received\n");
return -EIO;
}
err = brcmf_fil_cmd_int_set(vif->ifp, BRCMF_C_SET_SCB_TIMEOUT,
BRCMF_SCB_TIMEOUT_VALUE);
return err;
}
static int brcmf_p2p_request_p2p_if(struct brcmf_p2p_info *p2p,
struct brcmf_if *ifp, u8 ea[ETH_ALEN],
enum brcmf_fil_p2p_if_types iftype)
{
struct brcmf_fil_p2p_if_le if_request;
int err;
u16 chanspec;
/* we need a default channel */
brcmf_p2p_get_current_chanspec(p2p, &chanspec);
/* fill the firmware request */ /* fill the firmware request */
memcpy(if_request.addr, ea, ETH_ALEN); memcpy(if_request.addr, ea, ETH_ALEN);
...@@ -813,7 +894,8 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, ...@@ -813,7 +894,8 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
return (struct wireless_dev *)vif; return (struct wireless_dev *)vif;
brcmf_cfg80211_arm_vif_event(cfg, vif); brcmf_cfg80211_arm_vif_event(cfg, vif);
err = brcmf_p2p_request_p2p_if(ifp, cfg->p2p.int_addr, iftype); err = brcmf_p2p_request_p2p_if(&cfg->p2p, ifp, cfg->p2p.int_addr,
iftype);
if (err) { if (err) {
brcmf_cfg80211_arm_vif_event(cfg, NULL); brcmf_cfg80211_arm_vif_event(cfg, NULL);
goto fail; goto fail;
......
...@@ -108,6 +108,8 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, ...@@ -108,6 +108,8 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
enum nl80211_iftype type, u32 *flags, enum nl80211_iftype type, u32 *flags,
struct vif_params *params); struct vif_params *params);
int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev); int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev);
int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
enum brcmf_fil_p2p_if_types if_type);
int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev); int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev);
void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev); void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev);
int brcmf_p2p_scan_prep(struct wiphy *wiphy, int brcmf_p2p_scan_prep(struct wiphy *wiphy,
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <brcmu_wifi.h> #include <brcmu_wifi.h>
#include "dhd.h" #include "dhd.h"
#include "dhd_dbg.h" #include "dhd_dbg.h"
#include "fwil_types.h"
#include "p2p.h" #include "p2p.h"
#include "wl_cfg80211.h" #include "wl_cfg80211.h"
#include "fwil.h" #include "fwil.h"
...@@ -445,7 +446,7 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, ...@@ -445,7 +446,7 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
} }
} }
static void brcmf_set_mpc(struct net_device *ndev, int mpc) void brcmf_set_mpc(struct net_device *ndev, int mpc)
{ {
struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_if *ifp = netdev_priv(ndev);
s32 err = 0; s32 err = 0;
...@@ -460,7 +461,7 @@ static void brcmf_set_mpc(struct net_device *ndev, int mpc) ...@@ -460,7 +461,7 @@ static void brcmf_set_mpc(struct net_device *ndev, int mpc)
} }
} }
static s32 s32
brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
struct net_device *ndev, struct net_device *ndev,
bool aborted, bool fw_abort) bool aborted, bool fw_abort)
...@@ -567,6 +568,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, ...@@ -567,6 +568,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
enum nl80211_iftype type, u32 *flags, enum nl80211_iftype type, u32 *flags,
struct vif_params *params) struct vif_params *params)
{ {
struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_cfg80211_vif *vif = ifp->vif; struct brcmf_cfg80211_vif *vif = ifp->vif;
s32 infra = 0; s32 infra = 0;
...@@ -590,6 +592,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, ...@@ -590,6 +592,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
infra = 1; infra = 1;
break; break;
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
vif->mode = WL_MODE_AP; vif->mode = WL_MODE_AP;
ap = 1; ap = 1;
break; break;
...@@ -599,8 +602,14 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, ...@@ -599,8 +602,14 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
} }
if (ap) { if (ap) {
if (type == NL80211_IFTYPE_P2P_GO) {
brcmf_dbg(INFO, "IF Type = P2P GO\n");
err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
}
if (!err) {
set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state); set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
brcmf_dbg(INFO, "IF Type = AP\n"); brcmf_dbg(INFO, "IF Type = AP\n");
}
} else { } else {
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra); err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
if (err) { if (err) {
...@@ -4422,7 +4431,6 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp, ...@@ -4422,7 +4431,6 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
ifevent->action, ifevent->flags, ifevent->ifidx, ifevent->action, ifevent->flags, ifevent->ifidx,
ifevent->bssidx); ifevent->bssidx);
mutex_lock(&event->vif_event_lock); mutex_lock(&event->vif_event_lock);
event->action = ifevent->action; event->action = ifevent->action;
vif = event->vif; vif = event->vif;
...@@ -4453,6 +4461,11 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp, ...@@ -4453,6 +4461,11 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
wake_up(&event->vif_wq); wake_up(&event->vif_wq);
return 0; return 0;
case BRCMF_E_IF_CHANGE:
mutex_unlock(&event->vif_event_lock);
wake_up(&event->vif_wq);
return 0;
default: default:
mutex_unlock(&event->vif_event_lock); mutex_unlock(&event->vif_event_lock);
break; break;
......
...@@ -492,5 +492,9 @@ bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg); ...@@ -492,5 +492,9 @@ bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg);
int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
u8 action, ulong timeout); u8 action, ulong timeout);
void brcmf_cfg80211_vif_complete(struct brcmf_cfg80211_info *info); void brcmf_cfg80211_vif_complete(struct brcmf_cfg80211_info *info);
s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
struct net_device *ndev,
bool aborted, bool fw_abort);
void brcmf_set_mpc(struct net_device *ndev, int mpc);
#endif /* _wl_cfg80211_h_ */ #endif /* _wl_cfg80211_h_ */
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