1*4882a593Smuzhiyun // SPDX-License-Identifier: ISC
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2012 Broadcom Corporation
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun #include <linux/slab.h>
6*4882a593Smuzhiyun #include <linux/netdevice.h>
7*4882a593Smuzhiyun #include <linux/etherdevice.h>
8*4882a593Smuzhiyun #include <linux/rtnetlink.h>
9*4882a593Smuzhiyun #include <net/cfg80211.h>
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <brcmu_wifi.h>
12*4882a593Smuzhiyun #include <brcmu_utils.h>
13*4882a593Smuzhiyun #include <defs.h>
14*4882a593Smuzhiyun #include "core.h"
15*4882a593Smuzhiyun #include "debug.h"
16*4882a593Smuzhiyun #include "fwil.h"
17*4882a593Smuzhiyun #include "fwil_types.h"
18*4882a593Smuzhiyun #include "p2p.h"
19*4882a593Smuzhiyun #include "cfg80211.h"
20*4882a593Smuzhiyun #include "feature.h"
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun /* parameters used for p2p escan */
23*4882a593Smuzhiyun #define P2PAPI_SCAN_NPROBES 1
24*4882a593Smuzhiyun #define P2PAPI_SCAN_DWELL_TIME_MS 80
25*4882a593Smuzhiyun #define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40
26*4882a593Smuzhiyun #define P2PAPI_SCAN_HOME_TIME_MS 60
27*4882a593Smuzhiyun #define P2PAPI_SCAN_NPROBS_TIME_MS 30
28*4882a593Smuzhiyun #define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100
29*4882a593Smuzhiyun #define WL_SCAN_CONNECT_DWELL_TIME_MS 200
30*4882a593Smuzhiyun #define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define BRCMF_P2P_WILDCARD_SSID "DIRECT-"
33*4882a593Smuzhiyun #define BRCMF_P2P_WILDCARD_SSID_LEN (sizeof(BRCMF_P2P_WILDCARD_SSID) - 1)
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #define SOCIAL_CHAN_1 1
36*4882a593Smuzhiyun #define SOCIAL_CHAN_2 6
37*4882a593Smuzhiyun #define SOCIAL_CHAN_3 11
38*4882a593Smuzhiyun #define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \
39*4882a593Smuzhiyun (channel == SOCIAL_CHAN_2) || \
40*4882a593Smuzhiyun (channel == SOCIAL_CHAN_3))
41*4882a593Smuzhiyun #define BRCMF_P2P_TEMP_CHAN SOCIAL_CHAN_3
42*4882a593Smuzhiyun #define SOCIAL_CHAN_CNT 3
43*4882a593Smuzhiyun #define AF_PEER_SEARCH_CNT 2
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #define BRCMF_SCB_TIMEOUT_VALUE 20
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #define P2P_VER 9 /* P2P version: 9=WiFi P2P v1.0 */
48*4882a593Smuzhiyun #define P2P_PUB_AF_CATEGORY 0x04
49*4882a593Smuzhiyun #define P2P_PUB_AF_ACTION 0x09
50*4882a593Smuzhiyun #define P2P_AF_CATEGORY 0x7f
51*4882a593Smuzhiyun #define P2P_OUI "\x50\x6F\x9A" /* P2P OUI */
52*4882a593Smuzhiyun #define P2P_OUI_LEN 3 /* P2P OUI length */
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun /* Action Frame Constants */
55*4882a593Smuzhiyun #define DOT11_ACTION_HDR_LEN 2 /* action frame category + action */
56*4882a593Smuzhiyun #define DOT11_ACTION_CAT_OFF 0 /* category offset */
57*4882a593Smuzhiyun #define DOT11_ACTION_ACT_OFF 1 /* action offset */
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun #define P2P_AF_DWELL_TIME 200
60*4882a593Smuzhiyun #define P2P_AF_MIN_DWELL_TIME 100
61*4882a593Smuzhiyun #define P2P_AF_MED_DWELL_TIME 400
62*4882a593Smuzhiyun #define P2P_AF_LONG_DWELL_TIME 1000
63*4882a593Smuzhiyun #define P2P_AF_TX_MAX_RETRY 5
64*4882a593Smuzhiyun #define P2P_AF_MAX_WAIT_TIME msecs_to_jiffies(2000)
65*4882a593Smuzhiyun #define P2P_INVALID_CHANNEL -1
66*4882a593Smuzhiyun #define P2P_CHANNEL_SYNC_RETRY 5
67*4882a593Smuzhiyun #define P2P_AF_FRM_SCAN_MAX_WAIT msecs_to_jiffies(450)
68*4882a593Smuzhiyun #define P2P_DEFAULT_SLEEP_TIME_VSDB 200
69*4882a593Smuzhiyun #define P2P_AF_RETRY_DELAY_TIME 40
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun /* WiFi P2P Public Action Frame OUI Subtypes */
72*4882a593Smuzhiyun #define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */
73*4882a593Smuzhiyun #define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */
74*4882a593Smuzhiyun #define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */
75*4882a593Smuzhiyun #define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */
76*4882a593Smuzhiyun #define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */
77*4882a593Smuzhiyun #define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */
78*4882a593Smuzhiyun #define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */
79*4882a593Smuzhiyun #define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */
80*4882a593Smuzhiyun #define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Response */
81*4882a593Smuzhiyun #define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun /* WiFi P2P Action Frame OUI Subtypes */
84*4882a593Smuzhiyun #define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */
85*4882a593Smuzhiyun #define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */
86*4882a593Smuzhiyun #define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */
87*4882a593Smuzhiyun #define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun /* P2P Service Discovery related */
90*4882a593Smuzhiyun #define P2PSD_ACTION_CATEGORY 0x04 /* Public action frame */
91*4882a593Smuzhiyun #define P2PSD_ACTION_ID_GAS_IREQ 0x0a /* GAS Initial Request AF */
92*4882a593Smuzhiyun #define P2PSD_ACTION_ID_GAS_IRESP 0x0b /* GAS Initial Response AF */
93*4882a593Smuzhiyun #define P2PSD_ACTION_ID_GAS_CREQ 0x0c /* GAS Comback Request AF */
94*4882a593Smuzhiyun #define P2PSD_ACTION_ID_GAS_CRESP 0x0d /* GAS Comback Response AF */
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun #define BRCMF_P2P_DISABLE_TIMEOUT msecs_to_jiffies(500)
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /* Mask for retry counter of custom dwell time */
99*4882a593Smuzhiyun #define CUSTOM_RETRY_MASK 0xff000000
100*4882a593Smuzhiyun /**
101*4882a593Smuzhiyun * struct brcmf_p2p_disc_st_le - set discovery state in firmware.
102*4882a593Smuzhiyun *
103*4882a593Smuzhiyun * @state: requested discovery state (see enum brcmf_p2p_disc_state).
104*4882a593Smuzhiyun * @chspec: channel parameter for %WL_P2P_DISC_ST_LISTEN state.
105*4882a593Smuzhiyun * @dwell: dwell time in ms for %WL_P2P_DISC_ST_LISTEN state.
106*4882a593Smuzhiyun */
107*4882a593Smuzhiyun struct brcmf_p2p_disc_st_le {
108*4882a593Smuzhiyun u8 state;
109*4882a593Smuzhiyun __le16 chspec;
110*4882a593Smuzhiyun __le16 dwell;
111*4882a593Smuzhiyun };
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun /**
114*4882a593Smuzhiyun * enum brcmf_p2p_disc_state - P2P discovery state values
115*4882a593Smuzhiyun *
116*4882a593Smuzhiyun * @WL_P2P_DISC_ST_SCAN: P2P discovery with wildcard SSID and P2P IE.
117*4882a593Smuzhiyun * @WL_P2P_DISC_ST_LISTEN: P2P discovery off-channel for specified time.
118*4882a593Smuzhiyun * @WL_P2P_DISC_ST_SEARCH: P2P discovery with P2P wildcard SSID and P2P IE.
119*4882a593Smuzhiyun */
120*4882a593Smuzhiyun enum brcmf_p2p_disc_state {
121*4882a593Smuzhiyun WL_P2P_DISC_ST_SCAN,
122*4882a593Smuzhiyun WL_P2P_DISC_ST_LISTEN,
123*4882a593Smuzhiyun WL_P2P_DISC_ST_SEARCH
124*4882a593Smuzhiyun };
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun /**
127*4882a593Smuzhiyun * struct brcmf_p2p_scan_le - P2P specific scan request.
128*4882a593Smuzhiyun *
129*4882a593Smuzhiyun * @type: type of scan method requested (values: 'E' or 'S').
130*4882a593Smuzhiyun * @reserved: reserved (ignored).
131*4882a593Smuzhiyun * @eparams: parameters used for type 'E'.
132*4882a593Smuzhiyun * @sparams: parameters used for type 'S'.
133*4882a593Smuzhiyun */
134*4882a593Smuzhiyun struct brcmf_p2p_scan_le {
135*4882a593Smuzhiyun u8 type;
136*4882a593Smuzhiyun u8 reserved[3];
137*4882a593Smuzhiyun union {
138*4882a593Smuzhiyun struct brcmf_escan_params_le eparams;
139*4882a593Smuzhiyun struct brcmf_scan_params_le sparams;
140*4882a593Smuzhiyun };
141*4882a593Smuzhiyun };
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun /**
144*4882a593Smuzhiyun * struct brcmf_p2p_pub_act_frame - WiFi P2P Public Action Frame
145*4882a593Smuzhiyun *
146*4882a593Smuzhiyun * @category: P2P_PUB_AF_CATEGORY
147*4882a593Smuzhiyun * @action: P2P_PUB_AF_ACTION
148*4882a593Smuzhiyun * @oui: P2P_OUI
149*4882a593Smuzhiyun * @oui_type: OUI type - P2P_VER
150*4882a593Smuzhiyun * @subtype: OUI subtype - P2P_TYPE_*
151*4882a593Smuzhiyun * @dialog_token: nonzero, identifies req/rsp transaction
152*4882a593Smuzhiyun * @elts: Variable length information elements.
153*4882a593Smuzhiyun */
154*4882a593Smuzhiyun struct brcmf_p2p_pub_act_frame {
155*4882a593Smuzhiyun u8 category;
156*4882a593Smuzhiyun u8 action;
157*4882a593Smuzhiyun u8 oui[3];
158*4882a593Smuzhiyun u8 oui_type;
159*4882a593Smuzhiyun u8 subtype;
160*4882a593Smuzhiyun u8 dialog_token;
161*4882a593Smuzhiyun u8 elts[1];
162*4882a593Smuzhiyun };
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun /**
165*4882a593Smuzhiyun * struct brcmf_p2p_action_frame - WiFi P2P Action Frame
166*4882a593Smuzhiyun *
167*4882a593Smuzhiyun * @category: P2P_AF_CATEGORY
168*4882a593Smuzhiyun * @oui: OUI - P2P_OUI
169*4882a593Smuzhiyun * @type: OUI Type - P2P_VER
170*4882a593Smuzhiyun * @subtype: OUI Subtype - P2P_AF_*
171*4882a593Smuzhiyun * @dialog_token: nonzero, identifies req/resp tranaction
172*4882a593Smuzhiyun * @elts: Variable length information elements.
173*4882a593Smuzhiyun */
174*4882a593Smuzhiyun struct brcmf_p2p_action_frame {
175*4882a593Smuzhiyun u8 category;
176*4882a593Smuzhiyun u8 oui[3];
177*4882a593Smuzhiyun u8 type;
178*4882a593Smuzhiyun u8 subtype;
179*4882a593Smuzhiyun u8 dialog_token;
180*4882a593Smuzhiyun u8 elts[1];
181*4882a593Smuzhiyun };
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun /**
184*4882a593Smuzhiyun * struct brcmf_p2psd_gas_pub_act_frame - Wi-Fi GAS Public Action Frame
185*4882a593Smuzhiyun *
186*4882a593Smuzhiyun * @category: 0x04 Public Action Frame
187*4882a593Smuzhiyun * @action: 0x6c Advertisement Protocol
188*4882a593Smuzhiyun * @dialog_token: nonzero, identifies req/rsp transaction
189*4882a593Smuzhiyun * @query_data: Query Data. SD gas ireq SD gas iresp
190*4882a593Smuzhiyun */
191*4882a593Smuzhiyun struct brcmf_p2psd_gas_pub_act_frame {
192*4882a593Smuzhiyun u8 category;
193*4882a593Smuzhiyun u8 action;
194*4882a593Smuzhiyun u8 dialog_token;
195*4882a593Smuzhiyun u8 query_data[1];
196*4882a593Smuzhiyun };
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun /**
199*4882a593Smuzhiyun * struct brcmf_config_af_params - Action Frame Parameters for tx.
200*4882a593Smuzhiyun *
201*4882a593Smuzhiyun * @mpc_onoff: To make sure to send successfully action frame, we have to
202*4882a593Smuzhiyun * turn off mpc 0: off, 1: on, (-1): do nothing
203*4882a593Smuzhiyun * @search_channel: 1: search peer's channel to send af
204*4882a593Smuzhiyun * @extra_listen: keep the dwell time to get af response frame.
205*4882a593Smuzhiyun */
206*4882a593Smuzhiyun struct brcmf_config_af_params {
207*4882a593Smuzhiyun s32 mpc_onoff;
208*4882a593Smuzhiyun bool search_channel;
209*4882a593Smuzhiyun bool extra_listen;
210*4882a593Smuzhiyun };
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun /**
213*4882a593Smuzhiyun * brcmf_p2p_is_pub_action() - true if p2p public type frame.
214*4882a593Smuzhiyun *
215*4882a593Smuzhiyun * @frame: action frame data.
216*4882a593Smuzhiyun * @frame_len: length of action frame data.
217*4882a593Smuzhiyun *
218*4882a593Smuzhiyun * Determine if action frame is p2p public action type
219*4882a593Smuzhiyun */
brcmf_p2p_is_pub_action(void * frame,u32 frame_len)220*4882a593Smuzhiyun static bool brcmf_p2p_is_pub_action(void *frame, u32 frame_len)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun struct brcmf_p2p_pub_act_frame *pact_frm;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun if (frame == NULL)
225*4882a593Smuzhiyun return false;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun pact_frm = (struct brcmf_p2p_pub_act_frame *)frame;
228*4882a593Smuzhiyun if (frame_len < sizeof(struct brcmf_p2p_pub_act_frame) - 1)
229*4882a593Smuzhiyun return false;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun if (pact_frm->category == P2P_PUB_AF_CATEGORY &&
232*4882a593Smuzhiyun pact_frm->action == P2P_PUB_AF_ACTION &&
233*4882a593Smuzhiyun pact_frm->oui_type == P2P_VER &&
234*4882a593Smuzhiyun memcmp(pact_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0)
235*4882a593Smuzhiyun return true;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun return false;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun /**
241*4882a593Smuzhiyun * brcmf_p2p_is_p2p_action() - true if p2p action type frame.
242*4882a593Smuzhiyun *
243*4882a593Smuzhiyun * @frame: action frame data.
244*4882a593Smuzhiyun * @frame_len: length of action frame data.
245*4882a593Smuzhiyun *
246*4882a593Smuzhiyun * Determine if action frame is p2p action type
247*4882a593Smuzhiyun */
brcmf_p2p_is_p2p_action(void * frame,u32 frame_len)248*4882a593Smuzhiyun static bool brcmf_p2p_is_p2p_action(void *frame, u32 frame_len)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun struct brcmf_p2p_action_frame *act_frm;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun if (frame == NULL)
253*4882a593Smuzhiyun return false;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun act_frm = (struct brcmf_p2p_action_frame *)frame;
256*4882a593Smuzhiyun if (frame_len < sizeof(struct brcmf_p2p_action_frame) - 1)
257*4882a593Smuzhiyun return false;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun if (act_frm->category == P2P_AF_CATEGORY &&
260*4882a593Smuzhiyun act_frm->type == P2P_VER &&
261*4882a593Smuzhiyun memcmp(act_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0)
262*4882a593Smuzhiyun return true;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun return false;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun /**
268*4882a593Smuzhiyun * brcmf_p2p_is_gas_action() - true if p2p gas action type frame.
269*4882a593Smuzhiyun *
270*4882a593Smuzhiyun * @frame: action frame data.
271*4882a593Smuzhiyun * @frame_len: length of action frame data.
272*4882a593Smuzhiyun *
273*4882a593Smuzhiyun * Determine if action frame is p2p gas action type
274*4882a593Smuzhiyun */
brcmf_p2p_is_gas_action(void * frame,u32 frame_len)275*4882a593Smuzhiyun static bool brcmf_p2p_is_gas_action(void *frame, u32 frame_len)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun if (frame == NULL)
280*4882a593Smuzhiyun return false;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;
283*4882a593Smuzhiyun if (frame_len < sizeof(struct brcmf_p2psd_gas_pub_act_frame) - 1)
284*4882a593Smuzhiyun return false;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)
287*4882a593Smuzhiyun return false;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ ||
290*4882a593Smuzhiyun sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP ||
291*4882a593Smuzhiyun sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ ||
292*4882a593Smuzhiyun sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP)
293*4882a593Smuzhiyun return true;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun return false;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun /**
299*4882a593Smuzhiyun * brcmf_p2p_print_actframe() - debug print routine.
300*4882a593Smuzhiyun *
301*4882a593Smuzhiyun * @tx: Received or to be transmitted
302*4882a593Smuzhiyun * @frame: action frame data.
303*4882a593Smuzhiyun * @frame_len: length of action frame data.
304*4882a593Smuzhiyun *
305*4882a593Smuzhiyun * Print information about the p2p action frame
306*4882a593Smuzhiyun */
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun #ifdef DEBUG
309*4882a593Smuzhiyun
brcmf_p2p_print_actframe(bool tx,void * frame,u32 frame_len)310*4882a593Smuzhiyun static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len)
311*4882a593Smuzhiyun {
312*4882a593Smuzhiyun struct brcmf_p2p_pub_act_frame *pact_frm;
313*4882a593Smuzhiyun struct brcmf_p2p_action_frame *act_frm;
314*4882a593Smuzhiyun struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun if (!frame || frame_len <= 2)
317*4882a593Smuzhiyun return;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun if (brcmf_p2p_is_pub_action(frame, frame_len)) {
320*4882a593Smuzhiyun pact_frm = (struct brcmf_p2p_pub_act_frame *)frame;
321*4882a593Smuzhiyun switch (pact_frm->subtype) {
322*4882a593Smuzhiyun case P2P_PAF_GON_REQ:
323*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Req Frame\n",
324*4882a593Smuzhiyun (tx) ? "TX" : "RX");
325*4882a593Smuzhiyun break;
326*4882a593Smuzhiyun case P2P_PAF_GON_RSP:
327*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Rsp Frame\n",
328*4882a593Smuzhiyun (tx) ? "TX" : "RX");
329*4882a593Smuzhiyun break;
330*4882a593Smuzhiyun case P2P_PAF_GON_CONF:
331*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Confirm Frame\n",
332*4882a593Smuzhiyun (tx) ? "TX" : "RX");
333*4882a593Smuzhiyun break;
334*4882a593Smuzhiyun case P2P_PAF_INVITE_REQ:
335*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P Invitation Request Frame\n",
336*4882a593Smuzhiyun (tx) ? "TX" : "RX");
337*4882a593Smuzhiyun break;
338*4882a593Smuzhiyun case P2P_PAF_INVITE_RSP:
339*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P Invitation Response Frame\n",
340*4882a593Smuzhiyun (tx) ? "TX" : "RX");
341*4882a593Smuzhiyun break;
342*4882a593Smuzhiyun case P2P_PAF_DEVDIS_REQ:
343*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P Device Discoverability Request Frame\n",
344*4882a593Smuzhiyun (tx) ? "TX" : "RX");
345*4882a593Smuzhiyun break;
346*4882a593Smuzhiyun case P2P_PAF_DEVDIS_RSP:
347*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P Device Discoverability Response Frame\n",
348*4882a593Smuzhiyun (tx) ? "TX" : "RX");
349*4882a593Smuzhiyun break;
350*4882a593Smuzhiyun case P2P_PAF_PROVDIS_REQ:
351*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P Provision Discovery Request Frame\n",
352*4882a593Smuzhiyun (tx) ? "TX" : "RX");
353*4882a593Smuzhiyun break;
354*4882a593Smuzhiyun case P2P_PAF_PROVDIS_RSP:
355*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P Provision Discovery Response Frame\n",
356*4882a593Smuzhiyun (tx) ? "TX" : "RX");
357*4882a593Smuzhiyun break;
358*4882a593Smuzhiyun default:
359*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s Unknown P2P Public Action Frame\n",
360*4882a593Smuzhiyun (tx) ? "TX" : "RX");
361*4882a593Smuzhiyun break;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun } else if (brcmf_p2p_is_p2p_action(frame, frame_len)) {
364*4882a593Smuzhiyun act_frm = (struct brcmf_p2p_action_frame *)frame;
365*4882a593Smuzhiyun switch (act_frm->subtype) {
366*4882a593Smuzhiyun case P2P_AF_NOTICE_OF_ABSENCE:
367*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P Notice of Absence Frame\n",
368*4882a593Smuzhiyun (tx) ? "TX" : "RX");
369*4882a593Smuzhiyun break;
370*4882a593Smuzhiyun case P2P_AF_PRESENCE_REQ:
371*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P Presence Request Frame\n",
372*4882a593Smuzhiyun (tx) ? "TX" : "RX");
373*4882a593Smuzhiyun break;
374*4882a593Smuzhiyun case P2P_AF_PRESENCE_RSP:
375*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P Presence Response Frame\n",
376*4882a593Smuzhiyun (tx) ? "TX" : "RX");
377*4882a593Smuzhiyun break;
378*4882a593Smuzhiyun case P2P_AF_GO_DISC_REQ:
379*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P Discoverability Request Frame\n",
380*4882a593Smuzhiyun (tx) ? "TX" : "RX");
381*4882a593Smuzhiyun break;
382*4882a593Smuzhiyun default:
383*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s Unknown P2P Action Frame\n",
384*4882a593Smuzhiyun (tx) ? "TX" : "RX");
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun } else if (brcmf_p2p_is_gas_action(frame, frame_len)) {
388*4882a593Smuzhiyun sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;
389*4882a593Smuzhiyun switch (sd_act_frm->action) {
390*4882a593Smuzhiyun case P2PSD_ACTION_ID_GAS_IREQ:
391*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P GAS Initial Request\n",
392*4882a593Smuzhiyun (tx) ? "TX" : "RX");
393*4882a593Smuzhiyun break;
394*4882a593Smuzhiyun case P2PSD_ACTION_ID_GAS_IRESP:
395*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P GAS Initial Response\n",
396*4882a593Smuzhiyun (tx) ? "TX" : "RX");
397*4882a593Smuzhiyun break;
398*4882a593Smuzhiyun case P2PSD_ACTION_ID_GAS_CREQ:
399*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P GAS Comback Request\n",
400*4882a593Smuzhiyun (tx) ? "TX" : "RX");
401*4882a593Smuzhiyun break;
402*4882a593Smuzhiyun case P2PSD_ACTION_ID_GAS_CRESP:
403*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s P2P GAS Comback Response\n",
404*4882a593Smuzhiyun (tx) ? "TX" : "RX");
405*4882a593Smuzhiyun break;
406*4882a593Smuzhiyun default:
407*4882a593Smuzhiyun brcmf_dbg(TRACE, "%s Unknown P2P GAS Frame\n",
408*4882a593Smuzhiyun (tx) ? "TX" : "RX");
409*4882a593Smuzhiyun break;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun #else
415*4882a593Smuzhiyun
brcmf_p2p_print_actframe(bool tx,void * frame,u32 frame_len)416*4882a593Smuzhiyun static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun #endif
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun /**
424*4882a593Smuzhiyun * brcmf_p2p_set_firmware() - prepare firmware for peer-to-peer operation.
425*4882a593Smuzhiyun *
426*4882a593Smuzhiyun * @ifp: ifp to use for iovars (primary).
427*4882a593Smuzhiyun * @p2p_mac: mac address to configure for p2p_da_override
428*4882a593Smuzhiyun */
brcmf_p2p_set_firmware(struct brcmf_if * ifp,u8 * p2p_mac)429*4882a593Smuzhiyun static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun struct brcmf_pub *drvr = ifp->drvr;
432*4882a593Smuzhiyun s32 ret = 0;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
435*4882a593Smuzhiyun brcmf_fil_iovar_int_set(ifp, "apsta", 1);
436*4882a593Smuzhiyun brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun /* In case of COB type, firmware has default mac address
439*4882a593Smuzhiyun * After Initializing firmware, we have to set current mac address to
440*4882a593Smuzhiyun * firmware for P2P device address. This must be done with discovery
441*4882a593Smuzhiyun * disabled.
442*4882a593Smuzhiyun */
443*4882a593Smuzhiyun brcmf_fil_iovar_int_set(ifp, "p2p_disc", 0);
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun ret = brcmf_fil_iovar_data_set(ifp, "p2p_da_override", p2p_mac,
446*4882a593Smuzhiyun ETH_ALEN);
447*4882a593Smuzhiyun if (ret)
448*4882a593Smuzhiyun bphy_err(drvr, "failed to update device address ret %d\n", ret);
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun return ret;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun /**
454*4882a593Smuzhiyun * brcmf_p2p_generate_bss_mac() - derive mac addresses for P2P.
455*4882a593Smuzhiyun *
456*4882a593Smuzhiyun * @p2p: P2P specific data.
457*4882a593Smuzhiyun * @dev_addr: optional device address.
458*4882a593Smuzhiyun *
459*4882a593Smuzhiyun * P2P needs mac addresses for P2P device and interface. If no device
460*4882a593Smuzhiyun * address it specified, these are derived from a random ethernet
461*4882a593Smuzhiyun * address.
462*4882a593Smuzhiyun */
brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info * p2p,u8 * dev_addr)463*4882a593Smuzhiyun static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
466*4882a593Smuzhiyun bool random_addr = false;
467*4882a593Smuzhiyun bool local_admin = false;
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun if (!dev_addr || is_zero_ether_addr(dev_addr)) {
470*4882a593Smuzhiyun /* If the primary interface address is already locally
471*4882a593Smuzhiyun * administered, create a new random address.
472*4882a593Smuzhiyun */
473*4882a593Smuzhiyun if (pri_ifp->mac_addr[0] & 0x02) {
474*4882a593Smuzhiyun random_addr = true;
475*4882a593Smuzhiyun } else {
476*4882a593Smuzhiyun dev_addr = pri_ifp->mac_addr;
477*4882a593Smuzhiyun local_admin = true;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun /* Generate the P2P Device Address obtaining a random ethernet
482*4882a593Smuzhiyun * address with the locally administered bit set.
483*4882a593Smuzhiyun */
484*4882a593Smuzhiyun if (random_addr)
485*4882a593Smuzhiyun eth_random_addr(p2p->dev_addr);
486*4882a593Smuzhiyun else
487*4882a593Smuzhiyun memcpy(p2p->dev_addr, dev_addr, ETH_ALEN);
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun if (local_admin)
490*4882a593Smuzhiyun p2p->dev_addr[0] |= 0x02;
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun /* Generate the P2P Interface Address. If the discovery and connection
493*4882a593Smuzhiyun * BSSCFGs need to simultaneously co-exist, then this address must be
494*4882a593Smuzhiyun * different from the P2P Device Address, but also locally administered.
495*4882a593Smuzhiyun */
496*4882a593Smuzhiyun memcpy(p2p->conn_int_addr, p2p->dev_addr, ETH_ALEN);
497*4882a593Smuzhiyun p2p->conn_int_addr[0] |= 0x02;
498*4882a593Smuzhiyun p2p->conn_int_addr[4] ^= 0x80;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun memcpy(p2p->conn2_int_addr, p2p->dev_addr, ETH_ALEN);
501*4882a593Smuzhiyun p2p->conn2_int_addr[0] |= 0x02;
502*4882a593Smuzhiyun p2p->conn2_int_addr[4] ^= 0x90;
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun /**
506*4882a593Smuzhiyun * brcmf_p2p_scan_is_p2p_request() - is cfg80211 scan request a P2P scan.
507*4882a593Smuzhiyun *
508*4882a593Smuzhiyun * @request: the scan request as received from cfg80211.
509*4882a593Smuzhiyun *
510*4882a593Smuzhiyun * returns true if one of the ssids in the request matches the
511*4882a593Smuzhiyun * P2P wildcard ssid; otherwise returns false.
512*4882a593Smuzhiyun */
brcmf_p2p_scan_is_p2p_request(struct cfg80211_scan_request * request)513*4882a593Smuzhiyun static bool brcmf_p2p_scan_is_p2p_request(struct cfg80211_scan_request *request)
514*4882a593Smuzhiyun {
515*4882a593Smuzhiyun struct cfg80211_ssid *ssids = request->ssids;
516*4882a593Smuzhiyun int i;
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun for (i = 0; i < request->n_ssids; i++) {
519*4882a593Smuzhiyun if (ssids[i].ssid_len != BRCMF_P2P_WILDCARD_SSID_LEN)
520*4882a593Smuzhiyun continue;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun brcmf_dbg(INFO, "comparing ssid \"%s\"", ssids[i].ssid);
523*4882a593Smuzhiyun if (!memcmp(BRCMF_P2P_WILDCARD_SSID, ssids[i].ssid,
524*4882a593Smuzhiyun BRCMF_P2P_WILDCARD_SSID_LEN))
525*4882a593Smuzhiyun return true;
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun return false;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun /**
531*4882a593Smuzhiyun * brcmf_p2p_set_discover_state - set discover state in firmware.
532*4882a593Smuzhiyun *
533*4882a593Smuzhiyun * @ifp: low-level interface object.
534*4882a593Smuzhiyun * @state: discover state to set.
535*4882a593Smuzhiyun * @chanspec: channel parameters (for state @WL_P2P_DISC_ST_LISTEN only).
536*4882a593Smuzhiyun * @listen_ms: duration to listen (for state @WL_P2P_DISC_ST_LISTEN only).
537*4882a593Smuzhiyun */
brcmf_p2p_set_discover_state(struct brcmf_if * ifp,u8 state,u16 chanspec,u16 listen_ms)538*4882a593Smuzhiyun static s32 brcmf_p2p_set_discover_state(struct brcmf_if *ifp, u8 state,
539*4882a593Smuzhiyun u16 chanspec, u16 listen_ms)
540*4882a593Smuzhiyun {
541*4882a593Smuzhiyun struct brcmf_p2p_disc_st_le discover_state;
542*4882a593Smuzhiyun s32 ret = 0;
543*4882a593Smuzhiyun brcmf_dbg(TRACE, "enter\n");
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun discover_state.state = state;
546*4882a593Smuzhiyun discover_state.chspec = cpu_to_le16(chanspec);
547*4882a593Smuzhiyun discover_state.dwell = cpu_to_le16(listen_ms);
548*4882a593Smuzhiyun ret = brcmf_fil_bsscfg_data_set(ifp, "p2p_state", &discover_state,
549*4882a593Smuzhiyun sizeof(discover_state));
550*4882a593Smuzhiyun return ret;
551*4882a593Smuzhiyun }
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun /**
554*4882a593Smuzhiyun * brcmf_p2p_deinit_discovery() - disable P2P device discovery.
555*4882a593Smuzhiyun *
556*4882a593Smuzhiyun * @p2p: P2P specific data.
557*4882a593Smuzhiyun *
558*4882a593Smuzhiyun * Resets the discovery state and disables it in firmware.
559*4882a593Smuzhiyun */
brcmf_p2p_deinit_discovery(struct brcmf_p2p_info * p2p)560*4882a593Smuzhiyun static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun struct brcmf_cfg80211_vif *vif;
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun brcmf_dbg(TRACE, "enter\n");
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun /* Set the discovery state to SCAN */
567*4882a593Smuzhiyun vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
568*4882a593Smuzhiyun (void)brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun /* Disable P2P discovery in the firmware */
571*4882a593Smuzhiyun vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
572*4882a593Smuzhiyun (void)brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 0);
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun return 0;
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun /**
578*4882a593Smuzhiyun * brcmf_p2p_enable_discovery() - initialize and configure discovery.
579*4882a593Smuzhiyun *
580*4882a593Smuzhiyun * @p2p: P2P specific data.
581*4882a593Smuzhiyun *
582*4882a593Smuzhiyun * Initializes the discovery device and configure the virtual interface.
583*4882a593Smuzhiyun */
brcmf_p2p_enable_discovery(struct brcmf_p2p_info * p2p)584*4882a593Smuzhiyun static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun struct brcmf_pub *drvr = p2p->cfg->pub;
587*4882a593Smuzhiyun struct brcmf_cfg80211_vif *vif;
588*4882a593Smuzhiyun s32 ret = 0;
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun brcmf_dbg(TRACE, "enter\n");
591*4882a593Smuzhiyun vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
592*4882a593Smuzhiyun if (!vif) {
593*4882a593Smuzhiyun bphy_err(drvr, "P2P config device not available\n");
594*4882a593Smuzhiyun ret = -EPERM;
595*4882a593Smuzhiyun goto exit;
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun if (test_bit(BRCMF_P2P_STATUS_ENABLED, &p2p->status)) {
599*4882a593Smuzhiyun brcmf_dbg(INFO, "P2P config device already configured\n");
600*4882a593Smuzhiyun goto exit;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun /* Re-initialize P2P Discovery in the firmware */
604*4882a593Smuzhiyun vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
605*4882a593Smuzhiyun ret = brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 1);
606*4882a593Smuzhiyun if (ret < 0) {
607*4882a593Smuzhiyun bphy_err(drvr, "set p2p_disc error\n");
608*4882a593Smuzhiyun goto exit;
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
611*4882a593Smuzhiyun ret = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
612*4882a593Smuzhiyun if (ret < 0) {
613*4882a593Smuzhiyun bphy_err(drvr, "unable to set WL_P2P_DISC_ST_SCAN\n");
614*4882a593Smuzhiyun goto exit;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun /*
618*4882a593Smuzhiyun * Set wsec to any non-zero value in the discovery bsscfg
619*4882a593Smuzhiyun * to ensure our P2P probe responses have the privacy bit
620*4882a593Smuzhiyun * set in the 802.11 WPA IE. Some peer devices may not
621*4882a593Smuzhiyun * initiate WPS with us if this bit is not set.
622*4882a593Smuzhiyun */
623*4882a593Smuzhiyun ret = brcmf_fil_bsscfg_int_set(vif->ifp, "wsec", AES_ENABLED);
624*4882a593Smuzhiyun if (ret < 0) {
625*4882a593Smuzhiyun bphy_err(drvr, "wsec error %d\n", ret);
626*4882a593Smuzhiyun goto exit;
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun set_bit(BRCMF_P2P_STATUS_ENABLED, &p2p->status);
630*4882a593Smuzhiyun exit:
631*4882a593Smuzhiyun return ret;
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun /**
635*4882a593Smuzhiyun * brcmf_p2p_escan() - initiate a P2P scan.
636*4882a593Smuzhiyun *
637*4882a593Smuzhiyun * @p2p: P2P specific data.
638*4882a593Smuzhiyun * @num_chans: number of channels to scan.
639*4882a593Smuzhiyun * @chanspecs: channel parameters for @num_chans channels.
640*4882a593Smuzhiyun * @search_state: P2P discover state to use.
641*4882a593Smuzhiyun * @bss_type: type of P2P bss.
642*4882a593Smuzhiyun */
brcmf_p2p_escan(struct brcmf_p2p_info * p2p,u32 num_chans,u16 chanspecs[],s32 search_state,enum p2p_bss_type bss_type)643*4882a593Smuzhiyun static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans,
644*4882a593Smuzhiyun u16 chanspecs[], s32 search_state,
645*4882a593Smuzhiyun enum p2p_bss_type bss_type)
646*4882a593Smuzhiyun {
647*4882a593Smuzhiyun struct brcmf_pub *drvr = p2p->cfg->pub;
648*4882a593Smuzhiyun s32 ret = 0;
649*4882a593Smuzhiyun s32 memsize = offsetof(struct brcmf_p2p_scan_le,
650*4882a593Smuzhiyun eparams.params_le.channel_list);
651*4882a593Smuzhiyun s32 nprobes;
652*4882a593Smuzhiyun s32 active;
653*4882a593Smuzhiyun u32 i;
654*4882a593Smuzhiyun u8 *memblk;
655*4882a593Smuzhiyun struct brcmf_cfg80211_vif *vif;
656*4882a593Smuzhiyun struct brcmf_p2p_scan_le *p2p_params;
657*4882a593Smuzhiyun struct brcmf_scan_params_le *sparams;
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun memsize += num_chans * sizeof(__le16);
660*4882a593Smuzhiyun memblk = kzalloc(memsize, GFP_KERNEL);
661*4882a593Smuzhiyun if (!memblk)
662*4882a593Smuzhiyun return -ENOMEM;
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun vif = p2p->bss_idx[bss_type].vif;
665*4882a593Smuzhiyun if (vif == NULL) {
666*4882a593Smuzhiyun bphy_err(drvr, "no vif for bss type %d\n", bss_type);
667*4882a593Smuzhiyun ret = -EINVAL;
668*4882a593Smuzhiyun goto exit;
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun p2p_params = (struct brcmf_p2p_scan_le *)memblk;
671*4882a593Smuzhiyun sparams = &p2p_params->eparams.params_le;
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun switch (search_state) {
674*4882a593Smuzhiyun case WL_P2P_DISC_ST_SEARCH:
675*4882a593Smuzhiyun /*
676*4882a593Smuzhiyun * If we in SEARCH STATE, we don't need to set SSID explictly
677*4882a593Smuzhiyun * because dongle use P2P WILDCARD internally by default, use
678*4882a593Smuzhiyun * null ssid, which it is already due to kzalloc.
679*4882a593Smuzhiyun */
680*4882a593Smuzhiyun break;
681*4882a593Smuzhiyun case WL_P2P_DISC_ST_SCAN:
682*4882a593Smuzhiyun /*
683*4882a593Smuzhiyun * wpa_supplicant has p2p_find command with type social or
684*4882a593Smuzhiyun * progressive. For progressive, we need to set the ssid to
685*4882a593Smuzhiyun * P2P WILDCARD because we just do broadcast scan unless
686*4882a593Smuzhiyun * setting SSID.
687*4882a593Smuzhiyun */
688*4882a593Smuzhiyun sparams->ssid_le.SSID_len =
689*4882a593Smuzhiyun cpu_to_le32(BRCMF_P2P_WILDCARD_SSID_LEN);
690*4882a593Smuzhiyun memcpy(sparams->ssid_le.SSID, BRCMF_P2P_WILDCARD_SSID,
691*4882a593Smuzhiyun BRCMF_P2P_WILDCARD_SSID_LEN);
692*4882a593Smuzhiyun break;
693*4882a593Smuzhiyun default:
694*4882a593Smuzhiyun bphy_err(drvr, " invalid search state %d\n", search_state);
695*4882a593Smuzhiyun ret = -EINVAL;
696*4882a593Smuzhiyun goto exit;
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun brcmf_p2p_set_discover_state(vif->ifp, search_state, 0, 0);
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun /*
702*4882a593Smuzhiyun * set p2p scan parameters.
703*4882a593Smuzhiyun */
704*4882a593Smuzhiyun p2p_params->type = 'E';
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun /* determine the scan engine parameters */
707*4882a593Smuzhiyun sparams->bss_type = DOT11_BSSTYPE_ANY;
708*4882a593Smuzhiyun sparams->scan_type = BRCMF_SCANTYPE_ACTIVE;
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun eth_broadcast_addr(sparams->bssid);
711*4882a593Smuzhiyun sparams->home_time = cpu_to_le32(P2PAPI_SCAN_HOME_TIME_MS);
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun /*
714*4882a593Smuzhiyun * SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan
715*4882a593Smuzhiyun * supported by the supplicant.
716*4882a593Smuzhiyun */
717*4882a593Smuzhiyun if (num_chans == SOCIAL_CHAN_CNT || num_chans == (SOCIAL_CHAN_CNT + 1))
718*4882a593Smuzhiyun active = P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS;
719*4882a593Smuzhiyun else if (num_chans == AF_PEER_SEARCH_CNT)
720*4882a593Smuzhiyun active = P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS;
721*4882a593Smuzhiyun else if (brcmf_get_vif_state_any(p2p->cfg, BRCMF_VIF_STATUS_CONNECTED))
722*4882a593Smuzhiyun active = -1;
723*4882a593Smuzhiyun else
724*4882a593Smuzhiyun active = P2PAPI_SCAN_DWELL_TIME_MS;
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun /* Override scan params to find a peer for a connection */
727*4882a593Smuzhiyun if (num_chans == 1) {
728*4882a593Smuzhiyun active = WL_SCAN_CONNECT_DWELL_TIME_MS;
729*4882a593Smuzhiyun /* WAR to sync with presence period of VSDB GO.
730*4882a593Smuzhiyun * send probe request more frequently
731*4882a593Smuzhiyun */
732*4882a593Smuzhiyun nprobes = active / WL_SCAN_JOIN_PROBE_INTERVAL_MS;
733*4882a593Smuzhiyun } else {
734*4882a593Smuzhiyun nprobes = active / P2PAPI_SCAN_NPROBS_TIME_MS;
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun if (nprobes <= 0)
738*4882a593Smuzhiyun nprobes = 1;
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun brcmf_dbg(INFO, "nprobes # %d, active_time %d\n", nprobes, active);
741*4882a593Smuzhiyun sparams->active_time = cpu_to_le32(active);
742*4882a593Smuzhiyun sparams->nprobes = cpu_to_le32(nprobes);
743*4882a593Smuzhiyun sparams->passive_time = cpu_to_le32(-1);
744*4882a593Smuzhiyun sparams->channel_num = cpu_to_le32(num_chans &
745*4882a593Smuzhiyun BRCMF_SCAN_PARAMS_COUNT_MASK);
746*4882a593Smuzhiyun for (i = 0; i < num_chans; i++)
747*4882a593Smuzhiyun sparams->channel_list[i] = cpu_to_le16(chanspecs[i]);
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun /* set the escan specific parameters */
750*4882a593Smuzhiyun p2p_params->eparams.version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
751*4882a593Smuzhiyun p2p_params->eparams.action = cpu_to_le16(WL_ESCAN_ACTION_START);
752*4882a593Smuzhiyun p2p_params->eparams.sync_id = cpu_to_le16(0x1234);
753*4882a593Smuzhiyun /* perform p2p scan on primary device */
754*4882a593Smuzhiyun ret = brcmf_fil_bsscfg_data_set(vif->ifp, "p2p_scan", memblk, memsize);
755*4882a593Smuzhiyun if (!ret)
756*4882a593Smuzhiyun set_bit(BRCMF_SCAN_STATUS_BUSY, &p2p->cfg->scan_status);
757*4882a593Smuzhiyun exit:
758*4882a593Smuzhiyun kfree(memblk);
759*4882a593Smuzhiyun return ret;
760*4882a593Smuzhiyun }
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun /**
763*4882a593Smuzhiyun * brcmf_p2p_run_escan() - escan callback for peer-to-peer.
764*4882a593Smuzhiyun *
765*4882a593Smuzhiyun * @cfg: driver private data for cfg80211 interface.
766*4882a593Smuzhiyun * @ifp: interface control.
767*4882a593Smuzhiyun * @request: scan request from cfg80211.
768*4882a593Smuzhiyun *
769*4882a593Smuzhiyun * Determines the P2P discovery state based to scan request parameters and
770*4882a593Smuzhiyun * validates the channels in the request.
771*4882a593Smuzhiyun */
brcmf_p2p_run_escan(struct brcmf_cfg80211_info * cfg,struct brcmf_if * ifp,struct cfg80211_scan_request * request)772*4882a593Smuzhiyun static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,
773*4882a593Smuzhiyun struct brcmf_if *ifp,
774*4882a593Smuzhiyun struct cfg80211_scan_request *request)
775*4882a593Smuzhiyun {
776*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = &cfg->p2p;
777*4882a593Smuzhiyun struct brcmf_pub *drvr = cfg->pub;
778*4882a593Smuzhiyun s32 err = 0;
779*4882a593Smuzhiyun s32 search_state = WL_P2P_DISC_ST_SCAN;
780*4882a593Smuzhiyun struct brcmf_cfg80211_vif *vif;
781*4882a593Smuzhiyun struct net_device *dev = NULL;
782*4882a593Smuzhiyun int i, num_nodfs = 0;
783*4882a593Smuzhiyun u16 *chanspecs;
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun brcmf_dbg(TRACE, "enter\n");
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun if (!request) {
788*4882a593Smuzhiyun err = -EINVAL;
789*4882a593Smuzhiyun goto exit;
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun
792*4882a593Smuzhiyun if (request->n_channels) {
793*4882a593Smuzhiyun chanspecs = kcalloc(request->n_channels, sizeof(*chanspecs),
794*4882a593Smuzhiyun GFP_KERNEL);
795*4882a593Smuzhiyun if (!chanspecs) {
796*4882a593Smuzhiyun err = -ENOMEM;
797*4882a593Smuzhiyun goto exit;
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;
800*4882a593Smuzhiyun if (vif)
801*4882a593Smuzhiyun dev = vif->wdev.netdev;
802*4882a593Smuzhiyun if (request->n_channels == 3 &&
803*4882a593Smuzhiyun request->channels[0]->hw_value == SOCIAL_CHAN_1 &&
804*4882a593Smuzhiyun request->channels[1]->hw_value == SOCIAL_CHAN_2 &&
805*4882a593Smuzhiyun request->channels[2]->hw_value == SOCIAL_CHAN_3) {
806*4882a593Smuzhiyun /* SOCIAL CHANNELS 1, 6, 11 */
807*4882a593Smuzhiyun search_state = WL_P2P_DISC_ST_SEARCH;
808*4882a593Smuzhiyun brcmf_dbg(INFO, "P2P SEARCH PHASE START\n");
809*4882a593Smuzhiyun } else if (dev != NULL &&
810*4882a593Smuzhiyun vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
811*4882a593Smuzhiyun /* If you are already a GO, then do SEARCH only */
812*4882a593Smuzhiyun brcmf_dbg(INFO, "Already a GO. Do SEARCH Only\n");
813*4882a593Smuzhiyun search_state = WL_P2P_DISC_ST_SEARCH;
814*4882a593Smuzhiyun } else {
815*4882a593Smuzhiyun brcmf_dbg(INFO, "P2P SCAN STATE START\n");
816*4882a593Smuzhiyun }
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun /*
819*4882a593Smuzhiyun * no P2P scanning on passive or DFS channels.
820*4882a593Smuzhiyun */
821*4882a593Smuzhiyun for (i = 0; i < request->n_channels; i++) {
822*4882a593Smuzhiyun struct ieee80211_channel *chan = request->channels[i];
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun if (chan->flags & (IEEE80211_CHAN_RADAR |
825*4882a593Smuzhiyun IEEE80211_CHAN_NO_IR))
826*4882a593Smuzhiyun continue;
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun chanspecs[i] = channel_to_chanspec(&p2p->cfg->d11inf,
829*4882a593Smuzhiyun chan);
830*4882a593Smuzhiyun brcmf_dbg(INFO, "%d: chan=%d, channel spec=%x\n",
831*4882a593Smuzhiyun num_nodfs, chan->hw_value, chanspecs[i]);
832*4882a593Smuzhiyun num_nodfs++;
833*4882a593Smuzhiyun }
834*4882a593Smuzhiyun err = brcmf_p2p_escan(p2p, num_nodfs, chanspecs, search_state,
835*4882a593Smuzhiyun P2PAPI_BSSCFG_DEVICE);
836*4882a593Smuzhiyun kfree(chanspecs);
837*4882a593Smuzhiyun }
838*4882a593Smuzhiyun exit:
839*4882a593Smuzhiyun if (err)
840*4882a593Smuzhiyun bphy_err(drvr, "error (%d)\n", err);
841*4882a593Smuzhiyun return err;
842*4882a593Smuzhiyun }
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun
845*4882a593Smuzhiyun /**
846*4882a593Smuzhiyun * brcmf_p2p_find_listen_channel() - find listen channel in ie string.
847*4882a593Smuzhiyun *
848*4882a593Smuzhiyun * @ie: string of information elements.
849*4882a593Smuzhiyun * @ie_len: length of string.
850*4882a593Smuzhiyun *
851*4882a593Smuzhiyun * Scan ie for p2p ie and look for attribute 6 channel. If available determine
852*4882a593Smuzhiyun * channel and return it.
853*4882a593Smuzhiyun */
brcmf_p2p_find_listen_channel(const u8 * ie,u32 ie_len)854*4882a593Smuzhiyun static s32 brcmf_p2p_find_listen_channel(const u8 *ie, u32 ie_len)
855*4882a593Smuzhiyun {
856*4882a593Smuzhiyun u8 channel_ie[5];
857*4882a593Smuzhiyun s32 listen_channel;
858*4882a593Smuzhiyun s32 err;
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun err = cfg80211_get_p2p_attr(ie, ie_len,
861*4882a593Smuzhiyun IEEE80211_P2P_ATTR_LISTEN_CHANNEL,
862*4882a593Smuzhiyun channel_ie, sizeof(channel_ie));
863*4882a593Smuzhiyun if (err < 0)
864*4882a593Smuzhiyun return err;
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun /* listen channel subel length format: */
867*4882a593Smuzhiyun /* 3(country) + 1(op. class) + 1(chan num) */
868*4882a593Smuzhiyun listen_channel = (s32)channel_ie[3 + 1];
869*4882a593Smuzhiyun
870*4882a593Smuzhiyun if (listen_channel == SOCIAL_CHAN_1 ||
871*4882a593Smuzhiyun listen_channel == SOCIAL_CHAN_2 ||
872*4882a593Smuzhiyun listen_channel == SOCIAL_CHAN_3) {
873*4882a593Smuzhiyun brcmf_dbg(INFO, "Found my Listen Channel %d\n", listen_channel);
874*4882a593Smuzhiyun return listen_channel;
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun return -EPERM;
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun
881*4882a593Smuzhiyun /**
882*4882a593Smuzhiyun * brcmf_p2p_scan_prep() - prepare scan based on request.
883*4882a593Smuzhiyun *
884*4882a593Smuzhiyun * @wiphy: wiphy device.
885*4882a593Smuzhiyun * @request: scan request from cfg80211.
886*4882a593Smuzhiyun * @vif: vif on which scan request is to be executed.
887*4882a593Smuzhiyun *
888*4882a593Smuzhiyun * Prepare the scan appropriately for type of scan requested. Overrides the
889*4882a593Smuzhiyun * escan .run() callback for peer-to-peer scanning.
890*4882a593Smuzhiyun */
brcmf_p2p_scan_prep(struct wiphy * wiphy,struct cfg80211_scan_request * request,struct brcmf_cfg80211_vif * vif)891*4882a593Smuzhiyun int brcmf_p2p_scan_prep(struct wiphy *wiphy,
892*4882a593Smuzhiyun struct cfg80211_scan_request *request,
893*4882a593Smuzhiyun struct brcmf_cfg80211_vif *vif)
894*4882a593Smuzhiyun {
895*4882a593Smuzhiyun struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
896*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = &cfg->p2p;
897*4882a593Smuzhiyun int err;
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun if (brcmf_p2p_scan_is_p2p_request(request)) {
900*4882a593Smuzhiyun /* find my listen channel */
901*4882a593Smuzhiyun err = brcmf_p2p_find_listen_channel(request->ie,
902*4882a593Smuzhiyun request->ie_len);
903*4882a593Smuzhiyun if (err < 0)
904*4882a593Smuzhiyun return err;
905*4882a593Smuzhiyun
906*4882a593Smuzhiyun p2p->afx_hdl.my_listen_chan = err;
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
909*4882a593Smuzhiyun brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n");
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun err = brcmf_p2p_enable_discovery(p2p);
912*4882a593Smuzhiyun if (err)
913*4882a593Smuzhiyun return err;
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun /* override .run_escan() callback. */
916*4882a593Smuzhiyun cfg->escan_info.run = brcmf_p2p_run_escan;
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun return 0;
919*4882a593Smuzhiyun }
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun
922*4882a593Smuzhiyun /**
923*4882a593Smuzhiyun * brcmf_p2p_discover_listen() - set firmware to discover listen state.
924*4882a593Smuzhiyun *
925*4882a593Smuzhiyun * @p2p: p2p device.
926*4882a593Smuzhiyun * @channel: channel nr for discover listen.
927*4882a593Smuzhiyun * @duration: time in ms to stay on channel.
928*4882a593Smuzhiyun *
929*4882a593Smuzhiyun */
930*4882a593Smuzhiyun static s32
brcmf_p2p_discover_listen(struct brcmf_p2p_info * p2p,u16 channel,u32 duration)931*4882a593Smuzhiyun brcmf_p2p_discover_listen(struct brcmf_p2p_info *p2p, u16 channel, u32 duration)
932*4882a593Smuzhiyun {
933*4882a593Smuzhiyun struct brcmf_pub *drvr = p2p->cfg->pub;
934*4882a593Smuzhiyun struct brcmf_cfg80211_vif *vif;
935*4882a593Smuzhiyun struct brcmu_chan ch;
936*4882a593Smuzhiyun s32 err = 0;
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
939*4882a593Smuzhiyun if (!vif) {
940*4882a593Smuzhiyun bphy_err(drvr, "Discovery is not set, so we have nothing to do\n");
941*4882a593Smuzhiyun err = -EPERM;
942*4882a593Smuzhiyun goto exit;
943*4882a593Smuzhiyun }
944*4882a593Smuzhiyun
945*4882a593Smuzhiyun if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status)) {
946*4882a593Smuzhiyun bphy_err(drvr, "Previous LISTEN is not completed yet\n");
947*4882a593Smuzhiyun /* WAR: prevent cookie mismatch in wpa_supplicant return OK */
948*4882a593Smuzhiyun goto exit;
949*4882a593Smuzhiyun }
950*4882a593Smuzhiyun
951*4882a593Smuzhiyun ch.chnum = channel;
952*4882a593Smuzhiyun ch.bw = BRCMU_CHAN_BW_20;
953*4882a593Smuzhiyun p2p->cfg->d11inf.encchspec(&ch);
954*4882a593Smuzhiyun err = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_LISTEN,
955*4882a593Smuzhiyun ch.chspec, (u16)duration);
956*4882a593Smuzhiyun if (!err) {
957*4882a593Smuzhiyun set_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status);
958*4882a593Smuzhiyun p2p->remain_on_channel_cookie++;
959*4882a593Smuzhiyun }
960*4882a593Smuzhiyun exit:
961*4882a593Smuzhiyun return err;
962*4882a593Smuzhiyun }
963*4882a593Smuzhiyun
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun /**
966*4882a593Smuzhiyun * brcmf_p2p_remain_on_channel() - put device on channel and stay there.
967*4882a593Smuzhiyun *
968*4882a593Smuzhiyun * @wiphy: wiphy device.
969*4882a593Smuzhiyun * @wdev: wireless device.
970*4882a593Smuzhiyun * @channel: channel to stay on.
971*4882a593Smuzhiyun * @duration: time in ms to remain on channel.
972*4882a593Smuzhiyun * @cookie: cookie.
973*4882a593Smuzhiyun */
brcmf_p2p_remain_on_channel(struct wiphy * wiphy,struct wireless_dev * wdev,struct ieee80211_channel * channel,unsigned int duration,u64 * cookie)974*4882a593Smuzhiyun int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
975*4882a593Smuzhiyun struct ieee80211_channel *channel,
976*4882a593Smuzhiyun unsigned int duration, u64 *cookie)
977*4882a593Smuzhiyun {
978*4882a593Smuzhiyun struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
979*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = &cfg->p2p;
980*4882a593Smuzhiyun s32 err;
981*4882a593Smuzhiyun u16 channel_nr;
982*4882a593Smuzhiyun
983*4882a593Smuzhiyun channel_nr = ieee80211_frequency_to_channel(channel->center_freq);
984*4882a593Smuzhiyun brcmf_dbg(TRACE, "Enter, channel: %d, duration ms (%d)\n", channel_nr,
985*4882a593Smuzhiyun duration);
986*4882a593Smuzhiyun
987*4882a593Smuzhiyun err = brcmf_p2p_enable_discovery(p2p);
988*4882a593Smuzhiyun if (err)
989*4882a593Smuzhiyun goto exit;
990*4882a593Smuzhiyun err = brcmf_p2p_discover_listen(p2p, channel_nr, duration);
991*4882a593Smuzhiyun if (err)
992*4882a593Smuzhiyun goto exit;
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun memcpy(&p2p->remain_on_channel, channel, sizeof(*channel));
995*4882a593Smuzhiyun *cookie = p2p->remain_on_channel_cookie;
996*4882a593Smuzhiyun cfg80211_ready_on_channel(wdev, *cookie, channel, duration, GFP_KERNEL);
997*4882a593Smuzhiyun
998*4882a593Smuzhiyun exit:
999*4882a593Smuzhiyun return err;
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun
1002*4882a593Smuzhiyun
1003*4882a593Smuzhiyun /**
1004*4882a593Smuzhiyun * brcmf_p2p_notify_listen_complete() - p2p listen has completed.
1005*4882a593Smuzhiyun *
1006*4882a593Smuzhiyun * @ifp: interfac control.
1007*4882a593Smuzhiyun * @e: event message. Not used, to make it usable for fweh event dispatcher.
1008*4882a593Smuzhiyun * @data: payload of message. Not used.
1009*4882a593Smuzhiyun *
1010*4882a593Smuzhiyun */
brcmf_p2p_notify_listen_complete(struct brcmf_if * ifp,const struct brcmf_event_msg * e,void * data)1011*4882a593Smuzhiyun int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
1012*4882a593Smuzhiyun const struct brcmf_event_msg *e,
1013*4882a593Smuzhiyun void *data)
1014*4882a593Smuzhiyun {
1015*4882a593Smuzhiyun struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
1016*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = &cfg->p2p;
1017*4882a593Smuzhiyun
1018*4882a593Smuzhiyun brcmf_dbg(TRACE, "Enter\n");
1019*4882a593Smuzhiyun if (test_and_clear_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN,
1020*4882a593Smuzhiyun &p2p->status)) {
1021*4882a593Smuzhiyun if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
1022*4882a593Smuzhiyun &p2p->status)) {
1023*4882a593Smuzhiyun clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
1024*4882a593Smuzhiyun &p2p->status);
1025*4882a593Smuzhiyun brcmf_dbg(INFO, "Listen DONE, wake up wait_next_af\n");
1026*4882a593Smuzhiyun complete(&p2p->wait_next_af);
1027*4882a593Smuzhiyun }
1028*4882a593Smuzhiyun
1029*4882a593Smuzhiyun cfg80211_remain_on_channel_expired(&ifp->vif->wdev,
1030*4882a593Smuzhiyun p2p->remain_on_channel_cookie,
1031*4882a593Smuzhiyun &p2p->remain_on_channel,
1032*4882a593Smuzhiyun GFP_KERNEL);
1033*4882a593Smuzhiyun }
1034*4882a593Smuzhiyun return 0;
1035*4882a593Smuzhiyun }
1036*4882a593Smuzhiyun
1037*4882a593Smuzhiyun
1038*4882a593Smuzhiyun /**
1039*4882a593Smuzhiyun * brcmf_p2p_cancel_remain_on_channel() - cancel p2p listen state.
1040*4882a593Smuzhiyun *
1041*4882a593Smuzhiyun * @ifp: interfac control.
1042*4882a593Smuzhiyun *
1043*4882a593Smuzhiyun */
brcmf_p2p_cancel_remain_on_channel(struct brcmf_if * ifp)1044*4882a593Smuzhiyun void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp)
1045*4882a593Smuzhiyun {
1046*4882a593Smuzhiyun if (!ifp)
1047*4882a593Smuzhiyun return;
1048*4882a593Smuzhiyun brcmf_p2p_set_discover_state(ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
1049*4882a593Smuzhiyun brcmf_p2p_notify_listen_complete(ifp, NULL, NULL);
1050*4882a593Smuzhiyun }
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun
1053*4882a593Smuzhiyun /**
1054*4882a593Smuzhiyun * brcmf_p2p_act_frm_search() - search function for action frame.
1055*4882a593Smuzhiyun *
1056*4882a593Smuzhiyun * @p2p: p2p device.
1057*4882a593Smuzhiyun * @channel: channel on which action frame is to be trasmitted.
1058*4882a593Smuzhiyun *
1059*4882a593Smuzhiyun * search function to reach at common channel to send action frame. When
1060*4882a593Smuzhiyun * channel is 0 then all social channels will be used to send af
1061*4882a593Smuzhiyun */
brcmf_p2p_act_frm_search(struct brcmf_p2p_info * p2p,u16 channel)1062*4882a593Smuzhiyun static s32 brcmf_p2p_act_frm_search(struct brcmf_p2p_info *p2p, u16 channel)
1063*4882a593Smuzhiyun {
1064*4882a593Smuzhiyun struct brcmf_pub *drvr = p2p->cfg->pub;
1065*4882a593Smuzhiyun s32 err;
1066*4882a593Smuzhiyun u32 channel_cnt;
1067*4882a593Smuzhiyun u16 *default_chan_list;
1068*4882a593Smuzhiyun u32 i;
1069*4882a593Smuzhiyun struct brcmu_chan ch;
1070*4882a593Smuzhiyun
1071*4882a593Smuzhiyun brcmf_dbg(TRACE, "Enter\n");
1072*4882a593Smuzhiyun
1073*4882a593Smuzhiyun if (channel)
1074*4882a593Smuzhiyun channel_cnt = AF_PEER_SEARCH_CNT;
1075*4882a593Smuzhiyun else
1076*4882a593Smuzhiyun channel_cnt = SOCIAL_CHAN_CNT;
1077*4882a593Smuzhiyun default_chan_list = kcalloc(channel_cnt, sizeof(*default_chan_list),
1078*4882a593Smuzhiyun GFP_KERNEL);
1079*4882a593Smuzhiyun if (default_chan_list == NULL) {
1080*4882a593Smuzhiyun bphy_err(drvr, "channel list allocation failed\n");
1081*4882a593Smuzhiyun err = -ENOMEM;
1082*4882a593Smuzhiyun goto exit;
1083*4882a593Smuzhiyun }
1084*4882a593Smuzhiyun ch.bw = BRCMU_CHAN_BW_20;
1085*4882a593Smuzhiyun if (channel) {
1086*4882a593Smuzhiyun ch.chnum = channel;
1087*4882a593Smuzhiyun p2p->cfg->d11inf.encchspec(&ch);
1088*4882a593Smuzhiyun /* insert same channel to the chan_list */
1089*4882a593Smuzhiyun for (i = 0; i < channel_cnt; i++)
1090*4882a593Smuzhiyun default_chan_list[i] = ch.chspec;
1091*4882a593Smuzhiyun } else {
1092*4882a593Smuzhiyun ch.chnum = SOCIAL_CHAN_1;
1093*4882a593Smuzhiyun p2p->cfg->d11inf.encchspec(&ch);
1094*4882a593Smuzhiyun default_chan_list[0] = ch.chspec;
1095*4882a593Smuzhiyun ch.chnum = SOCIAL_CHAN_2;
1096*4882a593Smuzhiyun p2p->cfg->d11inf.encchspec(&ch);
1097*4882a593Smuzhiyun default_chan_list[1] = ch.chspec;
1098*4882a593Smuzhiyun ch.chnum = SOCIAL_CHAN_3;
1099*4882a593Smuzhiyun p2p->cfg->d11inf.encchspec(&ch);
1100*4882a593Smuzhiyun default_chan_list[2] = ch.chspec;
1101*4882a593Smuzhiyun }
1102*4882a593Smuzhiyun err = brcmf_p2p_escan(p2p, channel_cnt, default_chan_list,
1103*4882a593Smuzhiyun WL_P2P_DISC_ST_SEARCH, P2PAPI_BSSCFG_DEVICE);
1104*4882a593Smuzhiyun kfree(default_chan_list);
1105*4882a593Smuzhiyun exit:
1106*4882a593Smuzhiyun return err;
1107*4882a593Smuzhiyun }
1108*4882a593Smuzhiyun
1109*4882a593Smuzhiyun
1110*4882a593Smuzhiyun /**
1111*4882a593Smuzhiyun * brcmf_p2p_afx_handler() - afx worker thread.
1112*4882a593Smuzhiyun *
1113*4882a593Smuzhiyun * @work:
1114*4882a593Smuzhiyun *
1115*4882a593Smuzhiyun */
brcmf_p2p_afx_handler(struct work_struct * work)1116*4882a593Smuzhiyun static void brcmf_p2p_afx_handler(struct work_struct *work)
1117*4882a593Smuzhiyun {
1118*4882a593Smuzhiyun struct afx_hdl *afx_hdl = container_of(work, struct afx_hdl, afx_work);
1119*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = container_of(afx_hdl,
1120*4882a593Smuzhiyun struct brcmf_p2p_info,
1121*4882a593Smuzhiyun afx_hdl);
1122*4882a593Smuzhiyun struct brcmf_pub *drvr = p2p->cfg->pub;
1123*4882a593Smuzhiyun s32 err;
1124*4882a593Smuzhiyun
1125*4882a593Smuzhiyun if (!afx_hdl->is_active)
1126*4882a593Smuzhiyun return;
1127*4882a593Smuzhiyun
1128*4882a593Smuzhiyun if (afx_hdl->is_listen && afx_hdl->my_listen_chan)
1129*4882a593Smuzhiyun /* 100ms ~ 300ms */
1130*4882a593Smuzhiyun err = brcmf_p2p_discover_listen(p2p, afx_hdl->my_listen_chan,
1131*4882a593Smuzhiyun 100 * (1 + prandom_u32() % 3));
1132*4882a593Smuzhiyun else
1133*4882a593Smuzhiyun err = brcmf_p2p_act_frm_search(p2p, afx_hdl->peer_listen_chan);
1134*4882a593Smuzhiyun
1135*4882a593Smuzhiyun if (err) {
1136*4882a593Smuzhiyun bphy_err(drvr, "ERROR occurred! value is (%d)\n", err);
1137*4882a593Smuzhiyun if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
1138*4882a593Smuzhiyun &p2p->status))
1139*4882a593Smuzhiyun complete(&afx_hdl->act_frm_scan);
1140*4882a593Smuzhiyun }
1141*4882a593Smuzhiyun }
1142*4882a593Smuzhiyun
1143*4882a593Smuzhiyun
1144*4882a593Smuzhiyun /**
1145*4882a593Smuzhiyun * brcmf_p2p_af_searching_channel() - search channel.
1146*4882a593Smuzhiyun *
1147*4882a593Smuzhiyun * @p2p: p2p device info struct.
1148*4882a593Smuzhiyun *
1149*4882a593Smuzhiyun */
brcmf_p2p_af_searching_channel(struct brcmf_p2p_info * p2p)1150*4882a593Smuzhiyun static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p)
1151*4882a593Smuzhiyun {
1152*4882a593Smuzhiyun struct afx_hdl *afx_hdl = &p2p->afx_hdl;
1153*4882a593Smuzhiyun struct brcmf_cfg80211_vif *pri_vif;
1154*4882a593Smuzhiyun s32 retry;
1155*4882a593Smuzhiyun
1156*4882a593Smuzhiyun brcmf_dbg(TRACE, "Enter\n");
1157*4882a593Smuzhiyun
1158*4882a593Smuzhiyun pri_vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
1159*4882a593Smuzhiyun
1160*4882a593Smuzhiyun reinit_completion(&afx_hdl->act_frm_scan);
1161*4882a593Smuzhiyun set_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status);
1162*4882a593Smuzhiyun afx_hdl->is_active = true;
1163*4882a593Smuzhiyun afx_hdl->peer_chan = P2P_INVALID_CHANNEL;
1164*4882a593Smuzhiyun
1165*4882a593Smuzhiyun /* Loop to wait until we find a peer's channel or the
1166*4882a593Smuzhiyun * pending action frame tx is cancelled.
1167*4882a593Smuzhiyun */
1168*4882a593Smuzhiyun retry = 0;
1169*4882a593Smuzhiyun while ((retry < P2P_CHANNEL_SYNC_RETRY) &&
1170*4882a593Smuzhiyun (afx_hdl->peer_chan == P2P_INVALID_CHANNEL)) {
1171*4882a593Smuzhiyun afx_hdl->is_listen = false;
1172*4882a593Smuzhiyun brcmf_dbg(TRACE, "Scheduling action frame for sending.. (%d)\n",
1173*4882a593Smuzhiyun retry);
1174*4882a593Smuzhiyun /* search peer on peer's listen channel */
1175*4882a593Smuzhiyun schedule_work(&afx_hdl->afx_work);
1176*4882a593Smuzhiyun wait_for_completion_timeout(&afx_hdl->act_frm_scan,
1177*4882a593Smuzhiyun P2P_AF_FRM_SCAN_MAX_WAIT);
1178*4882a593Smuzhiyun if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) ||
1179*4882a593Smuzhiyun (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
1180*4882a593Smuzhiyun &p2p->status)))
1181*4882a593Smuzhiyun break;
1182*4882a593Smuzhiyun
1183*4882a593Smuzhiyun if (afx_hdl->my_listen_chan) {
1184*4882a593Smuzhiyun brcmf_dbg(TRACE, "Scheduling listen peer, channel=%d\n",
1185*4882a593Smuzhiyun afx_hdl->my_listen_chan);
1186*4882a593Smuzhiyun /* listen on my listen channel */
1187*4882a593Smuzhiyun afx_hdl->is_listen = true;
1188*4882a593Smuzhiyun schedule_work(&afx_hdl->afx_work);
1189*4882a593Smuzhiyun wait_for_completion_timeout(&afx_hdl->act_frm_scan,
1190*4882a593Smuzhiyun P2P_AF_FRM_SCAN_MAX_WAIT);
1191*4882a593Smuzhiyun }
1192*4882a593Smuzhiyun if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) ||
1193*4882a593Smuzhiyun (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
1194*4882a593Smuzhiyun &p2p->status)))
1195*4882a593Smuzhiyun break;
1196*4882a593Smuzhiyun retry++;
1197*4882a593Smuzhiyun
1198*4882a593Smuzhiyun /* if sta is connected or connecting, sleep for a while before
1199*4882a593Smuzhiyun * retry af tx or finding a peer
1200*4882a593Smuzhiyun */
1201*4882a593Smuzhiyun if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &pri_vif->sme_state) ||
1202*4882a593Smuzhiyun test_bit(BRCMF_VIF_STATUS_CONNECTING, &pri_vif->sme_state))
1203*4882a593Smuzhiyun msleep(P2P_DEFAULT_SLEEP_TIME_VSDB);
1204*4882a593Smuzhiyun }
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun brcmf_dbg(TRACE, "Completed search/listen peer_chan=%d\n",
1207*4882a593Smuzhiyun afx_hdl->peer_chan);
1208*4882a593Smuzhiyun afx_hdl->is_active = false;
1209*4882a593Smuzhiyun
1210*4882a593Smuzhiyun clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status);
1211*4882a593Smuzhiyun
1212*4882a593Smuzhiyun return afx_hdl->peer_chan;
1213*4882a593Smuzhiyun }
1214*4882a593Smuzhiyun
1215*4882a593Smuzhiyun
1216*4882a593Smuzhiyun /**
1217*4882a593Smuzhiyun * brcmf_p2p_scan_finding_common_channel() - was escan used for finding channel
1218*4882a593Smuzhiyun *
1219*4882a593Smuzhiyun * @cfg: common configuration struct.
1220*4882a593Smuzhiyun * @bi: bss info struct, result from scan.
1221*4882a593Smuzhiyun *
1222*4882a593Smuzhiyun */
brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info * cfg,struct brcmf_bss_info_le * bi)1223*4882a593Smuzhiyun bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg,
1224*4882a593Smuzhiyun struct brcmf_bss_info_le *bi)
1225*4882a593Smuzhiyun
1226*4882a593Smuzhiyun {
1227*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = &cfg->p2p;
1228*4882a593Smuzhiyun struct afx_hdl *afx_hdl = &p2p->afx_hdl;
1229*4882a593Smuzhiyun struct brcmu_chan ch;
1230*4882a593Smuzhiyun u8 *ie;
1231*4882a593Smuzhiyun s32 err;
1232*4882a593Smuzhiyun u8 p2p_dev_addr[ETH_ALEN];
1233*4882a593Smuzhiyun
1234*4882a593Smuzhiyun if (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status))
1235*4882a593Smuzhiyun return false;
1236*4882a593Smuzhiyun
1237*4882a593Smuzhiyun if (bi == NULL) {
1238*4882a593Smuzhiyun brcmf_dbg(TRACE, "ACTION FRAME SCAN Done\n");
1239*4882a593Smuzhiyun if (afx_hdl->peer_chan == P2P_INVALID_CHANNEL)
1240*4882a593Smuzhiyun complete(&afx_hdl->act_frm_scan);
1241*4882a593Smuzhiyun return true;
1242*4882a593Smuzhiyun }
1243*4882a593Smuzhiyun
1244*4882a593Smuzhiyun ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
1245*4882a593Smuzhiyun memset(p2p_dev_addr, 0, sizeof(p2p_dev_addr));
1246*4882a593Smuzhiyun err = cfg80211_get_p2p_attr(ie, le32_to_cpu(bi->ie_length),
1247*4882a593Smuzhiyun IEEE80211_P2P_ATTR_DEVICE_INFO,
1248*4882a593Smuzhiyun p2p_dev_addr, sizeof(p2p_dev_addr));
1249*4882a593Smuzhiyun if (err < 0)
1250*4882a593Smuzhiyun err = cfg80211_get_p2p_attr(ie, le32_to_cpu(bi->ie_length),
1251*4882a593Smuzhiyun IEEE80211_P2P_ATTR_DEVICE_ID,
1252*4882a593Smuzhiyun p2p_dev_addr, sizeof(p2p_dev_addr));
1253*4882a593Smuzhiyun if ((err >= 0) &&
1254*4882a593Smuzhiyun (ether_addr_equal(p2p_dev_addr, afx_hdl->tx_dst_addr))) {
1255*4882a593Smuzhiyun if (!bi->ctl_ch) {
1256*4882a593Smuzhiyun ch.chspec = le16_to_cpu(bi->chanspec);
1257*4882a593Smuzhiyun cfg->d11inf.decchspec(&ch);
1258*4882a593Smuzhiyun bi->ctl_ch = ch.control_ch_num;
1259*4882a593Smuzhiyun }
1260*4882a593Smuzhiyun afx_hdl->peer_chan = bi->ctl_ch;
1261*4882a593Smuzhiyun brcmf_dbg(TRACE, "ACTION FRAME SCAN : Peer %pM found, channel : %d\n",
1262*4882a593Smuzhiyun afx_hdl->tx_dst_addr, afx_hdl->peer_chan);
1263*4882a593Smuzhiyun complete(&afx_hdl->act_frm_scan);
1264*4882a593Smuzhiyun }
1265*4882a593Smuzhiyun return true;
1266*4882a593Smuzhiyun }
1267*4882a593Smuzhiyun
1268*4882a593Smuzhiyun /**
1269*4882a593Smuzhiyun * brcmf_p2p_abort_action_frame() - abort action frame.
1270*4882a593Smuzhiyun *
1271*4882a593Smuzhiyun * @cfg: common configuration struct.
1272*4882a593Smuzhiyun *
1273*4882a593Smuzhiyun */
brcmf_p2p_abort_action_frame(struct brcmf_cfg80211_info * cfg)1274*4882a593Smuzhiyun static s32 brcmf_p2p_abort_action_frame(struct brcmf_cfg80211_info *cfg)
1275*4882a593Smuzhiyun {
1276*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = &cfg->p2p;
1277*4882a593Smuzhiyun struct brcmf_cfg80211_vif *vif;
1278*4882a593Smuzhiyun s32 err;
1279*4882a593Smuzhiyun s32 int_val = 1;
1280*4882a593Smuzhiyun
1281*4882a593Smuzhiyun brcmf_dbg(TRACE, "Enter\n");
1282*4882a593Smuzhiyun
1283*4882a593Smuzhiyun vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
1284*4882a593Smuzhiyun err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe_abort", &int_val,
1285*4882a593Smuzhiyun sizeof(s32));
1286*4882a593Smuzhiyun if (err)
1287*4882a593Smuzhiyun brcmf_err(" aborting action frame has failed (%d)\n", err);
1288*4882a593Smuzhiyun
1289*4882a593Smuzhiyun return err;
1290*4882a593Smuzhiyun }
1291*4882a593Smuzhiyun
1292*4882a593Smuzhiyun /**
1293*4882a593Smuzhiyun * brcmf_p2p_stop_wait_next_action_frame() - finish scan if af tx complete.
1294*4882a593Smuzhiyun *
1295*4882a593Smuzhiyun * @cfg: common configuration struct.
1296*4882a593Smuzhiyun *
1297*4882a593Smuzhiyun */
1298*4882a593Smuzhiyun static void
brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info * cfg)1299*4882a593Smuzhiyun brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg)
1300*4882a593Smuzhiyun {
1301*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = &cfg->p2p;
1302*4882a593Smuzhiyun struct brcmf_if *ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
1303*4882a593Smuzhiyun s32 err;
1304*4882a593Smuzhiyun
1305*4882a593Smuzhiyun if (test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status) &&
1306*4882a593Smuzhiyun (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status) ||
1307*4882a593Smuzhiyun test_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status))) {
1308*4882a593Smuzhiyun brcmf_dbg(TRACE, "*** Wake UP ** abort actframe iovar\n");
1309*4882a593Smuzhiyun /* if channel is not zero, "actfame" uses off channel scan.
1310*4882a593Smuzhiyun * So abort scan for off channel completion.
1311*4882a593Smuzhiyun */
1312*4882a593Smuzhiyun if (p2p->af_sent_channel) {
1313*4882a593Smuzhiyun /* abort actframe using actframe_abort or abort scan */
1314*4882a593Smuzhiyun err = brcmf_p2p_abort_action_frame(cfg);
1315*4882a593Smuzhiyun if (err)
1316*4882a593Smuzhiyun brcmf_notify_escan_complete(cfg, ifp, true,
1317*4882a593Smuzhiyun true);
1318*4882a593Smuzhiyun }
1319*4882a593Smuzhiyun } else if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
1320*4882a593Smuzhiyun &p2p->status)) {
1321*4882a593Smuzhiyun brcmf_dbg(TRACE, "*** Wake UP ** abort listen for next af frame\n");
1322*4882a593Smuzhiyun /* So abort scan to cancel listen */
1323*4882a593Smuzhiyun brcmf_notify_escan_complete(cfg, ifp, true, true);
1324*4882a593Smuzhiyun }
1325*4882a593Smuzhiyun }
1326*4882a593Smuzhiyun
1327*4882a593Smuzhiyun
1328*4882a593Smuzhiyun /**
1329*4882a593Smuzhiyun * brcmf_p2p_gon_req_collision() - Check if go negotiaton collission
1330*4882a593Smuzhiyun *
1331*4882a593Smuzhiyun * @p2p: p2p device info struct.
1332*4882a593Smuzhiyun * @mac: MAC address.
1333*4882a593Smuzhiyun *
1334*4882a593Smuzhiyun * return true if recevied action frame is to be dropped.
1335*4882a593Smuzhiyun */
1336*4882a593Smuzhiyun static bool
brcmf_p2p_gon_req_collision(struct brcmf_p2p_info * p2p,u8 * mac)1337*4882a593Smuzhiyun brcmf_p2p_gon_req_collision(struct brcmf_p2p_info *p2p, u8 *mac)
1338*4882a593Smuzhiyun {
1339*4882a593Smuzhiyun struct brcmf_cfg80211_info *cfg = p2p->cfg;
1340*4882a593Smuzhiyun struct brcmf_if *ifp;
1341*4882a593Smuzhiyun
1342*4882a593Smuzhiyun brcmf_dbg(TRACE, "Enter\n");
1343*4882a593Smuzhiyun
1344*4882a593Smuzhiyun if (!test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) ||
1345*4882a593Smuzhiyun !p2p->gon_req_action)
1346*4882a593Smuzhiyun return false;
1347*4882a593Smuzhiyun
1348*4882a593Smuzhiyun brcmf_dbg(TRACE, "GO Negotiation Request COLLISION !!!\n");
1349*4882a593Smuzhiyun /* if sa(peer) addr is less than da(my) addr, then this device
1350*4882a593Smuzhiyun * process peer's gon request and block to send gon req.
1351*4882a593Smuzhiyun * if not (sa addr > da addr),
1352*4882a593Smuzhiyun * this device will process gon request and drop gon req of peer.
1353*4882a593Smuzhiyun */
1354*4882a593Smuzhiyun ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp;
1355*4882a593Smuzhiyun if (memcmp(mac, ifp->mac_addr, ETH_ALEN) < 0) {
1356*4882a593Smuzhiyun brcmf_dbg(INFO, "Block transmit gon req !!!\n");
1357*4882a593Smuzhiyun p2p->block_gon_req_tx = true;
1358*4882a593Smuzhiyun /* if we are finding a common channel for sending af,
1359*4882a593Smuzhiyun * do not scan more to block to send current gon req
1360*4882a593Smuzhiyun */
1361*4882a593Smuzhiyun if (test_and_clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
1362*4882a593Smuzhiyun &p2p->status))
1363*4882a593Smuzhiyun complete(&p2p->afx_hdl.act_frm_scan);
1364*4882a593Smuzhiyun if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
1365*4882a593Smuzhiyun &p2p->status))
1366*4882a593Smuzhiyun brcmf_p2p_stop_wait_next_action_frame(cfg);
1367*4882a593Smuzhiyun return false;
1368*4882a593Smuzhiyun }
1369*4882a593Smuzhiyun
1370*4882a593Smuzhiyun /* drop gon request of peer to process gon request by this device. */
1371*4882a593Smuzhiyun brcmf_dbg(INFO, "Drop received gon req !!!\n");
1372*4882a593Smuzhiyun
1373*4882a593Smuzhiyun return true;
1374*4882a593Smuzhiyun }
1375*4882a593Smuzhiyun
1376*4882a593Smuzhiyun
1377*4882a593Smuzhiyun /**
1378*4882a593Smuzhiyun * brcmf_p2p_notify_action_frame_rx() - received action frame.
1379*4882a593Smuzhiyun *
1380*4882a593Smuzhiyun * @ifp: interfac control.
1381*4882a593Smuzhiyun * @e: event message. Not used, to make it usable for fweh event dispatcher.
1382*4882a593Smuzhiyun * @data: payload of message, containing action frame data.
1383*4882a593Smuzhiyun *
1384*4882a593Smuzhiyun */
brcmf_p2p_notify_action_frame_rx(struct brcmf_if * ifp,const struct brcmf_event_msg * e,void * data)1385*4882a593Smuzhiyun int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
1386*4882a593Smuzhiyun const struct brcmf_event_msg *e,
1387*4882a593Smuzhiyun void *data)
1388*4882a593Smuzhiyun {
1389*4882a593Smuzhiyun struct brcmf_pub *drvr = ifp->drvr;
1390*4882a593Smuzhiyun struct brcmf_cfg80211_info *cfg = drvr->config;
1391*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = &cfg->p2p;
1392*4882a593Smuzhiyun struct afx_hdl *afx_hdl = &p2p->afx_hdl;
1393*4882a593Smuzhiyun struct wireless_dev *wdev;
1394*4882a593Smuzhiyun u32 mgmt_frame_len = e->datalen - sizeof(struct brcmf_rx_mgmt_data);
1395*4882a593Smuzhiyun struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
1396*4882a593Smuzhiyun u8 *frame = (u8 *)(rxframe + 1);
1397*4882a593Smuzhiyun struct brcmf_p2p_pub_act_frame *act_frm;
1398*4882a593Smuzhiyun struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;
1399*4882a593Smuzhiyun struct brcmu_chan ch;
1400*4882a593Smuzhiyun struct ieee80211_mgmt *mgmt_frame;
1401*4882a593Smuzhiyun s32 freq;
1402*4882a593Smuzhiyun u16 mgmt_type;
1403*4882a593Smuzhiyun u8 action;
1404*4882a593Smuzhiyun
1405*4882a593Smuzhiyun if (e->datalen < sizeof(*rxframe)) {
1406*4882a593Smuzhiyun brcmf_dbg(SCAN, "Event data to small. Ignore\n");
1407*4882a593Smuzhiyun return 0;
1408*4882a593Smuzhiyun }
1409*4882a593Smuzhiyun
1410*4882a593Smuzhiyun ch.chspec = be16_to_cpu(rxframe->chanspec);
1411*4882a593Smuzhiyun cfg->d11inf.decchspec(&ch);
1412*4882a593Smuzhiyun /* Check if wpa_supplicant has registered for this frame */
1413*4882a593Smuzhiyun brcmf_dbg(INFO, "ifp->vif->mgmt_rx_reg %04x\n", ifp->vif->mgmt_rx_reg);
1414*4882a593Smuzhiyun mgmt_type = (IEEE80211_STYPE_ACTION & IEEE80211_FCTL_STYPE) >> 4;
1415*4882a593Smuzhiyun if ((ifp->vif->mgmt_rx_reg & BIT(mgmt_type)) == 0)
1416*4882a593Smuzhiyun return 0;
1417*4882a593Smuzhiyun
1418*4882a593Smuzhiyun brcmf_p2p_print_actframe(false, frame, mgmt_frame_len);
1419*4882a593Smuzhiyun
1420*4882a593Smuzhiyun action = P2P_PAF_SUBTYPE_INVALID;
1421*4882a593Smuzhiyun if (brcmf_p2p_is_pub_action(frame, mgmt_frame_len)) {
1422*4882a593Smuzhiyun act_frm = (struct brcmf_p2p_pub_act_frame *)frame;
1423*4882a593Smuzhiyun action = act_frm->subtype;
1424*4882a593Smuzhiyun if ((action == P2P_PAF_GON_REQ) &&
1425*4882a593Smuzhiyun (brcmf_p2p_gon_req_collision(p2p, (u8 *)e->addr))) {
1426*4882a593Smuzhiyun if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
1427*4882a593Smuzhiyun &p2p->status) &&
1428*4882a593Smuzhiyun (ether_addr_equal(afx_hdl->tx_dst_addr, e->addr))) {
1429*4882a593Smuzhiyun afx_hdl->peer_chan = ch.control_ch_num;
1430*4882a593Smuzhiyun brcmf_dbg(INFO, "GON request: Peer found, channel=%d\n",
1431*4882a593Smuzhiyun afx_hdl->peer_chan);
1432*4882a593Smuzhiyun complete(&afx_hdl->act_frm_scan);
1433*4882a593Smuzhiyun }
1434*4882a593Smuzhiyun return 0;
1435*4882a593Smuzhiyun }
1436*4882a593Smuzhiyun /* After complete GO Negotiation, roll back to mpc mode */
1437*4882a593Smuzhiyun if ((action == P2P_PAF_GON_CONF) ||
1438*4882a593Smuzhiyun (action == P2P_PAF_PROVDIS_RSP))
1439*4882a593Smuzhiyun brcmf_set_mpc(ifp, 1);
1440*4882a593Smuzhiyun if (action == P2P_PAF_GON_CONF) {
1441*4882a593Smuzhiyun brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n");
1442*4882a593Smuzhiyun clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
1443*4882a593Smuzhiyun }
1444*4882a593Smuzhiyun } else if (brcmf_p2p_is_gas_action(frame, mgmt_frame_len)) {
1445*4882a593Smuzhiyun sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;
1446*4882a593Smuzhiyun action = sd_act_frm->action;
1447*4882a593Smuzhiyun }
1448*4882a593Smuzhiyun
1449*4882a593Smuzhiyun if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) &&
1450*4882a593Smuzhiyun (p2p->next_af_subtype == action)) {
1451*4882a593Smuzhiyun brcmf_dbg(TRACE, "We got a right next frame! (%d)\n", action);
1452*4882a593Smuzhiyun clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
1453*4882a593Smuzhiyun &p2p->status);
1454*4882a593Smuzhiyun /* Stop waiting for next AF. */
1455*4882a593Smuzhiyun brcmf_p2p_stop_wait_next_action_frame(cfg);
1456*4882a593Smuzhiyun }
1457*4882a593Smuzhiyun
1458*4882a593Smuzhiyun mgmt_frame = kzalloc(offsetof(struct ieee80211_mgmt, u) +
1459*4882a593Smuzhiyun mgmt_frame_len, GFP_KERNEL);
1460*4882a593Smuzhiyun if (!mgmt_frame) {
1461*4882a593Smuzhiyun bphy_err(drvr, "No memory available for action frame\n");
1462*4882a593Smuzhiyun return -ENOMEM;
1463*4882a593Smuzhiyun }
1464*4882a593Smuzhiyun memcpy(mgmt_frame->da, ifp->mac_addr, ETH_ALEN);
1465*4882a593Smuzhiyun brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mgmt_frame->bssid,
1466*4882a593Smuzhiyun ETH_ALEN);
1467*4882a593Smuzhiyun memcpy(mgmt_frame->sa, e->addr, ETH_ALEN);
1468*4882a593Smuzhiyun mgmt_frame->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION);
1469*4882a593Smuzhiyun memcpy(&mgmt_frame->u, frame, mgmt_frame_len);
1470*4882a593Smuzhiyun mgmt_frame_len += offsetof(struct ieee80211_mgmt, u);
1471*4882a593Smuzhiyun
1472*4882a593Smuzhiyun freq = ieee80211_channel_to_frequency(ch.control_ch_num,
1473*4882a593Smuzhiyun ch.band == BRCMU_CHAN_BAND_2G ?
1474*4882a593Smuzhiyun NL80211_BAND_2GHZ :
1475*4882a593Smuzhiyun NL80211_BAND_5GHZ);
1476*4882a593Smuzhiyun
1477*4882a593Smuzhiyun wdev = &ifp->vif->wdev;
1478*4882a593Smuzhiyun cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 0);
1479*4882a593Smuzhiyun
1480*4882a593Smuzhiyun kfree(mgmt_frame);
1481*4882a593Smuzhiyun return 0;
1482*4882a593Smuzhiyun }
1483*4882a593Smuzhiyun
1484*4882a593Smuzhiyun
1485*4882a593Smuzhiyun /**
1486*4882a593Smuzhiyun * brcmf_p2p_notify_action_tx_complete() - transmit action frame complete
1487*4882a593Smuzhiyun *
1488*4882a593Smuzhiyun * @ifp: interfac control.
1489*4882a593Smuzhiyun * @e: event message. Not used, to make it usable for fweh event dispatcher.
1490*4882a593Smuzhiyun * @data: not used.
1491*4882a593Smuzhiyun *
1492*4882a593Smuzhiyun */
brcmf_p2p_notify_action_tx_complete(struct brcmf_if * ifp,const struct brcmf_event_msg * e,void * data)1493*4882a593Smuzhiyun int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp,
1494*4882a593Smuzhiyun const struct brcmf_event_msg *e,
1495*4882a593Smuzhiyun void *data)
1496*4882a593Smuzhiyun {
1497*4882a593Smuzhiyun struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
1498*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = &cfg->p2p;
1499*4882a593Smuzhiyun
1500*4882a593Smuzhiyun brcmf_dbg(INFO, "Enter: event %s, status=%d\n",
1501*4882a593Smuzhiyun e->event_code == BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE ?
1502*4882a593Smuzhiyun "ACTION_FRAME_OFF_CHAN_COMPLETE" : "ACTION_FRAME_COMPLETE",
1503*4882a593Smuzhiyun e->status);
1504*4882a593Smuzhiyun
1505*4882a593Smuzhiyun if (!test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status))
1506*4882a593Smuzhiyun return 0;
1507*4882a593Smuzhiyun
1508*4882a593Smuzhiyun if (e->event_code == BRCMF_E_ACTION_FRAME_COMPLETE) {
1509*4882a593Smuzhiyun if (e->status == BRCMF_E_STATUS_SUCCESS) {
1510*4882a593Smuzhiyun set_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED,
1511*4882a593Smuzhiyun &p2p->status);
1512*4882a593Smuzhiyun if (!p2p->wait_for_offchan_complete)
1513*4882a593Smuzhiyun complete(&p2p->send_af_done);
1514*4882a593Smuzhiyun } else {
1515*4882a593Smuzhiyun set_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
1516*4882a593Smuzhiyun /* If there is no ack, we don't need to wait for
1517*4882a593Smuzhiyun * WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE event
1518*4882a593Smuzhiyun */
1519*4882a593Smuzhiyun brcmf_p2p_stop_wait_next_action_frame(cfg);
1520*4882a593Smuzhiyun }
1521*4882a593Smuzhiyun
1522*4882a593Smuzhiyun } else {
1523*4882a593Smuzhiyun complete(&p2p->send_af_done);
1524*4882a593Smuzhiyun }
1525*4882a593Smuzhiyun return 0;
1526*4882a593Smuzhiyun }
1527*4882a593Smuzhiyun
1528*4882a593Smuzhiyun
1529*4882a593Smuzhiyun /**
1530*4882a593Smuzhiyun * brcmf_p2p_tx_action_frame() - send action frame over fil.
1531*4882a593Smuzhiyun *
1532*4882a593Smuzhiyun * @p2p: p2p info struct for vif.
1533*4882a593Smuzhiyun * @af_params: action frame data/info.
1534*4882a593Smuzhiyun *
1535*4882a593Smuzhiyun * Send an action frame immediately without doing channel synchronization.
1536*4882a593Smuzhiyun *
1537*4882a593Smuzhiyun * This function waits for a completion event before returning.
1538*4882a593Smuzhiyun * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action
1539*4882a593Smuzhiyun * frame is transmitted.
1540*4882a593Smuzhiyun */
brcmf_p2p_tx_action_frame(struct brcmf_p2p_info * p2p,struct brcmf_fil_af_params_le * af_params)1541*4882a593Smuzhiyun static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p,
1542*4882a593Smuzhiyun struct brcmf_fil_af_params_le *af_params)
1543*4882a593Smuzhiyun {
1544*4882a593Smuzhiyun struct brcmf_pub *drvr = p2p->cfg->pub;
1545*4882a593Smuzhiyun struct brcmf_cfg80211_vif *vif;
1546*4882a593Smuzhiyun struct brcmf_p2p_action_frame *p2p_af;
1547*4882a593Smuzhiyun s32 err = 0;
1548*4882a593Smuzhiyun
1549*4882a593Smuzhiyun brcmf_dbg(TRACE, "Enter\n");
1550*4882a593Smuzhiyun
1551*4882a593Smuzhiyun reinit_completion(&p2p->send_af_done);
1552*4882a593Smuzhiyun clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status);
1553*4882a593Smuzhiyun clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
1554*4882a593Smuzhiyun
1555*4882a593Smuzhiyun /* check if it is a p2p_presence response */
1556*4882a593Smuzhiyun p2p_af = (struct brcmf_p2p_action_frame *)af_params->action_frame.data;
1557*4882a593Smuzhiyun if (p2p_af->subtype == P2P_AF_PRESENCE_RSP)
1558*4882a593Smuzhiyun vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;
1559*4882a593Smuzhiyun else
1560*4882a593Smuzhiyun vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
1561*4882a593Smuzhiyun
1562*4882a593Smuzhiyun err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe", af_params,
1563*4882a593Smuzhiyun sizeof(*af_params));
1564*4882a593Smuzhiyun if (err) {
1565*4882a593Smuzhiyun bphy_err(drvr, " sending action frame has failed\n");
1566*4882a593Smuzhiyun goto exit;
1567*4882a593Smuzhiyun }
1568*4882a593Smuzhiyun
1569*4882a593Smuzhiyun p2p->af_sent_channel = le32_to_cpu(af_params->channel);
1570*4882a593Smuzhiyun p2p->af_tx_sent_jiffies = jiffies;
1571*4882a593Smuzhiyun
1572*4882a593Smuzhiyun if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status) &&
1573*4882a593Smuzhiyun p2p->af_sent_channel ==
1574*4882a593Smuzhiyun ieee80211_frequency_to_channel(p2p->remain_on_channel.center_freq))
1575*4882a593Smuzhiyun p2p->wait_for_offchan_complete = false;
1576*4882a593Smuzhiyun else
1577*4882a593Smuzhiyun p2p->wait_for_offchan_complete = true;
1578*4882a593Smuzhiyun
1579*4882a593Smuzhiyun brcmf_dbg(TRACE, "Waiting for %s tx completion event\n",
1580*4882a593Smuzhiyun (p2p->wait_for_offchan_complete) ?
1581*4882a593Smuzhiyun "off-channel" : "on-channel");
1582*4882a593Smuzhiyun
1583*4882a593Smuzhiyun wait_for_completion_timeout(&p2p->send_af_done, P2P_AF_MAX_WAIT_TIME);
1584*4882a593Smuzhiyun
1585*4882a593Smuzhiyun if (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status)) {
1586*4882a593Smuzhiyun brcmf_dbg(TRACE, "TX action frame operation is success\n");
1587*4882a593Smuzhiyun } else {
1588*4882a593Smuzhiyun err = -EIO;
1589*4882a593Smuzhiyun brcmf_dbg(TRACE, "TX action frame operation has failed\n");
1590*4882a593Smuzhiyun }
1591*4882a593Smuzhiyun /* clear status bit for action tx */
1592*4882a593Smuzhiyun clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status);
1593*4882a593Smuzhiyun clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
1594*4882a593Smuzhiyun
1595*4882a593Smuzhiyun exit:
1596*4882a593Smuzhiyun return err;
1597*4882a593Smuzhiyun }
1598*4882a593Smuzhiyun
1599*4882a593Smuzhiyun
1600*4882a593Smuzhiyun /**
1601*4882a593Smuzhiyun * brcmf_p2p_pub_af_tx() - public action frame tx routine.
1602*4882a593Smuzhiyun *
1603*4882a593Smuzhiyun * @cfg: driver private data for cfg80211 interface.
1604*4882a593Smuzhiyun * @af_params: action frame data/info.
1605*4882a593Smuzhiyun * @config_af_params: configuration data for action frame.
1606*4882a593Smuzhiyun *
1607*4882a593Smuzhiyun * routine which transmits ation frame public type.
1608*4882a593Smuzhiyun */
brcmf_p2p_pub_af_tx(struct brcmf_cfg80211_info * cfg,struct brcmf_fil_af_params_le * af_params,struct brcmf_config_af_params * config_af_params)1609*4882a593Smuzhiyun static s32 brcmf_p2p_pub_af_tx(struct brcmf_cfg80211_info *cfg,
1610*4882a593Smuzhiyun struct brcmf_fil_af_params_le *af_params,
1611*4882a593Smuzhiyun struct brcmf_config_af_params *config_af_params)
1612*4882a593Smuzhiyun {
1613*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = &cfg->p2p;
1614*4882a593Smuzhiyun struct brcmf_pub *drvr = cfg->pub;
1615*4882a593Smuzhiyun struct brcmf_fil_action_frame_le *action_frame;
1616*4882a593Smuzhiyun struct brcmf_p2p_pub_act_frame *act_frm;
1617*4882a593Smuzhiyun s32 err = 0;
1618*4882a593Smuzhiyun u16 ie_len;
1619*4882a593Smuzhiyun
1620*4882a593Smuzhiyun action_frame = &af_params->action_frame;
1621*4882a593Smuzhiyun act_frm = (struct brcmf_p2p_pub_act_frame *)(action_frame->data);
1622*4882a593Smuzhiyun
1623*4882a593Smuzhiyun config_af_params->extra_listen = true;
1624*4882a593Smuzhiyun
1625*4882a593Smuzhiyun switch (act_frm->subtype) {
1626*4882a593Smuzhiyun case P2P_PAF_GON_REQ:
1627*4882a593Smuzhiyun brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status set\n");
1628*4882a593Smuzhiyun set_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
1629*4882a593Smuzhiyun config_af_params->mpc_onoff = 0;
1630*4882a593Smuzhiyun config_af_params->search_channel = true;
1631*4882a593Smuzhiyun p2p->next_af_subtype = act_frm->subtype + 1;
1632*4882a593Smuzhiyun p2p->gon_req_action = true;
1633*4882a593Smuzhiyun /* increase dwell time to wait for RESP frame */
1634*4882a593Smuzhiyun af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
1635*4882a593Smuzhiyun break;
1636*4882a593Smuzhiyun case P2P_PAF_GON_RSP:
1637*4882a593Smuzhiyun p2p->next_af_subtype = act_frm->subtype + 1;
1638*4882a593Smuzhiyun /* increase dwell time to wait for CONF frame */
1639*4882a593Smuzhiyun af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
1640*4882a593Smuzhiyun break;
1641*4882a593Smuzhiyun case P2P_PAF_GON_CONF:
1642*4882a593Smuzhiyun /* If we reached till GO Neg confirmation reset the filter */
1643*4882a593Smuzhiyun brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n");
1644*4882a593Smuzhiyun clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
1645*4882a593Smuzhiyun /* turn on mpc again if go nego is done */
1646*4882a593Smuzhiyun config_af_params->mpc_onoff = 1;
1647*4882a593Smuzhiyun /* minimize dwell time */
1648*4882a593Smuzhiyun af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
1649*4882a593Smuzhiyun config_af_params->extra_listen = false;
1650*4882a593Smuzhiyun break;
1651*4882a593Smuzhiyun case P2P_PAF_INVITE_REQ:
1652*4882a593Smuzhiyun config_af_params->search_channel = true;
1653*4882a593Smuzhiyun p2p->next_af_subtype = act_frm->subtype + 1;
1654*4882a593Smuzhiyun /* increase dwell time */
1655*4882a593Smuzhiyun af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
1656*4882a593Smuzhiyun break;
1657*4882a593Smuzhiyun case P2P_PAF_INVITE_RSP:
1658*4882a593Smuzhiyun /* minimize dwell time */
1659*4882a593Smuzhiyun af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
1660*4882a593Smuzhiyun config_af_params->extra_listen = false;
1661*4882a593Smuzhiyun break;
1662*4882a593Smuzhiyun case P2P_PAF_DEVDIS_REQ:
1663*4882a593Smuzhiyun config_af_params->search_channel = true;
1664*4882a593Smuzhiyun p2p->next_af_subtype = act_frm->subtype + 1;
1665*4882a593Smuzhiyun /* maximize dwell time to wait for RESP frame */
1666*4882a593Smuzhiyun af_params->dwell_time = cpu_to_le32(P2P_AF_LONG_DWELL_TIME);
1667*4882a593Smuzhiyun break;
1668*4882a593Smuzhiyun case P2P_PAF_DEVDIS_RSP:
1669*4882a593Smuzhiyun /* minimize dwell time */
1670*4882a593Smuzhiyun af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
1671*4882a593Smuzhiyun config_af_params->extra_listen = false;
1672*4882a593Smuzhiyun break;
1673*4882a593Smuzhiyun case P2P_PAF_PROVDIS_REQ:
1674*4882a593Smuzhiyun ie_len = le16_to_cpu(action_frame->len) -
1675*4882a593Smuzhiyun offsetof(struct brcmf_p2p_pub_act_frame, elts);
1676*4882a593Smuzhiyun if (cfg80211_get_p2p_attr(&act_frm->elts[0], ie_len,
1677*4882a593Smuzhiyun IEEE80211_P2P_ATTR_GROUP_ID,
1678*4882a593Smuzhiyun NULL, 0) < 0)
1679*4882a593Smuzhiyun config_af_params->search_channel = true;
1680*4882a593Smuzhiyun config_af_params->mpc_onoff = 0;
1681*4882a593Smuzhiyun p2p->next_af_subtype = act_frm->subtype + 1;
1682*4882a593Smuzhiyun /* increase dwell time to wait for RESP frame */
1683*4882a593Smuzhiyun af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
1684*4882a593Smuzhiyun break;
1685*4882a593Smuzhiyun case P2P_PAF_PROVDIS_RSP:
1686*4882a593Smuzhiyun /* wpa_supplicant send go nego req right after prov disc */
1687*4882a593Smuzhiyun p2p->next_af_subtype = P2P_PAF_GON_REQ;
1688*4882a593Smuzhiyun /* increase dwell time to MED level */
1689*4882a593Smuzhiyun af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
1690*4882a593Smuzhiyun config_af_params->extra_listen = false;
1691*4882a593Smuzhiyun break;
1692*4882a593Smuzhiyun default:
1693*4882a593Smuzhiyun bphy_err(drvr, "Unknown p2p pub act frame subtype: %d\n",
1694*4882a593Smuzhiyun act_frm->subtype);
1695*4882a593Smuzhiyun err = -EINVAL;
1696*4882a593Smuzhiyun }
1697*4882a593Smuzhiyun return err;
1698*4882a593Smuzhiyun }
1699*4882a593Smuzhiyun
brcmf_p2p_check_dwell_overflow(u32 requested_dwell,unsigned long dwell_jiffies)1700*4882a593Smuzhiyun static bool brcmf_p2p_check_dwell_overflow(u32 requested_dwell,
1701*4882a593Smuzhiyun unsigned long dwell_jiffies)
1702*4882a593Smuzhiyun {
1703*4882a593Smuzhiyun if ((requested_dwell & CUSTOM_RETRY_MASK) &&
1704*4882a593Smuzhiyun (jiffies_to_msecs(jiffies - dwell_jiffies) >
1705*4882a593Smuzhiyun (requested_dwell & ~CUSTOM_RETRY_MASK))) {
1706*4882a593Smuzhiyun brcmf_err("Action frame TX retry time over dwell time!\n");
1707*4882a593Smuzhiyun return true;
1708*4882a593Smuzhiyun }
1709*4882a593Smuzhiyun return false;
1710*4882a593Smuzhiyun }
1711*4882a593Smuzhiyun /**
1712*4882a593Smuzhiyun * brcmf_p2p_send_action_frame() - send action frame .
1713*4882a593Smuzhiyun *
1714*4882a593Smuzhiyun * @cfg: driver private data for cfg80211 interface.
1715*4882a593Smuzhiyun * @ndev: net device to transmit on.
1716*4882a593Smuzhiyun * @af_params: configuration data for action frame.
1717*4882a593Smuzhiyun */
brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info * cfg,struct net_device * ndev,struct brcmf_fil_af_params_le * af_params)1718*4882a593Smuzhiyun bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
1719*4882a593Smuzhiyun struct net_device *ndev,
1720*4882a593Smuzhiyun struct brcmf_fil_af_params_le *af_params)
1721*4882a593Smuzhiyun {
1722*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = &cfg->p2p;
1723*4882a593Smuzhiyun struct brcmf_if *ifp = netdev_priv(ndev);
1724*4882a593Smuzhiyun struct brcmf_fil_action_frame_le *action_frame;
1725*4882a593Smuzhiyun struct brcmf_config_af_params config_af_params;
1726*4882a593Smuzhiyun struct afx_hdl *afx_hdl = &p2p->afx_hdl;
1727*4882a593Smuzhiyun struct brcmf_pub *drvr = cfg->pub;
1728*4882a593Smuzhiyun u16 action_frame_len;
1729*4882a593Smuzhiyun bool ack = false;
1730*4882a593Smuzhiyun u8 category;
1731*4882a593Smuzhiyun u8 action;
1732*4882a593Smuzhiyun s32 tx_retry;
1733*4882a593Smuzhiyun s32 extra_listen_time;
1734*4882a593Smuzhiyun uint delta_ms;
1735*4882a593Smuzhiyun unsigned long dwell_jiffies = 0;
1736*4882a593Smuzhiyun bool dwell_overflow = false;
1737*4882a593Smuzhiyun
1738*4882a593Smuzhiyun u32 requested_dwell = le32_to_cpu(af_params->dwell_time);
1739*4882a593Smuzhiyun action_frame = &af_params->action_frame;
1740*4882a593Smuzhiyun action_frame_len = le16_to_cpu(action_frame->len);
1741*4882a593Smuzhiyun
1742*4882a593Smuzhiyun brcmf_p2p_print_actframe(true, action_frame->data, action_frame_len);
1743*4882a593Smuzhiyun
1744*4882a593Smuzhiyun /* Add the default dwell time. Dwell time to stay off-channel */
1745*4882a593Smuzhiyun /* to wait for a response action frame after transmitting an */
1746*4882a593Smuzhiyun /* GO Negotiation action frame */
1747*4882a593Smuzhiyun af_params->dwell_time = cpu_to_le32(P2P_AF_DWELL_TIME);
1748*4882a593Smuzhiyun
1749*4882a593Smuzhiyun category = action_frame->data[DOT11_ACTION_CAT_OFF];
1750*4882a593Smuzhiyun action = action_frame->data[DOT11_ACTION_ACT_OFF];
1751*4882a593Smuzhiyun
1752*4882a593Smuzhiyun /* initialize variables */
1753*4882a593Smuzhiyun p2p->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
1754*4882a593Smuzhiyun p2p->gon_req_action = false;
1755*4882a593Smuzhiyun
1756*4882a593Smuzhiyun /* config parameters */
1757*4882a593Smuzhiyun config_af_params.mpc_onoff = -1;
1758*4882a593Smuzhiyun config_af_params.search_channel = false;
1759*4882a593Smuzhiyun config_af_params.extra_listen = false;
1760*4882a593Smuzhiyun
1761*4882a593Smuzhiyun if (brcmf_p2p_is_pub_action(action_frame->data, action_frame_len)) {
1762*4882a593Smuzhiyun /* p2p public action frame process */
1763*4882a593Smuzhiyun if (brcmf_p2p_pub_af_tx(cfg, af_params, &config_af_params)) {
1764*4882a593Smuzhiyun /* Just send unknown subtype frame with */
1765*4882a593Smuzhiyun /* default parameters. */
1766*4882a593Smuzhiyun bphy_err(drvr, "P2P Public action frame, unknown subtype.\n");
1767*4882a593Smuzhiyun }
1768*4882a593Smuzhiyun } else if (brcmf_p2p_is_gas_action(action_frame->data,
1769*4882a593Smuzhiyun action_frame_len)) {
1770*4882a593Smuzhiyun /* service discovery process */
1771*4882a593Smuzhiyun if (action == P2PSD_ACTION_ID_GAS_IREQ ||
1772*4882a593Smuzhiyun action == P2PSD_ACTION_ID_GAS_CREQ) {
1773*4882a593Smuzhiyun /* configure service discovery query frame */
1774*4882a593Smuzhiyun config_af_params.search_channel = true;
1775*4882a593Smuzhiyun
1776*4882a593Smuzhiyun /* save next af suptype to cancel */
1777*4882a593Smuzhiyun /* remaining dwell time */
1778*4882a593Smuzhiyun p2p->next_af_subtype = action + 1;
1779*4882a593Smuzhiyun
1780*4882a593Smuzhiyun af_params->dwell_time =
1781*4882a593Smuzhiyun cpu_to_le32(P2P_AF_MED_DWELL_TIME);
1782*4882a593Smuzhiyun } else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
1783*4882a593Smuzhiyun action == P2PSD_ACTION_ID_GAS_CRESP) {
1784*4882a593Smuzhiyun /* configure service discovery response frame */
1785*4882a593Smuzhiyun af_params->dwell_time =
1786*4882a593Smuzhiyun cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
1787*4882a593Smuzhiyun } else {
1788*4882a593Smuzhiyun bphy_err(drvr, "Unknown action type: %d\n", action);
1789*4882a593Smuzhiyun goto exit;
1790*4882a593Smuzhiyun }
1791*4882a593Smuzhiyun } else if (brcmf_p2p_is_p2p_action(action_frame->data,
1792*4882a593Smuzhiyun action_frame_len)) {
1793*4882a593Smuzhiyun /* do not configure anything. it will be */
1794*4882a593Smuzhiyun /* sent with a default configuration */
1795*4882a593Smuzhiyun } else {
1796*4882a593Smuzhiyun bphy_err(drvr, "Unknown Frame: category 0x%x, action 0x%x\n",
1797*4882a593Smuzhiyun category, action);
1798*4882a593Smuzhiyun return false;
1799*4882a593Smuzhiyun }
1800*4882a593Smuzhiyun
1801*4882a593Smuzhiyun /* if connecting on primary iface, sleep for a while before sending
1802*4882a593Smuzhiyun * af tx for VSDB
1803*4882a593Smuzhiyun */
1804*4882a593Smuzhiyun if (test_bit(BRCMF_VIF_STATUS_CONNECTING,
1805*4882a593Smuzhiyun &p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->sme_state))
1806*4882a593Smuzhiyun msleep(50);
1807*4882a593Smuzhiyun
1808*4882a593Smuzhiyun /* if scan is ongoing, abort current scan. */
1809*4882a593Smuzhiyun if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
1810*4882a593Smuzhiyun brcmf_abort_scanning(cfg);
1811*4882a593Smuzhiyun
1812*4882a593Smuzhiyun memcpy(afx_hdl->tx_dst_addr, action_frame->da, ETH_ALEN);
1813*4882a593Smuzhiyun
1814*4882a593Smuzhiyun /* To make sure to send successfully action frame, turn off mpc */
1815*4882a593Smuzhiyun if (config_af_params.mpc_onoff == 0)
1816*4882a593Smuzhiyun brcmf_set_mpc(ifp, 0);
1817*4882a593Smuzhiyun
1818*4882a593Smuzhiyun /* set status and destination address before sending af */
1819*4882a593Smuzhiyun if (p2p->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
1820*4882a593Smuzhiyun /* set status to cancel the remained dwell time in rx process */
1821*4882a593Smuzhiyun set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status);
1822*4882a593Smuzhiyun }
1823*4882a593Smuzhiyun
1824*4882a593Smuzhiyun p2p->af_sent_channel = 0;
1825*4882a593Smuzhiyun set_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status);
1826*4882a593Smuzhiyun /* validate channel and p2p ies */
1827*4882a593Smuzhiyun if (config_af_params.search_channel &&
1828*4882a593Smuzhiyun IS_P2P_SOCIAL_CHANNEL(le32_to_cpu(af_params->channel)) &&
1829*4882a593Smuzhiyun p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->saved_ie.probe_req_ie_len) {
1830*4882a593Smuzhiyun afx_hdl = &p2p->afx_hdl;
1831*4882a593Smuzhiyun afx_hdl->peer_listen_chan = le32_to_cpu(af_params->channel);
1832*4882a593Smuzhiyun
1833*4882a593Smuzhiyun if (brcmf_p2p_af_searching_channel(p2p) ==
1834*4882a593Smuzhiyun P2P_INVALID_CHANNEL) {
1835*4882a593Smuzhiyun bphy_err(drvr, "Couldn't find peer's channel.\n");
1836*4882a593Smuzhiyun goto exit;
1837*4882a593Smuzhiyun }
1838*4882a593Smuzhiyun
1839*4882a593Smuzhiyun /* Abort scan even for VSDB scenarios. Scan gets aborted in
1840*4882a593Smuzhiyun * firmware but after the check of piggyback algorithm. To take
1841*4882a593Smuzhiyun * care of current piggback algo, lets abort the scan here
1842*4882a593Smuzhiyun * itself.
1843*4882a593Smuzhiyun */
1844*4882a593Smuzhiyun brcmf_notify_escan_complete(cfg, ifp, true, true);
1845*4882a593Smuzhiyun
1846*4882a593Smuzhiyun /* update channel */
1847*4882a593Smuzhiyun af_params->channel = cpu_to_le32(afx_hdl->peer_chan);
1848*4882a593Smuzhiyun }
1849*4882a593Smuzhiyun dwell_jiffies = jiffies;
1850*4882a593Smuzhiyun dwell_overflow = brcmf_p2p_check_dwell_overflow(requested_dwell,
1851*4882a593Smuzhiyun dwell_jiffies);
1852*4882a593Smuzhiyun
1853*4882a593Smuzhiyun tx_retry = 0;
1854*4882a593Smuzhiyun while (!p2p->block_gon_req_tx &&
1855*4882a593Smuzhiyun (!ack) && (tx_retry < P2P_AF_TX_MAX_RETRY) &&
1856*4882a593Smuzhiyun !dwell_overflow) {
1857*4882a593Smuzhiyun if (af_params->channel)
1858*4882a593Smuzhiyun msleep(P2P_AF_RETRY_DELAY_TIME);
1859*4882a593Smuzhiyun
1860*4882a593Smuzhiyun ack = !brcmf_p2p_tx_action_frame(p2p, af_params);
1861*4882a593Smuzhiyun tx_retry++;
1862*4882a593Smuzhiyun dwell_overflow = brcmf_p2p_check_dwell_overflow(requested_dwell,
1863*4882a593Smuzhiyun dwell_jiffies);
1864*4882a593Smuzhiyun }
1865*4882a593Smuzhiyun if (!ack) {
1866*4882a593Smuzhiyun bphy_err(drvr, "Failed to send Action Frame(retry %d)\n",
1867*4882a593Smuzhiyun tx_retry);
1868*4882a593Smuzhiyun clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
1869*4882a593Smuzhiyun }
1870*4882a593Smuzhiyun
1871*4882a593Smuzhiyun exit:
1872*4882a593Smuzhiyun clear_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status);
1873*4882a593Smuzhiyun
1874*4882a593Smuzhiyun /* WAR: sometimes dongle does not keep the dwell time of 'actframe'.
1875*4882a593Smuzhiyun * if we coundn't get the next action response frame and dongle does
1876*4882a593Smuzhiyun * not keep the dwell time, go to listen state again to get next action
1877*4882a593Smuzhiyun * response frame.
1878*4882a593Smuzhiyun */
1879*4882a593Smuzhiyun if (ack && config_af_params.extra_listen && !p2p->block_gon_req_tx &&
1880*4882a593Smuzhiyun test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) &&
1881*4882a593Smuzhiyun p2p->af_sent_channel == afx_hdl->my_listen_chan) {
1882*4882a593Smuzhiyun delta_ms = jiffies_to_msecs(jiffies - p2p->af_tx_sent_jiffies);
1883*4882a593Smuzhiyun if (le32_to_cpu(af_params->dwell_time) > delta_ms)
1884*4882a593Smuzhiyun extra_listen_time = le32_to_cpu(af_params->dwell_time) -
1885*4882a593Smuzhiyun delta_ms;
1886*4882a593Smuzhiyun else
1887*4882a593Smuzhiyun extra_listen_time = 0;
1888*4882a593Smuzhiyun if (extra_listen_time > 50) {
1889*4882a593Smuzhiyun set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
1890*4882a593Smuzhiyun &p2p->status);
1891*4882a593Smuzhiyun brcmf_dbg(INFO, "Wait more time! actual af time:%d, calculated extra listen:%d\n",
1892*4882a593Smuzhiyun le32_to_cpu(af_params->dwell_time),
1893*4882a593Smuzhiyun extra_listen_time);
1894*4882a593Smuzhiyun extra_listen_time += 100;
1895*4882a593Smuzhiyun if (!brcmf_p2p_discover_listen(p2p,
1896*4882a593Smuzhiyun p2p->af_sent_channel,
1897*4882a593Smuzhiyun extra_listen_time)) {
1898*4882a593Smuzhiyun unsigned long duration;
1899*4882a593Smuzhiyun
1900*4882a593Smuzhiyun extra_listen_time += 100;
1901*4882a593Smuzhiyun duration = msecs_to_jiffies(extra_listen_time);
1902*4882a593Smuzhiyun wait_for_completion_timeout(&p2p->wait_next_af,
1903*4882a593Smuzhiyun duration);
1904*4882a593Smuzhiyun }
1905*4882a593Smuzhiyun clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
1906*4882a593Smuzhiyun &p2p->status);
1907*4882a593Smuzhiyun }
1908*4882a593Smuzhiyun }
1909*4882a593Smuzhiyun
1910*4882a593Smuzhiyun if (p2p->block_gon_req_tx) {
1911*4882a593Smuzhiyun /* if ack is true, supplicant will wait more time(100ms).
1912*4882a593Smuzhiyun * so we will return it as a success to get more time .
1913*4882a593Smuzhiyun */
1914*4882a593Smuzhiyun p2p->block_gon_req_tx = false;
1915*4882a593Smuzhiyun ack = true;
1916*4882a593Smuzhiyun }
1917*4882a593Smuzhiyun
1918*4882a593Smuzhiyun clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status);
1919*4882a593Smuzhiyun /* if all done, turn mpc on again */
1920*4882a593Smuzhiyun if (config_af_params.mpc_onoff == 1)
1921*4882a593Smuzhiyun brcmf_set_mpc(ifp, 1);
1922*4882a593Smuzhiyun
1923*4882a593Smuzhiyun return ack;
1924*4882a593Smuzhiyun }
1925*4882a593Smuzhiyun
1926*4882a593Smuzhiyun /**
1927*4882a593Smuzhiyun * brcmf_p2p_notify_rx_mgmt_p2p_probereq() - Event handler for p2p probe req.
1928*4882a593Smuzhiyun *
1929*4882a593Smuzhiyun * @ifp: interface pointer for which event was received.
1930*4882a593Smuzhiyun * @e: even message.
1931*4882a593Smuzhiyun * @data: payload of event message (probe request).
1932*4882a593Smuzhiyun */
brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if * ifp,const struct brcmf_event_msg * e,void * data)1933*4882a593Smuzhiyun s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
1934*4882a593Smuzhiyun const struct brcmf_event_msg *e,
1935*4882a593Smuzhiyun void *data)
1936*4882a593Smuzhiyun {
1937*4882a593Smuzhiyun struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
1938*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = &cfg->p2p;
1939*4882a593Smuzhiyun struct afx_hdl *afx_hdl = &p2p->afx_hdl;
1940*4882a593Smuzhiyun struct brcmf_cfg80211_vif *vif = ifp->vif;
1941*4882a593Smuzhiyun struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
1942*4882a593Smuzhiyun struct brcmu_chan ch;
1943*4882a593Smuzhiyun u8 *mgmt_frame;
1944*4882a593Smuzhiyun u32 mgmt_frame_len;
1945*4882a593Smuzhiyun s32 freq;
1946*4882a593Smuzhiyun u16 mgmt_type;
1947*4882a593Smuzhiyun
1948*4882a593Smuzhiyun brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code,
1949*4882a593Smuzhiyun e->reason);
1950*4882a593Smuzhiyun
1951*4882a593Smuzhiyun if (e->datalen < sizeof(*rxframe)) {
1952*4882a593Smuzhiyun brcmf_dbg(SCAN, "Event data to small. Ignore\n");
1953*4882a593Smuzhiyun return 0;
1954*4882a593Smuzhiyun }
1955*4882a593Smuzhiyun
1956*4882a593Smuzhiyun ch.chspec = be16_to_cpu(rxframe->chanspec);
1957*4882a593Smuzhiyun cfg->d11inf.decchspec(&ch);
1958*4882a593Smuzhiyun
1959*4882a593Smuzhiyun if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status) &&
1960*4882a593Smuzhiyun (ether_addr_equal(afx_hdl->tx_dst_addr, e->addr))) {
1961*4882a593Smuzhiyun afx_hdl->peer_chan = ch.control_ch_num;
1962*4882a593Smuzhiyun brcmf_dbg(INFO, "PROBE REQUEST: Peer found, channel=%d\n",
1963*4882a593Smuzhiyun afx_hdl->peer_chan);
1964*4882a593Smuzhiyun complete(&afx_hdl->act_frm_scan);
1965*4882a593Smuzhiyun }
1966*4882a593Smuzhiyun
1967*4882a593Smuzhiyun /* Firmware sends us two proberesponses for each idx one. At the */
1968*4882a593Smuzhiyun /* moment anything but bsscfgidx 0 is passed up to supplicant */
1969*4882a593Smuzhiyun if (e->bsscfgidx == 0)
1970*4882a593Smuzhiyun return 0;
1971*4882a593Smuzhiyun
1972*4882a593Smuzhiyun /* Filter any P2P probe reqs arriving during the GO-NEG Phase */
1973*4882a593Smuzhiyun if (test_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status)) {
1974*4882a593Smuzhiyun brcmf_dbg(INFO, "Filtering P2P probe_req in GO-NEG phase\n");
1975*4882a593Smuzhiyun return 0;
1976*4882a593Smuzhiyun }
1977*4882a593Smuzhiyun
1978*4882a593Smuzhiyun /* Check if wpa_supplicant has registered for this frame */
1979*4882a593Smuzhiyun brcmf_dbg(INFO, "vif->mgmt_rx_reg %04x\n", vif->mgmt_rx_reg);
1980*4882a593Smuzhiyun mgmt_type = (IEEE80211_STYPE_PROBE_REQ & IEEE80211_FCTL_STYPE) >> 4;
1981*4882a593Smuzhiyun if ((vif->mgmt_rx_reg & BIT(mgmt_type)) == 0)
1982*4882a593Smuzhiyun return 0;
1983*4882a593Smuzhiyun
1984*4882a593Smuzhiyun mgmt_frame = (u8 *)(rxframe + 1);
1985*4882a593Smuzhiyun mgmt_frame_len = e->datalen - sizeof(*rxframe);
1986*4882a593Smuzhiyun freq = ieee80211_channel_to_frequency(ch.control_ch_num,
1987*4882a593Smuzhiyun ch.band == BRCMU_CHAN_BAND_2G ?
1988*4882a593Smuzhiyun NL80211_BAND_2GHZ :
1989*4882a593Smuzhiyun NL80211_BAND_5GHZ);
1990*4882a593Smuzhiyun
1991*4882a593Smuzhiyun cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
1992*4882a593Smuzhiyun
1993*4882a593Smuzhiyun brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
1994*4882a593Smuzhiyun mgmt_frame_len, e->datalen, ch.chspec, freq);
1995*4882a593Smuzhiyun
1996*4882a593Smuzhiyun return 0;
1997*4882a593Smuzhiyun }
1998*4882a593Smuzhiyun
1999*4882a593Smuzhiyun
2000*4882a593Smuzhiyun /**
2001*4882a593Smuzhiyun * brcmf_p2p_get_current_chanspec() - Get current operation channel.
2002*4882a593Smuzhiyun *
2003*4882a593Smuzhiyun * @p2p: P2P specific data.
2004*4882a593Smuzhiyun * @chanspec: chanspec to be returned.
2005*4882a593Smuzhiyun */
brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info * p2p,u16 * chanspec)2006*4882a593Smuzhiyun static void brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info *p2p,
2007*4882a593Smuzhiyun u16 *chanspec)
2008*4882a593Smuzhiyun {
2009*4882a593Smuzhiyun struct brcmf_if *ifp;
2010*4882a593Smuzhiyun u8 mac_addr[ETH_ALEN];
2011*4882a593Smuzhiyun struct brcmu_chan ch;
2012*4882a593Smuzhiyun struct brcmf_bss_info_le *bi;
2013*4882a593Smuzhiyun u8 *buf;
2014*4882a593Smuzhiyun
2015*4882a593Smuzhiyun ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
2016*4882a593Smuzhiyun
2017*4882a593Smuzhiyun if (brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mac_addr,
2018*4882a593Smuzhiyun ETH_ALEN) == 0) {
2019*4882a593Smuzhiyun buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
2020*4882a593Smuzhiyun if (buf != NULL) {
2021*4882a593Smuzhiyun *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
2022*4882a593Smuzhiyun if (brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
2023*4882a593Smuzhiyun buf, WL_BSS_INFO_MAX) == 0) {
2024*4882a593Smuzhiyun bi = (struct brcmf_bss_info_le *)(buf + 4);
2025*4882a593Smuzhiyun *chanspec = le16_to_cpu(bi->chanspec);
2026*4882a593Smuzhiyun kfree(buf);
2027*4882a593Smuzhiyun return;
2028*4882a593Smuzhiyun }
2029*4882a593Smuzhiyun kfree(buf);
2030*4882a593Smuzhiyun }
2031*4882a593Smuzhiyun }
2032*4882a593Smuzhiyun /* Use default channel for P2P */
2033*4882a593Smuzhiyun ch.chnum = BRCMF_P2P_TEMP_CHAN;
2034*4882a593Smuzhiyun ch.bw = BRCMU_CHAN_BW_20;
2035*4882a593Smuzhiyun p2p->cfg->d11inf.encchspec(&ch);
2036*4882a593Smuzhiyun *chanspec = ch.chspec;
2037*4882a593Smuzhiyun }
2038*4882a593Smuzhiyun
2039*4882a593Smuzhiyun /**
2040*4882a593Smuzhiyun * Change a P2P Role.
2041*4882a593Smuzhiyun * @cfg: driver private data for cfg80211 interface.
2042*4882a593Smuzhiyun * @if_type: interface type.
2043*4882a593Smuzhiyun * Returns 0 if success.
2044*4882a593Smuzhiyun */
brcmf_p2p_ifchange(struct brcmf_cfg80211_info * cfg,enum brcmf_fil_p2p_if_types if_type)2045*4882a593Smuzhiyun int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
2046*4882a593Smuzhiyun enum brcmf_fil_p2p_if_types if_type)
2047*4882a593Smuzhiyun {
2048*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = &cfg->p2p;
2049*4882a593Smuzhiyun struct brcmf_pub *drvr = cfg->pub;
2050*4882a593Smuzhiyun struct brcmf_cfg80211_vif *vif;
2051*4882a593Smuzhiyun struct brcmf_fil_p2p_if_le if_request;
2052*4882a593Smuzhiyun s32 err;
2053*4882a593Smuzhiyun u16 chanspec;
2054*4882a593Smuzhiyun
2055*4882a593Smuzhiyun brcmf_dbg(TRACE, "Enter\n");
2056*4882a593Smuzhiyun
2057*4882a593Smuzhiyun vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
2058*4882a593Smuzhiyun if (!vif) {
2059*4882a593Smuzhiyun bphy_err(drvr, "vif for P2PAPI_BSSCFG_PRIMARY does not exist\n");
2060*4882a593Smuzhiyun return -EPERM;
2061*4882a593Smuzhiyun }
2062*4882a593Smuzhiyun brcmf_notify_escan_complete(cfg, vif->ifp, true, true);
2063*4882a593Smuzhiyun vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;
2064*4882a593Smuzhiyun if (!vif) {
2065*4882a593Smuzhiyun bphy_err(drvr, "vif for P2PAPI_BSSCFG_CONNECTION does not exist\n");
2066*4882a593Smuzhiyun return -EPERM;
2067*4882a593Smuzhiyun }
2068*4882a593Smuzhiyun brcmf_set_mpc(vif->ifp, 0);
2069*4882a593Smuzhiyun
2070*4882a593Smuzhiyun /* In concurrency case, STA may be already associated in a particular */
2071*4882a593Smuzhiyun /* channel. so retrieve the current channel of primary interface and */
2072*4882a593Smuzhiyun /* then start the virtual interface on that. */
2073*4882a593Smuzhiyun brcmf_p2p_get_current_chanspec(p2p, &chanspec);
2074*4882a593Smuzhiyun
2075*4882a593Smuzhiyun if_request.type = cpu_to_le16((u16)if_type);
2076*4882a593Smuzhiyun if_request.chspec = cpu_to_le16(chanspec);
2077*4882a593Smuzhiyun memcpy(if_request.addr, p2p->conn_int_addr, sizeof(if_request.addr));
2078*4882a593Smuzhiyun
2079*4882a593Smuzhiyun brcmf_cfg80211_arm_vif_event(cfg, vif);
2080*4882a593Smuzhiyun err = brcmf_fil_iovar_data_set(vif->ifp, "p2p_ifupd", &if_request,
2081*4882a593Smuzhiyun sizeof(if_request));
2082*4882a593Smuzhiyun if (err) {
2083*4882a593Smuzhiyun bphy_err(drvr, "p2p_ifupd FAILED, err=%d\n", err);
2084*4882a593Smuzhiyun brcmf_cfg80211_arm_vif_event(cfg, NULL);
2085*4882a593Smuzhiyun return err;
2086*4882a593Smuzhiyun }
2087*4882a593Smuzhiyun err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_CHANGE,
2088*4882a593Smuzhiyun BRCMF_VIF_EVENT_TIMEOUT);
2089*4882a593Smuzhiyun brcmf_cfg80211_arm_vif_event(cfg, NULL);
2090*4882a593Smuzhiyun if (!err) {
2091*4882a593Smuzhiyun bphy_err(drvr, "No BRCMF_E_IF_CHANGE event received\n");
2092*4882a593Smuzhiyun return -EIO;
2093*4882a593Smuzhiyun }
2094*4882a593Smuzhiyun
2095*4882a593Smuzhiyun err = brcmf_fil_cmd_int_set(vif->ifp, BRCMF_C_SET_SCB_TIMEOUT,
2096*4882a593Smuzhiyun BRCMF_SCB_TIMEOUT_VALUE);
2097*4882a593Smuzhiyun
2098*4882a593Smuzhiyun return err;
2099*4882a593Smuzhiyun }
2100*4882a593Smuzhiyun
brcmf_p2p_request_p2p_if(struct brcmf_p2p_info * p2p,struct brcmf_if * ifp,u8 ea[ETH_ALEN],enum brcmf_fil_p2p_if_types iftype)2101*4882a593Smuzhiyun static int brcmf_p2p_request_p2p_if(struct brcmf_p2p_info *p2p,
2102*4882a593Smuzhiyun struct brcmf_if *ifp, u8 ea[ETH_ALEN],
2103*4882a593Smuzhiyun enum brcmf_fil_p2p_if_types iftype)
2104*4882a593Smuzhiyun {
2105*4882a593Smuzhiyun struct brcmf_fil_p2p_if_le if_request;
2106*4882a593Smuzhiyun int err;
2107*4882a593Smuzhiyun u16 chanspec;
2108*4882a593Smuzhiyun
2109*4882a593Smuzhiyun /* we need a default channel */
2110*4882a593Smuzhiyun brcmf_p2p_get_current_chanspec(p2p, &chanspec);
2111*4882a593Smuzhiyun
2112*4882a593Smuzhiyun /* fill the firmware request */
2113*4882a593Smuzhiyun memcpy(if_request.addr, ea, ETH_ALEN);
2114*4882a593Smuzhiyun if_request.type = cpu_to_le16((u16)iftype);
2115*4882a593Smuzhiyun if_request.chspec = cpu_to_le16(chanspec);
2116*4882a593Smuzhiyun
2117*4882a593Smuzhiyun err = brcmf_fil_iovar_data_set(ifp, "p2p_ifadd", &if_request,
2118*4882a593Smuzhiyun sizeof(if_request));
2119*4882a593Smuzhiyun
2120*4882a593Smuzhiyun return err;
2121*4882a593Smuzhiyun }
2122*4882a593Smuzhiyun
brcmf_p2p_disable_p2p_if(struct brcmf_cfg80211_vif * vif)2123*4882a593Smuzhiyun static int brcmf_p2p_disable_p2p_if(struct brcmf_cfg80211_vif *vif)
2124*4882a593Smuzhiyun {
2125*4882a593Smuzhiyun struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev);
2126*4882a593Smuzhiyun struct net_device *pri_ndev = cfg_to_ndev(cfg);
2127*4882a593Smuzhiyun struct brcmf_if *ifp = netdev_priv(pri_ndev);
2128*4882a593Smuzhiyun u8 *addr = vif->wdev.netdev->dev_addr;
2129*4882a593Smuzhiyun
2130*4882a593Smuzhiyun return brcmf_fil_iovar_data_set(ifp, "p2p_ifdis", addr, ETH_ALEN);
2131*4882a593Smuzhiyun }
2132*4882a593Smuzhiyun
brcmf_p2p_release_p2p_if(struct brcmf_cfg80211_vif * vif)2133*4882a593Smuzhiyun static int brcmf_p2p_release_p2p_if(struct brcmf_cfg80211_vif *vif)
2134*4882a593Smuzhiyun {
2135*4882a593Smuzhiyun struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev);
2136*4882a593Smuzhiyun struct net_device *pri_ndev = cfg_to_ndev(cfg);
2137*4882a593Smuzhiyun struct brcmf_if *ifp = netdev_priv(pri_ndev);
2138*4882a593Smuzhiyun u8 *addr = vif->wdev.netdev->dev_addr;
2139*4882a593Smuzhiyun
2140*4882a593Smuzhiyun return brcmf_fil_iovar_data_set(ifp, "p2p_ifdel", addr, ETH_ALEN);
2141*4882a593Smuzhiyun }
2142*4882a593Smuzhiyun
2143*4882a593Smuzhiyun /**
2144*4882a593Smuzhiyun * brcmf_p2p_create_p2pdev() - create a P2P_DEVICE virtual interface.
2145*4882a593Smuzhiyun *
2146*4882a593Smuzhiyun * @p2p: P2P specific data.
2147*4882a593Smuzhiyun * @wiphy: wiphy device of new interface.
2148*4882a593Smuzhiyun * @addr: mac address for this new interface.
2149*4882a593Smuzhiyun */
brcmf_p2p_create_p2pdev(struct brcmf_p2p_info * p2p,struct wiphy * wiphy,u8 * addr)2150*4882a593Smuzhiyun static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p,
2151*4882a593Smuzhiyun struct wiphy *wiphy,
2152*4882a593Smuzhiyun u8 *addr)
2153*4882a593Smuzhiyun {
2154*4882a593Smuzhiyun struct brcmf_pub *drvr = p2p->cfg->pub;
2155*4882a593Smuzhiyun struct brcmf_cfg80211_vif *p2p_vif;
2156*4882a593Smuzhiyun struct brcmf_if *p2p_ifp;
2157*4882a593Smuzhiyun struct brcmf_if *pri_ifp;
2158*4882a593Smuzhiyun int err;
2159*4882a593Smuzhiyun u32 bsscfgidx;
2160*4882a593Smuzhiyun
2161*4882a593Smuzhiyun if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
2162*4882a593Smuzhiyun return ERR_PTR(-ENOSPC);
2163*4882a593Smuzhiyun
2164*4882a593Smuzhiyun p2p_vif = brcmf_alloc_vif(p2p->cfg, NL80211_IFTYPE_P2P_DEVICE);
2165*4882a593Smuzhiyun if (IS_ERR(p2p_vif)) {
2166*4882a593Smuzhiyun bphy_err(drvr, "could not create discovery vif\n");
2167*4882a593Smuzhiyun return (struct wireless_dev *)p2p_vif;
2168*4882a593Smuzhiyun }
2169*4882a593Smuzhiyun
2170*4882a593Smuzhiyun pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
2171*4882a593Smuzhiyun
2172*4882a593Smuzhiyun /* firmware requires unique mac address for p2pdev interface */
2173*4882a593Smuzhiyun if (addr && ether_addr_equal(addr, pri_ifp->mac_addr)) {
2174*4882a593Smuzhiyun bphy_err(drvr, "discovery vif must be different from primary interface\n");
2175*4882a593Smuzhiyun err = -EINVAL;
2176*4882a593Smuzhiyun goto fail;
2177*4882a593Smuzhiyun }
2178*4882a593Smuzhiyun
2179*4882a593Smuzhiyun brcmf_p2p_generate_bss_mac(p2p, addr);
2180*4882a593Smuzhiyun brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
2181*4882a593Smuzhiyun
2182*4882a593Smuzhiyun brcmf_cfg80211_arm_vif_event(p2p->cfg, p2p_vif);
2183*4882a593Smuzhiyun brcmf_fweh_p2pdev_setup(pri_ifp, true);
2184*4882a593Smuzhiyun
2185*4882a593Smuzhiyun /* Initialize P2P Discovery in the firmware */
2186*4882a593Smuzhiyun err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
2187*4882a593Smuzhiyun if (err < 0) {
2188*4882a593Smuzhiyun bphy_err(drvr, "set p2p_disc error\n");
2189*4882a593Smuzhiyun brcmf_fweh_p2pdev_setup(pri_ifp, false);
2190*4882a593Smuzhiyun brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL);
2191*4882a593Smuzhiyun goto fail;
2192*4882a593Smuzhiyun }
2193*4882a593Smuzhiyun
2194*4882a593Smuzhiyun /* wait for firmware event */
2195*4882a593Smuzhiyun err = brcmf_cfg80211_wait_vif_event(p2p->cfg, BRCMF_E_IF_ADD,
2196*4882a593Smuzhiyun BRCMF_VIF_EVENT_TIMEOUT);
2197*4882a593Smuzhiyun brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL);
2198*4882a593Smuzhiyun brcmf_fweh_p2pdev_setup(pri_ifp, false);
2199*4882a593Smuzhiyun if (!err) {
2200*4882a593Smuzhiyun bphy_err(drvr, "timeout occurred\n");
2201*4882a593Smuzhiyun err = -EIO;
2202*4882a593Smuzhiyun goto fail;
2203*4882a593Smuzhiyun }
2204*4882a593Smuzhiyun
2205*4882a593Smuzhiyun /* discovery interface created */
2206*4882a593Smuzhiyun p2p_ifp = p2p_vif->ifp;
2207*4882a593Smuzhiyun p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif;
2208*4882a593Smuzhiyun memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
2209*4882a593Smuzhiyun memcpy(&p2p_vif->wdev.address, p2p->dev_addr, sizeof(p2p->dev_addr));
2210*4882a593Smuzhiyun
2211*4882a593Smuzhiyun /* verify bsscfg index for P2P discovery */
2212*4882a593Smuzhiyun err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bsscfgidx);
2213*4882a593Smuzhiyun if (err < 0) {
2214*4882a593Smuzhiyun bphy_err(drvr, "retrieving discover bsscfg index failed\n");
2215*4882a593Smuzhiyun goto fail;
2216*4882a593Smuzhiyun }
2217*4882a593Smuzhiyun
2218*4882a593Smuzhiyun WARN_ON(p2p_ifp->bsscfgidx != bsscfgidx);
2219*4882a593Smuzhiyun
2220*4882a593Smuzhiyun init_completion(&p2p->send_af_done);
2221*4882a593Smuzhiyun INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler);
2222*4882a593Smuzhiyun init_completion(&p2p->afx_hdl.act_frm_scan);
2223*4882a593Smuzhiyun init_completion(&p2p->wait_next_af);
2224*4882a593Smuzhiyun
2225*4882a593Smuzhiyun return &p2p_vif->wdev;
2226*4882a593Smuzhiyun
2227*4882a593Smuzhiyun fail:
2228*4882a593Smuzhiyun brcmf_free_vif(p2p_vif);
2229*4882a593Smuzhiyun return ERR_PTR(err);
2230*4882a593Smuzhiyun }
2231*4882a593Smuzhiyun
brcmf_p2p_get_conn_idx(struct brcmf_cfg80211_info * cfg)2232*4882a593Smuzhiyun static int brcmf_p2p_get_conn_idx(struct brcmf_cfg80211_info *cfg)
2233*4882a593Smuzhiyun {
2234*4882a593Smuzhiyun int i;
2235*4882a593Smuzhiyun struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
2236*4882a593Smuzhiyun
2237*4882a593Smuzhiyun if (!ifp)
2238*4882a593Smuzhiyun return -ENODEV;
2239*4882a593Smuzhiyun
2240*4882a593Smuzhiyun for (i = P2PAPI_BSSCFG_CONNECTION; i < P2PAPI_BSSCFG_MAX; i++) {
2241*4882a593Smuzhiyun if (!cfg->p2p.bss_idx[i].vif) {
2242*4882a593Smuzhiyun if (i == P2PAPI_BSSCFG_CONNECTION2 &&
2243*4882a593Smuzhiyun !(brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB))) {
2244*4882a593Smuzhiyun brcmf_err("Multi p2p not supported");
2245*4882a593Smuzhiyun return -EIO;
2246*4882a593Smuzhiyun }
2247*4882a593Smuzhiyun return i;
2248*4882a593Smuzhiyun }
2249*4882a593Smuzhiyun }
2250*4882a593Smuzhiyun return -EIO;
2251*4882a593Smuzhiyun }
2252*4882a593Smuzhiyun
2253*4882a593Smuzhiyun /**
2254*4882a593Smuzhiyun * brcmf_p2p_add_vif() - create a new P2P virtual interface.
2255*4882a593Smuzhiyun *
2256*4882a593Smuzhiyun * @wiphy: wiphy device of new interface.
2257*4882a593Smuzhiyun * @name: name of the new interface.
2258*4882a593Smuzhiyun * @name_assign_type: origin of the interface name
2259*4882a593Smuzhiyun * @type: nl80211 interface type.
2260*4882a593Smuzhiyun * @params: contains mac address for P2P device.
2261*4882a593Smuzhiyun */
brcmf_p2p_add_vif(struct wiphy * wiphy,const char * name,unsigned char name_assign_type,enum nl80211_iftype type,struct vif_params * params)2262*4882a593Smuzhiyun struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
2263*4882a593Smuzhiyun unsigned char name_assign_type,
2264*4882a593Smuzhiyun enum nl80211_iftype type,
2265*4882a593Smuzhiyun struct vif_params *params)
2266*4882a593Smuzhiyun {
2267*4882a593Smuzhiyun struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2268*4882a593Smuzhiyun struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
2269*4882a593Smuzhiyun struct brcmf_pub *drvr = cfg->pub;
2270*4882a593Smuzhiyun struct brcmf_cfg80211_vif *vif;
2271*4882a593Smuzhiyun enum brcmf_fil_p2p_if_types iftype;
2272*4882a593Smuzhiyun int err = 0;
2273*4882a593Smuzhiyun int connidx;
2274*4882a593Smuzhiyun u8 *p2p_intf_addr;
2275*4882a593Smuzhiyun
2276*4882a593Smuzhiyun if (brcmf_cfg80211_vif_event_armed(cfg))
2277*4882a593Smuzhiyun return ERR_PTR(-EBUSY);
2278*4882a593Smuzhiyun
2279*4882a593Smuzhiyun brcmf_dbg(INFO, "adding vif \"%s\" (type=%d)\n", name, type);
2280*4882a593Smuzhiyun
2281*4882a593Smuzhiyun switch (type) {
2282*4882a593Smuzhiyun case NL80211_IFTYPE_P2P_CLIENT:
2283*4882a593Smuzhiyun iftype = BRCMF_FIL_P2P_IF_CLIENT;
2284*4882a593Smuzhiyun break;
2285*4882a593Smuzhiyun case NL80211_IFTYPE_P2P_GO:
2286*4882a593Smuzhiyun iftype = BRCMF_FIL_P2P_IF_GO;
2287*4882a593Smuzhiyun break;
2288*4882a593Smuzhiyun case NL80211_IFTYPE_P2P_DEVICE:
2289*4882a593Smuzhiyun return brcmf_p2p_create_p2pdev(&cfg->p2p, wiphy,
2290*4882a593Smuzhiyun params->macaddr);
2291*4882a593Smuzhiyun default:
2292*4882a593Smuzhiyun return ERR_PTR(-EOPNOTSUPP);
2293*4882a593Smuzhiyun }
2294*4882a593Smuzhiyun
2295*4882a593Smuzhiyun vif = brcmf_alloc_vif(cfg, type);
2296*4882a593Smuzhiyun if (IS_ERR(vif))
2297*4882a593Smuzhiyun return (struct wireless_dev *)vif;
2298*4882a593Smuzhiyun brcmf_cfg80211_arm_vif_event(cfg, vif);
2299*4882a593Smuzhiyun
2300*4882a593Smuzhiyun connidx = brcmf_p2p_get_conn_idx(cfg);
2301*4882a593Smuzhiyun
2302*4882a593Smuzhiyun if (connidx == P2PAPI_BSSCFG_CONNECTION)
2303*4882a593Smuzhiyun p2p_intf_addr = cfg->p2p.conn_int_addr;
2304*4882a593Smuzhiyun else if (connidx == P2PAPI_BSSCFG_CONNECTION2)
2305*4882a593Smuzhiyun p2p_intf_addr = cfg->p2p.conn2_int_addr;
2306*4882a593Smuzhiyun else
2307*4882a593Smuzhiyun err = -EINVAL;
2308*4882a593Smuzhiyun
2309*4882a593Smuzhiyun if (!err)
2310*4882a593Smuzhiyun err = brcmf_p2p_request_p2p_if(&cfg->p2p, ifp,
2311*4882a593Smuzhiyun p2p_intf_addr, iftype);
2312*4882a593Smuzhiyun
2313*4882a593Smuzhiyun if (err) {
2314*4882a593Smuzhiyun brcmf_err("request p2p interface failed\n");
2315*4882a593Smuzhiyun brcmf_cfg80211_arm_vif_event(cfg, NULL);
2316*4882a593Smuzhiyun goto fail;
2317*4882a593Smuzhiyun }
2318*4882a593Smuzhiyun
2319*4882a593Smuzhiyun /* wait for firmware event */
2320*4882a593Smuzhiyun err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
2321*4882a593Smuzhiyun BRCMF_VIF_EVENT_TIMEOUT);
2322*4882a593Smuzhiyun brcmf_cfg80211_arm_vif_event(cfg, NULL);
2323*4882a593Smuzhiyun if (!err) {
2324*4882a593Smuzhiyun bphy_err(drvr, "timeout occurred\n");
2325*4882a593Smuzhiyun err = -EIO;
2326*4882a593Smuzhiyun goto fail;
2327*4882a593Smuzhiyun }
2328*4882a593Smuzhiyun
2329*4882a593Smuzhiyun /* interface created in firmware */
2330*4882a593Smuzhiyun ifp = vif->ifp;
2331*4882a593Smuzhiyun if (!ifp) {
2332*4882a593Smuzhiyun bphy_err(drvr, "no if pointer provided\n");
2333*4882a593Smuzhiyun err = -ENOENT;
2334*4882a593Smuzhiyun goto fail;
2335*4882a593Smuzhiyun }
2336*4882a593Smuzhiyun
2337*4882a593Smuzhiyun strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
2338*4882a593Smuzhiyun ifp->ndev->name_assign_type = name_assign_type;
2339*4882a593Smuzhiyun err = brcmf_net_attach(ifp, true);
2340*4882a593Smuzhiyun if (err) {
2341*4882a593Smuzhiyun bphy_err(drvr, "Registering netdevice failed\n");
2342*4882a593Smuzhiyun free_netdev(ifp->ndev);
2343*4882a593Smuzhiyun goto fail;
2344*4882a593Smuzhiyun }
2345*4882a593Smuzhiyun
2346*4882a593Smuzhiyun cfg->p2p.bss_idx[connidx].vif = vif;
2347*4882a593Smuzhiyun /* Disable firmware roaming for P2P interface */
2348*4882a593Smuzhiyun brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
2349*4882a593Smuzhiyun if (iftype == BRCMF_FIL_P2P_IF_GO) {
2350*4882a593Smuzhiyun /* set station timeout for p2p */
2351*4882a593Smuzhiyun brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCB_TIMEOUT,
2352*4882a593Smuzhiyun BRCMF_SCB_TIMEOUT_VALUE);
2353*4882a593Smuzhiyun }
2354*4882a593Smuzhiyun return &ifp->vif->wdev;
2355*4882a593Smuzhiyun
2356*4882a593Smuzhiyun fail:
2357*4882a593Smuzhiyun brcmf_free_vif(vif);
2358*4882a593Smuzhiyun return ERR_PTR(err);
2359*4882a593Smuzhiyun }
2360*4882a593Smuzhiyun
2361*4882a593Smuzhiyun /**
2362*4882a593Smuzhiyun * brcmf_p2p_del_vif() - delete a P2P virtual interface.
2363*4882a593Smuzhiyun *
2364*4882a593Smuzhiyun * @wiphy: wiphy device of interface.
2365*4882a593Smuzhiyun * @wdev: wireless device of interface.
2366*4882a593Smuzhiyun */
brcmf_p2p_del_vif(struct wiphy * wiphy,struct wireless_dev * wdev)2367*4882a593Smuzhiyun int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
2368*4882a593Smuzhiyun {
2369*4882a593Smuzhiyun struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2370*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = &cfg->p2p;
2371*4882a593Smuzhiyun struct brcmf_cfg80211_vif *vif;
2372*4882a593Smuzhiyun enum nl80211_iftype iftype;
2373*4882a593Smuzhiyun bool wait_for_disable = false;
2374*4882a593Smuzhiyun int err;
2375*4882a593Smuzhiyun
2376*4882a593Smuzhiyun brcmf_dbg(TRACE, "delete P2P vif\n");
2377*4882a593Smuzhiyun vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
2378*4882a593Smuzhiyun
2379*4882a593Smuzhiyun iftype = vif->wdev.iftype;
2380*4882a593Smuzhiyun brcmf_cfg80211_arm_vif_event(cfg, vif);
2381*4882a593Smuzhiyun switch (iftype) {
2382*4882a593Smuzhiyun case NL80211_IFTYPE_P2P_CLIENT:
2383*4882a593Smuzhiyun if (test_bit(BRCMF_VIF_STATUS_DISCONNECTING, &vif->sme_state))
2384*4882a593Smuzhiyun wait_for_disable = true;
2385*4882a593Smuzhiyun break;
2386*4882a593Smuzhiyun
2387*4882a593Smuzhiyun case NL80211_IFTYPE_P2P_GO:
2388*4882a593Smuzhiyun if (!brcmf_p2p_disable_p2p_if(vif))
2389*4882a593Smuzhiyun wait_for_disable = true;
2390*4882a593Smuzhiyun break;
2391*4882a593Smuzhiyun
2392*4882a593Smuzhiyun case NL80211_IFTYPE_P2P_DEVICE:
2393*4882a593Smuzhiyun if (!p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
2394*4882a593Smuzhiyun return 0;
2395*4882a593Smuzhiyun brcmf_p2p_cancel_remain_on_channel(vif->ifp);
2396*4882a593Smuzhiyun brcmf_p2p_deinit_discovery(p2p);
2397*4882a593Smuzhiyun break;
2398*4882a593Smuzhiyun
2399*4882a593Smuzhiyun default:
2400*4882a593Smuzhiyun return -ENOTSUPP;
2401*4882a593Smuzhiyun }
2402*4882a593Smuzhiyun
2403*4882a593Smuzhiyun clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
2404*4882a593Smuzhiyun brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n");
2405*4882a593Smuzhiyun
2406*4882a593Smuzhiyun if (wait_for_disable)
2407*4882a593Smuzhiyun wait_for_completion_timeout(&cfg->vif_disabled,
2408*4882a593Smuzhiyun BRCMF_P2P_DISABLE_TIMEOUT);
2409*4882a593Smuzhiyun
2410*4882a593Smuzhiyun err = 0;
2411*4882a593Smuzhiyun if (iftype != NL80211_IFTYPE_P2P_DEVICE) {
2412*4882a593Smuzhiyun brcmf_vif_clear_mgmt_ies(vif);
2413*4882a593Smuzhiyun err = brcmf_p2p_release_p2p_if(vif);
2414*4882a593Smuzhiyun }
2415*4882a593Smuzhiyun if (!err) {
2416*4882a593Smuzhiyun /* wait for firmware event */
2417*4882a593Smuzhiyun err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL,
2418*4882a593Smuzhiyun BRCMF_VIF_EVENT_TIMEOUT);
2419*4882a593Smuzhiyun if (!err)
2420*4882a593Smuzhiyun err = -EIO;
2421*4882a593Smuzhiyun else
2422*4882a593Smuzhiyun err = 0;
2423*4882a593Smuzhiyun }
2424*4882a593Smuzhiyun brcmf_remove_interface(vif->ifp, true);
2425*4882a593Smuzhiyun
2426*4882a593Smuzhiyun brcmf_cfg80211_arm_vif_event(cfg, NULL);
2427*4882a593Smuzhiyun if (iftype != NL80211_IFTYPE_P2P_DEVICE)
2428*4882a593Smuzhiyun p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL;
2429*4882a593Smuzhiyun
2430*4882a593Smuzhiyun return err;
2431*4882a593Smuzhiyun }
2432*4882a593Smuzhiyun
brcmf_p2p_ifp_removed(struct brcmf_if * ifp,bool rtnl_locked)2433*4882a593Smuzhiyun void brcmf_p2p_ifp_removed(struct brcmf_if *ifp, bool rtnl_locked)
2434*4882a593Smuzhiyun {
2435*4882a593Smuzhiyun struct brcmf_cfg80211_info *cfg;
2436*4882a593Smuzhiyun struct brcmf_cfg80211_vif *vif;
2437*4882a593Smuzhiyun
2438*4882a593Smuzhiyun brcmf_dbg(INFO, "P2P: device interface removed\n");
2439*4882a593Smuzhiyun vif = ifp->vif;
2440*4882a593Smuzhiyun cfg = wdev_to_cfg(&vif->wdev);
2441*4882a593Smuzhiyun cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
2442*4882a593Smuzhiyun if (!rtnl_locked)
2443*4882a593Smuzhiyun rtnl_lock();
2444*4882a593Smuzhiyun cfg80211_unregister_wdev(&vif->wdev);
2445*4882a593Smuzhiyun if (!rtnl_locked)
2446*4882a593Smuzhiyun rtnl_unlock();
2447*4882a593Smuzhiyun brcmf_free_vif(vif);
2448*4882a593Smuzhiyun }
2449*4882a593Smuzhiyun
brcmf_p2p_start_device(struct wiphy * wiphy,struct wireless_dev * wdev)2450*4882a593Smuzhiyun int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev)
2451*4882a593Smuzhiyun {
2452*4882a593Smuzhiyun struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2453*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = &cfg->p2p;
2454*4882a593Smuzhiyun struct brcmf_cfg80211_vif *vif;
2455*4882a593Smuzhiyun int err;
2456*4882a593Smuzhiyun
2457*4882a593Smuzhiyun vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
2458*4882a593Smuzhiyun mutex_lock(&cfg->usr_sync);
2459*4882a593Smuzhiyun err = brcmf_p2p_enable_discovery(p2p);
2460*4882a593Smuzhiyun if (!err)
2461*4882a593Smuzhiyun set_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);
2462*4882a593Smuzhiyun mutex_unlock(&cfg->usr_sync);
2463*4882a593Smuzhiyun return err;
2464*4882a593Smuzhiyun }
2465*4882a593Smuzhiyun
brcmf_p2p_stop_device(struct wiphy * wiphy,struct wireless_dev * wdev)2466*4882a593Smuzhiyun void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev)
2467*4882a593Smuzhiyun {
2468*4882a593Smuzhiyun struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2469*4882a593Smuzhiyun struct brcmf_p2p_info *p2p = &cfg->p2p;
2470*4882a593Smuzhiyun struct brcmf_cfg80211_vif *vif;
2471*4882a593Smuzhiyun
2472*4882a593Smuzhiyun vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
2473*4882a593Smuzhiyun /* This call can be result of the unregister_wdev call. In that case
2474*4882a593Smuzhiyun * we dont want to do anything anymore. Just return. The config vif
2475*4882a593Smuzhiyun * will have been cleared at this point.
2476*4882a593Smuzhiyun */
2477*4882a593Smuzhiyun if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif == vif) {
2478*4882a593Smuzhiyun mutex_lock(&cfg->usr_sync);
2479*4882a593Smuzhiyun /* Set the discovery state to SCAN */
2480*4882a593Smuzhiyun (void)brcmf_p2p_set_discover_state(vif->ifp,
2481*4882a593Smuzhiyun WL_P2P_DISC_ST_SCAN, 0, 0);
2482*4882a593Smuzhiyun brcmf_abort_scanning(cfg);
2483*4882a593Smuzhiyun clear_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);
2484*4882a593Smuzhiyun mutex_unlock(&cfg->usr_sync);
2485*4882a593Smuzhiyun }
2486*4882a593Smuzhiyun }
2487*4882a593Smuzhiyun
2488*4882a593Smuzhiyun /**
2489*4882a593Smuzhiyun * brcmf_p2p_attach() - attach for P2P.
2490*4882a593Smuzhiyun *
2491*4882a593Smuzhiyun * @cfg: driver private data for cfg80211 interface.
2492*4882a593Smuzhiyun * @p2pdev_forced: create p2p device interface at attach.
2493*4882a593Smuzhiyun */
brcmf_p2p_attach(struct brcmf_cfg80211_info * cfg,bool p2pdev_forced)2494*4882a593Smuzhiyun s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced)
2495*4882a593Smuzhiyun {
2496*4882a593Smuzhiyun struct brcmf_pub *drvr = cfg->pub;
2497*4882a593Smuzhiyun struct brcmf_p2p_info *p2p;
2498*4882a593Smuzhiyun struct brcmf_if *pri_ifp;
2499*4882a593Smuzhiyun s32 err = 0;
2500*4882a593Smuzhiyun void *err_ptr;
2501*4882a593Smuzhiyun
2502*4882a593Smuzhiyun p2p = &cfg->p2p;
2503*4882a593Smuzhiyun p2p->cfg = cfg;
2504*4882a593Smuzhiyun
2505*4882a593Smuzhiyun pri_ifp = brcmf_get_ifp(cfg->pub, 0);
2506*4882a593Smuzhiyun p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif;
2507*4882a593Smuzhiyun
2508*4882a593Smuzhiyun if (p2pdev_forced) {
2509*4882a593Smuzhiyun err_ptr = brcmf_p2p_create_p2pdev(p2p, NULL, NULL);
2510*4882a593Smuzhiyun if (IS_ERR(err_ptr)) {
2511*4882a593Smuzhiyun bphy_err(drvr, "P2P device creation failed.\n");
2512*4882a593Smuzhiyun err = PTR_ERR(err_ptr);
2513*4882a593Smuzhiyun }
2514*4882a593Smuzhiyun } else {
2515*4882a593Smuzhiyun p2p->p2pdev_dynamically = true;
2516*4882a593Smuzhiyun }
2517*4882a593Smuzhiyun return err;
2518*4882a593Smuzhiyun }
2519*4882a593Smuzhiyun
2520*4882a593Smuzhiyun /**
2521*4882a593Smuzhiyun * brcmf_p2p_detach() - detach P2P.
2522*4882a593Smuzhiyun *
2523*4882a593Smuzhiyun * @p2p: P2P specific data.
2524*4882a593Smuzhiyun */
brcmf_p2p_detach(struct brcmf_p2p_info * p2p)2525*4882a593Smuzhiyun void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
2526*4882a593Smuzhiyun {
2527*4882a593Smuzhiyun struct brcmf_cfg80211_vif *vif;
2528*4882a593Smuzhiyun
2529*4882a593Smuzhiyun vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
2530*4882a593Smuzhiyun if (vif != NULL) {
2531*4882a593Smuzhiyun brcmf_p2p_cancel_remain_on_channel(vif->ifp);
2532*4882a593Smuzhiyun brcmf_p2p_deinit_discovery(p2p);
2533*4882a593Smuzhiyun brcmf_remove_interface(vif->ifp, false);
2534*4882a593Smuzhiyun }
2535*4882a593Smuzhiyun /* just set it all to zero */
2536*4882a593Smuzhiyun memset(p2p, 0, sizeof(*p2p));
2537*4882a593Smuzhiyun }
2538*4882a593Smuzhiyun
2539