diff mbox

[2/3] brcmfmac: handle monitor mode marked msgbuf packets

Message ID 20180522131836.26858-2-zajec5@gmail.com (mailing list archive)
State Changes Requested
Delegated to: Kalle Valo
Headers show

Commit Message

Rafał Miłecki May 22, 2018, 1:18 p.m. UTC
From: Rafał Miłecki <rafal@milecki.pl>

New Broadcom firmwares mark monitor mode packets using a newly defined
bit in the flags field. Use it to filter them out and pass to the
monitor interface. These defines were found in bcmmsgbuf.h from SDK.

As not every firmware generates radiotap header this commit introduces
BRCMF_FEAT_MON_FMT_RADIOTAP that has to be set per firmware version. If
not present brcmf_netif_mon_rx() assumed packet being a raw 802.11 frame
and prepends it with an empty radiotap header.

It's limited to the msgbuf protocol. Adding support for SDIO/USB devices
will require some extra research.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
 .../wireless/broadcom/brcm80211/brcmfmac/core.c    | 24 ++++++++++++++++++++++
 .../wireless/broadcom/brcm80211/brcmfmac/core.h    |  2 ++
 .../wireless/broadcom/brcm80211/brcmfmac/feature.h |  6 +++++-
 .../wireless/broadcom/brcm80211/brcmfmac/msgbuf.c  | 17 +++++++++++++++
 4 files changed, 48 insertions(+), 1 deletion(-)

Comments

kernel test robot May 23, 2018, 10:30 a.m. UTC | #1
Hi Rafał,

I love your patch! Perhaps something to improve:

[auto build test WARNING on wireless-drivers-next/master]
[also build test WARNING on v4.17-rc6 next-20180517]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Rafa-Mi-ecki/brcmfmac-allow-specifying-features-per-firmware-version/20180523-160546
base:   https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next.git master
reproduce:
        # apt-get install sparse
        make ARCH=x86_64 allmodconfig
        make C=1 CF=-D__CHECK_ENDIAN__


sparse warnings: (new ones prefixed by >>)

   drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c:304:30: sparse: expression using sizeof(void)
>> drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c:417:34: sparse: incorrect type in assignment (different base types) @@    expected restricted __le16 [usertype] it_len @@    got 6 [usertype] it_len @@
   drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c:417:34:    expected restricted __le16 [usertype] it_len
   drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c:417:34:    got unsigned long

