diff options
author | Hante Meuleman <meuleman@broadcom.com> | 2013-02-08 09:53:38 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-02-08 14:51:37 -0500 |
commit | 0de8aace0ff499bf1b6597e7f272961d2e335933 (patch) | |
tree | 3bcaa7edefc2ecf74448f3ffa2665de262d014da /drivers/net/wireless | |
parent | d3c0b63396442d564ceb4db0dcc51e70918b9c93 (diff) |
brcmfmac: add support for P2P listen mode.
With this patch a device can be put in p2p listen mode and becomes
visible for other p2p devices (via p2p_find).
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Arend van Spriel <arend@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')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 13 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/fweh.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/p2p.c | 150 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/p2p.h | 15 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 189 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h | 2 |
6 files changed, 341 insertions, 34 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index b61254dd42c0..82724d371dd0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h | |||
@@ -452,6 +452,19 @@ struct brcmf_sta_info_le { | |||
452 | __le32 rx_decrypt_failures; /* # of packet decrypted failed */ | 452 | __le32 rx_decrypt_failures; /* # of packet decrypted failed */ |
453 | }; | 453 | }; |
454 | 454 | ||
455 | /* | ||
456 | * WLC_E_PROBRESP_MSG | ||
457 | * WLC_E_P2P_PROBREQ_MSG | ||
458 | * WLC_E_ACTION_FRAME_RX | ||
459 | */ | ||
460 | struct brcmf_rx_mgmt_data { | ||
461 | __be16 version; | ||
462 | __be16 chanspec; | ||
463 | __be32 rssi; | ||
464 | __be32 mactime; | ||
465 | __be32 rate; | ||
466 | }; | ||
467 | |||
455 | /* Bus independent dongle command */ | 468 | /* Bus independent dongle command */ |
456 | struct brcmf_dcmd { | 469 | struct brcmf_dcmd { |
457 | uint cmd; /* common dongle cmd definition */ | 470 | uint cmd; /* common dongle cmd definition */ |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h index 36901f76a3b5..8c39b51dcccf 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h | |||
@@ -83,6 +83,7 @@ struct brcmf_event; | |||
83 | BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \ | 83 | BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \ |
84 | BRCMF_ENUM_DEF(TRACE, 52) \ | 84 | BRCMF_ENUM_DEF(TRACE, 52) \ |
85 | BRCMF_ENUM_DEF(IF, 54) \ | 85 | BRCMF_ENUM_DEF(IF, 54) \ |
86 | BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \ | ||
86 | BRCMF_ENUM_DEF(RSSI, 56) \ | 87 | BRCMF_ENUM_DEF(RSSI, 56) \ |
87 | BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \ | 88 | BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \ |
88 | BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \ | 89 | BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \ |
@@ -96,8 +97,11 @@ struct brcmf_event; | |||
96 | BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \ | 97 | BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \ |
97 | BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \ | 98 | BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \ |
98 | BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \ | 99 | BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \ |
100 | BRCMF_ENUM_DEF(PROBERESP_MSG, 71) \ | ||
101 | BRCMF_ENUM_DEF(P2P_PROBEREQ_MSG, 72) \ | ||
99 | BRCMF_ENUM_DEF(DCS_REQUEST, 73) \ | 102 | BRCMF_ENUM_DEF(DCS_REQUEST, 73) \ |
100 | BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) | 103 | BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \ |
104 | BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) | ||
101 | 105 | ||
102 | #define BRCMF_ENUM_DEF(id, val) \ | 106 | #define BRCMF_ENUM_DEF(id, val) \ |
103 | BRCMF_E_##id = (val), | 107 | BRCMF_E_##id = (val), |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index 25c6b7de0594..ecc96f356a55 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c | |||
@@ -318,11 +318,6 @@ static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p) | |||
318 | brcmf_dbg(TRACE, "enter\n"); | 318 | brcmf_dbg(TRACE, "enter\n"); |
319 | 319 | ||
320 | bss_dev = &p2p->bss_idx[P2PAPI_BSSCFG_DEVICE]; | 320 | bss_dev = &p2p->bss_idx[P2PAPI_BSSCFG_DEVICE]; |
321 | if (bss_dev->vif == NULL) { | ||
322 | brcmf_err("do nothing, not initialized\n"); | ||
323 | return -EINVAL; | ||
324 | } | ||
325 | |||
326 | ifp = bss_dev->vif->ifp; | 321 | ifp = bss_dev->vif->ifp; |
327 | 322 | ||
328 | /* Set the discovery state to SCAN */ | 323 | /* Set the discovery state to SCAN */ |
@@ -348,8 +343,7 @@ static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p) | |||
348 | * | 343 | * |
349 | * Initializes the discovery device and configure the virtual interface. | 344 | * Initializes the discovery device and configure the virtual interface. |
350 | */ | 345 | */ |
351 | static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p, | 346 | static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p) |
352 | const u8 *ie, u32 ie_len) | ||
353 | { | 347 | { |
354 | struct brcmf_cfg80211_vif *vif; | 348 | struct brcmf_cfg80211_vif *vif; |
355 | s32 ret = 0; | 349 | s32 ret = 0; |
@@ -357,9 +351,8 @@ static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p, | |||
357 | brcmf_dbg(TRACE, "enter\n"); | 351 | brcmf_dbg(TRACE, "enter\n"); |
358 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | 352 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; |
359 | if (vif) { | 353 | if (vif) { |
360 | brcmf_dbg(INFO, | 354 | brcmf_dbg(INFO, "DISCOVERY init already done\n"); |
361 | "DISCOVERY init already done, just process IE\n"); | 355 | goto exit; |
362 | goto set_ie; | ||
363 | } | 356 | } |
364 | 357 | ||
365 | ret = brcmf_p2p_init_discovery(p2p); | 358 | ret = brcmf_p2p_init_discovery(p2p); |
@@ -380,20 +373,36 @@ static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p, | |||
380 | if (ret < 0) | 373 | if (ret < 0) |
381 | brcmf_err("wsec error %d\n", ret); | 374 | brcmf_err("wsec error %d\n", ret); |
382 | 375 | ||
383 | set_ie: | ||
384 | if (ie_len) { | ||
385 | ret = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG, | ||
386 | ie, ie_len); | ||
387 | |||
388 | if (ret < 0) { | ||
389 | brcmf_err("set probreq ie occurs error %d\n", ret); | ||
390 | goto exit; | ||
391 | } | ||
392 | } | ||
393 | exit: | 376 | exit: |
394 | return ret; | 377 | return ret; |
395 | } | 378 | } |
396 | 379 | ||
380 | /** | ||
381 | * brcmf_p2p_configure_probereq() - Configure probe request data. | ||
382 | * | ||
383 | * @p2p: P2P specific data. | ||
384 | * @ie: buffer containing information elements. | ||
385 | * @ie_len: length of @ie buffer. | ||
386 | * | ||
387 | */ | ||
388 | static int brcmf_p2p_configure_probereq(struct brcmf_p2p_info *p2p, | ||
389 | const u8 *ie, u32 ie_len) | ||
390 | { | ||
391 | struct brcmf_cfg80211_vif *vif; | ||
392 | s32 err = 0; | ||
393 | |||
394 | brcmf_dbg(TRACE, "enter\n"); | ||
395 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
396 | |||
397 | err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG, | ||
398 | ie, ie_len); | ||
399 | |||
400 | if (err < 0) | ||
401 | brcmf_err("set probreq ie occurs error %d\n", err); | ||
402 | |||
403 | return err; | ||
404 | } | ||
405 | |||
397 | /* | 406 | /* |
398 | * brcmf_p2p_escan() - initiate a P2P scan. | 407 | * brcmf_p2p_escan() - initiate a P2P scan. |
399 | * | 408 | * |
@@ -420,9 +429,6 @@ static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans, | |||
420 | struct brcmf_scan_params_le *sparams; | 429 | struct brcmf_scan_params_le *sparams; |
421 | struct brcmf_ssid ssid; | 430 | struct brcmf_ssid ssid; |
422 | 431 | ||
423 | /* add padding if uneven */ | ||
424 | if (num_chans % 2) | ||
425 | memsize += sizeof(__le16); | ||
426 | memsize += num_chans * sizeof(__le16); | 432 | memsize += num_chans * sizeof(__le16); |
427 | memblk = kzalloc(memsize, GFP_KERNEL); | 433 | memblk = kzalloc(memsize, GFP_KERNEL); |
428 | if (!memblk) | 434 | if (!memblk) |
@@ -639,8 +645,10 @@ int brcmf_p2p_scan_prep(struct wiphy *wiphy, | |||
639 | clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); | 645 | clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); |
640 | brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n"); | 646 | brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n"); |
641 | 647 | ||
642 | err = brcmf_p2p_enable_discovery(p2p, request->ie, | 648 | err = brcmf_p2p_enable_discovery(p2p); |
643 | request->ie_len); | 649 | if (err == 0) |
650 | err = brcmf_p2p_configure_probereq(p2p, request->ie, | ||
651 | request->ie_len); | ||
644 | 652 | ||
645 | /* | 653 | /* |
646 | * override .run_escan() callback. | 654 | * override .run_escan() callback. |
@@ -666,6 +674,92 @@ int brcmf_p2p_scan_prep(struct wiphy *wiphy, | |||
666 | return err; | 674 | return err; |
667 | } | 675 | } |
668 | 676 | ||
677 | |||
678 | /** | ||
679 | * brcmf_p2p_remain_on_channel() - put device on channel and stay there. | ||
680 | * | ||
681 | * @wiphy: wiphy device. | ||
682 | * @channel: channel to stay on. | ||
683 | * @duration: time in ms to remain on channel. | ||
684 | * | ||
685 | */ | ||
686 | int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
687 | struct ieee80211_channel *channel, | ||
688 | unsigned int duration, u64 *cookie) | ||
689 | { | ||
690 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
691 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
692 | struct brcmf_cfg80211_vif *vif; | ||
693 | s32 err; | ||
694 | u16 chanspec; | ||
695 | |||
696 | brcmf_dbg(TRACE, "Enter, channel: %d, duration ms (%d)\n", | ||
697 | ieee80211_frequency_to_channel(channel->center_freq), | ||
698 | duration); | ||
699 | |||
700 | *cookie = 0; | ||
701 | err = brcmf_p2p_enable_discovery(p2p); | ||
702 | if (err) | ||
703 | goto exit; | ||
704 | |||
705 | chanspec = channel_to_chanspec(channel); | ||
706 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
707 | err = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_LISTEN, | ||
708 | chanspec, (u16)duration); | ||
709 | if (err) | ||
710 | goto exit; | ||
711 | |||
712 | memcpy(&p2p->remain_on_channel, channel, | ||
713 | sizeof(p2p->remain_on_channel)); | ||
714 | |||
715 | set_bit(BRCMF_P2P_STATUS_REMAIN_ON_CHANNEL, &p2p->status); | ||
716 | |||
717 | exit: | ||
718 | cfg80211_ready_on_channel(wdev, *cookie, channel, duration, GFP_KERNEL); | ||
719 | return err; | ||
720 | } | ||
721 | |||
722 | |||
723 | /** | ||
724 | * brcmf_p2p_notify_listen_complete() - p2p listen has completed. | ||
725 | * | ||
726 | * @ifp: interfac control. | ||
727 | * @e: event message. Not used, to make it usable for fweh event dispatcher. | ||
728 | * @data: payload of message. Not used. | ||
729 | * | ||
730 | */ | ||
731 | int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp, | ||
732 | const struct brcmf_event_msg *e, | ||
733 | void *data) | ||
734 | { | ||
735 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; | ||
736 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
737 | |||
738 | brcmf_dbg(TRACE, "Enter\n"); | ||
739 | if (test_and_clear_bit(BRCMF_P2P_STATUS_REMAIN_ON_CHANNEL, | ||
740 | &p2p->status)) | ||
741 | cfg80211_remain_on_channel_expired(&ifp->vif->wdev, 0, | ||
742 | &p2p->remain_on_channel, | ||
743 | GFP_KERNEL); | ||
744 | return 0; | ||
745 | } | ||
746 | |||
747 | |||
748 | /** | ||
749 | * brcmf_p2p_cancel_remain_on_channel() - cancel p2p listen state. | ||
750 | * | ||
751 | * @ifp: interfac control. | ||
752 | * | ||
753 | */ | ||
754 | void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp) | ||
755 | { | ||
756 | if (!ifp) | ||
757 | return; | ||
758 | brcmf_p2p_set_discover_state(ifp, WL_P2P_DISC_ST_SCAN, 0, 0); | ||
759 | brcmf_p2p_notify_listen_complete(ifp, NULL, NULL); | ||
760 | } | ||
761 | |||
762 | |||
669 | /** | 763 | /** |
670 | * brcmf_p2p_attach() - attach for P2P. | 764 | * brcmf_p2p_attach() - attach for P2P. |
671 | * | 765 | * |
@@ -689,7 +783,11 @@ void brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg) | |||
689 | */ | 783 | */ |
690 | void brcmf_p2p_detach(struct brcmf_p2p_info *p2p) | 784 | void brcmf_p2p_detach(struct brcmf_p2p_info *p2p) |
691 | { | 785 | { |
692 | brcmf_p2p_deinit_discovery(p2p); | 786 | if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif != NULL) { |
787 | brcmf_p2p_cancel_remain_on_channel( | ||
788 | p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp); | ||
789 | brcmf_p2p_deinit_discovery(p2p); | ||
790 | } | ||
693 | /* just set it all to zero */ | 791 | /* just set it all to zero */ |
694 | memset(p2p, 0, sizeof(*p2p)); | 792 | memset(p2p, 0, sizeof(*p2p)); |
695 | } | 793 | } |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.h b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h index f304adfcce60..df93272ad49f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h | |||
@@ -60,10 +60,10 @@ struct p2p_bss { | |||
60 | * @BRCMF_P2P_STATUS_IF_DELETING: peer-to-peer vif delete sent to dongle. | 60 | * @BRCMF_P2P_STATUS_IF_DELETING: peer-to-peer vif delete sent to dongle. |
61 | * @BRCMF_P2P_STATUS_IF_CHANGING: peer-to-peer vif change sent to dongle. | 61 | * @BRCMF_P2P_STATUS_IF_CHANGING: peer-to-peer vif change sent to dongle. |
62 | * @BRCMF_P2P_STATUS_IF_CHANGED: peer-to-peer vif change completed on dongle. | 62 | * @BRCMF_P2P_STATUS_IF_CHANGED: peer-to-peer vif change completed on dongle. |
63 | * @BRCMF_P2P_STATUS_LISTEN_EXPIRED: listen duration expired. | ||
64 | * @BRCMF_P2P_STATUS_ACTION_TX_COMPLETED: action frame tx completed. | 63 | * @BRCMF_P2P_STATUS_ACTION_TX_COMPLETED: action frame tx completed. |
65 | * @BRCMF_P2P_STATUS_ACTION_TX_NOACK: action frame tx not acked. | 64 | * @BRCMF_P2P_STATUS_ACTION_TX_NOACK: action frame tx not acked. |
66 | * @BRCMF_P2P_STATUS_GO_NEG_PHASE: P2P GO negotiation ongoing. | 65 | * @BRCMF_P2P_STATUS_GO_NEG_PHASE: P2P GO negotiation ongoing. |
66 | * @BRCMF_P2P_STATUS_REMAIN_ON_CHANNEL: P2P listen, remaining on channel. | ||
67 | */ | 67 | */ |
68 | enum brcmf_p2p_status { | 68 | enum brcmf_p2p_status { |
69 | BRCMF_P2P_STATUS_IF_ADD = 0, | 69 | BRCMF_P2P_STATUS_IF_ADD = 0, |
@@ -71,10 +71,10 @@ enum brcmf_p2p_status { | |||
71 | BRCMF_P2P_STATUS_IF_DELETING, | 71 | BRCMF_P2P_STATUS_IF_DELETING, |
72 | BRCMF_P2P_STATUS_IF_CHANGING, | 72 | BRCMF_P2P_STATUS_IF_CHANGING, |
73 | BRCMF_P2P_STATUS_IF_CHANGED, | 73 | BRCMF_P2P_STATUS_IF_CHANGED, |
74 | BRCMF_P2P_STATUS_LISTEN_EXPIRED, | ||
75 | BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, | 74 | BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, |
76 | BRCMF_P2P_STATUS_ACTION_TX_NOACK, | 75 | BRCMF_P2P_STATUS_ACTION_TX_NOACK, |
77 | BRCMF_P2P_STATUS_GO_NEG_PHASE | 76 | BRCMF_P2P_STATUS_GO_NEG_PHASE, |
77 | BRCMF_P2P_STATUS_REMAIN_ON_CHANNEL | ||
78 | }; | 78 | }; |
79 | 79 | ||
80 | /** | 80 | /** |
@@ -88,6 +88,7 @@ enum brcmf_p2p_status { | |||
88 | * @listen_timer: timer for @WL_P2P_DISC_ST_LISTEN discover state. | 88 | * @listen_timer: timer for @WL_P2P_DISC_ST_LISTEN discover state. |
89 | * @ssid: ssid for P2P GO. | 89 | * @ssid: ssid for P2P GO. |
90 | * @listen_channel: channel for @WL_P2P_DISC_ST_LISTEN discover state. | 90 | * @listen_channel: channel for @WL_P2P_DISC_ST_LISTEN discover state. |
91 | * @remain_on_channel: contains copy of struct used by cfg80211. | ||
91 | */ | 92 | */ |
92 | struct brcmf_p2p_info { | 93 | struct brcmf_p2p_info { |
93 | struct brcmf_cfg80211_info *cfg; | 94 | struct brcmf_cfg80211_info *cfg; |
@@ -98,6 +99,7 @@ struct brcmf_p2p_info { | |||
98 | struct timer_list listen_timer; | 99 | struct timer_list listen_timer; |
99 | struct brcmf_ssid ssid; | 100 | struct brcmf_ssid ssid; |
100 | u8 listen_channel; | 101 | u8 listen_channel; |
102 | struct ieee80211_channel remain_on_channel; | ||
101 | }; | 103 | }; |
102 | 104 | ||
103 | void brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg); | 105 | void brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg); |
@@ -110,5 +112,12 @@ int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev); | |||
110 | void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev); | 112 | void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev); |
111 | int brcmf_p2p_scan_prep(struct wiphy *wiphy, | 113 | int brcmf_p2p_scan_prep(struct wiphy *wiphy, |
112 | struct cfg80211_scan_request *request); | 114 | struct cfg80211_scan_request *request); |
115 | int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
116 | struct ieee80211_channel *channel, | ||
117 | unsigned int duration, u64 *cookie); | ||
118 | int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp, | ||
119 | const struct brcmf_event_msg *e, | ||
120 | void *data); | ||
121 | void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp); | ||
113 | 122 | ||
114 | #endif /* WL_CFGP2P_H_ */ | 123 | #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 6b4e877123d6..6ab6397219a5 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | |||
@@ -3359,6 +3359,11 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, | |||
3359 | mgmt_ie_len = &saved_ie->probe_req_ie_len; | 3359 | mgmt_ie_len = &saved_ie->probe_req_ie_len; |
3360 | mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie); | 3360 | mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie); |
3361 | break; | 3361 | break; |
3362 | case BRCMF_VNDR_IE_PRBRSP_FLAG: | ||
3363 | mgmt_ie_buf = saved_ie->probe_res_ie; | ||
3364 | mgmt_ie_len = &saved_ie->probe_res_ie_len; | ||
3365 | mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie); | ||
3366 | break; | ||
3362 | default: | 3367 | default: |
3363 | err = -EPERM; | 3368 | err = -EPERM; |
3364 | brcmf_err("not suitable type\n"); | 3369 | brcmf_err("not suitable type\n"); |
@@ -3674,6 +3679,150 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, | |||
3674 | return err; | 3679 | return err; |
3675 | } | 3680 | } |
3676 | 3681 | ||
3682 | |||
3683 | static void | ||
3684 | brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy, | ||
3685 | struct wireless_dev *wdev, | ||
3686 | u16 frame_type, bool reg) | ||
3687 | { | ||
3688 | struct brcmf_if *ifp = netdev_priv(wdev->netdev); | ||
3689 | struct brcmf_cfg80211_vif *vif = ifp->vif; | ||
3690 | u16 mgmt_type; | ||
3691 | |||
3692 | brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg); | ||
3693 | |||
3694 | mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; | ||
3695 | if (reg) | ||
3696 | vif->mgmt_rx_reg |= BIT(mgmt_type); | ||
3697 | else | ||
3698 | vif->mgmt_rx_reg |= ~BIT(mgmt_type); | ||
3699 | } | ||
3700 | |||
3701 | |||
3702 | static int | ||
3703 | brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
3704 | struct ieee80211_channel *chan, bool offchan, | ||
3705 | unsigned int wait, const u8 *buf, size_t len, | ||
3706 | bool no_cck, bool dont_wait_for_ack, u64 *cookie) | ||
3707 | { | ||
3708 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
3709 | const struct ieee80211_mgmt *mgmt; | ||
3710 | struct brcmf_cfg80211_vif *vif; | ||
3711 | s32 err = 0; | ||
3712 | s32 ie_offset; | ||
3713 | s32 ie_len; | ||
3714 | |||
3715 | brcmf_dbg(TRACE, "Enter\n"); | ||
3716 | |||
3717 | *cookie = 0; | ||
3718 | |||
3719 | mgmt = (const struct ieee80211_mgmt *)buf; | ||
3720 | |||
3721 | if (ieee80211_is_mgmt(mgmt->frame_control)) { | ||
3722 | if (ieee80211_is_probe_resp(mgmt->frame_control)) { | ||
3723 | /* Right now the only reason to get a probe response */ | ||
3724 | /* is for p2p listen response from wpa_supplicant. */ | ||
3725 | /* Unfortunately the wpa_supplicant sends it on the */ | ||
3726 | /* primary ndev, while dongle wants it on the p2p */ | ||
3727 | /* vif. Since this is only reason for a probe */ | ||
3728 | /* response to be sent, the vif is taken from cfg. */ | ||
3729 | /* If ever desired to send proberesp for non p2p */ | ||
3730 | /* response then data should be checked for */ | ||
3731 | /* "DIRECT-". Note in future supplicant will take */ | ||
3732 | /* dedicated p2p wdev to do this and then this 'hack'*/ | ||
3733 | /* is not needed anymore. */ | ||
3734 | ie_offset = DOT11_MGMT_HDR_LEN + | ||
3735 | DOT11_BCN_PRB_FIXED_LEN; | ||
3736 | ie_len = len - ie_offset; | ||
3737 | |||
3738 | vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
3739 | if (vif == NULL) { | ||
3740 | brcmf_err("No p2p device available for probe response\n"); | ||
3741 | err = -ENODEV; | ||
3742 | goto exit; | ||
3743 | } | ||
3744 | err = brcmf_vif_set_mgmt_ie(vif, | ||
3745 | BRCMF_VNDR_IE_PRBRSP_FLAG, | ||
3746 | &buf[ie_offset], | ||
3747 | ie_len); | ||
3748 | cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true, | ||
3749 | GFP_KERNEL); | ||
3750 | goto exit; | ||
3751 | } | ||
3752 | } | ||
3753 | brcmf_dbg(TRACE, "Unhandled, is_mgmt %d, fc=%04x!!!!!\n", | ||
3754 | ieee80211_is_mgmt(mgmt->frame_control), mgmt->frame_control); | ||
3755 | exit: | ||
3756 | return err; | ||
3757 | } | ||
3758 | |||
3759 | |||
3760 | static int | ||
3761 | brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, | ||
3762 | struct wireless_dev *wdev, | ||
3763 | u64 cookie) | ||
3764 | { | ||
3765 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
3766 | struct brcmf_cfg80211_vif *vif; | ||
3767 | int err = 0; | ||
3768 | |||
3769 | brcmf_dbg(TRACE, "Enter p2p listen cancel\n"); | ||
3770 | |||
3771 | vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
3772 | if (vif == NULL) { | ||
3773 | brcmf_err("No p2p device available for probe response\n"); | ||
3774 | err = -ENODEV; | ||
3775 | goto exit; | ||
3776 | } | ||
3777 | brcmf_p2p_cancel_remain_on_channel(vif->ifp); | ||
3778 | exit: | ||
3779 | return err; | ||
3780 | } | ||
3781 | |||
3782 | static s32 brcmf_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, | ||
3783 | const struct brcmf_event_msg *e, | ||
3784 | void *data) | ||
3785 | { | ||
3786 | struct wireless_dev *wdev; | ||
3787 | struct brcmf_cfg80211_vif *vif = ifp->vif; | ||
3788 | struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data; | ||
3789 | u16 chanspec = be16_to_cpu(rxframe->chanspec); | ||
3790 | u8 *mgmt_frame; | ||
3791 | u32 mgmt_frame_len; | ||
3792 | s32 freq; | ||
3793 | u16 mgmt_type; | ||
3794 | |||
3795 | brcmf_dbg(INFO, | ||
3796 | "Enter: event %d reason %d\n", e->event_code, e->reason); | ||
3797 | |||
3798 | /* Firmware sends us two proberesponses for each idx one. At the */ | ||
3799 | /* moment only bsscfgidx 0 is passed up to supplicant */ | ||
3800 | if (e->bsscfgidx) | ||
3801 | return 0; | ||
3802 | |||
3803 | /* Check if wpa_supplicant has registered for this frame */ | ||
3804 | brcmf_dbg(INFO, "vif->mgmt_rx_reg %04x\n", vif->mgmt_rx_reg); | ||
3805 | mgmt_type = (IEEE80211_STYPE_PROBE_REQ & IEEE80211_FCTL_STYPE) >> 4; | ||
3806 | if ((vif->mgmt_rx_reg & BIT(mgmt_type)) == 0) | ||
3807 | return 0; | ||
3808 | |||
3809 | mgmt_frame = (u8 *)(rxframe + 1); | ||
3810 | mgmt_frame_len = e->datalen - sizeof(*rxframe); | ||
3811 | freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec), | ||
3812 | CHSPEC_IS2G(chanspec) ? | ||
3813 | IEEE80211_BAND_2GHZ : | ||
3814 | IEEE80211_BAND_5GHZ); | ||
3815 | wdev = ifp->ndev->ieee80211_ptr; | ||
3816 | cfg80211_rx_mgmt(wdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); | ||
3817 | |||
3818 | brcmf_dbg(INFO, | ||
3819 | "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n", | ||
3820 | mgmt_frame_len, e->datalen, chanspec, freq); | ||
3821 | |||
3822 | return 0; | ||
3823 | } | ||
3824 | |||
3825 | |||
3677 | static struct cfg80211_ops wl_cfg80211_ops = { | 3826 | static struct cfg80211_ops wl_cfg80211_ops = { |
3678 | .add_virtual_intf = brcmf_cfg80211_add_iface, | 3827 | .add_virtual_intf = brcmf_cfg80211_add_iface, |
3679 | .del_virtual_intf = brcmf_cfg80211_del_iface, | 3828 | .del_virtual_intf = brcmf_cfg80211_del_iface, |
@@ -3703,6 +3852,10 @@ static struct cfg80211_ops wl_cfg80211_ops = { | |||
3703 | .del_station = brcmf_cfg80211_del_station, | 3852 | .del_station = brcmf_cfg80211_del_station, |
3704 | .sched_scan_start = brcmf_cfg80211_sched_scan_start, | 3853 | .sched_scan_start = brcmf_cfg80211_sched_scan_start, |
3705 | .sched_scan_stop = brcmf_cfg80211_sched_scan_stop, | 3854 | .sched_scan_stop = brcmf_cfg80211_sched_scan_stop, |
3855 | .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register, | ||
3856 | .mgmt_tx = brcmf_cfg80211_mgmt_tx, | ||
3857 | .remain_on_channel = brcmf_p2p_remain_on_channel, | ||
3858 | .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel, | ||
3706 | #ifdef CONFIG_NL80211_TESTMODE | 3859 | #ifdef CONFIG_NL80211_TESTMODE |
3707 | .testmode_cmd = brcmf_cfg80211_testmode | 3860 | .testmode_cmd = brcmf_cfg80211_testmode |
3708 | #endif | 3861 | #endif |
@@ -3765,6 +3918,30 @@ static const struct ieee80211_iface_combination brcmf_iface_combos[] = { | |||
3765 | } | 3918 | } |
3766 | }; | 3919 | }; |
3767 | 3920 | ||
3921 | static const struct ieee80211_txrx_stypes | ||
3922 | brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { | ||
3923 | [NL80211_IFTYPE_STATION] = { | ||
3924 | .tx = 0xffff, | ||
3925 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
3926 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
3927 | }, | ||
3928 | [NL80211_IFTYPE_P2P_CLIENT] = { | ||
3929 | .tx = 0xffff, | ||
3930 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
3931 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
3932 | }, | ||
3933 | [NL80211_IFTYPE_P2P_GO] = { | ||
3934 | .tx = 0xffff, | ||
3935 | .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | | ||
3936 | BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | | ||
3937 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | | ||
3938 | BIT(IEEE80211_STYPE_DISASSOC >> 4) | | ||
3939 | BIT(IEEE80211_STYPE_AUTH >> 4) | | ||
3940 | BIT(IEEE80211_STYPE_DEAUTH >> 4) | | ||
3941 | BIT(IEEE80211_STYPE_ACTION >> 4) | ||
3942 | } | ||
3943 | }; | ||
3944 | |||
3768 | static struct wiphy *brcmf_setup_wiphy(struct device *phydev) | 3945 | static struct wiphy *brcmf_setup_wiphy(struct device *phydev) |
3769 | { | 3946 | { |
3770 | struct wiphy *wiphy; | 3947 | struct wiphy *wiphy; |
@@ -3797,10 +3974,10 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) | |||
3797 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | 3974 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |
3798 | wiphy->cipher_suites = __wl_cipher_suites; | 3975 | wiphy->cipher_suites = __wl_cipher_suites; |
3799 | wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); | 3976 | wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); |
3800 | wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power | 3977 | wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT | |
3801 | * save mode | 3978 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
3802 | * by default | 3979 | wiphy->mgmt_stypes = brcmf_txrx_stypes; |
3803 | */ | 3980 | wiphy->max_remain_on_channel_duration = 5000; |
3804 | brcmf_wiphy_pno_params(wiphy); | 3981 | brcmf_wiphy_pno_params(wiphy); |
3805 | err = wiphy_register(wiphy); | 3982 | err = wiphy_register(wiphy); |
3806 | if (err < 0) { | 3983 | if (err < 0) { |
@@ -4271,6 +4448,10 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg) | |||
4271 | brcmf_notify_sched_scan_results); | 4448 | brcmf_notify_sched_scan_results); |
4272 | brcmf_fweh_register(cfg->pub, BRCMF_E_IF, | 4449 | brcmf_fweh_register(cfg->pub, BRCMF_E_IF, |
4273 | brcmf_notify_vif_event); | 4450 | brcmf_notify_vif_event); |
4451 | brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG, | ||
4452 | brcmf_notify_rx_mgmt_p2p_probereq); | ||
4453 | brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE, | ||
4454 | brcmf_p2p_notify_listen_complete); | ||
4274 | } | 4455 | } |
4275 | 4456 | ||
4276 | static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) | 4457 | static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index 691f613d99d2..a996afa8df4d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h | |||
@@ -189,6 +189,7 @@ struct vif_saved_ie { | |||
189 | * @sme_state: SME state using enum brcmf_vif_status bits. | 189 | * @sme_state: SME state using enum brcmf_vif_status bits. |
190 | * @pm_block: power-management blocked. | 190 | * @pm_block: power-management blocked. |
191 | * @list: linked list. | 191 | * @list: linked list. |
192 | * @mgmt_rx_reg: registered rx mgmt frame types. | ||
192 | */ | 193 | */ |
193 | struct brcmf_cfg80211_vif { | 194 | struct brcmf_cfg80211_vif { |
194 | struct brcmf_if *ifp; | 195 | struct brcmf_if *ifp; |
@@ -200,6 +201,7 @@ struct brcmf_cfg80211_vif { | |||
200 | bool pm_block; | 201 | bool pm_block; |
201 | struct vif_saved_ie saved_ie; | 202 | struct vif_saved_ie saved_ie; |
202 | struct list_head list; | 203 | struct list_head list; |
204 | u16 mgmt_rx_reg; | ||
203 | }; | 205 | }; |
204 | 206 | ||
205 | /* association inform */ | 207 | /* association inform */ |