]> Pileus Git - ~andy/linux/commitdiff
brcmfmac: add support for P2P listen mode.
authorHante Meuleman <meuleman@broadcom.com>
Fri, 8 Feb 2013 14:53:38 +0000 (15:53 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 8 Feb 2013 19:51:37 +0000 (14:51 -0500)
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>
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/fweh.h
drivers/net/wireless/brcm80211/brcmfmac/p2p.c
drivers/net/wireless/brcm80211/brcmfmac/p2p.h
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h

index b61254dd42c022dd4c23a473da018f5bbf7f11cd..82724d371dd00ef4f5c3d05e668bfe04be88efb7 100644 (file)
@@ -452,6 +452,19 @@ struct brcmf_sta_info_le {
        __le32  rx_decrypt_failures;    /* # of packet decrypted failed */
 };
 
+/*
+ * WLC_E_PROBRESP_MSG
+ * WLC_E_P2P_PROBREQ_MSG
+ * WLC_E_ACTION_FRAME_RX
+ */
+struct brcmf_rx_mgmt_data {
+       __be16  version;
+       __be16  chanspec;
+       __be32  rssi;
+       __be32  mactime;
+       __be32  rate;
+};
+
 /* Bus independent dongle command */
 struct brcmf_dcmd {
        uint cmd;               /* common dongle cmd definition */
index 36901f76a3b5b76f3ff73082c2b977e6f7f53db6..8c39b51dcccfcead4dd00efd8f2bf572476ecbeb 100644 (file)
@@ -83,6 +83,7 @@ struct brcmf_event;
        BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \
        BRCMF_ENUM_DEF(TRACE, 52) \
        BRCMF_ENUM_DEF(IF, 54) \
+       BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \
        BRCMF_ENUM_DEF(RSSI, 56) \
        BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \
        BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \
@@ -96,8 +97,11 @@ struct brcmf_event;
        BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \
        BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \
        BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \
+       BRCMF_ENUM_DEF(PROBERESP_MSG, 71) \
+       BRCMF_ENUM_DEF(P2P_PROBEREQ_MSG, 72) \
        BRCMF_ENUM_DEF(DCS_REQUEST, 73) \
-       BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74)
+       BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \
+       BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75)
 
 #define BRCMF_ENUM_DEF(id, val) \
        BRCMF_E_##id = (val),
index 25c6b7de0594f19550c5829fe0de4e1b01634a20..ecc96f356a556b4d6d7b257338fc62d43b483f10 100644 (file)
@@ -318,11 +318,6 @@ static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p)
        brcmf_dbg(TRACE, "enter\n");
 
        bss_dev = &p2p->bss_idx[P2PAPI_BSSCFG_DEVICE];
-       if (bss_dev->vif == NULL) {
-               brcmf_err("do nothing, not initialized\n");
-               return -EINVAL;
-       }
-
        ifp = bss_dev->vif->ifp;
 
        /* Set the discovery state to SCAN */
@@ -348,8 +343,7 @@ static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p)
  *
  * Initializes the discovery device and configure the virtual interface.
  */
-static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p,
-                                     const u8 *ie, u32 ie_len)
+static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p)
 {
        struct brcmf_cfg80211_vif *vif;
        s32 ret = 0;
@@ -357,9 +351,8 @@ static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p,
        brcmf_dbg(TRACE, "enter\n");
        vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
        if (vif) {
-               brcmf_dbg(INFO,
-                         "DISCOVERY init already done, just process IE\n");
-               goto set_ie;
+               brcmf_dbg(INFO, "DISCOVERY init already done\n");
+               goto exit;
        }
 
        ret = brcmf_p2p_init_discovery(p2p);
@@ -380,20 +373,36 @@ static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p,
        if (ret < 0)
                brcmf_err("wsec error %d\n", ret);
 
-set_ie:
-       if (ie_len) {
-               ret = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG,
-                                           ie, ie_len);
-
-               if (ret < 0) {
-                       brcmf_err("set probreq ie occurs error %d\n", ret);
-                       goto exit;
-               }
-       }
 exit:
        return ret;
 }
 
