Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "dhd_bus.h"
#include "dhd_proto.h"
#include "dhd_dbg.h"
#include "fwil_types.h"
#include "p2p.h"
#include "wl_cfg80211.h"
#include "fwil.h"
+94 −12
Original line number Diff line number Diff line
@@ -718,24 +718,105 @@ void brcmf_p2p_detach(struct brcmf_p2p_info *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;
	u16 chanspec = 11 & WL_CHANSPEC_CHAN_MASK;
	int err;
	s32 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));
	if (!err) {
		chanspec = le32_to_cpu(ci.hw_channel) & WL_CHANSPEC_CHAN_MASK;
		if (chanspec < CH_MAX_2G_CHANNEL)
			chanspec |= WL_CHANSPEC_BAND_2G;
		*chanspec = le32_to_cpu(ci.hw_channel) & WL_CHANSPEC_CHAN_MASK;
		if (*chanspec < CH_MAX_2G_CHANNEL)
			*chanspec |= WL_CHANSPEC_BAND_2G;
		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 */
	memcpy(if_request.addr, ea, ETH_ALEN);
@@ -813,7 +894,8 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
		return (struct wireless_dev *)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) {
		brcmf_cfg80211_arm_vif_event(cfg, NULL);
		goto fail;
+2 −0
Original line number Diff line number Diff line
@@ -108,6 +108,8 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
				       enum nl80211_iftype type, u32 *flags,
				       struct vif_params *params);
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);
void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev);
int brcmf_p2p_scan_prep(struct wiphy *wiphy,
+18 −5
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <brcmu_wifi.h>
#include "dhd.h"
#include "dhd_dbg.h"
#include "fwil_types.h"
#include "p2p.h"
#include "wl_cfg80211.h"
#include "fwil.h"
@@ -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);
	s32 err = 0;
@@ -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,
			    struct net_device *ndev,
			    bool aborted, bool fw_abort)
@@ -567,6 +568,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
			 enum nl80211_iftype type, u32 *flags,
			 struct vif_params *params)
{
	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_vif *vif = ifp->vif;
	s32 infra = 0;
@@ -590,6 +592,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
		infra = 1;
		break;
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_P2P_GO:
		vif->mode = WL_MODE_AP;
		ap = 1;
		break;
@@ -599,8 +602,14 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
	}

	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);
			brcmf_dbg(INFO, "IF Type = AP\n");
		}
	} else {
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
		if (err) {
@@ -4422,7 +4431,6 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
		  ifevent->action, ifevent->flags, ifevent->ifidx,
		  ifevent->bssidx);


	mutex_lock(&event->vif_event_lock);
	event->action = ifevent->action;
	vif = event->vif;
@@ -4453,6 +4461,11 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
			wake_up(&event->vif_wq);
		return 0;

	case BRCMF_E_IF_CHANGE:
		mutex_unlock(&event->vif_event_lock);
		wake_up(&event->vif_wq);
		return 0;

	default:
		mutex_unlock(&event->vif_event_lock);
		break;
+4 −0
Original line number Diff line number Diff line
@@ -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,
					  u8 action, ulong timeout);
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_ */