vim +417 drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c

   264	
   265	static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
   266						   struct net_device *ndev)
   267	{
   268		int ret;
   269		struct brcmf_if *ifp = netdev_priv(ndev);
   270		struct brcmf_pub *drvr = ifp->drvr;
   271		struct ethhdr *eh;
   272		int head_delta;
   273	
   274		brcmf_dbg(DATA, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx);
   275	
   276		/* Can the device send data? */
   277		if (drvr->bus_if->state != BRCMF_BUS_UP) {
   278			brcmf_err("xmit rejected state=%d\n", drvr->bus_if->state);
   279			netif_stop_queue(ndev);
   280			dev_kfree_skb(skb);
   281			ret = -ENODEV;
   282			goto done;
   283		}
   284	
   285		/* Some recent Broadcom's firmwares disassociate STA when they receive
   286		 * an 802.11f ADD frame. This behavior can lead to a local DoS security
   287		 * issue. Attacker may trigger disassociation of any STA by sending a
   288		 * proper Ethernet frame to the wireless interface.
   289		 *
   290		 * Moreover this feature may break AP interfaces in some specific
   291		 * setups. This applies e.g. to the bridge with hairpin mode enabled and
   292		 * IFLA_BRPORT_MCAST_TO_UCAST set. IAPP packet generated by a firmware
   293		 * will get passed back to the wireless interface and cause immediate
   294		 * disassociation of a just-connected STA.
   295		 */
   296		if (!drvr->settings->iapp && brcmf_skb_is_iapp(skb)) {
   297			dev_kfree_skb(skb);
   298			ret = -EINVAL;
   299			goto done;
   300		}
   301	
   302		/* Make sure there's enough writeable headroom */
   303		if (skb_headroom(skb) < drvr->hdrlen || skb_header_cloned(skb)) {
 > 304			head_delta = max_t(int, drvr->hdrlen - skb_headroom(skb), 0);
   305	
   306			brcmf_dbg(INFO, "%s: insufficient headroom (%d)\n",
   307				  brcmf_ifname(ifp), head_delta);
   308			atomic_inc(&drvr->bus_if->stats.pktcowed);
   309			ret = pskb_expand_head(skb, ALIGN(head_delta, NET_SKB_PAD), 0,
   310					       GFP_ATOMIC);
   311			if (ret < 0) {
   312				brcmf_err("%s: failed to expand headroom\n",
   313					  brcmf_ifname(ifp));
   314				atomic_inc(&drvr->bus_if->stats.pktcow_failed);
   315				goto done;
   316			}
   317		}
   318	
   319		/* validate length for ether packet */
   320		if (skb->len < sizeof(*eh)) {
   321			ret = -EINVAL;
   322			dev_kfree_skb(skb);
   323			goto done;
   324		}
   325	
   326		eh = (struct ethhdr *)(skb->data);
   327	
   328		if (eh->h_proto == htons(ETH_P_PAE))
   329			atomic_inc(&ifp->pend_8021x_cnt);
   330	
   331		/* determine the priority */
   332		if ((skb->priority == 0) || (skb->priority > 7))
   333			skb->priority = cfg80211_classify8021d(skb, NULL);
   334	
   335		ret = brcmf_proto_tx_queue_data(drvr, ifp->ifidx, skb);
   336		if (ret < 0)
   337			brcmf_txfinalize(ifp, skb, false);
   338	
   339	done:
   340		if (ret) {
   341			ndev->stats.tx_dropped++;
   342		} else {
   343			ndev->stats.tx_packets++;
   344			ndev->stats.tx_bytes += skb->len;
   345		}
   346	
   347		/* Return ok: we always eat the packet */
   348		return NETDEV_TX_OK;
   349	}
   350	
   351	void brcmf_txflowblock_if(struct brcmf_if *ifp,
   352				  enum brcmf_netif_stop_reason reason, bool state)
   353	{
   354		unsigned long flags;
   355	
   356		if (!ifp || !ifp->ndev)
   357			return;
   358	
   359		brcmf_dbg(TRACE, "enter: bsscfgidx=%d stop=0x%X reason=%d state=%d\n",
   360			  ifp->bsscfgidx, ifp->netif_stop, reason, state);
   361	
   362		spin_lock_irqsave(&ifp->netif_stop_lock, flags);
   363		if (state) {
   364			if (!ifp->netif_stop)
   365				netif_stop_queue(ifp->ndev);
   366			ifp->netif_stop |= reason;
   367		} else {
   368			ifp->netif_stop &= ~reason;
   369			if (!ifp->netif_stop)
   370				netif_wake_queue(ifp->ndev);
   371		}
   372		spin_unlock_irqrestore(&ifp->netif_stop_lock, flags);
   373	}
   374	
   375	void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
   376	{
   377		/* Most of Broadcom's firmwares send 802.11f ADD frame every time a new
   378		 * STA connects to the AP interface. This is an obsoleted standard most
   379		 * users don't use, so don't pass these frames up unless requested.
   380		 */
   381		if (!ifp->drvr->settings->iapp && brcmf_skb_is_iapp(skb)) {
   382			brcmu_pkt_buf_free_skb(skb);
   383			return;
   384		}
   385	
   386		if (skb->pkt_type == PACKET_MULTICAST)
   387			ifp->ndev->stats.multicast++;
   388	
   389		if (!(ifp->ndev->flags & IFF_UP)) {
   390			brcmu_pkt_buf_free_skb(skb);
   391			return;
   392		}
   393	
   394		ifp->ndev->stats.rx_bytes += skb->len;
   395		ifp->ndev->stats.rx_packets++;
   396	
   397		brcmf_dbg(DATA, "rx proto=0x%X\n", ntohs(skb->protocol));
   398		if (in_interrupt())
   399			netif_rx(skb);
   400		else
   401			/* If the receive is not processed inside an ISR,
   402			 * the softirqd must be woken explicitly to service
   403			 * the NET_RX_SOFTIRQ.  This is handled by netif_rx_ni().
   404			 */
   405			netif_rx_ni(skb);
   406	}
   407	
   408	void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)
   409	{
   410		if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MON_FMT_RADIOTAP)) {
   411			/* Do nothing */
   412		} else {
   413			struct ieee80211_radiotap_header *radiotap;
   414	
   415			radiotap = skb_push(skb, sizeof(*radiotap));
   416			memset(radiotap, 0, sizeof(*radiotap));
 > 417			radiotap->it_len = sizeof(*radiotap);
   418	
   419			/* TODO: what are these extra 4 bytes? */
   420			skb->len -= 4;
   421		}
   422	
   423		skb->dev = ifp->ndev;
   424		skb_reset_mac_header(skb);
   425		skb->pkt_type = PACKET_OTHERHOST;
   426		skb->protocol = htons(ETH_P_802_2);
   427	
   428		brcmf_netif_rx(ifp, skb);
   429	}
   430	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Arend van Spriel May 24, 2018, 6:54 p.m. UTC | #2
