diff options
author | Hante Meuleman <meuleman@broadcom.com> | 2013-02-08 09:53:48 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-02-08 14:51:39 -0500 |
commit | e6da3400b34a063119b911b268d168441a1b80e9 (patch) | |
tree | 2a6ff8a061ecadb9ec87499f07c8c0daee3c0d7e /drivers/net/wireless/brcm80211/brcmfmac/p2p.c | |
parent | a0f07959ee6e7f5be147ca4c3906b9d7fd173ea0 (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/net/wireless/brcm80211/brcmfmac/p2p.c')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/p2p.c | 345 |
1 files changed, 345 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 | */ | ||
137 | struct 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 | */ | ||
157 | struct 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 | */ | ||
174 | struct 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 | */ | ||
190 | static 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 | */ | ||
218 | static 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 | */ | ||
245 | static 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 | */ | ||
277 | static 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 | */ | ||
984 | int 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. |