diff options
Diffstat (limited to 'drivers/net/wireless/bcmdhd/wl_cfgp2p.c')
-rw-r--r-- | drivers/net/wireless/bcmdhd/wl_cfgp2p.c | 433 |
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, ðer_bcast, ETHER_ADDR_LEN); + if (tx_dst_addr == NULL) + memcpy(&eparams->params.bssid, ðer_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); +} |