aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorHante Meuleman <meuleman@broadcom.com>2013-02-08 09:53:38 -0500
committerJohn W. Linville <linville@tuxdriver.com>2013-02-08 14:51:37 -0500
commit0de8aace0ff499bf1b6597e7f272961d2e335933 (patch)
tree3bcaa7edefc2ecf74448f3ffa2665de262d014da /drivers/net/wireless
parentd3c0b63396442d564ceb4db0dcc51e70918b9c93 (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.h13
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fweh.h6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.c150
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.h15
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c189
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h2
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 */
460struct 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 */
456struct brcmf_dcmd { 469struct 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 */
351static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p, 346static 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
383set_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 }
393exit: 376exit:
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 */
388static 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 */
686int 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
717exit:
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 */
731int 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 */
754void 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 */
690void brcmf_p2p_detach(struct brcmf_p2p_info *p2p) 784void 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 */
68enum brcmf_p2p_status { 68enum 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 */
92struct brcmf_p2p_info { 93struct 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
103void brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg); 105void brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg);
@@ -110,5 +112,12 @@ int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev);
110void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev); 112void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev);
111int brcmf_p2p_scan_prep(struct wiphy *wiphy, 113int brcmf_p2p_scan_prep(struct wiphy *wiphy,
112 struct cfg80211_scan_request *request); 114 struct cfg80211_scan_request *request);
115int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
116 struct ieee80211_channel *channel,
117 unsigned int duration, u64 *cookie);
118int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
119 const struct brcmf_event_msg *e,
120 void *data);
121void 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
3683static void
3684brcmf_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
3702static int
3703brcmf_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);
3755exit:
3756 return err;
3757}
3758
3759
3760static int
3761brcmf_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);
3778exit:
3779 return err;
3780}
3781
3782static 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
3677static struct cfg80211_ops wl_cfg80211_ops = { 3826static 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
3921static const struct ieee80211_txrx_stypes
3922brcmf_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
3768static struct wiphy *brcmf_setup_wiphy(struct device *phydev) 3945static 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
4276static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) 4457static 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 */
193struct brcmf_cfg80211_vif { 194struct 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 */