DF-0533 / fix.diff
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | diff --git a/sys/netgraph7/bluetooth/drivers/bt3c/ng_bt3c_var.h b/sys/netgraph7/bluetooth/drivers/bt3c/ng_bt3c_var.h --- a/sys/netgraph7/bluetooth/drivers/bt3c/ng_bt3c_var.h +++ b/sys/netgraph7/bluetooth/drivers/bt3c/ng_bt3c_var.h @@ -92,6 +92,15 @@ u_int32_t status; /* from ISR */ void *ith; /* ithread handler */ + /* + * Serializes inq/outq mutation between the hard ISR (bt3c_intr -> + * bt3c_receive: IF_ENQUEUE) and the SWI/netgraph paths (bt3c_forward, + * bt3c_send, bt3c_rcvdata: IF_DEQUEUE/IF_ENQUEUE). IF_*QUEUE macros + * are lock-free linked-list ops, so without this the hard ISR can + * corrupt the list mid-IF_DEQUEUE. (DF-0533) + */ + struct spinlock sc_lock; + struct mbuf *m; /* current frame */ u_int32_t want; /* # of chars we want */ diff --git a/sys/netgraph7/bluetooth/drivers/bt3c/ng_bt3c_pccard.c b/sys/netgraph7/bluetooth/drivers/bt3c/ng_bt3c_pccard.c --- a/sys/netgraph7/bluetooth/drivers/bt3c/ng_bt3c_pccard.c +++ b/sys/netgraph7/bluetooth/drivers/bt3c/ng_bt3c_pccard.c @@ -53,6 +53,7 @@ #include <sys/module.h> #include <sys/rman.h> +#include <sys/spinlock.h> #include <sys/socket.h> #include <net/if.h> @@ -554,6 +555,7 @@ NGI_GET_M(item, m); + spin_lock(&sc->sc_lock); if (IF_QFULL(&sc->outq)) { NG_BT3C_ERR(sc->dev, "Outgoing queue is full. Dropping mbuf, len=%d\n", m->m_pkthdr.len); @@ -564,6 +566,7 @@ NG_FREE_M(m); } else IF_ENQUEUE(&sc->outq, m); + spin_unlock(&sc->sc_lock); error = ng_send_fn(sc->node, NULL, bt3c_send, NULL, 0 /* new send */); out: @@ -666,6 +669,7 @@ sc->debug = NG_BT3C_WARN_LEVEL; sc->inq.ifq_maxlen = sc->outq.ifq_maxlen = BT3C_DEFAULTQLEN; + spin_init(&sc->sc_lock, "bt3c sc"); sc->state = NG_BT3C_W4_PKT_IND; sc->want = 1; @@ -927,6 +931,7 @@ NG_BT3C_STAT_BYTES_RECV(sc->stat, sc->m->m_pkthdr.len); NG_BT3C_STAT_PCKTS_RECV(sc->stat); + spin_lock(&sc->sc_lock); if (IF_QFULL(&sc->inq)) { NG_BT3C_ERR(sc->dev, "Incoming queue is full. Dropping mbuf, len=%d\n", sc->m->m_pkthdr.len); @@ -939,6 +944,7 @@ IF_ENQUEUE(&sc->inq, sc->m); sc->m = NULL; } + spin_unlock(&sc->sc_lock); sc->state = NG_BT3C_W4_PKT_IND; sc->want = 1; @@ -1013,6 +1019,7 @@ return; if (sc->hook != NULL && NG_HOOK_IS_VALID(sc->hook)) { + spin_lock(&sc->sc_lock); for (;;) { IF_DEQUEUE(&sc->inq, m); if (m == NULL) @@ -1022,7 +1029,9 @@ if (error != 0) NG_BT3C_STAT_IERROR(sc->stat); } + spin_unlock(&sc->sc_lock); } else { + spin_lock(&sc->sc_lock); for (;;) { IF_DEQUEUE(&sc->inq, m); if (m == NULL) @@ -1031,6 +1040,7 @@ NG_BT3C_STAT_IERROR(sc->stat); NG_FREE_M(m); } + spin_unlock(&sc->sc_lock); } } /* bt3c_forward */ @@ -1056,6 +1066,7 @@ bt3c_set_address(sc, 0x7080); + spin_lock(&sc->sc_lock); for (wrote = 0; wrote < BT3C_FIFO_SIZE; ) { IF_DEQUEUE(&sc->outq, m); if (m == NULL) @@ -1084,6 +1095,7 @@ NG_BT3C_STAT_PCKTS_SENT(sc->stat); } + spin_unlock(&sc->sc_lock); if (wrote > 0) { NG_BT3C_INFO(sc->dev, "Wrote %d bytes\n", wrote); |