+/**
+ * brcmf_p2p_configure_probereq() - Configure probe request data.
+ *
+ * @p2p: P2P specific data.
+ * @ie: buffer containing information elements.
+ * @ie_len: length of @ie buffer.
+ *
+ */
+static int brcmf_p2p_configure_probereq(struct brcmf_p2p_info *p2p,
+                                       const u8 *ie, u32 ie_len)
+{
+       struct brcmf_cfg80211_vif *vif;
+       s32 err = 0;
+
+       brcmf_dbg(TRACE, "enter\n");
+       vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+
+       err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG,
+                                   ie, ie_len);
+
+       if (err < 0)
+               brcmf_err("set probreq ie occurs error %d\n", err);
+
+       return err;
+}
+
 /*
  * brcmf_p2p_escan() - initiate a P2P scan.
  *
@@ -420,9 +429,6 @@ static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans,
        struct brcmf_scan_params_le *sparams;
        struct brcmf_ssid ssid;
 
-       /* add padding if uneven */
-       if (num_chans % 2)
-               memsize += sizeof(__le16);
        memsize += num_chans * sizeof(__le16);
        memblk = kzalloc(memsize, GFP_KERNEL);
        if (!memblk)
@@ -639,8 +645,10 @@ int brcmf_p2p_scan_prep(struct wiphy *wiphy,
                clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
                brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n");
 
-               err = brcmf_p2p_enable_discovery(p2p, request->ie,
-                                                request->ie_len);
+               err = brcmf_p2p_enable_discovery(p2p);
+               if (err == 0)
+                       err = brcmf_p2p_configure_probereq(p2p, request->ie,
+                                                          request->ie_len);
 
                /*
                 * override .run_escan() callback.
@@ -666,6 +674,92 @@ int brcmf_p2p_scan_prep(struct wiphy *wiphy,
        return err;
 }
 
+
+/**
+ * brcmf_p2p_remain_on_channel() - put device on channel and stay there.
+ *
+ * @wiphy: wiphy device.
+ * @channel: channel to stay on.
+ * @duration: time in ms to remain on channel.
+ *
+ */
+int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
+                               struct ieee80211_channel *channel,
+                               unsigned int duration, u64 *cookie)
+{
+       struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct brcmf_p2p_info *p2p = &cfg->p2p;
+       struct brcmf_cfg80211_vif *vif;
+       s32 err;
+       u16 chanspec;
+
+       brcmf_dbg(TRACE, "Enter, channel: %d, duration ms (%d)\n",
+                 ieee80211_frequency_to_channel(channel->center_freq),
+                 duration);
+
+       *cookie = 0;
+       err = brcmf_p2p_enable_discovery(p2p);
+       if (err)
+               goto exit;
+
+       chanspec = channel_to_chanspec(channel);
+       vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+       err = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_LISTEN,
+                                          chanspec, (u16)duration);
+       if (err)
+               goto exit;
+
+       memcpy(&p2p->remain_on_channel, channel,
+              sizeof(p2p->remain_on_channel));
+
+       set_bit(BRCMF_P2P_STATUS_REMAIN_ON_CHANNEL, &p2p->status);
+
+exit:
+       cfg80211_ready_on_channel(wdev, *cookie, channel, duration, GFP_KERNEL);
+       return err;
+}
+
+
+/**
+ * brcmf_p2p_notify_listen_complete() - p2p listen has completed.
+ *
+ * @ifp: interfac control.
+ * @e: event message. Not used, to make it usable for fweh event dispatcher.
+ * @data: payload of message. Not used.
+ *
+ */
+int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
+                                    const struct brcmf_event_msg *e,
+                                    void *data)
+{
+       struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+       struct brcmf_p2p_info *p2p = &cfg->p2p;
+
+       brcmf_dbg(TRACE, "Enter\n");
+       if (test_and_clear_bit(BRCMF_P2P_STATUS_REMAIN_ON_CHANNEL,
+                              &p2p->status))
+               cfg80211_remain_on_channel_expired(&ifp->vif->wdev, 0,
+                                                  &p2p->remain_on_channel,
+                                                  GFP_KERNEL);
+       return 0;
+}
+
+
+/**
+ * brcmf_p2p_cancel_remain_on_channel() - cancel p2p listen state.
+ *
+ * @ifp: interfac control.
+ *
+ */
+void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp)
+{
+       if (!ifp)
+               return;
+       brcmf_p2p_set_discover_state(ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
+       brcmf_p2p_notify_listen_complete(ifp, NULL, NULL);
+}
+
+
 /**
  * brcmf_p2p_attach() - attach for P2P.
  *
@@ -689,7 +783,11 @@ void brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
  */
 void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
 {
-       brcmf_p2p_deinit_discovery(p2p);
+       if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif != NULL) {
+               brcmf_p2p_cancel_remain_on_channel(
+                       p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp);
+               brcmf_p2p_deinit_discovery(p2p);
+       }
        /* just set it all to zero */
        memset(p2p, 0, sizeof(*p2p));
 }
