From 83aacedec2af35a79438ed7baa48d2291fcc6dcc Mon Sep 17 00:00:00 2001 From: Hasso Tepper Date: Tue, 18 Mar 2008 13:41:42 +0000 Subject: [PATCH] Sync Bluetooth stack with NetBSD. Obtained-from: NetBSD via OpenBSD --- sys/dev/usbmisc/ubt/ubt.c | 304 ++++++++++++++++---------- sys/netbt/bluetooth.h | 12 +- sys/netbt/bt_input.c | 2 +- sys/netbt/bt_proto.c | 2 +- sys/netbt/hci.h | 520 +++++++++++++++++++++++++++++++++++++-------- sys/netbt/hci_event.c | 323 ++++++++++++++++++++-------- sys/netbt/hci_ioctl.c | 31 +-- sys/netbt/hci_link.c | 98 +++++---- sys/netbt/hci_misc.c | 45 +++- sys/netbt/hci_socket.c | 428 ++++++++++++++++++++++++++++--------- sys/netbt/hci_unit.c | 220 +++++++++++-------- sys/netbt/l2cap.h | 7 +- sys/netbt/l2cap_lower.c | 13 +- sys/netbt/l2cap_misc.c | 17 +- sys/netbt/l2cap_signal.c | 66 +++++- sys/netbt/l2cap_socket.c | 2 +- sys/netbt/l2cap_upper.c | 2 +- sys/netbt/rfcomm.h | 9 +- sys/netbt/rfcomm_dlc.c | 8 +- sys/netbt/rfcomm_session.c | 8 +- sys/netbt/rfcomm_socket.c | 18 +- sys/netbt/rfcomm_upper.c | 46 ++-- sys/netbt/sco.h | 2 +- sys/netbt/sco_socket.c | 6 +- sys/netbt/sco_upper.c | 2 +- 25 files changed, 1551 insertions(+), 640 deletions(-) diff --git a/sys/dev/usbmisc/ubt/ubt.c b/sys/dev/usbmisc/ubt/ubt.c index 03d1d2a537..de1da4b6b0 100644 --- a/sys/dev/usbmisc/ubt/ubt.c +++ b/sys/dev/usbmisc/ubt/ubt.c @@ -1,5 +1,6 @@ -/* $OpenBSD: ubt.c,v 1.9 2007/10/11 18:33:14 deraadt Exp $ */ -/* $DragonFly: src/sys/dev/usbmisc/ubt/ubt.c,v 1.2 2008/02/03 06:27:48 hasso Exp $ */ +/* $DragonFly: src/sys/dev/usbmisc/ubt/ubt.c,v 1.3 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/dev/usb/ubt.c,v 1.11 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: ubt.c,v 1.30 2007/12/16 19:01:37 christos Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -165,6 +166,7 @@ struct ubt_softc { usbd_device_handle sc_udev; int sc_refcnt; int sc_dying; + int sc_enabled; /* Control Interface */ usbd_interface_handle sc_iface0; @@ -172,6 +174,8 @@ struct ubt_softc { /* Commands (control) */ usbd_xfer_handle sc_cmd_xfer; u_char *sc_cmd_buf; + int sc_cmd_busy; /* write active */ + struct ifqueue sc_cmd_queue; /* output queue */ /* Events (interrupt) */ int sc_evt_addr; /* endpoint address */ @@ -191,6 +195,8 @@ struct ubt_softc { usbd_pipe_handle sc_aclwr_pipe; /* write pipe */ usbd_xfer_handle sc_aclwr_xfer; /* write xfer */ u_char *sc_aclwr_buf; /* write buffer */ + int sc_aclwr_busy; /* write active */ + struct ifqueue sc_aclwr_queue;/* output queue */ /* ISOC interface */ usbd_interface_handle sc_iface1; /* ISOC interface */ @@ -211,9 +217,12 @@ struct ubt_softc { int sc_scowr_size; /* frame length */ struct ubt_isoc_xfer sc_scowr[UBT_NXFERS]; struct mbuf *sc_scowr_mbuf; /* current packet */ + int sc_scowr_busy; /* write active */ + struct ifqueue sc_scowr_queue;/* output queue */ /* Protocol structure */ - struct hci_unit sc_unit; + struct hci_unit *sc_unit; + struct bt_stats sc_stats; /* Successfully attached */ int sc_ok; @@ -225,18 +234,21 @@ struct ubt_softc { /* * Bluetooth unit/USB callback routines */ -int ubt_enable(struct hci_unit *); -void ubt_disable(struct hci_unit *); +int ubt_enable(struct device *); +void ubt_disable(struct device *); -void ubt_xmit_cmd_start(struct hci_unit *); +void ubt_xmit_cmd(struct device *, struct mbuf *); +void ubt_xmit_cmd_start(struct ubt_softc *); void ubt_xmit_cmd_complete(usbd_xfer_handle, usbd_private_handle, usbd_status); -void ubt_xmit_acl_start(struct hci_unit *); +void ubt_xmit_acl(struct device *, struct mbuf *); +void ubt_xmit_acl_start(struct ubt_softc *); void ubt_xmit_acl_complete(usbd_xfer_handle, usbd_private_handle, usbd_status); -void ubt_xmit_sco_start(struct hci_unit *); +void ubt_xmit_sco(struct device *, struct mbuf *); +void ubt_xmit_sco_start(struct ubt_softc *); void ubt_xmit_sco_start1(struct ubt_softc *, struct ubt_isoc_xfer *); void ubt_xmit_sco_complete(usbd_xfer_handle, usbd_private_handle, usbd_status); @@ -252,6 +264,8 @@ void ubt_recv_sco_start1(struct ubt_softc *, struct ubt_isoc_xfer *); void ubt_recv_sco_complete(usbd_xfer_handle, usbd_private_handle, usbd_status); +void ubt_stats(struct device *, struct bt_stats *, int); + static device_probe_t ubt_match; static device_attach_t ubt_attach; static device_detach_t ubt_detach; @@ -279,6 +293,15 @@ MODULE_DEPEND(ubt, bthub, 1, 1, 1); #endif MODULE_DEPEND(ubt, usb, 1, 1, 1); +const struct hci_if ubt_hci = { + .enable = ubt_enable, + .disable = ubt_disable, + .output_cmd = ubt_xmit_cmd, + .output_acl = ubt_xmit_acl, + .output_sco = ubt_xmit_sco, + .get_stats = ubt_stats, +}; + static int ubt_set_isoc_config(struct ubt_softc *); static int ubt_sysctl_config(SYSCTL_HANDLER_ARGS); static void ubt_abortdealloc(struct ubt_softc *); @@ -292,15 +315,13 @@ static void ubt_abortdealloc(struct ubt_softc *); * to the ubt_ignore list. */ static const struct usb_devno ubt_ignore[] = { - { USB_DEVICE(0x0a5c, 0x2000) }, /* Braodcom BCM2033 */ - { USB_DEVICE(0x0a5c, 0x2033) }, /* Broadcom BCM2033 (no fw) */ + { USB_DEVICE(0x0a5c, 0x2033) }, /* Broadcom BCM2033 */ { 0, 0 } /* end of list */ }; static int ubt_match(device_t self) { - struct usb_attach_arg *uaa = device_get_ivars(self); usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device); @@ -328,7 +349,7 @@ ubt_attach(device_t self) uint8_t count, i; DPRINTFN(50, "ubt_attach: sc=%p\n", sc); - + sc->sc_udev = uaa->device; sc->sc_dev = self; @@ -349,7 +370,6 @@ ubt_attach(device_t self) * 2) Bulk IN endpoint to receive ACL data * 3) Bulk OUT endpoint to send ACL data */ - err = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface0); if (err) { kprintf("%s: Could not get interface 0 handle %s (%d)\n", @@ -415,11 +435,10 @@ ubt_attach(device_t self) * via a sysctl variable. We select config 0 to start, which * means that no SCO data will be available. */ - err = usbd_device2interface_handle(sc->sc_udev, 1, &sc->sc_iface1); if (err) { kprintf("%s: Could not get interface 1 handle %s (%d)\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(err), err); + device_get_nameunit(sc->sc_dev), usbd_errstr(err), err); return ENXIO; } @@ -435,7 +454,6 @@ ubt_attach(device_t self) sc->sc_alt_config = usbd_get_no_alts(cd, 1); /* set initial config */ - err = ubt_set_isoc_config(sc); if (err) { kprintf("%s: ISOC config failed\n", @@ -444,23 +462,12 @@ ubt_attach(device_t self) return ENXIO; } - /* Attach HCI host's software */ - - /* Fill HCI part of struct with data */ - sc->sc_unit.hci_softc = self; - sc->sc_unit.hci_devname = device_get_nameunit(sc->sc_dev); - sc->sc_unit.hci_enable = ubt_enable; - sc->sc_unit.hci_disable = ubt_disable; - sc->sc_unit.hci_start_cmd = ubt_xmit_cmd_start; - sc->sc_unit.hci_start_acl = ubt_xmit_acl_start; - sc->sc_unit.hci_start_sco = ubt_xmit_sco_start; - - /* Attach to HCI software stack */ - - hci_attach(&sc->sc_unit); + /* Attach HCI */ + sc->sc_unit = hci_attach(&ubt_hci, sc->sc_dev, 0); usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev); + sc->sc_ok = 1; sysctl_ctx_init(&sc->sysctl_ctx); @@ -506,8 +513,10 @@ ubt_detach(device_t self) return 0; /* Detach HCI interface */ - - hci_detach(&sc->sc_unit); + if (sc->sc_unit) { + hci_detach(sc->sc_unit); + sc->sc_unit = NULL; + } /* * Abort all pipes. Causes processes waiting for transfer to wake. @@ -516,11 +525,9 @@ ubt_detach(device_t self) * call ubt_abortdealloc(), but lets be sure since doing it twice * wont cause an error. */ - ubt_abortdealloc(sc); /* wait for all processes to finish */ - if (sc->sc_refcnt-- > 0) usb_detach_wait(sc->sc_dev); @@ -654,7 +661,7 @@ ubt_sysctl_config(SYSCTL_HANDLER_ARGS) return EINVAL; /* This may not change when the unit is enabled */ - if (sc->sc_unit.hci_flags & BTF_RUNNING) + if (sc->sc_enabled) return EBUSY; sc->sc_config = t; @@ -667,6 +674,7 @@ ubt_abortdealloc(struct ubt_softc *sc) int i; DPRINTFN(1, "sc=%p\n", sc); + crit_enter(); /* Abort all pipes */ if (sc->sc_evt_pipe != NULL) { @@ -748,6 +756,12 @@ ubt_abortdealloc(struct ubt_softc *sc) m_freem(sc->sc_scowr_mbuf); sc->sc_scowr_mbuf = NULL; } + + /* Empty mbuf queues */ + IF_DRAIN(&sc->sc_cmd_queue); + IF_DRAIN(&sc->sc_aclwr_queue); + IF_DRAIN(&sc->sc_scowr_queue); + crit_exit(); } @@ -758,19 +772,20 @@ ubt_abortdealloc(struct ubt_softc *sc) * All of this will be called at the IPL_ we specified above */ int -ubt_enable(struct hci_unit *unit) +ubt_enable(struct device *self) { - struct ubt_softc *sc = device_get_softc(unit->hci_softc); + struct ubt_softc *sc = device_get_softc(self); usbd_status err; int i, error; DPRINTFN(1, "%s: sc=%p\n", __func__, sc); - if (unit->hci_flags & BTF_RUNNING) + if (sc->sc_enabled) return 0; + crit_enter(); + /* Events */ - sc->sc_evt_buf = kmalloc(UBT_BUFSIZ_EVENT, M_USBDEV, M_NOWAIT); if (sc->sc_evt_buf == NULL) { error = ENOMEM; @@ -793,7 +808,6 @@ ubt_enable(struct hci_unit *unit) } /* Commands */ - sc->sc_cmd_xfer = usbd_alloc_xfer(sc->sc_udev); if (sc->sc_cmd_xfer == NULL) { kprintf("can't allocate cmd_xfer\n"); @@ -806,9 +820,9 @@ ubt_enable(struct hci_unit *unit) error = ENOMEM; goto bad; } + sc->sc_cmd_busy = 0; /* ACL read */ - err = usbd_open_pipe(sc->sc_iface0, sc->sc_aclrd_addr, USBD_EXCLUSIVE_USE, &sc->sc_aclrd_pipe); if (err != USBD_NORMAL_COMPLETION) { @@ -832,7 +846,6 @@ ubt_enable(struct hci_unit *unit) ubt_recv_acl_start(sc); /* ACL write */ - err = usbd_open_pipe(sc->sc_iface0, sc->sc_aclwr_addr, USBD_EXCLUSIVE_USE, &sc->sc_aclwr_pipe); if (err != USBD_NORMAL_COMPLETION) { @@ -852,9 +865,9 @@ ubt_enable(struct hci_unit *unit) error = ENOMEM; goto bad; } + sc->sc_aclwr_busy = 0; /* SCO read */ - if (sc->sc_scord_size > 0) { err = usbd_open_pipe(sc->sc_iface1, sc->sc_scord_addr, USBD_EXCLUSIVE_USE, &sc->sc_scord_pipe); @@ -882,7 +895,6 @@ ubt_enable(struct hci_unit *unit) } /* SCO write */ - if (sc->sc_scowr_size > 0) { err = usbd_open_pipe(sc->sc_iface1, sc->sc_scowr_addr, USBD_EXCLUSIVE_USE, &sc->sc_scowr_pipe); @@ -906,38 +918,53 @@ ubt_enable(struct hci_unit *unit) sc->sc_scowr[i].softc = sc; sc->sc_scowr[i].busy = 0; } + + sc->sc_scowr_busy = 0; } - unit->hci_flags &= ~BTF_XMIT; - unit->hci_flags |= BTF_RUNNING; - + sc->sc_enabled = 1; + crit_exit(); return 0; bad: - kprintf("ubt_enable: something going wrong... :( \n"); ubt_abortdealloc(sc); + crit_exit(); return error; } void -ubt_disable(struct hci_unit *unit) +ubt_disable(struct device *self) { - struct ubt_softc *sc = device_get_softc(unit->hci_softc); + struct ubt_softc *sc = device_get_softc(self); DPRINTFN(1, "sc=%p\n", sc); - if ((unit->hci_flags & BTF_RUNNING) == 0) + if (sc->sc_enabled == 0) return; ubt_abortdealloc(sc); + sc->sc_enabled = 0; +} + +void +ubt_xmit_cmd(struct device *self, struct mbuf *m) +{ + struct ubt_softc *sc = device_get_softc(self); + + KKASSERT(sc->sc_enabled); + + crit_enter(); + IF_ENQUEUE(&sc->sc_cmd_queue, m); - unit->hci_flags &= ~BTF_RUNNING; + if (sc->sc_cmd_busy == 0) + ubt_xmit_cmd_start(sc); + + crit_exit(); } void -ubt_xmit_cmd_start(struct hci_unit *unit) +ubt_xmit_cmd_start(struct ubt_softc *sc) { - struct ubt_softc *sc = device_get_softc(unit->hci_softc); usb_device_request_t req; usbd_status status; struct mbuf *m; @@ -946,17 +973,17 @@ ubt_xmit_cmd_start(struct hci_unit *unit) if (sc->sc_dying) return; - - - if (IF_QEMPTY(&unit->hci_cmdq)) + if (IF_QEMPTY(&sc->sc_cmd_queue)) return; - IF_DEQUEUE(&unit->hci_cmdq, m); + + IF_DEQUEUE(&sc->sc_cmd_queue, m); + KKASSERT(m != NULL); DPRINTFN(15, " %s: xmit CMD packet (%d bytes)\n", - unit->hci_devname, m->m_pkthdr.len); + device_get_nameunit(sc->sc_dev), m->m_pkthdr.len); sc->sc_refcnt++; - unit->hci_flags |= BTF_XMIT_CMD; + sc->sc_cmd_busy = 1; len = m->m_pkthdr.len - 1; m_copydata(m, 1, len, sc->sc_cmd_buf); @@ -968,7 +995,7 @@ ubt_xmit_cmd_start(struct hci_unit *unit) usbd_setup_default_xfer(sc->sc_cmd_xfer, sc->sc_udev, - unit, + sc, UBT_CMD_TIMEOUT, &req, sc->sc_cmd_buf, @@ -984,7 +1011,7 @@ ubt_xmit_cmd_start(struct hci_unit *unit) DPRINTF("usbd_transfer status=%s (%d)\n", usbd_errstr(status), status); sc->sc_refcnt--; - unit->hci_flags &= ~BTF_XMIT_CMD; + sc->sc_cmd_busy = 0; } } @@ -993,14 +1020,13 @@ void ubt_xmit_cmd_complete(usbd_xfer_handle xfer, usbd_private_handle h, usbd_status status) { - struct hci_unit *unit = h; - struct ubt_softc *sc = device_get_softc(unit->hci_softc); + struct ubt_softc *sc = h; uint32_t count; DPRINTFN(15, " %s: CMD complete status=%s (%d)\n", - unit->hci_devname, usbd_errstr(status), status); + device_get_nameunit(sc->sc_dev), usbd_errstr(status), status); - unit->hci_flags &= ~BTF_XMIT_CMD; + sc->sc_cmd_busy = 0; if (--sc->sc_refcnt < 0) { DPRINTF("sc_refcnt=%d\n", sc->sc_refcnt); @@ -1016,22 +1042,36 @@ ubt_xmit_cmd_complete(usbd_xfer_handle xfer, if (status != USBD_NORMAL_COMPLETION) { DPRINTF("status=%s (%d)\n", usbd_errstr(status), status); - unit->hci_stats.err_tx++; + sc->sc_stats.err_tx++; return; } usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL); + sc->sc_stats.cmd_tx++; + sc->sc_stats.byte_tx += count; - unit->hci_stats.cmd_tx++; - unit->hci_stats.byte_tx += count; + ubt_xmit_cmd_start(sc); +} + +void +ubt_xmit_acl(struct device *self, struct mbuf *m) +{ + struct ubt_softc *sc = device_get_softc(self); - ubt_xmit_cmd_start(unit); + KKASSERT(sc->sc_enabled); + + crit_enter(); + IF_ENQUEUE(&sc->sc_aclwr_queue, m); + + if (sc->sc_aclwr_busy == 0) + ubt_xmit_acl_start(sc); + + crit_exit(); } void -ubt_xmit_acl_start(struct hci_unit *unit) +ubt_xmit_acl_start(struct ubt_softc *sc) { - struct ubt_softc *sc = device_get_softc(unit->hci_softc); struct mbuf *m; usbd_status status; int len; @@ -1040,21 +1080,22 @@ ubt_xmit_acl_start(struct hci_unit *unit) return; - if (IF_QEMPTY(&unit->hci_acltxq)) + if (IF_QEMPTY(&sc->sc_aclwr_queue)) return; sc->sc_refcnt++; - unit->hci_flags |= BTF_XMIT_ACL; + sc->sc_aclwr_busy = 1; - IF_DEQUEUE(&unit->hci_acltxq, m); + IF_DEQUEUE(&sc->sc_aclwr_queue, m); + KKASSERT(m != NULL); DPRINTFN(15, "%s: xmit ACL packet (%d bytes)\n", - unit->hci_devname, m->m_pkthdr.len); + device_get_nameunit(sc->sc_dev), m->m_pkthdr.len); len = m->m_pkthdr.len - 1; if (len > UBT_BUFSIZ_ACL) { DPRINTF("%s: truncating ACL packet (%d => %d)!\n", - unit->hci_devname, len, UBT_BUFSIZ_ACL); + device_get_nameunit(sc->sc_dev), len, UBT_BUFSIZ_ACL); len = UBT_BUFSIZ_ACL; } @@ -1062,12 +1103,12 @@ ubt_xmit_acl_start(struct hci_unit *unit) m_copydata(m, 1, len, sc->sc_aclwr_buf); m_freem(m); - unit->hci_stats.acl_tx++; - unit->hci_stats.byte_tx += len; + sc->sc_stats.acl_tx++; + sc->sc_stats.byte_tx += len; usbd_setup_xfer(sc->sc_aclwr_xfer, sc->sc_aclwr_pipe, - unit, + sc, sc->sc_aclwr_buf, len, USBD_NO_COPY | USBD_FORCE_SHORT_XFER, @@ -1083,7 +1124,7 @@ ubt_xmit_acl_start(struct hci_unit *unit) usbd_errstr(status), status); sc->sc_refcnt--; - unit->hci_flags &= ~BTF_XMIT_ACL; + sc->sc_aclwr_busy = 0; } } @@ -1092,13 +1133,12 @@ void ubt_xmit_acl_complete(usbd_xfer_handle xfer, usbd_private_handle h, usbd_status status) { - struct hci_unit *unit = h; - struct ubt_softc *sc = device_get_softc(unit->hci_softc); + struct ubt_softc *sc = h; DPRINTFN(15, "%s: ACL complete status=%s (%d)\n", - unit->hci_devname, usbd_errstr(status), status); + device_get_nameunit(sc->sc_dev), usbd_errstr(status), status); - unit->hci_flags &= ~BTF_XMIT_ACL; + sc->sc_aclwr_busy = 0; if (--sc->sc_refcnt < 0) { usb_detach_wakeup(sc->sc_dev); @@ -1112,7 +1152,7 @@ ubt_xmit_acl_complete(usbd_xfer_handle xfer, DPRINTF("status=%s (%d)\n", usbd_errstr(status), status); - unit->hci_stats.err_tx++; + sc->sc_stats.err_tx++; if (status == USBD_STALLED) usbd_clear_endpoint_stall_async(sc->sc_aclwr_pipe); @@ -1120,14 +1160,29 @@ ubt_xmit_acl_complete(usbd_xfer_handle xfer, return; } - ubt_xmit_acl_start(unit); + ubt_xmit_acl_start(sc); } void -ubt_xmit_sco_start(struct hci_unit *unit) +ubt_xmit_sco(struct device *self, struct mbuf *m) +{ + struct ubt_softc *sc = device_get_softc(self); + + KKASSERT(sc->sc_enabled); + + crit_enter(); + IF_ENQUEUE(&sc->sc_scowr_queue, m); + + if (sc->sc_scowr_busy == 0) + ubt_xmit_sco_start(sc); + + crit_exit(); +} + +void +ubt_xmit_sco_start(struct ubt_softc *sc) { - struct ubt_softc *sc = device_get_softc(unit->hci_softc); int i; if (sc->sc_dying || sc->sc_scowr_size == 0) @@ -1168,7 +1223,7 @@ ubt_xmit_sco_start1(struct ubt_softc *sc, struct ubt_isoc_xfer *isoc) while (space > 0) { if (m == NULL) { crit_enter(); - IF_DEQUEUE(&sc->sc_unit.hci_scotxq, m); + IF_DEQUEUE(&sc->sc_scowr_queue, m); crit_exit(); if (m == NULL) break; @@ -1189,8 +1244,10 @@ ubt_xmit_sco_start1(struct ubt_softc *sc, struct ubt_isoc_xfer *isoc) } if (m->m_pkthdr.len == 0) { - sc->sc_unit.hci_stats.sco_tx++; - hci_complete_sco(&sc->sc_unit, m); + sc->sc_stats.sco_tx++; + if (!hci_complete_sco(sc->sc_unit, m)) + sc->sc_stats.err_tx++; + m = NULL; } } @@ -1203,8 +1260,8 @@ ubt_xmit_sco_start1(struct ubt_softc *sc, struct ubt_isoc_xfer *isoc) return; sc->sc_refcnt++; - sc->sc_unit.hci_flags |= BTF_XMIT_SCO; - sc->sc_unit.hci_stats.byte_tx += len; + sc->sc_scowr_busy = 1; + sc->sc_stats.byte_tx += len; isoc->busy = 1; /* @@ -1247,7 +1304,7 @@ ubt_xmit_sco_complete(usbd_xfer_handle xfer, for (i = 0 ; ; i++) { if (i == UBT_NXFERS) { - sc->sc_unit.hci_flags &= ~BTF_XMIT_SCO; + sc->sc_scowr_busy = 0; break; } @@ -1267,7 +1324,7 @@ ubt_xmit_sco_complete(usbd_xfer_handle xfer, DPRINTF("status=%s (%d)\n", usbd_errstr(status), status); - sc->sc_unit.hci_stats.err_tx++; + sc->sc_stats.err_tx++; if (status == USBD_STALLED) usbd_clear_endpoint_stall_async(sc->sc_scowr_pipe); @@ -1275,7 +1332,7 @@ ubt_xmit_sco_complete(usbd_xfer_handle xfer, return; } - ubt_xmit_sco_start(&sc->sc_unit); + ubt_xmit_sco_start(sc); } /* @@ -1319,19 +1376,16 @@ ubt_recv_event(usbd_xfer_handle xfer, usbd_private_handle h, usbd_status status) if (count < sizeof(hci_event_hdr_t) - 1) { DPRINTF("dumped undersized event (count = %d)\n", count); - sc->sc_unit.hci_stats.err_rx++; + sc->sc_stats.err_rx++; return; } - sc->sc_unit.hci_stats.evt_rx++; - sc->sc_unit.hci_stats.byte_rx += count; + sc->sc_stats.evt_rx++; + sc->sc_stats.byte_rx += count; m = ubt_mbufload(buf, count, HCI_EVENT_PKT); - if (m != NULL){ - hci_input_event(&sc->sc_unit, m); - } - else - sc->sc_unit.hci_stats.err_rx++; + if (m == NULL || !hci_input_event(sc->sc_unit, m)) + sc->sc_stats.err_rx++; } void @@ -1403,7 +1457,7 @@ ubt_recv_acl_complete(usbd_xfer_handle xfer, DPRINTF("status=%s (%d)\n", usbd_errstr(status), status); - sc->sc_unit.hci_stats.err_rx++; + sc->sc_stats.err_rx++; if (status == USBD_STALLED) usbd_clear_endpoint_stall_async(sc->sc_aclrd_pipe); @@ -1414,16 +1468,14 @@ ubt_recv_acl_complete(usbd_xfer_handle xfer, if (count < sizeof(hci_acldata_hdr_t) - 1) { DPRINTF("dumped undersized packet (%d)\n", count); - sc->sc_unit.hci_stats.err_rx++; + sc->sc_stats.err_rx++; } else { - sc->sc_unit.hci_stats.acl_rx++; - sc->sc_unit.hci_stats.byte_rx += count; + sc->sc_stats.acl_rx++; + sc->sc_stats.byte_rx += count; m = ubt_mbufload(buf, count, HCI_ACL_DATA_PKT); - if (m != NULL) - hci_input_acl(&sc->sc_unit, m); - else - sc->sc_unit.hci_stats.err_rx++; + if (m == NULL || !hci_input_acl(sc->sc_unit, m)) + sc->sc_stats.err_rx++; } } @@ -1496,7 +1548,7 @@ ubt_recv_sco_complete(usbd_xfer_handle xfer, DPRINTF("status=%s (%d)\n", usbd_errstr(status), status); - sc->sc_unit.hci_stats.err_rx++; + sc->sc_stats.err_rx++; if (status == USBD_STALLED) { usbd_clear_endpoint_stall_async(sc->sc_scord_pipe); @@ -1513,7 +1565,7 @@ ubt_recv_sco_complete(usbd_xfer_handle xfer, DPRINTFN(15, "sc=%p, isoc=%p, count=%u\n", sc, isoc, count); - sc->sc_unit.hci_stats.byte_rx += count; + sc->sc_stats.byte_rx += count; /* * Extract SCO packets from ISOC frames. The way we have it, @@ -1550,7 +1602,7 @@ ubt_recv_sco_complete(usbd_xfer_handle xfer, kprintf("%s: out of memory (xfer halted)\n", device_get_nameunit(sc->sc_dev)); - sc->sc_unit.hci_stats.err_rx++; + sc->sc_stats.err_rx++; return; /* lost sync */ } @@ -1583,8 +1635,10 @@ ubt_recv_sco_complete(usbd_xfer_handle xfer, if (got == want) { m->m_pkthdr.len = m->m_len = got; - sc->sc_unit.hci_stats.sco_rx++; - hci_input_sco(&sc->sc_unit, m); + sc->sc_stats.sco_rx++; + if (!hci_input_sco(sc->sc_unit, m)) + sc->sc_stats.err_rx++; + m = NULL; } } @@ -1601,3 +1655,17 @@ ubt_recv_sco_complete(usbd_xfer_handle xfer, restart: /* and restart */ ubt_recv_sco_start1(sc, isoc); } + +void +ubt_stats(struct device *self, struct bt_stats *dest, int flush) +{ + struct ubt_softc *sc = device_get_softc(self); + + crit_enter(); + memcpy(dest, &sc->sc_stats, sizeof(struct bt_stats)); + + if (flush) + memset(&sc->sc_stats, 0, sizeof(struct bt_stats)); + + crit_exit(); +} diff --git a/sys/netbt/bluetooth.h b/sys/netbt/bluetooth.h index e27e766a2c..42d8beb359 100644 --- a/sys/netbt/bluetooth.h +++ b/sys/netbt/bluetooth.h @@ -1,6 +1,6 @@ -/* $OpenBSD: bluetooth.h,v 1.4 2007/05/30 03:42:53 uwe Exp $ */ -/* $NetBSD: bluetooth.h,v 1.5 2007/04/21 06:15:22 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/bluetooth.h,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/bluetooth.h,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/bluetooth.h,v 1.5 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: bluetooth.h,v 1.6 2007/09/17 01:23:17 rillig Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. @@ -141,9 +141,9 @@ extern int bluetooth_debug; # define UNKNOWN(value) \ kprintf("%s: %s = %d unknown!\n", __func__, #value, (value)); #else -# define DPRINTF(...) -# define DPRINTFN(...) -# define UNKNOWN(x) +# define DPRINTF(...) ((void)0) +# define DPRINTFN(...) ((void)0) +# define UNKNOWN(x) ((void)0) #endif /* BLUETOOTH_DEBUG */ #define sbspace(sb) \ diff --git a/sys/netbt/bt_input.c b/sys/netbt/bt_input.c index 7a24f091ee..8f8931051a 100644 --- a/sys/netbt/bt_input.c +++ b/sys/netbt/bt_input.c @@ -1,5 +1,5 @@ +/* $DragonFly: src/sys/netbt/bt_input.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ /* $OpenBSD: bt_input.c,v 1.5 2007/06/24 20:55:27 uwe Exp $ */ -/* $DragonFly: src/sys/netbt/bt_input.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ /* * Copyright (c) 2004 Alexander Yurchenko diff --git a/sys/netbt/bt_proto.c b/sys/netbt/bt_proto.c index 3c61d9a3cc..1ae6308cee 100644 --- a/sys/netbt/bt_proto.c +++ b/sys/netbt/bt_proto.c @@ -1,5 +1,5 @@ +/* $DragonFly: src/sys/netbt/bt_proto.c,v 1.3 2008/03/18 13:41:42 hasso Exp $ */ /* $OpenBSD: bt_proto.c,v 1.4 2007/06/24 20:55:27 uwe Exp $ */ -/* $DragonFly: src/sys/netbt/bt_proto.c,v 1.2 2008/02/01 14:18:58 hasso Exp $ */ /* * Copyright (c) 2004 Alexander Yurchenko diff --git a/sys/netbt/hci.h b/sys/netbt/hci.h index 0dbc400ae2..5885400875 100644 --- a/sys/netbt/hci.h +++ b/sys/netbt/hci.h @@ -1,6 +1,6 @@ -/* $OpenBSD: hci.h,v 1.9 2007/07/22 21:05:00 gwk Exp $ */ -/* $NetBSD: hci.h,v 1.10 2007/04/21 06:15:23 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/hci.h,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/hci.h,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/hci.h,v 1.10 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: hci.h,v 1.22 2008/02/10 17:40:54 plunky Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. @@ -56,13 +56,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $Id: hci.h,v 1.22 2008/02/10 17:40:54 plunky Exp $ * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_hci.h,v 1.6 2005/01/07 01:45:43 imp Exp $ */ /* * This file contains everything that applications need to know from * Host Controller Interface (HCI). Information taken from Bluetooth - * Core Specifications (v1.1 and v2.0) + * Core Specifications (v1.1, v2.0 and v2.1) * * This file can be included by both kernel and userland applications. * @@ -77,6 +78,8 @@ #include +#include + /************************************************************************** ************************************************************************** ** Common defines and types (HCI) @@ -91,13 +94,15 @@ #define HCI_FEATURES_SIZE 8 /* LMP features */ #define HCI_UNIT_NAME_SIZE 248 /* unit name size */ #define HCI_DEVNAME_SIZE 16 /* same as dv_xname */ +#define HCI_COMMANDS_SIZE 64 /* supported commands mask */ /* HCI specification */ #define HCI_SPEC_V10 0x00 /* v1.0 */ #define HCI_SPEC_V11 0x01 /* v1.1 */ #define HCI_SPEC_V12 0x02 /* v1.2 */ #define HCI_SPEC_V20 0x03 /* v2.0 */ -/* 0x02 - 0xFF - reserved for future use */ +#define HCI_SPEC_V21 0x04 /* v2.1 */ +/* 0x05 - 0xFF - reserved for future use */ /* LMP features (and page 0 of extended features) */ /* ------------------- byte 0 --------------------*/ @@ -147,16 +152,25 @@ #define HCI_LMP_3SLOT_EDR_ACL 0x80 /* ------------------- byte 5 --------------------*/ #define HCI_LMP_5SLOT_EDR_ACL 0x01 -/* reserved 0x02 */ -/* reserved 0x04 */ +#define HCI_LMP_SNIFF_SUBRATING 0x02 +#define HCI_LMP_PAUSE_ENCRYPTION 0x04 #define HCI_LMP_AFH_CAPABLE_MASTER 0x08 #define HCI_LMP_AFH_CLASS_MASTER 0x10 #define HCI_LMP_EDR_eSCO_2MBPS 0x20 #define HCI_LMP_EDR_eSCO_3MBPS 0x40 #define HCI_LMP_3SLOT_EDR_eSCO 0x80 /* ------------------- byte 6 --------------------*/ -/* reserved */ +#define HCI_LMP_EXTENDED_INQUIRY 0x01 +/* reserved 0x02 */ +/* reserved 0x04 */ +#define HCI_LMP_SIMPLE_PAIRING 0x08 +#define HCI_LMP_ENCAPSULATED_PDU 0x10 +#define HCI_LMP_ERRDATA_REPORTING 0x20 +#define HCI_LMP_NOFLUSH_PB_FLAG 0x40 +/* reserved 0x80 */ /* ------------------- byte 7 --------------------*/ +#define HCI_LMP_LINK_SUPERVISION_TO 0x01 +#define HCI_LMP_INQ_RSP_TX_POWER 0x02 #define HCI_LMP_EXTENDED_FEATURES 0x80 /* Link types */ @@ -474,8 +488,8 @@ typedef hci_status_rp hci_exit_periodic_inquiry_rp; #define HCI_OCF_CREATE_CON 0x0005 #define HCI_CMD_CREATE_CON 0x0405 typedef struct { - bdaddr_t bdaddr; /* destination address */ - uint16_t pkt_type; /* packet type */ + bdaddr_t bdaddr; /* destination address */ + uint16_t pkt_type; /* packet type */ uint8_t page_scan_rep_mode; /* page scan repetition mode */ uint8_t page_scan_mode; /* reserved - set to 0x00 */ uint16_t clock_offset; /* clock offset */ @@ -530,7 +544,7 @@ typedef struct { #define HCI_OCF_LINK_KEY_REP 0x000b #define HCI_CMD_LINK_KEY_REP 0x040B typedef struct { - bdaddr_t bdaddr; /* remote address */ + bdaddr_t bdaddr; /* remote address */ uint8_t key[HCI_KEY_SIZE]; /* key */ } __attribute__ ((__packed__)) hci_link_key_rep_cp; @@ -553,8 +567,8 @@ typedef struct { #define HCI_OCF_PIN_CODE_REP 0x000d #define HCI_CMD_PIN_CODE_REP 0x040D typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t pin_size; /* pin code length (in bytes) */ + bdaddr_t bdaddr; /* remote address */ + uint8_t pin_size; /* pin code length (in bytes) */ uint8_t pin[HCI_PIN_SIZE]; /* pin code */ } __attribute__ ((__packed__)) hci_pin_code_rep_cp; @@ -592,7 +606,7 @@ typedef struct { #define HCI_OCF_SET_CON_ENCRYPTION 0x0013 #define HCI_CMD_SET_CON_ENCRYPTION 0x0413 typedef struct { - uint16_t con_handle; /* connection handle */ + uint16_t con_handle; /* connection handle */ uint8_t encryption_enable; /* 0x00 - disable, 0x01 - enable */ } __attribute__ ((__packed__)) hci_set_con_encryption_cp; /* No return parameter(s) */ @@ -614,7 +628,7 @@ typedef struct { #define HCI_OCF_REMOTE_NAME_REQ 0x0019 #define HCI_CMD_REMOTE_NAME_REQ 0x0419 typedef struct { - bdaddr_t bdaddr; /* remote address */ + bdaddr_t bdaddr; /* remote address */ uint8_t page_scan_rep_mode; /* page scan repetition mode */ uint8_t page_scan_mode; /* page scan mode */ uint16_t clock_offset; /* clock offset */ @@ -624,12 +638,12 @@ typedef struct { #define HCI_OCF_REMOTE_NAME_REQ_CANCEL 0x001a #define HCI_CMD_REMOTE_NAME_REQ_CANCEL 0x041A typedef struct { - bdaddr_t bdaddr; /* remote address */ + bdaddr_t bdaddr; /* remote address */ } __attribute__ ((__packed__)) hci_remote_name_req_cancel_cp; typedef struct { uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ + bdaddr_t bdaddr; /* remote address */ } __attribute__ ((__packed__)) hci_remote_name_req_cancel_rp; #define HCI_OCF_READ_REMOTE_FEATURES 0x001b @@ -708,6 +722,101 @@ typedef struct { } __attribute__ ((__packed__)) hci_reject_sco_con_req_cp; /* No return parameter(s) */ +#define HCI_OCF_IO_CAPABILITY_REP 0x002b +#define HCI_CMD_IO_CAPABILITY_REP 0x042a +typedef struct { + bdaddr_t bdaddr; /* remote address */ + uint8_t io_cap; /* IO capability */ + uint8_t oob_data; /* OOB data present */ + uint8_t auth_req; /* auth requirements */ +} __attribute__ ((__packed__)) hci_io_capability_rep_cp; + +typedef struct { + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ +} __attribute__ ((__packed__)) hci_io_capability_rep_rp; + +#define HCI_OCF_USER_CONFIRM_REP 0x002c +#define HCI_CMD_USER_CONFIRM_REP 0x042c +typedef struct { + bdaddr_t bdaddr; /* remote address */ +} __attribute__ ((__packed__)) hci_user_confirm_rep_cp; + +typedef struct { + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ +} __attribute__ ((__packed__)) hci_user_confirm_rep_rp; + +#define HCI_OCF_USER_CONFIRM_NEG_REP 0x002d +#define HCI_CMD_USER_CONFIRM_NEG_REP 0x042d +typedef struct { + bdaddr_t bdaddr; /* remote address */ +} __attribute__ ((__packed__)) hci_user_confirm_neg_rep_cp; + +typedef struct { + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ +} __attribute__ ((__packed__)) hci_user_confirm_neg_rep_rp; + +#define HCI_OCF_USER_PASSKEY_REP 0x002e +#define HCI_CMD_USER_PASSKEY_REP 0x042e +typedef struct { + bdaddr_t bdaddr; /* remote address */ + uint32_t value; /* 000000 - 999999 */ +} __attribute__ ((__packed__)) hci_user_passkey_rep_cp; + +typedef struct { + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ +} __attribute__ ((__packed__)) hci_user_passkey_rep_rp; + +#define HCI_OCF_USER_PASSKEY_NEG_REP 0x002f +#define HCI_CMD_USER_PASSKEY_NEG_REP 0x042f +typedef struct { + bdaddr_t bdaddr; /* remote address */ +} __attribute__ ((__packed__)) hci_user_passkey_neg_rep_cp; + +typedef struct { + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ +} __attribute__ ((__packed__)) hci_user_passkey_neg_rep_rp; + +#define HCI_OCF_OOB_DATA_REP 0x0030 +#define HCI_CMD_OOB_DATA_REP 0x0430 +typedef struct { + bdaddr_t bdaddr; /* remote address */ + uint8_t c[16]; /* pairing hash */ + uint8_t r[16]; /* pairing randomizer */ +} __attribute__ ((__packed__)) hci_user_oob_data_rep_cp; + +typedef struct { + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ +} __attribute__ ((__packed__)) hci_user_oob_data_rep_rp; + +#define HCI_OCF_OOB_DATA_NEG_REP 0x0033 +#define HCI_CMD_OOB_DATA_NEG_REP 0x0433 +typedef struct { + bdaddr_t bdaddr; /* remote address */ +} __attribute__ ((__packed__)) hci_user_oob_data_neg_rep_cp; + +typedef struct { + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ +} __attribute__ ((__packed__)) hci_user_oob_data_neg_rep_rp; + +#define HCI_OCF_IO_CAPABILITY_NEG_REP 0x0034 +#define HCI_CMD_IO_CAPABILITY_NEG_REP 0x0434 +typedef struct { + bdaddr_t bdaddr; /* remote address */ + uint8_t reason; /* error code */ +} __attribute__ ((__packed__)) hci_io_capability_neg_rep_cp; + +typedef struct { + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ +} __attribute__ ((__packed__)) hci_io_capability_neg_rep_rp; + /************************************************************************** ************************************************************************** ** OGF 0x02 Link policy commands and return parameters @@ -763,11 +872,11 @@ typedef struct { #define HCI_CMD_QOS_SETUP 0x0807 typedef struct { uint16_t con_handle; /* connection handle */ - uint8_t flags; /* reserved for future use */ + uint8_t flags; /* reserved for future use */ uint8_t service_type; /* service type */ uint32_t token_rate; /* bytes per second */ uint32_t peak_bandwidth; /* bytes per second */ - uint32_t latency; /* microseconds */ + uint32_t latency; /* microseconds */ uint32_t delay_variation; /* microseconds */ } __attribute__ ((__packed__)) hci_qos_setup_cp; /* No return parameter(s) */ @@ -846,6 +955,20 @@ typedef struct { } __attribute__ ((__packed__)) hci_flow_specification_cp; /* No return parameter(s) */ +#define HCI_OCF_SNIFF_SUBRATING 0x0011 +#define HCI_CMD_SNIFF_SUBRATING 0x0810 +typedef struct { + uint16_t con_handle; /* connection handle */ + uint16_t max_latency; + uint16_t max_timeout; /* max remote timeout */ + uint16_t min_timeout; /* min local timeout */ +} __attribute__ ((__packed__)) hci_sniff_subrating_cp; + +typedef struct { + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_sniff_subrating_rp; + /************************************************************************** ************************************************************************** ** OGF 0x03 Host Controller and Baseband commands and return parameters @@ -870,7 +993,7 @@ typedef hci_status_rp hci_reset_rp; #define HCI_OCF_SET_EVENT_FILTER 0x0005 #define HCI_CMD_SET_EVENT_FILTER 0x0C05 typedef struct { - uint8_t filter_type; /* filter type */ + uint8_t filter_type; /* filter type */ uint8_t filter_condition_type; /* filter condition type */ /* variable size condition uint8_t condition[]; -- conditions */ @@ -918,7 +1041,7 @@ typedef struct { } __attribute__ ((__packed__)) hci_read_stored_link_key_cp; typedef struct { - uint8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ uint16_t max_num_keys; /* Max. number of keys */ uint16_t num_keys_read; /* Number of stored keys */ } __attribute__ ((__packed__)) hci_read_stored_link_key_rp; @@ -933,7 +1056,7 @@ typedef struct { } __attribute__ ((__packed__)) hci_write_stored_link_key_cp; typedef struct { - uint8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ uint8_t num_keys_written; /* # of keys successfully written */ } __attribute__ ((__packed__)) hci_write_stored_link_key_rp; @@ -945,7 +1068,7 @@ typedef struct { } __attribute__ ((__packed__)) hci_delete_stored_link_key_cp; typedef struct { - uint8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ uint16_t num_keys_deleted; /* Number of keys deleted */ } __attribute__ ((__packed__)) hci_delete_stored_link_key_rp; @@ -961,7 +1084,7 @@ typedef hci_status_rp hci_write_local_name_rp; #define HCI_CMD_READ_LOCAL_NAME 0x0C14 /* No command parameter(s) */ typedef struct { - uint8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ char name[HCI_UNIT_NAME_SIZE]; /* unit name */ } __attribute__ ((__packed__)) hci_read_local_name_rp; @@ -1017,7 +1140,7 @@ typedef hci_status_rp hci_write_scan_enable_rp; #define HCI_CMD_READ_PAGE_SCAN_ACTIVITY 0x0C1B /* No command parameter(s) */ typedef struct { - uint8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ uint16_t page_scan_interval; /* interval * 0.625 msec */ uint16_t page_scan_window; /* window * 0.625 msec */ } __attribute__ ((__packed__)) hci_read_page_scan_activity_rp; @@ -1035,7 +1158,7 @@ typedef hci_status_rp hci_write_page_scan_activity_rp; #define HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY 0x0C1D /* No command parameter(s) */ typedef struct { - uint8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ uint16_t inquiry_scan_interval; /* interval * 0.625 msec */ uint16_t inquiry_scan_window; /* window * 0.625 msec */ } __attribute__ ((__packed__)) hci_read_inquiry_scan_activity_rp; @@ -1065,14 +1188,16 @@ typedef struct { typedef hci_status_rp hci_write_auth_enable_rp; +/* Read Encryption Mode is deprecated */ #define HCI_OCF_READ_ENCRYPTION_MODE 0x0021 #define HCI_CMD_READ_ENCRYPTION_MODE 0x0C21 /* No command parameter(s) */ typedef struct { - uint8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ uint8_t encryption_mode; /* encryption mode */ } __attribute__ ((__packed__)) hci_read_encryption_mode_rp; +/* Write Encryption Mode is deprecated */ #define HCI_OCF_WRITE_ENCRYPTION_MODE 0x0022 #define HCI_CMD_WRITE_ENCRYPTION_MODE 0x0C22 typedef struct { @@ -1085,7 +1210,7 @@ typedef hci_status_rp hci_write_encryption_mode_rp; #define HCI_CMD_READ_UNIT_CLASS 0x0C23 /* No command parameter(s) */ typedef struct { - uint8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ } __attribute__ ((__packed__)) hci_read_unit_class_rp; @@ -1157,7 +1282,7 @@ typedef hci_status_rp hci_write_num_broadcast_retrans_rp; #define HCI_CMD_READ_HOLD_MODE_ACTIVITY 0x0C2B /* No command parameter(s) */ typedef struct { - uint8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ uint8_t hold_mode_activity; /* Hold mode activities */ } __attribute__ ((__packed__)) hci_read_hold_mode_activity_rp; @@ -1279,14 +1404,16 @@ typedef struct { typedef hci_status_rp hci_write_iac_lap_rp; +/* Read Page Scan Period Mode is deprecated */ #define HCI_OCF_READ_PAGE_SCAN_PERIOD 0x003b #define HCI_CMD_READ_PAGE_SCAN_PERIOD 0x0C3B /* No command parameter(s) */ typedef struct { - uint8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ uint8_t page_scan_period_mode; /* Page scan period mode */ } __attribute__ ((__packed__)) hci_read_page_scan_period_rp; +/* Write Page Scan Period Mode is deprecated */ #define HCI_OCF_WRITE_PAGE_SCAN_PERIOD 0x003c #define HCI_CMD_WRITE_PAGE_SCAN_PERIOD 0x0C3C typedef struct { @@ -1300,7 +1427,7 @@ typedef hci_status_rp hci_write_page_scan_period_rp; #define HCI_CMD_READ_PAGE_SCAN 0x0C3D /* No command parameter(s) */ typedef struct { - uint8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ uint8_t page_scan_mode; /* Page scan mode */ } __attribute__ ((__packed__)) hci_read_page_scan_rp; @@ -1389,6 +1516,115 @@ typedef struct { typedef hci_status_rp hci_write_afh_assessment_rp; +#define HCI_OCF_READ_EXTENDED_INQUIRY_RSP 0x0051 +#define HCI_CMD_READ_EXTENDED_INQUIRY_RSP 0x0C51 +/* No command parameter(s) */ + +typedef struct { + uint8_t status; /* 0x00 - success */ + uint8_t fec_required; + uint8_t response[240]; +} __attribute__ ((__packed__)) hci_read_extended_inquiry_rsp_rp; + +#define HCI_OCF_WRITE_EXTENDED_INQUIRY_RSP 0x0052 +#define HCI_CMD_WRITE_EXTENDED_INQUIRY_RSP 0x0C52 +typedef struct { + uint8_t fec_required; + uint8_t response[240]; +} __attribute__ ((__packed__)) hci_write_extended_inquiry_rsp_cp; + +typedef hci_status_rp hci_write_extended_inquiry_rsp_rp; + +#define HCI_OCF_REFRESH_ENCRYPTION_KEY 0x0053 +#define HCI_CMD_REFRESH_ENCRYPTION_KEY 0x0C53 +typedef struct { + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_refresh_encryption_key_cp; + +typedef hci_status_rp hci_refresh_encryption_key_rp; + +#define HCI_OCF_READ_SIMPLE_PAIRING_MODE 0x0055 +#define HCI_CMD_READ_SIMPLE_PAIRING_MODE 0x0C55 +/* No command parameter(s) */ + +typedef struct { + uint8_t status; /* 0x00 - success */ + uint8_t mode; /* simple pairing mode */ +} __attribute__ ((__packed__)) hci_read_simple_pairing_mode_rp; + +#define HCI_OCF_WRITE_SIMPLE_PAIRING_MODE 0x0056 +#define HCI_CMD_WRITE_SIMPLE_PAIRING_MODE 0x0C56 +typedef struct { + uint8_t mode; /* simple pairing mode */ +} __attribute__ ((__packed__)) hci_write_simple_pairing_mode_cp; + +typedef hci_status_rp hci_write_simple_pairing_mode_rp; + +#define HCI_OCF_READ_LOCAL_OOB_DATA 0x0057 +#define HCI_CMD_READ_LOCAL_OOB_DATA 0x0C57 +/* No command parameter(s) */ + +typedef struct { + uint8_t status; /* 0x00 - success */ + uint8_t c[16]; /* pairing hash */ + uint8_t r[16]; /* pairing randomizer */ +} __attribute__ ((__packed__)) hci_read_local_oob_data_rp; + +#define HCI_OCF_READ_INQUIRY_RSP_XMIT_POWER 0x0058 +#define HCI_CMD_READ_INQUIRY_RSP_XMIT_POWER 0x0C58 +/* No command parameter(s) */ + +typedef struct { + uint8_t status; /* 0x00 - success */ + int8_t power; /* TX power */ +} __attribute__ ((__packed__)) hci_read_inquiry_rsp_xmit_power_rp; + +#define HCI_OCF_WRITE_INQUIRY_RSP_XMIT_POWER 0x0059 +#define HCI_CMD_WRITE_INQUIRY_RSP_XMIT_POWER 0x0C59 +typedef struct { + int8_t power; /* TX power */ +} __attribute__ ((__packed__)) hci_write_inquiry_rsp_xmit_power_cp; + +typedef hci_status_rp hci_write_inquiry_rsp_xmit_power_rp; + +#define HCI_OCF_READ_DEFAULT_ERRDATA_REPORTING 0x005A +#define HCI_CMD_READ_DEFAULT_ERRDATA_REPORTING 0x0C5A +/* No command parameter(s) */ + +typedef struct { + uint8_t status; /* 0x00 - success */ + uint8_t reporting; /* erroneous data reporting */ +} __attribute__ ((__packed__)) hci_read_default_errdata_reporting_rp; + +#define HCI_OCF_WRITE_DEFAULT_ERRDATA_REPORTING 0x005B +#define HCI_CMD_WRITE_DEFAULT_ERRDATA_REPORTING 0x0C5B +typedef struct { + uint8_t reporting; /* erroneous data reporting */ +} __attribute__ ((__packed__)) hci_write_default_errdata_reporting_cp; + +typedef hci_status_rp hci_write_default_errdata_reporting_rp; + +#define HCI_OCF_ENHANCED_FLUSH 0x005F +#define HCI_CMD_ENHANCED_FLUSH 0x0C5F +typedef struct { + uint16_t con_handle; /* connection handle */ + uint8_t packet_type; +} __attribute__ ((__packed__)) hci_enhanced_flush_cp; + +/* No response parameter(s) */ + +#define HCI_OCF_SEND_KEYPRESS_NOTIFICATION 0x0060 +#define HCI_CMD_SEND_KEYPRESS_NOTIFICATION 0x0C60 +typedef struct { + bdaddr_t bdaddr; /* remote address */ + uint8_t type; /* notification type */ +} __attribute__ ((__packed__)) hci_send_keypress_notification_cp; + +typedef struct { + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ +} __attribute__ ((__packed__)) hci_send_keypress_notification_rp; + /************************************************************************** ************************************************************************** ** OGF 0x04 Informational commands and return parameters @@ -1401,7 +1637,7 @@ typedef hci_status_rp hci_write_afh_assessment_rp; #define HCI_CMD_READ_LOCAL_VER 0x1001 /* No command parameter(s) */ typedef struct { - uint8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ uint8_t hci_version; /* HCI version */ uint16_t hci_revision; /* HCI revision */ uint8_t lmp_version; /* LMP version */ @@ -1414,14 +1650,14 @@ typedef struct { /* No command parameter(s) */ typedef struct { uint8_t status; /* 0x00 - success */ - uint8_t commands[64]; /* opcode bitmask */ + uint8_t commands[HCI_COMMANDS_SIZE]; /* opcode bitmask */ } __attribute__ ((__packed__)) hci_read_local_commands_rp; #define HCI_OCF_READ_LOCAL_FEATURES 0x0003 #define HCI_CMD_READ_LOCAL_FEATURES 0x1003 /* No command parameter(s) */ typedef struct { - uint8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ } __attribute__ ((__packed__)) hci_read_local_features_rp; @@ -1578,6 +1814,14 @@ typedef hci_status_rp hci_write_loopback_mode_rp; /* No command parameter(s) */ typedef hci_status_rp hci_enable_unit_under_test_rp; +#define HCI_OCF_WRITE_SIMPLE_PAIRING_DEBUG_MODE 0x0004 +#define HCI_CMD_WRITE_SIMPLE_PAIRING_DEBUG_MODE 0x1804 +typedef struct { + uint8_t mode; /* simple pairing debug mode */ +} __attribute__ ((__packed__)) hci_write_simple_pairing_debug_mode_cp; + +typedef hci_status_rp hci_write_simple_pairing_debug_mode_rp; + /************************************************************************** ************************************************************************** ** OGF 0x3e Bluetooth Logo Testing @@ -1615,28 +1859,28 @@ typedef struct { } __attribute__ ((__packed__)) hci_inquiry_result_ep; typedef struct { - bdaddr_t bdaddr; /* unit address */ + bdaddr_t bdaddr; /* unit address */ uint8_t page_scan_rep_mode; /* page scan rep. mode */ uint8_t page_scan_period_mode; /* page scan period mode */ - uint8_t page_scan_mode; /* page scan mode */ + uint8_t page_scan_mode; /* page scan mode */ uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ - uint16_t clock_offset; /* clock offset */ + uint16_t clock_offset; /* clock offset */ } __attribute__ ((__packed__)) hci_inquiry_response; #define HCI_EVENT_CON_COMPL 0x03 typedef struct { - uint8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ uint16_t con_handle; /* Connection handle */ - bdaddr_t bdaddr; /* remote unit address */ + bdaddr_t bdaddr; /* remote unit address */ uint8_t link_type; /* Link type */ uint8_t encryption_mode; /* Encryption mode */ } __attribute__ ((__packed__)) hci_con_compl_ep; #define HCI_EVENT_CON_REQ 0x04 typedef struct { - bdaddr_t bdaddr; /* remote unit address */ + bdaddr_t bdaddr; /* remote unit address */ uint8_t uclass[HCI_CLASS_SIZE]; /* remote unit class */ - uint8_t link_type; /* link type */ + uint8_t link_type; /* link type */ } __attribute__ ((__packed__)) hci_con_req_ep; #define HCI_EVENT_DISCON_COMPL 0x05 @@ -1654,16 +1898,16 @@ typedef struct { #define HCI_EVENT_REMOTE_NAME_REQ_COMPL 0x07 typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote unit address */ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote unit address */ char name[HCI_UNIT_NAME_SIZE]; /* remote unit name */ } __attribute__ ((__packed__)) hci_remote_name_req_compl_ep; #define HCI_EVENT_ENCRYPTION_CHANGE 0x08 typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* Connection handle */ - uint8_t encryption_enable; /* 0x00 - disable */ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* Connection handle */ + uint8_t encryption_enable; /* 0x00 - disable */ } __attribute__ ((__packed__)) hci_encryption_change_ep; #define HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL 0x09 @@ -1681,14 +1925,14 @@ typedef struct { #define HCI_EVENT_READ_REMOTE_FEATURES_COMPL 0x0b typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* Connection handle */ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* Connection handle */ uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ } __attribute__ ((__packed__)) hci_read_remote_features_compl_ep; #define HCI_EVENT_READ_REMOTE_VER_INFO_COMPL 0x0c typedef struct { - uint8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ uint16_t con_handle; /* Connection handle */ uint8_t lmp_version; /* LMP version */ uint16_t manufacturer; /* Hardware manufacturer name */ @@ -1697,13 +1941,13 @@ typedef struct { #define HCI_EVENT_QOS_SETUP_COMPL 0x0d typedef struct { - uint8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ uint16_t con_handle; /* connection handle */ - uint8_t flags; /* reserved for future use */ + uint8_t flags; /* reserved for future use */ uint8_t service_type; /* service type */ uint32_t token_rate; /* bytes per second */ uint32_t peak_bandwidth; /* bytes per second */ - uint32_t latency; /* microseconds */ + uint32_t latency; /* microseconds */ uint32_t delay_variation; /* microseconds */ } __attribute__ ((__packed__)) hci_qos_setup_compl_ep; @@ -1774,9 +2018,9 @@ typedef struct { #define HCI_EVENT_LINK_KEY_NOTIFICATION 0x18 typedef struct { - bdaddr_t bdaddr; /* remote unit address */ + bdaddr_t bdaddr; /* remote unit address */ uint8_t key[HCI_KEY_SIZE]; /* link key */ - uint8_t key_type; /* type of the key */ + uint8_t key_type; /* type of the key */ } __attribute__ ((__packed__)) hci_link_key_notification_ep; #define HCI_EVENT_LOOPBACK_COMMAND 0x19 @@ -1815,13 +2059,13 @@ typedef struct { /* Page Scan Mode Change Event is deprecated */ #define HCI_EVENT_PAGE_SCAN_MODE_CHANGE 0x1f typedef struct { - bdaddr_t bdaddr; /* destination address */ + bdaddr_t bdaddr; /* destination address */ uint8_t page_scan_mode; /* page scan mode */ } __attribute__ ((__packed__)) hci_page_scan_mode_change_ep; #define HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE 0x20 typedef struct { - bdaddr_t bdaddr; /* destination address */ + bdaddr_t bdaddr; /* destination address */ uint8_t page_scan_rep_mode; /* page scan repetition mode */ } __attribute__ ((__packed__)) hci_page_scan_rep_mode_change_ep; @@ -1851,7 +2095,7 @@ typedef struct { uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ uint16_t clock_offset; /* clock offset */ int8_t rssi; /* rssi */ -} __attribute__ ((__packed__)) hci_rssi_response_ep; +} __attribute__ ((__packed__)) hci_rssi_response; #define HCI_EVENT_READ_REMOTE_EXTENDED_FEATURES 0x23 typedef struct { @@ -1885,6 +2129,98 @@ typedef struct { uint16_t txlen; /* tx packet length */ } __attribute__ ((__packed__)) hci_sco_con_changed_ep; +#define HCI_EVENT_SNIFF_SUBRATING 0x2e +typedef struct { + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint16_t tx_latency; /* max transmit latency */ + uint16_t rx_latency; /* max receive latency */ + uint16_t remote_timeout; /* remote timeout */ + uint16_t local_timeout; /* local timeout */ +} __attribute__ ((__packed__)) hci_sniff_subrating_ep; + +#define HCI_EVENT_EXTENDED_RESULT 0x2f +typedef struct { + uint8_t num_responses; /* must be 0x01 */ + bdaddr_t bdaddr; /* remote device address */ + uint8_t page_scan_rep_mode; + uint8_t reserved; + uint8_t uclass[HCI_CLASS_SIZE]; + uint16_t clock_offset; + int8_t rssi; + uint8_t response[240]; /* extended inquiry response */ +} __attribute__ ((__packed__)) hci_extended_result_ep; + +#define HCI_EVENT_ENCRYPTION_KEY_REFRESH 0x30 +typedef struct { + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_encryption_key_refresh_ep; + +#define HCI_EVENT_IO_CAPABILITY_REQ 0x31 +typedef struct { + bdaddr_t bdaddr; /* remote device address */ +} __attribute__ ((__packed__)) hci_io_capability_req_ep; + +#define HCI_EVENT_IO_CAPABILITY_RSP 0x32 +typedef struct { + bdaddr_t bdaddr; /* remote device address */ + uint8_t io_capability; + uint8_t oob_data_present; + uint8_t auth_requirement; +} __attribute__ ((__packed__)) hci_io_capability_rsp_ep; + +#define HCI_EVENT_USER_CONFIRM_REQ 0x33 +typedef struct { + bdaddr_t bdaddr; /* remote device address */ + uint32_t value; /* 000000 - 999999 */ +} __attribute__ ((__packed__)) hci_user_confirm_req_ep; + +#define HCI_EVENT_USER_PASSKEY_REQ 0x34 +typedef struct { + bdaddr_t bdaddr; /* remote device address */ +} __attribute__ ((__packed__)) hci_user_passkey_req_ep; + +#define HCI_EVENT_REMOTE_OOB_DATA_REQ 0x35 +typedef struct { + bdaddr_t bdaddr; /* remote device address */ +} __attribute__ ((__packed__)) hci_remote_oob_data_req_ep; + +#define HCI_EVENT_SIMPLE_PAIRING_COMPL 0x36 +typedef struct { + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote device address */ +} __attribute__ ((__packed__)) hci_simple_pairing_compl_ep; + +#define HCI_EVENT_LINK_SUPERVISION_TO_CHANGED 0x38 +typedef struct { + uint16_t con_handle; /* connection handle */ + uint16_t timeout; /* link supervision timeout */ +} __attribute__ ((__packed__)) hci_link_supervision_to_changed_ep; + +#define HCI_EVENT_ENHANCED_FLUSH_COMPL 0x39 +typedef struct { + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_enhanced_flush_compl_ep; + +#define HCI_EVENT_USER_PASSKEY_NOTIFICATION 0x3b +typedef struct { + bdaddr_t bdaddr; /* remote device address */ + uint32_t value; /* 000000 - 999999 */ +} __attribute__ ((__packed__)) hci_user_passkey_notification_ep; + +#define HCI_EVENT_KEYPRESS_NOTIFICATION 0x3c +typedef struct { + bdaddr_t bdaddr; /* remote device address */ + uint8_t notification_type; +} __attribute__ ((__packed__)) hci_keypress_notification_ep; + +#define HCI_EVENT_REMOTE_FEATURES_NOTIFICATION 0x3d +typedef struct { + bdaddr_t bdaddr; /* remote device address */ + uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ +} __attribute__ ((__packed__)) hci_remote_features_notification_ep; + #define HCI_EVENT_BT_LOGO 0xfe #define HCI_EVENT_VENDOR 0xff @@ -2000,7 +2336,6 @@ struct btreq { #define btr_sco_mtu btru.btri.btri_sco_mtu #define btr_link_policy btru.btri.btri_link_policy #define btr_packet_type btru.btri.btri_packet_type -#define btr_uclass btru.btri.btri_uclass #define btr_stats btru.btrs /* hci_unit & btr_flags */ @@ -2013,7 +2348,13 @@ struct btreq { #define BTF_INIT_BDADDR (1<<5) /* waiting for bdaddr */ #define BTF_INIT_BUFFER_SIZE (1<<6) /* waiting for buffer size */ #define BTF_INIT_FEATURES (1<<7) /* waiting for features */ -#define BTF_INIT (BTF_INIT_BDADDR | BTF_INIT_BUFFER_SIZE | BTF_INIT_FEATURES) +#define BTF_POWER_UP_NOOP (1<<8) /* should wait for No-op on power up */ +#define BTF_INIT_COMMANDS (1<<9) /* waiting for supported commands */ + +#define BTF_INIT (BTF_INIT_BDADDR \ + | BTF_INIT_BUFFER_SIZE \ + | BTF_INIT_FEATURES \ + | BTF_INIT_COMMANDS) /************************************************************************** ************************************************************************** @@ -2057,6 +2398,7 @@ struct hci_link { uint16_t hl_refcnt; /* reference count */ uint16_t hl_mtu; /* signalling mtu for link */ uint16_t hl_flush; /* flush timeout */ + uint16_t hl_clock; /* remote clock offset */ TAILQ_HEAD(,l2cap_pdu) hl_txq; /* queue of outgoing PDUs */ int hl_txqlen; /* number of fragments */ @@ -2093,21 +2435,36 @@ struct hci_link { */ struct hci_memo { struct timeval time; /* time of last response */ - hci_inquiry_response response; /* inquiry response */ + bdaddr_t bdaddr; + uint8_t page_scan_rep_mode; + uint8_t page_scan_mode; + uint16_t clock_offset; LIST_ENTRY(hci_memo) next; }; /* + * The Bluetooth HCI interface attachment structure + */ +struct hci_if { + int (*enable)(struct device *); + void (*disable)(struct device *); + void (*output_cmd)(struct device *, struct mbuf *); + void (*output_acl)(struct device *, struct mbuf *); + void (*output_sco)(struct device *, struct mbuf *); + void (*get_stats)(struct device *, struct bt_stats *, int); +}; + +/* * The Bluetooth HCI device unit structure */ struct hci_unit { - device_t hci_softc; /* ptr to device softc */ + struct device *hci_dev; /* bthci handle */ #if 0 /* not yet */ - device_t hci_bthub; /* bthub(4) handle */ + device_t hci_bthub; /* bthub(4) handle */ #endif + const struct hci_if *hci_if; /* bthci driver interface */ /* device info */ - char *hci_devname; /* device name */ bdaddr_t hci_bdaddr; /* device address */ uint16_t hci_flags; /* see BTF_ above */ @@ -2118,6 +2475,8 @@ struct hci_unit { uint16_t hci_link_policy; /* link policy */ uint16_t hci_lmp_mask; /* link policy capabilities */ + uint8_t hci_cmds[HCI_COMMANDS_SIZE]; /* opcode bitmask */ + /* flow control */ uint16_t hci_max_acl_size; /* ACL payload mtu */ uint16_t hci_num_acl_pkts; /* free ACL packet buffers */ @@ -2128,24 +2487,9 @@ struct hci_unit { TAILQ_HEAD(,hci_link) hci_links; /* list of ACL/SCO links */ LIST_HEAD(,hci_memo) hci_memos; /* cached memo list */ - /* - * h/w driver callbacks - * - * the device driver must supply these. - */ - int (*hci_enable) /* enable device */ - (struct hci_unit *); - void (*hci_disable) /* disable device */ - (struct hci_unit *); - void (*hci_start_cmd) /* initiate cmd output routine */ - (struct hci_unit *); - void (*hci_start_acl) /* initiate acl output routine */ - (struct hci_unit *); - void (*hci_start_sco) /* initiate sco output routine */ - (struct hci_unit *); - int hci_ipl; /* to block queue operations */ - /* input queues */ + void *hci_rxint; /* receive interrupt cookie */ + struct lock hci_devlock; /* device queue lock */ struct ifqueue hci_eventq; /* Event queue */ struct ifqueue hci_aclrxq; /* ACL rx queue */ struct ifqueue hci_scorxq; /* SCO rx queue */ @@ -2155,13 +2499,8 @@ struct hci_unit { /* output queues */ struct ifqueue hci_cmdwait; /* pending commands */ - struct ifqueue hci_cmdq; /* Command queue */ - struct ifqueue hci_acltxq; /* ACL tx queue */ - struct ifqueue hci_scotxq; /* SCO tx queue */ struct ifqueue hci_scodone; /* SCO done queue */ - struct bt_stats hci_stats; /* unit statistics */ - TAILQ_ENTRY(hci_unit) hci_next; }; @@ -2201,6 +2540,7 @@ struct hci_link *hci_link_lookup_handle(struct hci_unit *, uint16_t); /* hci_misc.c */ int hci_route_lookup(bdaddr_t *, bdaddr_t *); struct hci_memo *hci_memo_find(struct hci_unit *, bdaddr_t *); +struct hci_memo *hci_memo_new(struct hci_unit *, bdaddr_t *); void hci_memo_free(struct hci_memo *); /* hci_socket.c */ @@ -2210,16 +2550,16 @@ int hci_ctloutput(struct socket *so, struct sockopt *sopt); void hci_mtap(struct mbuf *, struct hci_unit *); /* hci_unit.c */ -void hci_attach(struct hci_unit *); +struct hci_unit *hci_attach(const struct hci_if *, struct device *, uint16_t); void hci_detach(struct hci_unit *); int hci_enable(struct hci_unit *); void hci_disable(struct hci_unit *); struct hci_unit *hci_unit_lookup(bdaddr_t *); int hci_send_cmd(struct hci_unit *, uint16_t, void *, uint8_t); -void hci_input_event(struct hci_unit *, struct mbuf *); -void hci_input_acl(struct hci_unit *, struct mbuf *); -void hci_input_sco(struct hci_unit *, struct mbuf *); -void hci_complete_sco(struct hci_unit *, struct mbuf *); +int hci_input_event(struct hci_unit *, struct mbuf *); +int hci_input_acl(struct hci_unit *, struct mbuf *); +int hci_input_sco(struct hci_unit *, struct mbuf *); +int hci_complete_sco(struct hci_unit *, struct mbuf *); void hci_output_cmd(struct hci_unit *, struct mbuf *); void hci_output_acl(struct hci_unit *, struct mbuf *); void hci_output_sco(struct hci_unit *, struct mbuf *); diff --git a/sys/netbt/hci_event.c b/sys/netbt/hci_event.c index 5b0981f8a5..4fc277955c 100644 --- a/sys/netbt/hci_event.c +++ b/sys/netbt/hci_event.c @@ -1,6 +1,6 @@ -/* $OpenBSD: hci_event.c,v 1.6 2007/10/01 16:39:30 krw Exp $ */ -/* $NetBSD: hci_event.c,v 1.6 2007/04/21 06:15:23 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/hci_event.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/hci_event.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/hci_event.c,v 1.7 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: hci_event.c,v 1.14 2008/02/10 17:40:54 plunky Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. @@ -32,8 +32,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include - #include #include #include @@ -48,6 +46,7 @@ #include static void hci_event_inquiry_result(struct hci_unit *, struct mbuf *); +static void hci_event_rssi_result(struct hci_unit *, struct mbuf *); static void hci_event_command_status(struct hci_unit *, struct mbuf *); static void hci_event_command_compl(struct hci_unit *, struct mbuf *); static void hci_event_con_compl(struct hci_unit *, struct mbuf *); @@ -57,9 +56,12 @@ static void hci_event_num_compl_pkts(struct hci_unit *, struct mbuf *); static void hci_event_auth_compl(struct hci_unit *, struct mbuf *); static void hci_event_encryption_change(struct hci_unit *, struct mbuf *); static void hci_event_change_con_link_key_compl(struct hci_unit *, struct mbuf *); +static void hci_event_read_clock_offset_compl(struct hci_unit *, struct mbuf *); static void hci_cmd_read_bdaddr(struct hci_unit *, struct mbuf *); static void hci_cmd_read_buffer_size(struct hci_unit *, struct mbuf *); static void hci_cmd_read_local_features(struct hci_unit *, struct mbuf *); +static void hci_cmd_read_local_ver(struct hci_unit *, struct mbuf *); +static void hci_cmd_read_local_commands(struct hci_unit *, struct mbuf *); static void hci_cmd_reset(struct hci_unit *, struct mbuf *); #ifdef BLUETOOTH_DEBUG @@ -101,7 +103,33 @@ static const char *hci_eventnames[] = { /* 0x20 */ "PAGE SCAN REP MODE CHANGE", /* 0x21 */ "FLOW SPECIFICATION COMPLETE", /* 0x22 */ "RSSI RESULT", -/* 0x23 */ "READ REMOTE EXT FEATURES" +/* 0x23 */ "READ REMOTE EXT FEATURES", +/* 0x24 */ "UNKNOWN", +/* 0x25 */ "UNKNOWN", +/* 0x26 */ "UNKNOWN", +/* 0x27 */ "UNKNOWN", +/* 0x28 */ "UNKNOWN", +/* 0x29 */ "UNKNOWN", +/* 0x2a */ "UNKNOWN", +/* 0x2b */ "UNKNOWN", +/* 0x2c */ "SCO CON COMPLETE", +/* 0x2d */ "SCO CON CHANGED", +/* 0x2e */ "SNIFF SUBRATING", +/* 0x2f */ "EXTENDED INQUIRY RESULT", +/* 0x30 */ "ENCRYPTION KEY REFRESH", +/* 0x31 */ "IO CAPABILITY REQUEST", +/* 0x32 */ "IO CAPABILITY RESPONSE", +/* 0x33 */ "USER CONFIRM REQUEST", +/* 0x34 */ "USER PASSKEY REQUEST", +/* 0x35 */ "REMOTE OOB DATA REQUEST", +/* 0x36 */ "SIMPLE PAIRING COMPLETE", +/* 0x37 */ "UNKNOWN", +/* 0x38 */ "LINK SUPERVISION TIMEOUT CHANGED", +/* 0x39 */ "ENHANCED FLUSH COMPLETE", +/* 0x3a */ "UNKNOWN", +/* 0x3b */ "USER PASSKEY NOTIFICATION", +/* 0x3c */ "KEYPRESS NOTIFICATION", +/* 0x3d */ "REMOTE HOST FEATURES NOTIFICATION", }; static const char * @@ -112,12 +140,6 @@ hci_eventstr(unsigned int event) return hci_eventnames[event]; switch (event) { - case HCI_EVENT_SCO_CON_COMPL: /* 0x2c */ - return "SCO CON COMPLETE"; - - case HCI_EVENT_SCO_CON_CHANGED: /* 0x2d */ - return "SCO CON CHANGED"; - case HCI_EVENT_BT_LOGO: /* 0xfe */ return "BT_LOGO"; @@ -125,7 +147,7 @@ hci_eventstr(unsigned int event) return "VENDOR"; } - return "UNRECOGNISED"; + return "UNKNOWN"; } #endif /* BLUETOOTH_DEBUG */ @@ -135,7 +157,6 @@ hci_eventstr(unsigned int event) * We will free the mbuf at the end, no need for any sub * functions to handle that. We kind of assume that the * device sends us valid events. - * XXX "kind of"? This needs to be fixed. */ void hci_event(struct mbuf *m, struct hci_unit *unit) @@ -150,7 +171,8 @@ hci_event(struct mbuf *m, struct hci_unit *unit) KKASSERT(hdr.type == HCI_EVENT_PKT); - DPRINTFN(1, "(%s) event %s\n", unit->hci_devname, hci_eventstr(hdr.event)); + DPRINTFN(1, "(%s) event %s\n", + device_get_nameunit(unit->hci_dev), hci_eventstr(hdr.event)); switch(hdr.event) { case HCI_EVENT_COMMAND_STATUS: @@ -169,6 +191,10 @@ hci_event(struct mbuf *m, struct hci_unit *unit) hci_event_inquiry_result(unit, m); break; + case HCI_EVENT_RSSI_RESULT: + hci_event_rssi_result(unit, m); + break; + case HCI_EVENT_CON_COMPL: hci_event_con_compl(unit, m); break; @@ -193,39 +219,11 @@ hci_event(struct mbuf *m, struct hci_unit *unit) hci_event_change_con_link_key_compl(unit, m); break; - case HCI_EVENT_SCO_CON_COMPL: - case HCI_EVENT_INQUIRY_COMPL: - case HCI_EVENT_REMOTE_NAME_REQ_COMPL: - case HCI_EVENT_MASTER_LINK_KEY_COMPL: - case HCI_EVENT_READ_REMOTE_FEATURES_COMPL: - case HCI_EVENT_READ_REMOTE_VER_INFO_COMPL: - case HCI_EVENT_QOS_SETUP_COMPL: - case HCI_EVENT_HARDWARE_ERROR: - case HCI_EVENT_FLUSH_OCCUR: - case HCI_EVENT_ROLE_CHANGE: - case HCI_EVENT_MODE_CHANGE: - case HCI_EVENT_RETURN_LINK_KEYS: - case HCI_EVENT_PIN_CODE_REQ: - case HCI_EVENT_LINK_KEY_REQ: - case HCI_EVENT_LINK_KEY_NOTIFICATION: - case HCI_EVENT_LOOPBACK_COMMAND: - case HCI_EVENT_DATA_BUFFER_OVERFLOW: - case HCI_EVENT_MAX_SLOT_CHANGE: case HCI_EVENT_READ_CLOCK_OFFSET_COMPL: - case HCI_EVENT_CON_PKT_TYPE_CHANGED: - case HCI_EVENT_QOS_VIOLATION: - case HCI_EVENT_PAGE_SCAN_MODE_CHANGE: - case HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE: - case HCI_EVENT_FLOW_SPECIFICATION_COMPL: - case HCI_EVENT_RSSI_RESULT: - case HCI_EVENT_READ_REMOTE_EXTENDED_FEATURES: - case HCI_EVENT_SCO_CON_CHANGED: - case HCI_EVENT_BT_LOGO: - case HCI_EVENT_VENDOR: + hci_event_read_clock_offset_compl(unit, m); break; default: - UNKNOWN(hdr.event); break; } @@ -249,11 +247,17 @@ hci_event_command_status(struct hci_unit *unit, struct mbuf *m) m_adj(m, sizeof(ep)); DPRINTFN(1, "(%s) opcode (%03x|%04x) status = 0x%x num_cmd_pkts = %d\n", - unit->hci_devname, + device_get_nameunit(unit->hci_dev), HCI_OGF(letoh16(ep.opcode)), HCI_OCF(letoh16(ep.opcode)), ep.status, ep.num_cmd_pkts); + if (ep.status > 0) + kprintf("%s: CommandStatus opcode (%03x|%04x) failed " + "(status=0x%02x)\n", device_get_nameunit(unit->hci_dev), + HCI_OGF(letoh16(ep.opcode)), + HCI_OCF(letoh16(ep.opcode)), ep.status); + unit->hci_num_cmd_pkts = ep.num_cmd_pkts; /* @@ -264,7 +268,7 @@ hci_event_command_status(struct hci_unit *unit, struct mbuf *m) switch (ep.status) { case 0x12: /* Invalid HCI command parameters */ DPRINTF("(%s) Invalid HCI command parameters\n", - unit->hci_devname); + device_get_nameunit(unit->hci_dev)); while ((link = hci_link_lookup_state(unit, HCI_LINK_ACL, HCI_LINK_WAIT_CONNECT)) != NULL) hci_link_free(link, ECONNABORTED); @@ -291,16 +295,28 @@ static void hci_event_command_compl(struct hci_unit *unit, struct mbuf *m) { hci_command_compl_ep ep; + hci_status_rp rp; KKASSERT(m->m_pkthdr.len >= sizeof(ep)); m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); m_adj(m, sizeof(ep)); DPRINTFN(1, "(%s) opcode (%03x|%04x) num_cmd_pkts = %d\n", - unit->hci_devname, + device_get_nameunit(unit->hci_dev), HCI_OGF(letoh16(ep.opcode)), HCI_OCF(letoh16(ep.opcode)), ep.num_cmd_pkts); + /* + * I am not sure if this is completely correct, it is not guaranteed + * that a command_complete packet will contain the status though most + * do seem to. + */ + m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); + if (rp.status > 0) + kprintf("%s: CommandComplete opcode (%03x|%04x) failed (status=0x%02x)\n", + device_get_nameunit(unit->hci_dev), HCI_OGF(letoh16(ep.opcode)), + HCI_OCF(letoh16(ep.opcode)), rp.status); + unit->hci_num_cmd_pkts = ep.num_cmd_pkts; /* @@ -319,6 +335,14 @@ hci_event_command_compl(struct hci_unit *unit, struct mbuf *m) hci_cmd_read_local_features(unit, m); break; + case HCI_CMD_READ_LOCAL_VER: + hci_cmd_read_local_ver(unit, m); + break; + + case HCI_CMD_READ_LOCAL_COMMANDS: + hci_cmd_read_local_commands(unit, m); + break; + case HCI_CMD_RESET: hci_cmd_reset(unit, m); break; @@ -375,9 +399,9 @@ hci_event_num_compl_pkts(struct hci_unit *unit, struct mbuf *m) } else { /* XXX need to issue Read_Buffer_Size or Reset? */ kprintf("%s: unknown handle %d! " - "(losing track of %d packet buffer%s)\n", - unit->hci_devname, handle, - num, (num == 1 ? "" : "s")); + "(losing track of %d packet buffer%s)\n", + device_get_nameunit(unit->hci_dev), handle, + num, (num == 1 ? "" : "s")); } } @@ -418,42 +442,68 @@ static void hci_event_inquiry_result(struct hci_unit *unit, struct mbuf *m) { hci_inquiry_result_ep ep; + hci_inquiry_response ir; struct hci_memo *memo; - bdaddr_t bdaddr; KKASSERT(m->m_pkthdr.len >= sizeof(ep)); m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); m_adj(m, sizeof(ep)); - DPRINTFN(1, "%d response%s\n", ep.num_responses, - (ep.num_responses == 1 ? "" : "s")); + DPRINTFN(1, "(%s) %d response%s\n", device_get_nameunit(unit->hci_dev), + ep.num_responses, (ep.num_responses == 1 ? "" : "s")); while(ep.num_responses--) { - m_copydata(m, 0, sizeof(bdaddr_t), (caddr_t)&bdaddr); + KKASSERT(m->m_pkthdr.len >= sizeof(ir)); + m_copydata(m, 0, sizeof(ir), (caddr_t)&ir); + m_adj(m, sizeof(ir)); DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n", - bdaddr.b[5], bdaddr.b[4], bdaddr.b[3], - bdaddr.b[2], bdaddr.b[1], bdaddr.b[0]); - - memo = hci_memo_find(unit, &bdaddr); - if (memo == NULL) { - memo = kmalloc(sizeof(*memo), M_BLUETOOTH, - M_NOWAIT | M_ZERO); - if (memo == NULL) { - DPRINTFN(0, "out of memo memory!\n"); - break; - } - - LIST_INSERT_HEAD(&unit->hci_memos, memo, next); + ir.bdaddr.b[5], ir.bdaddr.b[4], ir.bdaddr.b[3], + ir.bdaddr.b[2], ir.bdaddr.b[1], ir.bdaddr.b[0]); + + memo = hci_memo_new(unit, &ir.bdaddr); + if (memo != NULL) { + memo->page_scan_rep_mode = ir.page_scan_rep_mode; + memo->page_scan_mode = ir.page_scan_mode; + memo->clock_offset = ir.clock_offset; } + } +} + +/* + * Inquiry Result with RSSI + * + * as above but different packet when RSSI result is enabled + */ +static void +hci_event_rssi_result(struct hci_unit *unit, struct mbuf *m) +{ + hci_rssi_result_ep ep; + hci_rssi_response rr; + struct hci_memo *memo; - microtime(&memo->time); - m_copydata(m, 0, sizeof(hci_inquiry_response), - (caddr_t)&memo->response); - m_adj(m, sizeof(hci_inquiry_response)); + KKASSERT(m->m_pkthdr.len >= sizeof(ep)); + m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); + m_adj(m, sizeof(ep)); + + DPRINTFN(1, "%d response%s\n", ep.num_responses, + (ep.num_responses == 1 ? "" : "s")); + + while(ep.num_responses--) { + KKASSERT(m->m_pkthdr.len >= sizeof(rr)); + m_copydata(m, 0, sizeof(rr), (caddr_t)&rr); + m_adj(m, sizeof(rr)); - memo->response.clock_offset = - letoh16(memo->response.clock_offset); + DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n", + rr.bdaddr.b[5], rr.bdaddr.b[4], rr.bdaddr.b[3], + rr.bdaddr.b[2], rr.bdaddr.b[1], rr.bdaddr.b[0]); + + memo = hci_memo_new(unit, &rr.bdaddr); + if (memo != NULL) { + memo->page_scan_rep_mode = rr.page_scan_rep_mode; + memo->page_scan_mode = 0; + memo->clock_offset = rr.clock_offset; + } } } @@ -478,7 +528,7 @@ hci_event_con_compl(struct hci_unit *unit, struct mbuf *m) DPRINTFN(1, "(%s) %s connection complete for " "%02x:%02x:%02x:%02x:%02x:%02x status %#x\n", - unit->hci_devname, + device_get_nameunit(unit->hci_dev), (ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO"), ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3], ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0], @@ -538,8 +588,14 @@ hci_event_con_compl(struct hci_unit *unit, struct mbuf *m) &cp, sizeof(cp)); if (err) kprintf("%s: Warning, could not write link policy\n", - unit->hci_devname); + device_get_nameunit(unit->hci_dev)); + err = hci_send_cmd(unit, HCI_CMD_READ_CLOCK_OFFSET, + &cp.con_handle, sizeof(cp.con_handle)); + if (err) + kprintf("%s: Warning, could not read clock offset\n", + device_get_nameunit(unit->hci_dev)); + err = hci_acl_setmode(link); if (err == EINPROGRESS) return; @@ -568,7 +624,8 @@ hci_event_discon_compl(struct hci_unit *unit, struct mbuf *m) ep.con_handle = letoh16(ep.con_handle); - DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status); + DPRINTFN(1, "(%s) handle #%d, status=0x%x\n", + device_get_nameunit(unit->hci_dev), ep.con_handle, ep.status); link = hci_link_lookup_handle(unit, HCI_CON_HANDLE(ep.con_handle)); if (link) @@ -593,12 +650,13 @@ hci_event_con_req(struct hci_unit *unit, struct mbuf *m) m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); m_adj(m, sizeof(ep)); - DPRINTFN(1, "bdaddr %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " + DPRINTFN(1, "(%s) bdaddr %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " "class %2.2x%2.2x%2.2x type %s\n", - ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3], - ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0], - ep.uclass[0], ep.uclass[1], ep.uclass[2], - ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO"); + device_get_nameunit(unit->hci_dev), + ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3], + ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0], + ep.uclass[0], ep.uclass[1], ep.uclass[2], + ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO"); if (ep.link_type == HCI_LINK_ACL) link = hci_acl_newconn(unit, &ep.bdaddr); @@ -642,7 +700,8 @@ hci_event_auth_compl(struct hci_unit *unit, struct mbuf *m) ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); - DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status); + DPRINTFN(1, "(%s) handle #%d, status=0x%x\n", + device_get_nameunit(unit->hci_dev), ep.con_handle, ep.status); link = hci_link_lookup_handle(unit, ep.con_handle); if (link == NULL || link->hl_type != HCI_LINK_ACL) @@ -684,8 +743,9 @@ hci_event_encryption_change(struct hci_unit *unit, struct mbuf *m) ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); - DPRINTFN(1, "handle #%d, status=0x%x, encryption_enable=0x%x\n", - ep.con_handle, ep.status, ep.encryption_enable); + DPRINTFN(1, "(%s) handle #%d, status=0x%x, encryption_enable=0x%x\n", + device_get_nameunit(unit->hci_dev), ep.con_handle, ep.status, + ep.encryption_enable); link = hci_link_lookup_handle(unit, ep.con_handle); if (link == NULL || link->hl_type != HCI_LINK_ACL) @@ -728,7 +788,8 @@ hci_event_change_con_link_key_compl(struct hci_unit *unit, struct mbuf *m) ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); - DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status); + DPRINTFN(1, "(%s) handle #%d, status=0x%x\n", + device_get_nameunit(unit->hci_dev), ep.con_handle, ep.status); link = hci_link_lookup_handle(unit, ep.con_handle); if (link == NULL || link->hl_type != HCI_LINK_ACL) @@ -751,6 +812,34 @@ hci_event_change_con_link_key_compl(struct hci_unit *unit, struct mbuf *m) } /* + * Read Clock Offset Complete + * + * We keep a note of the clock offset of remote devices when a + * link is made, in order to facilitate reconnections to the device + */ +static void +hci_event_read_clock_offset_compl(struct hci_unit *unit, struct mbuf *m) +{ + hci_read_clock_offset_compl_ep ep; + struct hci_link *link; + + KKASSERT(m->m_pkthdr.len >= sizeof(ep)); + m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); + m_adj(m, sizeof(ep)); + + DPRINTFN(1, "handle #%d, offset=%u, status=0x%x\n", + letoh16(ep.con_handle), letoh16(ep.clock_offset), ep.status); + + ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); + link = hci_link_lookup_handle(unit, ep.con_handle); + + if (ep.status != 0 || link == NULL) + return; + + link->hl_clock = ep.clock_offset; +} + +/* * process results of read_bdaddr command_complete event */ static void @@ -770,9 +859,7 @@ hci_cmd_read_bdaddr(struct hci_unit *unit, struct mbuf *m) bdaddr_copy(&unit->hci_bdaddr, &rp.bdaddr); - crit_enter(); unit->hci_flags &= ~BTF_INIT_BDADDR; - crit_exit(); wakeup(unit); } @@ -800,9 +887,7 @@ hci_cmd_read_buffer_size(struct hci_unit *unit, struct mbuf *m) unit->hci_max_sco_size = rp.max_sco_size; unit->hci_num_sco_pkts = letoh16(rp.num_sco_pkts); - crit_enter(); unit->hci_flags &= ~BTF_INIT_BUFFER_SIZE; - crit_exit(); wakeup(unit); } @@ -890,18 +975,69 @@ hci_cmd_read_local_features(struct hci_unit *unit, struct mbuf *m) /* XXX what do 2MBPS/3MBPS/3SLOT eSCO mean? */ - crit_enter(); unit->hci_flags &= ~BTF_INIT_FEATURES; - crit_exit(); wakeup(unit); DPRINTFN(1, "%s: lmp_mask %4.4x, acl_mask %4.4x, sco_mask %4.4x\n", - unit->hci_devname, unit->hci_lmp_mask, + device_get_nameunit(unit->hci_dev), unit->hci_lmp_mask, unit->hci_acl_mask, unit->hci_sco_mask); } /* + * process results of read_local_ver command_complete event + * + * reading local supported commands is only supported from 1.2 spec + */ +static void +hci_cmd_read_local_ver(struct hci_unit *unit, struct mbuf *m) +{ + hci_read_local_ver_rp rp; + + KKASSERT(m->m_pkthdr.len >= sizeof(rp)); + m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); + m_adj(m, sizeof(rp)); + + if (rp.status != 0) + return; + + if ((unit->hci_flags & BTF_INIT_COMMANDS) == 0) + return; + + if (rp.hci_version < HCI_SPEC_V12) { + unit->hci_flags &= ~BTF_INIT_COMMANDS; + wakeup(unit); + return; + } + + hci_send_cmd(unit, HCI_CMD_READ_LOCAL_COMMANDS, NULL, 0); +} + +/* + * process results of read_local_commands command_complete event + */ +static void +hci_cmd_read_local_commands(struct hci_unit *unit, struct mbuf *m) +{ + hci_read_local_commands_rp rp; + + KKASSERT(m->m_pkthdr.len >= sizeof(rp)); + m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); + m_adj(m, sizeof(rp)); + + if (rp.status != 0) + return; + + if ((unit->hci_flags & BTF_INIT_COMMANDS) == 0) + return; + + unit->hci_flags &= ~BTF_INIT_COMMANDS; + memcpy(unit->hci_cmds, rp.commands, HCI_COMMANDS_SIZE); + + wakeup(unit); +} + +/* * process results of reset command_complete event * * This has killed all the connections, so close down anything we have left, @@ -945,4 +1081,7 @@ hci_cmd_reset(struct hci_unit *unit, struct mbuf *m) if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_FEATURES, NULL, 0)) return; + + if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_VER, NULL, 0)) + return; } diff --git a/sys/netbt/hci_ioctl.c b/sys/netbt/hci_ioctl.c index b1d07510c8..cd1e168166 100644 --- a/sys/netbt/hci_ioctl.c +++ b/sys/netbt/hci_ioctl.c @@ -1,6 +1,6 @@ -/* $OpenBSD: hci_ioctl.c,v 1.1 2007/06/01 02:46:11 uwe Exp $ */ -/* $NetBSD: hci_ioctl.c,v 1.5 2007/01/04 19:07:03 elad Exp $ */ -/* $DragonFly: src/sys/netbt/hci_ioctl.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/hci_ioctl.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/hci_ioctl.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: hci_ioctl.c,v 1.7 2007/11/28 20:16:12 plunky Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. @@ -64,7 +64,7 @@ hci_dump(void) TAILQ_FOREACH(unit, &hci_unit_list, hci_next) { kprintf("UNIT %s: flags 0x%4.4x, " "num_cmd=%d, num_acl=%d, num_sco=%d\n", - unit->hci_devname, unit->hci_flags, + device_get_nameunit(unit->hci_dev), unit->hci_flags, unit->hci_num_cmd_pkts, unit->hci_num_acl_pkts, unit->hci_num_sco_pkts); @@ -177,8 +177,8 @@ hci_ioctl(unsigned long cmd, void *data, struct proc *p) case SIOCZBTSTATS: case SIOCSBTSCOMTU: TAILQ_FOREACH(unit, &hci_unit_list, hci_next) { - if (strncmp(unit->hci_devname, btr->btr_name, - HCI_DEVNAME_SIZE) == 0) + if (strncmp(device_get_nameunit(unit->hci_dev), + btr->btr_name, HCI_DEVNAME_SIZE) == 0) break; } @@ -207,7 +207,8 @@ hci_ioctl(unsigned long cmd, void *data, struct proc *p) case SIOCGBTINFO: /* get unit info */ case SIOCGBTINFOA: /* get info by address */ memset(btr, 0, sizeof(struct btreq)); - strlcpy(btr->btr_name, unit->hci_devname, HCI_DEVNAME_SIZE); + strlcpy(btr->btr_name, device_get_nameunit(unit->hci_dev), + HCI_DEVNAME_SIZE); bdaddr_copy(&btr->btr_bdaddr, &unit->hci_bdaddr); btr->btr_flags = unit->hci_flags; @@ -233,9 +234,7 @@ hci_ioctl(unsigned long cmd, void *data, struct proc *p) unit->hci_flags &= ~BTF_UP; } - crit_enter(); unit->hci_flags |= (btr->btr_flags & BTF_INIT); - crit_exit(); if ((unit->hci_flags & BTF_UP) == 0 && (btr->btr_flags & BTF_UP)) { @@ -243,9 +242,7 @@ hci_ioctl(unsigned long cmd, void *data, struct proc *p) if (err) break; - crit_enter(); unit->hci_flags |= BTF_UP; - crit_exit(); } btr->btr_flags = unit->hci_flags; @@ -272,10 +269,7 @@ hci_ioctl(unsigned long cmd, void *data, struct proc *p) break; case SIOCGBTSTATS: /* get unit statistics */ - crit_enter(); - memcpy(&btr->btr_stats, &unit->hci_stats, - sizeof(struct bt_stats)); - crit_exit(); + (*unit->hci_if->get_stats)(unit->hci_dev, &btr->btr_stats, 0); break; case SIOCZBTSTATS: /* get & reset unit statistics */ @@ -283,12 +277,7 @@ hci_ioctl(unsigned long cmd, void *data, struct proc *p) if (err) break; - crit_enter(); - memcpy(&btr->btr_stats, &unit->hci_stats, - sizeof(struct bt_stats)); - memset(&unit->hci_stats, 0, sizeof(struct bt_stats)); - crit_exit(); - + (*unit->hci_if->get_stats)(unit->hci_dev, &btr->btr_stats, 1); break; case SIOCSBTSCOMTU: /* set sco_mtu value for unit */ diff --git a/sys/netbt/hci_link.c b/sys/netbt/hci_link.c index d462bc4b92..d6c739df9c 100644 --- a/sys/netbt/hci_link.c +++ b/sys/netbt/hci_link.c @@ -1,6 +1,6 @@ -/* $OpenBSD: hci_link.c,v 1.6 2007/09/17 01:33:33 krw Exp $ */ -/* $NetBSD: hci_link.c,v 1.11 2007/04/21 06:15:23 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/hci_link.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/hci_link.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/hci_link.c,v 1.7 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: hci_link.c,v 1.16 2007/11/10 23:12:22 plunky Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. @@ -32,8 +32,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include - #include #include #include @@ -102,9 +100,9 @@ hci_acl_open(struct hci_unit *unit, bdaddr_t *bdaddr) memo = hci_memo_find(unit, bdaddr); if (memo != NULL) { - cp.page_scan_rep_mode = memo->response.page_scan_rep_mode; - cp.page_scan_mode = memo->response.page_scan_mode; - cp.clock_offset = htole16(memo->response.clock_offset); + cp.page_scan_rep_mode = memo->page_scan_rep_mode; + cp.page_scan_mode = memo->page_scan_mode; + cp.clock_offset = memo->clock_offset; } if (unit->hci_link_policy & HCI_LINK_POLICY_ENABLE_ROLE_SWITCH) @@ -264,8 +262,9 @@ hci_acl_setmode(struct hci_link *link) && !(link->hl_flags & HCI_LINK_AUTH)) { hci_auth_req_cp cp; - DPRINTF("requesting auth for handle #%d\n", - link->hl_handle); + DPRINTF("(%s) requesting auth for handle #%d\n", + device_get_nameunit(link->hl_unit->hci_dev), + link->hl_handle); link->hl_state = HCI_LINK_WAIT_AUTH; cp.con_handle = htole16(link->hl_handle); @@ -281,8 +280,9 @@ hci_acl_setmode(struct hci_link *link) /* XXX we should check features for encryption capability */ - DPRINTF("requesting encryption for handle #%d\n", - link->hl_handle); + DPRINTF("(%s) requesting encryption for handle #%d\n", + device_get_nameunit(link->hl_unit->hci_dev), + link->hl_handle); link->hl_state = HCI_LINK_WAIT_ENCRYPT; cp.con_handle = htole16(link->hl_handle); @@ -300,8 +300,9 @@ hci_acl_setmode(struct hci_link *link) /* always change link key for SECURE requests */ link->hl_flags &= ~HCI_LINK_SECURE; - DPRINTF("changing link key for handle #%d\n", - link->hl_handle); + DPRINTF("(%s) changing link key for handle #%d\n", + device_get_nameunit(link->hl_unit->hci_dev), + link->hl_handle); link->hl_state = HCI_LINK_WAIT_SECURE; cp.con_handle = htole16(link->hl_handle); @@ -327,11 +328,11 @@ hci_acl_linkmode(struct hci_link *link) struct l2cap_channel *chan, *next; int err, mode = 0; - DPRINTF("handle #%d, auth %s, encrypt %s, secure %s\n", - link->hl_handle, - (link->hl_flags & HCI_LINK_AUTH ? "on" : "off"), - (link->hl_flags & HCI_LINK_ENCRYPT ? "on" : "off"), - (link->hl_flags & HCI_LINK_SECURE ? "on" : "off")); + DPRINTF("(%s) handle #%d, auth %s, encrypt %s, secure %s\n", + device_get_nameunit(link->hl_unit->hci_dev), link->hl_handle, + (link->hl_flags & HCI_LINK_AUTH ? "on" : "off"), + (link->hl_flags & HCI_LINK_ENCRYPT ? "on" : "off"), + (link->hl_flags & HCI_LINK_SECURE ? "on" : "off")); if (link->hl_flags & HCI_LINK_AUTH) mode |= L2CAP_LM_AUTH; @@ -431,13 +432,15 @@ hci_acl_recv(struct mbuf *m, struct hci_unit *unit) #ifdef DIAGNOSTIC if (hdr.type != HCI_ACL_DATA_PKT) { - kprintf("%s: bad ACL packet type\n", unit->hci_devname); + kprintf("%s: bad ACL packet type\n", + device_get_nameunit(unit->hci_dev)); goto bad; } if (m->m_pkthdr.len != letoh16(hdr.length)) { kprintf("%s: bad ACL packet length (%d != %d)\n", - unit->hci_devname, m->m_pkthdr.len, letoh16(hdr.length)); + device_get_nameunit(unit->hci_dev), m->m_pkthdr.len, + letoh16(hdr.length)); goto bad; } #endif @@ -452,7 +455,7 @@ hci_acl_recv(struct mbuf *m, struct hci_unit *unit) hci_discon_cp cp; DPRINTF("%s: dumping packet for unknown handle #%d\n", - unit->hci_devname, handle); + device_get_nameunit(unit->hci_dev), handle); /* * There is no way to find out what this connection handle is @@ -470,11 +473,11 @@ hci_acl_recv(struct mbuf *m, struct hci_unit *unit) case HCI_PACKET_START: if (link->hl_rxp != NULL) kprintf("%s: dropped incomplete ACL packet\n", - unit->hci_devname); + device_get_nameunit(unit->hci_dev)); if (m->m_pkthdr.len < sizeof(l2cap_hdr_t)) { kprintf("%s: short ACL packet\n", - unit->hci_devname); + device_get_nameunit(unit->hci_dev)); goto bad; } @@ -486,7 +489,7 @@ hci_acl_recv(struct mbuf *m, struct hci_unit *unit) case HCI_PACKET_FRAGMENT: if (link->hl_rxp == NULL) { kprintf("%s: unexpected packet fragment\n", - unit->hci_devname); + device_get_nameunit(unit->hci_dev)); goto bad; } @@ -499,7 +502,7 @@ hci_acl_recv(struct mbuf *m, struct hci_unit *unit) default: kprintf("%s: unknown packet type\n", - unit->hci_devname); + device_get_nameunit(unit->hci_dev)); goto bad; } @@ -559,7 +562,8 @@ hci_acl_send(struct mbuf *m, struct hci_link *link, mlen = link->hl_unit->hci_max_acl_size; DPRINTFN(5, "%s: handle #%d, plen = %d, max = %d\n", - link->hl_unit->hci_devname, link->hl_handle, plen, mlen); + device_get_nameunit(link->hl_unit->hci_dev), + link->hl_handle, plen, mlen); while (plen > 0) { if (plen > mlen) { @@ -573,7 +577,8 @@ hci_acl_send(struct mbuf *m, struct hci_link *link, if (num++ == 0) m->m_flags |= M_PROTO1; /* tag first fragment */ - DPRINTFN(10, "chunk of %d (plen = %d) bytes\n", mlen, plen); + DPRINTFN(10, "(%s) chunk of %d (plen = %d) bytes\n", + device_get_nameunit(link->hl_unit->hci_dev), mlen, plen); IF_ENQUEUE(&pdu->lp_data, m); m = n; plen -= mlen; @@ -707,15 +712,16 @@ hci_acl_complete(struct hci_link *link, int num) struct l2cap_pdu *pdu; struct l2cap_channel *chan; - DPRINTFN(5, "handle #%d (%d)\n", link->hl_handle, num); + DPRINTFN(5, "(%s) handle #%d (%d)\n", + device_get_nameunit(link->hl_unit->hci_dev), link->hl_handle, num); while (num > 0) { pdu = TAILQ_FIRST(&link->hl_txq); if (pdu == NULL) { kprintf("%s: %d packets completed on handle #%x " "but none pending!\n", - link->hl_unit->hci_devname, num, - link->hl_handle); + device_get_nameunit(link->hl_unit->hci_dev), + num, link->hl_handle); return; } @@ -836,13 +842,15 @@ hci_sco_recv(struct mbuf *m, struct hci_unit *unit) #ifdef DIAGNOSTIC if (hdr.type != HCI_SCO_DATA_PKT) { - kprintf("%s: bad SCO packet type\n", unit->hci_devname); + kprintf("%s: bad SCO packet type\n", + device_get_nameunit(unit->hci_dev)); goto bad; } if (m->m_pkthdr.len != hdr.length) { kprintf("%s: bad SCO packet length (%d != %d)\n", - unit->hci_devname, m->m_pkthdr.len, hdr.length); + device_get_nameunit(unit->hci_dev), m->m_pkthdr.len, + hdr.length); goto bad; } #endif @@ -853,7 +861,7 @@ hci_sco_recv(struct mbuf *m, struct hci_unit *unit) link = hci_link_lookup_handle(unit, handle); if (link == NULL || link->hl_type == HCI_LINK_ACL) { DPRINTF("%s: dumping packet for unknown handle #%d\n", - unit->hci_devname, handle); + device_get_nameunit(unit->hci_dev), handle); goto bad; } @@ -912,6 +920,9 @@ hci_link_alloc(struct hci_unit *unit) link->hl_mtu = L2CAP_MTU_DEFAULT; /* L2CAP signal mtu */ link->hl_flush = L2CAP_FLUSH_TIMO_DEFAULT; /* flush timeout */ + /* init SCO portion */ + /* &link->hl_data is already zero-initialized. */ + /* attach to unit */ TAILQ_INSERT_HEAD(&unit->hci_links, link, hl_next); crit_exit(); @@ -927,9 +938,9 @@ hci_link_free(struct hci_link *link, int err) KKASSERT(link != NULL); - DPRINTF("#%d, type = %d, state = %d, refcnt = %d\n", - link->hl_handle, link->hl_type, - link->hl_state, link->hl_refcnt); + DPRINTF("(%s) #%d, type = %d, state = %d, refcnt = %d\n", + device_get_nameunit(link->hl_unit->hci_dev), link->hl_handle, + link->hl_type, link->hl_state, link->hl_refcnt); /* ACL reference count */ if (link->hl_refcnt > 0) { @@ -986,6 +997,7 @@ hci_link_free(struct hci_link *link, int err) crit_enter(); IF_DRAIN(&link->hl_data); crit_exit(); + /* * Halt the timeout - if its already running we cannot free the * link structure but the timeout function will call us back in @@ -996,6 +1008,18 @@ hci_link_free(struct hci_link *link, int err) if (callout_active(&link->hl_expire)) return; + /* + * If we made a note of clock offset, keep it in a memo + * to facilitate reconnections to this device + */ + if (link->hl_clock != 0) { + struct hci_memo *memo; + + memo = hci_memo_new(link->hl_unit, &link->hl_bdaddr); + if (memo != NULL) + memo->clock_offset = link->hl_clock; + } + crit_enter(); TAILQ_REMOVE(&link->hl_unit->hci_links, link, hl_next); crit_exit(); diff --git a/sys/netbt/hci_misc.c b/sys/netbt/hci_misc.c index 7a11155cfe..29af609922 100644 --- a/sys/netbt/hci_misc.c +++ b/sys/netbt/hci_misc.c @@ -1,6 +1,6 @@ -/* $OpenBSD: hci_misc.c,v 1.1 2007/05/30 03:42:53 uwe Exp $ */ -/* $NetBSD: hci_misc.c,v 1.1 2006/06/19 15:44:45 gdamore Exp $ */ -/* $DragonFly: src/sys/netbt/hci_misc.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/hci_misc.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/hci_misc.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: hci_misc.c,v 1.3 2007/09/16 19:59:30 plunky Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. @@ -32,8 +32,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include - #include #include #include @@ -130,7 +128,7 @@ hci_memo_find(struct hci_unit *unit, bdaddr_t *bdaddr) continue; } - if (bdaddr_same(bdaddr, &memo->response.bdaddr)) { + if (bdaddr_same(bdaddr, &memo->bdaddr)) { DPRINTF("memo %p found\n", memo); return memo; } @@ -140,6 +138,41 @@ hci_memo_find(struct hci_unit *unit, bdaddr_t *bdaddr) return NULL; } +/* + * Make a new memo on unit for bdaddr. If a memo exists, just + * update the timestamp. + */ +struct hci_memo * +hci_memo_new(struct hci_unit *unit, bdaddr_t *bdaddr) +{ + struct hci_memo *memo; + + memo = hci_memo_find(unit, bdaddr); + if (memo == NULL) { + memo = kmalloc(sizeof(struct hci_memo), + M_BLUETOOTH, M_NOWAIT | M_ZERO); + + if (memo == NULL) { + DPRINTFN(0, "no memory for memo!\n"); + return NULL; + } + + DPRINTF("memo created for %02x:%02x:%02x:%02x:%02x:%02x\n", + bdaddr->b[5], bdaddr->b[4], bdaddr->b[3], + bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]); + + bdaddr_copy(&memo->bdaddr, bdaddr); + LIST_INSERT_HEAD(&unit->hci_memos, memo, next); + } + else + DPRINTF("memo updated for %02x:%02x:%02x:%02x:%02x:%02x\n", + bdaddr->b[5], bdaddr->b[4], bdaddr->b[3], + bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]); + + microtime(&memo->time); + return memo; +} + void hci_memo_free(struct hci_memo *memo) { diff --git a/sys/netbt/hci_socket.c b/sys/netbt/hci_socket.c index 2e5ccfea35..0e28dec773 100644 --- a/sys/netbt/hci_socket.c +++ b/sys/netbt/hci_socket.c @@ -1,6 +1,6 @@ -/* $OpenBSD: hci_socket.c,v 1.4 2007/09/17 01:33:33 krw Exp $ */ -/* $NetBSD: hci_socket.c,v 1.10 2007/03/31 18:17:13 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/hci_socket.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/hci_socket.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/hci_socket.c,v 1.5 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: hci_socket.c,v 1.14 2008/02/10 17:40:54 plunky Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. @@ -32,8 +32,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include - /* load symbolic names */ #ifdef BLUETOOTH_DEBUG #define PRUREQUESTS @@ -109,104 +107,318 @@ static int hci_ssend (struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, struct mbuf *control, struct thread *td); +/* supported commands opcode table */ +static const struct { + uint16_t opcode; + uint8_t offs; /* 0 - 63 */ + uint8_t mask; /* bit 0 - 7 */ + int16_t length; /* -1 if privileged */ +} hci_cmds[] = { + { HCI_CMD_INQUIRY, + 0, 0x01, sizeof(hci_inquiry_cp) }, + { HCI_CMD_INQUIRY_CANCEL, + 0, 0x02, -1 }, + { HCI_CMD_PERIODIC_INQUIRY, + 0, 0x04, -1 }, + { HCI_CMD_EXIT_PERIODIC_INQUIRY, + 0, 0x08, -1 }, + { HCI_CMD_CREATE_CON, + 0, 0x10, -1 }, + { HCI_CMD_DISCONNECT, + 0, 0x20, -1 }, + { HCI_CMD_ADD_SCO_CON, + 0, 0x40, -1 }, + { HCI_CMD_CREATE_CON_CANCEL, + 0, 0x80, -1 }, + { HCI_CMD_ACCEPT_CON, + 1, 0x01, -1 }, + { HCI_CMD_REJECT_CON, + 1, 0x02, -1 }, + { HCI_CMD_LINK_KEY_REP, + 1, 0x04, -1 }, + { HCI_CMD_LINK_KEY_NEG_REP, + 1, 0x08, -1 }, + { HCI_CMD_PIN_CODE_REP, + 1, 0x10, -1 }, + { HCI_CMD_PIN_CODE_NEG_REP, + 1, 0x20, -1 }, + { HCI_CMD_CHANGE_CON_PACKET_TYPE, + 1, 0x40, -1 }, + { HCI_CMD_AUTH_REQ, + 1, 0x80, -1 }, + { HCI_CMD_SET_CON_ENCRYPTION, + 2, 0x01, -1 }, + { HCI_CMD_CHANGE_CON_LINK_KEY, + 2, 0x02, -1 }, + { HCI_CMD_MASTER_LINK_KEY, + 2, 0x04, -1 }, + { HCI_CMD_REMOTE_NAME_REQ, + 2, 0x08, sizeof(hci_remote_name_req_cp) }, + { HCI_CMD_REMOTE_NAME_REQ_CANCEL, + 2, 0x10, -1 }, + { HCI_CMD_READ_REMOTE_FEATURES, + 2, 0x20, sizeof(hci_read_remote_features_cp) }, + { HCI_CMD_READ_REMOTE_EXTENDED_FEATURES, + 2, 0x40, sizeof(hci_read_remote_extended_features_cp) }, + { HCI_CMD_READ_REMOTE_VER_INFO, + 2, 0x80, sizeof(hci_read_remote_ver_info_cp) }, + { HCI_CMD_READ_CLOCK_OFFSET, + 3, 0x01, sizeof(hci_read_clock_offset_cp) }, + { HCI_CMD_READ_LMP_HANDLE, + 3, 0x02, sizeof(hci_read_lmp_handle_cp) }, + { HCI_CMD_HOLD_MODE, + 4, 0x02, -1 }, + { HCI_CMD_SNIFF_MODE, + 4, 0x04, -1 }, + { HCI_CMD_EXIT_SNIFF_MODE, + 4, 0x08, -1 }, + { HCI_CMD_PARK_MODE, + 4, 0x10, -1 }, + { HCI_CMD_EXIT_PARK_MODE, + 4, 0x20, -1 }, + { HCI_CMD_QOS_SETUP, + 4, 0x40, -1 }, + { HCI_CMD_ROLE_DISCOVERY, + 4, 0x80, sizeof(hci_role_discovery_cp) }, + { HCI_CMD_SWITCH_ROLE, + 5, 0x01, -1 }, + { HCI_CMD_READ_LINK_POLICY_SETTINGS, + 5, 0x02, sizeof(hci_read_link_policy_settings_cp) }, + { HCI_CMD_WRITE_LINK_POLICY_SETTINGS, + 5, 0x04, -1 }, + { HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS, + 5, 0x08, 0 }, + { HCI_CMD_WRITE_DEFAULT_LINK_POLICY_SETTINGS, + 5, 0x10, -1 }, + { HCI_CMD_FLOW_SPECIFICATION, + 5, 0x20, -1 }, + { HCI_CMD_SET_EVENT_MASK, + 5, 0x40, -1 }, + { HCI_CMD_RESET, + 5, 0x80, -1 }, + { HCI_CMD_SET_EVENT_FILTER, + 6, 0x01, -1 }, + { HCI_CMD_FLUSH, + 6, 0x02, -1 }, + { HCI_CMD_READ_PIN_TYPE, + 6, 0x04, 0 }, + { HCI_CMD_WRITE_PIN_TYPE, + 6, 0x08, -1 }, + { HCI_CMD_CREATE_NEW_UNIT_KEY, + 6, 0x10, -1 }, + { HCI_CMD_READ_STORED_LINK_KEY, + 6, 0x20, -1 }, + { HCI_CMD_WRITE_STORED_LINK_KEY, + 6, 0x40, -1 }, + { HCI_CMD_DELETE_STORED_LINK_KEY, + 6, 0x80, -1 }, + { HCI_CMD_WRITE_LOCAL_NAME, + 7, 0x01, -1 }, + { HCI_CMD_READ_LOCAL_NAME, + 7, 0x02, 0 }, + { HCI_CMD_READ_CON_ACCEPT_TIMEOUT, + 7, 0x04, 0 }, + { HCI_CMD_WRITE_CON_ACCEPT_TIMEOUT, + 7, 0x08, -1 }, + { HCI_CMD_READ_PAGE_TIMEOUT, + 7, 0x10, 0 }, + { HCI_CMD_WRITE_PAGE_TIMEOUT, + 7, 0x20, -1 }, + { HCI_CMD_READ_SCAN_ENABLE, + 7, 0x40, 0 }, + { HCI_CMD_WRITE_SCAN_ENABLE, + 7, 0x80, -1 }, + { HCI_CMD_READ_PAGE_SCAN_ACTIVITY, + 8, 0x01, 0 }, + { HCI_CMD_WRITE_PAGE_SCAN_ACTIVITY, + 8, 0x02, -1 }, + { HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY, + 8, 0x04, 0 }, + { HCI_CMD_WRITE_INQUIRY_SCAN_ACTIVITY, + 8, 0x08, -1 }, + { HCI_CMD_READ_AUTH_ENABLE, + 8, 0x10, 0 }, + { HCI_CMD_WRITE_AUTH_ENABLE, + 8, 0x20, -1 }, + { HCI_CMD_READ_ENCRYPTION_MODE, + 8, 0x40, 0 }, + { HCI_CMD_WRITE_ENCRYPTION_MODE, + 8, 0x80, -1 }, + { HCI_CMD_READ_UNIT_CLASS, + 9, 0x01, 0 }, + { HCI_CMD_WRITE_UNIT_CLASS, + 9, 0x02, -1 }, + { HCI_CMD_READ_VOICE_SETTING, + 9, 0x04, 0 }, + { HCI_CMD_WRITE_VOICE_SETTING, + 9, 0x08, -1 }, + { HCI_CMD_READ_AUTO_FLUSH_TIMEOUT, + 9, 0x10, sizeof(hci_read_auto_flush_timeout_cp) }, + { HCI_CMD_WRITE_AUTO_FLUSH_TIMEOUT, + 9, 0x20, -1 }, + { HCI_CMD_READ_NUM_BROADCAST_RETRANS, + 9, 0x40, 0 }, + { HCI_CMD_WRITE_NUM_BROADCAST_RETRANS, + 9, 0x80, -1 }, + { HCI_CMD_READ_HOLD_MODE_ACTIVITY, + 10, 0x01, 0 }, + { HCI_CMD_WRITE_HOLD_MODE_ACTIVITY, + 10, 0x02, -1 }, + { HCI_CMD_READ_XMIT_LEVEL, + 10, 0x04, sizeof(hci_read_xmit_level_cp) }, + { HCI_CMD_READ_SCO_FLOW_CONTROL, + 10, 0x08, 0 }, + { HCI_CMD_WRITE_SCO_FLOW_CONTROL, + 10, 0x10, -1 }, + { HCI_CMD_HC2H_FLOW_CONTROL, + 10, 0x20, -1 }, + { HCI_CMD_HOST_BUFFER_SIZE, + 10, 0x40, -1 }, + { HCI_CMD_HOST_NUM_COMPL_PKTS, + 10, 0x80, -1 }, + { HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT, + 11, 0x01, sizeof(hci_read_link_supervision_timeout_cp) }, + { HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT, + 11, 0x02, -1 }, + { HCI_CMD_READ_NUM_SUPPORTED_IAC, + 11, 0x04, 0 }, + { HCI_CMD_READ_IAC_LAP, + 11, 0x08, 0 }, + { HCI_CMD_WRITE_IAC_LAP, + 11, 0x10, -1 }, + { HCI_CMD_READ_PAGE_SCAN_PERIOD, + 11, 0x20, 0 }, + { HCI_CMD_WRITE_PAGE_SCAN_PERIOD, + 11, 0x40, -1 }, + { HCI_CMD_READ_PAGE_SCAN, + 11, 0x80, 0 }, + { HCI_CMD_WRITE_PAGE_SCAN, + 12, 0x01, -1 }, + { HCI_CMD_SET_AFH_CLASSIFICATION, + 12, 0x02, -1 }, + { HCI_CMD_READ_INQUIRY_SCAN_TYPE, + 12, 0x10, 0 }, + { HCI_CMD_WRITE_INQUIRY_SCAN_TYPE, + 12, 0x20, -1 }, + { HCI_CMD_READ_INQUIRY_MODE, + 12, 0x40, 0 }, + { HCI_CMD_WRITE_INQUIRY_MODE, + 12, 0x80, -1 }, + { HCI_CMD_READ_PAGE_SCAN_TYPE, + 13, 0x01, 0 }, + { HCI_CMD_WRITE_PAGE_SCAN_TYPE, + 13, 0x02, -1 }, + { HCI_CMD_READ_AFH_ASSESSMENT, + 13, 0x04, 0 }, + { HCI_CMD_WRITE_AFH_ASSESSMENT, + 13, 0x08, -1 }, + { HCI_CMD_READ_LOCAL_VER, + 14, 0x08, 0 }, + { HCI_CMD_READ_LOCAL_COMMANDS, + 14, 0x10, 0 }, + { HCI_CMD_READ_LOCAL_FEATURES, + 14, 0x20, 0 }, + { HCI_CMD_READ_LOCAL_EXTENDED_FEATURES, + 14, 0x40, sizeof(hci_read_local_extended_features_cp) }, + { HCI_CMD_READ_BUFFER_SIZE, + 14, 0x80, 0 }, + { HCI_CMD_READ_COUNTRY_CODE, + 15, 0x01, 0 }, + { HCI_CMD_READ_BDADDR, + 15, 0x02, 0 }, + { HCI_CMD_READ_FAILED_CONTACT_CNTR, + 15, 0x04, sizeof(hci_read_failed_contact_cntr_cp) }, + { HCI_CMD_RESET_FAILED_CONTACT_CNTR, + 15, 0x08, -1 }, + { HCI_CMD_READ_LINK_QUALITY, + 15, 0x10, sizeof(hci_read_link_quality_cp) }, + { HCI_CMD_READ_RSSI, + 15, 0x20, sizeof(hci_read_rssi_cp) }, + { HCI_CMD_READ_AFH_CHANNEL_MAP, + 15, 0x40, sizeof(hci_read_afh_channel_map_cp) }, + { HCI_CMD_READ_CLOCK, + 15, 0x80, sizeof(hci_read_clock_cp) }, + { HCI_CMD_READ_LOOPBACK_MODE, + 16, 0x01, 0 }, + { HCI_CMD_WRITE_LOOPBACK_MODE, + 16, 0x02, -1 }, + { HCI_CMD_ENABLE_UNIT_UNDER_TEST, + 16, 0x04, -1 }, + { HCI_CMD_SETUP_SCO_CON, + 16, 0x08, -1 }, + { HCI_CMD_ACCEPT_SCO_CON_REQ, + 16, 0x10, -1 }, + { HCI_CMD_REJECT_SCO_CON_REQ, + 16, 0x20, -1 }, + { HCI_CMD_READ_EXTENDED_INQUIRY_RSP, + 17, 0x01, 0 }, + { HCI_CMD_WRITE_EXTENDED_INQUIRY_RSP, + 17, 0x02, -1 }, + { HCI_CMD_REFRESH_ENCRYPTION_KEY, + 17, 0x04, -1 }, + { HCI_CMD_SNIFF_SUBRATING, + 17, 0x10, -1 }, + { HCI_CMD_READ_SIMPLE_PAIRING_MODE, + 17, 0x20, 0 }, + { HCI_CMD_WRITE_SIMPLE_PAIRING_MODE, + 17, 0x40, -1 }, + { HCI_CMD_READ_LOCAL_OOB_DATA, + 17, 0x80, -1 }, + { HCI_CMD_READ_INQUIRY_RSP_XMIT_POWER, + 18, 0x01, 0 }, + { HCI_CMD_WRITE_INQUIRY_RSP_XMIT_POWER, + 18, 0x02, -1 }, + { HCI_CMD_READ_DEFAULT_ERRDATA_REPORTING, + 18, 0x04, 0 }, + { HCI_CMD_WRITE_DEFAULT_ERRDATA_REPORTING, + 18, 0x08, -1 }, + { HCI_CMD_IO_CAPABILITY_REP, + 18, 0x80, -1 }, + { HCI_CMD_USER_CONFIRM_REP, + 19, 0x01, -1 }, + { HCI_CMD_USER_CONFIRM_NEG_REP, + 19, 0x02, -1 }, + { HCI_CMD_USER_PASSKEY_REP, + 19, 0x04, -1 }, + { HCI_CMD_USER_PASSKEY_NEG_REP, + 19, 0x08, -1 }, + { HCI_CMD_OOB_DATA_REP, + 19, 0x10, -1 }, + { HCI_CMD_WRITE_SIMPLE_PAIRING_DEBUG_MODE, + 19, 0x20, -1 }, + { HCI_CMD_ENHANCED_FLUSH, + 19, 0x40, -1 }, + { HCI_CMD_OOB_DATA_NEG_REP, + 19, 0x80, -1 }, + { HCI_CMD_SEND_KEYPRESS_NOTIFICATION, + 20, 0x40, -1 }, + { HCI_CMD_IO_CAPABILITY_NEG_REP, + 20, 0x80, -1 }, +}; + /* * Security filter routines for unprivileged users. * Allow all but a few critical events, and only permit read commands. + * If a unit is given, verify the command is supported. */ static int -hci_security_check_opcode(uint16_t opcode) +hci_security_check_opcode(struct hci_unit *unit, uint16_t opcode) { + int i; + + for (i = 0 ; i < sizeof(hci_cmds) / sizeof(hci_cmds[0]); i++) { + if (opcode != hci_cmds[i].opcode) + continue; - switch (opcode) { - /* Link control */ - case HCI_CMD_INQUIRY: - return sizeof(hci_inquiry_cp); - case HCI_CMD_REMOTE_NAME_REQ: - return sizeof(hci_remote_name_req_cp); - case HCI_CMD_READ_REMOTE_FEATURES: - return sizeof(hci_read_remote_features_cp); - case HCI_CMD_READ_REMOTE_EXTENDED_FEATURES: - return sizeof(hci_read_remote_extended_features_cp); - case HCI_CMD_READ_REMOTE_VER_INFO: - return sizeof(hci_read_remote_ver_info_cp); - case HCI_CMD_READ_CLOCK_OFFSET: - return sizeof(hci_read_clock_offset_cp); - case HCI_CMD_READ_LMP_HANDLE: - return sizeof(hci_read_lmp_handle_cp); - - /* Link policy */ - case HCI_CMD_ROLE_DISCOVERY: - return sizeof(hci_role_discovery_cp); - case HCI_CMD_READ_LINK_POLICY_SETTINGS: - return sizeof(hci_read_link_policy_settings_cp); - case HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS: - return 0; /* No command parameters */ - - /* Host controller and baseband */ - case HCI_CMD_READ_PIN_TYPE: - case HCI_CMD_READ_LOCAL_NAME: - case HCI_CMD_READ_CON_ACCEPT_TIMEOUT: - case HCI_CMD_READ_PAGE_TIMEOUT: - case HCI_CMD_READ_SCAN_ENABLE: - case HCI_CMD_READ_PAGE_SCAN_ACTIVITY: - case HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY: - case HCI_CMD_READ_AUTH_ENABLE: - case HCI_CMD_READ_ENCRYPTION_MODE: - case HCI_CMD_READ_UNIT_CLASS: - case HCI_CMD_READ_VOICE_SETTING: - return 0; /* No command parameters */ - case HCI_CMD_READ_AUTO_FLUSH_TIMEOUT: - return sizeof(hci_read_auto_flush_timeout_cp); - case HCI_CMD_READ_NUM_BROADCAST_RETRANS: - case HCI_CMD_READ_HOLD_MODE_ACTIVITY: - return 0; /* No command parameters */ - case HCI_CMD_READ_XMIT_LEVEL: - return sizeof(hci_read_xmit_level_cp); - case HCI_CMD_READ_SCO_FLOW_CONTROL: - return 0; /* No command parameters */ - case HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT: - return sizeof(hci_read_link_supervision_timeout_cp); - case HCI_CMD_READ_NUM_SUPPORTED_IAC: - case HCI_CMD_READ_IAC_LAP: - case HCI_CMD_READ_PAGE_SCAN_PERIOD: - case HCI_CMD_READ_PAGE_SCAN: - case HCI_CMD_READ_INQUIRY_SCAN_TYPE: - case HCI_CMD_READ_INQUIRY_MODE: - case HCI_CMD_READ_PAGE_SCAN_TYPE: - case HCI_CMD_READ_AFH_ASSESSMENT: - return 0; /* No command parameters */ - - /* Informational */ - case HCI_CMD_READ_LOCAL_VER: - case HCI_CMD_READ_LOCAL_COMMANDS: - case HCI_CMD_READ_LOCAL_FEATURES: - return 0; /* No command parameters */ - case HCI_CMD_READ_LOCAL_EXTENDED_FEATURES: - return sizeof(hci_read_local_extended_features_cp); - case HCI_CMD_READ_BUFFER_SIZE: - case HCI_CMD_READ_COUNTRY_CODE: - case HCI_CMD_READ_BDADDR: - return 0; /* No command parameters */ - - /* Status */ - case HCI_CMD_READ_FAILED_CONTACT_CNTR: - return sizeof(hci_read_failed_contact_cntr_cp); - case HCI_CMD_READ_LINK_QUALITY: - return sizeof(hci_read_link_quality_cp); - case HCI_CMD_READ_RSSI: - return sizeof(hci_read_rssi_cp); - case HCI_CMD_READ_AFH_CHANNEL_MAP: - return sizeof(hci_read_afh_channel_map_cp); - case HCI_CMD_READ_CLOCK: - return sizeof(hci_read_clock_cp); - - /* Testing */ - case HCI_CMD_READ_LOOPBACK_MODE: - return 0; /* No command parameters */ + if (unit == NULL + || (unit->hci_cmds[hci_cmds[i].offs] & hci_cmds[i].mask)) + return hci_cmds[i].length; + + break; } - return -1; /* disallowed */ + return -1; } static int @@ -216,6 +428,8 @@ hci_security_check_event(uint8_t event) switch (event) { case HCI_EVENT_RETURN_LINK_KEYS: case HCI_EVENT_LINK_KEY_NOTIFICATION: + case HCI_EVENT_USER_CONFIRM_REQ: + case HCI_EVENT_USER_PASSKEY_NOTIFICATION: case HCI_EVENT_VENDOR: return -1; /* disallowed */ } @@ -283,6 +497,7 @@ hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr) goto bad; } m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr); + hdr.opcode = letoh16(hdr.opcode); /* only allows CMD packets to be sent */ if (hdr.type != HCI_CMD_PKT) { @@ -296,13 +511,6 @@ hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr) goto bad; } - /* security checks for unprivileged users */ - if ((pcb->hp_flags & HCI_PRIVILEGED) == 0 - && hci_security_check_opcode(letoh16(hdr.opcode)) != hdr.length) { - err = EPERM; - goto bad; - } - /* finds destination */ unit = hci_unit_lookup(addr); if (unit == NULL) { @@ -310,6 +518,13 @@ hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr) goto bad; } + /* security checks for unprivileged users */ + if ((pcb->hp_flags & HCI_PRIVILEGED) == 0 + && hci_security_check_opcode(unit, hdr.opcode) != hdr.length) { + err = EPERM; + goto bad; + } + /* makes a copy for precious to keep */ m0 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT); if (m0 == NULL) { @@ -319,20 +534,21 @@ hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr) sbappendrecord(&pcb->hp_socket->so_snd.sb, m0); M_SETCTX(m, pcb->hp_socket); /* enable drop callback */ - DPRINTFN(2, "(%s) opcode (%03x|%04x)\n", unit->hci_devname, - HCI_OGF(letoh16(hdr.opcode)), HCI_OCF(letoh16(hdr.opcode))); + DPRINTFN(2, "(%s) opcode (%03x|%04x)\n", + device_get_nameunit(unit->hci_dev), + HCI_OGF(hdr.opcode), HCI_OCF(hdr.opcode)); /* Sendss it */ - if (unit->hci_num_cmd_pkts == 0) { + if (unit->hci_num_cmd_pkts == 0) IF_ENQUEUE(&unit->hci_cmdwait, m); - } else + else hci_output_cmd(unit, m); return 0; bad: DPRINTF("packet (%d bytes) not sent (error %d)\n", - m->m_pkthdr.len, err); + m->m_pkthdr.len, err); if (m) m_freem(m); return err; } @@ -704,7 +920,7 @@ hci_mtap(struct mbuf *m, struct hci_unit *unit) opcode = letoh16(mtod(m, hci_cmd_hdr_t *)->opcode); if ((pcb->hp_flags & HCI_PRIVILEGED) == 0 - && hci_security_check_opcode(opcode) == -1) + && hci_security_check_opcode(NULL, opcode) == -1) continue; break; diff --git a/sys/netbt/hci_unit.c b/sys/netbt/hci_unit.c index 0a63fb1c42..0fced4d747 100644 --- a/sys/netbt/hci_unit.c +++ b/sys/netbt/hci_unit.c @@ -1,6 +1,6 @@ -/* $OpenBSD: hci_unit.c,v 1.7 2007/06/24 20:55:27 uwe Exp $ */ -/* $NetBSD: hci_unit.c,v 1.4 2007/03/30 20:47:03 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/hci_unit.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/hci_unit.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/hci_unit.c,v 1.8 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: hci_unit.c,v 1.9 2007/12/30 18:26:42 plunky Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. @@ -32,8 +32,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include - #include #include #include @@ -59,38 +57,77 @@ struct hci_unit_list hci_unit_list = TAILQ_HEAD_INITIALIZER(hci_unit_list); int hci_eventq_max = 20; int hci_aclrxq_max = 50; int hci_scorxq_max = 50; +int hci_cmdwait_max = 50; +int hci_scodone_max = 50; + +/* + * This is the default minimum command set supported by older + * devices. Anything conforming to 1.2 spec or later will get + * updated during init. + */ +static const uint8_t hci_cmds_v10[HCI_COMMANDS_SIZE] = { + 0xff, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7f, 0x32, 0x03, 0xb8, 0xfe, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; /* * bluetooth unit functions */ -void -hci_attach(struct hci_unit *unit) +struct hci_unit * +hci_attach(const struct hci_if *hci_if, struct device *dev, uint16_t flags) { - KKASSERT(unit->hci_softc != NULL); - KKASSERT(unit->hci_devname != NULL); - KKASSERT(unit->hci_enable != NULL); - KKASSERT(unit->hci_disable != NULL); - KKASSERT(unit->hci_start_cmd != NULL); - KKASSERT(unit->hci_start_acl != NULL); - KKASSERT(unit->hci_start_sco != NULL); + struct hci_unit *unit; + + KKASSERT(dev != NULL); + KKASSERT(hci_if->enable != NULL); + KKASSERT(hci_if->disable != NULL); + KKASSERT(hci_if->output_cmd != NULL); + KKASSERT(hci_if->output_acl != NULL); + KKASSERT(hci_if->output_sco != NULL); + KKASSERT(hci_if->get_stats != NULL); + + unit = kmalloc(sizeof(struct hci_unit), M_BLUETOOTH, M_ZERO | M_WAITOK); + KKASSERT(unit != NULL); + + unit->hci_dev = dev; + unit->hci_if = hci_if; + unit->hci_flags = flags; + + lockinit(&unit->hci_devlock, "HCI device lock", 0, 0); unit->hci_eventq.ifq_maxlen = hci_eventq_max; unit->hci_aclrxq.ifq_maxlen = hci_aclrxq_max; unit->hci_scorxq.ifq_maxlen = hci_scorxq_max; + unit->hci_cmdwait.ifq_maxlen = hci_cmdwait_max; + unit->hci_scodone.ifq_maxlen = hci_scodone_max; TAILQ_INIT(&unit->hci_links); LIST_INIT(&unit->hci_memos); + crit_enter(); TAILQ_INSERT_TAIL(&hci_unit_list, unit, hci_next); + crit_exit(); + + return unit; } void hci_detach(struct hci_unit *unit) { + crit_enter(); hci_disable(unit); TAILQ_REMOVE(&hci_unit_list, unit, hci_next); + crit_exit(); + + kfree(unit, M_BLUETOOTH); } int @@ -103,11 +140,9 @@ hci_enable(struct hci_unit *unit) * command on power up until they send a Command Status * or Command Complete event with more information, but * it seems that some devices cant and prefer to send a - * No-op Command Status packet when they are ready, so - * we set this here and allow the driver (bt3c) to zero - * it. + * No-op Command Status packet when they are ready. */ - unit->hci_num_cmd_pkts = 1; + unit->hci_num_cmd_pkts = (unit->hci_flags & BTF_POWER_UP_NOOP) ? 0 : 1; unit->hci_num_acl_pkts = 0; unit->hci_num_sco_pkts = 0; @@ -117,11 +152,14 @@ hci_enable(struct hci_unit *unit) */ unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1; unit->hci_packet_type = unit->hci_acl_mask; - - err = (*unit->hci_enable)(unit); + + memcpy(unit->hci_cmds, hci_cmds_v10, HCI_COMMANDS_SIZE); + err = (*unit->hci_if->enable)(unit->hci_dev); if (err) goto bad1; + unit->hci_flags |= BTF_RUNNING; + /* * Reset the device, this will trigger initialisation * and wake us up. @@ -170,7 +208,8 @@ hci_enable(struct hci_unit *unit) return 0; bad2: - (*unit->hci_disable)(unit); + (*unit->hci_if->disable)(unit->hci_dev); + unit->hci_flags &= ~BTF_RUNNING; bad1: return err; @@ -190,7 +229,8 @@ hci_disable(struct hci_unit *unit) } #endif - (*unit->hci_disable)(unit); + (*unit->hci_if->disable)(unit->hci_dev); + unit->hci_flags &= ~BTF_RUNNING; /* * close down any links, take care to close SCO first since @@ -208,6 +248,8 @@ hci_disable(struct hci_unit *unit) 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; @@ -217,10 +259,7 @@ hci_disable(struct hci_unit *unit) IF_DRAIN(&unit->hci_scorxq); unit->hci_scorxqlen = 0; - IF_DRAIN(&unit->hci_cmdq); IF_DRAIN(&unit->hci_cmdwait); - IF_DRAIN(&unit->hci_acltxq); - IF_DRAIN(&unit->hci_scotxq); IF_DRAIN(&unit->hci_scodone); } @@ -246,7 +285,6 @@ hci_unit_lookup(bdaddr_t *addr) int hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len) { - struct mbuf *m; hci_cmd_hdr_t *p; @@ -261,7 +299,7 @@ hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len) p->opcode = htole16(opcode); p->length = len; m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t); - M_SETCTX(m, NULL); + M_SETCTX(m, NULL); /* XXX is this needed? */ if (len) { KKASSERT(buf != NULL); @@ -273,13 +311,14 @@ hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len) } } - DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n", unit->hci_devname, + DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n", + device_get_nameunit(unit->hci_dev), HCI_OGF(opcode), HCI_OCF(opcode)); /* and send it on */ - if (unit->hci_num_cmd_pkts == 0) { + if (unit->hci_num_cmd_pkts == 0) IF_ENQUEUE(&unit->hci_cmdwait, m); - } else + else hci_output_cmd(unit, m); return 0; @@ -298,16 +337,17 @@ hci_intr(void *arg) struct mbuf *m; another: - crit_enter(); + lockmgr(&unit->hci_devlock, LK_EXCLUSIVE); if (unit->hci_eventqlen > 0) { IF_DEQUEUE(&unit->hci_eventq, m); unit->hci_eventqlen--; - crit_exit(); + lockmgr(&unit->hci_devlock, LK_RELEASE); + KKASSERT(m != NULL); DPRINTFN(10, "(%s) recv event, len = %d\n", - unit->hci_devname, m->m_pkthdr.len); + device_get_nameunit(unit->hci_dev), m->m_pkthdr.len); m->m_flags |= IFF_LINK0; /* mark incoming packet */ hci_mtap(m, unit); @@ -319,11 +359,11 @@ another: if (unit->hci_scorxqlen > 0) { IF_DEQUEUE(&unit->hci_scorxq, m); unit->hci_scorxqlen--; - crit_exit(); + lockmgr(&unit->hci_devlock, LK_RELEASE); KKASSERT(m != NULL); DPRINTFN(10, "(%s) recv SCO, len = %d\n", - unit->hci_devname, m->m_pkthdr.len); + device_get_nameunit(unit->hci_dev), m->m_pkthdr.len); m->m_flags |= IFF_LINK0; /* mark incoming packet */ hci_mtap(m, unit); @@ -335,11 +375,12 @@ another: if (unit->hci_aclrxqlen > 0) { IF_DEQUEUE(&unit->hci_aclrxq, m); unit->hci_aclrxqlen--; - crit_exit(); + lockmgr(&unit->hci_devlock, LK_RELEASE); + KKASSERT(m != NULL); DPRINTFN(10, "(%s) recv ACL, len = %d\n", - unit->hci_devname, m->m_pkthdr.len); + device_get_nameunit(unit->hci_dev), m->m_pkthdr.len); m->m_flags |= IFF_LINK0; /* mark incoming packet */ hci_mtap(m, unit); @@ -351,10 +392,10 @@ another: IF_DEQUEUE(&unit->hci_scodone, m); if (m != NULL) { struct hci_link *link; - crit_exit(); + lockmgr(&unit->hci_devlock, LK_RELEASE); DPRINTFN(11, "(%s) complete SCO\n", - unit->hci_devname); + device_get_nameunit(unit->hci_dev)); TAILQ_FOREACH(link, &unit->hci_links, hl_next) { if (link == M_GETCTX(m, struct hci_link *)) { @@ -369,7 +410,7 @@ another: goto another; } - crit_exit(); + lockmgr(&unit->hci_devlock, LK_RELEASE); DPRINTFN(10, "done\n"); } @@ -378,56 +419,76 @@ another: * * IO routines * - * input & complete routines will be called from device driver - * (at unit->hci_ipl) + * input & complete routines will be called from device drivers, + * possibly in interrupt context. We return success or failure to + * enable proper accounting but we own the mbuf. */ -void +int hci_input_event(struct hci_unit *unit, struct mbuf *m) { + int rv; + + lockmgr(&unit->hci_devlock, LK_EXCLUSIVE); + if (unit->hci_eventqlen > hci_eventq_max) { - DPRINTF("(%s) dropped event packet.\n", unit->hci_devname); - unit->hci_stats.err_rx++; + DPRINTF("(%s) dropped event packet.\n", + device_get_nameunit(unit->hci_dev)); m_freem(m); + rv = 0; } else { unit->hci_eventqlen++; - crit_enter(); IF_ENQUEUE(&unit->hci_eventq, m); - crit_exit(); netisr_queue(NETISR_BLUETOOTH, m); + rv = 1; } + lockmgr(&unit->hci_devlock, LK_RELEASE); + + return rv; } -void +int hci_input_acl(struct hci_unit *unit, struct mbuf *m) { + int rv; + + lockmgr(&unit->hci_devlock, LK_EXCLUSIVE); if (unit->hci_aclrxqlen > hci_aclrxq_max) { - DPRINTF("(%s) dropped ACL packet.\n", unit->hci_devname); - unit->hci_stats.err_rx++; + DPRINTF("(%s) dropped ACL packet.\n", + device_get_nameunit(unit->hci_dev)); m_freem(m); + rv = 0; } else { unit->hci_aclrxqlen++; - crit_enter(); IF_ENQUEUE(&unit->hci_aclrxq, m); - crit_exit(); - netisr_queue(NETISR_BLUETOOTH,m); + netisr_queue(NETISR_BLUETOOTH, m); + rv = 1; } + lockmgr(&unit->hci_devlock, LK_RELEASE); + + return rv; } -void +int hci_input_sco(struct hci_unit *unit, struct mbuf *m) { + int rv; + + lockmgr(&unit->hci_devlock, LK_EXCLUSIVE); if (unit->hci_scorxqlen > hci_scorxq_max) { - DPRINTF("(%s) dropped SCO packet.\n", unit->hci_devname); - unit->hci_stats.err_rx++; + DPRINTF("(%s) dropped SCO packet.\n", + device_get_nameunit(unit->hci_dev)); m_freem(m); + rv = 0; } else { unit->hci_scorxqlen++; - crit_enter(); IF_ENQUEUE(&unit->hci_scorxq, m); - crit_exit(); - netisr_queue(NETISR_BLUETOOTH,m); + netisr_queue(NETISR_BLUETOOTH, m); + rv = 1; } + lockmgr(&unit->hci_devlock, LK_RELEASE); + + return rv; } void @@ -437,8 +498,8 @@ hci_output_cmd(struct hci_unit *unit, struct mbuf *m) hci_mtap(m, unit); - DPRINTFN(10, "(%s) num_cmd_pkts=%d\n", unit->hci_devname, - unit->hci_num_cmd_pkts); + DPRINTFN(10, "(%s) num_cmd_pkts=%d\n", + device_get_nameunit(unit->hci_dev), unit->hci_num_cmd_pkts); unit->hci_num_cmd_pkts--; @@ -450,11 +511,7 @@ hci_output_cmd(struct hci_unit *unit, struct mbuf *m) if (arg != NULL) hci_drop(arg); - crit_enter(); - IF_ENQUEUE(&unit->hci_cmdq, m); - crit_exit(); - if ((unit->hci_flags & BTF_XMIT_CMD) == 0) - (*unit->hci_start_cmd)(unit); + (*unit->hci_if->output_cmd)(unit->hci_dev, m); } void @@ -462,43 +519,34 @@ hci_output_acl(struct hci_unit *unit, struct mbuf *m) { hci_mtap(m, unit); - DPRINTFN(10, "(%s) num_acl_pkts=%d\n", unit->hci_devname, - unit->hci_num_acl_pkts); + DPRINTFN(10, "(%s) num_acl_pkts=%d\n", + device_get_nameunit(unit->hci_dev), unit->hci_num_acl_pkts); unit->hci_num_acl_pkts--; - crit_enter(); - IF_ENQUEUE(&unit->hci_acltxq, m); - crit_exit(); - - if ((unit->hci_flags & BTF_XMIT_ACL) == 0) - (*unit->hci_start_acl)(unit); + (*unit->hci_if->output_acl)(unit->hci_dev, m); } void hci_output_sco(struct hci_unit *unit, struct mbuf *m) { - hci_mtap(m, unit); - DPRINTFN(10, "(%s) num_sco_pkts=%d\n", unit->hci_devname, - unit->hci_num_sco_pkts); + DPRINTFN(10, "(%s) num_sco_pkts=%d\n", + device_get_nameunit(unit->hci_dev), unit->hci_num_sco_pkts); unit->hci_num_sco_pkts--; - crit_enter(); - IF_ENQUEUE(&unit->hci_scotxq, m); - crit_exit(); - if ((unit->hci_flags & BTF_XMIT_SCO) == 0) - (*unit->hci_start_sco)(unit); - + (*unit->hci_if->output_sco)(unit->hci_dev, m); } -void +int hci_complete_sco(struct hci_unit *unit, struct mbuf *m) { + lockmgr(&unit->hci_devlock, LK_EXCLUSIVE); IF_ENQUEUE(&unit->hci_scodone, m); - crit_enter(); netisr_queue(NETISR_BLUETOOTH,m); - crit_exit(); + lockmgr(&unit->hci_devlock, LK_RELEASE); + + return 1; } diff --git a/sys/netbt/l2cap.h b/sys/netbt/l2cap.h index 4391f12495..55147f0ed6 100644 --- a/sys/netbt/l2cap.h +++ b/sys/netbt/l2cap.h @@ -1,6 +1,6 @@ -/* $OpenBSD: l2cap.h,v 1.4 2007/06/01 02:46:11 uwe Exp $ */ -/* $NetBSD: l2cap.h,v 1.5 2007/04/21 06:15:23 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/l2cap.h,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/l2cap.h,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/l2cap.h,v 1.5 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: l2cap.h,v 1.6 2007/11/03 17:20:17 plunky Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. @@ -56,6 +56,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $Id: l2cap.h,v 1.6 2007/11/03 17:20:17 plunky Exp $ * $FreeBSD: src/sys/netgraph/bluetooth/include/l2cap.h,v 1.4 2005/08/31 18:13:23 emax Exp $ */ diff --git a/sys/netbt/l2cap_lower.c b/sys/netbt/l2cap_lower.c index 09f4c9f163..99d14a9b66 100644 --- a/sys/netbt/l2cap_lower.c +++ b/sys/netbt/l2cap_lower.c @@ -1,6 +1,6 @@ -/* $OpenBSD: l2cap_lower.c,v 1.1 2007/05/30 03:42:53 uwe Exp $ */ -/* $NetBSD: l2cap_lower.c,v 1.6 2007/04/21 06:15:23 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/l2cap_lower.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/l2cap_lower.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/l2cap_lower.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: l2cap_lower.c,v 1.7 2007/11/10 23:12:23 plunky Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. @@ -32,8 +32,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include - #include #include #include @@ -121,7 +119,7 @@ l2cap_recv_frame(struct mbuf *m, struct hci_link *link) hdr.dcid = letoh16(hdr.dcid); DPRINTFN(5, "(%s) received packet (%d bytes)\n", - link->hl_unit->hci_devname, hdr.length); + device_get_nameunit(link->hl_unit->hci_dev), hdr.length); if (hdr.length != m->m_pkthdr.len) goto failed; @@ -144,7 +142,8 @@ l2cap_recv_frame(struct mbuf *m, struct hci_link *link) } DPRINTF("(%s) dropping %d L2CAP data bytes for unknown CID #%d\n", - link->hl_unit->hci_devname, hdr.length, hdr.dcid); + device_get_nameunit(link->hl_unit->hci_dev), hdr.length, + hdr.dcid); failed: m_freem(m); diff --git a/sys/netbt/l2cap_misc.c b/sys/netbt/l2cap_misc.c index cb77b1cafb..63b768cdbb 100644 --- a/sys/netbt/l2cap_misc.c +++ b/sys/netbt/l2cap_misc.c @@ -1,6 +1,6 @@ -/* $OpenBSD: l2cap_misc.c,v 1.2 2007/06/01 02:46:11 uwe Exp $ */ -/* $NetBSD: l2cap_misc.c,v 1.3 2007/04/21 06:15:23 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/l2cap_misc.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/l2cap_misc.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/l2cap_misc.c,v 1.3 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: l2cap_misc.c,v 1.5 2007/11/03 17:20:17 plunky Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. @@ -32,8 +32,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include - #include #include #include @@ -86,10 +84,11 @@ l2cap_setmode(struct l2cap_channel *chan) KKASSERT(chan != NULL); KKASSERT(chan->lc_link != NULL); - DPRINTF("CID #%d, auth %s, encrypt %s, secure %s\n", chan->lc_lcid, - (chan->lc_mode & L2CAP_LM_AUTH ? "yes" : "no"), - (chan->lc_mode & L2CAP_LM_ENCRYPT ? "yes" : "no"), - (chan->lc_mode & L2CAP_LM_SECURE ? "yes" : "no")); + DPRINTF("(%s) CID #%d, auth %s, encrypt %s, secure %s\n", + device_get_nameunit(chan->lc_link->hl_unit->hci_dev), chan->lc_lcid, + (chan->lc_mode & L2CAP_LM_AUTH ? "yes" : "no"), + (chan->lc_mode & L2CAP_LM_ENCRYPT ? "yes" : "no"), + (chan->lc_mode & L2CAP_LM_SECURE ? "yes" : "no")); if (chan->lc_mode & L2CAP_LM_AUTH) chan->lc_link->hl_flags |= HCI_LINK_AUTH_REQ; diff --git a/sys/netbt/l2cap_signal.c b/sys/netbt/l2cap_signal.c index 75b21371cd..4e02721115 100644 --- a/sys/netbt/l2cap_signal.c +++ b/sys/netbt/l2cap_signal.c @@ -1,6 +1,6 @@ -/* $OpenBSD: l2cap_signal.c,v 1.2 2007/07/22 21:05:00 gwk Exp $ */ -/* $NetBSD: l2cap_signal.c,v 1.8 2007/05/16 18:34:49 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/l2cap_signal.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/l2cap_signal.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/l2cap_signal.c,v 1.3 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: l2cap_signal.c,v 1.9 2007/11/10 23:12:23 plunky Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. @@ -32,8 +32,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include - #include #include @@ -87,7 +85,7 @@ l2cap_recv_signal(struct mbuf *m, struct hci_link *link) goto reject; DPRINTFN(2, "(%s) code %d, ident %d, len %d\n", - link->hl_unit->hci_devname, + device_get_nameunit(link->hl_unit->hci_dev), cmd.code, cmd.ident, cmd.length); switch (cmd.code) { @@ -409,7 +407,7 @@ l2cap_recv_connect_rsp(struct mbuf *m, struct hci_link *link) } /* - * Process Received Config Reqest. + * Process Received Config Request. */ static void l2cap_recv_config_req(struct mbuf *m, struct hci_link *link) @@ -526,18 +524,63 @@ l2cap_recv_config_req(struct mbuf *m, struct hci_link *link) break; case L2CAP_OPT_QOS: + if (rp.result == L2CAP_UNKNOWN_OPTION) + break; + + if (opt.length != L2CAP_OPT_QOS_SIZE) + goto reject; + + m_copydata(m, 0, L2CAP_OPT_QOS_SIZE, (caddr_t)&val); + if (val.qos.service_type == L2CAP_QOS_NO_TRAFFIC || + val.qos.service_type == L2CAP_QOS_BEST_EFFORT) + /* + * In accordance with the spec, we choose to + * ignore the fields an provide no response. + */ + break; + + if (len + sizeof(opt) + L2CAP_OPT_QOS_SIZE > sizeof(buf)) + goto reject; + + if (val.qos.service_type != L2CAP_QOS_GUARANTEED) { + /* + * Instead of sending an "unacceptable + * parameters" response, treat this as an + * unknown option and include the option + * value in the response. + */ + rp.result = L2CAP_UNKNOWN_OPTION; + } else { + /* + * According to the spec, we must return + * specific values for wild card parameters. + * I don't know what to return without lying, + * so return "unacceptable parameters" and + * specify the preferred service type as + * "Best Effort". + */ + rp.result = L2CAP_UNACCEPTABLE_PARAMS; + val.qos.service_type = L2CAP_QOS_BEST_EFFORT; + } + + memcpy(buf + len, &opt, sizeof(opt)); + len += sizeof(opt); + memcpy(buf + len, &val, L2CAP_OPT_QOS_SIZE); + len += L2CAP_OPT_QOS_SIZE; + break; + default: /* ignore hints */ if (opt.type & L2CAP_OPT_HINT_BIT) break; - /* unknown options supercede all else */ + /* unknown options supersede all else */ if (rp.result != L2CAP_UNKNOWN_OPTION) { rp.result = L2CAP_UNKNOWN_OPTION; len = sizeof(rp); } - /* ignore if it don't fit */ + /* ignore if it doesn't fit */ if (len + sizeof(opt) > sizeof(buf)) break; @@ -906,7 +949,7 @@ l2cap_send_signal(struct hci_link *link, uint8_t code, uint8_t ident, if (sizeof(l2cap_cmd_hdr_t) + length > link->hl_mtu) kprintf("(%s) exceeding L2CAP Signal MTU for link!\n", - link->hl_unit->hci_devname); + device_get_nameunit(link->hl_unit->hci_dev)); #endif m = m_gethdr(MB_DONTWAIT, MT_DATA); @@ -942,7 +985,8 @@ l2cap_send_signal(struct hci_link *link, uint8_t code, uint8_t ident, m->m_len = MIN(length, MHLEN); DPRINTFN(2, "(%s) code %d, ident %d, len %d\n", - link->hl_unit->hci_devname, code, ident, length); + device_get_nameunit(link->hl_unit->hci_dev), code, ident, + length); return hci_acl_send(m, link, NULL); } diff --git a/sys/netbt/l2cap_socket.c b/sys/netbt/l2cap_socket.c index c37c5b5029..d1f56fc10a 100644 --- a/sys/netbt/l2cap_socket.c +++ b/sys/netbt/l2cap_socket.c @@ -1,6 +1,6 @@ +/* $DragonFly: src/sys/netbt/l2cap_socket.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ /* $OpenBSD: l2cap_socket.c,v 1.1 2007/06/01 02:46:11 uwe Exp $ */ /* $NetBSD: l2cap_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/l2cap_socket.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. diff --git a/sys/netbt/l2cap_upper.c b/sys/netbt/l2cap_upper.c index 1c874a3fc9..5d80b50419 100644 --- a/sys/netbt/l2cap_upper.c +++ b/sys/netbt/l2cap_upper.c @@ -1,6 +1,6 @@ +/* $DragonFly: src/sys/netbt/l2cap_upper.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ /* $OpenBSD: l2cap_upper.c,v 1.2 2007/10/01 16:39:30 krw Exp $ */ /* $NetBSD: l2cap_upper.c,v 1.8 2007/04/29 20:23:36 msaitoh Exp $ */ -/* $DragonFly: src/sys/netbt/l2cap_upper.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. diff --git a/sys/netbt/rfcomm.h b/sys/netbt/rfcomm.h index 5bb505e62b..54134617d2 100644 --- a/sys/netbt/rfcomm.h +++ b/sys/netbt/rfcomm.h @@ -1,6 +1,6 @@ -/* $OpenBSD: rfcomm.h,v 1.1 2007/06/01 02:46:11 uwe Exp $ */ -/* $NetBSD: rfcomm.h,v 1.3 2007/04/21 06:15:23 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/rfcomm.h,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/rfcomm.h,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/rfcomm.h,v 1.2 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: rfcomm.h,v 1.6 2007/11/20 20:25:58 plunky Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -57,7 +57,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: rfcomm.h,v 1.1.1.1 2007/11/20 11:56:11 griffin Exp $ + * $Id: rfcomm.h,v 1.6 2007/11/20 20:25:58 plunky Exp $ * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h,v 1.4 2005/01/11 01:39:53 emax Exp $ */ @@ -79,6 +79,7 @@ #define RFCOMM_CREDITS_MAX 255 /* in any single packet */ #define RFCOMM_CREDITS_DEFAULT 7 /* default initial value */ +#define RFCOMM_CHANNEL_ANY 0 #define RFCOMM_CHANNEL_MIN 1 #define RFCOMM_CHANNEL_MAX 30 diff --git a/sys/netbt/rfcomm_dlc.c b/sys/netbt/rfcomm_dlc.c index 987463a8c7..ad4ef4f38b 100644 --- a/sys/netbt/rfcomm_dlc.c +++ b/sys/netbt/rfcomm_dlc.c @@ -1,6 +1,6 @@ -/* $OpenBSD: rfcomm_dlc.c,v 1.1 2007/06/01 02:46:12 uwe Exp $ */ -/* $NetBSD: rfcomm_dlc.c,v 1.3 2007/04/21 06:15:23 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/rfcomm_dlc.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/rfcomm_dlc.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/rfcomm_dlc.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: rfcomm_dlc.c,v 1.4 2007/11/03 17:20:17 plunky Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -33,8 +33,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include - #include #include #include diff --git a/sys/netbt/rfcomm_session.c b/sys/netbt/rfcomm_session.c index eb004d2a08..5f891b3993 100644 --- a/sys/netbt/rfcomm_session.c +++ b/sys/netbt/rfcomm_session.c @@ -1,6 +1,6 @@ -/* $OpenBSD: rfcomm_session.c,v 1.2 2007/09/17 01:33:33 krw Exp $ */ -/* $NetBSD: rfcomm_session.c,v 1.9 2007/04/21 06:15:23 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/rfcomm_session.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/rfcomm_session.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/rfcomm_session.c,v 1.3 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: rfcomm_session.c,v 1.12 2008/01/31 19:30:23 plunky Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -33,8 +33,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include - #include #include #include diff --git a/sys/netbt/rfcomm_socket.c b/sys/netbt/rfcomm_socket.c index 43ddfa4fd7..ff119c0581 100644 --- a/sys/netbt/rfcomm_socket.c +++ b/sys/netbt/rfcomm_socket.c @@ -1,6 +1,6 @@ -/* $OpenBSD: rfcomm_socket.c,v 1.1 2007/06/01 02:46:12 uwe Exp $ */ -/* $NetBSD: rfcomm_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/rfcomm_socket.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/rfcomm_socket.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/rfcomm_socket.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: rfcomm_socket.c,v 1.8 2007/10/15 18:04:34 plunky Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -33,8 +33,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include - /* load symbolic names */ #ifdef BLUETOOTH_DEBUG #define PRUREQUESTS @@ -293,18 +291,20 @@ rfcomm_sattach (struct socket *so, int proto, * Since we have nothing to add, we attach the DLC * structure directly to our PCB pointer. */ - err = rfcomm_attach((struct rfcomm_dlc **)&so->so_pcb, - &rfcomm_proto, so); + err = soreserve(so, rfcomm_sendspace, rfcomm_recvspace, NULL); if (err) return err; - err = soreserve(so, rfcomm_sendspace, rfcomm_recvspace,NULL); + err = rfcomm_attach((struct rfcomm_dlc **)&so->so_pcb, + &rfcomm_proto, so); if (err) return err; err = rfcomm_rcvd(so->so_pcb, sbspace(&so->so_rcv)); - if (err) + if (err) { + rfcomm_detach((struct rfcomm_dlc **)&so->so_pcb); return err; + } return 0; } diff --git a/sys/netbt/rfcomm_upper.c b/sys/netbt/rfcomm_upper.c index dceeac6c7e..62a5eefef0 100644 --- a/sys/netbt/rfcomm_upper.c +++ b/sys/netbt/rfcomm_upper.c @@ -1,6 +1,6 @@ -/* $OpenBSD: rfcomm_upper.c,v 1.3 2007/10/01 16:39:30 krw Exp $ */ -/* $NetBSD: rfcomm_upper.c,v 1.6 2007/04/21 06:15:23 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/rfcomm_upper.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ +/* $DragonFly: src/sys/netbt/rfcomm_upper.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ +/* $OpenBSD: src/sys/netbt/rfcomm_upper.c,v 1.4 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: rfcomm_upper.c,v 1.10 2007/11/20 20:25:57 plunky Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -33,8 +33,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include - #include #include #include @@ -305,20 +303,23 @@ rfcomm_detach(struct rfcomm_dlc **handle) * * This DLC is a listener. We look for an existing listening session * with a matching address to attach to or else create a new one on - * the listeners list. + * the listeners list. If the ANY channel is given, allocate the first + * available for the session. */ int rfcomm_listen(struct rfcomm_dlc *dlc) { - struct rfcomm_session *rs, *any, *best; + struct rfcomm_session *rs; + struct rfcomm_dlc *used; struct sockaddr_bt addr; - int err; + int err, channel; if (dlc->rd_state != RFCOMM_DLC_CLOSED) return EISCONN; - if (dlc->rd_laddr.bt_channel < RFCOMM_CHANNEL_MIN - || dlc->rd_laddr.bt_channel > RFCOMM_CHANNEL_MAX) + if (dlc->rd_laddr.bt_channel != RFCOMM_CHANNEL_ANY + && (dlc->rd_laddr.bt_channel < RFCOMM_CHANNEL_MIN + || dlc->rd_laddr.bt_channel > RFCOMM_CHANNEL_MAX)) return EADDRNOTAVAIL; if (dlc->rd_laddr.bt_psm == L2CAP_PSM_ANY) @@ -328,7 +329,6 @@ rfcomm_listen(struct rfcomm_dlc *dlc) || L2CAP_PSM_INVALID(dlc->rd_laddr.bt_psm))) return EADDRNOTAVAIL; - any = best = NULL; LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) { l2cap_sockaddr(rs->rs_l2cap, &addr); @@ -336,13 +336,9 @@ rfcomm_listen(struct rfcomm_dlc *dlc) continue; if (bdaddr_same(&dlc->rd_laddr.bt_bdaddr, &addr.bt_bdaddr)) - best = rs; - - if (bdaddr_any(&addr.bt_bdaddr)) - any = rs; + break; } - rs = best ? best : any; if (rs == NULL) { rs = rfcomm_session_alloc(&rfcomm_session_listen, &dlc->rd_laddr); @@ -358,6 +354,24 @@ rfcomm_listen(struct rfcomm_dlc *dlc) } } + if (dlc->rd_laddr.bt_channel == RFCOMM_CHANNEL_ANY) { + channel = RFCOMM_CHANNEL_MIN; + used = LIST_FIRST(&rs->rs_dlcs); + + while (used != NULL) { + if (used->rd_laddr.bt_channel == channel) { + if (channel++ == RFCOMM_CHANNEL_MAX) + return EADDRNOTAVAIL; + + used = LIST_FIRST(&rs->rs_dlcs); + } else { + used = LIST_NEXT(used, rd_next); + } + } + + dlc->rd_laddr.bt_channel = channel; + } + dlc->rd_session = rs; dlc->rd_state = RFCOMM_DLC_LISTEN; LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next); diff --git a/sys/netbt/sco.h b/sys/netbt/sco.h index 71be475ac6..c6d734386c 100644 --- a/sys/netbt/sco.h +++ b/sys/netbt/sco.h @@ -1,6 +1,6 @@ +/* $DragonFly: src/sys/netbt/sco.h,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ /* $OpenBSD: sco.h,v 1.2 2007/06/01 02:46:12 uwe Exp $ */ /* $NetBSD: sco.h,v 1.2 2006/07/26 10:20:56 tron Exp $ */ -/* $DragonFly: src/sys/netbt/sco.h,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. diff --git a/sys/netbt/sco_socket.c b/sys/netbt/sco_socket.c index f738eba924..e1b5639ae5 100644 --- a/sys/netbt/sco_socket.c +++ b/sys/netbt/sco_socket.c @@ -1,6 +1,6 @@ +/* $DragonFly: src/sys/netbt/sco_socket.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ /* $OpenBSD: sco_socket.c,v 1.1 2007/06/01 02:46:12 uwe Exp $ */ /* $NetBSD: sco_socket.c,v 1.9 2007/04/21 06:15:23 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/sco_socket.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -109,8 +109,8 @@ sco_ctloutput(struct socket *so, struct sockopt *sopt) m = NULL; err = ENOPROTOOPT; } -/* *opt = m;*/ -#warning Griffin - Theare is possible memory leeks... + /* *opt = m; */ + /* XXX There are possible memory leaks (Griffin) */ err = sooptcopyout(sopt, mtod(m, void *), m->m_len); break; diff --git a/sys/netbt/sco_upper.c b/sys/netbt/sco_upper.c index 3c865d8d36..74778d3a53 100644 --- a/sys/netbt/sco_upper.c +++ b/sys/netbt/sco_upper.c @@ -1,6 +1,6 @@ +/* $DragonFly: src/sys/netbt/sco_upper.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ /* $OpenBSD: sco_upper.c,v 1.2 2007/10/01 16:39:30 krw Exp $ */ /* $NetBSD: sco_upper.c,v 1.6 2007/03/30 20:47:03 plunky Exp $ */ -/* $DragonFly: src/sys/netbt/sco_upper.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. -- 2.11.4.GIT