On 5/22/2018 3:18 PM, Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
>
> New Broadcom firmwares mark monitor mode packets using a newly defined
> bit in the flags field. Use it to filter them out and pass to the
> monitor interface. These defines were found in bcmmsgbuf.h from SDK.
>
> As not every firmware generates radiotap header this commit introduces
> BRCMF_FEAT_MON_FMT_RADIOTAP that has to be set per firmware version. If
> not present brcmf_netif_mon_rx() assumed packet being a raw 802.11 frame
> and prepends it with an empty radiotap header.
>
> It's limited to the msgbuf protocol. Adding support for SDIO/USB devices
> will require some extra research.

So I went looking on my shelf and found the patch I made for SDIO a 
while back. It relies on firmware change and I did not introduce a 
firmware flag for it. I will send the patch as RFT so you can have a 
look at it.

I checked our internal driver and it turns out the raw vs. radiotap is a 
compilation option. So depending on customer they would get either 
firmware doing the radiotap header generation or the host driver, 
without any run-time way to determine it. Not nice for brcmfmac.

Regards,
Arend

> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
> ---
>   .../wireless/broadcom/brcm80211/brcmfmac/core.c    | 24 ++++++++++++++++++++++
>   .../wireless/broadcom/brcm80211/brcmfmac/core.h    |  2 ++
>   .../wireless/broadcom/brcm80211/brcmfmac/feature.h |  6 +++++-
>   .../wireless/broadcom/brcm80211/brcmfmac/msgbuf.c  | 17 +++++++++++++++
>   4 files changed, 48 insertions(+), 1 deletion(-)
>
Julian Calaby May 27, 2018, 5:34 a.m. UTC | #3
Hi Arend,
On Fri, May 25, 2018 at 12:38 PM Arend van Spriel <
arend.vanspriel@broadcom.com> wrote:

> On 5/22/2018 3:18 PM, Rafał Miłecki wrote:
> > From: Rafał Miłecki <rafal@milecki.pl>
> >
> > New Broadcom firmwares mark monitor mode packets using a newly defined
> > bit in the flags field. Use it to filter them out and pass to the
> > monitor interface. These defines were found in bcmmsgbuf.h from SDK.
> >
> > As not every firmware generates radiotap header this commit introduces
> > BRCMF_FEAT_MON_FMT_RADIOTAP that has to be set per firmware version. If
> > not present brcmf_netif_mon_rx() assumed packet being a raw 802.11 frame
> > and prepends it with an empty radiotap header.
> >
> > It's limited to the msgbuf protocol. Adding support for SDIO/USB devices
> > will require some extra research.

> So I went looking on my shelf and found the patch I made for SDIO a
> while back. It relies on firmware change and I did not introduce a
> firmware flag for it. I will send the patch as RFT so you can have a
> look at it.

> I checked our internal driver and it turns out the raw vs. radiotap is a
> compilation option. So depending on customer they would get either
> firmware doing the radiotap header generation or the host driver,
> without any run-time way to determine it. Not nice for brcmfmac.

I pretty sure I know what the answer to this is going to be, however I
still have to ask:

