Skip to content

Commit

Permalink
brcmfmac: add support for P2P listen mode.
Browse files Browse the repository at this point in the history
With this patch a device can be put in p2p listen mode and becomes
visible for other p2p devices (via p2p_find).

Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Hante Meuleman authored and John W. Linville committed Feb 8, 2013
1 parent d3c0b63 commit 0de8aac
Show file tree
Hide file tree
Showing 6 changed files with 341 additions and 34 deletions.
13 changes: 13 additions & 0 deletions drivers/net/wireless/brcm80211/brcmfmac/dhd.h
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,19 @@ struct brcmf_sta_info_le {
__le32 rx_decrypt_failures; /* # of packet decrypted failed */
};

/*
* WLC_E_PROBRESP_MSG
* WLC_E_P2P_PROBREQ_MSG
* WLC_E_ACTION_FRAME_RX
*/
struct brcmf_rx_mgmt_data {
__be16 version;
__be16 chanspec;
__be32 rssi;
__be32 mactime;
__be32 rate;
};

/* Bus independent dongle command */
struct brcmf_dcmd {
uint cmd; /* common dongle cmd definition */
Expand Down
6 changes: 5 additions & 1 deletion drivers/net/wireless/brcm80211/brcmfmac/fweh.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ struct brcmf_event;
BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \
BRCMF_ENUM_DEF(TRACE, 52) \
BRCMF_ENUM_DEF(IF, 54) \
BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \
BRCMF_ENUM_DEF(RSSI, 56) \
BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \
BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \
Expand All @@ -96,8 +97,11 @@ struct brcmf_event;
BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \
BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \
BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \
BRCMF_ENUM_DEF(PROBERESP_MSG, 71) \
BRCMF_ENUM_DEF(P2P_PROBEREQ_MSG, 72) \
BRCMF_ENUM_DEF(DCS_REQUEST, 73) \
BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74)
BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \
BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75)

#define BRCMF_ENUM_DEF(id, val) \
BRCMF_E_##id = (val),
Expand Down
150 changes: 124 additions & 26 deletions drivers/net/wireless/brcm80211/brcmfmac/p2p.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,11 +318,6 @@ static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p)
brcmf_dbg(TRACE, "enter\n");

bss_dev = &p2p->bss_idx[P2PAPI_BSSCFG_DEVICE];
if (bss_dev->vif == NULL) {
brcmf_err("do nothing, not initialized\n");
return -EINVAL;
}

ifp = bss_dev->vif->ifp;

/* Set the discovery state to SCAN */
Expand All @@ -348,18 +343,16 @@ static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p)
*
* Initializes the discovery device and configure the virtual interface.
*/
static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p,
const u8 *ie, u32 ie_len)
static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p)
{
struct brcmf_cfg80211_vif *vif;
s32 ret = 0;

brcmf_dbg(TRACE, "enter\n");
vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
if (vif) {
brcmf_dbg(INFO,
"DISCOVERY init already done, just process IE\n");
goto set_ie;
brcmf_dbg(INFO, "DISCOVERY init already done\n");
goto exit;
}

ret = brcmf_p2p_init_discovery(p2p);
Expand All @@ -380,20 +373,36 @@ static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p,
if (ret < 0)
brcmf_err("wsec error %d\n", ret);

set_ie:
if (ie_len) {
ret = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG,
ie, ie_len);

if (ret < 0) {
brcmf_err("set probreq ie occurs error %d\n", ret);
goto exit;
}
}
exit:
return ret;
}

/**
* brcmf_p2p_configure_probereq() - Configure probe request data.
*
* @p2p: P2P specific data.
* @ie: buffer containing information elements.
* @ie_len: length of @ie buffer.
*
*/
static int brcmf_p2p_configure_probereq(struct brcmf_p2p_info *p2p,
const u8 *ie, u32 ie_len)
{
struct brcmf_cfg80211_vif *vif;
s32 err = 0;

brcmf_dbg(TRACE, "enter\n");
vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;

err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG,
ie, ie_len);

if (err < 0)
brcmf_err("set probreq ie occurs error %d\n", err);

return err;
}

/*
* brcmf_p2p_escan() - initiate a P2P scan.
*
Expand All @@ -420,9 +429,6 @@ static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans,
struct brcmf_scan_params_le *sparams;
struct brcmf_ssid ssid;

/* add padding if uneven */
if (num_chans % 2)
memsize += sizeof(__le16);
memsize += num_chans * sizeof(__le16);
memblk = kzalloc(memsize, GFP_KERNEL);
if (!memblk)
Expand Down Expand Up @@ -639,8 +645,10 @@ int brcmf_p2p_scan_prep(struct wiphy *wiphy,
clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n");

err = brcmf_p2p_enable_discovery(p2p, request->ie,
request->ie_len);
err = brcmf_p2p_enable_discovery(p2p);
if (err == 0)
err = brcmf_p2p_configure_probereq(p2p, request->ie,
request->ie_len);

/*
* override .run_escan() callback.
Expand All @@ -666,6 +674,92 @@ int brcmf_p2p_scan_prep(struct wiphy *wiphy,
return err;
}


/**
* brcmf_p2p_remain_on_channel() - put device on channel and stay there.
*
* @wiphy: wiphy device.
* @channel: channel to stay on.
* @duration: time in ms to remain on channel.
*
*/
int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *channel,
unsigned int duration, u64 *cookie)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_p2p_info *p2p = &cfg->p2p;
struct brcmf_cfg80211_vif *vif;
s32 err;
u16 chanspec;

