From 2802c1786dcf2dffd4d14c32296bd81bfcdaf95e Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 17 Jul 2018 19:44:38 +0000 Subject: [PATCH] TX packets, which can be either Ethernet or control packets, must be sent in order. Otherwise it is possible that the key is set before we send out the EAPOL packet, or that packets are sent out before the key is set. Thus modify the SDIO backend to put both types into the same internal TX queue, which will be sent asynchronously. Discussed with bluhm@ --- sys/dev/ic/bwfm.c | 6 +- sys/dev/ic/bwfmvar.h | 5 +- sys/dev/sdmmc/if_bwfm_sdio.c | 201 +++++++++++++++++++---------------- sys/dev/usb/if_bwfm_usb.c | 96 ++++++++--------- 4 files changed, 158 insertions(+), 150 deletions(-) diff --git a/sys/dev/ic/bwfm.c b/sys/dev/ic/bwfm.c index 27c5307c9f0..1c7f2820241 100644 --- a/sys/dev/ic/bwfm.c +++ b/sys/dev/ic/bwfm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bwfm.c,v 1.52 2018/07/16 13:46:17 patrick Exp $ */ +/* $OpenBSD: bwfm.c,v 1.53 2018/07/17 19:44:38 patrick Exp $ */ /* * Copyright (c) 2010-2016 Broadcom Corporation * Copyright (c) 2016,2017 Patrick Wildt @@ -174,7 +174,6 @@ bwfm_attach(struct bwfm_softc *sc) struct ifnet *ifp = &ic->ic_if; TAILQ_INIT(&sc->sc_bcdc_rxctlq); - TAILQ_INIT(&sc->sc_bcdc_txctlq); /* Init host async commands ring. */ sc->sc_cmdq.cur = sc->sc_cmdq.next = sc->sc_cmdq.queued = 0; @@ -1359,9 +1358,8 @@ bwfm_proto_bcdc_txctl(struct bwfm_softc *sc, int reqid, char *buf, size_t *len) ctl->reqid = reqid; ctl->buf = buf; ctl->len = *len; - TAILQ_INSERT_TAIL(&sc->sc_bcdc_txctlq, ctl, next); - if (sc->sc_bus_ops->bs_txctl(sc)) { + if (sc->sc_bus_ops->bs_txctl(sc, ctl)) { DPRINTF(("%s: tx failed\n", DEVNAME(sc))); return 1; } diff --git a/sys/dev/ic/bwfmvar.h b/sys/dev/ic/bwfmvar.h index 250aba20bc4..7ea91a21a28 100644 --- a/sys/dev/ic/bwfmvar.h +++ b/sys/dev/ic/bwfmvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bwfmvar.h,v 1.14 2018/05/23 11:32:14 patrick Exp $ */ +/* $OpenBSD: bwfmvar.h,v 1.15 2018/07/17 19:44:38 patrick Exp $ */ /* * Copyright (c) 2010-2016 Broadcom Corporation * Copyright (c) 2016,2017 Patrick Wildt @@ -89,7 +89,7 @@ struct bwfm_bus_ops { void (*bs_stop)(struct bwfm_softc *); int (*bs_txcheck)(struct bwfm_softc *); int (*bs_txdata)(struct bwfm_softc *, struct mbuf *); - int (*bs_txctl)(struct bwfm_softc *); + int (*bs_txctl)(struct bwfm_softc *, void *); }; struct bwfm_buscore_ops { @@ -169,7 +169,6 @@ struct bwfm_softc { struct task sc_task; int sc_bcdc_reqid; - TAILQ_HEAD(, bwfm_proto_bcdc_ctl) sc_bcdc_txctlq; TAILQ_HEAD(, bwfm_proto_bcdc_ctl) sc_bcdc_rxctlq; }; diff --git a/sys/dev/sdmmc/if_bwfm_sdio.c b/sys/dev/sdmmc/if_bwfm_sdio.c index 38ac463889c..b55957e4317 100644 --- a/sys/dev/sdmmc/if_bwfm_sdio.c +++ b/sys/dev/sdmmc/if_bwfm_sdio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bwfm_sdio.c,v 1.22 2018/07/16 13:46:17 patrick Exp $ */ +/* $OpenBSD: if_bwfm_sdio.c,v 1.23 2018/07/17 19:44:38 patrick Exp $ */ /* * Copyright (c) 2010-2016 Broadcom Corporation * Copyright (c) 2016,2017 Patrick Wildt @@ -99,7 +99,8 @@ struct bwfm_sdio_softc { uint8_t sc_tx_seq; uint8_t sc_tx_max_seq; - struct mbuf_queue sc_txdata_queue; + struct mbuf_list sc_tx_queue; + int sc_tx_count; struct task sc_task; }; @@ -147,15 +148,16 @@ void bwfm_sdio_buscore_activate(struct bwfm_softc *, uint32_t); struct mbuf * bwfm_sdio_newbuf(void); int bwfm_sdio_tx_ok(struct bwfm_sdio_softc *); -void bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *); -void bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *); +void bwfm_sdio_tx_frames(struct bwfm_sdio_softc *); +void bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *, struct mbuf *); +void bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *, struct mbuf *); void bwfm_sdio_rx_frames(struct bwfm_sdio_softc *); void bwfm_sdio_rx_glom(struct bwfm_sdio_softc *, uint16_t *, int, uint16_t *); int bwfm_sdio_txcheck(struct bwfm_softc *); int bwfm_sdio_txdata(struct bwfm_softc *, struct mbuf *); -int bwfm_sdio_txctl(struct bwfm_softc *); +int bwfm_sdio_txctl(struct bwfm_softc *, void *); #ifdef BWFM_DEBUG void bwfm_sdio_debug_console(struct bwfm_sdio_softc *); @@ -246,7 +248,7 @@ bwfm_sdio_attach(struct device *parent, struct device *self, void *aux) printf("\n"); task_set(&sc->sc_task, bwfm_sdio_task, sc); - mq_init(&sc->sc_txdata_queue, 16, IPL_SOFTNET); + ml_init(&sc->sc_tx_queue); sc->sc_bounce_size = 64 * 1024; sc->sc_bounce_buf = dma_alloc(sc->sc_bounce_size, PR_WAITOK); sc->sc_tx_seq = 0xff; @@ -684,12 +686,8 @@ bwfm_sdio_task(void *v) bwfm_sdio_rx_frames(sc); } - if (!TAILQ_EMPTY(&sc->sc_sc.sc_bcdc_txctlq)) { - bwfm_sdio_tx_ctrlframe(sc); - } - - if (!mq_empty(&sc->sc_txdata_queue)) { - bwfm_sdio_tx_dataframe(sc); + if (!ml_empty(&sc->sc_tx_queue)) { + bwfm_sdio_tx_frames(sc); } #ifdef BWFM_DEBUG @@ -1034,115 +1032,117 @@ bwfm_sdio_tx_ok(struct bwfm_sdio_softc *sc) } void -bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *sc) +bwfm_sdio_tx_frames(struct bwfm_sdio_softc *sc) { - struct bwfm_sdio_hwhdr *hwhdr; - struct bwfm_sdio_swhdr *swhdr; - struct bwfm_proto_bcdc_ctl *ctl, *tmp; - size_t len, roundto; + struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if; + struct mbuf *m; + int i; if (!bwfm_sdio_tx_ok(sc)) return; - TAILQ_FOREACH_SAFE(ctl, &sc->sc_sc.sc_bcdc_txctlq, next, tmp) { - TAILQ_REMOVE(&sc->sc_sc.sc_bcdc_txctlq, ctl, next); - - len = sizeof(*hwhdr) + sizeof(*swhdr) + ctl->len; + i = min((uint8_t)(sc->sc_tx_max_seq - sc->sc_tx_seq), 32); + while (i--) { + m = ml_dequeue(&sc->sc_tx_queue); + if (m == NULL) + break; - /* Zero-pad to either block-size or 4-byte alignment. */ - if (len > 512 && (len % 512) != 0) - roundto = 512; + if (m->m_type == MT_CONTROL) + bwfm_sdio_tx_ctrlframe(sc, m); else - roundto = 4; + bwfm_sdio_tx_dataframe(sc, m); - KASSERT(roundup(len, roundto) <= sc->sc_bounce_size); + m_freem(m); + } + + if (sc->sc_tx_count < 64) + ifq_restart(&ifp->if_snd); +} - hwhdr = (void *)sc->sc_bounce_buf; - hwhdr->frmlen = htole16(len); - hwhdr->cksum = htole16(~len); +void +bwfm_sdio_tx_ctrlframe(struct bwfm_sdio_softc *sc, struct mbuf *m) +{ + struct bwfm_sdio_hwhdr *hwhdr; + struct bwfm_sdio_swhdr *swhdr; + size_t len, roundto; - swhdr = (void *)&hwhdr[1]; - swhdr->seqnr = sc->sc_tx_seq++; - swhdr->chanflag = BWFM_SDIO_SWHDR_CHANNEL_CONTROL; - swhdr->nextlen = 0; - swhdr->dataoff = sizeof(*hwhdr) + sizeof(*swhdr); - swhdr->maxseqnr = 0; + len = sizeof(*hwhdr) + sizeof(*swhdr) + m->m_len; - memcpy(&swhdr[1], ctl->buf, ctl->len); + /* Zero-pad to either block-size or 4-byte alignment. */ + if (len > 512 && (len % 512) != 0) + roundto = 512; + else + roundto = 4; - if (roundup(len, roundto) != len) - memset(sc->sc_bounce_buf + len, 0, - roundup(len, roundto) - len); + KASSERT(roundup(len, roundto) <= sc->sc_bounce_size); - bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf, - roundup(len, roundto), 1); + hwhdr = (void *)sc->sc_bounce_buf; + hwhdr->frmlen = htole16(len); + hwhdr->cksum = htole16(~len); - TAILQ_INSERT_TAIL(&sc->sc_sc.sc_bcdc_rxctlq, ctl, next); - } + swhdr = (void *)&hwhdr[1]; + swhdr->seqnr = sc->sc_tx_seq++; + swhdr->chanflag = BWFM_SDIO_SWHDR_CHANNEL_CONTROL; + swhdr->nextlen = 0; + swhdr->dataoff = sizeof(*hwhdr) + sizeof(*swhdr); + swhdr->maxseqnr = 0; + + m_copydata(m, 0, m->m_len, (caddr_t)&swhdr[1]); + + if (roundup(len, roundto) != len) + memset(sc->sc_bounce_buf + len, 0, + roundup(len, roundto) - len); + + bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf, + roundup(len, roundto), 1); } void -bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *sc) +bwfm_sdio_tx_dataframe(struct bwfm_sdio_softc *sc, struct mbuf *m) { - struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if; struct bwfm_sdio_hwhdr *hwhdr; struct bwfm_sdio_swhdr *swhdr; struct bwfm_proto_bcdc_hdr *bcdc; size_t len, roundto; - struct mbuf *m; - int i; - if (!bwfm_sdio_tx_ok(sc)) - return; - - i = min((uint8_t)(sc->sc_tx_max_seq - sc->sc_tx_seq), 32); - while (i--) { - m = mq_dequeue(&sc->sc_txdata_queue); - if (m == NULL) - break; + len = sizeof(*hwhdr) + sizeof(*swhdr) + sizeof(*bcdc) + + m->m_pkthdr.len; - len = sizeof(*hwhdr) + sizeof(*swhdr) + sizeof(*bcdc) - + m->m_pkthdr.len; - - /* Zero-pad to either block-size or 4-byte alignment. */ - if (len > 512 && (len % 512) != 0) - roundto = 512; - else - roundto = 4; - - KASSERT(roundup(len, roundto) <= sc->sc_bounce_size); + /* Zero-pad to either block-size or 4-byte alignment. */ + if (len > 512 && (len % 512) != 0) + roundto = 512; + else + roundto = 4; - hwhdr = (void *)sc->sc_bounce_buf; - hwhdr->frmlen = htole16(len); - hwhdr->cksum = htole16(~len); + KASSERT(roundup(len, roundto) <= sc->sc_bounce_size); - swhdr = (void *)&hwhdr[1]; - swhdr->seqnr = sc->sc_tx_seq++; - swhdr->chanflag = BWFM_SDIO_SWHDR_CHANNEL_DATA; - swhdr->nextlen = 0; - swhdr->dataoff = sizeof(*hwhdr) + sizeof(*swhdr); - swhdr->maxseqnr = 0; + hwhdr = (void *)sc->sc_bounce_buf; + hwhdr->frmlen = htole16(len); + hwhdr->cksum = htole16(~len); - bcdc = (void *)&swhdr[1]; - bcdc->data_offset = 0; - bcdc->priority = ieee80211_classify(&sc->sc_sc.sc_ic, m); - bcdc->flags = BWFM_BCDC_FLAG_VER(BWFM_BCDC_FLAG_PROTO_VER); - bcdc->flags2 = 0; + swhdr = (void *)&hwhdr[1]; + swhdr->seqnr = sc->sc_tx_seq++; + swhdr->chanflag = BWFM_SDIO_SWHDR_CHANNEL_DATA; + swhdr->nextlen = 0; + swhdr->dataoff = sizeof(*hwhdr) + sizeof(*swhdr); + swhdr->maxseqnr = 0; - m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&bcdc[1]); + bcdc = (void *)&swhdr[1]; + bcdc->data_offset = 0; + bcdc->priority = ieee80211_classify(&sc->sc_sc.sc_ic, m); + bcdc->flags = BWFM_BCDC_FLAG_VER(BWFM_BCDC_FLAG_PROTO_VER); + bcdc->flags2 = 0; - if (roundup(len, roundto) != len) - memset(sc->sc_bounce_buf + len, 0, - roundup(len, roundto) - len); + m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&bcdc[1]); - bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf, - roundup(len, roundto), 1); + if (roundup(len, roundto) != len) + memset(sc->sc_bounce_buf + len, 0, + roundup(len, roundto) - len); - m_freem(m); - } + bwfm_sdio_frame_read_write(sc, sc->sc_bounce_buf, + roundup(len, roundto), 1); - if (!mq_full(&sc->sc_txdata_queue)) - ifq_restart(&ifp->if_snd); + sc->sc_tx_count--; } void @@ -1372,7 +1372,7 @@ bwfm_sdio_txcheck(struct bwfm_softc *bwfm) { struct bwfm_sdio_softc *sc = (void *)bwfm; - if (mq_full(&sc->sc_txdata_queue)) + if (sc->sc_tx_count >= 64) return ENOBUFS; return 0; @@ -1383,18 +1383,33 @@ bwfm_sdio_txdata(struct bwfm_softc *bwfm, struct mbuf *m) { struct bwfm_sdio_softc *sc = (void *)bwfm; - if (mq_full(&sc->sc_txdata_queue)) + if (sc->sc_tx_count >= 64) return ENOBUFS; - mq_enqueue(&sc->sc_txdata_queue, m); + sc->sc_tx_count++; + ml_enqueue(&sc->sc_tx_queue, m); task_add(systq, &sc->sc_task); return 0; } int -bwfm_sdio_txctl(struct bwfm_softc *bwfm) +bwfm_sdio_txctl(struct bwfm_softc *bwfm, void *arg) { struct bwfm_sdio_softc *sc = (void *)bwfm; + struct bwfm_proto_bcdc_ctl *ctl = arg; + struct mbuf *m; + + MGET(m, M_DONTWAIT, MT_CONTROL); + if (m == NULL || M_TRAILINGSPACE(m) < ctl->len) { + free(ctl->buf, M_TEMP, ctl->len); + free(ctl, M_TEMP, sizeof(*ctl)); + return 1; + } + memcpy(mtod(m, char *), ctl->buf, ctl->len); + m->m_len = ctl->len; + + TAILQ_INSERT_TAIL(&sc->sc_sc.sc_bcdc_rxctlq, ctl, next); + ml_enqueue(&sc->sc_tx_queue, m); task_add(systq, &sc->sc_task); return 0; } diff --git a/sys/dev/usb/if_bwfm_usb.c b/sys/dev/usb/if_bwfm_usb.c index 505bb91cc9d..148de48ef91 100644 --- a/sys/dev/usb/if_bwfm_usb.c +++ b/sys/dev/usb/if_bwfm_usb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bwfm_usb.c,v 1.15 2018/05/23 14:15:06 patrick Exp $ */ +/* $OpenBSD: if_bwfm_usb.c,v 1.16 2018/07/17 19:44:38 patrick Exp $ */ /* * Copyright (c) 2010-2016 Broadcom Corporation * Copyright (c) 2016,2017 Patrick Wildt @@ -201,7 +201,7 @@ void bwfm_usb_free_tx_list(struct bwfm_usb_softc *); int bwfm_usb_preinit(struct bwfm_softc *); int bwfm_usb_txcheck(struct bwfm_softc *); int bwfm_usb_txdata(struct bwfm_softc *, struct mbuf *); -int bwfm_usb_txctl(struct bwfm_softc *); +int bwfm_usb_txctl(struct bwfm_softc *, void *); void bwfm_usb_txctl_cb(struct usbd_xfer *, void *, usbd_status); struct mbuf * bwfm_usb_newbuf(void); @@ -801,10 +801,10 @@ bwfm_usb_txdata(struct bwfm_softc *bwfm, struct mbuf *m) } int -bwfm_usb_txctl(struct bwfm_softc *bwfm) +bwfm_usb_txctl(struct bwfm_softc *bwfm, void *arg) { struct bwfm_usb_softc *sc = (void *)bwfm; - struct bwfm_proto_bcdc_ctl *ctl, *tmp; + struct bwfm_proto_bcdc_ctl *ctl = arg; usb_device_request_t req; struct usbd_xfer *xfer; usbd_status error; @@ -812,58 +812,54 @@ bwfm_usb_txctl(struct bwfm_softc *bwfm) DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); - TAILQ_FOREACH_SAFE(ctl, &sc->sc_sc.sc_bcdc_txctlq, next, tmp) { - TAILQ_REMOVE(&sc->sc_sc.sc_bcdc_txctlq, ctl, next); - - /* Send out control packet. */ - req.bmRequestType = UT_WRITE_CLASS_INTERFACE; - req.bRequest = 0; - USETW(req.wValue, 0); - USETW(req.wIndex, sc->sc_ifaceno); - USETW(req.wLength, ctl->len); - - error = usbd_do_request(sc->sc_udev, &req, ctl->buf); - if (error != 0) { - printf("%s: could not write ctl packet: %s\n", - DEVNAME(sc), usbd_errstr(error)); - free(ctl->buf, M_TEMP, ctl->len); - free(ctl, M_TEMP, sizeof(*ctl)); - return 1; - } + /* Send out control packet. */ + req.bmRequestType = UT_WRITE_CLASS_INTERFACE; + req.bRequest = 0; + USETW(req.wValue, 0); + USETW(req.wIndex, sc->sc_ifaceno); + USETW(req.wLength, ctl->len); - /* Setup asynchronous receive. */ - if ((xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL) { - free(ctl->buf, M_TEMP, ctl->len); - free(ctl, M_TEMP, sizeof(*ctl)); - return 1; - } - if ((buf = usbd_alloc_buffer(xfer, ctl->len)) == NULL) { - free(ctl->buf, M_TEMP, ctl->len); - free(ctl, M_TEMP, sizeof(*ctl)); - usbd_free_xfer(xfer); - return 1; - } + error = usbd_do_request(sc->sc_udev, &req, ctl->buf); + if (error != 0) { + printf("%s: could not write ctl packet: %s\n", + DEVNAME(sc), usbd_errstr(error)); + free(ctl->buf, M_TEMP, ctl->len); + free(ctl, M_TEMP, sizeof(*ctl)); + return 1; + } - memset(buf, 0, ctl->len); - req.bmRequestType = UT_READ_CLASS_INTERFACE; - req.bRequest = 1; - USETW(req.wValue, 0); - USETW(req.wIndex, sc->sc_ifaceno); - USETW(req.wLength, ctl->len); + /* Setup asynchronous receive. */ + if ((xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL) { + free(ctl->buf, M_TEMP, ctl->len); + free(ctl, M_TEMP, sizeof(*ctl)); + return 1; + } + if ((buf = usbd_alloc_buffer(xfer, ctl->len)) == NULL) { + free(ctl->buf, M_TEMP, ctl->len); + free(ctl, M_TEMP, sizeof(*ctl)); + usbd_free_xfer(xfer); + return 1; + } - error = usbd_request_async(xfer, &req, sc, bwfm_usb_txctl_cb); - if (error != 0) { - printf("%s: could not read ctl packet: %s\n", - DEVNAME(sc), usbd_errstr(error)); - free(ctl->buf, M_TEMP, ctl->len); - free(ctl, M_TEMP, sizeof(*ctl)); - usbd_free_xfer(xfer); - return 1; - } + memset(buf, 0, ctl->len); + req.bmRequestType = UT_READ_CLASS_INTERFACE; + req.bRequest = 1; + USETW(req.wValue, 0); + USETW(req.wIndex, sc->sc_ifaceno); + USETW(req.wLength, ctl->len); - TAILQ_INSERT_TAIL(&sc->sc_sc.sc_bcdc_rxctlq, ctl, next); + error = usbd_request_async(xfer, &req, sc, bwfm_usb_txctl_cb); + if (error != 0) { + printf("%s: could not read ctl packet: %s\n", + DEVNAME(sc), usbd_errstr(error)); + free(ctl->buf, M_TEMP, ctl->len); + free(ctl, M_TEMP, sizeof(*ctl)); + usbd_free_xfer(xfer); + return 1; } + TAILQ_INSERT_TAIL(&sc->sc_sc.sc_bcdc_rxctlq, ctl, next); + return 0; } -- 2.20.1