Is it possible to open up _any_ part of the firmware? (Even if it's just
the host-interface end and the hardware end is a big ugly blob) It'd make
dealing with stuff like this so much easier if we can just toggle a flag
and recompile. (I'm also sure that we'd be more than happy to pass some
flag through telling us/you that it's unofficial firmware and has probably
broken the hardware, etc.)

Thanks,
Arend van Spriel May 30, 2018, 10:05 a.m. UTC | #4
On 5/27/2018 7:34 AM, Julian Calaby wrote:
> Hi Arend,
> On Fri, May 25, 2018 at 12:38 PM Arend van Spriel <
> arend.vanspriel@broadcom.com> wrote:
>
>> On 5/22/2018 3:18 PM, Rafał Miłecki wrote:
>>> From: Rafał Miłecki <rafal@milecki.pl>
>>>
>>> New Broadcom firmwares mark monitor mode packets using a newly defined
>>> bit in the flags field. Use it to filter them out and pass to the
>>> monitor interface. These defines were found in bcmmsgbuf.h from SDK.
>>>
>>> As not every firmware generates radiotap header this commit introduces
>>> BRCMF_FEAT_MON_FMT_RADIOTAP that has to be set per firmware version. If
>>> not present brcmf_netif_mon_rx() assumed packet being a raw 802.11 frame
>>> and prepends it with an empty radiotap header.
>>>
>>> It's limited to the msgbuf protocol. Adding support for SDIO/USB devices
>>> will require some extra research.
>
>> So I went looking on my shelf and found the patch I made for SDIO a
>> while back. It relies on firmware change and I did not introduce a
>> firmware flag for it. I will send the patch as RFT so you can have a
>> look at it.
>
>> I checked our internal driver and it turns out the raw vs. radiotap is a
>> compilation option. So depending on customer they would get either
>> firmware doing the radiotap header generation or the host driver,
>> without any run-time way to determine it. Not nice for brcmfmac.
>
> I pretty sure I know what the answer to this is going to be, however I
> still have to ask:
>
> Is it possible to open up _any_ part of the firmware? (Even if it's just
> the host-interface end and the hardware end is a big ugly blob) It'd make
> dealing with stuff like this so much easier if we can just toggle a flag
> and recompile. (I'm also sure that we'd be more than happy to pass some
> flag through telling us/you that it's unofficial firmware and has probably
> broken the hardware, etc.)

Hah. Yeah, with next to nil uncertainty I know the answer to this as 
well. If you know how long it took before we committed to supporting the 
upstream drivers. Despite my better judgement I will pass your idea, but 
it is not something that is going to fall in the timeframe that Rafał 
had in mind.

Regards,
Arend
Arend van Spriel May 30, 2018, 10:12 a.m. UTC | #5
On 5/22/2018 3:18 PM, Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
>
> New Broadcom firmwares mark monitor mode packets using a newly defined
> bit in the flags field. Use it to filter them out and pass to the
> monitor interface. These defines were found in bcmmsgbuf.h from SDK.
>
> As not every firmware generates radiotap header this commit introduces
> BRCMF_FEAT_MON_FMT_RADIOTAP that has to be set per firmware version. If
> not present brcmf_netif_mon_rx() assumed packet being a raw 802.11 frame
> and prepends it with an empty radiotap header.
>
> It's limited to the msgbuf protocol. Adding support for SDIO/USB devices
> will require some extra research.
>
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
> ---
>   .../wireless/broadcom/brcm80211/brcmfmac/core.c    | 24 ++++++++++++++++++++++
>   .../wireless/broadcom/brcm80211/brcmfmac/core.h    |  2 ++
>   .../wireless/broadcom/brcm80211/brcmfmac/feature.h |  6 +++++-
>   .../wireless/broadcom/brcm80211/brcmfmac/msgbuf.c  | 17 +++++++++++++++
>   4 files changed, 48 insertions(+), 1 deletion(-)
>

[snip]

> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
> index d1193825e559..6e417d104b7f 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
> @@ -33,6 +33,8 @@
>    * MFP: 802.11w Management Frame Protection.
>    * GSCAN: enhanced scan offload feature.
>    * FWSUP: Firmware supplicant.
> + * MON_802_11_FLAG: monitor packets flagged as 802.11
> + * MON_FMT_RADIOTAP: monitor packets include radiotap header

