Skip to content

Commit c56caa9

Browse files
zflamKalle Valo
authored andcommitted
brcmfmac: screening firmware event packet
Firmware uses asynchronized events as a communication method to the host. The event packets are marked as ETH_P_LINK_CTL protocol type. For SDIO and PCIe bus, this kind of packets are delivered through virtual event channel not data channel. This patch adds a screening logic to make sure the event handler only processes the events coming from the correct channel. Reviewed-by: Pieter-Paul Giesberts <[email protected]> Signed-off-by: Franky Lin <[email protected]> Signed-off-by: Arend van Spriel <[email protected]> Signed-off-by: Kalle Valo <[email protected]>
1 parent 2aec2c9 commit c56caa9

File tree

6 files changed

+90
-39
lines changed

6 files changed

+90
-39
lines changed

drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,9 @@ bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt,
216216
int prec);
217217

218218
/* Receive frame for delivery to OS. Callee disposes of rxp. */
219-
void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
219+
void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_evnt);
220+
/* Receive async event packet from firmware. Callee disposes of rxp. */
221+
void brcmf_rx_event(struct device *dev, struct sk_buff *rxp);
220222

221223
/* Indication from bus module regarding presence/insertion of dongle. */
222224
int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings);

drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -311,16 +311,17 @@ void brcmf_txflowblock(struct device *dev, bool state)
311311
brcmf_fws_bus_blocked(drvr, state);
312312
}
313313

314-
void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
314+
void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb,
315+
bool handle_event)
315316
{
316-
skb->dev = ifp->ndev;
317-
skb->protocol = eth_type_trans(skb, skb->dev);
317+
skb->protocol = eth_type_trans(skb, ifp->ndev);
318318

319319
if (skb->pkt_type == PACKET_MULTICAST)
320320
ifp->stats.multicast++;
321321

322322
/* Process special event packets */
323-
brcmf_fweh_process_skb(ifp->drvr, skb);
323+
if (handle_event)
324+
brcmf_fweh_process_skb(ifp->drvr, skb);
324325

325326
if (!(ifp->ndev->flags & IFF_UP)) {
326327
brcmu_pkt_buf_free_skb(skb);
@@ -381,7 +382,7 @@ static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data,
381382
/* validate flags and flow id */
382383
if (flags == 0xFF) {
383384
brcmf_err("invalid flags...so ignore this packet\n");
384-
brcmf_netif_rx(ifp, pkt);
385+
brcmf_netif_rx(ifp, pkt, false);
385386
return;
386387
}
387388

@@ -393,7 +394,7 @@ static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data,
393394
if (rfi == NULL) {
394395
brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
395396
flow_id);
396-
brcmf_netif_rx(ifp, pkt);
397+
brcmf_netif_rx(ifp, pkt, false);
397398
return;
398399
}
399400

@@ -418,7 +419,7 @@ static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data,
418419
rfi = kzalloc(buf_size, GFP_ATOMIC);
419420
if (rfi == NULL) {
420421
brcmf_err("failed to alloc buffer\n");
421-
brcmf_netif_rx(ifp, pkt);
422+
brcmf_netif_rx(ifp, pkt, false);
422423
return;
423424
}
424425

@@ -532,11 +533,11 @@ static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data,
532533
netif_rx:
533534
skb_queue_walk_safe(&reorder_list, pkt, pnext) {
534535
__skb_unlink(pkt, &reorder_list);
535-
brcmf_netif_rx(ifp, pkt);
536+
brcmf_netif_rx(ifp, pkt, false);
536537
}
537538
}
538539

539-
void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)
540+
void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_evnt)
540541
{
541542
struct brcmf_if *ifp;
542543
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
@@ -560,7 +561,32 @@ void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)
560561
if (rd->reorder)
561562
brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
562563
else
563-
brcmf_netif_rx(ifp, skb);
564+
brcmf_netif_rx(ifp, skb, handle_evnt);
565+
}
566+
567+
void brcmf_rx_event(struct device *dev, struct sk_buff *skb)
568+
{
569+
struct brcmf_if *ifp;
570+
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
571+
struct brcmf_pub *drvr = bus_if->drvr;
572+
int ret;
573+
574+
brcmf_dbg(EVENT, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
575+
576+
/* process and remove protocol-specific header */
577+
ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp);
578+
579+
if (ret || !ifp || !ifp->ndev) {
580+
if (ret != -ENODATA && ifp)
581+
ifp->stats.rx_errors++;
582+
brcmu_pkt_buf_free_skb(skb);
583+
return;
584+
}
585+
586+
skb->protocol = eth_type_trans(skb, ifp->ndev);
587+
588+
brcmf_fweh_process_skb(ifp->drvr, skb);
589+
brcmu_pkt_buf_free_skb(skb);
564590
}
565591

566592
void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)

drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,8 @@ int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr);
225225
void brcmf_txflowblock_if(struct brcmf_if *ifp,
226226
enum brcmf_netif_stop_reason reason, bool state);
227227
void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
228-
void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
228+
void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb,
229+
bool handle_event);
229230
void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
230231
int __init brcmf_core_init(void);
231232
void __exit brcmf_core_exit(void);

drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include <linux/types.h>
2222
#include <linux/netdevice.h>
23+
#include <linux/etherdevice.h>
2324

2425
#include <brcmu_utils.h>
2526
#include <brcmu_wifi.h>
@@ -1075,28 +1076,13 @@ static void brcmf_msgbuf_rxbuf_event_post(struct brcmf_msgbuf *msgbuf)
10751076
}
10761077

10771078