index f304adfcce6038e315524cc1b0250fbbc79fbf5a..df93272ad49f63358a69d5c0180d7cff179d4819 100644 (file)
@@ -60,10 +60,10 @@ struct p2p_bss {
  * @BRCMF_P2P_STATUS_IF_DELETING: peer-to-peer vif delete sent to dongle.
  * @BRCMF_P2P_STATUS_IF_CHANGING: peer-to-peer vif change sent to dongle.
  * @BRCMF_P2P_STATUS_IF_CHANGED: peer-to-peer vif change completed on dongle.
- * @BRCMF_P2P_STATUS_LISTEN_EXPIRED: listen duration expired.
  * @BRCMF_P2P_STATUS_ACTION_TX_COMPLETED: action frame tx completed.
  * @BRCMF_P2P_STATUS_ACTION_TX_NOACK: action frame tx not acked.
  * @BRCMF_P2P_STATUS_GO_NEG_PHASE: P2P GO negotiation ongoing.
+ * @BRCMF_P2P_STATUS_REMAIN_ON_CHANNEL: P2P listen, remaining on channel.
  */
 enum brcmf_p2p_status {
        BRCMF_P2P_STATUS_IF_ADD = 0,
@@ -71,10 +71,10 @@ enum brcmf_p2p_status {
        BRCMF_P2P_STATUS_IF_DELETING,
        BRCMF_P2P_STATUS_IF_CHANGING,
        BRCMF_P2P_STATUS_IF_CHANGED,
-       BRCMF_P2P_STATUS_LISTEN_EXPIRED,
        BRCMF_P2P_STATUS_ACTION_TX_COMPLETED,
        BRCMF_P2P_STATUS_ACTION_TX_NOACK,
-       BRCMF_P2P_STATUS_GO_NEG_PHASE
+       BRCMF_P2P_STATUS_GO_NEG_PHASE,
+       BRCMF_P2P_STATUS_REMAIN_ON_CHANNEL
 };
 
 /**
@@ -88,6 +88,7 @@ enum brcmf_p2p_status {
  * @listen_timer: timer for @WL_P2P_DISC_ST_LISTEN discover state.
  * @ssid: ssid for P2P GO.
  * @listen_channel: channel for @WL_P2P_DISC_ST_LISTEN discover state.
+ * @remain_on_channel: contains copy of struct used by cfg80211.
  */
 struct brcmf_p2p_info {
        struct brcmf_cfg80211_info *cfg;
@@ -98,6 +99,7 @@ struct brcmf_p2p_info {
        struct timer_list listen_timer;
        struct brcmf_ssid ssid;
        u8 listen_channel;
+       struct ieee80211_channel remain_on_channel;
 };
 
 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);
 void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev);
 int brcmf_p2p_scan_prep(struct wiphy *wiphy,
                        struct cfg80211_scan_request *request);
+int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
+                               struct ieee80211_channel *channel,
+                               unsigned int duration, u64 *cookie);
+int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
+                                    const struct brcmf_event_msg *e,
+                                    void *data);
+void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp);
 
 #endif /* WL_CFGP2P_H_ */
index 6b4e877123d60966c2a0ea978497b13babed9bed..6ab6397219a55b3a796036dbd1a9f163c1078cfd 100644 (file)
@@ -3359,6 +3359,11 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
                        mgmt_ie_len = &saved_ie->probe_req_ie_len;
                        mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
                        break;