Hi Rafał,

I am preparing the 4366c0 release. Can you tell me which firmwares that 
you have provide 802.11 packets and/or radiotap+802.11? Doing 'strings 
fwfile | tail -1' should give me the necessary info.

Regards,
Arend

>    */
>   #define BRCMF_FEAT_LIST \
>   	BRCMF_FEAT_DEF(MBSS) \
> @@ -48,7 +50,9 @@
>   	BRCMF_FEAT_DEF(WOWL_ARP_ND) \
>   	BRCMF_FEAT_DEF(MFP) \
>   	BRCMF_FEAT_DEF(GSCAN) \
> -	BRCMF_FEAT_DEF(FWSUP)
> +	BRCMF_FEAT_DEF(FWSUP) \
> +	BRCMF_FEAT_DEF(MON_802_11_FLAG) \
> +	BRCMF_FEAT_DEF(MON_FMT_RADIOTAP)
Julian Calaby May 30, 2018, 10:25 a.m. UTC | #6
Hi Arend,

On Wed, May 30, 2018 at 8:05 PM Arend van Spriel <
arend.vanspriel@broadcom.com> wrote:

> On 5/27/2018 7:34 AM, Julian Calaby wrote:
> > Hi Arend,
> > On Fri, May 25, 2018 at 12:38 PM Arend van Spriel <
> > arend.vanspriel@broadcom.com> wrote:
> >
> >> On 5/22/2018 3:18 PM, Rafał Miłecki wrote:
> >>> From: Rafał Miłecki <rafal@milecki.pl>
> >>>
> >>> New Broadcom firmwares mark monitor mode packets using a newly defined
> >>> bit in the flags field. Use it to filter them out and pass to the
> >>> monitor interface. These defines were found in bcmmsgbuf.h from SDK.
> >>>
> >>> As not every firmware generates radiotap header this commit introduces
> >>> BRCMF_FEAT_MON_FMT_RADIOTAP that has to be set per firmware version.
If
> >>> not present brcmf_netif_mon_rx() assumed packet being a raw 802.11
frame
> >>> and prepends it with an empty radiotap header.
> >>>
> >>> It's limited to the msgbuf protocol. Adding support for SDIO/USB
devices
> >>> will require some extra research.
> >
> >> So I went looking on my shelf and found the patch I made for SDIO a
> >> while back. It relies on firmware change and I did not introduce a
> >> firmware flag for it. I will send the patch as RFT so you can have a
> >> look at it.
> >
> >> I checked our internal driver and it turns out the raw vs. radiotap is
a
> >> compilation option. So depending on customer they would get either
> >> firmware doing the radiotap header generation or the host driver,
> >> without any run-time way to determine it. Not nice for brcmfmac.
> >
> > I pretty sure I know what the answer to this is going to be, however I
> > still have to ask:
> >
> > Is it possible to open up _any_ part of the firmware? (Even if it's just
> > the host-interface end and the hardware end is a big ugly blob) It'd
make
> > dealing with stuff like this so much easier if we can just toggle a flag
> > and recompile. (I'm also sure that we'd be more than happy to pass some
> > flag through telling us/you that it's unofficial firmware and has
probably
> > broken the hardware, etc.)

> Hah. Yeah, with next to nil uncertainty I know the answer to this as
> well. If you know how long it took before we committed to supporting the
> upstream drivers. Despite my better judgement I will pass your idea, but
> it is not something that is going to fall in the timeframe that Rafał
> had in mind.

Fair enough, I can't ask for more than that.

Good Luck!
diff mbox

Patch

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index 8d4511eaa9b9..f58d7f7f1359 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -21,6 +21,7 @@ 
 #include <net/cfg80211.h>
 #include <net/rtnetlink.h>
 #include <net/addrconf.h>
+#include <net/ieee80211_radiotap.h>
 #include <net/ipv6.h>
 #include <brcmu_utils.h>
 #include <brcmu_wifi.h>
@@ -404,6 +405,29 @@  void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
 		netif_rx_ni(skb);
 }
 
