TX packets, which can be either Ethernet or control packets, must be
authorpatrick <patrick@openbsd.org>
Tue, 17 Jul 2018 19:44:38 +0000 (19:44 +0000)
committerpatrick <patrick@openbsd.org>
Tue, 17 Jul 2018 19:44:38 +0000 (19:44 +0000)
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
sys/dev/ic/bwfmvar.h
sys/dev/sdmmc/if_bwfm_sdio.c
sys/dev/usb/if_bwfm_usb.c

index 27c5307..1c7f282 100644 (file)
@@ -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 <patrick@blueri.se>
@@ -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;
        }
index 250aba2..7ea91a2 100644 (file)
@@ -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 <patrick@blueri.se>
@@ -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;
 };
 
index 38ac463..b55957e 100644 (file)
@@ -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 <patrick@blueri.se>
@@ -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;
 }
index 505bb91..148de48 100644 (file)
@@ -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 <patrick@blueri.se>
@@ -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;
 }