Path: blob/main/sys/contrib/dev/broadcom/brcm80211/brcmfmac/p2p.c
178665 views
// SPDX-License-Identifier: ISC1/*2* Copyright (c) 2012 Broadcom Corporation3*/4#include <linux/slab.h>5#include <linux/netdevice.h>6#include <linux/etherdevice.h>7#include <linux/rtnetlink.h>8#include <net/cfg80211.h>9#if defined(__FreeBSD__)10#include <linux/delay.h>11#endif1213#include <brcmu_wifi.h>14#include <brcmu_utils.h>15#include <defs.h>16#include "core.h"17#include "debug.h"18#include "fwil.h"19#include "fwil_types.h"20#include "p2p.h"21#include "cfg80211.h"22#include "feature.h"2324/* parameters used for p2p escan */25#define P2PAPI_SCAN_NPROBES 126#define P2PAPI_SCAN_DWELL_TIME_MS 8027#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 4028#define P2PAPI_SCAN_HOME_TIME_MS 6029#define P2PAPI_SCAN_NPROBS_TIME_MS 3030#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 10031#define WL_SCAN_CONNECT_DWELL_TIME_MS 20032#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 203334#define BRCMF_P2P_WILDCARD_SSID "DIRECT-"35#define BRCMF_P2P_WILDCARD_SSID_LEN (sizeof(BRCMF_P2P_WILDCARD_SSID) - 1)3637#define SOCIAL_CHAN_1 138#define SOCIAL_CHAN_2 639#define SOCIAL_CHAN_3 1140#define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \41(channel == SOCIAL_CHAN_2) || \42(channel == SOCIAL_CHAN_3))43#define BRCMF_P2P_TEMP_CHAN SOCIAL_CHAN_344#define SOCIAL_CHAN_CNT 345#define AF_PEER_SEARCH_CNT 24647#define BRCMF_SCB_TIMEOUT_VALUE 204849#define P2P_VER 9 /* P2P version: 9=WiFi P2P v1.0 */50#define P2P_PUB_AF_CATEGORY 0x0451#define P2P_PUB_AF_ACTION 0x0952#define P2P_AF_CATEGORY 0x7f53#define P2P_OUI "\x50\x6F\x9A" /* P2P OUI */54#define P2P_OUI_LEN 3 /* P2P OUI length */5556/* Action Frame Constants */57#define DOT11_ACTION_HDR_LEN 2 /* action frame category + action */58#define DOT11_ACTION_CAT_OFF 0 /* category offset */59#define DOT11_ACTION_ACT_OFF 1 /* action offset */6061#define P2P_AF_DWELL_TIME 20062#define P2P_AF_MIN_DWELL_TIME 10063#define P2P_AF_MED_DWELL_TIME 40064#define P2P_AF_LONG_DWELL_TIME 100065#define P2P_AF_TX_MAX_RETRY 566#define P2P_AF_MAX_WAIT_TIME msecs_to_jiffies(2000)67#define P2P_INVALID_CHANNEL -168#define P2P_CHANNEL_SYNC_RETRY 569#define P2P_AF_FRM_SCAN_MAX_WAIT msecs_to_jiffies(450)70#define P2P_DEFAULT_SLEEP_TIME_VSDB 20071#define P2P_AF_RETRY_DELAY_TIME 407273/* WiFi P2P Public Action Frame OUI Subtypes */74#define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */75#define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */76#define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */77#define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */78#define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */79#define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */80#define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */81#define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */82#define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Response */83#define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */8485/* WiFi P2P Action Frame OUI Subtypes */86#define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */87#define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */88#define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */89#define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */9091/* P2P Service Discovery related */92#define P2PSD_ACTION_CATEGORY 0x04 /* Public action frame */93#define P2PSD_ACTION_ID_GAS_IREQ 0x0a /* GAS Initial Request AF */94#define P2PSD_ACTION_ID_GAS_IRESP 0x0b /* GAS Initial Response AF */95#define P2PSD_ACTION_ID_GAS_CREQ 0x0c /* GAS Comeback Request AF */96#define P2PSD_ACTION_ID_GAS_CRESP 0x0d /* GAS Comeback Response AF */9798#define BRCMF_P2P_DISABLE_TIMEOUT msecs_to_jiffies(500)99100/* Mask for retry counter of custom dwell time */101#define CUSTOM_RETRY_MASK 0xff000000102/**103* struct brcmf_p2p_disc_st_le - set discovery state in firmware.104*105* @state: requested discovery state (see enum brcmf_p2p_disc_state).106* @chspec: channel parameter for %WL_P2P_DISC_ST_LISTEN state.107* @dwell: dwell time in ms for %WL_P2P_DISC_ST_LISTEN state.108*/109struct brcmf_p2p_disc_st_le {110u8 state;111__le16 chspec;112__le16 dwell;113};114115/**116* enum brcmf_p2p_disc_state - P2P discovery state values117*118* @WL_P2P_DISC_ST_SCAN: P2P discovery with wildcard SSID and P2P IE.119* @WL_P2P_DISC_ST_LISTEN: P2P discovery off-channel for specified time.120* @WL_P2P_DISC_ST_SEARCH: P2P discovery with P2P wildcard SSID and P2P IE.121*/122enum brcmf_p2p_disc_state {123WL_P2P_DISC_ST_SCAN,124WL_P2P_DISC_ST_LISTEN,125WL_P2P_DISC_ST_SEARCH126};127128/**129* struct brcmf_p2p_scan_le - P2P specific scan request.130*131* @type: type of scan method requested (values: 'E' or 'S').132* @reserved: reserved (ignored).133* @eparams: parameters used for type 'E'.134* @sparams: parameters used for type 'S'.135*/136struct brcmf_p2p_scan_le {137u8 type;138u8 reserved[3];139union {140struct brcmf_escan_params_le eparams;141struct brcmf_scan_params_le sparams;142};143};144145/**146* struct brcmf_p2p_pub_act_frame - WiFi P2P Public Action Frame147*148* @category: P2P_PUB_AF_CATEGORY149* @action: P2P_PUB_AF_ACTION150* @oui: P2P_OUI151* @oui_type: OUI type - P2P_VER152* @subtype: OUI subtype - P2P_TYPE_*153* @dialog_token: nonzero, identifies req/rsp transaction154* @elts: Variable length information elements.155*/156struct brcmf_p2p_pub_act_frame {157u8 category;158u8 action;159u8 oui[3];160u8 oui_type;161u8 subtype;162u8 dialog_token;163u8 elts[];164};165166/**167* struct brcmf_p2p_action_frame - WiFi P2P Action Frame168*169* @category: P2P_AF_CATEGORY170* @oui: OUI - P2P_OUI171* @type: OUI Type - P2P_VER172* @subtype: OUI Subtype - P2P_AF_*173* @dialog_token: nonzero, identifies req/resp tranaction174* @elts: Variable length information elements.175*/176struct brcmf_p2p_action_frame {177u8 category;178u8 oui[3];179u8 type;180u8 subtype;181u8 dialog_token;182u8 elts[];183};184185/**186* struct brcmf_p2psd_gas_pub_act_frame - Wi-Fi GAS Public Action Frame187*188* @category: 0x04 Public Action Frame189* @action: 0x6c Advertisement Protocol190* @dialog_token: nonzero, identifies req/rsp transaction191* @query_data: Query Data. SD gas ireq SD gas iresp192*/193struct brcmf_p2psd_gas_pub_act_frame {194u8 category;195u8 action;196u8 dialog_token;197u8 query_data[];198};199200/**201* struct brcmf_config_af_params - Action Frame Parameters for tx.202*203* @mpc_onoff: To make sure to send successfully action frame, we have to204* turn off mpc 0: off, 1: on, (-1): do nothing205* @search_channel: 1: search peer's channel to send af206* @extra_listen: keep the dwell time to get af response frame.207*/208struct brcmf_config_af_params {209s32 mpc_onoff;210bool search_channel;211bool extra_listen;212};213214/**215* brcmf_p2p_is_pub_action() - true if p2p public type frame.216*217* @frame: action frame data.218* @frame_len: length of action frame data.219*220* Determine if action frame is p2p public action type221*/222static bool brcmf_p2p_is_pub_action(void *frame, u32 frame_len)223{224struct brcmf_p2p_pub_act_frame *pact_frm;225226if (frame == NULL)227return false;228229pact_frm = (struct brcmf_p2p_pub_act_frame *)frame;230if (frame_len < sizeof(*pact_frm))231return false;232233if (pact_frm->category == P2P_PUB_AF_CATEGORY &&234pact_frm->action == P2P_PUB_AF_ACTION &&235pact_frm->oui_type == P2P_VER &&236memcmp(pact_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0)237return true;238239return false;240}241242/**243* brcmf_p2p_is_p2p_action() - true if p2p action type frame.244*245* @frame: action frame data.246* @frame_len: length of action frame data.247*248* Determine if action frame is p2p action type249*/250static bool brcmf_p2p_is_p2p_action(void *frame, u32 frame_len)251{252struct brcmf_p2p_action_frame *act_frm;253254if (frame == NULL)255return false;256257act_frm = (struct brcmf_p2p_action_frame *)frame;258if (frame_len < sizeof(*act_frm))259return false;260261if (act_frm->category == P2P_AF_CATEGORY &&262act_frm->type == P2P_VER &&263memcmp(act_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0)264return true;265266return false;267}268269/**270* brcmf_p2p_is_gas_action() - true if p2p gas action type frame.271*272* @frame: action frame data.273* @frame_len: length of action frame data.274*275* Determine if action frame is p2p gas action type276*/277static bool brcmf_p2p_is_gas_action(void *frame, u32 frame_len)278{279struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;280281if (frame == NULL)282return false;283284sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;285if (frame_len < sizeof(*sd_act_frm))286return false;287288if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)289return false;290291if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ ||292sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP ||293sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ ||294sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP)295return true;296297return false;298}299300/**301* brcmf_p2p_print_actframe() - debug print routine.302*303* @tx: Received or to be transmitted304* @frame: action frame data.305* @frame_len: length of action frame data.306*307* Print information about the p2p action frame308*/309310#ifdef DEBUG311312static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len)313{314struct brcmf_p2p_pub_act_frame *pact_frm;315struct brcmf_p2p_action_frame *act_frm;316struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;317318if (!frame || frame_len <= 2)319return;320321if (brcmf_p2p_is_pub_action(frame, frame_len)) {322pact_frm = (struct brcmf_p2p_pub_act_frame *)frame;323switch (pact_frm->subtype) {324case P2P_PAF_GON_REQ:325brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Req Frame\n",326(tx) ? "TX" : "RX");327break;328case P2P_PAF_GON_RSP:329brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Rsp Frame\n",330(tx) ? "TX" : "RX");331break;332case P2P_PAF_GON_CONF:333brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Confirm Frame\n",334(tx) ? "TX" : "RX");335break;336case P2P_PAF_INVITE_REQ:337brcmf_dbg(TRACE, "%s P2P Invitation Request Frame\n",338(tx) ? "TX" : "RX");339break;340case P2P_PAF_INVITE_RSP:341brcmf_dbg(TRACE, "%s P2P Invitation Response Frame\n",342(tx) ? "TX" : "RX");343break;344case P2P_PAF_DEVDIS_REQ:345brcmf_dbg(TRACE, "%s P2P Device Discoverability Request Frame\n",346(tx) ? "TX" : "RX");347break;348case P2P_PAF_DEVDIS_RSP:349brcmf_dbg(TRACE, "%s P2P Device Discoverability Response Frame\n",350(tx) ? "TX" : "RX");351break;352case P2P_PAF_PROVDIS_REQ:353brcmf_dbg(TRACE, "%s P2P Provision Discovery Request Frame\n",354(tx) ? "TX" : "RX");355break;356case P2P_PAF_PROVDIS_RSP:357brcmf_dbg(TRACE, "%s P2P Provision Discovery Response Frame\n",358(tx) ? "TX" : "RX");359break;360default:361brcmf_dbg(TRACE, "%s Unknown P2P Public Action Frame\n",362(tx) ? "TX" : "RX");363break;364}365} else if (brcmf_p2p_is_p2p_action(frame, frame_len)) {366act_frm = (struct brcmf_p2p_action_frame *)frame;367switch (act_frm->subtype) {368case P2P_AF_NOTICE_OF_ABSENCE:369brcmf_dbg(TRACE, "%s P2P Notice of Absence Frame\n",370(tx) ? "TX" : "RX");371break;372case P2P_AF_PRESENCE_REQ:373brcmf_dbg(TRACE, "%s P2P Presence Request Frame\n",374(tx) ? "TX" : "RX");375break;376case P2P_AF_PRESENCE_RSP:377brcmf_dbg(TRACE, "%s P2P Presence Response Frame\n",378(tx) ? "TX" : "RX");379break;380case P2P_AF_GO_DISC_REQ:381brcmf_dbg(TRACE, "%s P2P Discoverability Request Frame\n",382(tx) ? "TX" : "RX");383break;384default:385brcmf_dbg(TRACE, "%s Unknown P2P Action Frame\n",386(tx) ? "TX" : "RX");387}388389} else if (brcmf_p2p_is_gas_action(frame, frame_len)) {390sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;391switch (sd_act_frm->action) {392case P2PSD_ACTION_ID_GAS_IREQ:393brcmf_dbg(TRACE, "%s P2P GAS Initial Request\n",394(tx) ? "TX" : "RX");395break;396case P2PSD_ACTION_ID_GAS_IRESP:397brcmf_dbg(TRACE, "%s P2P GAS Initial Response\n",398(tx) ? "TX" : "RX");399break;400case P2PSD_ACTION_ID_GAS_CREQ:401brcmf_dbg(TRACE, "%s P2P GAS Comeback Request\n",402(tx) ? "TX" : "RX");403break;404case P2PSD_ACTION_ID_GAS_CRESP:405brcmf_dbg(TRACE, "%s P2P GAS Comeback Response\n",406(tx) ? "TX" : "RX");407break;408default:409brcmf_dbg(TRACE, "%s Unknown P2P GAS Frame\n",410(tx) ? "TX" : "RX");411break;412}413}414}415416#else417418static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len)419{420}421422#endif423424425/**426* brcmf_p2p_set_firmware() - prepare firmware for peer-to-peer operation.427*428* @ifp: ifp to use for iovars (primary).429* @p2p_mac: mac address to configure for p2p_da_override430*/431static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac)432{433struct brcmf_pub *drvr = ifp->drvr;434s32 ret = 0;435436brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);437brcmf_fil_iovar_int_set(ifp, "apsta", 1);438brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);439440/* In case of COB type, firmware has default mac address441* After Initializing firmware, we have to set current mac address to442* firmware for P2P device address. This must be done with discovery443* disabled.444*/445brcmf_fil_iovar_int_set(ifp, "p2p_disc", 0);446447ret = brcmf_fil_iovar_data_set(ifp, "p2p_da_override", p2p_mac,448ETH_ALEN);449if (ret)450bphy_err(drvr, "failed to update device address ret %d\n", ret);451452return ret;453}454455/**456* brcmf_p2p_generate_bss_mac() - derive mac addresses for P2P.457*458* @p2p: P2P specific data.459* @dev_addr: optional device address.460*461* P2P needs mac addresses for P2P device and interface. If no device462* address it specified, these are derived from a random ethernet463* address.464*/465static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr)466{467struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;468bool random_addr = false;469bool local_admin = false;470471if (!dev_addr || is_zero_ether_addr(dev_addr)) {472/* If the primary interface address is already locally473* administered, create a new random address.474*/475if (pri_ifp->mac_addr[0] & 0x02) {476random_addr = true;477} else {478dev_addr = pri_ifp->mac_addr;479local_admin = true;480}481}482483/* Generate the P2P Device Address obtaining a random ethernet484* address with the locally administered bit set.485*/486if (random_addr)487eth_random_addr(p2p->dev_addr);488else489memcpy(p2p->dev_addr, dev_addr, ETH_ALEN);490491if (local_admin)492p2p->dev_addr[0] |= 0x02;493494/* Generate the P2P Interface Address. If the discovery and connection495* BSSCFGs need to simultaneously co-exist, then this address must be496* different from the P2P Device Address, but also locally administered.497*/498memcpy(p2p->conn_int_addr, p2p->dev_addr, ETH_ALEN);499p2p->conn_int_addr[0] |= 0x02;500p2p->conn_int_addr[4] ^= 0x80;501502memcpy(p2p->conn2_int_addr, p2p->dev_addr, ETH_ALEN);503p2p->conn2_int_addr[0] |= 0x02;504p2p->conn2_int_addr[4] ^= 0x90;505}506507/**508* brcmf_p2p_scan_is_p2p_request() - is cfg80211 scan request a P2P scan.509*510* @request: the scan request as received from cfg80211.511*512* returns true if one of the ssids in the request matches the513* P2P wildcard ssid; otherwise returns false.514*/515static bool brcmf_p2p_scan_is_p2p_request(struct cfg80211_scan_request *request)516{517struct cfg80211_ssid *ssids = request->ssids;518int i;519520for (i = 0; i < request->n_ssids; i++) {521if (ssids[i].ssid_len != BRCMF_P2P_WILDCARD_SSID_LEN)522continue;523524brcmf_dbg(INFO, "comparing ssid \"%s\"", ssids[i].ssid);525if (!memcmp(BRCMF_P2P_WILDCARD_SSID, ssids[i].ssid,526BRCMF_P2P_WILDCARD_SSID_LEN))527return true;528}529return false;530}531532/**533* brcmf_p2p_set_discover_state - set discover state in firmware.534*535* @ifp: low-level interface object.536* @state: discover state to set.537* @chanspec: channel parameters (for state @WL_P2P_DISC_ST_LISTEN only).538* @listen_ms: duration to listen (for state @WL_P2P_DISC_ST_LISTEN only).539*/540static s32 brcmf_p2p_set_discover_state(struct brcmf_if *ifp, u8 state,541u16 chanspec, u16 listen_ms)542{543struct brcmf_p2p_disc_st_le discover_state;544s32 ret = 0;545brcmf_dbg(TRACE, "enter\n");546547discover_state.state = state;548discover_state.chspec = cpu_to_le16(chanspec);549discover_state.dwell = cpu_to_le16(listen_ms);550ret = brcmf_fil_bsscfg_data_set(ifp, "p2p_state", &discover_state,551sizeof(discover_state));552return ret;553}554555/**556* brcmf_p2p_deinit_discovery() - disable P2P device discovery.557*558* @p2p: P2P specific data.559*560* Resets the discovery state and disables it in firmware.561*/562static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p)563{564struct brcmf_cfg80211_vif *vif;565566brcmf_dbg(TRACE, "enter\n");567568/* Set the discovery state to SCAN */569vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;570(void)brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0);571572/* Disable P2P discovery in the firmware */573vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;574(void)brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 0);575576return 0;577}578579/**580* brcmf_p2p_enable_discovery() - initialize and configure discovery.581*582* @p2p: P2P specific data.583*584* Initializes the discovery device and configure the virtual interface.585*/586static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p)587{588struct brcmf_pub *drvr = p2p->cfg->pub;589struct brcmf_cfg80211_vif *vif;590s32 ret = 0;591592brcmf_dbg(TRACE, "enter\n");593vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;594if (!vif) {595bphy_err(drvr, "P2P config device not available\n");596ret = -EPERM;597goto exit;598}599600if (test_bit(BRCMF_P2P_STATUS_ENABLED, &p2p->status)) {601brcmf_dbg(INFO, "P2P config device already configured\n");602goto exit;603}604605/* Re-initialize P2P Discovery in the firmware */606vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;607ret = brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 1);608if (ret < 0) {609bphy_err(drvr, "set p2p_disc error\n");610goto exit;611}612vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;613ret = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0);614if (ret < 0) {615bphy_err(drvr, "unable to set WL_P2P_DISC_ST_SCAN\n");616goto exit;617}618619/*620* Set wsec to any non-zero value in the discovery bsscfg621* to ensure our P2P probe responses have the privacy bit622* set in the 802.11 WPA IE. Some peer devices may not623* initiate WPS with us if this bit is not set.624*/625ret = brcmf_fil_bsscfg_int_set(vif->ifp, "wsec", AES_ENABLED);626if (ret < 0) {627bphy_err(drvr, "wsec error %d\n", ret);628goto exit;629}630631set_bit(BRCMF_P2P_STATUS_ENABLED, &p2p->status);632exit:633return ret;634}635636/**637* brcmf_p2p_escan() - initiate a P2P scan.638*639* @p2p: P2P specific data.640* @num_chans: number of channels to scan.641* @chanspecs: channel parameters for @num_chans channels.642* @search_state: P2P discover state to use.643* @bss_type: type of P2P bss.644*/645static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans,646u16 chanspecs[], s32 search_state,647enum p2p_bss_type bss_type)648{649struct brcmf_pub *drvr = p2p->cfg->pub;650s32 ret = 0;651s32 memsize = offsetof(struct brcmf_p2p_scan_le,652eparams.params_le.channel_list);653s32 nprobes;654s32 active;655u32 i;656u8 *memblk;657struct brcmf_cfg80211_vif *vif;658struct brcmf_p2p_scan_le *p2p_params;659struct brcmf_scan_params_le *sparams;660661memsize += num_chans * sizeof(__le16);662memblk = kzalloc(memsize, GFP_KERNEL);663if (!memblk)664return -ENOMEM;665666vif = p2p->bss_idx[bss_type].vif;667if (vif == NULL) {668bphy_err(drvr, "no vif for bss type %d\n", bss_type);669ret = -EINVAL;670goto exit;671}672p2p_params = (struct brcmf_p2p_scan_le *)memblk;673sparams = &p2p_params->eparams.params_le;674675switch (search_state) {676case WL_P2P_DISC_ST_SEARCH:677/*678* If we in SEARCH STATE, we don't need to set SSID explictly679* because dongle use P2P WILDCARD internally by default, use680* null ssid, which it is already due to kzalloc.681*/682break;683case WL_P2P_DISC_ST_SCAN:684/*685* wpa_supplicant has p2p_find command with type social or686* progressive. For progressive, we need to set the ssid to687* P2P WILDCARD because we just do broadcast scan unless688* setting SSID.689*/690sparams->ssid_le.SSID_len =691cpu_to_le32(BRCMF_P2P_WILDCARD_SSID_LEN);692memcpy(sparams->ssid_le.SSID, BRCMF_P2P_WILDCARD_SSID,693BRCMF_P2P_WILDCARD_SSID_LEN);694break;695default:696bphy_err(drvr, " invalid search state %d\n", search_state);697ret = -EINVAL;698goto exit;699}700701brcmf_p2p_set_discover_state(vif->ifp, search_state, 0, 0);702703/*704* set p2p scan parameters.705*/706p2p_params->type = 'E';707708/* determine the scan engine parameters */709sparams->bss_type = DOT11_BSSTYPE_ANY;710sparams->scan_type = BRCMF_SCANTYPE_ACTIVE;711712eth_broadcast_addr(sparams->bssid);713sparams->home_time = cpu_to_le32(P2PAPI_SCAN_HOME_TIME_MS);714715/*716* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan717* supported by the supplicant.718*/719if (num_chans == SOCIAL_CHAN_CNT || num_chans == (SOCIAL_CHAN_CNT + 1))720active = P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS;721else if (num_chans == AF_PEER_SEARCH_CNT)722active = P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS;723else if (brcmf_get_vif_state_any(p2p->cfg, BRCMF_VIF_STATUS_CONNECTED))724active = -1;725else726active = P2PAPI_SCAN_DWELL_TIME_MS;727728/* Override scan params to find a peer for a connection */729if (num_chans == 1) {730active = WL_SCAN_CONNECT_DWELL_TIME_MS;731/* WAR to sync with presence period of VSDB GO.732* send probe request more frequently733*/734nprobes = active / WL_SCAN_JOIN_PROBE_INTERVAL_MS;735} else {736nprobes = active / P2PAPI_SCAN_NPROBS_TIME_MS;737}738739if (nprobes <= 0)740nprobes = 1;741742brcmf_dbg(INFO, "nprobes # %d, active_time %d\n", nprobes, active);743sparams->active_time = cpu_to_le32(active);744sparams->nprobes = cpu_to_le32(nprobes);745sparams->passive_time = cpu_to_le32(-1);746sparams->channel_num = cpu_to_le32(num_chans &747BRCMF_SCAN_PARAMS_COUNT_MASK);748for (i = 0; i < num_chans; i++)749sparams->channel_list[i] = cpu_to_le16(chanspecs[i]);750751/* set the escan specific parameters */752p2p_params->eparams.version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);753p2p_params->eparams.action = cpu_to_le16(WL_ESCAN_ACTION_START);754p2p_params->eparams.sync_id = cpu_to_le16(0x1234);755/* perform p2p scan on primary device */756ret = brcmf_fil_bsscfg_data_set(vif->ifp, "p2p_scan", memblk, memsize);757if (!ret)758set_bit(BRCMF_SCAN_STATUS_BUSY, &p2p->cfg->scan_status);759exit:760kfree(memblk);761return ret;762}763764/**765* brcmf_p2p_run_escan() - escan callback for peer-to-peer.766*767* @cfg: driver private data for cfg80211 interface.768* @ifp: interface control.769* @request: scan request from cfg80211.770*771* Determines the P2P discovery state based to scan request parameters and772* validates the channels in the request.773*/774static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,775struct brcmf_if *ifp,776struct cfg80211_scan_request *request)777{778struct brcmf_p2p_info *p2p = &cfg->p2p;779struct brcmf_pub *drvr = cfg->pub;780s32 err = 0;781s32 search_state = WL_P2P_DISC_ST_SCAN;782struct brcmf_cfg80211_vif *vif;783struct net_device *dev = NULL;784int i, num_nodfs = 0;785u16 *chanspecs;786787brcmf_dbg(TRACE, "enter\n");788789if (!request) {790err = -EINVAL;791goto exit;792}793794if (request->n_channels) {795chanspecs = kcalloc(request->n_channels, sizeof(*chanspecs),796GFP_KERNEL);797if (!chanspecs) {798err = -ENOMEM;799goto exit;800}801vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;802if (vif)803dev = vif->wdev.netdev;804if (request->n_channels == 3 &&805request->channels[0]->hw_value == SOCIAL_CHAN_1 &&806request->channels[1]->hw_value == SOCIAL_CHAN_2 &&807request->channels[2]->hw_value == SOCIAL_CHAN_3) {808/* SOCIAL CHANNELS 1, 6, 11 */809search_state = WL_P2P_DISC_ST_SEARCH;810brcmf_dbg(INFO, "P2P SEARCH PHASE START\n");811} else if (dev != NULL &&812vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {813/* If you are already a GO, then do SEARCH only */814brcmf_dbg(INFO, "Already a GO. Do SEARCH Only\n");815search_state = WL_P2P_DISC_ST_SEARCH;816} else {817brcmf_dbg(INFO, "P2P SCAN STATE START\n");818}819820/*821* no P2P scanning on passive or DFS channels.822*/823for (i = 0; i < request->n_channels; i++) {824struct ieee80211_channel *chan = request->channels[i];825826if (chan->flags & (IEEE80211_CHAN_RADAR |827IEEE80211_CHAN_NO_IR))828continue;829830chanspecs[i] = channel_to_chanspec(&p2p->cfg->d11inf,831chan);832brcmf_dbg(INFO, "%d: chan=%d, channel spec=%x\n",833num_nodfs, chan->hw_value, chanspecs[i]);834num_nodfs++;835}836err = brcmf_p2p_escan(p2p, num_nodfs, chanspecs, search_state,837P2PAPI_BSSCFG_DEVICE);838kfree(chanspecs);839}840exit:841if (err)842bphy_err(drvr, "error (%d)\n", err);843return err;844}845846847/**848* brcmf_p2p_find_listen_channel() - find listen channel in ie string.849*850* @ie: string of information elements.851* @ie_len: length of string.852*853* Scan ie for p2p ie and look for attribute 6 channel. If available determine854* channel and return it.855*/856static s32 brcmf_p2p_find_listen_channel(const u8 *ie, u32 ie_len)857{858u8 channel_ie[5];859s32 listen_channel;860s32 err;861862err = cfg80211_get_p2p_attr(ie, ie_len,863IEEE80211_P2P_ATTR_LISTEN_CHANNEL,864channel_ie, sizeof(channel_ie));865if (err < 0)866return err;867868/* listen channel subel length format: */869/* 3(country) + 1(op. class) + 1(chan num) */870listen_channel = (s32)channel_ie[3 + 1];871872if (listen_channel == SOCIAL_CHAN_1 ||873listen_channel == SOCIAL_CHAN_2 ||874listen_channel == SOCIAL_CHAN_3) {875brcmf_dbg(INFO, "Found my Listen Channel %d\n", listen_channel);876return listen_channel;877}878879return -EPERM;880}881882883/**884* brcmf_p2p_scan_prep() - prepare scan based on request.885*886* @wiphy: wiphy device.887* @request: scan request from cfg80211.888* @vif: vif on which scan request is to be executed.889*890* Prepare the scan appropriately for type of scan requested. Overrides the891* escan .run() callback for peer-to-peer scanning.892*/893int brcmf_p2p_scan_prep(struct wiphy *wiphy,894struct cfg80211_scan_request *request,895struct brcmf_cfg80211_vif *vif)896{897struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);898struct brcmf_p2p_info *p2p = &cfg->p2p;899int err;900901if (brcmf_p2p_scan_is_p2p_request(request)) {902/* find my listen channel */903err = brcmf_p2p_find_listen_channel(request->ie,904request->ie_len);905if (err < 0)906return err;907908p2p->afx_hdl.my_listen_chan = err;909910clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);911brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n");912913err = brcmf_p2p_enable_discovery(p2p);914if (err)915return err;916917/* override .run_escan() callback. */918cfg->escan_info.run = brcmf_p2p_run_escan;919}920return 0;921}922923924/**925* brcmf_p2p_discover_listen() - set firmware to discover listen state.926*927* @p2p: p2p device.928* @channel: channel nr for discover listen.929* @duration: time in ms to stay on channel.930*931*/932static s32933brcmf_p2p_discover_listen(struct brcmf_p2p_info *p2p, u16 channel, u32 duration)934{935struct brcmf_pub *drvr = p2p->cfg->pub;936struct brcmf_cfg80211_vif *vif;937struct brcmu_chan ch;938s32 err = 0;939940vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;941if (!vif) {942bphy_err(drvr, "Discovery is not set, so we have nothing to do\n");943err = -EPERM;944goto exit;945}946947if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status)) {948bphy_err(drvr, "Previous LISTEN is not completed yet\n");949/* WAR: prevent cookie mismatch in wpa_supplicant return OK */950goto exit;951}952953ch.chnum = channel;954ch.bw = BRCMU_CHAN_BW_20;955p2p->cfg->d11inf.encchspec(&ch);956err = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_LISTEN,957ch.chspec, (u16)duration);958if (!err) {959set_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status);960p2p->remain_on_channel_cookie++;961}962exit:963return err;964}965966967/**968* brcmf_p2p_remain_on_channel() - put device on channel and stay there.969*970* @wiphy: wiphy device.971* @wdev: wireless device.972* @channel: channel to stay on.973* @duration: time in ms to remain on channel.974* @cookie: cookie.975*/976int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,977struct ieee80211_channel *channel,978unsigned int duration, u64 *cookie)979{980struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);981struct brcmf_p2p_info *p2p = &cfg->p2p;982s32 err;983u16 channel_nr;984985channel_nr = ieee80211_frequency_to_channel(channel->center_freq);986brcmf_dbg(TRACE, "Enter, channel: %d, duration ms (%d)\n", channel_nr,987duration);988989err = brcmf_p2p_enable_discovery(p2p);990if (err)991goto exit;992err = brcmf_p2p_discover_listen(p2p, channel_nr, duration);993if (err)994goto exit;995996memcpy(&p2p->remain_on_channel, channel, sizeof(*channel));997*cookie = p2p->remain_on_channel_cookie;998cfg80211_ready_on_channel(wdev, *cookie, channel, duration, GFP_KERNEL);9991000exit:1001return err;1002}100310041005/**1006* brcmf_p2p_notify_listen_complete() - p2p listen has completed.1007*1008* @ifp: interfac control.1009* @e: event message. Not used, to make it usable for fweh event dispatcher.1010* @data: payload of message. Not used.1011*1012*/1013int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,1014const struct brcmf_event_msg *e,1015void *data)1016{1017struct brcmf_cfg80211_info *cfg = ifp->drvr->config;1018struct brcmf_p2p_info *p2p = &cfg->p2p;10191020brcmf_dbg(TRACE, "Enter\n");1021if (test_and_clear_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN,1022&p2p->status)) {1023if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,1024&p2p->status)) {1025clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,1026&p2p->status);1027brcmf_dbg(INFO, "Listen DONE, wake up wait_next_af\n");1028complete(&p2p->wait_next_af);1029}10301031cfg80211_remain_on_channel_expired(&ifp->vif->wdev,1032p2p->remain_on_channel_cookie,1033&p2p->remain_on_channel,1034GFP_KERNEL);1035}1036return 0;1037}103810391040/**1041* brcmf_p2p_cancel_remain_on_channel() - cancel p2p listen state.1042*1043* @ifp: interfac control.1044*1045*/1046void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp)1047{1048if (!ifp)1049return;1050brcmf_p2p_set_discover_state(ifp, WL_P2P_DISC_ST_SCAN, 0, 0);1051brcmf_p2p_notify_listen_complete(ifp, NULL, NULL);1052}105310541055/**1056* brcmf_p2p_act_frm_search() - search function for action frame.1057*1058* @p2p: p2p device.1059* @channel: channel on which action frame is to be trasmitted.1060*1061* search function to reach at common channel to send action frame. When1062* channel is 0 then all social channels will be used to send af1063*/1064static s32 brcmf_p2p_act_frm_search(struct brcmf_p2p_info *p2p, u16 channel)1065{1066struct brcmf_pub *drvr = p2p->cfg->pub;1067s32 err;1068u32 channel_cnt;1069u16 *default_chan_list;1070u32 i;1071struct brcmu_chan ch;10721073brcmf_dbg(TRACE, "Enter\n");10741075if (channel)1076channel_cnt = AF_PEER_SEARCH_CNT;1077else1078channel_cnt = SOCIAL_CHAN_CNT;1079default_chan_list = kcalloc(channel_cnt, sizeof(*default_chan_list),1080GFP_KERNEL);1081if (default_chan_list == NULL) {1082bphy_err(drvr, "channel list allocation failed\n");1083err = -ENOMEM;1084goto exit;1085}1086ch.bw = BRCMU_CHAN_BW_20;1087if (channel) {1088ch.chnum = channel;1089p2p->cfg->d11inf.encchspec(&ch);1090/* insert same channel to the chan_list */1091for (i = 0; i < channel_cnt; i++)1092default_chan_list[i] = ch.chspec;1093} else {1094ch.chnum = SOCIAL_CHAN_1;1095p2p->cfg->d11inf.encchspec(&ch);1096default_chan_list[0] = ch.chspec;1097ch.chnum = SOCIAL_CHAN_2;1098p2p->cfg->d11inf.encchspec(&ch);1099default_chan_list[1] = ch.chspec;1100ch.chnum = SOCIAL_CHAN_3;1101p2p->cfg->d11inf.encchspec(&ch);1102default_chan_list[2] = ch.chspec;1103}1104err = brcmf_p2p_escan(p2p, channel_cnt, default_chan_list,1105WL_P2P_DISC_ST_SEARCH, P2PAPI_BSSCFG_DEVICE);1106kfree(default_chan_list);1107exit:1108return err;1109}111011111112/**1113* brcmf_p2p_afx_handler() - afx worker thread.1114*1115* @work:1116*1117*/1118static void brcmf_p2p_afx_handler(struct work_struct *work)1119{1120struct afx_hdl *afx_hdl = container_of(work, struct afx_hdl, afx_work);1121struct brcmf_p2p_info *p2p = container_of(afx_hdl,1122struct brcmf_p2p_info,1123afx_hdl);1124struct brcmf_pub *drvr = p2p->cfg->pub;1125s32 err;11261127if (!afx_hdl->is_active)1128return;11291130if (afx_hdl->is_listen && afx_hdl->my_listen_chan)1131/* 100ms ~ 300ms */1132err = brcmf_p2p_discover_listen(p2p, afx_hdl->my_listen_chan,1133100 * get_random_u32_inclusive(1, 3));1134else1135err = brcmf_p2p_act_frm_search(p2p, afx_hdl->peer_listen_chan);11361137if (err) {1138bphy_err(drvr, "ERROR occurred! value is (%d)\n", err);1139if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,1140&p2p->status))1141complete(&afx_hdl->act_frm_scan);1142}1143}114411451146/**1147* brcmf_p2p_af_searching_channel() - search channel.1148*1149* @p2p: p2p device info struct.1150*1151*/1152static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p)1153{1154struct afx_hdl *afx_hdl = &p2p->afx_hdl;1155struct brcmf_cfg80211_vif *pri_vif;1156s32 retry;11571158brcmf_dbg(TRACE, "Enter\n");11591160pri_vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;11611162reinit_completion(&afx_hdl->act_frm_scan);1163set_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status);1164afx_hdl->is_active = true;1165afx_hdl->peer_chan = P2P_INVALID_CHANNEL;11661167/* Loop to wait until we find a peer's channel or the1168* pending action frame tx is cancelled.1169*/1170retry = 0;1171while ((retry < P2P_CHANNEL_SYNC_RETRY) &&1172(afx_hdl->peer_chan == P2P_INVALID_CHANNEL)) {1173afx_hdl->is_listen = false;1174brcmf_dbg(TRACE, "Scheduling action frame for sending.. (%d)\n",1175retry);1176/* search peer on peer's listen channel */1177schedule_work(&afx_hdl->afx_work);1178wait_for_completion_timeout(&afx_hdl->act_frm_scan,1179P2P_AF_FRM_SCAN_MAX_WAIT);1180if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) ||1181(!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,1182&p2p->status)))1183break;11841185if (afx_hdl->my_listen_chan) {1186brcmf_dbg(TRACE, "Scheduling listen peer, channel=%d\n",1187afx_hdl->my_listen_chan);1188/* listen on my listen channel */1189afx_hdl->is_listen = true;1190schedule_work(&afx_hdl->afx_work);1191wait_for_completion_timeout(&afx_hdl->act_frm_scan,1192P2P_AF_FRM_SCAN_MAX_WAIT);1193}1194if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) ||1195(!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,1196&p2p->status)))1197break;1198retry++;11991200/* if sta is connected or connecting, sleep for a while before1201* retry af tx or finding a peer1202*/1203if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &pri_vif->sme_state) ||1204test_bit(BRCMF_VIF_STATUS_CONNECTING, &pri_vif->sme_state))1205#if defined(__linux__)1206msleep(P2P_DEFAULT_SLEEP_TIME_VSDB);1207#elif defined(__FreeBSD__)1208linux_msleep(P2P_DEFAULT_SLEEP_TIME_VSDB);1209#endif1210}12111212brcmf_dbg(TRACE, "Completed search/listen peer_chan=%d\n",1213afx_hdl->peer_chan);1214afx_hdl->is_active = false;12151216clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status);12171218return afx_hdl->peer_chan;1219}122012211222/**1223* brcmf_p2p_scan_finding_common_channel() - was escan used for finding channel1224*1225* @cfg: common configuration struct.1226* @bi: bss info struct, result from scan.1227*1228*/1229bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg,1230struct brcmf_bss_info_le *bi)12311232{1233struct brcmf_p2p_info *p2p = &cfg->p2p;1234struct afx_hdl *afx_hdl = &p2p->afx_hdl;1235struct brcmu_chan ch;1236u8 *ie;1237s32 err;1238u8 p2p_dev_addr[ETH_ALEN];12391240if (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status))1241return false;12421243if (bi == NULL) {1244brcmf_dbg(TRACE, "ACTION FRAME SCAN Done\n");1245if (afx_hdl->peer_chan == P2P_INVALID_CHANNEL)1246complete(&afx_hdl->act_frm_scan);1247return true;1248}12491250ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);1251memset(p2p_dev_addr, 0, sizeof(p2p_dev_addr));1252err = cfg80211_get_p2p_attr(ie, le32_to_cpu(bi->ie_length),1253IEEE80211_P2P_ATTR_DEVICE_INFO,1254p2p_dev_addr, sizeof(p2p_dev_addr));1255if (err < 0)1256err = cfg80211_get_p2p_attr(ie, le32_to_cpu(bi->ie_length),1257IEEE80211_P2P_ATTR_DEVICE_ID,1258p2p_dev_addr, sizeof(p2p_dev_addr));1259if ((err >= 0) &&1260(ether_addr_equal(p2p_dev_addr, afx_hdl->tx_dst_addr))) {1261if (!bi->ctl_ch) {1262ch.chspec = le16_to_cpu(bi->chanspec);1263cfg->d11inf.decchspec(&ch);1264bi->ctl_ch = ch.control_ch_num;1265}1266afx_hdl->peer_chan = bi->ctl_ch;1267brcmf_dbg(TRACE, "ACTION FRAME SCAN : Peer %pM found, channel : %d\n",1268afx_hdl->tx_dst_addr, afx_hdl->peer_chan);1269complete(&afx_hdl->act_frm_scan);1270}1271return true;1272}12731274/**1275* brcmf_p2p_abort_action_frame() - abort action frame.1276*1277* @cfg: common configuration struct.1278*1279*/1280static s32 brcmf_p2p_abort_action_frame(struct brcmf_cfg80211_info *cfg)1281{1282struct brcmf_p2p_info *p2p = &cfg->p2p;1283struct brcmf_cfg80211_vif *vif;1284s32 err;1285s32 int_val = 1;12861287brcmf_dbg(TRACE, "Enter\n");12881289vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;1290err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe_abort", &int_val,1291sizeof(s32));1292if (err)1293brcmf_err(" aborting action frame has failed (%d)\n", err);12941295return err;1296}12971298/**1299* brcmf_p2p_stop_wait_next_action_frame() - finish scan if af tx complete.1300*1301* @cfg: common configuration struct.1302*1303*/1304static void1305brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg)1306{1307struct brcmf_p2p_info *p2p = &cfg->p2p;1308struct brcmf_if *ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;1309s32 err;13101311if (test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status) &&1312(test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status) ||1313test_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status))) {1314brcmf_dbg(TRACE, "*** Wake UP ** abort actframe iovar\n");1315/* if channel is not zero, "actfame" uses off channel scan.1316* So abort scan for off channel completion.1317*/1318if (p2p->af_sent_channel) {1319/* abort actframe using actframe_abort or abort scan */1320err = brcmf_p2p_abort_action_frame(cfg);1321if (err)1322brcmf_notify_escan_complete(cfg, ifp, true,1323true);1324}1325} else if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,1326&p2p->status)) {1327brcmf_dbg(TRACE, "*** Wake UP ** abort listen for next af frame\n");1328/* So abort scan to cancel listen */1329brcmf_notify_escan_complete(cfg, ifp, true, true);1330}1331}133213331334/**1335* brcmf_p2p_gon_req_collision() - Check if go negotiaton collission1336*1337* @p2p: p2p device info struct.1338* @mac: MAC address.1339*1340* return true if recevied action frame is to be dropped.1341*/1342static bool1343#if defined(__linux__)1344brcmf_p2p_gon_req_collision(struct brcmf_p2p_info *p2p, u8 *mac)1345#elif defined(__FreeBSD__)1346brcmf_p2p_gon_req_collision(struct brcmf_p2p_info *p2p, const u8 *mac)1347#endif1348{1349struct brcmf_cfg80211_info *cfg = p2p->cfg;1350struct brcmf_if *ifp;13511352brcmf_dbg(TRACE, "Enter\n");13531354if (!test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) ||1355!p2p->gon_req_action)1356return false;13571358brcmf_dbg(TRACE, "GO Negotiation Request COLLISION !!!\n");1359/* if sa(peer) addr is less than da(my) addr, then this device1360* process peer's gon request and block to send gon req.1361* if not (sa addr > da addr),1362* this device will process gon request and drop gon req of peer.1363*/1364ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp;1365if (memcmp(mac, ifp->mac_addr, ETH_ALEN) < 0) {1366brcmf_dbg(INFO, "Block transmit gon req !!!\n");1367p2p->block_gon_req_tx = true;1368/* if we are finding a common channel for sending af,1369* do not scan more to block to send current gon req1370*/1371if (test_and_clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,1372&p2p->status))1373complete(&p2p->afx_hdl.act_frm_scan);1374if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,1375&p2p->status))1376brcmf_p2p_stop_wait_next_action_frame(cfg);1377return false;1378}13791380/* drop gon request of peer to process gon request by this device. */1381brcmf_dbg(INFO, "Drop received gon req !!!\n");13821383return true;1384}138513861387/**1388* brcmf_p2p_notify_action_frame_rx() - received action frame.1389*1390* @ifp: interfac control.1391* @e: event message. Not used, to make it usable for fweh event dispatcher.1392* @data: payload of message, containing action frame data.1393*1394*/1395int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,1396const struct brcmf_event_msg *e,1397void *data)1398{1399struct brcmf_pub *drvr = ifp->drvr;1400struct brcmf_cfg80211_info *cfg = drvr->config;1401struct brcmf_p2p_info *p2p = &cfg->p2p;1402struct afx_hdl *afx_hdl = &p2p->afx_hdl;1403struct wireless_dev *wdev;1404u32 mgmt_frame_len = e->datalen - sizeof(struct brcmf_rx_mgmt_data);1405struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;1406u8 *frame = (u8 *)(rxframe + 1);1407struct brcmf_p2p_pub_act_frame *act_frm;1408struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;1409struct brcmu_chan ch;1410struct ieee80211_mgmt *mgmt_frame;1411s32 freq;1412u16 mgmt_type;1413u8 action;14141415if (e->datalen < sizeof(*rxframe)) {1416brcmf_dbg(SCAN, "Event data too small. Ignore\n");1417return 0;1418}14191420ch.chspec = be16_to_cpu(rxframe->chanspec);1421cfg->d11inf.decchspec(&ch);1422/* Check if wpa_supplicant has registered for this frame */1423brcmf_dbg(INFO, "ifp->vif->mgmt_rx_reg %04x\n", ifp->vif->mgmt_rx_reg);1424mgmt_type = (IEEE80211_STYPE_ACTION & IEEE80211_FCTL_STYPE) >> 4;1425if ((ifp->vif->mgmt_rx_reg & BIT(mgmt_type)) == 0)1426return 0;14271428brcmf_p2p_print_actframe(false, frame, mgmt_frame_len);14291430action = P2P_PAF_SUBTYPE_INVALID;1431if (brcmf_p2p_is_pub_action(frame, mgmt_frame_len)) {1432act_frm = (struct brcmf_p2p_pub_act_frame *)frame;1433action = act_frm->subtype;1434if ((action == P2P_PAF_GON_REQ) &&1435#if defined(__linux__)1436(brcmf_p2p_gon_req_collision(p2p, (u8 *)e->addr))) {1437#elif defined(__FreeBSD__)1438(brcmf_p2p_gon_req_collision(p2p, e->addr))) {1439#endif1440if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,1441&p2p->status) &&1442(ether_addr_equal(afx_hdl->tx_dst_addr, e->addr))) {1443afx_hdl->peer_chan = ch.control_ch_num;1444brcmf_dbg(INFO, "GON request: Peer found, channel=%d\n",1445afx_hdl->peer_chan);1446complete(&afx_hdl->act_frm_scan);1447}1448return 0;1449}1450/* After complete GO Negotiation, roll back to mpc mode */1451if ((action == P2P_PAF_GON_CONF) ||1452(action == P2P_PAF_PROVDIS_RSP))1453brcmf_set_mpc(ifp, 1);1454if (action == P2P_PAF_GON_CONF) {1455brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n");1456clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);1457}1458} else if (brcmf_p2p_is_gas_action(frame, mgmt_frame_len)) {1459sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;1460action = sd_act_frm->action;1461}14621463if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) &&1464(p2p->next_af_subtype == action)) {1465brcmf_dbg(TRACE, "We got a right next frame! (%d)\n", action);1466clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,1467&p2p->status);1468/* Stop waiting for next AF. */1469brcmf_p2p_stop_wait_next_action_frame(cfg);1470}14711472mgmt_frame = kzalloc(offsetof(struct ieee80211_mgmt, u) +1473mgmt_frame_len, GFP_KERNEL);1474if (!mgmt_frame) {1475bphy_err(drvr, "No memory available for action frame\n");1476return -ENOMEM;1477}1478memcpy(mgmt_frame->da, ifp->mac_addr, ETH_ALEN);1479brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mgmt_frame->bssid,1480ETH_ALEN);1481memcpy(mgmt_frame->sa, e->addr, ETH_ALEN);1482mgmt_frame->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION);1483memcpy(mgmt_frame->u.body, frame, mgmt_frame_len);1484mgmt_frame_len += offsetof(struct ieee80211_mgmt, u.body);14851486freq = ieee80211_channel_to_frequency(ch.control_ch_num,1487ch.band == BRCMU_CHAN_BAND_2G ?1488NL80211_BAND_2GHZ :1489NL80211_BAND_5GHZ);14901491wdev = &ifp->vif->wdev;1492cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 0);14931494kfree(mgmt_frame);1495return 0;1496}149714981499/**1500* brcmf_p2p_notify_action_tx_complete() - transmit action frame complete1501*1502* @ifp: interfac control.1503* @e: event message. Not used, to make it usable for fweh event dispatcher.1504* @data: not used.1505*1506*/1507int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp,1508const struct brcmf_event_msg *e,1509void *data)1510{1511struct brcmf_cfg80211_info *cfg = ifp->drvr->config;1512struct brcmf_p2p_info *p2p = &cfg->p2p;15131514brcmf_dbg(INFO, "Enter: event %s, status=%d\n",1515e->event_code == BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE ?1516"ACTION_FRAME_OFF_CHAN_COMPLETE" : "ACTION_FRAME_COMPLETE",1517e->status);15181519if (!test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status))1520return 0;15211522if (e->event_code == BRCMF_E_ACTION_FRAME_COMPLETE) {1523if (e->status == BRCMF_E_STATUS_SUCCESS) {1524set_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED,1525&p2p->status);1526if (!p2p->wait_for_offchan_complete)1527complete(&p2p->send_af_done);1528} else {1529set_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);1530/* If there is no ack, we don't need to wait for1531* WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE event1532*/1533brcmf_p2p_stop_wait_next_action_frame(cfg);1534}15351536} else {1537complete(&p2p->send_af_done);1538}1539return 0;1540}154115421543/**1544* brcmf_p2p_tx_action_frame() - send action frame over fil.1545*1546* @ifp: interface to transmit on.1547* @p2p: p2p info struct for vif.1548* @af_params: action frame data/info.1549*1550* Send an action frame immediately without doing channel synchronization.1551*1552* This function waits for a completion event before returning.1553* The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action1554* frame is transmitted.1555*/1556static s32 brcmf_p2p_tx_action_frame(struct brcmf_if *ifp,1557struct brcmf_p2p_info *p2p,1558struct brcmf_fil_af_params_le *af_params)1559{1560struct brcmf_pub *drvr = p2p->cfg->pub;1561s32 err = 0;15621563brcmf_dbg(TRACE, "Enter\n");15641565reinit_completion(&p2p->send_af_done);1566clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status);1567clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);15681569err = brcmf_fil_bsscfg_data_set(ifp, "actframe", af_params,1570sizeof(*af_params));1571if (err) {1572bphy_err(drvr, " sending action frame has failed\n");1573goto exit;1574}15751576p2p->af_sent_channel = le32_to_cpu(af_params->channel);1577p2p->af_tx_sent_jiffies = jiffies;15781579if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status) &&1580p2p->af_sent_channel ==1581ieee80211_frequency_to_channel(p2p->remain_on_channel.center_freq))1582p2p->wait_for_offchan_complete = false;1583else1584p2p->wait_for_offchan_complete = true;15851586brcmf_dbg(TRACE, "Waiting for %s tx completion event\n",1587(p2p->wait_for_offchan_complete) ?1588"off-channel" : "on-channel");15891590wait_for_completion_timeout(&p2p->send_af_done, P2P_AF_MAX_WAIT_TIME);15911592if (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status)) {1593brcmf_dbg(TRACE, "TX action frame operation is success\n");1594} else {1595err = -EIO;1596brcmf_dbg(TRACE, "TX action frame operation has failed\n");1597}1598/* clear status bit for action tx */1599clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status);1600clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);16011602exit:1603return err;1604}160516061607/**1608* brcmf_p2p_pub_af_tx() - public action frame tx routine.1609*1610* @cfg: driver private data for cfg80211 interface.1611* @af_params: action frame data/info.1612* @config_af_params: configuration data for action frame.1613*1614* routine which transmits ation frame public type.1615*/1616static s32 brcmf_p2p_pub_af_tx(struct brcmf_cfg80211_info *cfg,1617struct brcmf_fil_af_params_le *af_params,1618struct brcmf_config_af_params *config_af_params)1619{1620struct brcmf_p2p_info *p2p = &cfg->p2p;1621struct brcmf_pub *drvr = cfg->pub;1622struct brcmf_fil_action_frame_le *action_frame;1623struct brcmf_p2p_pub_act_frame *act_frm;1624s32 err = 0;1625u16 ie_len;16261627action_frame = &af_params->action_frame;1628act_frm = (struct brcmf_p2p_pub_act_frame *)(action_frame->data);16291630config_af_params->extra_listen = true;16311632switch (act_frm->subtype) {1633case P2P_PAF_GON_REQ:1634brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status set\n");1635set_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);1636config_af_params->mpc_onoff = 0;1637config_af_params->search_channel = true;1638p2p->next_af_subtype = act_frm->subtype + 1;1639p2p->gon_req_action = true;1640/* increase dwell time to wait for RESP frame */1641af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);1642break;1643case P2P_PAF_GON_RSP:1644p2p->next_af_subtype = act_frm->subtype + 1;1645/* increase dwell time to wait for CONF frame */1646af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);1647break;1648case P2P_PAF_GON_CONF:1649/* If we reached till GO Neg confirmation reset the filter */1650brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n");1651clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);1652/* turn on mpc again if go nego is done */1653config_af_params->mpc_onoff = 1;1654/* minimize dwell time */1655af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME);1656config_af_params->extra_listen = false;1657break;1658case P2P_PAF_INVITE_REQ:1659config_af_params->search_channel = true;1660p2p->next_af_subtype = act_frm->subtype + 1;1661/* increase dwell time */1662af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);1663break;1664case P2P_PAF_INVITE_RSP:1665/* minimize dwell time */1666af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME);1667config_af_params->extra_listen = false;1668break;1669case P2P_PAF_DEVDIS_REQ:1670config_af_params->search_channel = true;1671p2p->next_af_subtype = act_frm->subtype + 1;1672/* maximize dwell time to wait for RESP frame */1673af_params->dwell_time = cpu_to_le32(P2P_AF_LONG_DWELL_TIME);1674break;1675case P2P_PAF_DEVDIS_RSP:1676/* minimize dwell time */1677af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME);1678config_af_params->extra_listen = false;1679break;1680case P2P_PAF_PROVDIS_REQ:1681ie_len = le16_to_cpu(action_frame->len) -1682offsetof(struct brcmf_p2p_pub_act_frame, elts);1683if (cfg80211_get_p2p_attr(&act_frm->elts[0], ie_len,1684IEEE80211_P2P_ATTR_GROUP_ID,1685NULL, 0) < 0)1686config_af_params->search_channel = true;1687config_af_params->mpc_onoff = 0;1688p2p->next_af_subtype = act_frm->subtype + 1;1689/* increase dwell time to wait for RESP frame */1690af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);1691break;1692case P2P_PAF_PROVDIS_RSP:1693/* wpa_supplicant send go nego req right after prov disc */1694p2p->next_af_subtype = P2P_PAF_GON_REQ;1695/* increase dwell time to MED level */1696af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);1697config_af_params->extra_listen = false;1698break;1699default:1700bphy_err(drvr, "Unknown p2p pub act frame subtype: %d\n",1701act_frm->subtype);1702err = -EINVAL;1703}1704return err;1705}17061707static bool brcmf_p2p_check_dwell_overflow(u32 requested_dwell,1708unsigned long dwell_jiffies)1709{1710if ((requested_dwell & CUSTOM_RETRY_MASK) &&1711(jiffies_to_msecs(jiffies - dwell_jiffies) >1712(requested_dwell & ~CUSTOM_RETRY_MASK))) {1713brcmf_err("Action frame TX retry time over dwell time!\n");1714return true;1715}1716return false;1717}1718/**1719* brcmf_p2p_send_action_frame() - send action frame .1720*1721* @ifp: interface to transmit on.1722* @af_params: configuration data for action frame.1723*/1724bool brcmf_p2p_send_action_frame(struct brcmf_if *ifp,1725struct brcmf_fil_af_params_le *af_params)1726{1727struct brcmf_cfg80211_info *cfg = ifp->drvr->config;1728struct brcmf_p2p_info *p2p = &cfg->p2p;1729struct brcmf_fil_action_frame_le *action_frame;1730struct brcmf_config_af_params config_af_params;1731struct afx_hdl *afx_hdl = &p2p->afx_hdl;1732struct brcmf_pub *drvr = cfg->pub;1733u16 action_frame_len;1734bool ack = false;1735u8 category;1736u8 action;1737s32 tx_retry;1738s32 extra_listen_time;1739uint delta_ms;1740unsigned long dwell_jiffies = 0;1741bool dwell_overflow = false;17421743u32 requested_dwell = le32_to_cpu(af_params->dwell_time);1744action_frame = &af_params->action_frame;1745action_frame_len = le16_to_cpu(action_frame->len);17461747brcmf_p2p_print_actframe(true, action_frame->data, action_frame_len);17481749/* Add the default dwell time. Dwell time to stay off-channel */1750/* to wait for a response action frame after transmitting an */1751/* GO Negotiation action frame */1752af_params->dwell_time = cpu_to_le32(P2P_AF_DWELL_TIME);17531754category = action_frame->data[DOT11_ACTION_CAT_OFF];1755action = action_frame->data[DOT11_ACTION_ACT_OFF];17561757/* initialize variables */1758p2p->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;1759p2p->gon_req_action = false;17601761/* config parameters */1762config_af_params.mpc_onoff = -1;1763config_af_params.search_channel = false;1764config_af_params.extra_listen = false;17651766if (brcmf_p2p_is_pub_action(action_frame->data, action_frame_len)) {1767/* p2p public action frame process */1768if (brcmf_p2p_pub_af_tx(cfg, af_params, &config_af_params)) {1769/* Just send unknown subtype frame with */1770/* default parameters. */1771bphy_err(drvr, "P2P Public action frame, unknown subtype.\n");1772}1773} else if (brcmf_p2p_is_gas_action(action_frame->data,1774action_frame_len)) {1775/* service discovery process */1776if (action == P2PSD_ACTION_ID_GAS_IREQ ||1777action == P2PSD_ACTION_ID_GAS_CREQ) {1778/* configure service discovery query frame */1779config_af_params.search_channel = true;17801781/* save next af suptype to cancel */1782/* remaining dwell time */1783p2p->next_af_subtype = action + 1;17841785af_params->dwell_time =1786cpu_to_le32(P2P_AF_MED_DWELL_TIME);1787} else if (action == P2PSD_ACTION_ID_GAS_IRESP ||1788action == P2PSD_ACTION_ID_GAS_CRESP) {1789/* configure service discovery response frame */1790af_params->dwell_time =1791cpu_to_le32(P2P_AF_MIN_DWELL_TIME);1792} else {1793bphy_err(drvr, "Unknown action type: %d\n", action);1794goto exit;1795}1796} else if (brcmf_p2p_is_p2p_action(action_frame->data,1797action_frame_len)) {1798/* do not configure anything. it will be */1799/* sent with a default configuration */1800} else {1801bphy_err(drvr, "Unknown Frame: category 0x%x, action 0x%x\n",1802category, action);1803return false;1804}18051806/* if connecting on primary iface, sleep for a while before sending1807* af tx for VSDB1808*/1809if (test_bit(BRCMF_VIF_STATUS_CONNECTING,1810&p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->sme_state))1811#if defined(__linux__)1812msleep(50);1813#elif defined(__FreeBSD__)1814linux_msleep(50);1815#endif18161817/* if scan is ongoing, abort current scan. */1818if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))1819brcmf_abort_scanning(cfg);18201821memcpy(afx_hdl->tx_dst_addr, action_frame->da, ETH_ALEN);18221823/* To make sure to send successfully action frame, turn off mpc */1824if (config_af_params.mpc_onoff == 0)1825brcmf_set_mpc(ifp, 0);18261827/* set status and destination address before sending af */1828if (p2p->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {1829/* set status to cancel the remained dwell time in rx process */1830set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status);1831}18321833p2p->af_sent_channel = 0;1834set_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status);1835/* validate channel and p2p ies */1836if (config_af_params.search_channel &&1837IS_P2P_SOCIAL_CHANNEL(le32_to_cpu(af_params->channel)) &&1838p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->saved_ie.probe_req_ie_len) {1839afx_hdl = &p2p->afx_hdl;1840afx_hdl->peer_listen_chan = le32_to_cpu(af_params->channel);18411842if (brcmf_p2p_af_searching_channel(p2p) ==1843P2P_INVALID_CHANNEL) {1844bphy_err(drvr, "Couldn't find peer's channel.\n");1845goto exit;1846}18471848/* Abort scan even for VSDB scenarios. Scan gets aborted in1849* firmware but after the check of piggyback algorithm. To take1850* care of current piggback algo, lets abort the scan here1851* itself.1852*/1853brcmf_notify_escan_complete(cfg, ifp, true, true);18541855/* update channel */1856af_params->channel = cpu_to_le32(afx_hdl->peer_chan);1857}1858dwell_jiffies = jiffies;1859dwell_overflow = brcmf_p2p_check_dwell_overflow(requested_dwell,1860dwell_jiffies);18611862tx_retry = 0;1863while (!p2p->block_gon_req_tx &&1864(!ack) && (tx_retry < P2P_AF_TX_MAX_RETRY) &&1865!dwell_overflow) {1866if (af_params->channel)1867#if defined(__linux__)1868msleep(P2P_AF_RETRY_DELAY_TIME);1869#elif defined(__FreeBSD__)1870linux_msleep(P2P_AF_RETRY_DELAY_TIME);1871#endif18721873ack = !brcmf_p2p_tx_action_frame(ifp, p2p, af_params);1874tx_retry++;1875dwell_overflow = brcmf_p2p_check_dwell_overflow(requested_dwell,1876dwell_jiffies);1877}1878if (!ack) {1879bphy_err(drvr, "Failed to send Action Frame(retry %d)\n",1880tx_retry);1881clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);1882}18831884exit:1885clear_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status);18861887/* WAR: sometimes dongle does not keep the dwell time of 'actframe'.1888* if we coundn't get the next action response frame and dongle does1889* not keep the dwell time, go to listen state again to get next action1890* response frame.1891*/1892if (ack && config_af_params.extra_listen && !p2p->block_gon_req_tx &&1893test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) &&1894p2p->af_sent_channel == afx_hdl->my_listen_chan) {1895delta_ms = jiffies_to_msecs(jiffies - p2p->af_tx_sent_jiffies);1896if (le32_to_cpu(af_params->dwell_time) > delta_ms)1897extra_listen_time = le32_to_cpu(af_params->dwell_time) -1898delta_ms;1899else1900extra_listen_time = 0;1901if (extra_listen_time > 50) {1902set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,1903&p2p->status);1904brcmf_dbg(INFO, "Wait more time! actual af time:%d, calculated extra listen:%d\n",1905le32_to_cpu(af_params->dwell_time),1906extra_listen_time);1907extra_listen_time += 100;1908if (!brcmf_p2p_discover_listen(p2p,1909p2p->af_sent_channel,1910extra_listen_time)) {1911unsigned long duration;19121913extra_listen_time += 100;1914duration = msecs_to_jiffies(extra_listen_time);1915wait_for_completion_timeout(&p2p->wait_next_af,1916duration);1917}1918clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,1919&p2p->status);1920}1921}19221923if (p2p->block_gon_req_tx) {1924/* if ack is true, supplicant will wait more time(100ms).1925* so we will return it as a success to get more time .1926*/1927p2p->block_gon_req_tx = false;1928ack = true;1929}19301931clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status);1932/* if all done, turn mpc on again */1933if (config_af_params.mpc_onoff == 1)1934brcmf_set_mpc(ifp, 1);19351936return ack;1937}19381939/**1940* brcmf_p2p_notify_rx_mgmt_p2p_probereq() - Event handler for p2p probe req.1941*1942* @ifp: interface pointer for which event was received.1943* @e: even message.1944* @data: payload of event message (probe request).1945*/1946s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,1947const struct brcmf_event_msg *e,1948void *data)1949{1950struct brcmf_cfg80211_info *cfg = ifp->drvr->config;1951struct brcmf_p2p_info *p2p = &cfg->p2p;1952struct afx_hdl *afx_hdl = &p2p->afx_hdl;1953struct brcmf_cfg80211_vif *vif = ifp->vif;1954struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;1955struct brcmu_chan ch;1956u8 *mgmt_frame;1957u32 mgmt_frame_len;1958s32 freq;1959u16 mgmt_type;19601961brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code,1962e->reason);19631964if (e->datalen < sizeof(*rxframe)) {1965brcmf_dbg(SCAN, "Event data too small. Ignore\n");1966return 0;1967}19681969ch.chspec = be16_to_cpu(rxframe->chanspec);1970cfg->d11inf.decchspec(&ch);19711972if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status) &&1973(ether_addr_equal(afx_hdl->tx_dst_addr, e->addr))) {1974afx_hdl->peer_chan = ch.control_ch_num;1975brcmf_dbg(INFO, "PROBE REQUEST: Peer found, channel=%d\n",1976afx_hdl->peer_chan);1977complete(&afx_hdl->act_frm_scan);1978}19791980/* Firmware sends us two proberesponses for each idx one. At the */1981/* moment anything but bsscfgidx 0 is passed up to supplicant */1982if (e->bsscfgidx == 0)1983return 0;19841985/* Filter any P2P probe reqs arriving during the GO-NEG Phase */1986if (test_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status)) {1987brcmf_dbg(INFO, "Filtering P2P probe_req in GO-NEG phase\n");1988return 0;1989}19901991/* Check if wpa_supplicant has registered for this frame */1992brcmf_dbg(INFO, "vif->mgmt_rx_reg %04x\n", vif->mgmt_rx_reg);1993mgmt_type = (IEEE80211_STYPE_PROBE_REQ & IEEE80211_FCTL_STYPE) >> 4;1994if ((vif->mgmt_rx_reg & BIT(mgmt_type)) == 0)1995return 0;19961997mgmt_frame = (u8 *)(rxframe + 1);1998mgmt_frame_len = e->datalen - sizeof(*rxframe);1999freq = ieee80211_channel_to_frequency(ch.control_ch_num,2000ch.band == BRCMU_CHAN_BAND_2G ?2001NL80211_BAND_2GHZ :2002NL80211_BAND_5GHZ);20032004cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);20052006brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",2007mgmt_frame_len, e->datalen, ch.chspec, freq);20082009return 0;2010}201120122013/**2014* brcmf_p2p_get_current_chanspec() - Get current operation channel.2015*2016* @p2p: P2P specific data.2017* @chanspec: chanspec to be returned.2018*/2019static void brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info *p2p,2020u16 *chanspec)2021{2022struct brcmf_if *ifp;2023u8 mac_addr[ETH_ALEN];2024struct brcmu_chan ch;2025struct brcmf_bss_info_le *bi;2026u8 *buf;20272028ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;20292030if (brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mac_addr,2031ETH_ALEN) == 0) {2032buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);2033if (buf != NULL) {2034*(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);2035if (brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,2036buf, WL_BSS_INFO_MAX) == 0) {2037bi = (struct brcmf_bss_info_le *)(buf + 4);2038*chanspec = le16_to_cpu(bi->chanspec);2039kfree(buf);2040return;2041}2042kfree(buf);2043}2044}2045/* Use default channel for P2P */2046ch.chnum = BRCMF_P2P_TEMP_CHAN;2047ch.bw = BRCMU_CHAN_BW_20;2048p2p->cfg->d11inf.encchspec(&ch);2049*chanspec = ch.chspec;2050}20512052/**2053* brcmf_p2p_ifchange - Change a P2P Role.2054* @cfg: driver private data for cfg80211 interface.2055* @if_type: interface type.2056* Returns 0 if success.2057*/2058int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,2059enum brcmf_fil_p2p_if_types if_type)2060{2061struct brcmf_p2p_info *p2p = &cfg->p2p;2062struct brcmf_pub *drvr = cfg->pub;2063struct brcmf_cfg80211_vif *vif;2064struct brcmf_fil_p2p_if_le if_request;2065s32 err;2066u16 chanspec;20672068brcmf_dbg(TRACE, "Enter\n");20692070vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;2071if (!vif) {2072bphy_err(drvr, "vif for P2PAPI_BSSCFG_PRIMARY does not exist\n");2073return -EPERM;2074}2075brcmf_notify_escan_complete(cfg, vif->ifp, true, true);2076vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;2077if (!vif) {2078bphy_err(drvr, "vif for P2PAPI_BSSCFG_CONNECTION does not exist\n");2079return -EPERM;2080}2081brcmf_set_mpc(vif->ifp, 0);20822083/* In concurrency case, STA may be already associated in a particular */2084/* channel. so retrieve the current channel of primary interface and */2085/* then start the virtual interface on that. */2086brcmf_p2p_get_current_chanspec(p2p, &chanspec);20872088if_request.type = cpu_to_le16((u16)if_type);2089if_request.chspec = cpu_to_le16(chanspec);2090memcpy(if_request.addr, p2p->conn_int_addr, sizeof(if_request.addr));20912092brcmf_cfg80211_arm_vif_event(cfg, vif);2093err = brcmf_fil_iovar_data_set(vif->ifp, "p2p_ifupd", &if_request,2094sizeof(if_request));2095if (err) {2096bphy_err(drvr, "p2p_ifupd FAILED, err=%d\n", err);2097brcmf_cfg80211_arm_vif_event(cfg, NULL);2098return err;2099}2100err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_CHANGE,2101BRCMF_VIF_EVENT_TIMEOUT);2102brcmf_cfg80211_arm_vif_event(cfg, NULL);2103if (!err) {2104bphy_err(drvr, "No BRCMF_E_IF_CHANGE event received\n");2105return -EIO;2106}21072108err = brcmf_fil_cmd_int_set(vif->ifp, BRCMF_C_SET_SCB_TIMEOUT,2109BRCMF_SCB_TIMEOUT_VALUE);21102111return err;2112}21132114static int brcmf_p2p_request_p2p_if(struct brcmf_p2p_info *p2p,2115struct brcmf_if *ifp, u8 ea[ETH_ALEN],2116enum brcmf_fil_p2p_if_types iftype)2117{2118struct brcmf_fil_p2p_if_le if_request;2119int err;2120u16 chanspec;21212122/* we need a default channel */2123brcmf_p2p_get_current_chanspec(p2p, &chanspec);21242125/* fill the firmware request */2126memcpy(if_request.addr, ea, ETH_ALEN);2127if_request.type = cpu_to_le16((u16)iftype);2128if_request.chspec = cpu_to_le16(chanspec);21292130err = brcmf_fil_iovar_data_set(ifp, "p2p_ifadd", &if_request,2131sizeof(if_request));21322133return err;2134}21352136static int brcmf_p2p_disable_p2p_if(struct brcmf_cfg80211_vif *vif)2137{2138struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev);2139struct net_device *pri_ndev = cfg_to_ndev(cfg);2140struct brcmf_if *ifp = netdev_priv(pri_ndev);2141const u8 *addr = vif->wdev.netdev->dev_addr;21422143return brcmf_fil_iovar_data_set(ifp, "p2p_ifdis", addr, ETH_ALEN);2144}21452146static int brcmf_p2p_release_p2p_if(struct brcmf_cfg80211_vif *vif)2147{2148struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev);2149struct net_device *pri_ndev = cfg_to_ndev(cfg);2150struct brcmf_if *ifp = netdev_priv(pri_ndev);2151const u8 *addr = vif->wdev.netdev->dev_addr;21522153return brcmf_fil_iovar_data_set(ifp, "p2p_ifdel", addr, ETH_ALEN);2154}21552156/**2157* brcmf_p2p_create_p2pdev() - create a P2P_DEVICE virtual interface.2158*2159* @p2p: P2P specific data.2160* @wiphy: wiphy device of new interface.2161* @addr: mac address for this new interface.2162*/2163static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p,2164struct wiphy *wiphy,2165u8 *addr)2166{2167struct brcmf_pub *drvr = p2p->cfg->pub;2168struct brcmf_cfg80211_vif *p2p_vif;2169struct brcmf_if *p2p_ifp;2170struct brcmf_if *pri_ifp;2171int err;2172u32 bsscfgidx;21732174if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif)2175return ERR_PTR(-ENOSPC);21762177p2p_vif = brcmf_alloc_vif(p2p->cfg, NL80211_IFTYPE_P2P_DEVICE);2178if (IS_ERR(p2p_vif)) {2179bphy_err(drvr, "could not create discovery vif\n");2180return (struct wireless_dev *)p2p_vif;2181}21822183pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;21842185/* firmware requires unique mac address for p2pdev interface */2186if (addr && ether_addr_equal(addr, pri_ifp->mac_addr)) {2187bphy_err(drvr, "discovery vif must be different from primary interface\n");2188err = -EINVAL;2189goto fail;2190}21912192brcmf_p2p_generate_bss_mac(p2p, addr);2193brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);21942195brcmf_cfg80211_arm_vif_event(p2p->cfg, p2p_vif);2196brcmf_fweh_p2pdev_setup(pri_ifp, true);21972198/* Initialize P2P Discovery in the firmware */2199err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);2200if (err < 0) {2201bphy_err(drvr, "set p2p_disc error\n");2202brcmf_fweh_p2pdev_setup(pri_ifp, false);2203brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL);2204goto fail;2205}22062207/* wait for firmware event */2208err = brcmf_cfg80211_wait_vif_event(p2p->cfg, BRCMF_E_IF_ADD,2209BRCMF_VIF_EVENT_TIMEOUT);2210brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL);2211brcmf_fweh_p2pdev_setup(pri_ifp, false);2212if (!err) {2213bphy_err(drvr, "timeout occurred\n");2214err = -EIO;2215goto fail;2216}22172218/* discovery interface created */2219p2p_ifp = p2p_vif->ifp;2220p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif;2221memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);2222memcpy(&p2p_vif->wdev.address, p2p->dev_addr, sizeof(p2p->dev_addr));22232224/* verify bsscfg index for P2P discovery */2225err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bsscfgidx);2226if (err < 0) {2227bphy_err(drvr, "retrieving discover bsscfg index failed\n");2228goto fail;2229}22302231WARN_ON(p2p_ifp->bsscfgidx != bsscfgidx);22322233INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler);2234init_completion(&p2p->afx_hdl.act_frm_scan);2235init_completion(&p2p->wait_next_af);22362237return &p2p_vif->wdev;22382239fail:2240brcmf_free_vif(p2p_vif);2241return ERR_PTR(err);2242}22432244static int brcmf_p2p_get_conn_idx(struct brcmf_cfg80211_info *cfg)2245{2246int i;2247struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));22482249if (!ifp)2250return -ENODEV;22512252for (i = P2PAPI_BSSCFG_CONNECTION; i < P2PAPI_BSSCFG_MAX; i++) {2253if (!cfg->p2p.bss_idx[i].vif) {2254if (i == P2PAPI_BSSCFG_CONNECTION2 &&2255!(brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {2256brcmf_err("Multi p2p not supported");2257return -EIO;2258}2259return i;2260}2261}2262return -EIO;2263}22642265/**2266* brcmf_p2p_add_vif() - create a new P2P virtual interface.2267*2268* @wiphy: wiphy device of new interface.2269* @name: name of the new interface.2270* @name_assign_type: origin of the interface name2271* @type: nl80211 interface type.2272* @params: contains mac address for P2P device.2273*/2274struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,2275unsigned char name_assign_type,2276enum nl80211_iftype type,2277struct vif_params *params)2278{2279struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);2280struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));2281struct brcmf_pub *drvr = cfg->pub;2282struct brcmf_cfg80211_vif *vif;2283enum brcmf_fil_p2p_if_types iftype;2284int err = 0;2285int connidx;2286u8 *p2p_intf_addr;22872288if (brcmf_cfg80211_vif_event_armed(cfg))2289return ERR_PTR(-EBUSY);22902291brcmf_dbg(INFO, "adding vif \"%s\" (type=%d)\n", name, type);22922293switch (type) {2294case NL80211_IFTYPE_P2P_CLIENT:2295iftype = BRCMF_FIL_P2P_IF_CLIENT;2296break;2297case NL80211_IFTYPE_P2P_GO:2298iftype = BRCMF_FIL_P2P_IF_GO;2299break;2300case NL80211_IFTYPE_P2P_DEVICE:2301return brcmf_p2p_create_p2pdev(&cfg->p2p, wiphy,2302params->macaddr);2303default:2304return ERR_PTR(-EOPNOTSUPP);2305}23062307vif = brcmf_alloc_vif(cfg, type);2308if (IS_ERR(vif))2309return (struct wireless_dev *)vif;2310brcmf_cfg80211_arm_vif_event(cfg, vif);23112312connidx = brcmf_p2p_get_conn_idx(cfg);23132314if (connidx == P2PAPI_BSSCFG_CONNECTION)2315p2p_intf_addr = cfg->p2p.conn_int_addr;2316else if (connidx == P2PAPI_BSSCFG_CONNECTION2)2317p2p_intf_addr = cfg->p2p.conn2_int_addr;2318else2319err = -EINVAL;23202321if (!err)2322err = brcmf_p2p_request_p2p_if(&cfg->p2p, ifp,2323p2p_intf_addr, iftype);23242325if (err) {2326brcmf_err("request p2p interface failed\n");2327brcmf_cfg80211_arm_vif_event(cfg, NULL);2328goto fail;2329}23302331/* wait for firmware event */2332err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,2333BRCMF_VIF_EVENT_TIMEOUT);2334brcmf_cfg80211_arm_vif_event(cfg, NULL);2335if (!err) {2336bphy_err(drvr, "timeout occurred\n");2337err = -EIO;2338goto fail;2339}23402341/* interface created in firmware */2342ifp = vif->ifp;2343if (!ifp) {2344bphy_err(drvr, "no if pointer provided\n");2345err = -ENOENT;2346goto fail;2347}23482349strscpy(ifp->ndev->name, name, sizeof(ifp->ndev->name));2350ifp->ndev->name_assign_type = name_assign_type;2351err = brcmf_net_attach(ifp, true);2352if (err) {2353bphy_err(drvr, "Registering netdevice failed\n");2354free_netdev(ifp->ndev);2355goto fail;2356}23572358cfg->p2p.bss_idx[connidx].vif = vif;2359/* Disable firmware roaming for P2P interface */2360brcmf_fil_iovar_int_set(ifp, "roam_off", 1);2361if (iftype == BRCMF_FIL_P2P_IF_GO) {2362/* set station timeout for p2p */2363brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCB_TIMEOUT,2364BRCMF_SCB_TIMEOUT_VALUE);2365}2366return &ifp->vif->wdev;23672368fail:2369brcmf_free_vif(vif);2370return ERR_PTR(err);2371}23722373/**2374* brcmf_p2p_del_vif() - delete a P2P virtual interface.2375*2376* @wiphy: wiphy device of interface.2377* @wdev: wireless device of interface.2378*/2379int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)2380{2381struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);2382struct brcmf_p2p_info *p2p = &cfg->p2p;2383struct brcmf_cfg80211_vif *vif;2384enum nl80211_iftype iftype;2385bool wait_for_disable = false;2386int err;23872388brcmf_dbg(TRACE, "delete P2P vif\n");2389vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);23902391iftype = vif->wdev.iftype;2392brcmf_cfg80211_arm_vif_event(cfg, vif);2393switch (iftype) {2394case NL80211_IFTYPE_P2P_CLIENT:2395if (test_bit(BRCMF_VIF_STATUS_DISCONNECTING, &vif->sme_state))2396wait_for_disable = true;2397break;23982399case NL80211_IFTYPE_P2P_GO:2400if (!brcmf_p2p_disable_p2p_if(vif))2401wait_for_disable = true;2402break;24032404case NL80211_IFTYPE_P2P_DEVICE:2405if (!p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif)2406return 0;2407brcmf_p2p_cancel_remain_on_channel(vif->ifp);2408brcmf_p2p_deinit_discovery(p2p);2409break;24102411default:2412return -ENOTSUPP;2413}24142415clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);2416brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n");24172418if (wait_for_disable)2419wait_for_completion_timeout(&cfg->vif_disabled,2420BRCMF_P2P_DISABLE_TIMEOUT);24212422err = 0;2423if (iftype != NL80211_IFTYPE_P2P_DEVICE) {2424brcmf_vif_clear_mgmt_ies(vif);2425err = brcmf_p2p_release_p2p_if(vif);2426}2427if (!err) {2428/* wait for firmware event */2429err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL,2430BRCMF_VIF_EVENT_TIMEOUT);2431if (!err)2432err = -EIO;2433else2434err = 0;2435}2436brcmf_remove_interface(vif->ifp, true);24372438brcmf_cfg80211_arm_vif_event(cfg, NULL);2439if (iftype != NL80211_IFTYPE_P2P_DEVICE) {2440if (vif == p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif)2441p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL;2442if (vif == p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION2].vif)2443p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION2].vif = NULL;2444}24452446return err;2447}24482449void brcmf_p2p_ifp_removed(struct brcmf_if *ifp, bool locked)2450{2451struct brcmf_cfg80211_info *cfg;2452struct brcmf_cfg80211_vif *vif;24532454brcmf_dbg(INFO, "P2P: device interface removed\n");2455vif = ifp->vif;2456cfg = wdev_to_cfg(&vif->wdev);2457cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;2458if (!locked) {2459rtnl_lock();2460wiphy_lock(cfg->wiphy);2461cfg80211_unregister_wdev(&vif->wdev);2462wiphy_unlock(cfg->wiphy);2463rtnl_unlock();2464} else {2465cfg80211_unregister_wdev(&vif->wdev);2466}2467brcmf_free_vif(vif);2468}24692470int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev)2471{2472struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);2473struct brcmf_p2p_info *p2p = &cfg->p2p;2474struct brcmf_cfg80211_vif *vif;2475int err;24762477vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);2478mutex_lock(&cfg->usr_sync);2479err = brcmf_p2p_enable_discovery(p2p);2480if (!err)2481set_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);2482mutex_unlock(&cfg->usr_sync);2483return err;2484}24852486void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev)2487{2488struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);2489struct brcmf_p2p_info *p2p = &cfg->p2p;2490struct brcmf_cfg80211_vif *vif;24912492vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);2493/* This call can be result of the unregister_wdev call. In that case2494* we dont want to do anything anymore. Just return. The config vif2495* will have been cleared at this point.2496*/2497if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif == vif) {2498mutex_lock(&cfg->usr_sync);2499/* Set the discovery state to SCAN */2500(void)brcmf_p2p_set_discover_state(vif->ifp,2501WL_P2P_DISC_ST_SCAN, 0, 0);2502brcmf_abort_scanning(cfg);2503clear_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);2504mutex_unlock(&cfg->usr_sync);2505}2506}25072508/**2509* brcmf_p2p_attach() - attach for P2P.2510*2511* @cfg: driver private data for cfg80211 interface.2512* @p2pdev_forced: create p2p device interface at attach.2513*/2514s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced)2515{2516struct brcmf_pub *drvr = cfg->pub;2517struct brcmf_p2p_info *p2p;2518struct brcmf_if *pri_ifp;2519s32 err = 0;2520void *err_ptr;25212522p2p = &cfg->p2p;2523p2p->cfg = cfg;25242525pri_ifp = brcmf_get_ifp(cfg->pub, 0);2526p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif;25272528init_completion(&p2p->send_af_done);25292530if (p2pdev_forced) {2531err_ptr = brcmf_p2p_create_p2pdev(p2p, NULL, NULL);2532if (IS_ERR(err_ptr)) {2533bphy_err(drvr, "P2P device creation failed.\n");2534err = PTR_ERR(err_ptr);2535}2536} else {2537p2p->p2pdev_dynamically = true;2538}2539return err;2540}25412542/**2543* brcmf_p2p_detach() - detach P2P.2544*2545* @p2p: P2P specific data.2546*/2547void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)2548{2549struct brcmf_cfg80211_vif *vif;25502551vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;2552if (vif != NULL) {2553brcmf_p2p_cancel_remain_on_channel(vif->ifp);2554brcmf_p2p_deinit_discovery(p2p);2555brcmf_remove_interface(vif->ifp, false);2556}2557/* just set it all to zero */2558memset(p2p, 0, sizeof(*p2p));2559}2560256125622563