+void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)
+{
+	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MON_FMT_RADIOTAP)) {
+		/* Do nothing */
+	} else {
+		struct ieee80211_radiotap_header *radiotap;
+
+		radiotap = skb_push(skb, sizeof(*radiotap));
+		memset(radiotap, 0, sizeof(*radiotap));
+		radiotap->it_len = sizeof(*radiotap);
+
+		/* TODO: what are these extra 4 bytes? */
+		skb->len -= 4;
+	}
+
+	skb->dev = ifp->ndev;
+	skb_reset_mac_header(skb);
+	skb->pkt_type = PACKET_OTHERHOST;
+	skb->protocol = htons(ETH_P_802_2);
+
+	brcmf_netif_rx(ifp, skb);
+}
+
 static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb,
 			    struct brcmf_if **ifp)
 {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
index 401f50458686..dcf6e27cc16f 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
@@ -121,6 +121,7 @@  struct brcmf_pub {
 
 	struct brcmf_if *iflist[BRCMF_MAX_IFS];
 	s32 if2bss[BRCMF_MAX_IFS];
+	struct brcmf_if *mon_if;
 
 	struct mutex proto_block;
 	unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
@@ -216,6 +217,7 @@  void brcmf_txflowblock_if(struct brcmf_if *ifp,
 			  enum brcmf_netif_stop_reason reason, bool state);
 void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
 void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
+void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb);
 void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
 int __init brcmf_core_init(void);
 void __exit brcmf_core_exit(void);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
index d1193825e559..6e417d104b7f 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
@@ -33,6 +33,8 @@ 
  * MFP: 802.11w Management Frame Protection.
  * GSCAN: enhanced scan offload feature.
  * FWSUP: Firmware supplicant.
+ * MON_802_11_FLAG: monitor packets flagged as 802.11
+ * MON_FMT_RADIOTAP: monitor packets include radiotap header
  */
 #define BRCMF_FEAT_LIST \
 	BRCMF_FEAT_DEF(MBSS) \
@@ -48,7 +50,9 @@ 
 	BRCMF_FEAT_DEF(WOWL_ARP_ND) \
 	BRCMF_FEAT_DEF(MFP) \
 	BRCMF_FEAT_DEF(GSCAN) \
-	BRCMF_FEAT_DEF(FWSUP)
+	BRCMF_FEAT_DEF(FWSUP) \
+	BRCMF_FEAT_DEF(MON_802_11_FLAG) \
+	BRCMF_FEAT_DEF(MON_FMT_RADIOTAP)
 
 /*
  * Quirks:
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
index 49d37ad96958..47a9318cccb8 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
@@ -69,6 +69,8 @@ 
 #define BRCMF_MSGBUF_MAX_EVENTBUF_POST		8
 
 #define BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_3	0x01
+#define BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_11	0x02
+#define BRCMF_MSGBUF_PKT_FLAGS_FRAME_MASK	0x07
 #define BRCMF_MSGBUF_PKT_FLAGS_PRIO_SHIFT	5
 
 #define BRCMF_MSGBUF_TX_FLUSH_CNT1		32
@@ -1128,6 +1130,7 @@  brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)
 	struct sk_buff *skb;
 	u16 data_offset;
 	u16 buflen;
+	u16 flags;
 	u32 idx;
 	struct brcmf_if *ifp;
 
@@ -1137,6 +1140,7 @@  brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)
 	data_offset = le16_to_cpu(rx_complete->data_offset);
 	buflen = le16_to_cpu(rx_complete->data_len);
 	idx = le32_to_cpu(rx_complete->msg.request_id);
+	flags = le16_to_cpu(rx_complete->flags);
 
 	skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,
 				     msgbuf->rx_pktids, idx);
@@ -1150,6 +1154,19 @@  brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)
 
 	skb_trim(skb, buflen);
 
+	if ((flags & BRCMF_MSGBUF_PKT_FLAGS_FRAME_MASK) ==
+	    BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_11) {
+		ifp = msgbuf->drvr->mon_if;
+
+		if (!ifp) {
+			brcmf_err("Received unexpected monitor pkt\n");
+			brcmu_pkt_buf_free_skb(skb);
+		}
+
+		brcmf_netif_mon_rx(ifp, skb);
+		return;
+	}
+
 	ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx);
 	if (!ifp || !ifp->ndev) {
 		brcmf_err("Received pkt for invalid ifidx %d\n",