1078-
static void
1079-
brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb,
1080-
u8 ifidx)
1081-
{
1082-
struct brcmf_if *ifp;
1083-
1084-
ifp = brcmf_get_ifp(msgbuf->drvr, ifidx);
1085-
if (!ifp || !ifp->ndev) {
1086-
brcmf_err("Received pkt for invalid ifidx %d\n", ifidx);
1087-
brcmu_pkt_buf_free_skb(skb);
1088-
return;
1089-
}
1090-
brcmf_netif_rx(ifp, skb);
1091-
}
1092-
1093-
10941079
static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf)
10951080
{
10961081
struct msgbuf_rx_event *event;
10971082
u32 idx;
10981083
u16 buflen;
10991084
struct sk_buff *skb;
1085+
struct brcmf_if *ifp;
11001086

11011087
event = (struct msgbuf_rx_event *)buf;
11021088
idx = le32_to_cpu(event->msg.request_id);
@@ -1116,7 +1102,19 @@ static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf)
11161102

11171103
skb_trim(skb, buflen);
11181104

1119-
brcmf_msgbuf_rx_skb(msgbuf, skb, event->msg.ifidx);
1105+
ifp = brcmf_get_ifp(msgbuf->drvr, event->msg.ifidx);
1106+
if (!ifp || !ifp->ndev) {
1107+
brcmf_err("Received pkt for invalid ifidx %d\n",
1108+
event->msg.ifidx);
1109+
goto exit;
1110+
}
1111+
1112+
skb->protocol = eth_type_trans(skb, ifp->ndev);
1113+
1114+
brcmf_fweh_process_skb(ifp->drvr, skb);
1115+
1116+
exit:
1117+
brcmu_pkt_buf_free_skb(skb);
11201118
}
11211119

11221120

@@ -1128,6 +1126,7 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)
11281126
u16 data_offset;
11291127
u16 buflen;
11301128
u32 idx;
1129+
struct brcmf_if *ifp;
11311130

11321131
brcmf_msgbuf_update_rxbufpost_count(msgbuf, 1);
11331132

@@ -1148,7 +1147,14 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)
11481147

11491148
skb_trim(skb, buflen);
11501149

1151-
brcmf_msgbuf_rx_skb(msgbuf, skb, rx_complete->msg.ifidx);
1150+
ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx);
1151+
if (!ifp || !ifp->ndev) {
1152+
brcmf_err("Received pkt for invalid ifidx %d\n",
1153+
rx_complete->msg.ifidx);
1154+
brcmu_pkt_buf_free_skb(skb);
1155+
return;
1156+
}
1157+
brcmf_netif_rx(ifp, skb, false);
11521158
}
11531159

11541160

drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,17 @@ static inline u8 brcmf_sdio_getdatoffset(u8 *swheader)
12941294
return (u8)((hdrvalue & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT);
12951295
}
12961296

1297+
static inline bool brcmf_sdio_fromevntchan(u8 *swheader)
1298+
{
1299+
u32 hdrvalue;
1300+
u8 ret;
1301+
1302+
hdrvalue = *(u32 *)swheader;
1303+
ret = (u8)((hdrvalue & SDPCM_CHANNEL_MASK) >> SDPCM_CHANNEL_SHIFT);
1304+
1305+
return (ret == SDPCM_EVENT_CHANNEL);
1306+
}
1307+
12971308
static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
12981309
struct brcmf_sdio_hdrinfo *rd,
12991310
enum brcmf_sdio_frmtype type)
@@ -1641,7 +1652,11 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
16411652
pfirst->len, pfirst->next,
16421653
pfirst->prev);
16431654
skb_unlink(pfirst, &bus->glom);
1644-
brcmf_rx_frame(bus->sdiodev->dev, pfirst);
1655+
if (brcmf_sdio_fromevntchan(pfirst->data))
1656+
brcmf_rx_event(bus->sdiodev->dev, pfirst);
1657+
else
1658+
brcmf_rx_frame(bus->sdiodev->dev, pfirst,
1659+
false);
16451660
bus->sdcnt.rxglompkts++;
16461661
}
16471662

@@ -1967,18 +1982,19 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
19671982
__skb_trim(pkt, rd->len);
19681983
skb_pull(pkt, rd->dat_offset);
19691984

1985+
if (pkt->len == 0)
1986+
brcmu_pkt_buf_free_skb(pkt);
1987+
else if (rd->channel == SDPCM_EVENT_CHANNEL)
1988+
brcmf_rx_event(bus->sdiodev->dev, pkt);
1989+
else
1990+
brcmf_rx_frame(bus->sdiodev->dev, pkt,
1991+
false);
1992+
19701993
/* prepare the descriptor for the next read */
19711994
rd->len = rd->len_nxtfrm << 4;
19721995
rd->len_nxtfrm = 0;
19731996
/* treat all packet as event if we don't know */
19741997
rd->channel = SDPCM_EVENT_CHANNEL;
1975-
1976-
if (pkt->len == 0) {
1977-
brcmu_pkt_buf_free_skb(pkt);
1978-
continue;
1979-
}
1980-
1981-
brcmf_rx_frame(bus->sdiodev->dev, pkt);
19821998
}
19831999

19842000
rxcount = maxframes - rxleft;

drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
514514

515515
if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
516516
skb_put(skb, urb->actual_length);
517-
brcmf_rx_frame(devinfo->dev, skb);
517+
brcmf_rx_frame(devinfo->dev, skb, true);
518518
brcmf_usb_rx_refill(devinfo, req);
519519
} else {
520520
brcmu_pkt_buf_free_skb(skb);

0 commit comments

Comments
 (0)