brcmf_dbg(TRACE, "Enter, channel: %d, duration ms (%d)\n",
ieee80211_frequency_to_channel(channel->center_freq),
duration);

*cookie = 0;
err = brcmf_p2p_enable_discovery(p2p);
if (err)
goto exit;

chanspec = channel_to_chanspec(channel);
vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
err = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_LISTEN,
chanspec, (u16)duration);
if (err)
goto exit;

memcpy(&p2p->remain_on_channel, channel,
sizeof(p2p->remain_on_channel));

set_bit(BRCMF_P2P_STATUS_REMAIN_ON_CHANNEL, &p2p->status);

exit:
cfg80211_ready_on_channel(wdev, *cookie, channel, duration, GFP_KERNEL);
return err;
}


/**
* brcmf_p2p_notify_listen_complete() - p2p listen has completed.
*
* @ifp: interfac control.
* @e: event message. Not used, to make it usable for fweh event dispatcher.
* @data: payload of message. Not used.
*
*/
int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
const struct brcmf_event_msg *e,
void *data)
{
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
struct brcmf_p2p_info *p2p = &cfg->p2p;

brcmf_dbg(TRACE, "Enter\n");
if (test_and_clear_bit(BRCMF_P2P_STATUS_REMAIN_ON_CHANNEL,
&p2p->status))
cfg80211_remain_on_channel_expired(&ifp->vif->wdev, 0,
&p2p->remain_on_channel,
GFP_KERNEL);
return 0;
}


/**
* brcmf_p2p_cancel_remain_on_channel() - cancel p2p listen state.
*
* @ifp: interfac control.
*
*/
void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp)
{
if (!ifp)
return;
brcmf_p2p_set_discover_state(ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
brcmf_p2p_notify_listen_complete(ifp, NULL, NULL);
}


/**
* brcmf_p2p_attach() - attach for P2P.
*
Expand All @@ -689,7 +783,11 @@ void brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
*/
void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
{
brcmf_p2p_deinit_discovery(p2p);
if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif != NULL) {
brcmf_p2p_cancel_remain_on_channel(
p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp);
brcmf_p2p_deinit_discovery(p2p);
}
/* just set it all to zero */
memset(p2p, 0, sizeof(*p2p));
}
Expand Down
15 changes: 12 additions & 3 deletions drivers/net/wireless/brcm80211/brcmfmac/p2p.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,21 @@ struct p2p_bss {
* @BRCMF_P2P_STATUS_IF_DELETING: peer-to-peer vif delete sent to dongle.
* @BRCMF_P2P_STATUS_IF_CHANGING: peer-to-peer vif change sent to dongle.
* @BRCMF_P2P_STATUS_IF_CHANGED: peer-to-peer vif change completed on dongle.
* @BRCMF_P2P_STATUS_LISTEN_EXPIRED: listen duration expired.
* @BRCMF_P2P_STATUS_ACTION_TX_COMPLETED: action frame tx completed.
* @BRCMF_P2P_STATUS_ACTION_TX_NOACK: action frame tx not acked.
* @BRCMF_P2P_STATUS_GO_NEG_PHASE: P2P GO negotiation ongoing.
* @BRCMF_P2P_STATUS_REMAIN_ON_CHANNEL: P2P listen, remaining on channel.
*/
enum brcmf_p2p_status {
BRCMF_P2P_STATUS_IF_ADD = 0,
BRCMF_P2P_STATUS_IF_DEL,
BRCMF_P2P_STATUS_IF_DELETING,
BRCMF_P2P_STATUS_IF_CHANGING,
BRCMF_P2P_STATUS_IF_CHANGED,
BRCMF_P2P_STATUS_LISTEN_EXPIRED,
BRCMF_P2P_STATUS_ACTION_TX_COMPLETED,
BRCMF_P2P_STATUS_ACTION_TX_NOACK,
BRCMF_P2P_STATUS_GO_NEG_PHASE
BRCMF_P2P_STATUS_GO_NEG_PHASE,
BRCMF_P2P_STATUS_REMAIN_ON_CHANNEL
};

/**
Expand All @@ -88,6 +88,7 @@ enum brcmf_p2p_status {
* @listen_timer: timer for @WL_P2P_DISC_ST_LISTEN discover state.
* @ssid: ssid for P2P GO.
* @listen_channel: channel for @WL_P2P_DISC_ST_LISTEN discover state.
* @remain_on_channel: contains copy of struct used by cfg80211.
*/
struct brcmf_p2p_info {
struct brcmf_cfg80211_info *cfg;
Expand All @@ -98,6 +99,7 @@ struct brcmf_p2p_info {
struct timer_list listen_timer;
struct brcmf_ssid ssid;
u8 listen_channel;
struct ieee80211_channel remain_on_channel;
};

void brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg);
Expand All @@ -110,5 +112,12 @@ 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,
struct cfg80211_scan_request *request);
int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *channel,
unsigned int duration, u64 *cookie);
int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
const struct brcmf_event_msg *e,
void *data);
void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp);

#endif /* WL_CFGP2P_H_ */
Loading

0 comments on commit 0de8aac

Please sign in to comment.