+               case BRCMF_VNDR_IE_PRBRSP_FLAG:
+                       mgmt_ie_buf = saved_ie->probe_res_ie;
+                       mgmt_ie_len = &saved_ie->probe_res_ie_len;
+                       mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
+                       break;
                default:
                        err = -EPERM;
                        brcmf_err("not suitable type\n");
@@ -3674,6 +3679,150 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
        return err;
 }
 
+
+static void
+brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
+                                  struct wireless_dev *wdev,
+                                  u16 frame_type, bool reg)
+{
+       struct brcmf_if *ifp = netdev_priv(wdev->netdev);
+       struct brcmf_cfg80211_vif *vif = ifp->vif;
+       u16 mgmt_type;
+
+       brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
+
+       mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
+       if (reg)
+               vif->mgmt_rx_reg |= BIT(mgmt_type);
+       else
+               vif->mgmt_rx_reg |= ~BIT(mgmt_type);
+}
+
+
+static int
+brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
+                      struct ieee80211_channel *chan, bool offchan,
+                      unsigned int wait, const u8 *buf, size_t len,
+                      bool no_cck, bool dont_wait_for_ack, u64 *cookie)
+{
+       struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       const struct ieee80211_mgmt *mgmt;
+       struct brcmf_cfg80211_vif *vif;
+       s32 err = 0;
+       s32 ie_offset;
+       s32 ie_len;
+
+       brcmf_dbg(TRACE, "Enter\n");
+
+       *cookie = 0;
+
+       mgmt = (const struct ieee80211_mgmt *)buf;
+
+       if (ieee80211_is_mgmt(mgmt->frame_control)) {
+               if (ieee80211_is_probe_resp(mgmt->frame_control)) {
+                       /* Right now the only reason to get a probe response */
+                       /* is for p2p listen response from wpa_supplicant.   */
+                       /* Unfortunately the wpa_supplicant sends it on the  */
+                       /* primary ndev, while dongle wants it on the p2p    */
+                       /* vif. Since this is only reason for a probe        */
+                       /* response to be sent, the vif is taken from cfg.   */
+                       /* If ever desired to send proberesp for non p2p     */
+                       /* response then data should be checked for          */
+                       /* "DIRECT-". Note in future supplicant will take    */
+                       /* dedicated p2p wdev to do this and then this 'hack'*/
+                       /* is not needed anymore.                            */
+                       ie_offset =  DOT11_MGMT_HDR_LEN +
+                                    DOT11_BCN_PRB_FIXED_LEN;
+                       ie_len = len - ie_offset;
+
+                       vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+                       if (vif == NULL) {
+                               brcmf_err("No p2p device available for probe response\n");
+                               err = -ENODEV;
+                               goto exit;
+                       }
+                       err = brcmf_vif_set_mgmt_ie(vif,
+                                                   BRCMF_VNDR_IE_PRBRSP_FLAG,
+                                                   &buf[ie_offset],
+                                                   ie_len);
+                       cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
+                                               GFP_KERNEL);
+                       goto exit;
+               }
+       }
+       brcmf_dbg(TRACE, "Unhandled, is_mgmt %d, fc=%04x!!!!!\n",
+                 ieee80211_is_mgmt(mgmt->frame_control), mgmt->frame_control);
+exit:
+       return err;
+}
+
+
+static int
+brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
+                                       struct wireless_dev *wdev,
+                                       u64 cookie)
+{
+       struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct brcmf_cfg80211_vif *vif;
+       int err = 0;
+
+       brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
+
+       vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+       if (vif == NULL) {
+               brcmf_err("No p2p device available for probe response\n");
+               err = -ENODEV;
+               goto exit;
+       }
+       brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+exit:
+       return err;
+}
+
+static s32 brcmf_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
+                                            const struct brcmf_event_msg *e,
+                                            void *data)
+{
+       struct wireless_dev *wdev;
+       struct brcmf_cfg80211_vif *vif = ifp->vif;
+       struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
+       u16 chanspec = be16_to_cpu(rxframe->chanspec);
+       u8 *mgmt_frame;
+       u32 mgmt_frame_len;
+       s32 freq;
+       u16 mgmt_type;
+
+       brcmf_dbg(INFO,
+                 "Enter: event %d reason %d\n", e->event_code, e->reason);
+
+       /* Firmware sends us two proberesponses for each idx one. At the */
+       /* moment only bsscfgidx 0 is passed up to supplicant            */
+       if (e->bsscfgidx)
+               return 0;
+
+       /* Check if wpa_supplicant has registered for this frame */
+       brcmf_dbg(INFO, "vif->mgmt_rx_reg %04x\n", vif->mgmt_rx_reg);
+       mgmt_type = (IEEE80211_STYPE_PROBE_REQ & IEEE80211_FCTL_STYPE) >> 4;
+       if ((vif->mgmt_rx_reg & BIT(mgmt_type)) == 0)
+               return 0;
+
+       mgmt_frame = (u8 *)(rxframe + 1);
+       mgmt_frame_len = e->datalen - sizeof(*rxframe);
+       freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec),
+                                             CHSPEC_IS2G(chanspec) ?
+                                             IEEE80211_BAND_2GHZ :
+                                             IEEE80211_BAND_5GHZ);
+       wdev = ifp->ndev->ieee80211_ptr;
+       cfg80211_rx_mgmt(wdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
+
+       brcmf_dbg(INFO,
+                 "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
+                 mgmt_frame_len, e->datalen, chanspec, freq);
+
+       return 0;
+}
+
+
 static struct cfg80211_ops wl_cfg80211_ops = {
        .add_virtual_intf = brcmf_cfg80211_add_iface,
        .del_virtual_intf = brcmf_cfg80211_del_iface,
@@ -3703,6 +3852,10 @@ static struct cfg80211_ops wl_cfg80211_ops = {
        .del_station = brcmf_cfg80211_del_station,
        .sched_scan_start = brcmf_cfg80211_sched_scan_start,
        .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
+       .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
+       .mgmt_tx = brcmf_cfg80211_mgmt_tx,
+       .remain_on_channel = brcmf_p2p_remain_on_channel,
+       .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
 #ifdef CONFIG_NL80211_TESTMODE
        .testmode_cmd = brcmf_cfg80211_testmode
 #endif
@@ -3765,6 +3918,30 @@ static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
        }
 };
 
