aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHante Meuleman <meuleman@broadcom.com>2013-02-08 09:53:48 -0500
committerJohn W. Linville <linville@tuxdriver.com>2013-02-08 14:51:39 -0500
commite6da3400b34a063119b911b268d168441a1b80e9 (patch)
tree2a6ff8a061ecadb9ec87499f07c8c0daee3c0d7e /drivers
parenta0f07959ee6e7f5be147ca4c3906b9d7fd173ea0 (diff)
brcmfmac: Add handling of receiving P2P action frames.
Once wpa_supplicant has registered for P2P action frames all received action frames for the device are passed up to cfg80211. Reviewed-by: Arend Van Spriel <arend@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Signed-off-by: Hante Meuleman <meuleman@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.c345
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.h3
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c2
3 files changed, 350 insertions, 0 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
index d5f97117b266..e5b1fb94a6d1 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -48,6 +48,38 @@
48 48
49#define BRCMF_SCB_TIMEOUT_VALUE 20 49#define BRCMF_SCB_TIMEOUT_VALUE 20
50 50
51#define P2P_VER 9 /* P2P version: 9=WiFi P2P v1.0 */
52#define P2P_PUB_AF_CATEGORY 0x04
53#define P2P_PUB_AF_ACTION 0x09
54#define P2P_AF_CATEGORY 0x7f
55#define P2P_OUI "\x50\x6F\x9A" /* P2P OUI */
56#define P2P_OUI_LEN 3 /* P2P OUI length */
57
58/* WiFi P2P Public Action Frame OUI Subtypes */
59#define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */
60#define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */
61#define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */
62#define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */
63#define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */
64#define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */
65#define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */
66#define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */
67#define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Response */
68#define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */
69
70/* WiFi P2P Action Frame OUI Subtypes */
71#define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */
72#define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */
73#define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */
74#define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */
75
76/* P2P Service Discovery related */
77#define P2PSD_ACTION_CATEGORY 0x04 /* Public action frame */
78#define P2PSD_ACTION_ID_GAS_IREQ 0x0a /* GAS Initial Request AF */
79#define P2PSD_ACTION_ID_GAS_IRESP 0x0b /* GAS Initial Response AF */
80#define P2PSD_ACTION_ID_GAS_CREQ 0x0c /* GAS Comback Request AF */
81#define P2PSD_ACTION_ID_GAS_CRESP 0x0d /* GAS Comback Response AF */
82
51/** 83/**
52 * struct brcmf_p2p_disc_st_le - set discovery state in firmware. 84 * struct brcmf_p2p_disc_st_le - set discovery state in firmware.
53 * 85 *
@@ -92,6 +124,261 @@ struct brcmf_p2p_scan_le {
92}; 124};
93 125
94/** 126/**
127 * struct brcmf_p2p_pub_act_frame - WiFi P2P Public Action Frame
128 *
129 * @category: P2P_PUB_AF_CATEGORY
130 * @action: P2P_PUB_AF_ACTION
131 * @oui[3]: P2P_OUI
132 * @oui_type: OUI type - P2P_VER
133 * @subtype: OUI subtype - P2P_TYPE_*
134 * @dialog_token: nonzero, identifies req/rsp transaction
135 * @elts[1]: Variable length information elements.
136 */
137struct brcmf_p2p_pub_act_frame {
138 u8 category;
139 u8 action;
140 u8 oui[3];
141 u8 oui_type;
142 u8 subtype;
143 u8 dialog_token;
144 u8 elts[1];
145};
146
147/**
148 * struct brcmf_p2p_action_frame - WiFi P2P Action Frame
149 *
150 * @category: P2P_AF_CATEGORY
151 * @OUI[3]: OUI - P2P_OUI
152 * @type: OUI Type - P2P_VER
153 * @subtype: OUI Subtype - P2P_AF_*
154 * @dialog_token: nonzero, identifies req/resp tranaction
155 * @elts[1]: Variable length information elements.
156 */
157struct brcmf_p2p_action_frame {
158 u8 category;
159 u8 oui[3];
160 u8 type;
161 u8 subtype;
162 u8 dialog_token;
163 u8 elts[1];
164};
165
166/**
167 * struct brcmf_p2psd_gas_pub_act_frame - Wi-Fi GAS Public Action Frame
168 *
169 * @category: 0x04 Public Action Frame
170 * @action: 0x6c Advertisement Protocol
171 * @dialog_token: nonzero, identifies req/rsp transaction
172 * @query_data[1]: Query Data. SD gas ireq SD gas iresp
173 */
174struct brcmf_p2psd_gas_pub_act_frame {
175 u8 category;
176 u8 action;
177 u8 dialog_token;
178 u8 query_data[1];
179};
180
181
182/**
183 * brcmf_p2p_is_pub_action() - true if p2p public type frame.
184 *
185 * @frame: action frame data.
186 * @frame_len: length of action frame data.
187 *
188 * Determine if action frame is p2p public action type
189 */
190static bool brcmf_p2p_is_pub_action(void *frame, u32 frame_len)
191{
192 struct brcmf_p2p_pub_act_frame *pact_frm;
193
194 if (frame == NULL)
195 return false;
196
197 pact_frm = (struct brcmf_p2p_pub_act_frame *)frame;
198 if (frame_len < sizeof(struct brcmf_p2p_pub_act_frame) - 1)
199 return false;
200
201 if (pact_frm->category == P2P_PUB_AF_CATEGORY &&
202 pact_frm->action == P2P_PUB_AF_ACTION &&
203 pact_frm->oui_type == P2P_VER &&
204 memcmp(pact_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0)
205 return true;
206
207 return false;
208}
209
210/**
211 * brcmf_p2p_is_p2p_action() - true if p2p action type frame.
212 *
213 * @frame: action frame data.
214 * @frame_len: length of action frame data.
215 *
216 * Determine if action frame is p2p action type
217 */
218static bool brcmf_p2p_is_p2p_action(void *frame, u32 frame_len)
219{
220 struct brcmf_p2p_action_frame *act_frm;
221
222 if (frame == NULL)
223 return false;
224
225 act_frm = (struct brcmf_p2p_action_frame *)frame;
226 if (frame_len < sizeof(struct brcmf_p2p_action_frame) - 1)
227 return false;
228
229 if (act_frm->category == P2P_AF_CATEGORY &&
230 act_frm->type == P2P_VER &&
231 memcmp(act_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0)
232 return true;
233
234 return false;
235}
236
237/**
238 * brcmf_p2p_is_gas_action() - true if p2p gas action type frame.
239 *
240 * @frame: action frame data.
241 * @frame_len: length of action frame data.
242 *
243 * Determine if action frame is p2p gas action type
244 */
245static bool brcmf_p2p_is_gas_action(void *frame, u32 frame_len)
246{
247 struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;
248
249 if (frame == NULL)
250 return false;
251
252 sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;
253 if (frame_len < sizeof(struct brcmf_p2psd_gas_pub_act_frame) - 1)
254 return false;
255
256 if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)
257 return false;
258
259 if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ ||
260 sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP ||
261 sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ ||
262 sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP)
263 return true;
264
265 return false;
266}
267
268/**
269 * brcmf_p2p_print_actframe() - debug print routine.
270 *
271 * @tx: Received or to be transmitted
272 * @frame: action frame data.
273 * @frame_len: length of action frame data.
274 *
275 * Print information about the p2p action frame
276 */
277static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len)
278{
279 struct brcmf_p2p_pub_act_frame *pact_frm;
280 struct brcmf_p2p_action_frame *act_frm;
281 struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;
282
283 if (!frame || frame_len <= 2)
284 return;
285
286 if (brcmf_p2p_is_pub_action(frame, frame_len)) {
287 pact_frm = (struct brcmf_p2p_pub_act_frame *)frame;
288 switch (pact_frm->subtype) {
289 case P2P_PAF_GON_REQ:
290 brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Req Frame\n",
291 (tx) ? "TX" : "RX");
292 break;
293 case P2P_PAF_GON_RSP:
294 brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Rsp Frame\n",
295 (tx) ? "TX" : "RX");
296 break;
297 case P2P_PAF_GON_CONF:
298 brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Confirm Frame\n",
299 (tx) ? "TX" : "RX");
300 break;
301 case P2P_PAF_INVITE_REQ:
302 brcmf_dbg(TRACE, "%s P2P Invitation Request Frame\n",
303 (tx) ? "TX" : "RX");
304 break;
305 case P2P_PAF_INVITE_RSP:
306 brcmf_dbg(TRACE, "%s P2P Invitation Response Frame\n",
307 (tx) ? "TX" : "RX");
308 break;
309 case P2P_PAF_DEVDIS_REQ:
310 brcmf_dbg(TRACE, "%s P2P Device Discoverability Request Frame\n",
311 (tx) ? "TX" : "RX");
312 break;
313 case P2P_PAF_DEVDIS_RSP:
314 brcmf_dbg(TRACE, "%s P2P Device Discoverability Response Frame\n",
315 (tx) ? "TX" : "RX");
316 break;
317 case P2P_PAF_PROVDIS_REQ:
318 brcmf_dbg(TRACE, "%s P2P Provision Discovery Request Frame\n",
319 (tx) ? "TX" : "RX");
320 break;
321 case P2P_PAF_PROVDIS_RSP:
322 brcmf_dbg(TRACE, "%s P2P Provision Discovery Response Frame\n",
323 (tx) ? "TX" : "RX");
324 break;
325 default:
326 brcmf_dbg(TRACE, "%s Unknown P2P Public Action Frame\n",
327 (tx) ? "TX" : "RX");
328 break;
329 }
330 } else if (brcmf_p2p_is_p2p_action(frame, frame_len)) {
331 act_frm = (struct brcmf_p2p_action_frame *)frame;
332 switch (act_frm->subtype) {
333 case P2P_AF_NOTICE_OF_ABSENCE:
334 brcmf_dbg(TRACE, "%s P2P Notice of Absence Frame\n",
335 (tx) ? "TX" : "RX");
336 break;
337 case P2P_AF_PRESENCE_REQ:
338 brcmf_dbg(TRACE, "%s P2P Presence Request Frame\n",
339 (tx) ? "TX" : "RX");
340 break;
341 case P2P_AF_PRESENCE_RSP:
342 brcmf_dbg(TRACE, "%s P2P Presence Response Frame\n",
343 (tx) ? "TX" : "RX");
344 break;
345 case P2P_AF_GO_DISC_REQ:
346 brcmf_dbg(TRACE, "%s P2P Discoverability Request Frame\n",
347 (tx) ? "TX" : "RX");
348 break;
349 default:
350 brcmf_dbg(TRACE, "%s Unknown P2P Action Frame\n",
351 (tx) ? "TX" : "RX");
352 }
353
354 } else if (brcmf_p2p_is_gas_action(frame, frame_len)) {
355 sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;
356 switch (sd_act_frm->action) {
357 case P2PSD_ACTION_ID_GAS_IREQ:
358 brcmf_dbg(TRACE, "%s P2P GAS Initial Request\n",
359 (tx) ? "TX" : "RX");
360 break;
361 case P2PSD_ACTION_ID_GAS_IRESP:
362 brcmf_dbg(TRACE, "%s P2P GAS Initial Response\n",
363 (tx) ? "TX" : "RX");
364 break;
365 case P2PSD_ACTION_ID_GAS_CREQ:
366 brcmf_dbg(TRACE, "%s P2P GAS Comback Request\n",
367 (tx) ? "TX" : "RX");
368 break;
369 case P2PSD_ACTION_ID_GAS_CRESP:
370 brcmf_dbg(TRACE, "%s P2P GAS Comback Response\n",
371 (tx) ? "TX" : "RX");
372 break;
373 default:
374 brcmf_dbg(TRACE, "%s Unknown P2P GAS Frame\n",
375 (tx) ? "TX" : "RX");
376 break;
377 }
378 }
379}
380
381/**
95 * brcmf_p2p_set_firmware() - prepare firmware for peer-to-peer operation. 382 * brcmf_p2p_set_firmware() - prepare firmware for peer-to-peer operation.
96 * 383 *
97 * @p2p: P2P specific data. 384 * @p2p: P2P specific data.
@@ -687,6 +974,64 @@ void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp)
687 974
688 975
689/** 976/**
977 * brcmf_p2p_notify_action_frame_rx() - received action frame.
978 *
979 * @ifp: interfac control.
980 * @e: event message. Not used, to make it usable for fweh event dispatcher.
981 * @data: payload of message, containing action frame data.
982 *
983 */
984int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
985 const struct brcmf_event_msg *e,
986 void *data)
987{
988 struct wireless_dev *wdev;
989 u32 mgmt_frame_len = e->datalen - sizeof(struct brcmf_rx_mgmt_data);
990 struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
991 u16 chanspec = be16_to_cpu(rxframe->chanspec);
992 struct ieee80211_mgmt *mgmt_frame;
993 s32 err;
994 s32 freq;
995 u16 mgmt_type;
996
997 /* Check if wpa_supplicant has registered for this frame */
998 brcmf_dbg(INFO, "ifp->vif->mgmt_rx_reg %04x\n", ifp->vif->mgmt_rx_reg);
999 mgmt_type = (IEEE80211_STYPE_ACTION & IEEE80211_FCTL_STYPE) >> 4;
1000 if ((ifp->vif->mgmt_rx_reg & BIT(mgmt_type)) == 0)
1001 return 0;
1002
1003 brcmf_p2p_print_actframe(false, (u8 *)(rxframe + 1), mgmt_frame_len);
1004
1005 mgmt_frame = kzalloc(offsetof(struct ieee80211_mgmt, u) +
1006 mgmt_frame_len, GFP_KERNEL);
1007 if (!mgmt_frame) {
1008 brcmf_err("No memory available for action frame\n");
1009 return -ENOMEM;
1010 }
1011 memcpy(mgmt_frame->da, ifp->mac_addr, ETH_ALEN);
1012 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mgmt_frame->bssid,
1013 ETH_ALEN);
1014 if (err < 0)
1015 brcmf_err("BRCMF_C_GET_BSSID error %d\n", err);
1016 memcpy(mgmt_frame->sa, e->addr, ETH_ALEN);
1017 mgmt_frame->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION);
1018 memcpy(&mgmt_frame->u, (u8 *)(rxframe + 1), mgmt_frame_len);
1019 mgmt_frame_len += offsetof(struct ieee80211_mgmt, u);
1020
1021 freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec),
1022 CHSPEC_IS2G(chanspec) ?
1023 IEEE80211_BAND_2GHZ :
1024 IEEE80211_BAND_5GHZ);
1025 wdev = ifp->ndev->ieee80211_ptr;
1026 cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len,
1027 GFP_ATOMIC);
1028
1029 kfree(mgmt_frame);
1030 return 0;
1031}
1032
1033
1034/**
690 * brcmf_p2p_attach() - attach for P2P. 1035 * brcmf_p2p_attach() - attach for P2P.
691 * 1036 *
692 * @cfg: driver private data for cfg80211 interface. 1037 * @cfg: driver private data for cfg80211 interface.
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.h b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h
index 4c1819c1fcc7..d247946fbec6 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h
@@ -123,5 +123,8 @@ int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
123 const struct brcmf_event_msg *e, 123 const struct brcmf_event_msg *e,
124 void *data); 124 void *data);
125void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp); 125void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp);
126int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
127 const struct brcmf_event_msg *e,
128 void *data);
126 129
127#endif /* WL_CFGP2P_H_ */ 130#endif /* WL_CFGP2P_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index c94d5361ca8f..3914beb896a7 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -4701,6 +4701,8 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
4701 brcmf_notify_rx_mgmt_p2p_probereq); 4701 brcmf_notify_rx_mgmt_p2p_probereq);
4702 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE, 4702 brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
4703 brcmf_p2p_notify_listen_complete); 4703 brcmf_p2p_notify_listen_complete);
4704 brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
4705 brcmf_p2p_notify_action_frame_rx);
4704} 4706}
4705 4707
4706static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) 4708static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)