aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcmdhd/wl_cfgp2p.c')
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.c433
1 files changed, 258 insertions, 175 deletions
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
index 7a9cbea..00334f5 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: wl_cfgp2p.c 358702 2012-09-25 06:48:56Z $
+ * $Id: wl_cfgp2p.c 391443 2013-03-18 07:53:46Z $
*
*/
#include <typedefs.h>
@@ -53,7 +53,7 @@ static bool
wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
static u32
-wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 bssidx, s32 pktflag,
+wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 pktflag,
s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd);
static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev);
@@ -109,11 +109,6 @@ bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len)
return false;
}
-/*
-* Currently Action frame just pass to P2P interface regardless real dst.
-* but GAS Action can be used for Hotspot2.0 as well
-* Need to distingush that it's for P2P or HS20
-*/
#ifdef WL11U
#define GAS_RESP_LEN 2
#define DOUBLE_TLV_BODY_OFF 4
@@ -185,9 +180,9 @@ bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len)
return true;
else
return false;
-#endif /* WLC11U */
+#endif /* WL11U */
}
-void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len)
+void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel)
{
wifi_p2p_pub_act_frame_t *pact_frm;
wifi_p2p_action_frame_t *act_frm;
@@ -199,44 +194,44 @@ void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len)
pact_frm = (wifi_p2p_pub_act_frame_t *)frame;
switch (pact_frm->subtype) {
case P2P_PAF_GON_REQ:
- CFGP2P_ACTION(("%s P2P Group Owner Negotiation Req Frame\n",
- (tx)? "TX": "RX"));
+ CFGP2P_ACTION(("%s P2P Group Owner Negotiation Req Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
break;
case P2P_PAF_GON_RSP:
- CFGP2P_ACTION(("%s P2P Group Owner Negotiation Rsp Frame\n",
- (tx)? "TX": "RX"));
+ CFGP2P_ACTION(("%s P2P Group Owner Negotiation Rsp Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
break;
case P2P_PAF_GON_CONF:
- CFGP2P_ACTION(("%s P2P Group Owner Negotiation Confirm Frame\n",
- (tx)? "TX": "RX"));
+ CFGP2P_ACTION(("%s P2P Group Owner Negotiation Confirm Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
break;
case P2P_PAF_INVITE_REQ:
- CFGP2P_ACTION(("%s P2P Invitation Request Frame\n",
- (tx)? "TX": "RX"));
+ CFGP2P_ACTION(("%s P2P Invitation Request Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
break;
case P2P_PAF_INVITE_RSP:
- CFGP2P_ACTION(("%s P2P Invitation Response Frame\n",
- (tx)? "TX": "RX"));
+ CFGP2P_ACTION(("%s P2P Invitation Response Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
break;
case P2P_PAF_DEVDIS_REQ:
- CFGP2P_ACTION(("%s P2P Device Discoverability Request Frame\n",
- (tx)? "TX": "RX"));
+ CFGP2P_ACTION(("%s P2P Device Discoverability Request Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
break;
case P2P_PAF_DEVDIS_RSP:
- CFGP2P_ACTION(("%s P2P Device Discoverability Response Frame\n",
- (tx)? "TX": "RX"));
+ CFGP2P_ACTION(("%s P2P Device Discoverability Response Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
break;
case P2P_PAF_PROVDIS_REQ:
- CFGP2P_ACTION(("%s P2P Provision Discovery Request Frame\n",
- (tx)? "TX": "RX"));
+ CFGP2P_ACTION(("%s P2P Provision Discovery Request Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
break;
case P2P_PAF_PROVDIS_RSP:
- CFGP2P_ACTION(("%s P2P Provision Discovery Response Frame\n",
- (tx)? "TX": "RX"));
+ CFGP2P_ACTION(("%s P2P Provision Discovery Response Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
break;
default:
- CFGP2P_ACTION(("%s Unknown P2P Public Action Frame\n",
- (tx)? "TX": "RX"));
+ CFGP2P_ACTION(("%s Unknown P2P Public Action Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
}
@@ -244,48 +239,48 @@ void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len)
act_frm = (wifi_p2p_action_frame_t *)frame;
switch (act_frm->subtype) {
case P2P_AF_NOTICE_OF_ABSENCE:
- CFGP2P_ACTION(("%s P2P Notice of Absence Frame\n",
- (tx)? "TX": "RX"));
+ CFGP2P_ACTION(("%s P2P Notice of Absence Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
break;
case P2P_AF_PRESENCE_REQ:
- CFGP2P_ACTION(("%s P2P Presence Request Frame\n",
- (tx)? "TX": "RX"));
+ CFGP2P_ACTION(("%s P2P Presence Request Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
break;
case P2P_AF_PRESENCE_RSP:
- CFGP2P_ACTION(("%s P2P Presence Response Frame\n",
- (tx)? "TX": "RX"));
+ CFGP2P_ACTION(("%s P2P Presence Response Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
break;
case P2P_AF_GO_DISC_REQ:
- CFGP2P_ACTION(("%s P2P Discoverability Request Frame\n",
- (tx)? "TX": "RX"));
+ CFGP2P_ACTION(("%s P2P Discoverability Request Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
break;
default:
- CFGP2P_ACTION(("%s Unknown P2P Action Frame\n",
- (tx)? "TX": "RX"));
+ CFGP2P_ACTION(("%s Unknown P2P Action Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
}
} else if (wl_cfgp2p_is_gas_action(frame, frame_len)) {
sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame;
switch (sd_act_frm->action) {
case P2PSD_ACTION_ID_GAS_IREQ:
- CFGP2P_ACTION(("%s P2P GAS Initial Request\n",
- (tx)? "TX" : "RX"));
+ CFGP2P_ACTION(("%s P2P GAS Initial Request,"
+ " channel=%d\n", (tx)? "TX" : "RX", channel));
break;
case P2PSD_ACTION_ID_GAS_IRESP:
- CFGP2P_ACTION(("%s P2P GAS Initial Response\n",
- (tx)? "TX" : "RX"));
+ CFGP2P_ACTION(("%s P2P GAS Initial Response,"
+ " channel=%d\n", (tx)? "TX" : "RX", channel));
break;
case P2PSD_ACTION_ID_GAS_CREQ:
- CFGP2P_ACTION(("%s P2P GAS Comback Request\n",
- (tx)? "TX" : "RX"));
+ CFGP2P_ACTION(("%s P2P GAS Comback Request,"
+ " channel=%d\n", (tx)? "TX" : "RX", channel));
break;
case P2PSD_ACTION_ID_GAS_CRESP:
- CFGP2P_ACTION(("%s P2P GAS Comback Response\n",
- (tx)? "TX" : "RX"));
+ CFGP2P_ACTION(("%s P2P GAS Comback Response,"
+ " channel=%d\n", (tx)? "TX" : "RX", channel));
break;
default:
- CFGP2P_ACTION(("%s Unknown P2P GAS Frame\n",
- (tx)? "TX" : "RX"));
+ CFGP2P_ACTION(("%s Unknown P2P GAS Frame,"
+ " channel=%d\n", (tx)? "TX" : "RX", channel));
}
@@ -360,7 +355,11 @@ wl_cfgp2p_set_firm_p2p(struct wl_priv *wl)
s32 ret = BCME_OK;
s32 val = 0;
/* Do we have to check whether APSTA is enabled or not ? */
- wldev_iovar_getint(ndev, "apsta", &val);
+ ret = wldev_iovar_getint(ndev, "apsta", &val);
+ if (ret < 0) {
+ CFGP2P_ERR(("get apsta error %d\n", ret));
+ return ret;
+ }
if (val == 0) {
val = 1;
ret = wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true);
@@ -566,12 +565,12 @@ wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms,
struct net_device *dev;
CFGP2P_DBG(("enter\n"));
- if (unlikely(bssidx == WL_INVALID || bssidx >= P2PAPI_BSSCFG_MAX)) {
+ if (unlikely(bssidx == WL_INVALID)) {
CFGP2P_ERR((" %d index out of range\n", bssidx));
return -1;
}
- dev = wl_to_p2p_bss_ndev(wl, bssidx);
+ dev = wl_cfgp2p_find_ndev(wl, bssidx);
if (unlikely(dev == NULL)) {
CFGP2P_ERR(("bssidx %d is not assigned\n", bssidx));
return BCME_NOTFOUND;
@@ -677,7 +676,7 @@ wl_cfgp2p_deinit_discovery(struct wl_priv *wl)
/* Clear the saved bsscfg index of the discovery BSSCFG to indicate we
* have no discovery BSS.
*/
- wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0;
+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = WL_INVALID;
wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL;
return ret;
@@ -695,8 +694,14 @@ wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev,
const u8 *ie, u32 ie_len)
{
s32 ret = BCME_OK;
- s32 bssidx = (wl_to_prmry_ndev(wl) == dev) ?
- wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) : wl_cfgp2p_find_idx(wl, dev);
+ s32 bssidx;
+
+ if (wl_to_prmry_ndev(wl) == dev) {
+ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
+ } else if (wl_cfgp2p_find_idx(wl, dev, &bssidx) != BCME_OK) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ return BCME_ERROR;
+ }
if (wl_get_p2p_status(wl, DISCOVERY_ON)) {
CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n"));
goto set_ie;
@@ -777,7 +782,7 @@ exit:
s32
wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
u32 num_chans, u16 *channels,
- s32 search_state, u16 action, u32 bssidx)
+ s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr)
{
s32 ret = BCME_OK;
s32 memsize;
@@ -804,7 +809,7 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
memsize = sizeof(wl_p2p_scan_t) + eparams_size;
memblk = scanparambuf;
if (memsize > sizeof(scanparambuf)) {
- CFGP2P_ERR((" scanpar buf too small (%u > %u)\n",
+ CFGP2P_ERR((" scanpar buf too small (%u > %zu)\n",
memsize, sizeof(scanparambuf)));
return -1;
}
@@ -816,8 +821,9 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
* because dongle use P2P WILDCARD internally by default
*/
wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx);
- ssid.SSID_len = htod32(0);
-
+ /* use null ssid */
+ ssid.SSID_len = 0;
+ memset(&ssid.SSID, 0, sizeof(ssid.SSID));
} else if (search_state == WL_P2P_DISC_ST_SCAN) {
/* SCAN STATE 802.11 SCAN
* WFD Supplicant has p2p_find command with (type=progressive, type= full)
@@ -825,12 +831,12 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
* we have to set ssid to P2P WILDCARD because
* we just do broadcast scan unless setting SSID
*/
- strncpy(ssid.SSID, WL_P2P_WILDCARD_SSID, sizeof(ssid.SSID) - 1);
- ssid.SSID[sizeof(ssid.SSID) - 1] = 0;
- ssid.SSID_len = htod32(WL_P2P_WILDCARD_SSID_LEN);
wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx);
- }
- else {
+ /* use wild card ssid */
+ ssid.SSID_len = WL_P2P_WILDCARD_SSID_LEN;
+ memset(&ssid.SSID, 0, sizeof(ssid.SSID));
+ memcpy(&ssid.SSID, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN);
+ } else {
CFGP2P_ERR((" invalid search state %d\n", search_state));
return -1;
}
@@ -847,7 +853,11 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
else
eparams->params.scan_type = DOT11_SCANTYPE_PASSIVE;
- memcpy(&eparams->params.bssid, &ether_bcast, ETHER_ADDR_LEN);
+ if (tx_dst_addr == NULL)
+ memcpy(&eparams->params.bssid, &ether_bcast, ETHER_ADDR_LEN);
+ else
+ memcpy(&eparams->params.bssid, tx_dst_addr, ETHER_ADDR_LEN);
+
if (ssid.SSID_len)
memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t));
@@ -887,11 +897,11 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
}
eparams->version = htod32(ESCAN_REQ_VERSION);
eparams->action = htod16(action);
-#if defined(DUAL_ESCAN_RESULT_BUFFER)
+#if defined(CUSTOMER_HW4) && defined(DUAL_ESCAN_RESULT_BUFFER)
eparams->sync_id = wl->escan_info.cur_sync_id;
#else
eparams->sync_id = htod16(0x1234);
-#endif
+#endif /* CUSTOMER_HW4 && DUAL_ESCAN_RESULT_BUFFER */
CFGP2P_INFO(("SCAN CHANNELS : "));
for (i = 0; i < num_chans; i++) {
@@ -917,7 +927,7 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
*/
s32
wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev,
- s32 bssidx, s32 channel)
+ s32 bssidx, s32 channel, struct ether_addr *tx_dst_addr)
{
s32 ret = 0;
u32 chan_cnt = 0;
@@ -925,8 +935,8 @@ wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev,
if (!p2p_is_on(wl) || ndev == NULL || bssidx == WL_INVALID)
return -BCME_ERROR;
CFGP2P_ERR((" Enter\n"));
- if (bssidx == P2PAPI_BSSCFG_PRIMARY)
- bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
+ if (bssidx == wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY))
+ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
if (channel)
chan_cnt = AF_PEER_SEARCH_CNT;
else
@@ -950,7 +960,7 @@ wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev,
}
ret = wl_cfgp2p_escan(wl, ndev, true, chan_cnt,
default_chan_list, WL_P2P_DISC_ST_SEARCH,
- WL_SCAN_ACTION_START, bssidx);
+ WL_SCAN_ACTION_START, bssidx, tx_dst_addr);
kfree(default_chan_list);
exit:
return ret;
@@ -966,7 +976,9 @@ exit:
#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
(const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P)
/* Check whether the given IE looks like WFA WFDisplay IE. */
+#ifndef WFA_OUI_TYPE_WFD
#define WFA_OUI_TYPE_WFD 0x0a /* WiFi Display OUI TYPE */
+#endif
#define wl_cfgp2p_is_wfd_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
(const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_WFD)
@@ -1055,45 +1067,50 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
struct parsed_vndr_ies new_vndr_ies;
s32 i;
u8 *ptr;
+ s32 type = -1;
s32 remained_buf_len;
-
#define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie)
#define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len)
memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf));
curr_ie_buf = g_mgmt_ie_buf;
CFGP2P_DBG((" bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag));
if (wl->p2p != NULL) {
+ if (wl_cfgp2p_find_type(wl, bssidx, &type)) {
+ CFGP2P_ERR(("cannot find type from bssidx : %d\n", bssidx));
+ return BCME_ERROR;
+ }
+
switch (pktflag) {
case VNDR_IE_PRBREQ_FLAG :
- mgmt_ie_buf = IE_TYPE(probe_req, bssidx);
- mgmt_ie_len = &IE_TYPE_LEN(probe_req, bssidx);
- mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, bssidx));
+ mgmt_ie_buf = IE_TYPE(probe_req, type);
+ mgmt_ie_len = &IE_TYPE_LEN(probe_req, type);
+ mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, type));
break;
case VNDR_IE_PRBRSP_FLAG :
- mgmt_ie_buf = IE_TYPE(probe_res, bssidx);
- mgmt_ie_len = &IE_TYPE_LEN(probe_res, bssidx);
- mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, bssidx));
+ mgmt_ie_buf = IE_TYPE(probe_res, type);
+ mgmt_ie_len = &IE_TYPE_LEN(probe_res, type);
+ mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, type));
break;
case VNDR_IE_ASSOCREQ_FLAG :
- mgmt_ie_buf = IE_TYPE(assoc_req, bssidx);
- mgmt_ie_len = &IE_TYPE_LEN(assoc_req, bssidx);
- mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, bssidx));
+ mgmt_ie_buf = IE_TYPE(assoc_req, type);
+ mgmt_ie_len = &IE_TYPE_LEN(assoc_req, type);
+ mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, type));
break;
case VNDR_IE_ASSOCRSP_FLAG :
- mgmt_ie_buf = IE_TYPE(assoc_res, bssidx);
- mgmt_ie_len = &IE_TYPE_LEN(assoc_res, bssidx);
- mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, bssidx));
+ mgmt_ie_buf = IE_TYPE(assoc_res, type);
+ mgmt_ie_len = &IE_TYPE_LEN(assoc_res, type);
+ mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, type));
break;
case VNDR_IE_BEACON_FLAG :
- mgmt_ie_buf = IE_TYPE(beacon, bssidx);
- mgmt_ie_len = &IE_TYPE_LEN(beacon, bssidx);
- mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, bssidx));
+ mgmt_ie_buf = IE_TYPE(beacon, type);
+ mgmt_ie_len = &IE_TYPE_LEN(beacon, type);
+ mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, type));
break;
default:
mgmt_ie_buf = NULL;
mgmt_ie_len = NULL;
CFGP2P_ERR(("not suitable type\n"));
- return -1;
+ return BCME_ERROR;
}
} else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
switch (pktflag) {
@@ -1111,7 +1128,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
mgmt_ie_buf = NULL;
mgmt_ie_len = NULL;
CFGP2P_ERR(("not suitable type\n"));
- return -1;
+ return BCME_ERROR;
}
bssidx = 0;
} else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) {
@@ -1130,12 +1147,12 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
mgmt_ie_buf = NULL;
mgmt_ie_len = NULL;
CFGP2P_ERR(("not suitable type\n"));
- return -1;
+ return BCME_ERROR;
}
bssidx = 0;
} else {
CFGP2P_ERR(("not suitable type\n"));
- return -1;
+ return BCME_ERROR;
}
if (vndr_ie_len > mgmt_ie_buf_len) {
@@ -1181,7 +1198,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
vndrie_info->vndrie.oui[2]));
del_add_ie_buf_len = wl_cfgp2p_vndr_ie(wl, curr_ie_buf,
- bssidx, pktflag, vndrie_info->vndrie.oui,
+ pktflag, vndrie_info->vndrie.oui,
vndrie_info->vndrie.id,
vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
@@ -1211,7 +1228,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
vndrie_info->vndrie.oui[2]));
del_add_ie_buf_len = wl_cfgp2p_vndr_ie(wl, curr_ie_buf,
- bssidx, pktflag, vndrie_info->vndrie.oui,
+ pktflag, vndrie_info->vndrie.oui,
vndrie_info->vndrie.id,
vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
@@ -1262,21 +1279,37 @@ exit:
s32
wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx)
{
+
+ s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG,
+ VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
+ s32 index = -1;
+ s32 type = -1;
+ struct net_device *ndev = wl_cfgp2p_find_ndev(wl, bssidx);
#define INIT_IE(IE_TYPE, BSS_TYPE) \
do { \
memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \
sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \
wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \
} while (0);
- if (bssidx < 0) {
- CFGP2P_ERR(("invalid bssidx\n"));
+
+ if (bssidx < 0 || ndev == NULL) {
+ CFGP2P_ERR(("invalid %s\n", (bssidx < 0) ? "bssidx" : "ndev"));
return BCME_BADARG;
}
- INIT_IE(probe_req, bssidx);
- INIT_IE(probe_res, bssidx);
- INIT_IE(assoc_req, bssidx);
- INIT_IE(assoc_res, bssidx);
- INIT_IE(beacon, bssidx);
+
+ if (wl_cfgp2p_find_type(wl, bssidx, &type)) {
+ CFGP2P_ERR(("invalid argument\n"));
+ return BCME_BADARG;
+ }
+ for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
+ /* clean up vndr ies in dongle */
+ wl_cfgp2p_set_management_ie(wl, ndev, bssidx, vndrie_flag[index], NULL, 0);
+ }
+ INIT_IE(probe_req, type);
+ INIT_IE(probe_res, type);
+ INIT_IE(assoc_req, type);
+ INIT_IE(assoc_res, type);
+ INIT_IE(beacon, type);
return BCME_OK;
}
@@ -1358,7 +1391,7 @@ wl_cfgp2p_find_wfdie(u8 *parse, u32 len)
return NULL;
}
static u32
-wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 bssidx, s32 pktflag,
+wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 pktflag,
s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd)
{
vndr_ie_setbuf_t hdr; /* aligned temporary vndr_ie buffer header */
@@ -1415,33 +1448,82 @@ wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 bssidx, s32 pktflag,
* Parameters:
* @wl : wl_private data
* @ndev : net device to search bssidx
- * Returns bssidx for ndev
+ * @bssidx : output arg to store bssidx of the bsscfg of firmware.
+ * Returns error
*/
s32
-wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev)
+wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev, s32 *bssidx)
{
u32 i;
- s32 index = -1;
-
- if (ndev == NULL) {
- CFGP2P_ERR((" ndev is NULL\n"));
- goto exit;
+ if (ndev == NULL || bssidx == NULL) {
+ CFGP2P_ERR((" argument is invalid\n"));
+ return BCME_BADARG;
}
if (!wl->p2p_supported) {
- return P2PAPI_BSSCFG_PRIMARY;
+ *bssidx = P2PAPI_BSSCFG_PRIMARY;
+ return BCME_OK;
}
+ /* we cannot find the bssidx of DISCOVERY BSS
+ * because the ndev is same with ndev of PRIMARY BSS.
+ */
for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
if (ndev == wl_to_p2p_bss_ndev(wl, i)) {
- index = wl_to_p2p_bss_bssidx(wl, i);
+ *bssidx = wl_to_p2p_bss_bssidx(wl, i);
+ return BCME_OK;
+ }
+ }
+ return BCME_BADARG;
+}
+struct net_device *
+wl_cfgp2p_find_ndev(struct wl_priv *wl, s32 bssidx)
+{
+ u32 i;
+ struct net_device *ndev = NULL;
+ if (bssidx < 0) {
+ CFGP2P_ERR((" bsscfg idx is invalid\n"));
+ goto exit;
+ }
+
+ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
+ if (bssidx == wl_to_p2p_bss_bssidx(wl, i)) {
+ ndev = wl_to_p2p_bss_ndev(wl, i);
break;
}
}
- if (index == -1)
- return P2PAPI_BSSCFG_PRIMARY;
+
exit:
- return index;
+ return ndev;
}
/*
+ * Search the driver array idx based on bssidx argument
+ * Parameters:
+ * @wl : wl_private data
+ * @bssidx : bssidx which indicate bsscfg->idx of firmware.
+ * @type : output arg to store array idx of p2p->bss.
+ * Returns error
+ */
+
+s32
+wl_cfgp2p_find_type(struct wl_priv *wl, s32 bssidx, s32 *type)
+{
+ u32 i;
+ if (bssidx < 0 || type == NULL) {
+ CFGP2P_ERR((" argument is invalid\n"));
+ goto exit;
+ }
+
+ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
+ if (bssidx == wl_to_p2p_bss_bssidx(wl, i)) {
+ *type = i;
+ return BCME_OK;
+ }
+ }
+
+exit:
+ return BCME_BADARG;
+}
+
+/*
* Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE
*/
s32
@@ -1657,24 +1739,29 @@ wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev,
u32 event_type = ntoh32(e->event_type);
u32 status = ntoh32(e->status);
CFGP2P_DBG((" Enter\n"));
- if (event_type == WLC_E_ACTION_FRAME_COMPLETE) {
+ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+ if (event_type == WLC_E_ACTION_FRAME_COMPLETE) {
- CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status));
- if (status == WLC_E_STATUS_SUCCESS) {
- wl_set_p2p_status(wl, ACTION_TX_COMPLETED);
- CFGP2P_DBG(("WLC_E_ACTION_FRAME_COMPLETE : ACK\n"));
- }
- else {
- wl_set_p2p_status(wl, ACTION_TX_NOACK);
- CFGP2P_INFO(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n"));
- wl_stop_wait_next_action_frame(wl, ndev);
- }
- } else {
- CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received,"
- "status : %d\n", status));
+ CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status));
+ if (status == WLC_E_STATUS_SUCCESS) {
+ wl_set_p2p_status(wl, ACTION_TX_COMPLETED);
+ CFGP2P_DBG(("WLC_E_ACTION_FRAME_COMPLETE : ACK\n"));
- if (wl_get_drv_status_all(wl, SENDING_ACT_FRM))
- complete(&wl->send_af_done);
+ }
+ else {
+ if (!wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) {
+ wl_set_p2p_status(wl, ACTION_TX_NOACK);
+ CFGP2P_INFO(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n"));
+ wl_stop_wait_next_action_frame(wl, ndev);
+ }
+ }
+ } else {
+ CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received,"
+ "status : %d\n", status));
+
+ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM))
+ complete(&wl->send_af_done);
+ }
}
return ret;
}
@@ -1700,7 +1787,6 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev,
wl_clr_p2p_status(wl, ACTION_TX_COMPLETED);
wl_clr_p2p_status(wl, ACTION_TX_NOACK);
-#define MAX_WAIT_TIME 2000
if (bssidx == P2PAPI_BSSCFG_PRIMARY)
bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
@@ -1718,7 +1804,8 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev,
goto exit;
}
- timeout = wait_for_completion_timeout(&wl->send_af_done, msecs_to_jiffies(MAX_WAIT_TIME));
+ timeout = wait_for_completion_timeout(&wl->send_af_done,
+ msecs_to_jiffies(af_params->dwell_time + WL_AF_TX_EXTRA_TIME_MAX));
if (timeout > 0 && wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) {
CFGP2P_INFO(("tx action frame operation is completed\n"));
@@ -1733,7 +1820,6 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev,
exit:
CFGP2P_INFO((" via act frame iovar : status = %d\n", ret));
-#undef MAX_WAIT_TIME
return ret;
}
@@ -1893,10 +1979,14 @@ wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev)
s32
wl_cfgp2p_down(struct wl_priv *wl)
{
-
+ s32 i = 0, index = -1;
wl_cfgp2p_cancel_listen(wl,
wl->p2p_net ? wl->p2p_net : wl_to_prmry_ndev(wl), TRUE);
-
+ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
+ index = wl_to_p2p_bss_bssidx(wl, i);
+ if (index != WL_INVALID)
+ wl_cfgp2p_clear_management_ie(wl, index);
+ }
wl_cfgp2p_deinit_priv(wl);
return 0;
}
@@ -2042,16 +2132,10 @@ wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int
}
if ((legacy_ps != -1) && ((legacy_ps == PM_MAX) || (legacy_ps == PM_OFF))) {
-#ifdef SUPPORT_PM2_ONLY
- if (legacy_ps == PM_MAX)
- legacy_ps = PM_FAST;
-#endif
ret = wldev_ioctl(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
WLC_SET_PM, &legacy_ps, sizeof(legacy_ps), true);
if (unlikely(ret)) {
CFGP2P_ERR(("error (%d)\n", ret));
- } else {
- wl_cfg80211_update_power_mode(ndev);
}
}
else
@@ -2172,13 +2256,25 @@ wl_cfgp2p_register_ndev(struct wl_priv *wl)
{
int ret = 0;
struct net_device* net = NULL;
- struct wireless_dev *wdev;
+ struct wireless_dev *wdev = NULL;
uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 };
+ if (wl->p2p_net) {
+ CFGP2P_ERR(("p2p_net defined already.\n"));
+ return -EINVAL;
+ }
+
/* Allocate etherdev, including space for private structure */
if (!(net = alloc_etherdev(sizeof(struct wl_priv *)))) {
CFGP2P_ERR(("%s: OOM - alloc_etherdev\n", __FUNCTION__));
- goto fail;
+ return -ENODEV;
+ }
+
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (unlikely(!wdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ free_netdev(net);
+ return -ENOMEM;
}
strncpy(net->name, "p2p%d", sizeof(net->name) - 1);
@@ -2201,12 +2297,6 @@ wl_cfgp2p_register_ndev(struct wl_priv *wl)
/* Register with a dummy MAC addr */
memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
- wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
- if (unlikely(!wdev)) {
- WL_ERR(("Could not allocate wireless device\n"));
- return -ENOMEM;
- }
-
wdev->wiphy = wl->wdev->wiphy;
wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
@@ -2222,40 +2312,23 @@ wl_cfgp2p_register_ndev(struct wl_priv *wl)
/* Associate p2p0 network interface with new wdev */
wdev->netdev = net;
- /* store p2p net ptr for further reference. Note that iflist won't have this
- * entry as there corresponding firmware interface is a "Hidden" interface.
- */
- if (wl->p2p_net) {
- CFGP2P_ERR(("p2p_net defined already.\n"));
- return -EINVAL;
- } else {
- wl->p2p_wdev = wdev;
- wl->p2p_net = net;
- }
-
ret = register_netdev(net);
if (ret) {
CFGP2P_ERR((" register_netdevice failed (%d)\n", ret));
- goto fail;
+ free_netdev(net);
+ kfree(wdev);
+ return -ENODEV;
}
+ /* store p2p net ptr for further reference. Note that iflist won't have this
+ * entry as there corresponding firmware interface is a "Hidden" interface.
+ */
+ wl->p2p_wdev = wdev;
+ wl->p2p_net = net;
+
printk("%s: P2P Interface Registered\n", net->name);
return ret;
-fail:
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
- net->open = NULL;
-#else
- net->netdev_ops = NULL;
-#endif
-
- if (net) {
- unregister_netdev(net);
- free_netdev(net);
- }
-
- return -ENODEV;
}
s32
@@ -2274,7 +2347,12 @@ wl_cfgp2p_unregister_ndev(struct wl_priv *wl)
}
static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
- CFGP2P_DBG(("(%s) is not used for data operations. Droping the packet. \n", ndev->name));
+ if (skb)
+ {
+ CFGP2P_DBG(("(%s) is not used for data operations.Droping the packet.\n",
+ ndev->name));
+ dev_kfree_skb_any(skb);
+ }
return 0;
}
@@ -2350,3 +2428,8 @@ static int wl_cfgp2p_if_stop(struct net_device *net)
BIT(NL80211_IFTYPE_P2P_GO)));
return 0;
}
+
+bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops)
+{
+ return (if_ops == &wl_cfgp2p_if_ops);
+}