diff options
author | Hante Meuleman <meuleman@broadcom.com> | 2013-02-08 15:53:38 +0100 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-02-08 14:51:37 -0500 |
commit | 0de8aace0ff499bf1b6597e7f272961d2e335933 (patch) | |
tree | 3bcaa7edefc2ecf74448f3ffa2665de262d014da /drivers/net/wireless/brcm80211/brcmfmac/p2p.c | |
parent | d3c0b63396442d564ceb4db0dcc51e70918b9c93 (diff) |
brcmfmac: add support for P2P listen mode.
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>
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/p2p.c')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/p2p.c | 150 |
1 files changed, 124 insertions, 26 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index 25c6b7de059..ecc96f356a5 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -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 */ @@ -348,8 +343,7 @@ 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; @@ -357,9 +351,8 @@ static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p, 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); @@ -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. * @@ -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) @@ -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. @@ -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. * @@ -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)); } |