a7e6af0f20b54fdf117ccf8e9a4ff291e0e1ef00
[oweals/openwrt.git] /
1 From a8d7631858aff156b72f807ee7cc062048e63836 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
3 Date: Sun, 24 Jun 2018 21:44:37 +0200
4 Subject: [PATCH] brcmfmac: handle msgbuf packets marked with monitor mode flag
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 New Broadcom firmwares mark monitor mode packets using a newly defined
10 bit in the flags field. Use it to filter them out and pass to the
11 monitor interface. These defines were found in bcmmsgbuf.h from SDK.
12
13 As not every firmware generates radiotap header this commit introduces
14 BRCMF_FEAT_MONITOR_FMT_RADIOTAP flag. It has to be has based on firmware
15 capabilities. If not present brcmf_netif_mon_rx() will assume packet is
16 a raw 802.11 frame and will prepend it with an empty radiotap header.
17
18 This new code is limited to the msgbuf protocol at this point. Adding
19 support for SDIO/USB devices will require some extra work (possibly a
20 new firmware release).
21
22 Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
23 Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
24 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
25 ---
26  .../wireless/broadcom/brcm80211/brcmfmac/core.c    | 25 ++++++++++++++++++++++
27  .../wireless/broadcom/brcm80211/brcmfmac/core.h    |  2 ++
28  .../wireless/broadcom/brcm80211/brcmfmac/msgbuf.c  | 18 ++++++++++++++++
29  3 files changed, 45 insertions(+)
30
31 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
32 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
33 @@ -21,6 +21,7 @@
34  #include <net/cfg80211.h>
35  #include <net/rtnetlink.h>
36  #include <net/addrconf.h>
37 +#include <net/ieee80211_radiotap.h>
38  #include <net/ipv6.h>
39  #include <brcmu_utils.h>
40  #include <brcmu_wifi.h>
41 @@ -367,6 +368,34 @@ void brcmf_netif_rx(struct brcmf_if *ifp
42                 netif_rx_ni(skb);
43  }
44  
45 +void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)
46 +{
47 +       if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MONITOR_FMT_RADIOTAP)) {
48 +               /* Do nothing */
49 +       } else {
50 +               struct ieee80211_radiotap_header *radiotap;
51 +
52 +               /* TODO: use RX status to fill some radiotap data */
53 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
54 +               radiotap = skb_push(skb, sizeof(*radiotap));
55 +#else
56 +               radiotap = (struct ieee80211_radiotap_header *)skb_push(skb, sizeof(*radiotap));
57 +#endif
58 +               memset(radiotap, 0, sizeof(*radiotap));
59 +               radiotap->it_len = cpu_to_le16(sizeof(*radiotap));
60 +
61 +               /* TODO: 4 bytes with receive status? */
62 +               skb->len -= 4;
63 +       }
64 +
65 +       skb->dev = ifp->ndev;
66 +       skb_reset_mac_header(skb);
67 +       skb->pkt_type = PACKET_OTHERHOST;
68 +       skb->protocol = htons(ETH_P_802_2);
69 +
70 +       brcmf_netif_rx(ifp, skb);
71 +}
72 +
73  static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb,
74                             struct brcmf_if **ifp)
75  {
76 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
77 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
78 @@ -122,6 +122,7 @@ struct brcmf_pub {
79  
80         struct brcmf_if *iflist[BRCMF_MAX_IFS];
81         s32 if2bss[BRCMF_MAX_IFS];
82 +       struct brcmf_if *mon_if;
83  
84         struct mutex proto_block;
85         unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
86 @@ -219,6 +220,7 @@ void brcmf_txflowblock_if(struct brcmf_i
87                           enum brcmf_netif_stop_reason reason, bool state);
88  void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
89  void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
90 +void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb);
91  void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
92  int __init brcmf_core_init(void);
93  void __exit brcmf_core_exit(void);
94 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
95 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
96 @@ -69,6 +69,8 @@
97  #define BRCMF_MSGBUF_MAX_EVENTBUF_POST         8
98  
99  #define BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_3     0x01
100 +#define BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_11    0x02
101 +#define BRCMF_MSGBUF_PKT_FLAGS_FRAME_MASK      0x07
102  #define BRCMF_MSGBUF_PKT_FLAGS_PRIO_SHIFT      5
103  
104  #define BRCMF_MSGBUF_TX_FLUSH_CNT1             32
105 @@ -1126,6 +1128,7 @@ brcmf_msgbuf_process_rx_complete(struct
106         struct sk_buff *skb;
107         u16 data_offset;
108         u16 buflen;
109 +       u16 flags;
110         u32 idx;
111         struct brcmf_if *ifp;
112  
113 @@ -1135,6 +1138,7 @@ brcmf_msgbuf_process_rx_complete(struct
114         data_offset = le16_to_cpu(rx_complete->data_offset);
115         buflen = le16_to_cpu(rx_complete->data_len);
116         idx = le32_to_cpu(rx_complete->msg.request_id);
117 +       flags = le16_to_cpu(rx_complete->flags);
118  
119         skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,
120                                      msgbuf->rx_pktids, idx);
121 @@ -1148,6 +1152,20 @@ brcmf_msgbuf_process_rx_complete(struct
122  
123         skb_trim(skb, buflen);
124  
125 +       if ((flags & BRCMF_MSGBUF_PKT_FLAGS_FRAME_MASK) ==
126 +           BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_11) {
127 +               ifp = msgbuf->drvr->mon_if;
128 +
129 +               if (!ifp) {
130 +                       brcmf_err("Received unexpected monitor pkt\n");
131 +                       brcmu_pkt_buf_free_skb(skb);
132 +                       return;
133 +               }
134 +
135 +               brcmf_netif_mon_rx(ifp, skb);
136 +               return;
137 +       }
138 +
139         ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx);
140         if (!ifp || !ifp->ndev) {
141                 brcmf_err("Received pkt for invalid ifidx %d\n",