+static const struct ieee80211_txrx_stypes
+brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
+       [NL80211_IFTYPE_STATION] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+                     BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+       },
+       [NL80211_IFTYPE_P2P_CLIENT] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+                     BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+       },
+       [NL80211_IFTYPE_P2P_GO] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+                     BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+                     BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+                     BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+                     BIT(IEEE80211_STYPE_AUTH >> 4) |
+                     BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+                     BIT(IEEE80211_STYPE_ACTION >> 4)
+       }
+};
+
 static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
 {
        struct wiphy *wiphy;
@@ -3797,10 +3974,10 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
        wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
        wiphy->cipher_suites = __wl_cipher_suites;
        wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
-       wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;    /* enable power
-                                                                * save mode
-                                                                * by default
-                                                                */
+       wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
+                       WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+       wiphy->mgmt_stypes = brcmf_txrx_stypes;
+       wiphy->max_remain_on_channel_duration = 5000;
        brcmf_wiphy_pno_params(wiphy);
        err = wiphy_register(wiphy);
        if (err < 0) {
@@ -4271,6 +4448,10 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
                            brcmf_notify_sched_scan_results);
        brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
                            brcmf_notify_vif_event);
+       brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
+                           brcmf_notify_rx_mgmt_p2p_probereq);
+       brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
+                           brcmf_p2p_notify_listen_complete);
 }
 
 static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
index 691f613d99d2214d4a08e33d08d0b8445cb9d96b..a996afa8df4d2922680af2b953a78651c58a5b46 100644 (file)
@@ -189,6 +189,7 @@ struct vif_saved_ie {
  * @sme_state: SME state using enum brcmf_vif_status bits.
  * @pm_block: power-management blocked.
  * @list: linked list.
+ * @mgmt_rx_reg: registered rx mgmt frame types.
  */
 struct brcmf_cfg80211_vif {
        struct brcmf_if *ifp;
@@ -200,6 +201,7 @@ struct brcmf_cfg80211_vif {
        bool pm_block;
        struct vif_saved_ie saved_ie;
        struct list_head list;
+       u16 mgmt_rx_reg;
 };
 
 /* association inform */