diff --git a/sys/netbt/hci_unit.c b/sys/netbt/hci_unit.c --- a/sys/netbt/hci_unit.c +++ b/sys/netbt/hci_unit.c @@ -232,6 +232,16 @@ unit->hci_flags &= ~BTF_RUNNING; /* + * Acquire hci_devlock: hci_intr is netisr-driven (via btintr in + * bt_input.c) and may be running concurrently on another CPU, + * iterating hci_links / dequeuing from the rx queues / touching + * the *rxqlen counters. Without this lock our teardown races + * hci_intr and can panic in its KASSERT(m != NULL) or use a link + * after hci_link_free() freed it. + */ + lockmgr(&unit->hci_devlock, LK_EXCLUSIVE); + + /* * close down any links, take care to close SCO first since * they may depend on ACL links. */ @@ -247,8 +257,6 @@ while ((memo = LIST_FIRST(&unit->hci_memos)) != NULL) hci_memo_free(memo); - /* (no need to hold hci_devlock, the driver is disabled) */ - IF_DRAIN(&unit->hci_eventq); unit->hci_eventqlen = 0; @@ -260,6 +268,8 @@ IF_DRAIN(&unit->hci_cmdwait); IF_DRAIN(&unit->hci_scodone); + + lockmgr(&unit->hci_devlock, LK_RELEASE); } struct hci_unit * @@ -339,6 +349,8 @@ unit->hci_eventqlen--; lockmgr(&unit->hci_devlock, LK_RELEASE); + if (m == NULL) + goto another; KKASSERT(m != NULL); DPRINTFN(10, "(%s) recv event, len = %d\n",