diff options
-rw-r--r-- | sys/conf/files | 16 | ||||
-rw-r--r-- | sys/netbt/bluetooth.h | 335 | ||||
-rw-r--r-- | sys/netbt/bt.h | 343 | ||||
-rw-r--r-- | sys/netbt/h4.h | 111 | ||||
-rw-r--r-- | sys/netbt/hci.h | 2720 | ||||
-rw-r--r-- | sys/netbt/hci_event.c | 936 | ||||
-rw-r--r-- | sys/netbt/hci_link.c | 1034 | ||||
-rw-r--r-- | sys/netbt/hci_misc.c | 148 | ||||
-rw-r--r-- | sys/netbt/hci_raw.c | 1750 | ||||
-rw-r--r-- | sys/netbt/hci_socket.c | 721 | ||||
-rw-r--r-- | sys/netbt/hci_unit.c | 529 | ||||
-rw-r--r-- | sys/netbt/hci_var.h | 96 | ||||
-rw-r--r-- | sys/netbt/l2cap.h | 859 | ||||
-rw-r--r-- | sys/netbt/l2cap_lower.c | 204 | ||||
-rw-r--r-- | sys/netbt/l2cap_misc.c | 260 | ||||
-rw-r--r-- | sys/netbt/l2cap_signal.c | 1107 | ||||
-rw-r--r-- | sys/netbt/l2cap_var.h | 215 | ||||
-rw-r--r-- | sys/netbt/rfcomm_var.h | 337 | ||||
-rw-r--r-- | sys/netbt/sco.h | 86 |
19 files changed, 7132 insertions, 4675 deletions
diff --git a/sys/conf/files b/sys/conf/files index 7e14394118d..c6f7cee6a3a 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.400 2007/05/29 18:21:19 claudio Exp $ +# $OpenBSD: files,v 1.401 2007/05/30 03:42:53 uwe Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -404,6 +404,7 @@ define pcmciabus {[controller = -1], [socket = -1]} # PCMCIA attachment define cbbus {[slot = -1]} # CardBus attachment define pcmciaslot {[slot = -1]} # PCMCIA slot itself define sdmmcbus {} # SD/MMC attachment +define btbus {} # Bluetooth host controller # UHCI USB controller device uhci: usbus @@ -823,9 +824,16 @@ file netatalk/at_proto.c netatalk file netatalk/ddp_input.c netatalk file netatalk/ddp_output.c netatalk file netatalk/ddp_usrreq.c netatalk -file netbt/bt_input.c bluetooth needs-flag -file netbt/bt_proto.c bluetooth -file netbt/hci_raw.c bluetooth +#file netbt/bt_input.c bluetooth needs-flag +#file netbt/bt_proto.c bluetooth +file netbt/hci_event.c bluetooth +file netbt/hci_link.c bluetooth +file netbt/hci_misc.c bluetooth +file netbt/hci_socket.c bluetooth +file netbt/hci_unit.c bluetooth +file netbt/l2cap_lower.c bluetooth +file netbt/l2cap_misc.c bluetooth +file netbt/l2cap_signal.c bluetooth file netnatm/natm_pcb.c natm file netnatm/natm_proto.c natm file netnatm/natm.c natm diff --git a/sys/netbt/bluetooth.h b/sys/netbt/bluetooth.h index 1e995036e18..796c26625aa 100644 --- a/sys/netbt/bluetooth.h +++ b/sys/netbt/bluetooth.h @@ -1,9 +1,9 @@ -/* $OpenBSD: bluetooth.h,v 1.3 2006/12/01 07:18:34 camield Exp $ */ +/* $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 $ */ -/* - * bluetooth.h - * - * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> +/*- + * Copyright (c) 2005 Iain Hibbert. + * Copyright (c) 2006 Itronix Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -14,250 +14,135 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_bluetooth.h,v 1.3 2003/11/14 03:45:29 emax Exp $ + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _NETGRAPH_BLUETOOTH_H_ -#define _NETGRAPH_BLUETOOTH_H_ +#ifndef _NETBT_BLUETOOTH_H_ +#define _NETBT_BLUETOOTH_H_ -/* - * XXX: This file only contains redundant mbuf wrapppers and must be - * removed later. - */ +#include <sys/socket.h> +#include <sys/types.h> /* - * XXX: dirty temporary hacks. + * Bluetooth Address Family Protocol Numbers */ -#undef KASSERT -#define KASSERT(a, b) -#undef mtx_init -#undef mtx_lock -#undef mtx_unlock -#undef mtx_assert -#undef mtx_destroy -#define mtx_init(a, b, c, d) -#define mtx_lock(a) -#define mtx_unlock(a) -#define mtx_assert(a, b) -#define mtx_destroy(a) -#define ACCEPT_LOCK() -#define SOCK_LOCK(a) +#define BTPROTO_HCI 1 +#define BTPROTO_L2CAP 2 +#define BTPROTO_RFCOMM 3 +#define BTPROTO_SCO 4 -#define NG_FREE_M(m) \ - do { \ - if ((m)) { \ - m_freem((m)); \ - (m) = NULL; \ - } \ - } while (0) +/* All sizes are in bytes */ +#define BLUETOOTH_BDADDR_SIZE 6 /* - * Version of the stack + * Bluetooth device address */ - -#define NG_BLUETOOTH_VERSION 1 +typedef struct { + uint8_t b[BLUETOOTH_BDADDR_SIZE]; +} __attribute__ ((packed)) bdaddr_t; /* - * Declare the base of the Bluetooth sysctl hierarchy, - * but only if this file cares about sysctl's + * bdaddr utility functions */ - -#ifdef SYSCTL_DECL -SYSCTL_DECL(_net_bluetooth); -SYSCTL_DECL(_net_bluetooth_hci); -SYSCTL_DECL(_net_bluetooth_l2cap); -SYSCTL_DECL(_net_bluetooth_rfcomm); -#endif /* SYSCTL_DECL */ +static __inline int +bdaddr_same(const bdaddr_t *a, const bdaddr_t *b) +{ + + return (a->b[0] == b->b[0] && a->b[1] == b->b[1] + && a->b[2] == b->b[2] && a->b[3] == b->b[3] + && a->b[4] == b->b[4] && a->b[5] == b->b[5]); +} + +static __inline int +bdaddr_any(const bdaddr_t *a) +{ + + return (a->b[0] == 0 && a->b[1] == 0 && a->b[2] == 0 + && a->b[3] == 0 && a->b[4] == 0 && a->b[5] == 0); +} + +static __inline void +bdaddr_copy(bdaddr_t *d, const bdaddr_t *s) +{ + + d->b[0] = s->b[0]; + d->b[1] = s->b[1]; + d->b[2] = s->b[2]; + d->b[3] = s->b[3]; + d->b[4] = s->b[4]; + d->b[5] = s->b[5]; +} /* - * Mbuf queue and useful mbufq macros. We do not use ifqueue because we - * do not need mutex and other locking stuff + * Socket address used by Bluetooth protocols */ - -struct mbuf; - -struct ng_bt_mbufq { - struct mbuf *head; /* first item in the queue */ - struct mbuf *tail; /* last item in the queue */ - u_int32_t len; /* number of items in the queue */ - u_int32_t maxlen; /* maximal number of items in the queue */ - u_int32_t drops; /* number if dropped items */ +struct sockaddr_bt { + uint8_t bt_len; + sa_family_t bt_family; + bdaddr_t bt_bdaddr; + uint16_t bt_psm; + uint8_t bt_channel; + uint8_t bt_zero[5]; }; -typedef struct ng_bt_mbufq ng_bt_mbufq_t; -typedef struct ng_bt_mbufq * ng_bt_mbufq_p; - -#define NG_BT_MBUFQ_INIT(q, _maxlen) \ - do { \ - (q)->head = NULL; \ - (q)->tail = NULL; \ - (q)->len = 0; \ - (q)->maxlen = (_maxlen); \ - (q)->drops = 0; \ - } while (0) - -#define NG_BT_MBUFQ_DESTROY(q) \ - do { \ - NG_BT_MBUFQ_DRAIN((q)); \ - } while (0) - -#define NG_BT_MBUFQ_FIRST(q) (q)->head - -#define NG_BT_MBUFQ_LEN(q) (q)->len - -#define NG_BT_MBUFQ_FULL(q) ((q)->len >= (q)->maxlen) - -#define NG_BT_MBUFQ_DROP(q) (q)->drops ++ - -#define NG_BT_MBUFQ_ENQUEUE(q, i) \ - do { \ - (i)->m_nextpkt = NULL; \ - \ - if ((q)->tail == NULL) \ - (q)->head = (i); \ - else \ - (q)->tail->m_nextpkt = (i); \ - \ - (q)->tail = (i); \ - (q)->len ++; \ - } while (0) -#define NG_BT_MBUFQ_DEQUEUE(q, i) \ - do { \ - (i) = (q)->head; \ - if ((i) != NULL) { \ - (q)->head = (q)->head->m_nextpkt; \ - if ((q)->head == NULL) \ - (q)->tail = NULL; \ - \ - (q)->len --; \ - (i)->m_nextpkt = NULL; \ - } \ - } while (0) +/* Note: this is actually 6 bytes including terminator */ +#define BDADDR_ANY ((const bdaddr_t *) "\000\000\000\000\000") -#define NG_BT_MBUFQ_PREPEND(q, i) \ - do { \ - (i)->m_nextpkt = (q)->head; \ - if ((q)->tail == NULL) \ - (q)->tail = (i); \ - \ - (q)->head = (i); \ - (q)->len ++; \ - } while (0) +#ifdef _KERNEL -#define NG_BT_MBUFQ_DRAIN(q) \ - do { \ - struct mbuf *m = NULL; \ - \ - for (;;) { \ - NG_BT_MBUFQ_DEQUEUE((q), m); \ - if (m == NULL) \ - break; \ - \ - NG_FREE_M(m); \ - } \ - } while (0) - -/* - * Netgraph item queue and useful itemq macros +/* + * Bluetooth Protocol API callback methods */ - -struct ng_item; - -struct ng_bt_itemq { - struct ng_item *head; /* first item in the queue */ - struct ng_item *tail; /* last item in the queue */ - u_int32_t len; /* number of items in the queue */ - u_int32_t maxlen; /* maximal number of items in the queue */ - u_int32_t drops; /* number if dropped items */ +struct mbuf; +struct btproto { + void (*connecting)(void *); + void (*connected)(void *); + void (*disconnected)(void *, int); + void *(*newconn)(void *, struct sockaddr_bt *, struct sockaddr_bt *); + void (*complete)(void *, int); + void (*linkmode)(void *, int); + void (*input)(void *, struct mbuf *); }; -typedef struct ng_bt_itemq ng_bt_itemq_t; -typedef struct ng_bt_itemq * ng_bt_itemq_p; - -#define NG_BT_ITEMQ_INIT(q, _maxlen) NG_BT_MBUFQ_INIT((q), (_maxlen)) - -#define NG_BT_ITEMQ_DESTROY(q) \ - do { \ - NG_BT_ITEMQ_DRAIN((q)); \ - } while (0) - -#define NG_BT_ITEMQ_FIRST(q) NG_BT_MBUFQ_FIRST((q)) - -#define NG_BT_ITEMQ_LEN(q) NG_BT_MBUFQ_LEN((q)) - -#define NG_BT_ITEMQ_FULL(q) NG_BT_MBUFQ_FULL((q)) - -#define NG_BT_ITEMQ_DROP(q) NG_BT_MBUFQ_DROP((q)) - -#define NG_BT_ITEMQ_ENQUEUE(q, i) \ - do { \ - (i)->el_next = NULL; \ - \ - if ((q)->tail == NULL) \ - (q)->head = (i); \ - else \ - (q)->tail->el_next = (i); \ - \ - (q)->tail = (i); \ - (q)->len ++; \ - } while (0) - -#define NG_BT_ITEMQ_DEQUEUE(q, i) \ - do { \ - (i) = (q)->head; \ - if ((i) != NULL) { \ - (q)->head = (q)->head->el_next; \ - if ((q)->head == NULL) \ - (q)->tail = NULL; \ - \ - (q)->len --; \ - (i)->el_next = NULL; \ - } \ - } while (0) - -#define NG_BT_ITEMQ_PREPEND(q, i) \ - do { \ - (i)->el_next = (q)->head; \ - if ((q)->tail == NULL) \ - (q)->tail = (i); \ - \ - (q)->head = (i); \ - (q)->len ++; \ - } while (0) - -#define NG_BT_ITEMQ_DRAIN(q) \ - do { \ - struct ng_item *i = NULL; \ - \ - for (;;) { \ - NG_BT_ITEMQ_DEQUEUE((q), i); \ - if (i == NULL) \ - break; \ - \ - NG_FREE_ITEM(i); \ - } \ - } while (0) /* - * Get Bluetooth stack sysctl globals + * Debugging stuff */ -u_int32_t bluetooth_hci_command_timeout (void); -u_int32_t bluetooth_hci_connect_timeout (void); -u_int32_t bluetooth_hci_max_neighbor_age (void); -u_int32_t bluetooth_l2cap_rtx_timeout (void); -u_int32_t bluetooth_l2cap_ertx_timeout (void); - -#endif /* _NETGRAPH_BLUETOOTH_H_ */ +#define BLUETOOTH_DEBUG +#ifdef BLUETOOTH_DEBUG +extern int bluetooth_debug; +# define DPRINTF(fmt, args...) do { \ + if (bluetooth_debug) \ + printf("%s: "fmt, __func__ , ##args); \ +} while (/* CONSTCOND */0) + +# define DPRINTFN(n, fmt, args...) do { \ + if (bluetooth_debug > (n)) \ + printf("%s: "fmt, __func__ , ##args); \ +} while (/* CONSTCOND */0) + +# define UNKNOWN(value) \ + printf("%s: %s = %d unknown!\n", __func__, #value, (value)); +#else +# define DPRINTF(...) +# define DPRINTFN(...) +# define UNKNOWN(x) +#endif /* BLUETOOTH_DEBUG */ + +#endif /* _KERNEL */ + +#endif /* _NETBT_BLUETOOTH_H_ */ diff --git a/sys/netbt/bt.h b/sys/netbt/bt.h deleted file mode 100644 index 75bf8c6dd07..00000000000 --- a/sys/netbt/bt.h +++ /dev/null @@ -1,343 +0,0 @@ -/* $OpenBSD: bt.h,v 1.2 2005/01/17 18:12:49 mickey Exp $ */ - -/* - * ng_btsocket.h - * - * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_btsocket.h,v 1.6 2004/08/20 01:24:23 julian Exp $ - */ - -#ifndef _NETGRAPH_BTSOCKET_H_ -#define _NETGRAPH_BTSOCKET_H_ - -/* - * XXX: bitstring operations, must be removed later. - */ -typedef unsigned char bitstr_t; -#define bitstr_size(nbits) (((nbits) + 7) >> 3) -#define bit_decl(name, nbits) ((name)[bitstr_size(nbits)]) -#define _bit_byte(bit) ((bit) >> 3) -#define _bit_mask(bit) (1 << ((bit)&0x7)) -#define bit_test(name, bit) ((name)[_bit_byte(bit)] & _bit_mask(bit)) -#define bit_set(name, bit) ((name)[_bit_byte(bit)] |= _bit_mask(bit)) -#define bit_clear(name, bit) ((name)[_bit_byte(bit)] &= ~_bit_mask(bit)) - -/* - * Bluetooth protocols - */ - -#define BLUETOOTH_PROTO_HCI 134 /* HCI protocol number */ -#define BLUETOOTH_PROTO_L2CAP 135 /* L2CAP protocol number */ -#define BLUETOOTH_PROTO_RFCOMM 136 /* RFCOMM protocol number */ - -/* - * Bluetooth version of struct sockaddr for raw HCI sockets - */ - -struct sockaddr_hci { - u_char hci_len; /* total length */ - u_char hci_family; /* address family */ - char hci_node[32]; /* address (size == NG_NODESIZ ) */ -}; - -/* Raw HCI socket options */ -#define SOL_HCI_RAW 0x0802 /* socket options level */ - -#define SO_HCI_RAW_FILTER 1 /* get/set filter on socket */ -#define SO_HCI_RAW_DIRECTION 2 /* turn on/off direction info */ -#define SCM_HCI_RAW_DIRECTION SO_HCI_RAW_DIRECTION /* cmsg_type */ - -/* - * Raw HCI socket filter. - * - * For packet mask use (1 << (HCI packet indicator - 1)) - * For event mask use (1 << (Event - 1)) - */ - -struct ng_btsocket_hci_raw_filter { - bitstr_t bit_decl(packet_mask, 32); - bitstr_t bit_decl(event_mask, (NG_HCI_EVENT_MASK_SIZE * 8)); -}; - -/* - * Raw HCI sockets ioctl's - */ - -/* Get state */ -struct ng_btsocket_hci_raw_node_state { - ng_hci_node_state_ep state; -}; -#define SIOC_HCI_RAW_NODE_GET_STATE \ - _IOWR('b', NGM_HCI_NODE_GET_STATE, \ - struct ng_btsocket_hci_raw_node_state) - -/* Initialize */ -#define SIOC_HCI_RAW_NODE_INIT \ - _IO('b', NGM_HCI_NODE_INIT) - -/* Get/Set debug level */ -struct ng_btsocket_hci_raw_node_debug { - ng_hci_node_debug_ep debug; -}; -#define SIOC_HCI_RAW_NODE_GET_DEBUG \ - _IOWR('b', NGM_HCI_NODE_GET_DEBUG, \ - struct ng_btsocket_hci_raw_node_debug) -#define SIOC_HCI_RAW_NODE_SET_DEBUG \ - _IOWR('b', NGM_HCI_NODE_SET_DEBUG, \ - struct ng_btsocket_hci_raw_node_debug) - -/* Get buffer info */ -struct ng_btsocket_hci_raw_node_buffer { - ng_hci_node_buffer_ep buffer; -}; -#define SIOC_HCI_RAW_NODE_GET_BUFFER \ - _IOWR('b', NGM_HCI_NODE_GET_BUFFER, \ - struct ng_btsocket_hci_raw_node_buffer) - -/* Get BD_ADDR */ -struct ng_btsocket_hci_raw_node_bdaddr { - bdaddr_t bdaddr; -}; -#define SIOC_HCI_RAW_NODE_GET_BDADDR \ - _IOWR('b', NGM_HCI_NODE_GET_BDADDR, \ - struct ng_btsocket_hci_raw_node_bdaddr) - -/* Get features */ -struct ng_btsocket_hci_raw_node_features { - u_int8_t features[NG_HCI_FEATURES_SIZE]; -}; -#define SIOC_HCI_RAW_NODE_GET_FEATURES \ - _IOWR('b', NGM_HCI_NODE_GET_FEATURES, \ - struct ng_btsocket_hci_raw_node_features) - -/* Get stat */ -struct ng_btsocket_hci_raw_node_stat { - ng_hci_node_stat_ep stat; -}; -#define SIOC_HCI_RAW_NODE_GET_STAT \ - _IOWR('b', NGM_HCI_NODE_GET_STAT, \ - struct ng_btsocket_hci_raw_node_stat) - -/* Reset stat */ -#define SIOC_HCI_RAW_NODE_RESET_STAT \ - _IO('b', NGM_HCI_NODE_RESET_STAT) - -/* Flush neighbor cache */ -#define SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE \ - _IO('b', NGM_HCI_NODE_FLUSH_NEIGHBOR_CACHE) - -/* Get neighbor cache */ -struct ng_btsocket_hci_raw_node_neighbor_cache { - u_int32_t num_entries; - ng_hci_node_neighbor_cache_entry_ep *entries; -}; -#define SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE \ - _IOWR('b', NGM_HCI_NODE_GET_NEIGHBOR_CACHE, \ - struct ng_btsocket_hci_raw_node_neighbor_cache) - -/* Get connection list */ -struct ng_btsocket_hci_raw_con_list { - u_int32_t num_connections; - ng_hci_node_con_ep *connections; -}; -#define SIOC_HCI_RAW_NODE_GET_CON_LIST \ - _IOWR('b', NGM_HCI_NODE_GET_CON_LIST, \ - struct ng_btsocket_hci_raw_con_list) - -/* Get/Set link policy settings mask */ -struct ng_btsocket_hci_raw_node_link_policy_mask { - ng_hci_node_link_policy_mask_ep policy_mask; -}; -#define SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK \ - _IOWR('b', NGM_HCI_NODE_GET_LINK_POLICY_SETTINGS_MASK, \ - struct ng_btsocket_hci_raw_node_link_policy_mask) -#define SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK \ - _IOWR('b', NGM_HCI_NODE_SET_LINK_POLICY_SETTINGS_MASK, \ - struct ng_btsocket_hci_raw_node_link_policy_mask) - -/* Get/Set packet mask */ -struct ng_btsocket_hci_raw_node_packet_mask { - ng_hci_node_packet_mask_ep packet_mask; -}; -#define SIOC_HCI_RAW_NODE_GET_PACKET_MASK \ - _IOWR('b', NGM_HCI_NODE_GET_PACKET_MASK, \ - struct ng_btsocket_hci_raw_node_packet_mask) -#define SIOC_HCI_RAW_NODE_SET_PACKET_MASK \ - _IOWR('b', NGM_HCI_NODE_SET_PACKET_MASK, \ - struct ng_btsocket_hci_raw_node_packet_mask) - -/* Get/Set role switch */ -struct ng_btsocket_hci_raw_node_role_switch { - ng_hci_node_role_switch_ep role_switch; -}; -#define SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH \ - _IOWR('b', NGM_HCI_NODE_GET_ROLE_SWITCH, \ - struct ng_btsocket_hci_raw_node_role_switch) -#define SIOC_HCI_RAW_NODE_SET_ROLE_SWITCH \ - _IOWR('b', NGM_HCI_NODE_SET_ROLE_SWITCH, \ - struct ng_btsocket_hci_raw_node_role_switch) - -/* - * XXX FIXME: probably does not belong here - * Bluetooth version of struct sockaddr for L2CAP sockets (RAW and SEQPACKET) - */ - -struct sockaddr_l2cap { - u_char l2cap_len; /* total length */ - u_char l2cap_family; /* address family */ - u_int16_t l2cap_psm; /* PSM (Protocol/Service Multiplexor) */ - bdaddr_t l2cap_bdaddr; /* address */ -}; - -/* L2CAP socket options */ -#define SOL_L2CAP 0x1609 /* socket option level */ - -#define SO_L2CAP_IMTU 1 /* get/set incoming MTU */ -#define SO_L2CAP_OMTU 2 /* get outgoing (peer incoming) MTU */ -#define SO_L2CAP_IFLOW 3 /* get incoming flow spec. */ -#define SO_L2CAP_OFLOW 4 /* get/set outgoing flow spec. */ -#define SO_L2CAP_FLUSH 5 /* get/set flush timeout */ - -/* - * Raw L2CAP sockets ioctl's - */ - -/* Ping */ -struct ng_btsocket_l2cap_raw_ping { - u_int32_t result; - u_int32_t echo_size; - u_int8_t *echo_data; -}; -#define SIOC_L2CAP_L2CA_PING \ - _IOWR('b', NGM_L2CAP_L2CA_PING, \ - struct ng_btsocket_l2cap_raw_ping) - -/* Get info */ -struct ng_btsocket_l2cap_raw_get_info { - u_int32_t result; - u_int32_t info_type; - u_int32_t info_size; - u_int8_t *info_data; -}; -#define SIOC_L2CAP_L2CA_GET_INFO \ - _IOWR('b', NGM_L2CAP_L2CA_GET_INFO, \ - struct ng_btsocket_l2cap_raw_get_info) - -/* Get flags */ -struct ng_btsocket_l2cap_raw_node_flags { - ng_l2cap_node_flags_ep flags; -}; -#define SIOC_L2CAP_NODE_GET_FLAGS \ - _IOWR('b', NGM_L2CAP_NODE_GET_FLAGS, \ - struct ng_btsocket_l2cap_raw_node_flags) - -/* Get/Set debug level */ -struct ng_btsocket_l2cap_raw_node_debug { - ng_l2cap_node_debug_ep debug; -}; -#define SIOC_L2CAP_NODE_GET_DEBUG \ - _IOWR('b', NGM_L2CAP_NODE_GET_DEBUG, \ - struct ng_btsocket_l2cap_raw_node_debug) -#define SIOC_L2CAP_NODE_SET_DEBUG \ - _IOWR('b', NGM_L2CAP_NODE_SET_DEBUG, \ - struct ng_btsocket_l2cap_raw_node_debug) - -/* Get connection list */ -struct ng_btsocket_l2cap_raw_con_list { - u_int32_t num_connections; - ng_l2cap_node_con_ep *connections; -}; -#define SIOC_L2CAP_NODE_GET_CON_LIST \ - _IOWR('b', NGM_L2CAP_NODE_GET_CON_LIST, \ - struct ng_btsocket_l2cap_raw_con_list) - -/* Get channel list */ -struct ng_btsocket_l2cap_raw_chan_list { - u_int32_t num_channels; - ng_l2cap_node_chan_ep *channels; -}; -#define SIOC_L2CAP_NODE_GET_CHAN_LIST \ - _IOWR('b', NGM_L2CAP_NODE_GET_CHAN_LIST, \ - struct ng_btsocket_l2cap_raw_chan_list) - -/* Get/Set auto disconnect timeout */ -struct ng_btsocket_l2cap_raw_auto_discon_timo -{ - ng_l2cap_node_auto_discon_ep timeout; -}; -#define SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO \ - _IOWR('b', NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO, \ - struct ng_btsocket_l2cap_raw_auto_discon_timo) -#define SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO \ - _IOWR('b', NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO, \ - struct ng_btsocket_l2cap_raw_auto_discon_timo) - -/* - * XXX FIXME: probably does not belong here - * Bluetooth version of struct sockaddr for RFCOMM sockets (STREAM) - */ - -struct sockaddr_rfcomm { - u_char rfcomm_len; /* total length */ - u_char rfcomm_family; /* address family */ - bdaddr_t rfcomm_bdaddr; /* address */ - u_int8_t rfcomm_channel; /* channel */ -}; - -/* Flow control information */ -struct ng_btsocket_rfcomm_fc_info { - u_int8_t lmodem; /* modem signals (local) */ - u_int8_t rmodem; /* modem signals (remote) */ - u_int8_t tx_cred; /* TX credits */ - u_int8_t rx_cred; /* RX credits */ - u_int8_t cfc; /* credit flow control */ - u_int8_t reserved; -}; - -/* STREAM RFCOMM socket options */ -#define SOL_RFCOMM 0x0816 /* socket options level */ - -#define SO_RFCOMM_MTU 1 /* get channel MTU */ -#define SO_RFCOMM_FC_INFO 2 /* get flow control information */ - -/* - * Netgraph node type name and cookie - */ - -#define NG_BTSOCKET_HCI_RAW_NODE_TYPE "btsock_hci_raw" -#define NG_BTSOCKET_L2CAP_RAW_NODE_TYPE "btsock_l2c_raw" -#define NG_BTSOCKET_L2CAP_NODE_TYPE "btsock_l2c" - -/* - * Debug levels - */ - -#define NG_BTSOCKET_ALERT_LEVEL 1 -#define NG_BTSOCKET_ERR_LEVEL 2 -#define NG_BTSOCKET_WARN_LEVEL 3 -#define NG_BTSOCKET_INFO_LEVEL 4 - -#endif /* _NETGRAPH_BTSOCKET_H_ */ diff --git a/sys/netbt/h4.h b/sys/netbt/h4.h deleted file mode 100644 index 224d9d085d0..00000000000 --- a/sys/netbt/h4.h +++ /dev/null @@ -1,111 +0,0 @@ -/* $OpenBSD: h4.h,v 1.2 2005/01/17 18:12:49 mickey Exp $ */ - -/* - * ng_h4.h - * - * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_h4.h,v 1.4 2004/05/10 02:24:55 emax Exp $ - * - * Based on: - * --------- - * - * FreeBSD: src/sys/netgraph/ng_tty.h - * Author: Archie Cobbs <archie@freebsd.org> - */ - -/* - * This file contains everything that application needs to know about - * Bluetooth HCI UART transport layer as per chapter H4 of the Bluetooth - * Specification Book v1.1. - * - * This file can be included by both kernel and userland applications. - */ - -#ifndef _NETGRAPH_H4_H_ -#define _NETGRAPH_H4_H_ - -/************************************************************************** - ************************************************************************** - ** Netgraph node hook name, type name and type cookie and commands - ************************************************************************** - **************************************************************************/ - -/* Hook name */ -#define NG_H4_HOOK "hook" - -/* Node type name and magic cookie */ -#define NG_H4_NODE_TYPE "h4" -#define NGM_H4_COOKIE 1013899512 - -/* Node states */ -#define NG_H4_W4_PKT_IND 1 /* Waiting for packet indicator */ -#define NG_H4_W4_PKT_HDR 2 /* Waiting for packet header */ -#define NG_H4_W4_PKT_DATA 3 /* Waiting for packet data */ - -/* Debug levels */ -#define NG_H4_ALERT_LEVEL 1 -#define NG_H4_ERR_LEVEL 2 -#define NG_H4_WARN_LEVEL 3 -#define NG_H4_INFO_LEVEL 4 - -/************************************************************************** - ************************************************************************** - ** H4 node command/event parameters - ************************************************************************** - **************************************************************************/ - -/* Reset node */ -#define NGM_H4_NODE_RESET 1 - -/* Get node state (see states above) */ -#define NGM_H4_NODE_GET_STATE 2 -typedef u_int16_t ng_h4_node_state_ep; - -/* Get/Set node debug level (see levels above) */ -#define NGM_H4_NODE_GET_DEBUG 3 -#define NGM_H4_NODE_SET_DEBUG 4 -typedef u_int16_t ng_h4_node_debug_ep; - -/* Get/Set max queue length for the node */ -#define NGM_H4_NODE_GET_QLEN 5 -#define NGM_H4_NODE_SET_QLEN 6 -typedef int32_t ng_h4_node_qlen_ep; - -/* Get node statistic */ -#define NGM_H4_NODE_GET_STAT 7 -typedef struct { - u_int32_t pckts_recv; /* # of packets received */ - u_int32_t bytes_recv; /* # of bytes received */ - u_int32_t pckts_sent; /* # of packets sent */ - u_int32_t bytes_sent; /* # of bytes sent */ - u_int32_t oerrors; /* # of output errors */ - u_int32_t ierrors; /* # of input errors */ -} ng_h4_node_stat_ep; - -/* Reset node statistic */ -#define NGM_H4_NODE_RESET_STAT 8 - -#endif /* _NETGRAPH_H4_H_ */ diff --git a/sys/netbt/hci.h b/sys/netbt/hci.h index 7ac3143fea6..cab7f897649 100644 --- a/sys/netbt/hci.h +++ b/sys/netbt/hci.h @@ -1,8 +1,36 @@ -/* $OpenBSD: hci.h,v 1.3 2005/07/15 21:16:40 grange Exp $ */ +/* $OpenBSD: hci.h,v 1.4 2007/05/30 03:42:53 uwe Exp $ */ +/* $NetBSD: hci.h,v 1.10 2007/04/21 06:15:23 plunky Exp $ */ -/* - * ng_hci.h +/*- + * Copyright (c) 2005 Iain Hibbert. + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/*- * Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com> * All rights reserved. * @@ -27,40 +55,27 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_hci.h,v 1.4 2004/08/10 00:38:50 emax Exp $ + * $Id: hci.h,v 1.4 2007/05/30 03:42:53 uwe 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 application needs to know about - * Host Controller Interface (HCI). All information was obtained from - * Bluetooth Specification Book v1.1. + * 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) * * This file can be included by both kernel and userland applications. * * NOTE: Here and after Bluetooth device is called a "unit". Bluetooth * specification refers to both devices and units. They are the - * same thing (i think), so to be consistent word "unit" will be + * same thing (I think), so to be consistent word "unit" will be * used. */ -#ifndef _NETGRAPH_HCI_H_ -#define _NETGRAPH_HCI_H_ +#ifndef _NETBT_HCI_H_ +#define _NETBT_HCI_H_ -/************************************************************************** - ************************************************************************** - ** Netgraph node hook name, type name and type cookie and commands - ************************************************************************** - **************************************************************************/ - -/* Node type name and type cookie */ -#define NG_HCI_NODE_TYPE "hci" -#define NGM_HCI_COOKIE 1000774184 - -/* Netgraph node hook names */ -#define NG_HCI_HOOK_DRV "drv" /* Driver <-> HCI */ -#define NG_HCI_HOOK_ACL "acl" /* HCI <-> Upper */ -#define NG_HCI_HOOK_SCO "sco" /* HCI <-> Upper */ -#define NG_HCI_HOOK_RAW "raw" /* HCI <-> Upper */ +#include <netbt/bluetooth.h> /************************************************************************** ************************************************************************** @@ -68,231 +83,270 @@ ************************************************************************** **************************************************************************/ -/* All sizes are in bytes */ -#define NG_HCI_BDADDR_SIZE 6 /* unit address */ -#define NG_HCI_LAP_SIZE 3 /* unit LAP */ -#define NG_HCI_KEY_SIZE 16 /* link key */ -#define NG_HCI_PIN_SIZE 16 /* link PIN */ -#define NG_HCI_EVENT_MASK_SIZE 8 /* event mask */ -#define NG_HCI_CLASS_SIZE 3 /* unit class */ -#define NG_HCI_FEATURES_SIZE 8 /* LMP features */ -#define NG_HCI_UNIT_NAME_SIZE 248 /* unit name size */ +#define HCI_LAP_SIZE 3 /* unit LAP */ +#define HCI_KEY_SIZE 16 /* link key */ +#define HCI_PIN_SIZE 16 /* link PIN */ +#define HCI_EVENT_MASK_SIZE 8 /* event mask */ +#define HCI_CLASS_SIZE 3 /* unit class */ +#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 */ /* HCI specification */ -#define NG_HCI_SPEC_V10 0x00 /* v1.0 */ -#define NG_HCI_SPEC_V11 0x01 /* v1.1 */ +#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 */ -/* LMP features */ +/* LMP features (and page 0 of extended features) */ /* ------------------- byte 0 --------------------*/ -#define NG_HCI_LMP_3SLOT 0x01 -#define NG_HCI_LMP_5SLOT 0x02 -#define NG_HCI_LMP_ENCRYPTION 0x04 -#define NG_HCI_LMP_SLOT_OFFSET 0x08 -#define NG_HCI_LMP_TIMING_ACCURACY 0x10 -#define NG_HCI_LMP_SWITCH 0x20 -#define NG_HCI_LMP_HOLD_MODE 0x40 -#define NG_HCI_LMP_SNIFF_MODE 0x80 +#define HCI_LMP_3SLOT 0x01 +#define HCI_LMP_5SLOT 0x02 +#define HCI_LMP_ENCRYPTION 0x04 +#define HCI_LMP_SLOT_OFFSET 0x08 +#define HCI_LMP_TIMIACCURACY 0x10 +#define HCI_LMP_ROLE_SWITCH 0x20 +#define HCI_LMP_HOLD_MODE 0x40 +#define HCI_LMP_SNIFF_MODE 0x80 /* ------------------- byte 1 --------------------*/ -#define NG_HCI_LMP_PARK_MODE 0x01 -#define NG_HCI_LMP_RSSI 0x02 -#define NG_HCI_LMP_CHANNEL_QUALITY 0x04 -#define NG_HCI_LMP_SCO_LINK 0x08 -#define NG_HCI_LMP_HV2_PKT 0x10 -#define NG_HCI_LMP_HV3_PKT 0x20 -#define NG_HCI_LMP_ULAW_LOG 0x40 -#define NG_HCI_LMP_ALAW_LOG 0x80 +#define HCI_LMP_PARK_MODE 0x01 +#define HCI_LMP_RSSI 0x02 +#define HCI_LMP_CHANNEL_QUALITY 0x04 +#define HCI_LMP_SCO_LINK 0x08 +#define HCI_LMP_HV2_PKT 0x10 +#define HCI_LMP_HV3_PKT 0x20 +#define HCI_LMP_ULAW_LOG 0x40 +#define HCI_LMP_ALAW_LOG 0x80 /* ------------------- byte 2 --------------------*/ -#define NG_HCI_LMP_CVSD 0x01 -#define NG_HCI_LMP_PAGING_SCHEME 0x02 -#define NG_HCI_LMP_POWER_CONTROL 0x04 -#define NG_HCI_LMP_TRANSPARENT_SCO 0x08 -#define NG_HCI_LMP_FLOW_CONTROL_LAG0 0x10 -#define NG_HCI_LMP_FLOW_CONTROL_LAG1 0x20 -#define NG_HCI_LMP_FLOW_CONTROL_LAG2 0x40 +#define HCI_LMP_CVSD 0x01 +#define HCI_LMP_PAGISCHEME 0x02 +#define HCI_LMP_POWER_CONTROL 0x04 +#define HCI_LMP_TRANSPARENT_SCO 0x08 +#define HCI_LMP_FLOW_CONTROL_LAG0 0x10 +#define HCI_LMP_FLOW_CONTROL_LAG1 0x20 +#define HCI_LMP_FLOW_CONTROL_LAG2 0x40 +#define HCI_LMP_BC_ENCRYPTION 0x80 +/* ------------------- byte 3 --------------------*/ +/* reserved 0x01 */ +#define HCI_LMP_EDR_ACL_2MBPS 0x02 +#define HCI_LMP_EDR_ACL_3MBPS 0x04 +#define HCI_LMP_ENHANCED_ISCAN 0x08 +#define HCI_LMP_INTERLACED_ISCAN 0x10 +#define HCI_LMP_INTERLACED_PSCAN 0x20 +#define HCI_LMP_RSSI_INQUIRY 0x40 +#define HCI_LMP_EV3_PKT 0x80 +/* ------------------- byte 4 --------------------*/ +#define HCI_LMP_EV4_PKT 0x01 +#define HCI_LMP_EV5_PKT 0x02 +/* reserved 0x04 */ +#define HCI_LMP_AFH_CAPABLE_SLAVE 0x08 +#define HCI_LMP_AFH_CLASS_SLAVE 0x10 +/* reserved 0x20 */ +/* reserved 0x40 */ +#define HCI_LMP_3SLOT_EDR_ACL 0x80 +/* ------------------- byte 5 --------------------*/ +#define HCI_LMP_5SLOT_EDR_ACL 0x01 +/* reserved 0x02 */ +/* reserved 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 */ +/* ------------------- byte 7 --------------------*/ +#define HCI_LMP_EXTENDED_FEATURES 0x80 /* Link types */ -#define NG_HCI_LINK_SCO 0x00 /* Voice */ -#define NG_HCI_LINK_ACL 0x01 /* Data */ -/* 0x02 - 0xFF - reserved for future use */ +#define HCI_LINK_SCO 0x00 /* Voice */ +#define HCI_LINK_ACL 0x01 /* Data */ +#define HCI_LINK_eSCO 0x02 /* eSCO */ +/* 0x03 - 0xFF - reserved for future use */ -/* Packet types */ - /* 0x0001 - 0x0004 - reserved for future use */ -#define NG_HCI_PKT_DM1 0x0008 /* ACL link */ -#define NG_HCI_PKT_DH1 0x0010 /* ACL link */ -#define NG_HCI_PKT_HV1 0x0020 /* SCO link */ -#define NG_HCI_PKT_HV2 0x0040 /* SCO link */ -#define NG_HCI_PKT_HV3 0x0080 /* SCO link */ - /* 0x0100 - 0x0200 - reserved for future use */ -#define NG_HCI_PKT_DM3 0x0400 /* ACL link */ -#define NG_HCI_PKT_DH3 0x0800 /* ACL link */ - /* 0x1000 - 0x2000 - reserved for future use */ -#define NG_HCI_PKT_DM5 0x4000 /* ACL link */ -#define NG_HCI_PKT_DH5 0x8000 /* ACL link */ - -/* +/* + * ACL/SCO packet type bits are set to enable the + * packet type, except for 2MBPS and 3MBPS when they + * are unset to enable the packet type. + */ +/* ACL Packet types for "Create Connection" */ +#define HCI_PKT_2MBPS_DH1 0x0002 +#define HCI_PKT_3MBPS_DH1 0x0004 +#define HCI_PKT_DM1 0x0008 +#define HCI_PKT_DH1 0x0010 +#define HCI_PKT_2MBPS_DH3 0x0100 +#define HCI_PKT_3MBPS_DH3 0x0200 +#define HCI_PKT_DM3 0x0400 +#define HCI_PKT_DH3 0x0800 +#define HCI_PKT_2MBPS_DH5 0x1000 +#define HCI_PKT_3MBPS_DH5 0x2000 +#define HCI_PKT_DM5 0x4000 +#define HCI_PKT_DH5 0x8000 + +/* SCO Packet types for "Setup Synchronous Connection" */ +#define HCI_PKT_HV1 0x0001 +#define HCI_PKT_HV2 0x0002 +#define HCI_PKT_HV3 0x0004 +#define HCI_PKT_EV3 0x0008 +#define HCI_PKT_EV4 0x0010 +#define HCI_PKT_EV5 0x0020 +#define HCI_PKT_2MBPS_EV3 0x0040 +#define HCI_PKT_3MBPS_EV3 0x0080 +#define HCI_PKT_2MBPS_EV5 0x0100 +#define HCI_PKT_3MBPS_EV5 0x0200 + +/* * Connection modes/Unit modes * * This is confusing. It means that one of the units change its mode - * for the specific connection. For example one connection was put on - * hold (but i could be wrong :) + * for the specific connection. For example one connection was put on + * hold (but i could be wrong :) */ -#define NG_HCI_UNIT_MODE_ACTIVE 0x00 -#define NG_HCI_UNIT_MODE_HOLD 0x01 -#define NG_HCI_UNIT_MODE_SNIFF 0x02 -#define NG_HCI_UNIT_MODE_PARK 0x03 -/* 0x04 - 0xFF - reserved for future use */ - -/* Page scan modes */ -#define NG_HCI_MANDATORY_PAGE_SCAN_MODE 0x00 -#define NG_HCI_OPTIONAL_PAGE_SCAN_MODE1 0x01 -#define NG_HCI_OPTIONAL_PAGE_SCAN_MODE2 0x02 -#define NG_HCI_OPTIONAL_PAGE_SCAN_MODE3 0x03 +/* Page scan modes (are deprecated) */ +#define HCI_MANDATORY_PAGE_SCAN_MODE 0x00 +#define HCI_OPTIONAL_PAGE_SCAN_MODE1 0x01 +#define HCI_OPTIONAL_PAGE_SCAN_MODE2 0x02 +#define HCI_OPTIONAL_PAGE_SCAN_MODE3 0x03 /* 0x04 - 0xFF - reserved for future use */ /* Page scan repetition modes */ -#define NG_HCI_SCAN_REP_MODE0 0x00 -#define NG_HCI_SCAN_REP_MODE1 0x01 -#define NG_HCI_SCAN_REP_MODE2 0x02 +#define HCI_SCAN_REP_MODE0 0x00 +#define HCI_SCAN_REP_MODE1 0x01 +#define HCI_SCAN_REP_MODE2 0x02 /* 0x03 - 0xFF - reserved for future use */ /* Page scan period modes */ -#define NG_HCI_PAGE_SCAN_PERIOD_MODE0 0x00 -#define NG_HCI_PAGE_SCAN_PERIOD_MODE1 0x01 -#define NG_HCI_PAGE_SCAN_PERIOD_MODE2 0x02 +#define HCI_PAGE_SCAN_PERIOD_MODE0 0x00 +#define HCI_PAGE_SCAN_PERIOD_MODE1 0x01 +#define HCI_PAGE_SCAN_PERIOD_MODE2 0x02 /* 0x03 - 0xFF - reserved for future use */ /* Scan enable */ -#define NG_HCI_NO_SCAN_ENABLE 0x00 -#define NG_HCI_INQUIRY_ENABLE_PAGE_DISABLE 0x01 -#define NG_HCI_INQUIRY_DISABLE_PAGE_ENABLE 0x02 -#define NG_HCI_INQUIRY_ENABLE_PAGE_ENABLE 0x03 +#define HCI_NO_SCAN_ENABLE 0x00 +#define HCI_INQUIRY_SCAN_ENABLE 0x01 +#define HCI_PAGE_SCAN_ENABLE 0x02 /* 0x04 - 0xFF - reserved for future use */ /* Hold mode activities */ -#define NG_HCI_HOLD_MODE_NO_CHANGE 0x00 -#define NG_HCI_HOLD_MODE_SUSPEND_PAGE_SCAN 0x01 -#define NG_HCI_HOLD_MODE_SUSPEND_INQUIRY_SCAN 0x02 -#define NG_HCI_HOLD_MODE_SUSPEND_PERIOD_INQUIRY 0x04 +#define HCI_HOLD_MODE_NO_CHANGE 0x00 +#define HCI_HOLD_MODE_SUSPEND_PAGE_SCAN 0x01 +#define HCI_HOLD_MODE_SUSPEND_INQUIRY_SCAN 0x02 +#define HCI_HOLD_MODE_SUSPEND_PERIOD_INQUIRY 0x04 /* 0x08 - 0x80 - reserved for future use */ /* Connection roles */ -#define NG_HCI_ROLE_MASTER 0x00 -#define NG_HCI_ROLE_SLAVE 0x01 +#define HCI_ROLE_MASTER 0x00 +#define HCI_ROLE_SLAVE 0x01 /* 0x02 - 0xFF - reserved for future use */ /* Key flags */ -#define NG_HCI_USE_SEMI_PERMANENT_LINK_KEYS 0x00 -#define NG_HCI_USE_TEMPORARY_LINK_KEY 0x01 +#define HCI_USE_SEMI_PERMANENT_LINK_KEYS 0x00 +#define HCI_USE_TEMPORARY_LINK_KEY 0x01 /* 0x02 - 0xFF - reserved for future use */ /* Pin types */ -#define NG_HCI_PIN_TYPE_VARIABLE 0x00 -#define NG_HCI_PIN_TYPE_FIXED 0x01 +#define HCI_PIN_TYPE_VARIABLE 0x00 +#define HCI_PIN_TYPE_FIXED 0x01 /* Link key types */ -#define NG_HCI_LINK_KEY_TYPE_COMBINATION_KEY 0x00 -#define NG_HCI_LINK_KEY_TYPE_LOCAL_UNIT_KEY 0x01 -#define NG_HCI_LINK_KEY_TYPE_REMOTE_UNIT_KEY 0x02 +#define HCI_LINK_KEY_TYPE_COMBINATION_KEY 0x00 +#define HCI_LINK_KEY_TYPE_LOCAL_UNIT_KEY 0x01 +#define HCI_LINK_KEY_TYPE_REMOTE_UNIT_KEY 0x02 /* 0x03 - 0xFF - reserved for future use */ /* Encryption modes */ -#define NG_HCI_ENCRYPTION_MODE_NONE 0x00 -#define NG_HCI_ENCRYPTION_MODE_P2P 0x01 -#define NG_HCI_ENCRYPTION_MODE_ALL 0x02 +#define HCI_ENCRYPTION_MODE_NONE 0x00 +#define HCI_ENCRYPTION_MODE_P2P 0x01 +#define HCI_ENCRYPTION_MODE_ALL 0x02 /* 0x03 - 0xFF - reserved for future use */ /* Quality of service types */ -#define NG_HCI_SERVICE_TYPE_NO_TRAFFIC 0x00 -#define NG_HCI_SERVICE_TYPE_BEST_EFFORT 0x01 -#define NG_HCI_SERVICE_TYPE_GUARANTEED 0x02 +#define HCI_SERVICE_TYPE_NO_TRAFFIC 0x00 +#define HCI_SERVICE_TYPE_BEST_EFFORT 0x01 +#define HCI_SERVICE_TYPE_GUARANTEED 0x02 /* 0x03 - 0xFF - reserved for future use */ /* Link policy settings */ -#define NG_HCI_LINK_POLICY_DISABLE_ALL_LM_MODES 0x0000 -#define NG_HCI_LINK_POLICY_ENABLE_ROLE_SWITCH 0x0001 /* Master/Slave switch */ -#define NG_HCI_LINK_POLICY_ENABLE_HOLD_MODE 0x0002 -#define NG_HCI_LINK_POLICY_ENABLE_SNIFF_MODE 0x0004 -#define NG_HCI_LINK_POLICY_ENABLE_PARK_MODE 0x0008 +#define HCI_LINK_POLICY_DISABLE_ALL_LM_MODES 0x0000 +#define HCI_LINK_POLICY_ENABLE_ROLE_SWITCH 0x0001 /* Master/Slave switch */ +#define HCI_LINK_POLICY_ENABLE_HOLD_MODE 0x0002 +#define HCI_LINK_POLICY_ENABLE_SNIFF_MODE 0x0004 +#define HCI_LINK_POLICY_ENABLE_PARK_MODE 0x0008 /* 0x0010 - 0x8000 - reserved for future use */ /* Event masks */ -#define NG_HCI_EVMSK_ALL 0x00000000ffffffff -#define NG_HCI_EVMSK_NONE 0x0000000000000000 -#define NG_HCI_EVMSK_INQUIRY_COMPL 0x0000000000000001 -#define NG_HCI_EVMSK_INQUIRY_RESULT 0x0000000000000002 -#define NG_HCI_EVMSK_CON_COMPL 0x0000000000000004 -#define NG_HCI_EVMSK_CON_REQ 0x0000000000000008 -#define NG_HCI_EVMSK_DISCON_COMPL 0x0000000000000010 -#define NG_HCI_EVMSK_AUTH_COMPL 0x0000000000000020 -#define NG_HCI_EVMSK_REMOTE_NAME_REQ_COMPL 0x0000000000000040 -#define NG_HCI_EVMSK_ENCRYPTION_CHANGE 0x0000000000000080 -#define NG_HCI_EVMSK_CHANGE_CON_LINK_KEY_COMPL 0x0000000000000100 -#define NG_HCI_EVMSK_MASTER_LINK_KEY_COMPL 0x0000000000000200 -#define NG_HCI_EVMSK_READ_REMOTE_FEATURES_COMPL 0x0000000000000400 -#define NG_HCI_EVMSK_READ_REMOTE_VER_INFO_COMPL 0x0000000000000800 -#define NG_HCI_EVMSK_QOS_SETUP_COMPL 0x0000000000001000 -#define NG_HCI_EVMSK_COMMAND_COMPL 0x0000000000002000 -#define NG_HCI_EVMSK_COMMAND_STATUS 0x0000000000004000 -#define NG_HCI_EVMSK_HARDWARE_ERROR 0x0000000000008000 -#define NG_HCI_EVMSK_FLUSH_OCCUR 0x0000000000010000 -#define NG_HCI_EVMSK_ROLE_CHANGE 0x0000000000020000 -#define NG_HCI_EVMSK_NUM_COMPL_PKTS 0x0000000000040000 -#define NG_HCI_EVMSK_MODE_CHANGE 0x0000000000080000 -#define NG_HCI_EVMSK_RETURN_LINK_KEYS 0x0000000000100000 -#define NG_HCI_EVMSK_PIN_CODE_REQ 0x0000000000200000 -#define NG_HCI_EVMSK_LINK_KEY_REQ 0x0000000000400000 -#define NG_HCI_EVMSK_LINK_KEY_NOTIFICATION 0x0000000000800000 -#define NG_HCI_EVMSK_LOOPBACK_COMMAND 0x0000000001000000 -#define NG_HCI_EVMSK_DATA_BUFFER_OVERFLOW 0x0000000002000000 -#define NG_HCI_EVMSK_MAX_SLOT_CHANGE 0x0000000004000000 -#define NG_HCI_EVMSK_READ_CLOCK_OFFSET_COMLETE 0x0000000008000000 -#define NG_HCI_EVMSK_CON_PKT_TYPE_CHANGED 0x0000000010000000 -#define NG_HCI_EVMSK_QOS_VIOLATION 0x0000000020000000 -#define NG_HCI_EVMSK_PAGE_SCAN_MODE_CHANGE 0x0000000040000000 -#define NG_HCI_EVMSK_PAGE_SCAN_REP_MODE_CHANGE 0x0000000080000000 +#define HCI_EVMSK_ALL 0x00000000ffffffff +#define HCI_EVMSK_NONE 0x0000000000000000 +#define HCI_EVMSK_INQUIRY_COMPL 0x0000000000000001 +#define HCI_EVMSK_INQUIRY_RESULT 0x0000000000000002 +#define HCI_EVMSK_CON_COMPL 0x0000000000000004 +#define HCI_EVMSK_CON_REQ 0x0000000000000008 +#define HCI_EVMSK_DISCON_COMPL 0x0000000000000010 +#define HCI_EVMSK_AUTH_COMPL 0x0000000000000020 +#define HCI_EVMSK_REMOTE_NAME_REQ_COMPL 0x0000000000000040 +#define HCI_EVMSK_ENCRYPTION_CHANGE 0x0000000000000080 +#define HCI_EVMSK_CHANGE_CON_LINK_KEY_COMPL 0x0000000000000100 +#define HCI_EVMSK_MASTER_LINK_KEY_COMPL 0x0000000000000200 +#define HCI_EVMSK_READ_REMOTE_FEATURES_COMPL 0x0000000000000400 +#define HCI_EVMSK_READ_REMOTE_VER_INFO_COMPL 0x0000000000000800 +#define HCI_EVMSK_QOS_SETUP_COMPL 0x0000000000001000 +#define HCI_EVMSK_COMMAND_COMPL 0x0000000000002000 +#define HCI_EVMSK_COMMAND_STATUS 0x0000000000004000 +#define HCI_EVMSK_HARDWARE_ERROR 0x0000000000008000 +#define HCI_EVMSK_FLUSH_OCCUR 0x0000000000010000 +#define HCI_EVMSK_ROLE_CHANGE 0x0000000000020000 +#define HCI_EVMSK_NUM_COMPL_PKTS 0x0000000000040000 +#define HCI_EVMSK_MODE_CHANGE 0x0000000000080000 +#define HCI_EVMSK_RETURN_LINK_KEYS 0x0000000000100000 +#define HCI_EVMSK_PIN_CODE_REQ 0x0000000000200000 +#define HCI_EVMSK_LINK_KEY_REQ 0x0000000000400000 +#define HCI_EVMSK_LINK_KEY_NOTIFICATION 0x0000000000800000 +#define HCI_EVMSK_LOOPBACK_COMMAND 0x0000000001000000 +#define HCI_EVMSK_DATA_BUFFER_OVERFLOW 0x0000000002000000 +#define HCI_EVMSK_MAX_SLOT_CHANGE 0x0000000004000000 +#define HCI_EVMSK_READ_CLOCK_OFFSET_COMLETE 0x0000000008000000 +#define HCI_EVMSK_CON_PKT_TYPE_CHANGED 0x0000000010000000 +#define HCI_EVMSK_QOS_VIOLATION 0x0000000020000000 +#define HCI_EVMSK_PAGE_SCAN_MODE_CHANGE 0x0000000040000000 +#define HCI_EVMSK_PAGE_SCAN_REP_MODE_CHANGE 0x0000000080000000 /* 0x0000000100000000 - 0x8000000000000000 - reserved for future use */ /* Filter types */ -#define NG_HCI_FILTER_TYPE_NONE 0x00 -#define NG_HCI_FILTER_TYPE_INQUIRY_RESULT 0x01 -#define NG_HCI_FILTER_TYPE_CON_SETUP 0x02 +#define HCI_FILTER_TYPE_NONE 0x00 +#define HCI_FILTER_TYPE_INQUIRY_RESULT 0x01 +#define HCI_FILTER_TYPE_CON_SETUP 0x02 /* 0x03 - 0xFF - reserved for future use */ -/* Filter condition types for NG_HCI_FILTER_TYPE_INQUIRY_RESULT */ -#define NG_HCI_FILTER_COND_INQUIRY_NEW_UNIT 0x00 -#define NG_HCI_FILTER_COND_INQUIRY_UNIT_CLASS 0x01 -#define NG_HCI_FILTER_COND_INQUIRY_BDADDR 0x02 +/* Filter condition types for HCI_FILTER_TYPE_INQUIRY_RESULT */ +#define HCI_FILTER_COND_INQUIRY_NEW_UNIT 0x00 +#define HCI_FILTER_COND_INQUIRY_UNIT_CLASS 0x01 +#define HCI_FILTER_COND_INQUIRY_BDADDR 0x02 /* 0x03 - 0xFF - reserved for future use */ -/* Filter condition types for NG_HCI_FILTER_TYPE_CON_SETUP */ -#define NG_HCI_FILTER_COND_CON_ANY_UNIT 0x00 -#define NG_HCI_FILTER_COND_CON_UNIT_CLASS 0x01 -#define NG_HCI_FILTER_COND_CON_BDADDR 0x02 +/* Filter condition types for HCI_FILTER_TYPE_CON_SETUP */ +#define HCI_FILTER_COND_CON_ANY_UNIT 0x00 +#define HCI_FILTER_COND_CON_UNIT_CLASS 0x01 +#define HCI_FILTER_COND_CON_BDADDR 0x02 /* 0x03 - 0xFF - reserved for future use */ /* Xmit level types */ -#define NG_HCI_XMIT_LEVEL_CURRENT 0x00 -#define NG_HCI_XMIT_LEVEL_MAXIMUM 0x01 +#define HCI_XMIT_LEVEL_CURRENT 0x00 +#define HCI_XMIT_LEVEL_MAXIMUM 0x01 /* 0x02 - 0xFF - reserved for future use */ -/* Host to Host Controller flow control */ -#define NG_HCI_H2HC_FLOW_CONTROL_NONE 0x00 -#define NG_HCI_H2HC_FLOW_CONTROL_ACL 0x01 -#define NG_HCI_H2HC_FLOW_CONTROL_SCO 0x02 -#define NG_HCI_H2HC_FLOW_CONTROL_BOTH 0x03 /* ACL and SCO */ +/* Host Controller to Host flow control */ +#define HCI_HC2H_FLOW_CONTROL_NONE 0x00 +#define HCI_HC2H_FLOW_CONTROL_ACL 0x01 +#define HCI_HC2H_FLOW_CONTROL_SCO 0x02 +#define HCI_HC2H_FLOW_CONTROL_BOTH 0x03 /* 0x04 - 0xFF - reserved future use */ -/* Country codes */ -#define NG_HCI_COUNTRY_CODE_NAM_EUR_JP 0x00 -#define NG_HCI_COUNTRY_CODE_FRANCE 0x01 -/* 0x02 - 0xFF - reserved future use */ - /* Loopback modes */ -#define NG_HCI_LOOPBACK_NONE 0x00 -#define NG_HCI_LOOPBACK_LOCAL 0x01 -#define NG_HCI_LOOPBACK_REMOTE 0x02 +#define HCI_LOOPBACK_NONE 0x00 +#define HCI_LOOPBACK_LOCAL 0x01 +#define HCI_LOOPBACK_REMOTE 0x02 /* 0x03 - 0xFF - reserved future use */ /************************************************************************** @@ -301,1127 +355,1247 @@ ************************************************************************** **************************************************************************/ -/* - * Macro(s) to combine OpCode and extract OGF (OpCode Group Field) +/* + * Macro(s) to combine OpCode and extract OGF (OpCode Group Field) * and OCF (OpCode Command Field) from OpCode. */ -#define NG_HCI_OPCODE(gf,cf) ((((gf) & 0x3f) << 10) | ((cf) & 0x3ff)) -#define NG_HCI_OCF(op) ((op) & 0x3ff) -#define NG_HCI_OGF(op) (((op) >> 10) & 0x3f) +#define HCI_OPCODE(gf,cf) ((((gf) & 0x3f) << 10) | ((cf) & 0x3ff)) +#define HCI_OCF(op) ((op) & 0x3ff) +#define HCI_OGF(op) (((op) >> 10) & 0x3f) -/* - * Marco(s) to extract/combine connection handle, BC (Broadcast) and +/* + * Macro(s) to extract/combine connection handle, BC (Broadcast) and * PB (Packet boundary) flags. */ -#define NG_HCI_CON_HANDLE(h) ((h) & 0x0fff) -#define NG_HCI_PB_FLAG(h) (((h) & 0x3000) >> 12) -#define NG_HCI_BC_FLAG(h) (((h) & 0xc000) >> 14) -#define NG_HCI_MK_CON_HANDLE(h, pb, bc) \ +#define HCI_CON_HANDLE(h) ((h) & 0x0fff) +#define HCI_PB_FLAG(h) (((h) & 0x3000) >> 12) +#define HCI_BC_FLAG(h) (((h) & 0xc000) >> 14) +#define HCI_MK_CON_HANDLE(h, pb, bc) \ (((h) & 0x0fff) | (((pb) & 3) << 12) | (((bc) & 3) << 14)) /* PB flag values */ /* 00 - reserved for future use */ -#define NG_HCI_PACKET_FRAGMENT 0x1 -#define NG_HCI_PACKET_START 0x2 +#define HCI_PACKET_FRAGMENT 0x1 +#define HCI_PACKET_START 0x2 /* 11 - reserved for future use */ /* BC flag values */ -#define NG_HCI_POINT2POINT 0x0 /* only Host controller to Host */ -#define NG_HCI_BROADCAST_ACTIVE 0x1 /* both directions */ -#define NG_HCI_BROADCAST_PICONET 0x2 /* both directions */ +#define HCI_POINT2POINT 0x0 /* only Host controller to Host */ +#define HCI_BROADCAST_ACTIVE 0x1 /* both directions */ +#define HCI_BROADCAST_PICONET 0x2 /* both directions */ /* 11 - reserved for future use */ /* HCI command packet header */ -#define NG_HCI_CMD_PKT 0x01 -#define NG_HCI_CMD_PKT_SIZE 0xff /* without header */ typedef struct { - u_int8_t type; /* MUST be 0x1 */ - u_int16_t opcode; /* OpCode */ - u_int8_t length; /* parameter(s) length in bytes */ -} __attribute__ ((packed)) ng_hci_cmd_pkt_t; + uint8_t type; /* MUST be 0x01 */ + uint16_t opcode; /* OpCode */ + uint8_t length; /* parameter(s) length in bytes */ +} __attribute__ ((__packed__)) hci_cmd_hdr_t; + +#define HCI_CMD_PKT 0x01 +#define HCI_CMD_PKT_SIZE (sizeof(hci_cmd_hdr_t) + 0xff) /* ACL data packet header */ -#define NG_HCI_ACL_DATA_PKT 0x02 -#define NG_HCI_ACL_PKT_SIZE 0xffff /* without header */ typedef struct { - u_int8_t type; /* MUST be 0x2 */ - u_int16_t con_handle; /* connection handle + PB + BC flags */ - u_int16_t length; /* payload length in bytes */ -} __attribute__ ((packed)) ng_hci_acldata_pkt_t; + uint8_t type; /* MUST be 0x02 */ + uint16_t con_handle; /* connection handle + PB + BC flags */ + uint16_t length; /* payload length in bytes */ +} __attribute__ ((__packed__)) hci_acldata_hdr_t; + +#define HCI_ACL_DATA_PKT 0x02 +#define HCI_ACL_PKT_SIZE (sizeof(hci_acldata_hdr_t) + 0xffff) /* SCO data packet header */ -#define NG_HCI_SCO_DATA_PKT 0x03 -#define NG_HCI_SCO_PKT_SIZE 0xff /* without header */ typedef struct { - u_int8_t type; /* MUST be 0x3 */ - u_int16_t con_handle; /* connection handle + reserved bits */ - u_int8_t length; /* payload length in bytes */ -} __attribute__ ((packed)) ng_hci_scodata_pkt_t; + uint8_t type; /* MUST be 0x03 */ + uint16_t con_handle; /* connection handle + reserved bits */ + uint8_t length; /* payload length in bytes */ +} __attribute__ ((__packed__)) hci_scodata_hdr_t; -/* HCI event packet header */ -#define NG_HCI_EVENT_PKT 0x04 -#define NG_HCI_EVENT_PKT_SIZE 0xff /* without header */ -typedef struct { - u_int8_t type; /* MUST be 0x4 */ - u_int8_t event; /* event */ - u_int8_t length; /* parameter(s) length in bytes */ -} __attribute__ ((packed)) ng_hci_event_pkt_t; +#define HCI_SCO_DATA_PKT 0x03 +#define HCI_SCO_PKT_SIZE (sizeof(hci_scodata_hdr_t) + 0xff) -/* Bluetooth unit address */ +/* HCI event packet header */ typedef struct { - u_int8_t b[NG_HCI_BDADDR_SIZE]; -} __attribute__ ((packed)) bdaddr_t; -typedef bdaddr_t * bdaddr_p; + uint8_t type; /* MUST be 0x04 */ + uint8_t event; /* event */ + uint8_t length; /* parameter(s) length in bytes */ +} __attribute__ ((__packed__)) hci_event_hdr_t; -/* Any BD_ADDR. Note: This is actually 7 bytes (count '\0' terminator) */ -#define NG_HCI_BDADDR_ANY ((bdaddr_p) "\000\000\000\000\000\000") +#define HCI_EVENT_PKT 0x04 +#define HCI_EVENT_PKT_SIZE (sizeof(hci_event_hdr_t) + 0xff) /* HCI status return parameter */ typedef struct { - u_int8_t status; /* 0x00 - success */ -} __attribute__ ((packed)) ng_hci_status_rp; + uint8_t status; /* 0x00 - success */ +} __attribute__ ((__packed__)) hci_status_rp; /************************************************************************** ************************************************************************** - ** Upper layer protocol interface. LP_xxx event parameters + ** OGF 0x01 Link control commands and return parameters ************************************************************************** **************************************************************************/ -/* Connection Request Event */ -#define NGM_HCI_LP_CON_REQ 1 /* Upper -> HCI */ -typedef struct { - u_int16_t link_type; /* type of connection */ - bdaddr_t bdaddr; /* remote unit address */ -} ng_hci_lp_con_req_ep; - -/* - * XXX XXX XXX - * - * NOTE: This request is not defined by Bluetooth specification, - * but i find it useful :) - */ -#define NGM_HCI_LP_DISCON_REQ 2 /* Upper -> HCI */ -typedef struct { - u_int16_t con_handle; /* connection handle */ - u_int16_t reason; /* reason to disconnect (only low byte) */ -} ng_hci_lp_discon_req_ep; - -/* Connection Confirmation Event */ -#define NGM_HCI_LP_CON_CFM 3 /* HCI -> Upper */ -typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t link_type; /* link type */ - u_int16_t con_handle; /* con_handle */ - bdaddr_t bdaddr; /* remote unit address */ -} ng_hci_lp_con_cfm_ep; - -/* Connection Indication Event */ -#define NGM_HCI_LP_CON_IND 4 /* HCI -> Upper */ -typedef struct { - u_int8_t link_type; /* link type */ - u_int8_t uclass[NG_HCI_CLASS_SIZE]; /* unit class */ - bdaddr_t bdaddr; /* remote unit address */ -} ng_hci_lp_con_ind_ep; +#define HCI_OGF_LINK_CONTROL 0x01 -/* Connection Response Event */ -#define NGM_HCI_LP_CON_RSP 5 /* Upper -> HCI */ +#define HCI_OCF_INQUIRY 0x0001 +#define HCI_CMD_INQUIRY 0x0401 typedef struct { - u_int8_t status; /* 0x00 - accept connection */ - u_int8_t link_type; /* link type */ - bdaddr_t bdaddr; /* remote unit address */ -} ng_hci_lp_con_rsp_ep; - -/* Disconnection Indication Event */ -#define NGM_HCI_LP_DISCON_IND 6 /* HCI -> Upper */ -typedef struct { - u_int8_t reason; /* reason to disconnect (only low byte) */ - u_int8_t link_type; /* link type */ - u_int16_t con_handle; /* connection handle */ -} ng_hci_lp_discon_ind_ep; - -/* QoS Setup Request Event */ -#define NGM_HCI_LP_QOS_REQ 7 /* Upper -> HCI */ -typedef struct { - u_int16_t con_handle; /* connection handle */ - u_int8_t flags; /* reserved */ - u_int8_t service_type; /* service type */ - u_int32_t token_rate; /* bytes/sec */ - u_int32_t peak_bandwidth; /* bytes/sec */ - u_int32_t latency; /* msec */ - u_int32_t delay_variation; /* msec */ -} ng_hci_lp_qos_req_ep; - -/* QoS Conformition Event */ -#define NGM_HCI_LP_QOS_CFM 8 /* HCI -> Upper */ -typedef struct { - u_int16_t status; /* 0x00 - success (only low byte) */ - u_int16_t con_handle; /* connection handle */ -} ng_hci_lp_qos_cfm_ep; - -/* QoS Violation Indication Event */ -#define NGM_HCI_LP_QOS_IND 9 /* HCI -> Upper */ -typedef struct { - u_int16_t con_handle; /* connection handle */ -} ng_hci_lp_qos_ind_ep; - -/************************************************************************** - ************************************************************************** - ** HCI node command/event parameters - ************************************************************************** - **************************************************************************/ - -/* Debug levels */ -#define NG_HCI_ALERT_LEVEL 1 -#define NG_HCI_ERR_LEVEL 2 -#define NG_HCI_WARN_LEVEL 3 -#define NG_HCI_INFO_LEVEL 4 - -/* Unit states */ -#define NG_HCI_UNIT_CONNECTED (1 << 0) -#define NG_HCI_UNIT_INITED (1 << 1) -#define NG_HCI_UNIT_READY (NG_HCI_UNIT_CONNECTED|NG_HCI_UNIT_INITED) -#define NG_HCI_UNIT_COMMAND_PENDING (1 << 2) - -/* Connection state */ -#define NG_HCI_CON_CLOSED 0 /* connection closed */ -#define NG_HCI_CON_W4_LP_CON_RSP 1 /* wait for LP_ConnectRsp */ -#define NG_HCI_CON_W4_CONN_COMPLETE 2 /* wait for Connection_Complete evt */ -#define NG_HCI_CON_OPEN 3 /* connection open */ - -/* Get HCI node (unit) state (see states above) */ -#define NGM_HCI_NODE_GET_STATE 100 /* HCI -> User */ -typedef u_int16_t ng_hci_node_state_ep; - -/* Turn on "inited" bit */ -#define NGM_HCI_NODE_INIT 101 /* User -> HCI */ -/* No parameters */ - -/* Get/Set node debug level (see debug levels above) */ -#define NGM_HCI_NODE_GET_DEBUG 102 /* HCI -> User */ -#define NGM_HCI_NODE_SET_DEBUG 103 /* User -> HCI */ -typedef u_int16_t ng_hci_node_debug_ep; - -/* Get node buffer info */ -#define NGM_HCI_NODE_GET_BUFFER 104 /* HCI -> User */ -typedef struct { - u_int8_t cmd_free; /* number of free command packets */ - u_int8_t sco_size; /* max. size of SCO packet */ - u_int16_t sco_pkts; /* number of SCO packets */ - u_int16_t sco_free; /* number of free SCO packets */ - u_int16_t acl_size; /* max. size of ACL packet */ - u_int16_t acl_pkts; /* number of ACL packets */ - u_int16_t acl_free; /* number of free ACL packets */ -} ng_hci_node_buffer_ep; - -/* Get BDADDR */ -#define NGM_HCI_NODE_GET_BDADDR 105 /* HCI -> User */ -/* bdaddr_t -- BDADDR */ - -/* Get features */ -#define NGM_HCI_NODE_GET_FEATURES 106 /* HCI -> User */ -/* features[NG_HCI_FEATURES_SIZE] -- features */ - -#define NGM_HCI_NODE_GET_STAT 107 /* HCI -> User */ -typedef struct { - u_int32_t cmd_sent; /* number of HCI commands sent */ - u_int32_t evnt_recv; /* number of HCI events received */ - u_int32_t acl_recv; /* number of ACL packets received */ - u_int32_t acl_sent; /* number of ACL packets sent */ - u_int32_t sco_recv; /* number of SCO packets received */ - u_int32_t sco_sent; /* number of SCO packets sent */ - u_int32_t bytes_recv; /* total number of bytes received */ - u_int32_t bytes_sent; /* total number of bytes sent */ -} ng_hci_node_stat_ep; - -#define NGM_HCI_NODE_RESET_STAT 108 /* User -> HCI */ -/* No parameters */ - -#define NGM_HCI_NODE_FLUSH_NEIGHBOR_CACHE 109 /* User -> HCI */ - -#define NGM_HCI_NODE_GET_NEIGHBOR_CACHE 110 /* HCI -> User */ -typedef struct { - u_int32_t num_entries; /* number of entries */ -} ng_hci_node_get_neighbor_cache_ep; - -typedef struct { - u_int16_t page_scan_rep_mode; /* page rep scan mode */ - u_int16_t page_scan_mode; /* page scan mode */ - u_int16_t clock_offset; /* clock offset */ - bdaddr_t bdaddr; /* bdaddr */ - u_int8_t features[NG_HCI_FEATURES_SIZE]; /* features */ -} ng_hci_node_neighbor_cache_entry_ep; - -#define NG_HCI_MAX_NEIGHBOR_NUM \ - ((0xffff - sizeof(ng_hci_node_get_neighbor_cache_ep))/sizeof(ng_hci_node_neighbor_cache_entry_ep)) - -#define NGM_HCI_NODE_GET_CON_LIST 111 /* HCI -> User */ -typedef struct { - u_int32_t num_connections; /* number of connections */ -} ng_hci_node_con_list_ep; - -typedef struct { - u_int8_t link_type; /* ACL or SCO */ - u_int8_t encryption_mode; /* none, p2p, ... */ - u_int8_t mode; /* ACTIVE, HOLD ... */ - u_int8_t role; /* MASTER/SLAVE */ - u_int16_t state; /* connection state */ - u_int16_t reserved; /* place holder */ - u_int16_t pending; /* number of pending packets */ - u_int16_t queue_len; /* number of packets in queue */ - u_int16_t con_handle; /* connection handle */ - bdaddr_t bdaddr; /* remote bdaddr */ -} ng_hci_node_con_ep; - -#define NG_HCI_MAX_CON_NUM \ - ((0xffff - sizeof(ng_hci_node_con_list_ep))/sizeof(ng_hci_node_con_ep)) - -#define NGM_HCI_NODE_UP 112 /* HCI -> Upper */ -typedef struct { - u_int16_t pkt_size; /* max. ACL/SCO packet size (w/out header) */ - u_int16_t num_pkts; /* ACL/SCO packet queue size */ - u_int16_t reserved; /* place holder */ - bdaddr_t bdaddr; /* bdaddr */ -} ng_hci_node_up_ep; - -#define NGM_HCI_SYNC_CON_QUEUE 113 /* HCI -> Upper */ -typedef struct { - u_int16_t con_handle; /* connection handle */ - u_int16_t completed; /* number of completed packets */ -} ng_hci_sync_con_queue_ep; - -#define NGM_HCI_NODE_GET_LINK_POLICY_SETTINGS_MASK 114 /* HCI -> User */ -#define NGM_HCI_NODE_SET_LINK_POLICY_SETTINGS_MASK 115 /* User -> HCI */ -typedef u_int16_t ng_hci_node_link_policy_mask_ep; - -#define NGM_HCI_NODE_GET_PACKET_MASK 116 /* HCI -> User */ -#define NGM_HCI_NODE_SET_PACKET_MASK 117 /* User -> HCI */ -typedef u_int16_t ng_hci_node_packet_mask_ep; - -#define NGM_HCI_NODE_GET_ROLE_SWITCH 118 /* HCI -> User */ -#define NGM_HCI_NODE_SET_ROLE_SWITCH 119 /* User -> HCI */ -typedef u_int16_t ng_hci_node_role_switch_ep; - -/************************************************************************** - ************************************************************************** - ** Link control commands and return parameters - ************************************************************************** - **************************************************************************/ - -#define NG_HCI_OGF_LINK_CONTROL 0x01 /* OpCode Group Field */ - -#define NG_HCI_OCF_INQUIRY 0x0001 -typedef struct { - u_int8_t lap[NG_HCI_LAP_SIZE]; /* LAP */ - u_int8_t inquiry_length; /* (N x 1.28) sec */ - u_int8_t num_responses; /* Max. # of responses before halted */ -} __attribute__ ((packed)) ng_hci_inquiry_cp; + uint8_t lap[HCI_LAP_SIZE]; /* LAP */ + uint8_t inquiry_length; /* (N x 1.28) sec */ + uint8_t num_responses; /* Max. # of responses */ +} __attribute__ ((__packed__)) hci_inquiry_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_INQUIRY_CANCEL 0x0002 +#define HCI_OCF_INQUIRY_CANCEL 0x0002 +#define HCI_CMD_INQUIRY_CANCEL 0x0402 /* No command parameter(s) */ -typedef ng_hci_status_rp ng_hci_inquiry_cancel_rp; +typedef hci_status_rp hci_inquiry_cancel_rp; -#define NG_HCI_OCF_PERIODIC_INQUIRY 0x0003 +#define HCI_OCF_PERIODIC_INQUIRY 0x0003 +#define HCI_CMD_PERIODIC_INQUIRY 0x0403 typedef struct { - u_int16_t max_period_length; /* Max. and min. amount of time */ - u_int16_t min_period_length; /* between consecutive inquiries */ - u_int8_t lap[NG_HCI_LAP_SIZE]; /* LAP */ - u_int8_t inquiry_length; /* (inquiry_length * 1.28) sec */ - u_int8_t num_responses; /* Max. # of responses */ -} __attribute__ ((packed)) ng_hci_periodic_inquiry_cp; + uint16_t max_period_length; /* Max. and min. amount of time */ + uint16_t min_period_length; /* between consecutive inquiries */ + uint8_t lap[HCI_LAP_SIZE]; /* LAP */ + uint8_t inquiry_length; /* (inquiry_length * 1.28) sec */ + uint8_t num_responses; /* Max. # of responses */ +} __attribute__ ((__packed__)) hci_periodic_inquiry_cp; + +typedef hci_status_rp hci_periodic_inquiry_rp; -typedef ng_hci_status_rp ng_hci_periodic_inquiry_rp; - -#define NG_HCI_OCF_EXIT_PERIODIC_INQUIRY 0x0004 +#define HCI_OCF_EXIT_PERIODIC_INQUIRY 0x0004 +#define HCI_CMD_EXIT_PERIODIC_INQUIRY 0x0404 /* No command parameter(s) */ -typedef ng_hci_status_rp ng_hci_exit_periodic_inquiry_rp; +typedef hci_status_rp hci_exit_periodic_inquiry_rp; -#define NG_HCI_OCF_CREATE_CON 0x0005 +#define HCI_OCF_CREATE_CON 0x0005 +#define HCI_CMD_CREATE_CON 0x0405 typedef struct { bdaddr_t bdaddr; /* destination address */ - u_int16_t pkt_type; /* packet type */ - u_int8_t page_scan_rep_mode; /* page scan repetition mode */ - u_int8_t page_scan_mode; /* page scan mode */ - u_int16_t clock_offset; /* clock offset */ - u_int8_t accept_role_switch; /* accept role switch? 0x00 - no */ -} __attribute__ ((packed)) ng_hci_create_con_cp; + 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 */ + uint8_t accept_role_switch; /* accept role switch? 0x00 == No */ +} __attribute__ ((__packed__)) hci_create_con_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_DISCON 0x0006 +#define HCI_OCF_DISCONNECT 0x0006 +#define HCI_CMD_DISCONNECT 0x0406 typedef struct { - u_int16_t con_handle; /* connection handle */ - u_int8_t reason; /* reason to disconnect */ -} __attribute__ ((packed)) ng_hci_discon_cp; + uint16_t con_handle; /* connection handle */ + uint8_t reason; /* reason to disconnect */ +} __attribute__ ((__packed__)) hci_discon_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_ADD_SCO_CON 0x0007 +/* Add SCO Connection is deprecated */ +#define HCI_OCF_ADD_SCO_CON 0x0007 +#define HCI_CMD_ADD_SCO_CON 0x0407 typedef struct { - u_int16_t con_handle; /* connection handle */ - u_int16_t pkt_type; /* packet type */ -} __attribute__ ((packed)) ng_hci_add_sco_con_cp; + uint16_t con_handle; /* connection handle */ + uint16_t pkt_type; /* packet type */ +} __attribute__ ((__packed__)) hci_add_sco_con_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_ACCEPT_CON 0x0009 +#define HCI_OCF_CREATE_CON_CANCEL 0x0008 +#define HCI_CMD_CREATE_CON_CANCEL 0x0408 +typedef struct { + bdaddr_t bdaddr; /* destination address */ +} __attribute__ ((__packed__)) hci_create_con_cancel_cp; + +typedef struct { + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* destination address */ +} __attribute__ ((__packed__)) hci_create_con_cancel_rp; + +#define HCI_OCF_ACCEPT_CON 0x0009 +#define HCI_CMD_ACCEPT_CON 0x0409 typedef struct { bdaddr_t bdaddr; /* address of unit to be connected */ - u_int8_t role; /* connection role */ -} __attribute__ ((packed)) ng_hci_accept_con_cp; + uint8_t role; /* connection role */ +} __attribute__ ((__packed__)) hci_accept_con_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_REJECT_CON 0x000a +#define HCI_OCF_REJECT_CON 0x000a +#define HCI_CMD_REJECT_CON 0x040A typedef struct { bdaddr_t bdaddr; /* remote address */ - u_int8_t reason; /* reason to reject */ -} __attribute__ ((packed)) ng_hci_reject_con_cp; + uint8_t reason; /* reason to reject */ +} __attribute__ ((__packed__)) hci_reject_con_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_LINK_KEY_REP 0x000b +#define HCI_OCF_LINK_KEY_REP 0x000b +#define HCI_CMD_LINK_KEY_REP 0x040B typedef struct { - bdaddr_t bdaddr; /* remote address */ - u_int8_t key[NG_HCI_KEY_SIZE]; /* key */ -} __attribute__ ((packed)) ng_hci_link_key_rep_cp; + bdaddr_t bdaddr; /* remote address */ + uint8_t key[HCI_KEY_SIZE]; /* key */ +} __attribute__ ((__packed__)) hci_link_key_rep_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ bdaddr_t bdaddr; /* unit address */ -} __attribute__ ((packed)) ng_hci_link_key_rep_rp; +} __attribute__ ((__packed__)) hci_link_key_rep_rp; -#define NG_HCI_OCF_LINK_KEY_NEG_REP 0x000c +#define HCI_OCF_LINK_KEY_NEG_REP 0x000c +#define HCI_CMD_LINK_KEY_NEG_REP 0x040C typedef struct { bdaddr_t bdaddr; /* remote address */ -} __attribute__ ((packed)) ng_hci_link_key_neg_rep_cp; +} __attribute__ ((__packed__)) hci_link_key_neg_rep_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ bdaddr_t bdaddr; /* unit address */ -} __attribute__ ((packed)) ng_hci_link_key_neg_rep_rp; +} __attribute__ ((__packed__)) hci_link_key_neg_rep_rp; -#define NG_HCI_OCF_PIN_CODE_REP 0x000d +#define HCI_OCF_PIN_CODE_REP 0x000d +#define HCI_CMD_PIN_CODE_REP 0x040D typedef struct { bdaddr_t bdaddr; /* remote address */ - u_int8_t pin_size; /* pin code length (in bytes) */ - u_int8_t pin[NG_HCI_PIN_SIZE]; /* pin code */ -} __attribute__ ((packed)) ng_hci_pin_code_rep_cp; + uint8_t pin_size; /* pin code length (in bytes) */ + uint8_t pin[HCI_PIN_SIZE]; /* pin code */ +} __attribute__ ((__packed__)) hci_pin_code_rep_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ bdaddr_t bdaddr; /* unit address */ -} __attribute__ ((packed)) ng_hci_pin_code_rep_rp; +} __attribute__ ((__packed__)) hci_pin_code_rep_rp; -#define NG_HCI_OCF_PIN_CODE_NEG_REP 0x000e +#define HCI_OCF_PIN_CODE_NEG_REP 0x000e +#define HCI_CMD_PIN_CODE_NEG_REP 0x040E typedef struct { - bdaddr_t bdaddr; /* remote address */ -} __attribute__ ((packed)) ng_hci_pin_code_neg_rep_cp; + bdaddr_t bdaddr; /* remote address */ +} __attribute__ ((__packed__)) hci_pin_code_neg_rep_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ bdaddr_t bdaddr; /* unit address */ -} __attribute__ ((packed)) ng_hci_pin_code_neg_rep_rp; +} __attribute__ ((__packed__)) hci_pin_code_neg_rep_rp; -#define NG_HCI_OCF_CHANGE_CON_PKT_TYPE 0x000f +#define HCI_OCF_CHANGE_CON_PACKET_TYPE 0x000f +#define HCI_CMD_CHANGE_CON_PACKET_TYPE 0x040F typedef struct { - u_int16_t con_handle; /* connection handle */ - u_int16_t pkt_type; /* packet type */ -} __attribute__ ((packed)) ng_hci_change_con_pkt_type_cp; + uint16_t con_handle; /* connection handle */ + uint16_t pkt_type; /* packet type */ +} __attribute__ ((__packed__)) hci_change_con_pkt_type_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_AUTH_REQ 0x0011 +#define HCI_OCF_AUTH_REQ 0x0011 +#define HCI_CMD_AUTH_REQ 0x0411 typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_auth_req_cp; + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_auth_req_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_SET_CON_ENCRYPTION 0x0013 +#define HCI_OCF_SET_CON_ENCRYPTION 0x0013 +#define HCI_CMD_SET_CON_ENCRYPTION 0x0413 typedef struct { - u_int16_t con_handle; /* connection handle */ - u_int8_t encryption_enable; /* 0x00 - disable, 0x01 - enable */ -} __attribute__ ((packed)) ng_hci_set_con_encryption_cp; + 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) */ -#define NG_HCI_OCF_CHANGE_CON_LINK_KEY 0x0015 +#define HCI_OCF_CHANGE_CON_LINK_KEY 0x0015 +#define HCI_CMD_CHANGE_CON_LINK_KEY 0x0415 typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_change_con_link_key_cp; + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_change_con_link_key_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_MASTER_LINK_KEY 0x0017 +#define HCI_OCF_MASTER_LINK_KEY 0x0017 +#define HCI_CMD_MASTER_LINK_KEY 0x0417 typedef struct { - u_int8_t key_flag; /* key flag */ -} __attribute__ ((packed)) ng_hci_master_link_key_cp; + uint8_t key_flag; /* key flag */ +} __attribute__ ((__packed__)) hci_master_link_key_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_REMOTE_NAME_REQ 0x0019 +#define HCI_OCF_REMOTE_NAME_REQ 0x0019 +#define HCI_CMD_REMOTE_NAME_REQ 0x0419 typedef struct { bdaddr_t bdaddr; /* remote address */ - u_int8_t page_scan_rep_mode; /* page scan repetition mode */ - u_int8_t page_scan_mode; /* page scan mode */ - u_int16_t clock_offset; /* clock offset */ -} __attribute__ ((packed)) ng_hci_remote_name_req_cp; + uint8_t page_scan_rep_mode; /* page scan repetition mode */ + uint8_t page_scan_mode; /* page scan mode */ + uint16_t clock_offset; /* clock offset */ +} __attribute__ ((__packed__)) hci_remote_name_req_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_READ_REMOTE_FEATURES 0x001b +#define HCI_OCF_REMOTE_NAME_REQ_CANCEL 0x001a +#define HCI_CMD_REMOTE_NAME_REQ_CANCEL 0x041A typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_read_remote_features_cp; + 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 */ +} __attribute__ ((__packed__)) hci_remote_name_req_cancel_rp; + +#define HCI_OCF_READ_REMOTE_FEATURES 0x001b +#define HCI_CMD_READ_REMOTE_FEATURES 0x041B +typedef struct { + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_read_remote_features_cp; +/* No return parameter(s) */ + +#define HCI_OCF_READ_REMOTE_EXTENDED_FEATURES 0x001c +#define HCI_CMD_READ_REMOTE_EXTENDED_FEATURES 0x041C +typedef struct { + uint16_t con_handle; /* connection handle */ + uint8_t page; /* page number */ +} __attribute__ ((__packed__)) hci_read_remote_extended_features_cp; +/* No return parameter(s) */ + +#define HCI_OCF_READ_REMOTE_VER_INFO 0x001d +#define HCI_CMD_READ_REMOTE_VER_INFO 0x041D +typedef struct { + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_read_remote_ver_info_cp; +/* No return parameter(s) */ + +#define HCI_OCF_READ_CLOCK_OFFSET 0x001f +#define HCI_CMD_READ_CLOCK_OFFSET 0x041F +typedef struct { + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_read_clock_offset_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_READ_REMOTE_VER_INFO 0x001d +#define HCI_OCF_READ_LMP_HANDLE 0x0020 +#define HCI_CMD_READ_LMP_HANDLE 0x0420 +typedef struct { + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_read_lmp_handle_cp; + typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_read_remote_ver_info_cp; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t lmp_handle; /* LMP handle */ + uint32_t reserved; /* reserved */ +} __attribute__ ((__packed__)) hci_read_lmp_handle_rp; + +#define HCI_OCF_SETUP_SCO_CON 0x0028 +#define HCI_CMD_SETUP_SCO_CON 0x0428 +typedef struct { + uint16_t con_handle; /* connection handle */ + uint32_t tx_bandwidth; /* transmit bandwidth */ + uint32_t rx_bandwidth; /* receive bandwidth */ + uint16_t latency; /* maximum latency */ + uint16_t voice; /* voice setting */ + uint8_t rt_effort; /* retransmission effort */ + uint16_t pkt_type; /* packet types */ +} __attribute__ ((__packed__)) hci_setup_sco_con_cp; +/* No return parameter(s) */ + +#define HCI_OCF_ACCEPT_SCO_CON_REQ 0x0029 +#define HCI_CMD_ACCEPT_SCO_CON_REQ 0x0429 +typedef struct { + bdaddr_t bdaddr; /* remote address */ + uint32_t tx_bandwidth; /* transmit bandwidth */ + uint32_t rx_bandwidth; /* receive bandwidth */ + uint16_t latency; /* maximum latency */ + uint16_t content; /* voice setting */ + uint8_t rt_effort; /* retransmission effort */ + uint16_t pkt_type; /* packet types */ +} __attribute__ ((__packed__)) hci_accept_sco_con_req_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_READ_CLOCK_OFFSET 0x001f +#define HCI_OCF_REJECT_SCO_CON_REQ 0x002a +#define HCI_CMD_REJECT_SCO_CON_REQ 0x042a typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_read_clock_offset_cp; + bdaddr_t bdaddr; /* remote address */ + uint8_t reason; /* reject error code */ +} __attribute__ ((__packed__)) hci_reject_sco_con_req_cp; /* No return parameter(s) */ /************************************************************************** ************************************************************************** - ** Link policy commands and return parameters + ** OGF 0x02 Link policy commands and return parameters ************************************************************************** **************************************************************************/ -#define NG_HCI_OGF_LINK_POLICY 0x02 /* OpCode Group Field */ +#define HCI_OGF_LINK_POLICY 0x02 -#define NG_HCI_OCF_HOLD_MODE 0x0001 +#define HCI_OCF_HOLD_MODE 0x0001 +#define HCI_CMD_HOLD_MODE 0x0801 typedef struct { - u_int16_t con_handle; /* connection handle */ - u_int16_t max_interval; /* (max_interval * 0.625) msec */ - u_int16_t min_interval; /* (max_interval * 0.625) msec */ -} __attribute__ ((packed)) ng_hci_hold_mode_cp; + uint16_t con_handle; /* connection handle */ + uint16_t max_interval; /* (max_interval * 0.625) msec */ + uint16_t min_interval; /* (max_interval * 0.625) msec */ +} __attribute__ ((__packed__)) hci_hold_mode_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_SNIFF_MODE 0x0003 +#define HCI_OCF_SNIFF_MODE 0x0003 +#define HCI_CMD_SNIFF_MODE 0x0803 typedef struct { - u_int16_t con_handle; /* connection handle */ - u_int16_t max_interval; /* (max_interval * 0.625) msec */ - u_int16_t min_interval; /* (max_interval * 0.625) msec */ - u_int16_t attempt; /* (2 * attempt - 1) * 0.625 msec */ - u_int16_t timeout; /* (2 * attempt - 1) * 0.625 msec */ -} __attribute__ ((packed)) ng_hci_sniff_mode_cp; + uint16_t con_handle; /* connection handle */ + uint16_t max_interval; /* (max_interval * 0.625) msec */ + uint16_t min_interval; /* (max_interval * 0.625) msec */ + uint16_t attempt; /* (2 * attempt - 1) * 0.625 msec */ + uint16_t timeout; /* (2 * attempt - 1) * 0.625 msec */ +} __attribute__ ((__packed__)) hci_sniff_mode_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_EXIT_SNIFF_MODE 0x0004 +#define HCI_OCF_EXIT_SNIFF_MODE 0x0004 +#define HCI_CMD_EXIT_SNIFF_MODE 0x0804 typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_exit_sniff_mode_cp; + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_exit_sniff_mode_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_PARK_MODE 0x0005 +#define HCI_OCF_PARK_MODE 0x0005 +#define HCI_CMD_PARK_MODE 0x0805 typedef struct { - u_int16_t con_handle; /* connection handle */ - u_int16_t max_interval; /* (max_interval * 0.625) msec */ - u_int16_t min_interval; /* (max_interval * 0.625) msec */ -} __attribute__ ((packed)) ng_hci_park_mode_cp; + uint16_t con_handle; /* connection handle */ + uint16_t max_interval; /* (max_interval * 0.625) msec */ + uint16_t min_interval; /* (max_interval * 0.625) msec */ +} __attribute__ ((__packed__)) hci_park_mode_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_EXIT_PARK_MODE 0x0006 +#define HCI_OCF_EXIT_PARK_MODE 0x0006 +#define HCI_CMD_EXIT_PARK_MODE 0x0806 typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_exit_park_mode_cp; + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_exit_park_mode_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_QOS_SETUP 0x0007 -typedef struct { - u_int16_t con_handle; /* connection handle */ - u_int8_t flags; /* reserved for future use */ - u_int8_t service_type; /* service type */ - u_int32_t token_rate; /* bytes per second */ - u_int32_t peak_bandwidth; /* bytes per second */ - u_int32_t latency; /* microseconds */ - u_int32_t delay_variation; /* microseconds */ -} __attribute__ ((packed)) ng_hci_qos_setup_cp; +#define HCI_OCF_QOS_SETUP 0x0007 +#define HCI_CMD_QOS_SETUP 0x0807 +typedef struct { + uint16_t con_handle; /* connection handle */ + 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 delay_variation; /* microseconds */ +} __attribute__ ((__packed__)) hci_qos_setup_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_ROLE_DISCOVERY 0x0009 +#define HCI_OCF_ROLE_DISCOVERY 0x0009 +#define HCI_CMD_ROLE_DISCOVERY 0x0809 typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_role_discovery_cp; + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_role_discovery_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ - u_int8_t role; /* role for the connection handle */ -} __attribute__ ((packed)) ng_hci_role_discovery_rp; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t role; /* role for the connection handle */ +} __attribute__ ((__packed__)) hci_role_discovery_rp; -#define NG_HCI_OCF_SWITCH_ROLE 0x000b +#define HCI_OCF_SWITCH_ROLE 0x000b +#define HCI_CMD_SWITCH_ROLE 0x080B typedef struct { bdaddr_t bdaddr; /* remote address */ - u_int8_t role; /* new local role */ -} __attribute__ ((packed)) ng_hci_switch_role_cp; + uint8_t role; /* new local role */ +} __attribute__ ((__packed__)) hci_switch_role_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_READ_LINK_POLICY_SETTINGS 0x000c +#define HCI_OCF_READ_LINK_POLICY_SETTINGS 0x000c +#define HCI_CMD_READ_LINK_POLICY_SETTINGS 0x080C +typedef struct { + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_read_link_policy_settings_cp; + +typedef struct { + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint16_t settings; /* link policy settings */ +} __attribute__ ((__packed__)) hci_read_link_policy_settings_rp; + +#define HCI_OCF_WRITE_LINK_POLICY_SETTINGS 0x000d +#define HCI_CMD_WRITE_LINK_POLICY_SETTINGS 0x080D +typedef struct { + uint16_t con_handle; /* connection handle */ + uint16_t settings; /* link policy settings */ +} __attribute__ ((__packed__)) hci_write_link_policy_settings_cp; + typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_read_link_policy_settings_cp; - + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_write_link_policy_settings_rp; + +#define HCI_OCF_READ_DEFAULT_LINK_POLICY_SETTINGS 0x000e +#define HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS 0x080E +/* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ - u_int16_t settings; /* link policy settings */ -} __attribute__ ((packed)) ng_hci_read_link_policy_settings_rp; + uint8_t status; /* 0x00 - success */ + uint16_t settings; /* link policy settings */ +} __attribute__ ((__packed__)) hci_read_default_link_policy_settings_rp; -#define NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS 0x000d +#define HCI_OCF_WRITE_DEFAULT_LINK_POLICY_SETTINGS 0x000f +#define HCI_CMD_WRITE_DEFAULT_LINK_POLICY_SETTINGS 0x080F typedef struct { - u_int16_t con_handle; /* connection handle */ - u_int16_t settings; /* link policy settings */ -} __attribute__ ((packed)) ng_hci_write_link_policy_settings_cp; + uint16_t settings; /* link policy settings */ +} __attribute__ ((__packed__)) hci_write_default_link_policy_settings_cp; + +typedef hci_status_rp hci_write_default_link_policy_settings_rp; +#define HCI_OCF_FLOW_SPECIFICATION 0x0010 +#define HCI_CMD_FLOW_SPECIFICATION 0x0810 typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_write_link_policy_settings_rp; + uint16_t con_handle; /* connection handle */ + uint8_t flags; /* reserved */ + uint8_t flow_direction; + uint8_t service_type; + uint32_t token_rate; + uint32_t token_bucket; + uint32_t peak_bandwidth; + uint32_t latency; +} __attribute__ ((__packed__)) hci_flow_specification_cp; +/* No return parameter(s) */ /************************************************************************** ************************************************************************** - ** Host controller and baseband commands and return parameters + ** OGF 0x03 Host Controller and Baseband commands and return parameters ************************************************************************** **************************************************************************/ -#define NG_HCI_OGF_HC_BASEBAND 0x03 /* OpCode Group Field */ +#define HCI_OGF_HC_BASEBAND 0x03 -#define NG_HCI_OCF_SET_EVENT_MASK 0x0001 +#define HCI_OCF_SET_EVENT_MASK 0x0001 +#define HCI_CMD_SET_EVENT_MASK 0x0C01 typedef struct { - u_int8_t event_mask[NG_HCI_EVENT_MASK_SIZE]; /* event_mask */ -} __attribute__ ((packed)) ng_hci_set_event_mask_cp; + uint8_t event_mask[HCI_EVENT_MASK_SIZE]; /* event_mask */ +} __attribute__ ((__packed__)) hci_set_event_mask_cp; -typedef ng_hci_status_rp ng_hci_set_event_mask_rp; +typedef hci_status_rp hci_set_event_mask_rp; -#define NG_HCI_OCF_RESET 0x0003 +#define HCI_OCF_RESET 0x0003 +#define HCI_CMD_RESET 0x0C03 /* No command parameter(s) */ -typedef ng_hci_status_rp ng_hci_reset_rp; +typedef hci_status_rp hci_reset_rp; -#define NG_HCI_OCF_SET_EVENT_FILTER 0x0005 +#define HCI_OCF_SET_EVENT_FILTER 0x0005 +#define HCI_CMD_SET_EVENT_FILTER 0x0C05 typedef struct { - u_int8_t filter_type; /* filter type */ - u_int8_t filter_condition_type; /* filter condition type */ - u_int8_t condition[0]; /* conditions - variable size */ -} __attribute__ ((packed)) ng_hci_set_event_filter_cp; + uint8_t filter_type; /* filter type */ + uint8_t filter_condition_type; /* filter condition type */ +/* variable size condition + uint8_t condition[]; -- conditions */ +} __attribute__ ((__packed__)) hci_set_event_filter_cp; -typedef ng_hci_status_rp ng_hci_set_event_filter_rp; +typedef hci_status_rp hci_set_event_filter_rp; -#define NG_HCI_OCF_FLUSH 0x0008 +#define HCI_OCF_FLUSH 0x0008 +#define HCI_CMD_FLUSH 0x0C08 typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_flush_cp; + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_flush_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_flush_rp; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_flush_rp; -#define NG_HCI_OCF_READ_PIN_TYPE 0x0009 +#define HCI_OCF_READ_PIN_TYPE 0x0009 +#define HCI_CMD_READ_PIN_TYPE 0x0C09 /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t pin_type; /* PIN type */ -} __attribute__ ((packed)) ng_hci_read_pin_type_rp; + uint8_t status; /* 0x00 - success */ + uint8_t pin_type; /* PIN type */ +} __attribute__ ((__packed__)) hci_read_pin_type_rp; -#define NG_HCI_OCF_WRITE_PIN_TYPE 0x000a +#define HCI_OCF_WRITE_PIN_TYPE 0x000a +#define HCI_CMD_WRITE_PIN_TYPE 0x0C0A typedef struct { - u_int8_t pin_type; /* PIN type */ -} __attribute__ ((packed)) ng_hci_write_pin_type_cp; + uint8_t pin_type; /* PIN type */ +} __attribute__ ((__packed__)) hci_write_pin_type_cp; -typedef ng_hci_status_rp ng_hci_write_pin_type_rp; +typedef hci_status_rp hci_write_pin_type_rp; -#define NG_HCI_OCF_CREATE_NEW_UNIT_KEY 0x000b +#define HCI_OCF_CREATE_NEW_UNIT_KEY 0x000b +#define HCI_CMD_CREATE_NEW_UNIT_KEY 0x0C0B /* No command parameter(s) */ -typedef ng_hci_status_rp ng_hci_create_new_unit_key_rp; +typedef hci_status_rp hci_create_new_unit_key_rp; -#define NG_HCI_OCF_READ_STORED_LINK_KEY 0x000d +#define HCI_OCF_READ_STORED_LINK_KEY 0x000d +#define HCI_CMD_READ_STORED_LINK_KEY 0x0C0D typedef struct { bdaddr_t bdaddr; /* address */ - u_int8_t read_all; /* read all keys? 0x01 - yes */ -} __attribute__ ((packed)) ng_hci_read_stored_link_key_cp; + uint8_t read_all; /* read all keys? 0x01 - yes */ +} __attribute__ ((__packed__)) hci_read_stored_link_key_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t max_num_keys; /* Max. number of keys */ - u_int16_t num_keys_read; /* Number of stored keys */ -} __attribute__ ((packed)) ng_hci_read_stored_link_key_rp; + 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; -#define NG_HCI_OCF_WRITE_STORED_LINK_KEY 0x0011 +#define HCI_OCF_WRITE_STORED_LINK_KEY 0x0011 +#define HCI_CMD_WRITE_STORED_LINK_KEY 0x0C11 typedef struct { - u_int8_t num_keys_write; /* # of keys to write */ -/* these are repeated "num_keys_write" times - bdaddr_t bdaddr; --- remote address(es) - u_int8_t key[NG_HCI_KEY_SIZE]; --- key(s) */ -} __attribute__ ((packed)) ng_hci_write_stored_link_key_cp; + uint8_t num_keys_write; /* # of keys to write */ +/* these are repeated "num_keys_write" times + bdaddr_t bdaddr; --- remote address(es) + uint8_t key[HCI_KEY_SIZE]; --- key(s) */ +} __attribute__ ((__packed__)) hci_write_stored_link_key_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t num_keys_written; /* # of keys successfully written */ -} __attribute__ ((packed)) ng_hci_write_stored_link_key_rp; + uint8_t status; /* 0x00 - success */ + uint8_t num_keys_written; /* # of keys successfully written */ +} __attribute__ ((__packed__)) hci_write_stored_link_key_rp; -#define NG_HCI_OCF_DELETE_STORED_LINK_KEY 0x0012 +#define HCI_OCF_DELETE_STORED_LINK_KEY 0x0012 +#define HCI_CMD_DELETE_STORED_LINK_KEY 0x0C12 typedef struct { bdaddr_t bdaddr; /* address */ - u_int8_t delete_all; /* delete all keys? 0x01 - yes */ -} __attribute__ ((packed)) ng_hci_delete_stored_link_key_cp; + uint8_t delete_all; /* delete all keys? 0x01 - yes */ +} __attribute__ ((__packed__)) hci_delete_stored_link_key_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t num_keys_deleted; /* Number of keys deleted */ -} __attribute__ ((packed)) ng_hci_delete_stored_link_key_rp; + uint8_t status; /* 0x00 - success */ + uint16_t num_keys_deleted; /* Number of keys deleted */ +} __attribute__ ((__packed__)) hci_delete_stored_link_key_rp; -#define NG_HCI_OCF_CHANGE_LOCAL_NAME 0x0013 +#define HCI_OCF_WRITE_LOCAL_NAME 0x0013 +#define HCI_CMD_WRITE_LOCAL_NAME 0x0C13 typedef struct { - char name[NG_HCI_UNIT_NAME_SIZE]; /* new unit name */ -} __attribute__ ((packed)) ng_hci_change_local_name_cp; + char name[HCI_UNIT_NAME_SIZE]; /* new unit name */ +} __attribute__ ((__packed__)) hci_write_local_name_cp; -typedef ng_hci_status_rp ng_hci_change_local_name_rp; +typedef hci_status_rp hci_write_local_name_rp; -#define NG_HCI_OCF_READ_LOCAL_NAME 0x0014 +#define HCI_OCF_READ_LOCAL_NAME 0x0014 +#define HCI_CMD_READ_LOCAL_NAME 0x0C14 /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - char name[NG_HCI_UNIT_NAME_SIZE]; /* unit name */ -} __attribute__ ((packed)) ng_hci_read_local_name_rp; + uint8_t status; /* 0x00 - success */ + char name[HCI_UNIT_NAME_SIZE]; /* unit name */ +} __attribute__ ((__packed__)) hci_read_local_name_rp; -#define NG_HCI_OCF_READ_CON_ACCEPT_TIMO 0x0015 +#define HCI_OCF_READ_CON_ACCEPT_TIMEOUT 0x0015 +#define HCI_CMD_READ_CON_ACCEPT_TIMEOUT 0x0C15 /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t timeout; /* (timeout * 0.625) msec */ -} __attribute__ ((packed)) ng_hci_read_con_accept_timo_rp; + uint8_t status; /* 0x00 - success */ + uint16_t timeout; /* (timeout * 0.625) msec */ +} __attribute__ ((__packed__)) hci_read_con_accept_timeout_rp; -#define NG_HCI_OCF_WRITE_CON_ACCEPT_TIMO 0x0016 +#define HCI_OCF_WRITE_CON_ACCEPT_TIMEOUT 0x0016 +#define HCI_CMD_WRITE_CON_ACCEPT_TIMEOUT 0x0C16 typedef struct { - u_int16_t timeout; /* (timeout * 0.625) msec */ -} __attribute__ ((packed)) ng_hci_write_con_accept_timo_cp; + uint16_t timeout; /* (timeout * 0.625) msec */ +} __attribute__ ((__packed__)) hci_write_con_accept_timeout_cp; -typedef ng_hci_status_rp ng_hci_write_con_accept_timo_rp; +typedef hci_status_rp hci_write_con_accept_timeout_rp; -#define NG_HCI_OCF_READ_PAGE_TIMO 0x0017 +#define HCI_OCF_READ_PAGE_TIMEOUT 0x0017 +#define HCI_CMD_READ_PAGE_TIMEOUT 0x0C17 /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t timeout; /* (timeout * 0.625) msec */ -} __attribute__ ((packed)) ng_hci_read_page_timo_rp; + uint8_t status; /* 0x00 - success */ + uint16_t timeout; /* (timeout * 0.625) msec */ +} __attribute__ ((__packed__)) hci_read_page_timeout_rp; -#define NG_HCI_OCF_WRITE_PAGE_TIMO 0x0018 +#define HCI_OCF_WRITE_PAGE_TIMEOUT 0x0018 +#define HCI_CMD_WRITE_PAGE_TIMEOUT 0x0C18 typedef struct { - u_int16_t timeout; /* (timeout * 0.625) msec */ -} __attribute__ ((packed)) ng_hci_write_page_timo_cp; + uint16_t timeout; /* (timeout * 0.625) msec */ +} __attribute__ ((__packed__)) hci_write_page_timeout_cp; -typedef ng_hci_status_rp ng_hci_write_page_timo_rp; +typedef hci_status_rp hci_write_page_timeout_rp; -#define NG_HCI_OCF_READ_SCAN_ENABLE 0x0019 +#define HCI_OCF_READ_SCAN_ENABLE 0x0019 +#define HCI_CMD_READ_SCAN_ENABLE 0x0C19 /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t scan_enable; /* Scan enable */ -} __attribute__ ((packed)) ng_hci_read_scan_enable_rp; + uint8_t status; /* 0x00 - success */ + uint8_t scan_enable; /* Scan enable */ +} __attribute__ ((__packed__)) hci_read_scan_enable_rp; -#define NG_HCI_OCF_WRITE_SCAN_ENABLE 0x001a +#define HCI_OCF_WRITE_SCAN_ENABLE 0x001a +#define HCI_CMD_WRITE_SCAN_ENABLE 0x0C1A typedef struct { - u_int8_t scan_enable; /* Scan enable */ -} __attribute__ ((packed)) ng_hci_write_scan_enable_cp; + uint8_t scan_enable; /* Scan enable */ +} __attribute__ ((__packed__)) hci_write_scan_enable_cp; -typedef ng_hci_status_rp ng_hci_write_scan_enable_rp; +typedef hci_status_rp hci_write_scan_enable_rp; -#define NG_HCI_OCF_READ_PAGE_SCAN_ACTIVITY 0x001b +#define HCI_OCF_READ_PAGE_SCAN_ACTIVITY 0x001b +#define HCI_CMD_READ_PAGE_SCAN_ACTIVITY 0x0C1B /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t page_scan_interval; /* interval * 0.625 msec */ - u_int16_t page_scan_window; /* window * 0.625 msec */ -} __attribute__ ((packed)) ng_hci_read_page_scan_activity_rp; + 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; -#define NG_HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY 0x001c +#define HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY 0x001c +#define HCI_CMD_WRITE_PAGE_SCAN_ACTIVITY 0x0C1C typedef struct { - u_int16_t page_scan_interval; /* interval * 0.625 msec */ - u_int16_t page_scan_window; /* window * 0.625 msec */ -} __attribute__ ((packed)) ng_hci_write_page_scan_activity_cp; + uint16_t page_scan_interval; /* interval * 0.625 msec */ + uint16_t page_scan_window; /* window * 0.625 msec */ +} __attribute__ ((__packed__)) hci_write_page_scan_activity_cp; -typedef ng_hci_status_rp ng_hci_write_page_scan_activity_rp; +typedef hci_status_rp hci_write_page_scan_activity_rp; -#define NG_HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY 0x001d +#define HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY 0x001d +#define HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY 0x0C1D /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t inquiry_scan_interval; /* interval * 0.625 msec */ - u_int16_t inquiry_scan_window; /* window * 0.625 msec */ -} __attribute__ ((packed)) ng_hci_read_inquiry_scan_activity_rp; + 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; -#define NG_HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY 0x001e +#define HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY 0x001e +#define HCI_CMD_WRITE_INQUIRY_SCAN_ACTIVITY 0x0C1E typedef struct { - u_int16_t inquiry_scan_interval; /* interval * 0.625 msec */ - u_int16_t inquiry_scan_window; /* window * 0.625 msec */ -} __attribute__ ((packed)) ng_hci_write_inquiry_scan_activity_cp; + uint16_t inquiry_scan_interval; /* interval * 0.625 msec */ + uint16_t inquiry_scan_window; /* window * 0.625 msec */ +} __attribute__ ((__packed__)) hci_write_inquiry_scan_activity_cp; -typedef ng_hci_status_rp ng_hci_write_inquiry_scan_activity_rp; +typedef hci_status_rp hci_write_inquiry_scan_activity_rp; -#define NG_HCI_OCF_READ_AUTH_ENABLE 0x001f +#define HCI_OCF_READ_AUTH_ENABLE 0x001f +#define HCI_CMD_READ_AUTH_ENABLE 0x0C1F /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t auth_enable; /* 0x01 - enabled */ -} __attribute__ ((packed)) ng_hci_read_auth_enable_rp; + uint8_t status; /* 0x00 - success */ + uint8_t auth_enable; /* 0x01 - enabled */ +} __attribute__ ((__packed__)) hci_read_auth_enable_rp; -#define NG_HCI_OCF_WRITE_AUTH_ENABLE 0x0020 +#define HCI_OCF_WRITE_AUTH_ENABLE 0x0020 +#define HCI_CMD_WRITE_AUTH_ENABLE 0x0C20 typedef struct { - u_int8_t auth_enable; /* 0x01 - enabled */ -} __attribute__ ((packed)) ng_hci_write_auth_enable_cp; + uint8_t auth_enable; /* 0x01 - enabled */ +} __attribute__ ((__packed__)) hci_write_auth_enable_cp; -typedef ng_hci_status_rp ng_hci_write_auth_enable_rp; +typedef hci_status_rp hci_write_auth_enable_rp; -#define NG_HCI_OCF_READ_ENCRYPTION_MODE 0x0021 +#define HCI_OCF_READ_ENCRYPTION_MODE 0x0021 +#define HCI_CMD_READ_ENCRYPTION_MODE 0x0C21 /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t encryption_mode; /* encryption mode */ -} __attribute__ ((packed)) ng_hci_read_encryption_mode_rp; + uint8_t status; /* 0x00 - success */ + uint8_t encryption_mode; /* encryption mode */ +} __attribute__ ((__packed__)) hci_read_encryption_mode_rp; -#define NG_HCI_OCF_WRITE_ENCRYPTION_MODE 0x0022 +#define HCI_OCF_WRITE_ENCRYPTION_MODE 0x0022 +#define HCI_CMD_WRITE_ENCRYPTION_MODE 0x0C22 typedef struct { - u_int8_t encryption_mode; /* encryption mode */ -} __attribute__ ((packed)) ng_hci_write_encryption_mode_cp; + uint8_t encryption_mode; /* encryption mode */ +} __attribute__ ((__packed__)) hci_write_encryption_mode_cp; -typedef ng_hci_status_rp ng_hci_write_encryption_mode_rp; +typedef hci_status_rp hci_write_encryption_mode_rp; -#define NG_HCI_OCF_READ_UNIT_CLASS 0x0023 +#define HCI_OCF_READ_UNIT_CLASS 0x0023 +#define HCI_CMD_READ_UNIT_CLASS 0x0C23 /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t uclass[NG_HCI_CLASS_SIZE]; /* unit class */ -} __attribute__ ((packed)) ng_hci_read_unit_class_rp; + uint8_t status; /* 0x00 - success */ + uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ +} __attribute__ ((__packed__)) hci_read_unit_class_rp; -#define NG_HCI_OCF_WRITE_UNIT_CLASS 0x0024 +#define HCI_OCF_WRITE_UNIT_CLASS 0x0024 +#define HCI_CMD_WRITE_UNIT_CLASS 0x0C24 typedef struct { - u_int8_t uclass[NG_HCI_CLASS_SIZE]; /* unit class */ -} __attribute__ ((packed)) ng_hci_write_unit_class_cp; + uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ +} __attribute__ ((__packed__)) hci_write_unit_class_cp; -typedef ng_hci_status_rp ng_hci_write_unit_class_rp; +typedef hci_status_rp hci_write_unit_class_rp; -#define NG_HCI_OCF_READ_VOICE_SETTINGS 0x0025 +#define HCI_OCF_READ_VOICE_SETTING 0x0025 +#define HCI_CMD_READ_VOICE_SETTING 0x0C25 /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t settings; /* voice settings */ -} __attribute__ ((packed)) ng_hci_read_voice_settings_rp; + uint8_t status; /* 0x00 - success */ + uint16_t settings; /* voice settings */ +} __attribute__ ((__packed__)) hci_read_voice_setting_rp; -#define NG_HCI_OCF_WRITE_VOICE_SETTINGS 0x0026 +#define HCI_OCF_WRITE_VOICE_SETTING 0x0026 +#define HCI_CMD_WRITE_VOICE_SETTING 0x0C26 typedef struct { - u_int16_t settings; /* voice settings */ -} __attribute__ ((packed)) ng_hci_write_voice_settings_cp; + uint16_t settings; /* voice settings */ +} __attribute__ ((__packed__)) hci_write_voice_setting_cp; -typedef ng_hci_status_rp ng_hci_write_voice_settings_rp; +typedef hci_status_rp hci_write_voice_setting_rp; -#define NG_HCI_OCF_READ_AUTO_FLUSH_TIMO 0x0027 +#define HCI_OCF_READ_AUTO_FLUSH_TIMEOUT 0x0027 +#define HCI_CMD_READ_AUTO_FLUSH_TIMEOUT 0x0C27 typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_read_auto_flush_timo_cp; + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_read_auto_flush_timeout_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ - u_int16_t timeout; /* 0x00 - no flush, timeout * 0.625 msec */ -} __attribute__ ((packed)) ng_hci_read_auto_flush_timo_rp; - -#define NG_HCI_OCF_WRITE_AUTO_FLUSH_TIMO 0x0028 + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint16_t timeout; /* 0x00 - no flush, timeout * 0.625 msec */ +} __attribute__ ((__packed__)) hci_read_auto_flush_timeout_rp; + +#define HCI_OCF_WRITE_AUTO_FLUSH_TIMEOUT 0x0028 +#define HCI_CMD_WRITE_AUTO_FLUSH_TIMEOUT 0x0C28 typedef struct { - u_int16_t con_handle; /* connection handle */ - u_int16_t timeout; /* 0x00 - no flush, timeout * 0.625 msec */ -} __attribute__ ((packed)) ng_hci_write_auto_flush_timo_cp; + uint16_t con_handle; /* connection handle */ + uint16_t timeout; /* 0x00 - no flush, timeout * 0.625 msec */ +} __attribute__ ((__packed__)) hci_write_auto_flush_timeout_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_write_auto_flush_timo_rp; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_write_auto_flush_timeout_rp; -#define NG_HCI_OCF_READ_NUM_BROADCAST_RETRANS 0x0029 +#define HCI_OCF_READ_NUM_BROADCAST_RETRANS 0x0029 +#define HCI_CMD_READ_NUM_BROADCAST_RETRANS 0x0C29 /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t counter; /* number of broadcast retransmissions */ -} __attribute__ ((packed)) ng_hci_read_num_broadcast_retrans_rp; + uint8_t status; /* 0x00 - success */ + uint8_t counter; /* number of broadcast retransmissions */ +} __attribute__ ((__packed__)) hci_read_num_broadcast_retrans_rp; -#define NG_HCI_OCF_WRITE_NUM_BROADCAST_RETRANS 0x002a +#define HCI_OCF_WRITE_NUM_BROADCAST_RETRANS 0x002a +#define HCI_CMD_WRITE_NUM_BROADCAST_RETRANS 0x0C2A typedef struct { - u_int8_t counter; /* number of broadcast retransmissions */ -} __attribute__ ((packed)) ng_hci_write_num_broadcast_retrans_cp; + uint8_t counter; /* number of broadcast retransmissions */ +} __attribute__ ((__packed__)) hci_write_num_broadcast_retrans_cp; -typedef ng_hci_status_rp ng_hci_write_num_broadcast_retrans_rp; +typedef hci_status_rp hci_write_num_broadcast_retrans_rp; -#define NG_HCI_OCF_READ_HOLD_MODE_ACTIVITY 0x002b +#define HCI_OCF_READ_HOLD_MODE_ACTIVITY 0x002b +#define HCI_CMD_READ_HOLD_MODE_ACTIVITY 0x0C2B /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t hold_mode_activity; /* Hold mode activities */ -} __attribute__ ((packed)) ng_hci_read_hold_mode_activity_rp; + uint8_t status; /* 0x00 - success */ + uint8_t hold_mode_activity; /* Hold mode activities */ +} __attribute__ ((__packed__)) hci_read_hold_mode_activity_rp; -#define NG_HCI_OCF_WRITE_HOLD_MODE_ACTIVITY 0x002c +#define HCI_OCF_WRITE_HOLD_MODE_ACTIVITY 0x002c +#define HCI_CMD_WRITE_HOLD_MODE_ACTIVITY 0x0C2C typedef struct { - u_int8_t hold_mode_activity; /* Hold mode activities */ -} __attribute__ ((packed)) ng_hci_write_hold_mode_activity_cp; + uint8_t hold_mode_activity; /* Hold mode activities */ +} __attribute__ ((__packed__)) hci_write_hold_mode_activity_cp; -typedef ng_hci_status_rp ng_hci_write_hold_mode_activity_rp; +typedef hci_status_rp hci_write_hold_mode_activity_rp; -#define NG_HCI_OCF_READ_XMIT_LEVEL 0x002d +#define HCI_OCF_READ_XMIT_LEVEL 0x002d +#define HCI_CMD_READ_XMIT_LEVEL 0x0C2D typedef struct { - u_int16_t con_handle; /* connection handle */ - u_int8_t type; /* Xmit level type */ -} __attribute__ ((packed)) ng_hci_read_xmit_level_cp; + uint16_t con_handle; /* connection handle */ + uint8_t type; /* Xmit level type */ +} __attribute__ ((__packed__)) hci_read_xmit_level_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ char level; /* -30 <= level <= 30 dBm */ -} __attribute__ ((packed)) ng_hci_read_xmit_level_rp; +} __attribute__ ((__packed__)) hci_read_xmit_level_rp; -#define NG_HCI_OCF_READ_SCO_FLOW_CONTROL 0x002e +#define HCI_OCF_READ_SCO_FLOW_CONTROL 0x002e +#define HCI_CMD_READ_SCO_FLOW_CONTROL 0x0C2E /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t flow_control; /* 0x00 - disabled */ -} __attribute__ ((packed)) ng_hci_read_sco_flow_control_rp; + uint8_t status; /* 0x00 - success */ + uint8_t flow_control; /* 0x00 - disabled */ +} __attribute__ ((__packed__)) hci_read_sco_flow_control_rp; -#define NG_HCI_OCF_WRITE_SCO_FLOW_CONTROL 0x002f +#define HCI_OCF_WRITE_SCO_FLOW_CONTROL 0x002f +#define HCI_CMD_WRITE_SCO_FLOW_CONTROL 0x0C2F typedef struct { - u_int8_t flow_control; /* 0x00 - disabled */ -} __attribute__ ((packed)) ng_hci_write_sco_flow_control_cp; + uint8_t flow_control; /* 0x00 - disabled */ +} __attribute__ ((__packed__)) hci_write_sco_flow_control_cp; -typedef ng_hci_status_rp ng_hci_write_sco_flow_control_rp; +typedef hci_status_rp hci_write_sco_flow_control_rp; -#define NG_HCI_OCF_H2HC_FLOW_CONTROL 0x0031 +#define HCI_OCF_HC2H_FLOW_CONTROL 0x0031 +#define HCI_CMD_HC2H_FLOW_CONTROL 0x0C31 typedef struct { - u_int8_t h2hc_flow; /* Host to Host controller flow control */ -} __attribute__ ((packed)) ng_hci_h2hc_flow_control_cp; + uint8_t hc2h_flow; /* Host Controller to Host flow control */ +} __attribute__ ((__packed__)) hci_hc2h_flow_control_cp; -typedef ng_hci_status_rp ng_hci_h2hc_flow_control_rp; +typedef hci_status_rp hci_h2hc_flow_control_rp; -#define NG_HCI_OCF_HOST_BUFFER_SIZE 0x0033 +#define HCI_OCF_HOST_BUFFER_SIZE 0x0033 +#define HCI_CMD_HOST_BUFFER_SIZE 0x0C33 typedef struct { - u_int16_t max_acl_size; /* Max. size of ACL packet (bytes) */ - u_int8_t max_sco_size; /* Max. size of SCO packet (bytes) */ - u_int16_t num_acl_pkt; /* Max. number of ACL packets */ - u_int16_t num_sco_pkt; /* Max. number of SCO packets */ -} __attribute__ ((packed)) ng_hci_host_buffer_size_cp; + uint16_t max_acl_size; /* Max. size of ACL packet (bytes) */ + uint8_t max_sco_size; /* Max. size of SCO packet (bytes) */ + uint16_t num_acl_pkts; /* Max. number of ACL packets */ + uint16_t num_sco_pkts; /* Max. number of SCO packets */ +} __attribute__ ((__packed__)) hci_host_buffer_size_cp; -typedef ng_hci_status_rp ng_hci_host_buffer_size_rp; +typedef hci_status_rp hci_host_buffer_size_rp; -#define NG_HCI_OCF_HOST_NUM_COMPL_PKTS 0x0035 +#define HCI_OCF_HOST_NUM_COMPL_PKTS 0x0035 +#define HCI_CMD_HOST_NUM_COMPL_PKTS 0x0C35 typedef struct { - u_int8_t num_con_handles; /* # of connection handles */ + uint8_t nu_con_handles; /* # of connection handles */ /* these are repeated "num_con_handles" times - u_int16_t con_handle; --- connection handle(s) - u_int16_t compl_pkt; --- # of completed packets */ -} __attribute__ ((packed)) ng_hci_host_num_compl_pkts_cp; + uint16_t con_handle; --- connection handle(s) + uint16_t compl_pkts; --- # of completed packets */ +} __attribute__ ((__packed__)) hci_host_num_compl_pkts_cp; /* No return parameter(s) */ -#define NG_HCI_OCF_READ_LINK_SUPERVISION_TIMO 0x0036 +#define HCI_OCF_READ_LINK_SUPERVISION_TIMEOUT 0x0036 +#define HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT 0x0C36 typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_read_link_supervision_timo_cp; + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_read_link_supervision_timeout_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ - u_int16_t timeout; /* Link supervision timeout * 0.625 msec */ -} __attribute__ ((packed)) ng_hci_read_link_supervision_timo_rp; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint16_t timeout; /* Link supervision timeout * 0.625 msec */ +} __attribute__ ((__packed__)) hci_read_link_supervision_timeout_rp; -#define NG_HCI_OCF_WRITE_LINK_SUPERVISION_TIMO 0x0037 +#define HCI_OCF_WRITE_LINK_SUPERVISION_TIMEOUT 0x0037 +#define HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT 0x0C37 typedef struct { - u_int16_t con_handle; /* connection handle */ - u_int16_t timeout; /* Link supervision timeout * 0.625 msec */ -} __attribute__ ((packed)) ng_hci_write_link_supervision_timo_cp; + uint16_t con_handle; /* connection handle */ + uint16_t timeout; /* Link supervision timeout * 0.625 msec */ +} __attribute__ ((__packed__)) hci_write_link_supervision_timeout_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_write_link_supervision_timo_rp; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_write_link_supervision_timeout_rp; -#define NG_HCI_OCF_READ_SUPPORTED_IAC_NUM 0x0038 +#define HCI_OCF_READ_NUM_SUPPORTED_IAC 0x0038 +#define HCI_CMD_READ_NUM_SUPPORTED_IAC 0x0C38 /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t num_iac; /* # of supported IAC during scan */ -} __attribute__ ((packed)) ng_hci_read_supported_iac_num_rp; + uint8_t status; /* 0x00 - success */ + uint8_t num_iac; /* # of supported IAC during scan */ +} __attribute__ ((__packed__)) hci_read_num_supported_iac_rp; -#define NG_HCI_OCF_READ_IAC_LAP 0x0039 +#define HCI_OCF_READ_IAC_LAP 0x0039 +#define HCI_CMD_READ_IAC_LAP 0x0C39 /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t num_iac; /* # of IAC */ -/* these are repeated "num_iac" times - u_int8_t laps[NG_HCI_LAP_SIZE]; --- LAPs */ -} __attribute__ ((packed)) ng_hci_read_iac_lap_rp; + uint8_t status; /* 0x00 - success */ + uint8_t num_iac; /* # of IAC */ +/* these are repeated "num_iac" times + uint8_t laps[HCI_LAP_SIZE]; --- LAPs */ +} __attribute__ ((__packed__)) hci_read_iac_lap_rp; -#define NG_HCI_OCF_WRITE_IAC_LAP 0x003a +#define HCI_OCF_WRITE_IAC_LAP 0x003a +#define HCI_CMD_WRITE_IAC_LAP 0x0C3A typedef struct { - u_int8_t num_iac; /* # of IAC */ -/* these are repeated "num_iac" times - u_int8_t laps[NG_HCI_LAP_SIZE]; --- LAPs */ -} __attribute__ ((packed)) ng_hci_write_iac_lap_cp; + uint8_t num_iac; /* # of IAC */ +/* these are repeated "num_iac" times + uint8_t laps[HCI_LAP_SIZE]; --- LAPs */ +} __attribute__ ((__packed__)) hci_write_iac_lap_cp; -typedef ng_hci_status_rp ng_hci_write_iac_lap_rp; +typedef hci_status_rp hci_write_iac_lap_rp; -#define NG_HCI_OCF_READ_PAGE_SCAN_PERIOD 0x003b +#define HCI_OCF_READ_PAGE_SCAN_PERIOD 0x003b +#define HCI_CMD_READ_PAGE_SCAN_PERIOD 0x0C3B /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t page_scan_period_mode; /* Page scan period mode */ -} __attribute__ ((packed)) ng_hci_read_page_scan_period_rp; + uint8_t status; /* 0x00 - success */ + uint8_t page_scan_period_mode; /* Page scan period mode */ +} __attribute__ ((__packed__)) hci_read_page_scan_period_rp; -#define NG_HCI_OCF_WRITE_PAGE_SCAN_PERIOD 0x003c +#define HCI_OCF_WRITE_PAGE_SCAN_PERIOD 0x003c +#define HCI_CMD_WRITE_PAGE_SCAN_PERIOD 0x0C3C typedef struct { - u_int8_t page_scan_period_mode; /* Page scan period mode */ -} __attribute__ ((packed)) ng_hci_write_page_scan_period_cp; + uint8_t page_scan_period_mode; /* Page scan period mode */ +} __attribute__ ((__packed__)) hci_write_page_scan_period_cp; -typedef ng_hci_status_rp ng_hci_write_page_scan_period_rp; +typedef hci_status_rp hci_write_page_scan_period_rp; -#define NG_HCI_OCF_READ_PAGE_SCAN 0x003d +/* Read Page Scan Mode is deprecated */ +#define HCI_OCF_READ_PAGE_SCAN 0x003d +#define HCI_CMD_READ_PAGE_SCAN 0x0C3D /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t page_scan_mode; /* Page scan mode */ -} __attribute__ ((packed)) ng_hci_read_page_scan_rp; + uint8_t status; /* 0x00 - success */ + uint8_t page_scan_mode; /* Page scan mode */ +} __attribute__ ((__packed__)) hci_read_page_scan_rp; + +/* Write Page Scan Mode is deprecated */ +#define HCI_OCF_WRITE_PAGE_SCAN 0x003e +#define HCI_CMD_WRITE_PAGE_SCAN 0x0C3E +typedef struct { + uint8_t page_scan_mode; /* Page scan mode */ +} __attribute__ ((__packed__)) hci_write_page_scan_cp; + +typedef hci_status_rp hci_write_page_scan_rp; + +#define HCI_OCF_SET_AFH_CLASSIFICATION 0x003f +#define HCI_CMD_SET_AFH_CLASSIFICATION 0x0C3F +typedef struct { + uint8_t classification[10]; +} __attribute__ ((__packed__)) hci_set_afh_classification_cp; + +typedef hci_status_rp hci_set_afh_classification_rp; + +#define HCI_OCF_READ_INQUIRY_SCAN_TYPE 0x0042 +#define HCI_CMD_READ_INQUIRY_SCAN_TYPE 0x0C42 +/* No command parameter(s) */ -#define NG_HCI_OCF_WRITE_PAGE_SCAN 0x003e typedef struct { - u_int8_t page_scan_mode; /* Page scan mode */ -} __attribute__ ((packed)) ng_hci_write_page_scan_cp; + uint8_t status; /* 0x00 - success */ + uint8_t type; /* inquiry scan type */ +} __attribute__ ((__packed__)) hci_read_inquiry_scan_type_rp; -typedef ng_hci_status_rp ng_hci_write_page_scan_rp; +#define HCI_OCF_WRITE_INQUIRY_SCAN_TYPE 0x0043 +#define HCI_CMD_WRITE_INQUIRY_SCAN_TYPE 0x0C43 +typedef struct { + uint8_t type; /* inquiry scan type */ +} __attribute__ ((__packed__)) hci_write_inquiry_scan_type_cp; + +typedef hci_status_rp hci_write_inquiry_scan_type_rp; + +#define HCI_OCF_READ_INQUIRY_MODE 0x0044 +#define HCI_CMD_READ_INQUIRY_MODE 0x0C44 +/* No command parameter(s) */ + +typedef struct { + uint8_t status; /* 0x00 - success */ + uint8_t mode; /* inquiry mode */ +} __attribute__ ((__packed__)) hci_read_inquiry_mode_rp; + +#define HCI_OCF_WRITE_INQUIRY_MODE 0x0045 +#define HCI_CMD_WRITE_INQUIRY_MODE 0x0C45 +typedef struct { + uint8_t mode; /* inquiry mode */ +} __attribute__ ((__packed__)) hci_write_inquiry_mode_cp; + +typedef hci_status_rp hci_write_inquiry_mode_rp; + +#define HCI_OCF_READ_PAGE_SCAN_TYPE 0x0046 +#define HCI_CMD_READ_PAGE_SCAN_TYPE 0x0C46 +/* No command parameter(s) */ + +typedef struct { + uint8_t status; /* 0x00 - success */ + uint8_t type; /* page scan type */ +} __attribute__ ((__packed__)) hci_read_page_scan_type_rp; + +#define HCI_OCF_WRITE_PAGE_SCAN_TYPE 0x0047 +#define HCI_CMD_WRITE_PAGE_SCAN_TYPE 0x0C47 +typedef struct { + uint8_t type; /* page scan type */ +} __attribute__ ((__packed__)) hci_write_page_scan_type_cp; + +typedef hci_status_rp hci_write_page_scan_type_rp; + +#define HCI_OCF_READ_AFH_ASSESSMENT 0x0048 +#define HCI_CMD_READ_AFH_ASSESSMENT 0x0C48 +/* No command parameter(s) */ + +typedef struct { + uint8_t status; /* 0x00 - success */ + uint8_t mode; /* assessment mode */ +} __attribute__ ((__packed__)) hci_read_afh_assessment_rp; + +#define HCI_OCF_WRITE_AFH_ASSESSMENT 0x0049 +#define HCI_CMD_WRITE_AFH_ASSESSMENT 0x0C49 +typedef struct { + uint8_t mode; /* assessment mode */ +} __attribute__ ((__packed__)) hci_write_afh_assessment_cp; + +typedef hci_status_rp hci_write_afh_assessment_rp; /************************************************************************** ************************************************************************** - ** Informational commands and return parameters - ** All commands in this category do not accept any parameters + ** OGF 0x04 Informational commands and return parameters ************************************************************************** **************************************************************************/ -#define NG_HCI_OGF_INFO 0x04 /* OpCode Group Field */ +#define HCI_OGF_INFO 0x04 + +#define HCI_OCF_READ_LOCAL_VER 0x0001 +#define HCI_CMD_READ_LOCAL_VER 0x1001 +/* No command parameter(s) */ +typedef struct { + uint8_t status; /* 0x00 - success */ + uint8_t hci_version; /* HCI version */ + uint16_t hci_revision; /* HCI revision */ + uint8_t lmp_version; /* LMP version */ + uint16_t manufacturer; /* Hardware manufacturer name */ + uint16_t lmp_subversion; /* LMP sub-version */ +} __attribute__ ((__packed__)) hci_read_local_ver_rp; + +#define HCI_OCF_READ_LOCAL_COMMANDS 0x0002 +#define HCI_CMD_READ_LOCAL_COMMANDS 0x1002 +/* No command parameter(s) */ +typedef struct { + uint8_t status; /* 0x00 - success */ + uint8_t commands[64]; /* opcode bitmask */ +} __attribute__ ((__packed__)) hci_read_local_commands_rp; -#define NG_HCI_OCF_READ_LOCAL_VER 0x0001 +#define HCI_OCF_READ_LOCAL_FEATURES 0x0003 +#define HCI_CMD_READ_LOCAL_FEATURES 0x1003 +/* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t hci_version; /* HCI version */ - u_int16_t hci_revision; /* HCI revision */ - u_int8_t lmp_version; /* LMP version */ - u_int16_t manufacturer; /* Hardware manufacturer name */ - u_int16_t lmp_subversion; /* LMP sub-version */ -} __attribute__ ((packed)) ng_hci_read_local_ver_rp; + uint8_t status; /* 0x00 - success */ + uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ +} __attribute__ ((__packed__)) hci_read_local_features_rp; -#define NG_HCI_OCF_READ_LOCAL_FEATURES 0x0003 +#define HCI_OCF_READ_LOCAL_EXTENDED_FEATURES 0x0004 +#define HCI_CMD_READ_LOCAL_EXTENDED_FEATURES 0x1004 typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t features[NG_HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ -} __attribute__ ((packed)) ng_hci_read_local_features_rp; + uint8_t page; /* page number */ +} __attribute__ ((__packed__)) hci_read_local_extended_features_cp; -#define NG_HCI_OCF_READ_BUFFER_SIZE 0x0005 typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t max_acl_size; /* Max. size of ACL packet (bytes) */ - u_int8_t max_sco_size; /* Max. size of SCO packet (bytes) */ - u_int16_t num_acl_pkt; /* Max. number of ACL packets */ - u_int16_t num_sco_pkt; /* Max. number of SCO packets */ -} __attribute__ ((packed)) ng_hci_read_buffer_size_rp; + uint8_t status; /* 0x00 - success */ + uint8_t page; /* page number */ + uint8_t max_page; /* maximum page number */ + uint8_t features[HCI_FEATURES_SIZE]; /* LMP features */ +} __attribute__ ((__packed__)) hci_read_local_extended_features_rp; -#define NG_HCI_OCF_READ_COUNTRY_CODE 0x0007 +#define HCI_OCF_READ_BUFFER_SIZE 0x0005 +#define HCI_CMD_READ_BUFFER_SIZE 0x1005 +/* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t country_code; /* 0x00 - NAM, EUR, JP; 0x01 - France */ -} __attribute__ ((packed)) ng_hci_read_country_code_rp; + uint8_t status; /* 0x00 - success */ + uint16_t max_acl_size; /* Max. size of ACL packet (bytes) */ + uint8_t max_sco_size; /* Max. size of SCO packet (bytes) */ + uint16_t num_acl_pkts; /* Max. number of ACL packets */ + uint16_t num_sco_pkts; /* Max. number of SCO packets */ +} __attribute__ ((__packed__)) hci_read_buffer_size_rp; -#define NG_HCI_OCF_READ_BDADDR 0x0009 +/* Read Country Code is deprecated */ +#define HCI_OCF_READ_COUNTRY_CODE 0x0007 +#define HCI_CMD_READ_COUNTRY_CODE 0x1007 +/* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ + uint8_t country_code; /* 0x00 - NAM, EUR, JP; 0x01 - France */ +} __attribute__ ((__packed__)) hci_read_country_code_rp; + +#define HCI_OCF_READ_BDADDR 0x0009 +#define HCI_CMD_READ_BDADDR 0x1009 +/* No command parameter(s) */ +typedef struct { + uint8_t status; /* 0x00 - success */ bdaddr_t bdaddr; /* unit address */ -} __attribute__ ((packed)) ng_hci_read_bdaddr_rp; +} __attribute__ ((__packed__)) hci_read_bdaddr_rp; /************************************************************************** ************************************************************************** - ** Status commands and return parameters + ** OGF 0x05 Status commands and return parameters ************************************************************************** **************************************************************************/ -#define NG_HCI_OGF_STATUS 0x05 /* OpCode Group Field */ +#define HCI_OGF_STATUS 0x05 -#define NG_HCI_OCF_READ_FAILED_CONTACT_CNTR 0x0001 +#define HCI_OCF_READ_FAILED_CONTACT_CNTR 0x0001 +#define HCI_CMD_READ_FAILED_CONTACT_CNTR 0x1401 typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_read_failed_contact_cntr_cp; + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_read_failed_contact_cntr_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ - u_int16_t counter; /* number of consecutive failed contacts */ -} __attribute__ ((packed)) ng_hci_read_failed_contact_cntr_rp; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint16_t counter; /* number of consecutive failed contacts */ +} __attribute__ ((__packed__)) hci_read_failed_contact_cntr_rp; -#define NG_HCI_OCF_RESET_FAILED_CONTACT_CNTR 0x0002 +#define HCI_OCF_RESET_FAILED_CONTACT_CNTR 0x0002 +#define HCI_CMD_RESET_FAILED_CONTACT_CNTR 0x1402 typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_reset_failed_contact_cntr_cp; + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_reset_failed_contact_cntr_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_reset_failed_contact_cntr_rp; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_reset_failed_contact_cntr_rp; -#define NG_HCI_OCF_GET_LINK_QUALITY 0x0003 +#define HCI_OCF_READ_LINK_QUALITY 0x0003 +#define HCI_CMD_READ_LINK_QUALITY 0x1403 typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_get_link_quality_cp; + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_read_link_quality_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ - u_int8_t quality; /* higher value means better quality */ -} __attribute__ ((packed)) ng_hci_get_link_quality_rp; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t quality; /* higher value means better quality */ +} __attribute__ ((__packed__)) hci_read_link_quality_rp; -#define NG_HCI_OCF_READ_RSSI 0x0005 +#define HCI_OCF_READ_RSSI 0x0005 +#define HCI_CMD_READ_RSSI 0x1405 typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_read_rssi_cp; + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_read_rssi_cp; typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ char rssi; /* -127 <= rssi <= 127 dB */ -} __attribute__ ((packed)) ng_hci_read_rssi_rp; +} __attribute__ ((__packed__)) hci_read_rssi_rp; + +#define HCI_OCF_READ_AFH_CHANNEL_MAP 0x0006 +#define HCI_CMD_READ_AFH_CHANNEL_MAP 0x1406 +typedef struct { + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_read_afh_channel_map_cp; + +typedef struct { + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t mode; /* AFH mode */ + uint8_t map[10]; /* AFH Channel Map */ +} __attribute__ ((__packed__)) hci_read_afh_channel_map_rp; + +#define HCI_OCF_READ_CLOCK 0x0007 +#define HCI_CMD_READ_CLOCK 0x1407 +typedef struct { + uint16_t con_handle; /* connection handle */ + uint8_t clock; /* which clock */ +} __attribute__ ((__packed__)) hci_read_clock_cp; + +typedef struct { + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint32_t clock; /* clock value */ + uint16_t accuracy; /* clock accuracy */ +} __attribute__ ((__packed__)) hci_read_clock_rp; + /************************************************************************** ************************************************************************** - ** Testing commands and return parameters + ** OGF 0x06 Testing commands and return parameters ************************************************************************** **************************************************************************/ -#define NG_HCI_OGF_TESTING 0x06 /* OpCode Group Field */ +#define HCI_OGF_TESTING 0x06 -#define NG_HCI_OCF_READ_LOOPBACK_MODE 0x0001 +#define HCI_OCF_READ_LOOPBACK_MODE 0x0001 +#define HCI_CMD_READ_LOOPBACK_MODE 0x1801 /* No command parameter(s) */ typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int8_t lbmode; /* loopback mode */ -} __attribute__ ((packed)) ng_hci_read_loopback_mode_rp; + uint8_t status; /* 0x00 - success */ + uint8_t lbmode; /* loopback mode */ +} __attribute__ ((__packed__)) hci_read_loopback_mode_rp; -#define NG_HCI_OCF_WRITE_LOOPBACK_MODE 0x0002 +#define HCI_OCF_WRITE_LOOPBACK_MODE 0x0002 +#define HCI_CMD_WRITE_LOOPBACK_MODE 0x1802 typedef struct { - u_int8_t lbmode; /* loopback mode */ -} __attribute__ ((packed)) ng_hci_write_loopback_mode_cp; + uint8_t lbmode; /* loopback mode */ +} __attribute__ ((__packed__)) hci_write_loopback_mode_cp; -typedef ng_hci_status_rp ng_hci_write_loopback_mode_rp; +typedef hci_status_rp hci_write_loopback_mode_rp; -#define NG_HCI_OCF_ENABLE_UNIT_UNDER_TEST 0x0003 +#define HCI_OCF_ENABLE_UNIT_UNDER_TEST 0x0003 +#define HCI_CMD_ENABLE_UNIT_UNDER_TEST 0x1803 /* No command parameter(s) */ -typedef ng_hci_status_rp ng_hci_enable_unit_under_test_rp; +typedef hci_status_rp hci_enable_unit_under_test_rp; /************************************************************************** ************************************************************************** - ** Special HCI OpCode group field values + ** OGF 0x3e Bluetooth Logo Testing + ** OGF 0x3f Vendor Specific ************************************************************************** **************************************************************************/ -#define NG_HCI_OGF_BT_LOGO 0x3e +#define HCI_OGF_BT_LOGO 0x3e +#define HCI_OGF_VENDOR 0x3f + +/* Ericsson specific FC */ +#define HCI_CMD_ERICSSON_WRITE_PCM_SETTINGS 0xFC07 +#define HCI_CMD_ERICSSON_SET_UART_BAUD_RATE 0xFC09 +#define HCI_CMD_ERICSSON_SET_SCO_DATA_PATH 0xFC1D + +/* Cambridge Silicon Radio specific FC */ +#define HCI_CMD_CSR_EXTN 0xFC00 -#define NG_HCI_OGF_VENDOR 0x3f /************************************************************************** ************************************************************************** @@ -1429,231 +1603,625 @@ typedef ng_hci_status_rp ng_hci_enable_unit_under_test_rp; ************************************************************************** **************************************************************************/ -#define NG_HCI_EVENT_INQUIRY_COMPL 0x01 +#define HCI_EVENT_INQUIRY_COMPL 0x01 typedef struct { - u_int8_t status; /* 0x00 - success */ -} __attribute__ ((packed)) ng_hci_inquiry_compl_ep; + uint8_t status; /* 0x00 - success */ +} __attribute__ ((__packed__)) hci_inquiry_compl_ep; -#define NG_HCI_EVENT_INQUIRY_RESULT 0x02 +#define HCI_EVENT_INQUIRY_RESULT 0x02 typedef struct { - u_int8_t num_responses; /* number of responses */ -/* ng_hci_inquiry_response[num_responses] -- see below */ -} __attribute__ ((packed)) ng_hci_inquiry_result_ep; + uint8_t num_responses; /* number of responses */ +/* hci_inquiry_response[num_responses] -- see below */ +} __attribute__ ((__packed__)) hci_inquiry_result_ep; typedef struct { bdaddr_t bdaddr; /* unit address */ - u_int8_t page_scan_rep_mode; /* page scan rep. mode */ - u_int8_t page_scan_period_mode; /* page scan period mode */ - u_int8_t page_scan_mode; /* page scan mode */ - u_int8_t uclass[NG_HCI_CLASS_SIZE]; /* unit class */ - u_int16_t clock_offset; /* clock offset */ -} __attribute__ ((packed)) ng_hci_inquiry_response; + 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 uclass[HCI_CLASS_SIZE]; /* unit class */ + uint16_t clock_offset; /* clock offset */ +} __attribute__ ((__packed__)) hci_inquiry_response; -#define NG_HCI_EVENT_CON_COMPL 0x03 +#define HCI_EVENT_CON_COMPL 0x03 typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* Connection handle */ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* Connection handle */ bdaddr_t bdaddr; /* remote unit address */ - u_int8_t link_type; /* Link type */ - u_int8_t encryption_mode; /* Encryption mode */ -} __attribute__ ((packed)) ng_hci_con_compl_ep; + uint8_t link_type; /* Link type */ + uint8_t encryption_mode; /* Encryption mode */ +} __attribute__ ((__packed__)) hci_con_compl_ep; -#define NG_HCI_EVENT_CON_REQ 0x04 +#define HCI_EVENT_CON_REQ 0x04 typedef struct { - bdaddr_t bdaddr; /* remote unit address */ - u_int8_t uclass[NG_HCI_CLASS_SIZE]; /* remote unit class */ - u_int8_t link_type; /* link type */ -} __attribute__ ((packed)) ng_hci_con_req_ep; + bdaddr_t bdaddr; /* remote unit address */ + uint8_t uclass[HCI_CLASS_SIZE]; /* remote unit class */ + uint8_t link_type; /* link type */ +} __attribute__ ((__packed__)) hci_con_req_ep; -#define NG_HCI_EVENT_DISCON_COMPL 0x05 +#define HCI_EVENT_DISCON_COMPL 0x05 typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ - u_int8_t reason; /* reason to disconnect */ -} __attribute__ ((packed)) ng_hci_discon_compl_ep; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t reason; /* reason to disconnect */ +} __attribute__ ((__packed__)) hci_discon_compl_ep; -#define NG_HCI_EVENT_AUTH_COMPL 0x06 +#define HCI_EVENT_AUTH_COMPL 0x06 typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_auth_compl_ep; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_auth_compl_ep; -#define NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL 0x7 +#define HCI_EVENT_REMOTE_NAME_REQ_COMPL 0x07 typedef struct { - u_int8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote unit address */ - char name[NG_HCI_UNIT_NAME_SIZE]; /* remote unit name */ -} __attribute__ ((packed)) ng_hci_remote_name_req_compl_ep; + 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 NG_HCI_EVENT_ENCRYPTION_CHANGE 0x08 +#define HCI_EVENT_ENCRYPTION_CHANGE 0x08 typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* Connection handle */ - u_int8_t encryption_enable; /* 0x00 - disable */ -} __attribute__ ((packed)) ng_hci_encryption_change_ep; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* Connection handle */ + uint8_t encryption_enable; /* 0x00 - disable */ +} __attribute__ ((__packed__)) hci_encryption_change_ep; -#define NG_HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL 0x09 +#define HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL 0x09 typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* Connection handle */ -} __attribute__ ((packed)) ng_hci_change_con_link_key_compl_ep; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* Connection handle */ +} __attribute__ ((__packed__)) hci_change_con_link_key_compl_ep; -#define NG_HCI_EVENT_MASTER_LINK_KEY_COMPL 0x0a +#define HCI_EVENT_MASTER_LINK_KEY_COMPL 0x0a typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* Connection handle */ - u_int8_t key_flag; /* Key flag */ -} __attribute__ ((packed)) ng_hci_master_link_key_compl_ep; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* Connection handle */ + uint8_t key_flag; /* Key flag */ +} __attribute__ ((__packed__)) hci_master_link_key_compl_ep; -#define NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL 0x0b +#define HCI_EVENT_READ_REMOTE_FEATURES_COMPL 0x0b typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* Connection handle */ - u_int8_t features[NG_HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ -} __attribute__ ((packed)) ng_hci_read_remote_features_compl_ep; + 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 NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL 0x0c +#define HCI_EVENT_READ_REMOTE_VER_INFO_COMPL 0x0c typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* Connection handle */ - u_int8_t lmp_version; /* LMP version */ - u_int16_t manufacturer; /* Hardware manufacturer name */ - u_int16_t lmp_subversion; /* LMP sub-version */ -} __attribute__ ((packed)) ng_hci_read_remote_ver_info_compl_ep; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* Connection handle */ + uint8_t lmp_version; /* LMP version */ + uint16_t manufacturer; /* Hardware manufacturer name */ + uint16_t lmp_subversion; /* LMP sub-version */ +} __attribute__ ((__packed__)) hci_read_remote_ver_info_compl_ep; -#define NG_HCI_EVENT_QOS_SETUP_COMPL 0x0d +#define HCI_EVENT_QOS_SETUP_COMPL 0x0d typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ - u_int8_t flags; /* reserved for future use */ - u_int8_t service_type; /* service type */ - u_int32_t token_rate; /* bytes per second */ - u_int32_t peak_bandwidth; /* bytes per second */ - u_int32_t latency; /* microseconds */ - u_int32_t delay_variation; /* microseconds */ -} __attribute__ ((packed)) ng_hci_qos_setup_compl_ep; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + 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 delay_variation; /* microseconds */ +} __attribute__ ((__packed__)) hci_qos_setup_compl_ep; -#define NG_HCI_EVENT_COMMAND_COMPL 0x0e +#define HCI_EVENT_COMMAND_COMPL 0x0e typedef struct { - u_int8_t num_cmd_pkts; /* # of HCI command packets */ - u_int16_t opcode; /* command OpCode */ + uint8_t num_cmd_pkts; /* # of HCI command packets */ + uint16_t opcode; /* command OpCode */ /* command return parameters (if any) */ -} __attribute__ ((packed)) ng_hci_command_compl_ep; +} __attribute__ ((__packed__)) hci_command_compl_ep; -#define NG_HCI_EVENT_COMMAND_STATUS 0x0f +#define HCI_EVENT_COMMAND_STATUS 0x0f typedef struct { - u_int8_t status; /* 0x00 - pending */ - u_int8_t num_cmd_pkts; /* # of HCI command packets */ - u_int16_t opcode; /* command OpCode */ -} __attribute__ ((packed)) ng_hci_command_status_ep; + uint8_t status; /* 0x00 - pending */ + uint8_t num_cmd_pkts; /* # of HCI command packets */ + uint16_t opcode; /* command OpCode */ +} __attribute__ ((__packed__)) hci_command_status_ep; -#define NG_HCI_EVENT_HARDWARE_ERROR 0x10 +#define HCI_EVENT_HARDWARE_ERROR 0x10 typedef struct { - u_int8_t hardware_code; /* hardware error code */ -} __attribute__ ((packed)) ng_hci_hardware_error_ep; + uint8_t hardware_code; /* hardware error code */ +} __attribute__ ((__packed__)) hci_hardware_error_ep; -#define NG_HCI_EVENT_FLUSH_OCCUR 0x11 +#define HCI_EVENT_FLUSH_OCCUR 0x11 typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_flush_occur_ep; + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_flush_occur_ep; -#define NG_HCI_EVENT_ROLE_CHANGE 0x12 +#define HCI_EVENT_ROLE_CHANGE 0x12 typedef struct { - u_int8_t status; /* 0x00 - success */ + uint8_t status; /* 0x00 - success */ bdaddr_t bdaddr; /* address of remote unit */ - u_int8_t role; /* new connection role */ -} __attribute__ ((packed)) ng_hci_role_change_ep; + uint8_t role; /* new connection role */ +} __attribute__ ((__packed__)) hci_role_change_ep; -#define NG_HCI_EVENT_NUM_COMPL_PKTS 0x13 +#define HCI_EVENT_NUM_COMPL_PKTS 0x13 typedef struct { - u_int8_t num_con_handles; /* # of connection handles */ -/* these are repeated "num_con_handles" times - u_int16_t con_handle; --- connection handle(s) - u_int16_t compl_pkt; --- # of completed packets */ -} __attribute__ ((packed)) ng_hci_num_compl_pkts_ep; + uint8_t num_con_handles; /* # of connection handles */ +/* these are repeated "num_con_handles" times + uint16_t con_handle; --- connection handle(s) + uint16_t compl_pkts; --- # of completed packets */ +} __attribute__ ((__packed__)) hci_num_compl_pkts_ep; -#define NG_HCI_EVENT_MODE_CHANGE 0x14 +#define HCI_EVENT_MODE_CHANGE 0x14 typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ - u_int8_t unit_mode; /* remote unit mode */ - u_int16_t interval; /* interval * 0.625 msec */ -} __attribute__ ((packed)) ng_hci_mode_change_ep; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t unit_mode; /* remote unit mode */ + uint16_t interval; /* interval * 0.625 msec */ +} __attribute__ ((__packed__)) hci_mode_change_ep; -#define NG_HCI_EVENT_RETURN_LINK_KEYS 0x15 +#define HCI_EVENT_RETURN_LINK_KEYS 0x15 typedef struct { - u_int8_t num_keys; /* # of keys */ -/* these are repeated "num_keys" times + uint8_t num_keys; /* # of keys */ +/* these are repeated "num_keys" times bdaddr_t bdaddr; --- remote address(es) - u_int8_t key[NG_HCI_KEY_SIZE]; --- key(s) */ -} __attribute__ ((packed)) ng_hci_return_link_keys_ep; + uint8_t key[HCI_KEY_SIZE]; --- key(s) */ +} __attribute__ ((__packed__)) hci_return_link_keys_ep; -#define NG_HCI_EVENT_PIN_CODE_REQ 0x16 +#define HCI_EVENT_PIN_CODE_REQ 0x16 typedef struct { bdaddr_t bdaddr; /* remote unit address */ -} __attribute__ ((packed)) ng_hci_pin_code_req_ep; +} __attribute__ ((__packed__)) hci_pin_code_req_ep; -#define NG_HCI_EVENT_LINK_KEY_REQ 0x17 +#define HCI_EVENT_LINK_KEY_REQ 0x17 typedef struct { bdaddr_t bdaddr; /* remote unit address */ -} __attribute__ ((packed)) ng_hci_link_key_req_ep; +} __attribute__ ((__packed__)) hci_link_key_req_ep; -#define NG_HCI_EVENT_LINK_KEY_NOTIFICATION 0x18 +#define HCI_EVENT_LINK_KEY_NOTIFICATION 0x18 typedef struct { - bdaddr_t bdaddr; /* remote unit address */ - u_int8_t key[NG_HCI_KEY_SIZE]; /* link key */ - u_int8_t key_type; /* type of the key */ -} __attribute__ ((packed)) ng_hci_link_key_notification_ep; + bdaddr_t bdaddr; /* remote unit address */ + uint8_t key[HCI_KEY_SIZE]; /* link key */ + uint8_t key_type; /* type of the key */ +} __attribute__ ((__packed__)) hci_link_key_notification_ep; -#define NG_HCI_EVENT_LOOPBACK_COMMAND 0x19 -typedef struct { - u_int8_t command[0]; /* Command packet */ -} __attribute__ ((packed)) ng_hci_loopback_command_ep; +#define HCI_EVENT_LOOPBACK_COMMAND 0x19 +typedef hci_cmd_hdr_t hci_loopback_command_ep; -#define NG_HCI_EVENT_DATA_BUFFER_OVERFLOW 0x1a +#define HCI_EVENT_DATA_BUFFER_OVERFLOW 0x1a typedef struct { - u_int8_t link_type; /* Link type */ -} __attribute__ ((packed)) ng_hci_data_buffer_overflow_ep; + uint8_t link_type; /* Link type */ +} __attribute__ ((__packed__)) hci_data_buffer_overflow_ep; -#define NG_HCI_EVENT_MAX_SLOT_CHANGE 0x1b +#define HCI_EVENT_MAX_SLOT_CHANGE 0x1b typedef struct { - u_int16_t con_handle; /* connection handle */ - u_int8_t lmp_max_slots; /* Max. # of slots allowed */ -} __attribute__ ((packed)) ng_hci_max_slot_change_ep; + uint16_t con_handle; /* connection handle */ + uint8_t lmp_max_slots; /* Max. # of slots allowed */ +} __attribute__ ((__packed__)) hci_max_slot_change_ep; -#define NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL 0x1c +#define HCI_EVENT_READ_CLOCK_OFFSET_COMPL 0x1c typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* Connection handle */ - u_int16_t clock_offset; /* Clock offset */ -} __attribute__ ((packed)) ng_hci_read_clock_offset_compl_ep; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* Connection handle */ + uint16_t clock_offset; /* Clock offset */ +} __attribute__ ((__packed__)) hci_read_clock_offset_compl_ep; -#define NG_HCI_EVENT_CON_PKT_TYPE_CHANGED 0x1d +#define HCI_EVENT_CON_PKT_TYPE_CHANGED 0x1d typedef struct { - u_int8_t status; /* 0x00 - success */ - u_int16_t con_handle; /* connection handle */ - u_int16_t pkt_type; /* packet type */ -} __attribute__ ((packed)) ng_hci_con_pkt_type_changed_ep; + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint16_t pkt_type; /* packet type */ +} __attribute__ ((__packed__)) hci_con_pkt_type_changed_ep; -#define NG_HCI_EVENT_QOS_VIOLATION 0x1e +#define HCI_EVENT_QOS_VIOLATION 0x1e typedef struct { - u_int16_t con_handle; /* connection handle */ -} __attribute__ ((packed)) ng_hci_qos_violation_ep; + uint16_t con_handle; /* connection handle */ +} __attribute__ ((__packed__)) hci_qos_violation_ep; -#define NG_HCI_EVENT_PAGE_SCAN_MODE_CHANGE 0x1f +/* Page Scan Mode Change Event is deprecated */ +#define HCI_EVENT_PAGE_SCAN_MODE_CHANGE 0x1f typedef struct { bdaddr_t bdaddr; /* destination address */ - u_int8_t page_scan_mode; /* page scan mode */ -} __attribute__ ((packed)) ng_hci_page_scan_mode_change_ep; + uint8_t page_scan_mode; /* page scan mode */ +} __attribute__ ((__packed__)) hci_page_scan_mode_change_ep; -#define NG_HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE 0x20 +#define HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE 0x20 typedef struct { bdaddr_t bdaddr; /* destination address */ - u_int8_t page_scan_rep_mode; /* page scan repetition mode */ -} __attribute__ ((packed)) ng_hci_page_scan_rep_mode_change_ep; + uint8_t page_scan_rep_mode; /* page scan repetition mode */ +} __attribute__ ((__packed__)) hci_page_scan_rep_mode_change_ep; + +#define HCI_EVENT_FLOW_SPECIFICATION_COMPL 0x21 +typedef struct { + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t flags; /* reserved */ + uint8_t direction; /* flow direction */ + uint8_t type; /* service type */ + uint32_t token_rate; /* token rate */ + uint32_t bucket_size; /* token bucket size */ + uint32_t peak_bandwidth; /* peak bandwidth */ + uint32_t latency; /* access latency */ +} __attribute__ ((__packed__)) hci_flow_specification_compl_ep; + +#define HCI_EVENT_RSSI_RESULT 0x22 +typedef struct { + uint8_t num_responses; /* number of responses */ +/* hci_rssi_response[num_responses] -- see below */ +} __attribute__ ((__packed__)) hci_rssi_result_ep; + +typedef struct { + bdaddr_t bdaddr; /* unit address */ + uint8_t page_scan_rep_mode; /* page scan rep. mode */ + uint8_t blank; /* reserved */ + uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ + uint16_t clock_offset; /* clock offset */ + int8_t rssi; /* rssi */ +} __attribute__ ((__packed__)) hci_rssi_response_ep; + +#define HCI_EVENT_READ_REMOTE_EXTENDED_FEATURES 0x23 +typedef struct { + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t page; /* page number */ + uint8_t max; /* max page number */ + uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ +} __attribute__ ((__packed__)) hci_read_remote_extended_features_ep; + +#define HCI_EVENT_SCO_CON_COMPL 0x2c +typedef struct { + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + bdaddr_t bdaddr; /* unit address */ + uint8_t link_type; /* link type */ + uint8_t interval; /* transmission interval */ + uint8_t window; /* retransmission window */ + uint16_t rxlen; /* rx packet length */ + uint16_t txlen; /* tx packet length */ + uint8_t mode; /* air mode */ +} __attribute__ ((__packed__)) hci_sco_con_compl_ep; + +#define HCI_EVENT_SCO_CON_CHANGED 0x2d +typedef struct { + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t interval; /* transmission interval */ + uint8_t window; /* retransmission window */ + uint16_t rxlen; /* rx packet length */ + uint16_t txlen; /* tx packet length */ +} __attribute__ ((__packed__)) hci_sco_con_changed_ep; + +#define HCI_EVENT_BT_LOGO 0xfe + +#define HCI_EVENT_VENDOR 0xff + +/************************************************************************** + ************************************************************************** + ** HCI Socket Definitions + ************************************************************************** + **************************************************************************/ + +/* HCI socket options */ +#define SO_HCI_EVT_FILTER 1 /* get/set event filter */ +#define SO_HCI_PKT_FILTER 2 /* get/set packet filter */ +#define SO_HCI_DIRECTION 3 /* packet direction indicator */ + +/* Control Messages */ +#define SCM_HCI_DIRECTION SO_HCI_DIRECTION + +/* + * HCI socket filter and get/set routines + * + * for ease of use, we filter 256 possible events/packets + */ +struct hci_filter { + uint32_t mask[8]; /* 256 bits */ +}; + +static __inline void +hci_filter_set(uint8_t bit, struct hci_filter *filter) +{ + uint8_t off = bit - 1; + + off >>= 5; + filter->mask[off] |= (1 << ((bit - 1) & 0x1f)); +} + +static __inline void +hci_filter_clr(uint8_t bit, struct hci_filter *filter) +{ + uint8_t off = bit - 1; + + off >>= 5; + filter->mask[off] &= ~(1 << ((bit - 1) & 0x1f)); +} + +static __inline int +hci_filter_test(uint8_t bit, struct hci_filter *filter) +{ + uint8_t off = bit - 1; -#define NG_HCI_EVENT_BT_LOGO 0xfe + off >>= 5; + return (filter->mask[off] & (1 << ((bit - 1) & 0x1f))); +} -#define NG_HCI_EVENT_VENDOR 0xff +/* + * HCI socket ioctl's + * + * Apart from GBTINFOA, these are all indexed on the unit name + */ + +#define SIOCGBTINFO _IOWR('b', 5, struct btreq) /* get unit info */ +#define SIOCGBTINFOA _IOWR('b', 6, struct btreq) /* get info by address */ +#define SIOCNBTINFO _IOWR('b', 7, struct btreq) /* next unit info */ + +#define SIOCSBTFLAGS _IOWR('b', 8, struct btreq) /* set unit flags */ +#define SIOCSBTPOLICY _IOWR('b', 9, struct btreq) /* set unit link policy */ +#define SIOCSBTPTYPE _IOWR('b', 10, struct btreq) /* set unit packet type */ + +#define SIOCGBTSTATS _IOWR('b', 11, struct btreq) /* get unit statistics */ +#define SIOCZBTSTATS _IOWR('b', 12, struct btreq) /* zero unit statistics */ + +#define SIOCBTDUMP _IOW('b', 13, struct btreq) /* print debug info */ +#define SIOCSBTSCOMTU _IOWR('b', 17, struct btreq) /* set sco_mtu value */ + +struct bt_stats { + uint32_t err_tx; + uint32_t err_rx; + uint32_t cmd_tx; + uint32_t evt_rx; + uint32_t acl_tx; + uint32_t acl_rx; + uint32_t sco_tx; + uint32_t sco_rx; + uint32_t byte_tx; + uint32_t byte_rx; +}; + +struct btreq { + char btr_name[HCI_DEVNAME_SIZE]; /* device name */ + + union { + struct { + bdaddr_t btri_bdaddr; /* device bdaddr */ + uint16_t btri_flags; /* flags */ + uint16_t btri_num_cmd; /* # of free cmd buffers */ + uint16_t btri_num_acl; /* # of free ACL buffers */ + uint16_t btri_num_sco; /* # of free SCO buffers */ + uint16_t btri_acl_mtu; /* ACL mtu */ + uint16_t btri_sco_mtu; /* SCO mtu */ + uint16_t btri_link_policy; /* Link Policy */ + uint16_t btri_packet_type; /* Packet Type */ + } btri; + struct bt_stats btrs; /* unit stats */ + } btru; +}; + +#define btr_flags btru.btri.btri_flags +#define btr_bdaddr btru.btri.btri_bdaddr +#define btr_num_cmd btru.btri.btri_num_cmd +#define btr_num_acl btru.btri.btri_num_acl +#define btr_num_sco btru.btri.btri_num_sco +#define btr_acl_mtu btru.btri.btri_acl_mtu +#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 */ +#define BTF_UP (1<<0) /* unit is up */ +#define BTF_RUNNING (1<<1) /* unit is running */ +#define BTF_XMIT_CMD (1<<2) /* unit is transmitting CMD packets */ +#define BTF_XMIT_ACL (1<<3) /* unit is transmitting ACL packets */ +#define BTF_XMIT_SCO (1<<4) /* unit is transmitting SCO packets */ +#define BTF_XMIT (BTF_XMIT_CMD | BTF_XMIT_ACL | BTF_XMIT_SCO) +#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) + +/************************************************************************** + ************************************************************************** + ** HCI Kernel Definitions + ************************************************************************** + **************************************************************************/ + +#ifdef _KERNEL + +#include <net/if.h> /* for struct ifqueue */ + +struct l2cap_channel; +struct mbuf; +struct sco_pcb; +struct socket; + +/* global HCI kernel variables */ + +/* sysctl variables */ +extern int hci_memo_expiry; +extern int hci_acl_expiry; +extern int hci_sendspace, hci_recvspace; +extern int hci_eventq_max, hci_aclrxq_max, hci_scorxq_max; + +/* + * HCI Connection Information + */ +struct hci_link { + struct hci_unit *hl_unit; /* our unit */ + TAILQ_ENTRY(hci_link) hl_next; /* next link on unit */ + + /* common info */ + uint16_t hl_state; /* connection state */ + uint16_t hl_flags; /* link flags */ + bdaddr_t hl_bdaddr; /* dest address */ + uint16_t hl_handle; /* connection handle */ + uint8_t hl_type; /* link type */ + + /* ACL link info */ + uint8_t hl_lastid; /* last id used */ + uint16_t hl_refcnt; /* reference count */ + uint16_t hl_mtu; /* signalling mtu for link */ + uint16_t hl_flush; /* flush timeout */ + + TAILQ_HEAD(,l2cap_pdu) hl_txq; /* queue of outgoing PDUs */ + int hl_txqlen; /* number of fragments */ + struct mbuf *hl_rxp; /* incoming PDU (accumulating)*/ + struct timeout hl_expire; /* connection expiry timer */ + TAILQ_HEAD(,l2cap_req) hl_reqs; /* pending requests */ + + /* SCO link info */ + struct hci_link *hl_link; /* SCO ACL link */ + struct sco_pcb *hl_sco; /* SCO pcb */ + struct ifqueue hl_data; /* SCO outgoing data */ +}; + +/* hci_link state */ +#define HCI_LINK_CLOSED 0 /* closed */ +#define HCI_LINK_WAIT_CONNECT 1 /* waiting to connect */ +#define HCI_LINK_WAIT_AUTH 2 /* waiting for auth */ +#define HCI_LINK_WAIT_ENCRYPT 3 /* waiting for encrypt */ +#define HCI_LINK_WAIT_SECURE 4 /* waiting for secure */ +#define HCI_LINK_OPEN 5 /* ready and willing */ +#define HCI_LINK_BLOCK 6 /* open but blocking (see hci_acl_start) */ + +/* hci_link flags */ +#define HCI_LINK_AUTH_REQ (1<<0) /* authentication requested */ +#define HCI_LINK_ENCRYPT_REQ (1<<1) /* encryption requested */ +#define HCI_LINK_SECURE_REQ (1<<2) /* secure link requested */ +#define HCI_LINK_AUTH (1<<3) /* link is authenticated */ +#define HCI_LINK_ENCRYPT (1<<4) /* link is encrypted */ +#define HCI_LINK_SECURE (1<<5) /* link is secured */ + +/* + * Bluetooth Memo + * cached device information for remote devices that this unit has seen + */ +struct hci_memo { + struct timeval time; /* time of last response */ + hci_inquiry_response response; /* inquiry response */ + LIST_ENTRY(hci_memo) next; +}; + +/* + * The Bluetooth HCI device unit structure + */ +struct hci_unit { + struct device *hci_softc; /* ptr to device softc */ + struct device *hci_bthub; /* bthub(4) handle */ + + /* device info */ + char *hci_devname; /* device name */ + bdaddr_t hci_bdaddr; /* device address */ + uint16_t hci_flags; /* see BTF_ above */ + + uint16_t hci_packet_type; /* packet types */ + uint16_t hci_acl_mask; /* ACL packet capabilities */ + uint16_t hci_sco_mask; /* SCO packet capabilities */ + + uint16_t hci_link_policy; /* link policy */ + uint16_t hci_lmp_mask; /* link policy capabilities */ + + /* flow control */ + uint16_t hci_max_acl_size; /* ACL payload mtu */ + uint16_t hci_num_acl_pkts; /* free ACL packet buffers */ + uint8_t hci_num_cmd_pkts; /* free CMD packet buffers */ + uint8_t hci_max_sco_size; /* SCO payload mtu */ + uint16_t hci_num_sco_pkts; /* free SCO packet buffers */ + + 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 ifqueue hci_eventq; /* Event queue */ + struct ifqueue hci_aclrxq; /* ACL rx queue */ + struct ifqueue hci_scorxq; /* SCO rx queue */ + uint16_t hci_eventqlen; /* Event queue length */ + uint16_t hci_aclrxqlen; /* ACL rx queue length */ + uint16_t hci_scorxqlen; /* SCO rx queue length */ + + /* 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; +}; + +extern TAILQ_HEAD(hci_unit_list, hci_unit) hci_unit_list; + +/* + * HCI layer function prototypes + */ -#endif /* ndef _NETGRAPH_HCI_H_ */ +/* hci_event.c */ +void hci_event(struct mbuf *, struct hci_unit *); + +/* hci_ioctl.c */ +int hci_ioctl(unsigned long, void *, struct proc *); + +/* hci_link.c */ +struct hci_link *hci_acl_open(struct hci_unit *, bdaddr_t *); +struct hci_link *hci_acl_newconn(struct hci_unit *, bdaddr_t *); +void hci_acl_close(struct hci_link *, int); +void hci_acl_timeout(void *); +int hci_acl_setmode(struct hci_link *); +void hci_acl_linkmode(struct hci_link *); +void hci_acl_recv(struct mbuf *, struct hci_unit *); +int hci_acl_send(struct mbuf *, struct hci_link *, struct l2cap_channel *); +void hci_acl_start(struct hci_link *); +void hci_acl_complete(struct hci_link *, int); +struct hci_link *hci_sco_newconn(struct hci_unit *, bdaddr_t *); +void hci_sco_recv(struct mbuf *, struct hci_unit *); +void hci_sco_start(struct hci_link *); +void hci_sco_complete(struct hci_link *, int); +struct hci_link *hci_link_alloc(struct hci_unit *); +void hci_link_free(struct hci_link *, int); +struct hci_link *hci_link_lookup_bdaddr(struct hci_unit *, bdaddr_t *, uint16_t); +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 *); +void hci_memo_free(struct hci_memo *); + +/* hci_socket.c */ +void hci_drop(void *); +int hci_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *); +int hci_ctloutput(int, struct socket *, int, int, struct mbuf **); +void hci_mtap(struct mbuf *, struct hci_unit *); + +/* hci_unit.c */ +void hci_attach(struct hci_unit *); +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 *); +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 *); + +#endif /* _KERNEL */ + +#endif /* _NETBT_HCI_H_ */ diff --git a/sys/netbt/hci_event.c b/sys/netbt/hci_event.c new file mode 100644 index 00000000000..645f53e251b --- /dev/null +++ b/sys/netbt/hci_event.c @@ -0,0 +1,936 @@ +/* $OpenBSD: hci_event.c,v 1.1 2007/05/30 03:42:53 uwe Exp $ */ +/* $NetBSD: hci_event.c,v 1.6 2007/04/21 06:15:23 plunky Exp $ */ + +/*- + * Copyright (c) 2005 Iain Hibbert. + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/proc.h> +#include <sys/systm.h> + +#include <netbt/bluetooth.h> +#include <netbt/hci.h> +#include <netbt/sco.h> + +static void hci_event_inquiry_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 *); +static void hci_event_discon_compl(struct hci_unit *, struct mbuf *); +static void hci_event_con_req(struct hci_unit *, struct mbuf *); +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_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_reset(struct hci_unit *, struct mbuf *); + +#ifdef BLUETOOTH_DEBUG +int bluetooth_debug = 99; + +static const char *hci_eventnames[] = { +/* 0x00 */ "NULL", +/* 0x01 */ "INQUIRY COMPLETE", +/* 0x02 */ "INQUIRY RESULT", +/* 0x03 */ "CONN COMPLETE", +/* 0x04 */ "CONN REQ", +/* 0x05 */ "DISCONN COMPLETE", +/* 0x06 */ "AUTH COMPLETE", +/* 0x07 */ "REMOTE NAME REQ COMPLETE", +/* 0x08 */ "ENCRYPTION CHANGE", +/* 0x09 */ "CHANGE CONN LINK KEY COMPLETE", +/* 0x0a */ "MASTER LINK KEY COMPLETE", +/* 0x0b */ "READ REMOTE FEATURES COMPLETE", +/* 0x0c */ "READ REMOTE VERSION INFO COMPLETE", +/* 0x0d */ "QoS SETUP COMPLETE", +/* 0x0e */ "COMMAND COMPLETE", +/* 0x0f */ "COMMAND STATUS", +/* 0x10 */ "HARDWARE ERROR", +/* 0x11 */ "FLUSH OCCUR", +/* 0x12 */ "ROLE CHANGE", +/* 0x13 */ "NUM COMPLETED PACKETS", +/* 0x14 */ "MODE CHANGE", +/* 0x15 */ "RETURN LINK KEYS", +/* 0x16 */ "PIN CODE REQ", +/* 0x17 */ "LINK KEY REQ", +/* 0x18 */ "LINK KEY NOTIFICATION", +/* 0x19 */ "LOOPBACK COMMAND", +/* 0x1a */ "DATA BUFFER OVERFLOW", +/* 0x1b */ "MAX SLOT CHANGE", +/* 0x1c */ "READ CLOCK OFFSET COMPLETE", +/* 0x1d */ "CONN PKT TYPE CHANGED", +/* 0x1e */ "QOS VIOLATION", +/* 0x1f */ "PAGE SCAN MODE CHANGE", +/* 0x20 */ "PAGE SCAN REP MODE CHANGE", +/* 0x21 */ "FLOW SPECIFICATION COMPLETE", +/* 0x22 */ "RSSI RESULT", +/* 0x23 */ "READ REMOTE EXT FEATURES" +}; + +static const char * +hci_eventstr(unsigned int event) +{ + + if (event < (sizeof(hci_eventnames) / sizeof(*hci_eventnames))) + 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"; + + case HCI_EVENT_VENDOR: /* 0xff */ + return "VENDOR"; + } + + return "UNRECOGNISED"; +} +#endif /* BLUETOOTH_DEBUG */ + +/* + * process HCI Events + * + * 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. + */ +void +hci_event(struct mbuf *m, struct hci_unit *unit) +{ + hci_event_hdr_t hdr; + + KASSERT(m->m_flags & M_PKTHDR); + + KASSERT(m->m_pkthdr.len >= sizeof(hdr)); + m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr); + m_adj(m, sizeof(hdr)); + + KASSERT(hdr.type == HCI_EVENT_PKT); + + DPRINTFN(1, "(%s) event %s\n", unit->hci_devname, hci_eventstr(hdr.event)); + + switch(hdr.event) { + case HCI_EVENT_COMMAND_STATUS: + hci_event_command_status(unit, m); + break; + + case HCI_EVENT_COMMAND_COMPL: + hci_event_command_compl(unit, m); + break; + + case HCI_EVENT_NUM_COMPL_PKTS: + hci_event_num_compl_pkts(unit, m); + break; + + case HCI_EVENT_INQUIRY_RESULT: + hci_event_inquiry_result(unit, m); + break; + + case HCI_EVENT_CON_COMPL: + hci_event_con_compl(unit, m); + break; + + case HCI_EVENT_DISCON_COMPL: + hci_event_discon_compl(unit, m); + break; + + case HCI_EVENT_CON_REQ: + hci_event_con_req(unit, m); + break; + + case HCI_EVENT_AUTH_COMPL: + hci_event_auth_compl(unit, m); + break; + + case HCI_EVENT_ENCRYPTION_CHANGE: + hci_event_encryption_change(unit, m); + break; + + case HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL: + 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: + break; + + default: + UNKNOWN(hdr.event); + break; + } + + m_freem(m); +} + +/* + * Command Status + * + * Update our record of num_cmd_pkts then post-process any pending commands + * and optionally restart cmd output on the unit. + */ +static void +hci_event_command_status(struct hci_unit *unit, struct mbuf *m) +{ + hci_command_status_ep ep; + + KASSERT(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) status = 0x%x num_cmd_pkts = %d\n", + unit->hci_devname, + HCI_OGF(letoh16(ep.opcode)), HCI_OCF(letoh16(ep.opcode)), + ep.status, + ep.num_cmd_pkts); + + unit->hci_num_cmd_pkts = ep.num_cmd_pkts; + + /* + * post processing of pending commands + */ + switch(letoh16(ep.opcode)) { + default: + break; + } + + while (unit->hci_num_cmd_pkts > 0 && !IF_IS_EMPTY(&unit->hci_cmdwait)) { + IF_DEQUEUE(&unit->hci_cmdwait, m); + hci_output_cmd(unit, m); + } +} + +/* + * Command Complete + * + * Update our record of num_cmd_pkts then handle the completed command, + * and optionally restart cmd output on the unit. + */ +static void +hci_event_command_compl(struct hci_unit *unit, struct mbuf *m) +{ + hci_command_compl_ep ep; + + KASSERT(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, + HCI_OGF(letoh16(ep.opcode)), HCI_OCF(letoh16(ep.opcode)), + ep.num_cmd_pkts); + + unit->hci_num_cmd_pkts = ep.num_cmd_pkts; + + /* + * post processing of completed commands + */ + switch(letoh16(ep.opcode)) { + case HCI_CMD_READ_BDADDR: + hci_cmd_read_bdaddr(unit, m); + break; + + case HCI_CMD_READ_BUFFER_SIZE: + hci_cmd_read_buffer_size(unit, m); + break; + + case HCI_CMD_READ_LOCAL_FEATURES: + hci_cmd_read_local_features(unit, m); + break; + + case HCI_CMD_RESET: + hci_cmd_reset(unit, m); + break; + + default: + break; + } + + while (unit->hci_num_cmd_pkts > 0 && !IF_IS_EMPTY(&unit->hci_cmdwait)) { + IF_DEQUEUE(&unit->hci_cmdwait, m); + hci_output_cmd(unit, m); + } +} + +/* + * Number of Completed Packets + * + * This is sent periodically by the Controller telling us how many + * buffers are now freed up and which handle was using them. From + * this we determine which type of buffer it was and add the qty + * back into the relevant packet counter, then restart output on + * links that have halted. + */ +static void +hci_event_num_compl_pkts(struct hci_unit *unit, struct mbuf *m) +{ + hci_num_compl_pkts_ep ep; + struct hci_link *link, *next; + uint16_t handle, num; + int num_acl = 0, num_sco = 0; + + KASSERT(m->m_pkthdr.len >= sizeof(ep)); + m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); + m_adj(m, sizeof(ep)); + + while (ep.num_con_handles--) { + m_copydata(m, 0, sizeof(handle), (caddr_t)&handle); + m_adj(m, sizeof(handle)); + handle = letoh16(handle); + + m_copydata(m, 0, sizeof(num), (caddr_t)&num); + m_adj(m, sizeof(num)); + num = letoh16(num); + + link = hci_link_lookup_handle(unit, handle); + if (link) { + if (link->hl_type == HCI_LINK_ACL) { + num_acl += num; + hci_acl_complete(link, num); + } else { + num_sco += num; + hci_sco_complete(link, num); + } + } else { + /* XXX need to issue Read_Buffer_Size or Reset? */ + printf("%s: unknown handle %d! " + "(losing track of %d packet buffer%s)\n", + unit->hci_devname, handle, + num, (num == 1 ? "" : "s")); + } + } + + /* + * Move up any queued packets. When a link has sent data, it will move + * to the back of the queue - technically then if a link had something + * to send and there were still buffers available it could get started + * twice but it seemed more important to to handle higher loads fairly + * than worry about wasting cycles when we are not busy. + */ + + unit->hci_num_acl_pkts += num_acl; + unit->hci_num_sco_pkts += num_sco; + + link = TAILQ_FIRST(&unit->hci_links); + while (link && (unit->hci_num_acl_pkts > 0 || unit->hci_num_sco_pkts > 0)) { + next = TAILQ_NEXT(link, hl_next); + + if (link->hl_type == HCI_LINK_ACL) { + if (unit->hci_num_acl_pkts > 0 && link->hl_txqlen > 0) + hci_acl_start(link); + } else { + if (unit->hci_num_sco_pkts > 0 && link->hl_txqlen > 0) + hci_sco_start(link); + } + + link = next; + } +} + +/* + * Inquiry Result + * + * keep a note of devices seen, so we know which unit to use + * on outgoing connections + */ +static void +hci_event_inquiry_result(struct hci_unit *unit, struct mbuf *m) +{ + hci_inquiry_result_ep ep; + struct hci_memo *memo; + bdaddr_t bdaddr; + + KASSERT(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--) { + m_copydata(m, 0, sizeof(bdaddr_t), (caddr_t)&bdaddr); + + 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 = malloc(sizeof(struct hci_memo), + M_BLUETOOTH, M_NOWAIT); + if (memo == NULL) { + DPRINTFN(0, "out of memo memory!\n"); + break; + } + bzero(memo, sizeof *memo); + + LIST_INSERT_HEAD(&unit->hci_memos, memo, next); + } + + microtime(&memo->time); + m_copydata(m, 0, sizeof(hci_inquiry_response), + (caddr_t)&memo->response); + m_adj(m, sizeof(hci_inquiry_response)); + + memo->response.clock_offset = + letoh16(memo->response.clock_offset); + } +} + +/* + * Connection Complete + * + * Sent to us when a connection is made. If there is no link + * structure already allocated for this, we must have changed + * our mind, so just disconnect. + */ +static void +hci_event_con_compl(struct hci_unit *unit, struct mbuf *m) +{ + hci_con_compl_ep ep; + hci_write_link_policy_settings_cp cp; + struct hci_link *link; + int err; + + KASSERT(m->m_pkthdr.len >= sizeof(ep)); + m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); + m_adj(m, sizeof(ep)); + + DPRINTFN(1, "(%s) %s connection complete for " + "%02x:%02x:%02x:%02x:%02x:%02x status %#x\n", + unit->hci_devname, + (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], + ep.status); + + link = hci_link_lookup_bdaddr(unit, &ep.bdaddr, ep.link_type); + + if (ep.status) { + if (link != NULL) { + switch (ep.status) { + case 0x04: /* "Page Timeout" */ + err = EHOSTDOWN; + break; + + case 0x08: /* "Connection Timed Out" */ + err = ETIMEDOUT; + break; + + case 0x16: /* "Connection Terminated by Local Host" */ + err = 0; + break; + + default: + err = ECONNREFUSED; + break; + } + + hci_link_free(link, err); + } + + return; + } + + if (link == NULL) { + hci_discon_cp dp; + + dp.con_handle = ep.con_handle; + dp.reason = 0x13; /* "Remote User Terminated Connection" */ + + hci_send_cmd(unit, HCI_CMD_DISCONNECT, &dp, sizeof(dp)); + return; + } + + /* XXX could check auth_enable here */ + + if (ep.encryption_mode) + link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT); + + link->hl_state = HCI_LINK_OPEN; + link->hl_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); + + if (ep.link_type == HCI_LINK_ACL) { + cp.con_handle = ep.con_handle; + cp.settings = htole16(unit->hci_link_policy); + err = hci_send_cmd(unit, HCI_CMD_WRITE_LINK_POLICY_SETTINGS, + &cp, sizeof(cp)); + if (err) + printf("%s: Warning, could not write link policy\n", + unit->hci_devname); + + err = hci_acl_setmode(link); + if (err == EINPROGRESS) + return; + + hci_acl_linkmode(link); + } else { + (*link->hl_sco->sp_proto->connected)(link->hl_sco->sp_upper); + } +} + +/* + * Disconnection Complete + * + * This is sent in response to a disconnection request, but also if + * the remote device goes out of range. + */ +static void +hci_event_discon_compl(struct hci_unit *unit, struct mbuf *m) +{ + hci_discon_compl_ep ep; + struct hci_link *link; + + KASSERT(m->m_pkthdr.len >= sizeof(ep)); + m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); + m_adj(m, sizeof(ep)); + + ep.con_handle = letoh16(ep.con_handle); + + DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status); + + link = hci_link_lookup_handle(unit, HCI_CON_HANDLE(ep.con_handle)); + if (link) + hci_link_free(link, ENOENT); /* XXX NetBSD used ENOLINK here */ +} + +/* + * Connect Request + * + * We check upstream for appropriate listeners and accept connections + * that are wanted. + */ +static void +hci_event_con_req(struct hci_unit *unit, struct mbuf *m) +{ + hci_con_req_ep ep; + hci_accept_con_cp ap; + hci_reject_con_cp rp; + struct hci_link *link; + + KASSERT(m->m_pkthdr.len >= sizeof(ep)); + 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 " + "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"); + + if (ep.link_type == HCI_LINK_ACL) + link = hci_acl_newconn(unit, &ep.bdaddr); + else + link = hci_sco_newconn(unit, &ep.bdaddr); + + if (link == NULL) { + memset(&rp, 0, sizeof(rp)); + bdaddr_copy(&rp.bdaddr, &ep.bdaddr); + rp.reason = 0x0f; /* Unacceptable BD_ADDR */ + + hci_send_cmd(unit, HCI_CMD_REJECT_CON, &rp, sizeof(rp)); + } else { + memset(&ap, 0, sizeof(ap)); + bdaddr_copy(&ap.bdaddr, &ep.bdaddr); + if (unit->hci_link_policy & HCI_LINK_POLICY_ENABLE_ROLE_SWITCH) + ap.role = HCI_ROLE_MASTER; + else + ap.role = HCI_ROLE_SLAVE; + + hci_send_cmd(unit, HCI_CMD_ACCEPT_CON, &ap, sizeof(ap)); + } +} + +/* + * Auth Complete + * + * Authentication has been completed on an ACL link. We can notify the + * upper layer protocols unless further mode changes are pending. + */ +static void +hci_event_auth_compl(struct hci_unit *unit, struct mbuf *m) +{ + hci_auth_compl_ep ep; + struct hci_link *link; + int err; + + KASSERT(m->m_pkthdr.len >= sizeof(ep)); + m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); + m_adj(m, sizeof(ep)); + + ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); + + DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status); + + link = hci_link_lookup_handle(unit, ep.con_handle); + if (link == NULL || link->hl_type != HCI_LINK_ACL) + return; + + if (ep.status == 0) { + link->hl_flags |= HCI_LINK_AUTH; + + if (link->hl_state == HCI_LINK_WAIT_AUTH) + link->hl_state = HCI_LINK_OPEN; + + err = hci_acl_setmode(link); + if (err == EINPROGRESS) + return; + } + + hci_acl_linkmode(link); +} + +/* + * Encryption Change + * + * The encryption status has changed. Basically, we note the change + * then notify the upper layer protocol unless further mode changes + * are pending. + * Note that if encryption gets disabled when it has been requested, + * we will attempt to enable it again.. (its a feature not a bug :) + */ +static void +hci_event_encryption_change(struct hci_unit *unit, struct mbuf *m) +{ + hci_encryption_change_ep ep; + struct hci_link *link; + int err; + + KASSERT(m->m_pkthdr.len >= sizeof(ep)); + m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); + m_adj(m, sizeof(ep)); + + 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); + + link = hci_link_lookup_handle(unit, ep.con_handle); + if (link == NULL || link->hl_type != HCI_LINK_ACL) + return; + + if (ep.status == 0) { + if (ep.encryption_enable == 0) + link->hl_flags &= ~HCI_LINK_ENCRYPT; + else + link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT); + + if (link->hl_state == HCI_LINK_WAIT_ENCRYPT) + link->hl_state = HCI_LINK_OPEN; + + err = hci_acl_setmode(link); + if (err == EINPROGRESS) + return; + } + + hci_acl_linkmode(link); +} + +/* + * Change Connection Link Key Complete + * + * Link keys are handled in userland but if we are waiting to secure + * this link, we should notify the upper protocols. A SECURE request + * only needs a single key change, so we can cancel the request. + */ +static void +hci_event_change_con_link_key_compl(struct hci_unit *unit, struct mbuf *m) +{ + hci_change_con_link_key_compl_ep ep; + struct hci_link *link; + int err; + + KASSERT(m->m_pkthdr.len >= sizeof(ep)); + m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); + m_adj(m, sizeof(ep)); + + ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); + + DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status); + + link = hci_link_lookup_handle(unit, ep.con_handle); + if (link == NULL || link->hl_type != HCI_LINK_ACL) + return; + + link->hl_flags &= ~HCI_LINK_SECURE_REQ; + + if (ep.status == 0) { + link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_SECURE); + + if (link->hl_state == HCI_LINK_WAIT_SECURE) + link->hl_state = HCI_LINK_OPEN; + + err = hci_acl_setmode(link); + if (err == EINPROGRESS) + return; + } + + hci_acl_linkmode(link); +} + +/* + * process results of read_bdaddr command_complete event + */ +static void +hci_cmd_read_bdaddr(struct hci_unit *unit, struct mbuf *m) +{ + hci_read_bdaddr_rp rp; + int s; + + KASSERT(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_BDADDR) == 0) + return; + + bdaddr_copy(&unit->hci_bdaddr, &rp.bdaddr); + +#define splraiseipl(ipl) spltty() /* XXX */ + s = splraiseipl(unit->hci_ipl); + unit->hci_flags &= ~BTF_INIT_BDADDR; + splx(s); + + wakeup(unit); +} + +/* + * process results of read_buffer_size command_complete event + */ +static void +hci_cmd_read_buffer_size(struct hci_unit *unit, struct mbuf *m) +{ + hci_read_buffer_size_rp rp; + int s; + + KASSERT(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_BUFFER_SIZE) == 0) + return; + + unit->hci_max_acl_size = letoh16(rp.max_acl_size); + unit->hci_num_acl_pkts = letoh16(rp.num_acl_pkts); + unit->hci_max_sco_size = rp.max_sco_size; + unit->hci_num_sco_pkts = letoh16(rp.num_sco_pkts); + + s = splraiseipl(unit->hci_ipl); + unit->hci_flags &= ~BTF_INIT_BUFFER_SIZE; + splx(s); + + wakeup(unit); +} + +/* + * process results of read_local_features command_complete event + */ +static void +hci_cmd_read_local_features(struct hci_unit *unit, struct mbuf *m) +{ + hci_read_local_features_rp rp; + int s; + + KASSERT(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_FEATURES) == 0) + return; + + unit->hci_lmp_mask = 0; + + if (rp.features[0] & HCI_LMP_ROLE_SWITCH) + unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_ROLE_SWITCH; + + if (rp.features[0] & HCI_LMP_HOLD_MODE) + unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_HOLD_MODE; + + if (rp.features[0] & HCI_LMP_SNIFF_MODE) + unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_SNIFF_MODE; + + if (rp.features[1] & HCI_LMP_PARK_MODE) + unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_PARK_MODE; + + /* ACL packet mask */ + unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1; + + if (rp.features[0] & HCI_LMP_3SLOT) + unit->hci_acl_mask |= HCI_PKT_DM3 | HCI_PKT_DH3; + + if (rp.features[0] & HCI_LMP_5SLOT) + unit->hci_acl_mask |= HCI_PKT_DM5 | HCI_PKT_DH5; + + if ((rp.features[3] & HCI_LMP_EDR_ACL_2MBPS) == 0) + unit->hci_acl_mask |= HCI_PKT_2MBPS_DH1 + | HCI_PKT_2MBPS_DH3 + | HCI_PKT_2MBPS_DH5; + + if ((rp.features[3] & HCI_LMP_EDR_ACL_3MBPS) == 0) + unit->hci_acl_mask |= HCI_PKT_3MBPS_DH1 + | HCI_PKT_3MBPS_DH3 + | HCI_PKT_3MBPS_DH5; + + if ((rp.features[4] & HCI_LMP_3SLOT_EDR_ACL) == 0) + unit->hci_acl_mask |= HCI_PKT_2MBPS_DH3 + | HCI_PKT_3MBPS_DH3; + + if ((rp.features[5] & HCI_LMP_5SLOT_EDR_ACL) == 0) + unit->hci_acl_mask |= HCI_PKT_2MBPS_DH5 + | HCI_PKT_3MBPS_DH5; + + unit->hci_packet_type = unit->hci_acl_mask; + + /* SCO packet mask */ + unit->hci_sco_mask = 0; + if (rp.features[1] & HCI_LMP_SCO_LINK) + unit->hci_sco_mask |= HCI_PKT_HV1; + + if (rp.features[1] & HCI_LMP_HV2_PKT) + unit->hci_sco_mask |= HCI_PKT_HV2; + + if (rp.features[1] & HCI_LMP_HV3_PKT) + unit->hci_sco_mask |= HCI_PKT_HV3; + + if (rp.features[3] & HCI_LMP_EV3_PKT) + unit->hci_sco_mask |= HCI_PKT_EV3; + + if (rp.features[4] & HCI_LMP_EV4_PKT) + unit->hci_sco_mask |= HCI_PKT_EV4; + + if (rp.features[4] & HCI_LMP_EV5_PKT) + unit->hci_sco_mask |= HCI_PKT_EV5; + + /* XXX what do 2MBPS/3MBPS/3SLOT eSCO mean? */ + + s = splraiseipl(unit->hci_ipl); + unit->hci_flags &= ~BTF_INIT_FEATURES; + splx(s); + + 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, + unit->hci_acl_mask, unit->hci_sco_mask); +} + +/* + * process results of reset command_complete event + * + * This has killed all the connections, so close down anything we have left, + * and reinitialise the unit. + */ +static void +hci_cmd_reset(struct hci_unit *unit, struct mbuf *m) +{ + hci_reset_rp rp; + struct hci_link *link, *next; + int acl; + + KASSERT(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; + + /* + * release SCO links first, since they may be holding + * an ACL link reference. + */ + for (acl = 0 ; acl < 2 ; acl++) { + next = TAILQ_FIRST(&unit->hci_links); + while ((link = next) != NULL) { + next = TAILQ_NEXT(link, hl_next); + if (acl || link->hl_type != HCI_LINK_ACL) + hci_link_free(link, ECONNABORTED); + } + } + + unit->hci_num_acl_pkts = 0; + unit->hci_num_sco_pkts = 0; + + if (hci_send_cmd(unit, HCI_CMD_READ_BDADDR, NULL, 0)) + return; + + if (hci_send_cmd(unit, HCI_CMD_READ_BUFFER_SIZE, NULL, 0)) + return; + + if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_FEATURES, NULL, 0)) + return; +} diff --git a/sys/netbt/hci_link.c b/sys/netbt/hci_link.c new file mode 100644 index 00000000000..6542568b1f6 --- /dev/null +++ b/sys/netbt/hci_link.c @@ -0,0 +1,1034 @@ +/* $OpenBSD: hci_link.c,v 1.1 2007/05/30 03:42:53 uwe Exp $ */ +/* $NetBSD: hci_link.c,v 1.11 2007/04/21 06:15:23 plunky Exp $ */ + +/*- + * Copyright (c) 2005 Iain Hibbert. + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/proc.h> +#include <sys/queue.h> +#include <sys/systm.h> + +#include <netbt/bluetooth.h> +#include <netbt/hci.h> +#include <netbt/l2cap.h> +#include <netbt/sco.h> + +/******************************************************************************* + * + * HCI ACL Connections + */ + +/* + * Automatically expire unused ACL connections after this number of + * seconds (if zero, do not expire unused connections) [sysctl] + */ +int hci_acl_expiry = 10; /* seconds */ + +/* + * hci_acl_open(unit, bdaddr) + * + * open ACL connection to remote bdaddr. Only one ACL connection is permitted + * between any two Bluetooth devices, so we look for an existing one before + * trying to start a new one. + */ +struct hci_link * +hci_acl_open(struct hci_unit *unit, bdaddr_t *bdaddr) +{ + struct hci_link *link; + struct hci_memo *memo; + hci_create_con_cp cp; + int err; + + KASSERT(unit != NULL); + KASSERT(bdaddr != NULL); + + link = hci_link_lookup_bdaddr(unit, bdaddr, HCI_LINK_ACL); + if (link == NULL) { + link = hci_link_alloc(unit); + if (link == NULL) + return NULL; + + link->hl_type = HCI_LINK_ACL; + bdaddr_copy(&link->hl_bdaddr, bdaddr); + } + + switch(link->hl_state) { + case HCI_LINK_CLOSED: + /* + * open connection to remote device + */ + memset(&cp, 0, sizeof(cp)); + bdaddr_copy(&cp.bdaddr, bdaddr); + cp.pkt_type = htole16(unit->hci_packet_type); + + 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); + } + + if (unit->hci_link_policy & HCI_LINK_POLICY_ENABLE_ROLE_SWITCH) + cp.accept_role_switch = 1; + + err = hci_send_cmd(unit, HCI_CMD_CREATE_CON, &cp, sizeof(cp)); + if (err) { + hci_link_free(link, err); + return NULL; + } + + link->hl_state = HCI_LINK_WAIT_CONNECT; + break; + + case HCI_LINK_WAIT_CONNECT: + case HCI_LINK_WAIT_AUTH: + case HCI_LINK_WAIT_ENCRYPT: + case HCI_LINK_WAIT_SECURE: + /* + * somebody else already trying to connect, we just + * sit on the bench with them.. + */ + break; + + case HCI_LINK_OPEN: + /* + * If already open, halt any expiry timeouts. We dont need + * to care about already invoking timeouts since refcnt >0 + * will keep the link alive. + */ + timeout_del(&link->hl_expire); + break; + + default: + UNKNOWN(link->hl_state); + return NULL; + } + + /* open */ + link->hl_refcnt++; + + return link; +} + +/* + * Close ACL connection. When there are no more references to this link, + * we can either close it down or schedule a delayed closedown. + */ +void +hci_acl_close(struct hci_link *link, int err) +{ + + KASSERT(link != NULL); + + if (--link->hl_refcnt == 0) { + if (link->hl_state == HCI_LINK_CLOSED) + hci_link_free(link, err); + else if (hci_acl_expiry > 0) + timeout_add(&link->hl_expire, hci_acl_expiry * hz); + } +} + +/* + * Incoming ACL connection. + * + * For now, we accept all connections but it would be better to check + * the L2CAP listen list and only accept when there is a listener + * available. + * + * There should not be a link to the same bdaddr already, we check + * anyway though its left unhandled for now. + */ +struct hci_link * +hci_acl_newconn(struct hci_unit *unit, bdaddr_t *bdaddr) +{ + struct hci_link *link; + + link = hci_link_lookup_bdaddr(unit, bdaddr, HCI_LINK_ACL); + if (link != NULL) + return NULL; + + link = hci_link_alloc(unit); + if (link != NULL) { + link->hl_state = HCI_LINK_WAIT_CONNECT; + link->hl_type = HCI_LINK_ACL; + bdaddr_copy(&link->hl_bdaddr, bdaddr); + + if (hci_acl_expiry > 0) + timeout_add(&link->hl_expire, hci_acl_expiry * hz); + } + + return link; +} + +void +hci_acl_timeout(void *arg) +{ + struct hci_link *link = arg; + hci_discon_cp cp; + int s, err; + + s = splsoftnet(); + + if (link->hl_refcnt > 0) + goto out; + + DPRINTF("link #%d expired\n", link->hl_handle); + + switch (link->hl_state) { + case HCI_LINK_CLOSED: + case HCI_LINK_WAIT_CONNECT: + hci_link_free(link, ECONNRESET); + break; + + case HCI_LINK_WAIT_AUTH: + case HCI_LINK_WAIT_ENCRYPT: + case HCI_LINK_WAIT_SECURE: + case HCI_LINK_OPEN: + cp.con_handle = htole16(link->hl_handle); + cp.reason = 0x13; /* "Remote User Terminated Connection" */ + + err = hci_send_cmd(link->hl_unit, HCI_CMD_DISCONNECT, + &cp, sizeof(cp)); + + if (err) { + DPRINTF("error %d sending HCI_CMD_DISCONNECT\n", + err); + } + + break; + + default: + UNKNOWN(link->hl_state); + break; + } + +out: + splx(s); +} + +/* + * Initiate any Link Mode change requests. + */ +int +hci_acl_setmode(struct hci_link *link) +{ + int err; + + KASSERT(link != NULL); + KASSERT(link->hl_unit != NULL); + + if (link->hl_state != HCI_LINK_OPEN) + return EINPROGRESS; + + if ((link->hl_flags & HCI_LINK_AUTH_REQ) + && !(link->hl_flags & HCI_LINK_AUTH)) { + hci_auth_req_cp cp; + + DPRINTF("requesting auth for handle #%d\n", + link->hl_handle); + + link->hl_state = HCI_LINK_WAIT_AUTH; + cp.con_handle = htole16(link->hl_handle); + err = hci_send_cmd(link->hl_unit, HCI_CMD_AUTH_REQ, + &cp, sizeof(cp)); + + return (err == 0 ? EINPROGRESS : err); + } + + if ((link->hl_flags & HCI_LINK_ENCRYPT_REQ) + && !(link->hl_flags & HCI_LINK_ENCRYPT)) { + hci_set_con_encryption_cp cp; + + /* XXX we should check features for encryption capability */ + + DPRINTF("requesting encryption for handle #%d\n", + link->hl_handle); + + link->hl_state = HCI_LINK_WAIT_ENCRYPT; + cp.con_handle = htole16(link->hl_handle); + cp.encryption_enable = 0x01; + + err = hci_send_cmd(link->hl_unit, HCI_CMD_SET_CON_ENCRYPTION, + &cp, sizeof(cp)); + + return (err == 0 ? EINPROGRESS : err); + } + + if ((link->hl_flags & HCI_LINK_SECURE_REQ)) { + hci_change_con_link_key_cp cp; + + /* always change link key for SECURE requests */ + link->hl_flags &= ~HCI_LINK_SECURE; + + DPRINTF("changing link key for handle #%d\n", + link->hl_handle); + + link->hl_state = HCI_LINK_WAIT_SECURE; + cp.con_handle = htole16(link->hl_handle); + + err = hci_send_cmd(link->hl_unit, HCI_CMD_CHANGE_CON_LINK_KEY, + &cp, sizeof(cp)); + + return (err == 0 ? EINPROGRESS : err); + } + + return 0; +} + +/* + * Link Mode changed. + * + * This is called from event handlers when the mode change + * is complete. We notify upstream and restart the link. + */ +void +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")); + + if (link->hl_flags & HCI_LINK_AUTH) + mode |= L2CAP_LM_AUTH; + + if (link->hl_flags & HCI_LINK_ENCRYPT) + mode |= L2CAP_LM_ENCRYPT; + + if (link->hl_flags & HCI_LINK_SECURE) + mode |= L2CAP_LM_SECURE; + + /* + * The link state will only be OPEN here if the mode change + * was successful. So, we can proceed with L2CAP connections, + * or notify already establshed channels, to allow any that + * are dissatisfied to disconnect before we restart. + */ + next = LIST_FIRST(&l2cap_active_list); + while ((chan = next) != NULL) { + next = LIST_NEXT(chan, lc_ncid); + + if (chan->lc_link != link) + continue; + + switch(chan->lc_state) { + case L2CAP_WAIT_SEND_CONNECT_REQ: /* we are connecting */ + if ((mode & chan->lc_mode) != chan->lc_mode) { + l2cap_close(chan, ECONNABORTED); + break; + } + + chan->lc_state = L2CAP_WAIT_RECV_CONNECT_RSP; + err = l2cap_send_connect_req(chan); + if (err) { + l2cap_close(chan, err); + break; + } + break; + + case L2CAP_WAIT_SEND_CONNECT_RSP: /* they are connecting */ + if ((mode & chan->lc_mode) != chan->lc_mode) { + l2cap_send_connect_rsp(link, chan->lc_ident, + 0, chan->lc_rcid, + L2CAP_SECURITY_BLOCK); + + l2cap_close(chan, ECONNABORTED); + break; + } + + l2cap_send_connect_rsp(link, chan->lc_ident, + chan->lc_lcid, chan->lc_rcid, + L2CAP_SUCCESS); + + chan->lc_state = L2CAP_WAIT_CONFIG; + chan->lc_flags |= (L2CAP_WAIT_CONFIG_RSP | L2CAP_WAIT_CONFIG_REQ); + err = l2cap_send_config_req(chan); + if (err) { + l2cap_close(chan, err); + break; + } + break; + + case L2CAP_WAIT_RECV_CONNECT_RSP: + case L2CAP_WAIT_CONFIG: + case L2CAP_OPEN: /* already established */ + (*chan->lc_proto->linkmode)(chan->lc_upper, mode); + break; + + default: + break; + } + } + + link->hl_state = HCI_LINK_OPEN; + hci_acl_start(link); +} + +/* + * Receive ACL Data + * + * we accumulate packet fragments on the hci_link structure + * until a full L2CAP frame is ready, then send it on. + */ +void +hci_acl_recv(struct mbuf *m, struct hci_unit *unit) +{ + struct hci_link *link; + hci_acldata_hdr_t hdr; + uint16_t handle, want; + int pb, got; + + KASSERT(m != NULL); + KASSERT(unit != NULL); + + KASSERT(m->m_pkthdr.len >= sizeof(hdr)); + m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr); + m_adj(m, sizeof(hdr)); + +#ifdef DIAGNOSTIC + if (hdr.type != HCI_ACL_DATA_PKT) { + printf("%s: bad ACL packet type\n", unit->hci_devname); + goto bad; + } + + if (m->m_pkthdr.len != letoh16(hdr.length)) { + printf("%s: bad ACL packet length (%d != %d)\n", + unit->hci_devname, m->m_pkthdr.len, letoh16(hdr.length)); + goto bad; + } +#endif + + hdr.length = letoh16(hdr.length); + hdr.con_handle = letoh16(hdr.con_handle); + handle = HCI_CON_HANDLE(hdr.con_handle); + pb = HCI_PB_FLAG(hdr.con_handle); + + link = hci_link_lookup_handle(unit, handle); + if (link == NULL) { + hci_discon_cp cp; + + DPRINTF("%s: dumping packet for unknown handle #%d\n", + unit->hci_devname, handle); + + /* + * There is no way to find out what this connection handle is + * for, just get rid of it. This may happen, if a USB dongle + * is plugged into a self powered hub and does not reset when + * the system is shut down. + */ + cp.con_handle = htole16(handle); + cp.reason = 0x13; /* "Remote User Terminated Connection" */ + hci_send_cmd(unit, HCI_CMD_DISCONNECT, &cp, sizeof(cp)); + goto bad; + } + + switch (pb) { + case HCI_PACKET_START: + if (link->hl_rxp != NULL) + printf("%s: dropped incomplete ACL packet\n", + unit->hci_devname); + + if (m->m_pkthdr.len < sizeof(l2cap_hdr_t)) { + printf("%s: short ACL packet\n", + unit->hci_devname); + + goto bad; + } + + link->hl_rxp = m; + got = m->m_pkthdr.len; + break; + + case HCI_PACKET_FRAGMENT: + if (link->hl_rxp == NULL) { + printf("%s: unexpected packet fragment\n", + unit->hci_devname); + + goto bad; + } + + got = m->m_pkthdr.len + link->hl_rxp->m_pkthdr.len; + m_cat(link->hl_rxp, m); + m = link->hl_rxp; + m->m_pkthdr.len = got; + break; + + default: + printf("%s: unknown packet type\n", + unit->hci_devname); + + goto bad; + } + + m_copydata(m, 0, sizeof(want), (caddr_t)&want); + want = letoh16(want) + sizeof(l2cap_hdr_t) - got; + + if (want > 0) + return; + + link->hl_rxp = NULL; + + if (want == 0) { + l2cap_recv_frame(m, link); + return; + } + +bad: + m_freem(m); +} + +/* + * Send ACL data on link + * + * We must fragment packets into chunks of less than unit->hci_max_acl_size and + * prepend a relevant ACL header to each fragment. We keep a PDU structure + * attached to the link, so that completed fragments can be marked off and + * more data requested from above once the PDU is sent. + */ +int +hci_acl_send(struct mbuf *m, struct hci_link *link, + struct l2cap_channel *chan) +{ + struct l2cap_pdu *pdu; + struct mbuf *n = NULL; + int plen, mlen, num = 0; + + KASSERT(link != NULL); + KASSERT(m != NULL); + KASSERT(m->m_flags & M_PKTHDR); + KASSERT(m->m_pkthdr.len > 0); + + if (link->hl_state == HCI_LINK_CLOSED) { + m_freem(m); + return ENETDOWN; + } + + pdu = pool_get(&l2cap_pdu_pool, PR_NOWAIT); + if (pdu == NULL) + goto nomem; + + pdu->lp_chan = chan; + pdu->lp_pending = 0; + + plen = m->m_pkthdr.len; + 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); + + while (plen > 0) { + if (plen > mlen) { + n = m_split(m, mlen, M_DONTWAIT); + if (n == NULL) + goto nomem; + } else { + mlen = plen; + } + + if (num++ == 0) + m->m_flags |= M_PROTO1; /* tag first fragment */ + + DPRINTFN(10, "chunk of %d (plen = %d) bytes\n", mlen, plen); + IF_ENQUEUE(&pdu->lp_data, m); + m = n; + plen -= mlen; + } + + TAILQ_INSERT_TAIL(&link->hl_txq, pdu, lp_next); + link->hl_txqlen += num; + + hci_acl_start(link); + + return 0; + +nomem: + if (m) m_freem(m); + if (pdu) { + IF_PURGE(&pdu->lp_data); + pool_put(&l2cap_pdu_pool, pdu); + } + + return ENOMEM; +} + +/* + * Start sending ACL data on link. + * + * This is called when the queue may need restarting: as new data + * is queued, after link mode changes have completed, or when device + * buffers have cleared. + * + * We may use all the available packet slots. The reason that we add + * the ACL encapsulation here rather than in hci_acl_send() is that L2CAP + * signal packets may be queued before the handle is given to us.. + */ +void +hci_acl_start(struct hci_link *link) +{ + struct hci_unit *unit; + hci_acldata_hdr_t *hdr; + struct l2cap_pdu *pdu; + struct mbuf *m; + uint16_t handle; + + KASSERT(link != NULL); + + unit = link->hl_unit; + KASSERT(unit != NULL); + + /* this is mainly to block ourselves (below) */ + if (link->hl_state != HCI_LINK_OPEN) + return; + + if (link->hl_txqlen == 0 || unit->hci_num_acl_pkts == 0) + return; + + /* find first PDU with data to send */ + pdu = TAILQ_FIRST(&link->hl_txq); + for (;;) { + if (pdu == NULL) + return; + + if (!IF_IS_EMPTY(&pdu->lp_data)) + break; + + pdu = TAILQ_NEXT(pdu, lp_next); + } + + while (unit->hci_num_acl_pkts > 0) { + IF_DEQUEUE(&pdu->lp_data, m); + KASSERT(m != NULL); + + if (m->m_flags & M_PROTO1) + handle = HCI_MK_CON_HANDLE(link->hl_handle, + HCI_PACKET_START, 0); + else + handle = HCI_MK_CON_HANDLE(link->hl_handle, + HCI_PACKET_FRAGMENT, 0); + + M_PREPEND(m, sizeof(*hdr), M_DONTWAIT); + if (m == NULL) + break; + + hdr = mtod(m, hci_acldata_hdr_t *); + hdr->type = HCI_ACL_DATA_PKT; + hdr->con_handle = htole16(handle); + hdr->length = htole16(m->m_pkthdr.len - sizeof(*hdr)); + + link->hl_txqlen--; + pdu->lp_pending++; + + hci_output_acl(unit, m); + + if (IF_IS_EMPTY(&pdu->lp_data)) { + if (pdu->lp_chan) { + /* + * This should enable streaming of PDUs - when + * we have placed all the fragments on the acl + * output queue, we trigger the L2CAP layer to + * send us down one more. Use a false state so + * we dont run into ourselves coming back from + * the future.. + */ + link->hl_state = HCI_LINK_BLOCK; + l2cap_start(pdu->lp_chan); + link->hl_state = HCI_LINK_OPEN; + } + + pdu = TAILQ_NEXT(pdu, lp_next); + if (pdu == NULL) + break; + } + } + + /* + * We had our turn now, move to the back of the queue to let + * other links have a go at the output buffers.. + */ + if (TAILQ_NEXT(link, hl_next)) { + TAILQ_REMOVE(&unit->hci_links, link, hl_next); + TAILQ_INSERT_TAIL(&unit->hci_links, link, hl_next); + } +} + +/* + * Confirm ACL packets cleared from Controller buffers. We scan our PDU + * list to clear pending fragments and signal upstream for more data + * when a PDU is complete. + */ +void +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); + + while (num > 0) { + pdu = TAILQ_FIRST(&link->hl_txq); + if (pdu == NULL) { + printf("%s: %d packets completed on handle #%x " + "but none pending!\n", + link->hl_unit->hci_devname, num, + link->hl_handle); + return; + } + + if (num >= pdu->lp_pending) { + num -= pdu->lp_pending; + pdu->lp_pending = 0; + + if (IF_IS_EMPTY(&pdu->lp_data)) { + TAILQ_REMOVE(&link->hl_txq, pdu, lp_next); + chan = pdu->lp_chan; + if (chan != NULL) { + chan->lc_pending--; + (*chan->lc_proto->complete) + (chan->lc_upper, 1); + + if (chan->lc_pending == 0) + l2cap_start(chan); + } + + pool_put(&l2cap_pdu_pool, pdu); + } + } else { + pdu->lp_pending -= num; + num = 0; + } + } +} + +/******************************************************************************* + * + * HCI SCO Connections + */ + +/* + * Incoming SCO Connection. We check the list for anybody willing + * to take it. + */ +struct hci_link * +hci_sco_newconn(struct hci_unit *unit, bdaddr_t *bdaddr) +{ +#ifdef notyet /* XXX */ + struct sockaddr_bt laddr, raddr; + struct sco_pcb *pcb, *new; + struct hci_link *sco, *acl; + + memset(&laddr, 0, sizeof(laddr)); + laddr.bt_len = sizeof(laddr); + laddr.bt_family = AF_BLUETOOTH; + bdaddr_copy(&laddr.bt_bdaddr, &unit->hci_bdaddr); + + memset(&raddr, 0, sizeof(raddr)); + raddr.bt_len = sizeof(raddr); + raddr.bt_family = AF_BLUETOOTH; + bdaddr_copy(&raddr.bt_bdaddr, bdaddr); + + /* + * There should already be an ACL link up and running before + * the controller sends us SCO connection requests, but you + * never know.. + */ + acl = hci_link_lookup_bdaddr(unit, bdaddr, HCI_LINK_ACL); + if (acl == NULL || acl->hl_state != HCI_LINK_OPEN) + return NULL; + + LIST_FOREACH(pcb, &sco_pcb, sp_next) { + if ((pcb->sp_flags & SP_LISTENING) == 0) + continue; + + new = (*pcb->sp_proto->newconn)(pcb->sp_upper, &laddr, &raddr); + if (new == NULL) + continue; + + /* + * Ok, got new pcb so we can start a new link and fill + * in all the details. + */ + bdaddr_copy(&new->sp_laddr, &unit->hci_bdaddr); + bdaddr_copy(&new->sp_raddr, bdaddr); + + sco = hci_link_alloc(unit); + if (sco == NULL) { + sco_detach(&new); + return NULL; + } + + sco->hl_type = HCI_LINK_SCO; + bdaddr_copy(&sco->hl_bdaddr, bdaddr); + + sco->hl_link = hci_acl_open(unit, bdaddr); + KASSERT(sco->hl_link == acl); + + sco->hl_sco = new; + new->sp_link = sco; + + new->sp_mtu = unit->hci_max_sco_size; + return sco; + } +#endif + + return NULL; +} + +/* + * receive SCO packet, we only need to strip the header and send + * it to the right handler + */ +void +hci_sco_recv(struct mbuf *m, struct hci_unit *unit) +{ + struct hci_link *link; + hci_scodata_hdr_t hdr; + uint16_t handle; + + KASSERT(m != NULL); + KASSERT(unit != NULL); + + KASSERT(m->m_pkthdr.len >= sizeof(hdr)); + m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr); + m_adj(m, sizeof(hdr)); + +#ifdef DIAGNOSTIC + if (hdr.type != HCI_SCO_DATA_PKT) { + printf("%s: bad SCO packet type\n", unit->hci_devname); + goto bad; + } + + if (m->m_pkthdr.len != hdr.length) { + printf("%s: bad SCO packet length (%d != %d)\n", unit->hci_devname, m->m_pkthdr.len, hdr.length); + goto bad; + } +#endif + + hdr.con_handle = letoh16(hdr.con_handle); + handle = HCI_CON_HANDLE(hdr.con_handle); + + 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); + + goto bad; + } + + (*link->hl_sco->sp_proto->input)(link->hl_sco->sp_upper, m); + return; + +bad: + m_freem(m); +} + +void +hci_sco_start(struct hci_link *link) +{ +} + +/* + * SCO packets have completed at the controller, so we can + * signal up to free the buffer space. + */ +void +hci_sco_complete(struct hci_link *link, int num) +{ + + DPRINTFN(5, "handle #%d (num=%d)\n", link->hl_handle, num); + link->hl_sco->sp_pending--; + (*link->hl_sco->sp_proto->complete)(link->hl_sco->sp_upper, num); +} + +/******************************************************************************* + * + * Generic HCI Connection alloc/free/lookup etc + */ + +struct hci_link * +hci_link_alloc(struct hci_unit *unit) +{ + struct hci_link *link; + + KASSERT(unit != NULL); + + link = malloc(sizeof *link, M_BLUETOOTH, M_NOWAIT); + if (link == NULL) + return NULL; + bzero(link, sizeof *link); + + link->hl_unit = unit; + link->hl_state = HCI_LINK_CLOSED; + + /* init ACL portion */ + timeout_set(&link->hl_expire, hci_acl_timeout, link); + + TAILQ_INIT(&link->hl_txq); /* outgoing packets */ + TAILQ_INIT(&link->hl_reqs); /* request queue */ + + link->hl_mtu = L2CAP_MTU_DEFAULT; /* L2CAP signal mtu */ + link->hl_flush = L2CAP_FLUSH_TIMO_DEFAULT; /* flush timeout */ + + /* attach to unit */ + TAILQ_INSERT_HEAD(&unit->hci_links, link, hl_next); + return link; +} + +void +hci_link_free(struct hci_link *link, int err) +{ + struct l2cap_req *req; + struct l2cap_pdu *pdu; + struct l2cap_channel *chan, *next; + + KASSERT(link != NULL); + + DPRINTF("#%d, type = %d, state = %d, refcnt = %d\n", + link->hl_handle, link->hl_type, + link->hl_state, link->hl_refcnt); + + /* ACL reference count */ + if (link->hl_refcnt > 0) { + next = LIST_FIRST(&l2cap_active_list); + while ((chan = next) != NULL) { + next = LIST_NEXT(chan, lc_ncid); + if (chan->lc_link == link) + l2cap_close(chan, err); + } + } + KASSERT(link->hl_refcnt == 0); + + /* ACL L2CAP requests.. */ + while ((req = TAILQ_FIRST(&link->hl_reqs)) != NULL) + l2cap_request_free(req); + + KASSERT(TAILQ_EMPTY(&link->hl_reqs)); + + /* ACL outgoing data queue */ + while ((pdu = TAILQ_FIRST(&link->hl_txq)) != NULL) { + TAILQ_REMOVE(&link->hl_txq, pdu, lp_next); + IF_PURGE(&pdu->lp_data); + if (pdu->lp_pending) + link->hl_unit->hci_num_acl_pkts += pdu->lp_pending; + + pool_put(&l2cap_pdu_pool, pdu); + } + + KASSERT(TAILQ_EMPTY(&link->hl_txq)); + + /* ACL incoming data packet */ + if (link->hl_rxp != NULL) { + m_freem(link->hl_rxp); + link->hl_rxp = NULL; + } + + /* SCO master ACL link */ + if (link->hl_link != NULL) { + hci_acl_close(link->hl_link, err); + link->hl_link = NULL; + } + + /* SCO pcb */ + if (link->hl_sco != NULL) { + struct sco_pcb *pcb; + + pcb = link->hl_sco; + pcb->sp_link = NULL; + link->hl_sco = NULL; + (*pcb->sp_proto->disconnected)(pcb->sp_upper, err); + } + + /* flush any SCO data */ + IF_PURGE(&link->hl_data); + + /* + * Halt the timeout - if its already running we cannot free the + * link structure but the timeout function will call us back in + * any case. + */ + link->hl_state = HCI_LINK_CLOSED; + timeout_del(&link->hl_expire); + if (timeout_triggered(&link->hl_expire)) + return; + + TAILQ_REMOVE(&link->hl_unit->hci_links, link, hl_next); + free(link, M_BLUETOOTH); +} + +/* + * Lookup HCI link by address and type. Note that for SCO links there may + * be more than one link per address, so we only return links with no + * handle (ie new links) + */ +struct hci_link * +hci_link_lookup_bdaddr(struct hci_unit *unit, bdaddr_t *bdaddr, uint16_t type) +{ + struct hci_link *link; + + KASSERT(unit != NULL); + KASSERT(bdaddr != NULL); + + TAILQ_FOREACH(link, &unit->hci_links, hl_next) { + if (link->hl_type != type) + continue; + + if (type == HCI_LINK_SCO && link->hl_handle != 0) + continue; + + if (bdaddr_same(&link->hl_bdaddr, bdaddr)) + break; + } + + return link; +} + +struct hci_link * +hci_link_lookup_handle(struct hci_unit *unit, uint16_t handle) +{ + struct hci_link *link; + + KASSERT(unit != NULL); + + TAILQ_FOREACH(link, &unit->hci_links, hl_next) { + if (handle == link->hl_handle) + break; + } + + return link; +} diff --git a/sys/netbt/hci_misc.c b/sys/netbt/hci_misc.c new file mode 100644 index 00000000000..dd5f3b10149 --- /dev/null +++ b/sys/netbt/hci_misc.c @@ -0,0 +1,148 @@ +/* $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 $ */ + +/*- + * Copyright (c) 2005 Iain Hibbert. + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/proc.h> +#include <sys/queue.h> +#include <sys/systm.h> + +#include <netbt/bluetooth.h> +#include <netbt/hci.h> + +/* + * cache Inquiry Responses for this number of seconds for routing + * purposes [sysctl] + */ +int hci_memo_expiry = 600; + +/* + * set 'src' address for routing to 'dest' + */ +int +hci_route_lookup(bdaddr_t *src, bdaddr_t *dest) +{ + struct hci_unit *unit; + struct hci_link *link; + struct hci_memo *memo; + + /* + * Walk the ACL connections, if we have a connection + * to 'dest' already then thats best.. + */ + TAILQ_FOREACH(unit, &hci_unit_list, hci_next) { + if ((unit->hci_flags & BTF_UP) == 0) + continue; + + TAILQ_FOREACH(link, &unit->hci_links, hl_next) { + if (link->hl_type != HCI_LINK_ACL) + continue; + + if (bdaddr_same(&link->hl_bdaddr, dest)) + goto found; + } + } + + /* + * Now check all the memos to see if there has been an + * inquiry repsonse.. + */ + TAILQ_FOREACH(unit, &hci_unit_list, hci_next) { + if ((unit->hci_flags & BTF_UP) == 0) + continue; + + memo = hci_memo_find(unit, dest); + if (memo) + goto found; + } + + /* + * Last ditch effort, lets use the first unit we find + * thats up and running. (XXX settable default route?) + */ + TAILQ_FOREACH(unit, &hci_unit_list, hci_next) { + if ((unit->hci_flags & BTF_UP) == 0) + continue; + + goto found; + } + + return EHOSTUNREACH; + +found: + bdaddr_copy(src, &unit->hci_bdaddr); + return 0; +} + +/* + * find unit memo from bdaddr + */ +struct hci_memo * +hci_memo_find(struct hci_unit *unit, bdaddr_t *bdaddr) +{ + struct hci_memo *memo, *m0; + struct timeval now; + + microtime(&now); + + m0 = LIST_FIRST(&unit->hci_memos); + while ((memo = m0) != NULL) { + m0 = LIST_NEXT(memo, next); + + if (now.tv_sec > memo->time.tv_sec + hci_memo_expiry) { + DPRINTF("memo %p too old (expiring)\n", memo); + hci_memo_free(memo); + continue; + } + + if (bdaddr_same(bdaddr, &memo->response.bdaddr)) { + DPRINTF("memo %p found\n", memo); + return memo; + } + } + + DPRINTF("no memo found\n"); + return NULL; +} + +void +hci_memo_free(struct hci_memo *memo) +{ + + LIST_REMOVE(memo, next); + free(memo, M_BLUETOOTH); +} diff --git a/sys/netbt/hci_raw.c b/sys/netbt/hci_raw.c deleted file mode 100644 index 2f3e52b1681..00000000000 --- a/sys/netbt/hci_raw.c +++ /dev/null @@ -1,1750 +0,0 @@ -/* $OpenBSD: hci_raw.c,v 1.5 2007/05/26 17:13:31 jason Exp $ */ - -/* - * ng_btsocket_hci_raw.c - * - * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD: src/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c,v 1.16 2004/10/18 22:19:42 rwatson Exp $ - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/domain.h> -#include <sys/endian.h> -#include <sys/errno.h> -#include <sys/filedesc.h> -#include <sys/ioccom.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/mutex.h> -#include <sys/protosw.h> -#include <sys/queue.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/sysctl.h> - -#include <net/if.h> -#include <net/if_types.h> -#include <net/netisr.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> -#include <netbt/l2cap.h> -#include <netbt/bt.h> -#include <netbt/hci_var.h> - -#if 0 -/* Netgraph node methods */ -static ng_constructor_t ng_btsocket_hci_raw_node_constructor; -static ng_rcvmsg_t ng_btsocket_hci_raw_node_rcvmsg; -static ng_shutdown_t ng_btsocket_hci_raw_node_shutdown; -static ng_newhook_t ng_btsocket_hci_raw_node_newhook; -static ng_connect_t ng_btsocket_hci_raw_node_connect; -static ng_rcvdata_t ng_btsocket_hci_raw_node_rcvdata; -static ng_disconnect_t ng_btsocket_hci_raw_node_disconnect; -#endif - -void ng_btsocket_hci_raw_output(void *, int); -void ng_btsocket_hci_raw_savctl(ng_btsocket_hci_raw_pcb_p, - struct mbuf **, - struct mbuf *); -int ng_btsocket_hci_raw_filter(ng_btsocket_hci_raw_pcb_p, - struct mbuf *, int); - -int ng_btsocket_hci_raw_send_ngmsg(char *, int, void *, int); -int ng_btsocket_hci_raw_send_sync_ngmsg(ng_btsocket_hci_raw_pcb_p, char *, - int, void *, int); - -#define ng_btsocket_hci_raw_wakeup_input_task() \ - taskqueue_enqueue(taskqueue_swi_giant, &ng_btsocket_hci_raw_task) - -/* Security filter */ -struct ng_btsocket_hci_raw_sec_filter { - bitstr_t bit_decl(events, 0xff); - bitstr_t bit_decl(commands[0x3f], 0x3ff); -}; - -#if 0 -/* Netgraph type descriptor */ -static struct ng_type typestruct = { - .version = NG_ABI_VERSION, - .name = NG_BTSOCKET_HCI_RAW_NODE_TYPE, - .constructor = ng_btsocket_hci_raw_node_constructor, - .rcvmsg = ng_btsocket_hci_raw_node_rcvmsg, - .shutdown = ng_btsocket_hci_raw_node_shutdown, - .newhook = ng_btsocket_hci_raw_node_newhook, - .connect = ng_btsocket_hci_raw_node_connect, - .rcvdata = ng_btsocket_hci_raw_node_rcvdata, - .disconnect = ng_btsocket_hci_raw_node_disconnect, -}; -#endif - -/* Globals */ -static u_int32_t ng_btsocket_hci_raw_debug_level; -static u_int32_t ng_btsocket_hci_raw_ioctl_timeout; -#if 0 -static node_p ng_btsocket_hci_raw_node; -#endif -static struct ng_bt_itemq ng_btsocket_hci_raw_queue; -#if 0 -static struct mtx ng_btsocket_hci_raw_queue_mtx; -static struct task ng_btsocket_hci_raw_task; -#endif -static LIST_HEAD(, ng_btsocket_hci_raw_pcb) ng_btsocket_hci_raw_sockets; -#if 0 -static struct mtx ng_btsocket_hci_raw_sockets_mtx; -#endif -static u_int32_t ng_btsocket_hci_raw_token; -#if 0 -static struct mtx ng_btsocket_hci_raw_token_mtx; -#endif -static struct ng_btsocket_hci_raw_sec_filter *ng_btsocket_hci_raw_sec_filter; - -extern struct ifqueue btintrq; - -/* Debug */ -#define NG_BTSOCKET_HCI_RAW_INFO \ - if (ng_btsocket_hci_raw_debug_level >= NG_BTSOCKET_INFO_LEVEL) \ - printf - -#define NG_BTSOCKET_HCI_RAW_WARN \ - if (ng_btsocket_hci_raw_debug_level >= NG_BTSOCKET_WARN_LEVEL) \ - printf - -#define NG_BTSOCKET_HCI_RAW_ERR \ - if (ng_btsocket_hci_raw_debug_level >= NG_BTSOCKET_ERR_LEVEL) \ - printf - -#define NG_BTSOCKET_HCI_RAW_ALERT \ - if (ng_btsocket_hci_raw_debug_level >= NG_BTSOCKET_ALERT_LEVEL) \ - printf - -#if 0 -/**************************************************************************** - **************************************************************************** - ** Netgraph specific - **************************************************************************** - ****************************************************************************/ - -/* - * Netgraph node constructor. Do not allow to create node of this type. - */ - -int -ng_btsocket_hci_raw_node_constructor(node_p node) -{ - return (EINVAL); -} /* ng_btsocket_hci_raw_node_constructor */ - -/* - * Netgraph node destructor. Just let old node go and create new fresh one. - */ - -int -ng_btsocket_hci_raw_node_shutdown(node_p node) -{ - int error = 0; - - NG_NODE_UNREF(node); - - error = ng_make_node_common(&typestruct, &ng_btsocket_hci_raw_node); - if (error != 0) { - NG_BTSOCKET_HCI_RAW_ALERT( -"%s: Could not create Netgraph node, error=%d\n", __func__, error); - - ng_btsocket_hci_raw_node = NULL; - - return (ENOMEM); - } - - error = ng_name_node(ng_btsocket_hci_raw_node, - NG_BTSOCKET_HCI_RAW_NODE_TYPE); - if (error != 0) { - NG_BTSOCKET_HCI_RAW_ALERT( -"%s: Could not name Netgraph node, error=%d\n", __func__, error); - - NG_NODE_UNREF(ng_btsocket_hci_raw_node); - ng_btsocket_hci_raw_node = NULL; - - return (EINVAL); - } - - return (0); -} /* ng_btsocket_hci_raw_node_shutdown */ - -/* - * Create new hook. Just say "yes" - */ - -int -ng_btsocket_hci_raw_node_newhook(node_p node, hook_p hook, char const *name) -{ - return (0); -} /* ng_btsocket_hci_raw_node_newhook */ - -/* - * Connect hook. Just say "yes" - */ - -int -ng_btsocket_hci_raw_node_connect(hook_p hook) -{ - return (0); -} /* ng_btsocket_hci_raw_node_connect */ - -/* - * Disconnect hook - */ - -int -ng_btsocket_hci_raw_node_disconnect(hook_p hook) -{ - return (0); -} /* ng_btsocket_hci_raw_node_disconnect */ - -/* - * Receive control message. - * Make sure it is a message from HCI node and it is a response. - * Enqueue item and schedule input task. - */ - -int -ng_btsocket_hci_raw_node_rcvmsg(node_p node, item_p item, hook_p lasthook) -{ - struct ng_mesg *msg = NGI_MSG(item); /* item still has message */ - int empty, error = 0; - - mtx_lock(&ng_btsocket_hci_raw_sockets_mtx); - empty = LIST_EMPTY(&ng_btsocket_hci_raw_sockets); - mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx); - - if (empty) { - NG_FREE_ITEM(item); - return (0); - } - - if (msg != NULL && - msg->header.typecookie == NGM_HCI_COOKIE && - msg->header.flags & NGF_RESP) { - if (msg->header.token == 0) { - NG_FREE_ITEM(item); - return (0); - } - - mtx_lock(&ng_btsocket_hci_raw_queue_mtx); - if (NG_BT_ITEMQ_FULL(&ng_btsocket_hci_raw_queue)) { - NG_BTSOCKET_HCI_RAW_ERR( -"%s: Input queue is full\n", __func__); - - NG_BT_ITEMQ_DROP(&ng_btsocket_hci_raw_queue); - NG_FREE_ITEM(item); - error = ENOBUFS; - } else { - NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_hci_raw_queue, item); - error = ng_btsocket_hci_raw_wakeup_input_task(); - } - mtx_unlock(&ng_btsocket_hci_raw_queue_mtx); - } else { - NG_FREE_ITEM(item); - error = EINVAL; - } - - return (error); -} /* ng_btsocket_hci_raw_node_rcvmsg */ -#endif - -/* - * Receive packet from the one of our hook. - * Prepend every packet with sockaddr_hci and record sender's node name. - * Enqueue item and schedule input task. - */ - -int -ng_btsocket_hci_raw_node_rcvdata(struct ifnet *ifp, struct mbuf *m) -{ - struct mbuf *nam = NULL; - int empty, error; - int s; - - mtx_lock(&ng_btsocket_hci_raw_sockets_mtx); - empty = LIST_EMPTY(&ng_btsocket_hci_raw_sockets); - mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx); - - if (empty) { -#if 0 - NG_FREE_ITEM(item); -#endif - return (0); - } - - MGET(nam, M_DONTWAIT, MT_SONAME); - if (nam != NULL) { - struct sockaddr_hci *sa = mtod(nam, struct sockaddr_hci *); - - nam->m_len = sizeof(struct sockaddr_hci); - - sa->hci_len = sizeof(*sa); - sa->hci_family = AF_BLUETOOTH; -#if 0 - strlcpy(sa->hci_node, NG_PEER_NODE_NAME(hook), - sizeof(sa->hci_node)); -#endif - strlcpy(sa->hci_node, ifp->if_xname, sizeof(sa->hci_node)); - -#if 0 - NGI_GET_M(item, nam->m_next); - NGI_M(item) = nam; -#endif - nam->m_next = m; - - mtx_lock(&ng_btsocket_hci_raw_queue_mtx); - if (NG_BT_ITEMQ_FULL(&ng_btsocket_hci_raw_queue)) { - NG_BTSOCKET_HCI_RAW_ERR( -"%s: Input queue is full\n", __func__); - - NG_BT_ITEMQ_DROP(&ng_btsocket_hci_raw_queue); -#if 0 - NG_FREE_ITEM(item); -#endif - error = ENOBUFS; - } else { -#if 0 - NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_hci_raw_queue, item); - error = ng_btsocket_hci_raw_wakeup_input_task(); -#endif - s = splnet(); - IF_INPUT_ENQUEUE(&btintrq, nam); - splx(s); - schednetisr(NETISR_BT); - } - mtx_unlock(&ng_btsocket_hci_raw_queue_mtx); - } else { - NG_BTSOCKET_HCI_RAW_ERR( -"%s: Failed to allocate address mbuf\n", __func__); - -#if 0 - NG_FREE_ITEM(item); -#endif - error = ENOBUFS; - } - - return (error); -} /* ng_btsocket_hci_raw_node_rcvdata */ - -/**************************************************************************** - **************************************************************************** - ** Sockets specific - **************************************************************************** - ****************************************************************************/ - -/* - * Get next token. We need token to avoid theoretical race where process - * submits ioctl() message then interrupts ioctl() and re-submits another - * ioctl() on the same socket *before* first ioctl() complete. - */ - -#if 0 -void -ng_btsocket_hci_raw_get_token(u_int32_t *token) -{ - mtx_lock(&ng_btsocket_hci_raw_token_mtx); - - if (++ ng_btsocket_hci_raw_token == 0) - ng_btsocket_hci_raw_token = 1; - - *token = ng_btsocket_hci_raw_token; - - mtx_unlock(&ng_btsocket_hci_raw_token_mtx); -} /* ng_btsocket_hci_raw_get_token */ -#endif - -/* - * Send Netgraph message to the node - do not expect reply - */ - -int -ng_btsocket_hci_raw_send_ngmsg(char *path, int cmd, void *arg, int arglen) -{ -#if 0 - struct ng_mesg *msg = NULL; - int error = 0; - - NG_MKMESSAGE(msg, NGM_HCI_COOKIE, cmd, arglen, M_NOWAIT); - if (msg == NULL) - return (ENOMEM); - - if (arg != NULL && arglen > 0) - bcopy(arg, msg->data, arglen); - - NG_SEND_MSG_PATH(error, ng_btsocket_hci_raw_node, msg, path, 0); - - return (error); -#endif - return (0); -} /* ng_btsocket_hci_raw_send_ngmsg */ - -/* - * Send Netgraph message to the node (no data) and wait for reply - */ - -int -ng_btsocket_hci_raw_send_sync_ngmsg(ng_btsocket_hci_raw_pcb_p pcb, char *path, - int cmd, void *rsp, int rsplen) -{ -#if 0 - struct ng_mesg *msg = NULL; - int error = 0; - - mtx_assert(&pcb->pcb_mtx, MA_OWNED); - - NG_MKMESSAGE(msg, NGM_HCI_COOKIE, cmd, 0, M_NOWAIT); - if (msg == NULL) - return (ENOMEM); - - ng_btsocket_hci_raw_get_token(&msg->header.token); - pcb->token = msg->header.token; - pcb->msg = NULL; - - NG_SEND_MSG_PATH(error, ng_btsocket_hci_raw_node, msg, path, 0); - if (error != 0) { - pcb->token = 0; - return (error); - } - - error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "hcictl", - ng_btsocket_hci_raw_ioctl_timeout * hz); - pcb->token = 0; - - if (error != 0) - return (error); - - if (pcb->msg != NULL && pcb->msg->header.cmd == cmd) - bcopy(pcb->msg->data, rsp, rsplen); - else - error = EINVAL; - - NG_FREE_MSG(pcb->msg); /* checks for != NULL */ -#endif - - return (0); -} /* ng_btsocket_hci_raw_send_sync_ngmsg */ - -/* - * Create control information for the packet - */ - -void -ng_btsocket_hci_raw_savctl(ng_btsocket_hci_raw_pcb_p pcb, struct mbuf **ctl, - struct mbuf *m) -{ - int dir; -#if 0 - struct timeval tv; -#endif - - mtx_assert(&pcb->pcb_mtx, MA_OWNED); - - if (pcb->flags & NG_BTSOCKET_HCI_RAW_DIRECTION) { - dir = (m->m_flags & M_PROTO1)? 1 : 0; - *ctl = sbcreatecontrol((caddr_t) &dir, sizeof(dir), - SCM_HCI_RAW_DIRECTION, SOL_HCI_RAW); - if (*ctl != NULL) - ctl = &((*ctl)->m_next); - } - -#if 0 - if (pcb->so->so_options & SO_TIMESTAMP) { - microtime(&tv); - *ctl = sbcreatecontrol((caddr_t) &tv, sizeof(tv), - SCM_TIMESTAMP, SOL_SOCKET); - if (*ctl != NULL) - ctl = &((*ctl)->m_next); - } -#endif -} /* ng_btsocket_hci_raw_savctl */ - -/* - * Raw HCI sockets data input routine - */ - -void -ng_btsocket_hci_raw_data_input(struct mbuf *nam) -{ - ng_btsocket_hci_raw_pcb_p pcb = NULL; - struct mbuf *m0 = NULL, *m = NULL; - struct sockaddr_hci *sa = NULL; - - m0 = nam->m_next; - nam->m_next = NULL; - - KASSERT((nam->m_type == MT_SONAME), - ("%s: m_type=%d\n", __func__, nam->m_type)); - KASSERT((m0->m_flags & M_PKTHDR), - ("%s: m_flags=%#x\n", __func__, m0->m_flags)); - - sa = mtod(nam, struct sockaddr_hci *); - - mtx_lock(&ng_btsocket_hci_raw_sockets_mtx); - - LIST_FOREACH(pcb, &ng_btsocket_hci_raw_sockets, next) { - - mtx_lock(&pcb->pcb_mtx); - - /* - * If socket was bound then check address and - * make sure it matches. - */ - - if (pcb->addr.hci_node[0] != 0 && - strcmp(sa->hci_node, pcb->addr.hci_node) != 0) - goto next; - - /* - * Check packet against filters - * XXX do we have to call m_pullup() here? - */ - -#if 0 - if (ng_btsocket_hci_raw_filter(pcb, m0, 1) != 0) - goto next; -#endif - - /* - * Make a copy of the packet, append to the socket's - * receive queue and wakeup socket. sbappendaddr() - * will check if socket has enough buffer space. - */ - -#if 0 - m = m_dup(m0, M_DONTWAIT); -#endif - m = m_copym2(m0, 0, M_COPYALL, M_DONTWAIT); - if (m != NULL) { - struct mbuf *ctl = NULL; - - ng_btsocket_hci_raw_savctl(pcb, &ctl, m); - - if (sbappendaddr(&pcb->so->so_rcv, - (struct sockaddr *) sa, m, ctl)) { - sorwakeup(pcb->so); - } else { - NG_BTSOCKET_HCI_RAW_INFO( -"%s: sbappendaddr() failed\n", __func__); - - NG_FREE_M(m); - NG_FREE_M(ctl); - } - } -next: - mtx_unlock(&pcb->pcb_mtx); - } - - mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx); - - NG_FREE_M(nam); - NG_FREE_M(m0); -} /* ng_btsocket_hci_raw_data_input */ - -#if 0 -/* - * Raw HCI sockets message input routine - */ - -void -ng_btsocket_hci_raw_msg_input(struct ng_mesg *msg) -{ - ng_btsocket_hci_raw_pcb_p pcb = NULL; - - mtx_lock(&ng_btsocket_hci_raw_sockets_mtx); - - LIST_FOREACH(pcb, &ng_btsocket_hci_raw_sockets, next) { - mtx_lock(&pcb->pcb_mtx); - - if (msg->header.token == pcb->token) { - pcb->msg = msg; - wakeup(&pcb->msg); - - mtx_unlock(&pcb->pcb_mtx); - mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx); - - return; - } - - mtx_unlock(&pcb->pcb_mtx); - } - - mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx); - -#if 0 - NG_FREE_MSG(msg); /* checks for != NULL */ -#endif -} /* ng_btsocket_hci_raw_msg_input */ -#endif - -#if 0 -/* - * Raw HCI sockets input routines - */ - -void -ng_btsocket_hci_raw_input(void *context, int pending) -{ - item_p item = NULL; - - for (;;) { - mtx_lock(&ng_btsocket_hci_raw_queue_mtx); - NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_hci_raw_queue, item); - mtx_unlock(&ng_btsocket_hci_raw_queue_mtx); - - if (item == NULL) - break; - - switch(item->el_flags & NGQF_TYPE) { - case NGQF_DATA: { - struct mbuf *m = NULL; - - NGI_GET_M(item, m); - ng_btsocket_hci_raw_data_input(m); - } break; - - case NGQF_MESG: { - struct ng_mesg *msg = NULL; - - NGI_GET_MSG(item, msg); - ng_btsocket_hci_raw_msg_input(msg); - } break; - - default: - KASSERT(0, -("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE))); - break; - } - - NG_FREE_ITEM(item); - } -} /* ng_btsocket_hci_raw_input */ -#endif - -/* - * Raw HCI sockets output routine - */ - -void -ng_btsocket_hci_raw_output(void *arg1, int arg2) -{ - struct mbuf *nam = (struct mbuf *) arg1, *m = NULL; - struct sockaddr_hci *sa = NULL; - struct ifnet *ifp; - int error; - int s; - - m = nam->m_next; - nam->m_next = NULL; - - KASSERT((nam->m_type == MT_SONAME), - ("%s: m_type=%d\n", __func__, nam->m_type)); - KASSERT((m->m_flags & M_PKTHDR), - ("%s: m_flags=%#x\n", __func__, m->m_flags)); - - sa = mtod(nam, struct sockaddr_hci *); - - /* - * Find downstream hook - * XXX For now access node hook list directly. Should be safe because - * we used ng_send_fn() and we should have exclusive lock on the node. - */ - -#if 0 - LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) { - if (hook == NULL || NG_HOOK_NOT_VALID(hook) || - NG_NODE_NOT_VALID(NG_PEER_NODE(hook))) - continue; - - if (strcmp(sa->hci_node, NG_PEER_NODE_NAME(hook)) == 0) { - NG_SEND_DATA_ONLY(error, hook, m); /* sets m to NULL */ - break; - } - } -#endif - TAILQ_FOREACH(ifp, &ifnet, if_list) { - if (ifp->if_type != IFT_BLUETOOTH) - continue; - - if (strcmp(sa->hci_node, ifp->if_xname) == 0) { - s = splnet(); - IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error); - if (error) { - splx(s); - return; - } - if ((ifp->if_flags & IFF_OACTIVE) == 0) - (*ifp->if_start)(ifp); - splx(s); - break; - } - } - - NG_FREE_M(nam); /* check for != NULL */ -#if 0 - NG_FREE_M(m); -#endif -} /* ng_btsocket_hci_raw_output */ - -/* - * Check frame against security and socket filters. - * d (direction bit) == 1 means incoming frame. - */ - -int -ng_btsocket_hci_raw_filter(ng_btsocket_hci_raw_pcb_p pcb, struct mbuf *m, int d) -{ - int type, event, opcode; - - mtx_assert(&pcb->pcb_mtx, MA_OWNED); - - switch ((type = *mtod(m, u_int8_t *))) { - case NG_HCI_CMD_PKT: - if (!(pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)) { - opcode = letoh16(mtod(m, ng_hci_cmd_pkt_t *)->opcode); - - if (!bit_test( -ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF(opcode) - 1], -NG_HCI_OCF(opcode) - 1)) - return (EPERM); - } - - if (d && !bit_test(pcb->filter.packet_mask, NG_HCI_CMD_PKT - 1)) - return (EPERM); - break; - - case NG_HCI_ACL_DATA_PKT: - case NG_HCI_SCO_DATA_PKT: - if (!(pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED) || - !bit_test(pcb->filter.packet_mask, type - 1) || - !d) - return (EPERM); - break; - - case NG_HCI_EVENT_PKT: - if (!d) - return (EINVAL); - - event = mtod(m, ng_hci_event_pkt_t *)->event - 1; - - if (!(pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)) - if (!bit_test(ng_btsocket_hci_raw_sec_filter->events, event)) - return (EPERM); - - if (!bit_test(pcb->filter.event_mask, event)) - return (EPERM); - break; - - default: - return (EINVAL); - } - - return (0); -} /* ng_btsocket_hci_raw_filter */ - -/* - * Initialize everything - */ - -void -hci_raw_init(void) -{ - bitstr_t *f = NULL; -#if 0 - int error = 0; -#endif - -#if 0 - ng_btsocket_hci_raw_node = NULL; -#endif - ng_btsocket_hci_raw_debug_level = NG_BTSOCKET_WARN_LEVEL; - ng_btsocket_hci_raw_ioctl_timeout = 5; - -#if 0 - /* Register Netgraph node type */ - error = ng_newtype(&typestruct); - if (error != 0) { - NG_BTSOCKET_HCI_RAW_ALERT( -"%s: Could not register Netgraph node type, error=%d\n", __func__, error); - - return; - } - - /* Create Netgrapg node */ - error = ng_make_node_common(&typestruct, &ng_btsocket_hci_raw_node); - if (error != 0) { - NG_BTSOCKET_HCI_RAW_ALERT( -"%s: Could not create Netgraph node, error=%d\n", __func__, error); - - ng_btsocket_hci_raw_node = NULL; - - return; - } - - error = ng_name_node(ng_btsocket_hci_raw_node, - NG_BTSOCKET_HCI_RAW_NODE_TYPE); - if (error != 0) { - NG_BTSOCKET_HCI_RAW_ALERT( -"%s: Could not name Netgraph node, error=%d\n", __func__, error); - - NG_NODE_UNREF(ng_btsocket_hci_raw_node); - ng_btsocket_hci_raw_node = NULL; - - return; - } -#endif - - /* Create input queue */ - NG_BT_ITEMQ_INIT(&ng_btsocket_hci_raw_queue, ifqmaxlen); - mtx_init(&ng_btsocket_hci_raw_queue_mtx, - "btsocks_hci_raw_queue_mtx", NULL, MTX_DEF); -#if 0 - TASK_INIT(&ng_btsocket_hci_raw_task, 0, - ng_btsocket_hci_raw_input, NULL); -#endif - - /* Create list of sockets */ - LIST_INIT(&ng_btsocket_hci_raw_sockets); - mtx_init(&ng_btsocket_hci_raw_sockets_mtx, - "btsocks_hci_raw_sockets_mtx", NULL, MTX_DEF); - - /* Tokens */ - ng_btsocket_hci_raw_token = 0; - mtx_init(&ng_btsocket_hci_raw_token_mtx, - "btsocks_hci_raw_token_mtx", NULL, MTX_DEF); - - /* - * Security filter - * XXX never FREE()ed - */ - - ng_btsocket_hci_raw_sec_filter = NULL; - - MALLOC(ng_btsocket_hci_raw_sec_filter, - struct ng_btsocket_hci_raw_sec_filter *, - sizeof(struct ng_btsocket_hci_raw_sec_filter), - M_BLUETOOTH, M_NOWAIT); - if (ng_btsocket_hci_raw_sec_filter == NULL) { - printf("%s: Could not allocate security filter!\n", __func__); - return; - } - bzero(ng_btsocket_hci_raw_sec_filter, - sizeof(struct ng_btsocket_hci_raw_sec_filter)); - - /* - * XXX How paranoid can we get? - * - * Initialize security filter. If bit is set in the mask then - * unprivileged socket is allowed to send (receive) this command - * (event). - */ - - /* Enable all events */ - memset(&ng_btsocket_hci_raw_sec_filter->events, 0xff, - sizeof(ng_btsocket_hci_raw_sec_filter->events)/ - sizeof(ng_btsocket_hci_raw_sec_filter->events[0])); - - /* Disable some critical events */ - f = ng_btsocket_hci_raw_sec_filter->events; - bit_clear(f, NG_HCI_EVENT_RETURN_LINK_KEYS - 1); - bit_clear(f, NG_HCI_EVENT_LINK_KEY_NOTIFICATION - 1); - bit_clear(f, NG_HCI_EVENT_VENDOR - 1); - - /* Commands - Link control */ - f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_LINK_CONTROL-1]; - bit_set(f, NG_HCI_OCF_INQUIRY - 1); - bit_set(f, NG_HCI_OCF_INQUIRY_CANCEL - 1); - bit_set(f, NG_HCI_OCF_PERIODIC_INQUIRY - 1); - bit_set(f, NG_HCI_OCF_EXIT_PERIODIC_INQUIRY - 1); - bit_set(f, NG_HCI_OCF_REMOTE_NAME_REQ - 1); - bit_set(f, NG_HCI_OCF_READ_REMOTE_FEATURES - 1); - bit_set(f, NG_HCI_OCF_READ_REMOTE_VER_INFO - 1); - bit_set(f, NG_HCI_OCF_READ_CLOCK_OFFSET - 1); - - /* Commands - Link policy */ - f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_LINK_POLICY-1]; - bit_set(f, NG_HCI_OCF_ROLE_DISCOVERY - 1); - bit_set(f, NG_HCI_OCF_READ_LINK_POLICY_SETTINGS - 1); - - /* Commands - Host controller and baseband */ - f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_HC_BASEBAND-1]; - bit_set(f, NG_HCI_OCF_READ_PIN_TYPE - 1); - bit_set(f, NG_HCI_OCF_READ_LOCAL_NAME - 1); - bit_set(f, NG_HCI_OCF_READ_CON_ACCEPT_TIMO - 1); - bit_set(f, NG_HCI_OCF_READ_PAGE_TIMO - 1); - bit_set(f, NG_HCI_OCF_READ_SCAN_ENABLE - 1); - bit_set(f, NG_HCI_OCF_READ_PAGE_SCAN_ACTIVITY - 1); - bit_set(f, NG_HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY - 1); - bit_set(f, NG_HCI_OCF_READ_AUTH_ENABLE - 1); - bit_set(f, NG_HCI_OCF_READ_ENCRYPTION_MODE - 1); - bit_set(f, NG_HCI_OCF_READ_UNIT_CLASS - 1); - bit_set(f, NG_HCI_OCF_READ_VOICE_SETTINGS - 1); - bit_set(f, NG_HCI_OCF_READ_AUTO_FLUSH_TIMO - 1); - bit_set(f, NG_HCI_OCF_READ_NUM_BROADCAST_RETRANS - 1); - bit_set(f, NG_HCI_OCF_READ_HOLD_MODE_ACTIVITY - 1); - bit_set(f, NG_HCI_OCF_READ_XMIT_LEVEL - 1); - bit_set(f, NG_HCI_OCF_READ_SCO_FLOW_CONTROL - 1); - bit_set(f, NG_HCI_OCF_READ_LINK_SUPERVISION_TIMO - 1); - bit_set(f, NG_HCI_OCF_READ_SUPPORTED_IAC_NUM - 1); - bit_set(f, NG_HCI_OCF_READ_IAC_LAP - 1); - bit_set(f, NG_HCI_OCF_READ_PAGE_SCAN_PERIOD - 1); - bit_set(f, NG_HCI_OCF_READ_PAGE_SCAN - 1); - - /* Commands - Informational */ - f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_INFO - 1]; - bit_set(f, NG_HCI_OCF_READ_LOCAL_VER - 1); - bit_set(f, NG_HCI_OCF_READ_LOCAL_FEATURES - 1); - bit_set(f, NG_HCI_OCF_READ_BUFFER_SIZE - 1); - bit_set(f, NG_HCI_OCF_READ_COUNTRY_CODE - 1); - bit_set(f, NG_HCI_OCF_READ_BDADDR - 1); - - /* Commands - Status */ - f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_STATUS - 1]; - bit_set(f, NG_HCI_OCF_READ_FAILED_CONTACT_CNTR - 1); - bit_set(f, NG_HCI_OCF_GET_LINK_QUALITY - 1); - bit_set(f, NG_HCI_OCF_READ_RSSI - 1); - - /* Commands - Testing */ - f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_TESTING - 1]; - bit_set(f, NG_HCI_OCF_READ_LOOPBACK_MODE - 1); -} /* ng_btsocket_hci_raw_init */ - -/* - * Abort connection on socket - */ - -int -ng_btsocket_hci_raw_abort(struct socket *so) -{ - return (ng_btsocket_hci_raw_detach(so)); -} /* ng_btsocket_hci_raw_abort */ - -/* - * Create new raw HCI socket - */ - -int -ng_btsocket_hci_raw_attach(struct socket *so, int proto, struct proc *p) -{ - ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so); - int error = 0; - - if (pcb != NULL) - return (EISCONN); - -#if 0 - if (ng_btsocket_hci_raw_node == NULL) - return (EPROTONOSUPPORT); -#endif - if (proto != BLUETOOTH_PROTO_HCI) - return (EPROTONOSUPPORT); - if (so->so_type != SOCK_RAW) - return (ESOCKTNOSUPPORT); - - error = soreserve(so, NG_BTSOCKET_HCI_RAW_SENDSPACE, - NG_BTSOCKET_HCI_RAW_RECVSPACE); - if (error != 0) - return (error); - - MALLOC(pcb, ng_btsocket_hci_raw_pcb_p, sizeof(*pcb), - M_BLUETOOTH, M_NOWAIT); - if (pcb == NULL) - return (ENOMEM); - bzero(pcb, sizeof(*pcb)); - - so->so_pcb = (caddr_t) pcb; - pcb->so = so; - - if (suser(p, 0) == 0) - pcb->flags |= NG_BTSOCKET_HCI_RAW_PRIVILEGED; - - /* - * Set default socket filter. By default socket only accepts HCI - * Command_Complete and Command_Status event packets. - */ - - bit_set(pcb->filter.event_mask, NG_HCI_EVENT_COMMAND_COMPL - 1); - bit_set(pcb->filter.event_mask, NG_HCI_EVENT_COMMAND_STATUS - 1); - - mtx_init(&pcb->pcb_mtx, "btsocks_hci_raw_pcb_mtx", NULL, MTX_DEF); - - mtx_lock(&ng_btsocket_hci_raw_sockets_mtx); - LIST_INSERT_HEAD(&ng_btsocket_hci_raw_sockets, pcb, next); - mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx); - - return (0); -} /* ng_btsocket_hci_raw_attach */ - -/* - * Bind raw HCI socket - */ - -int -ng_btsocket_hci_raw_bind(struct socket *so, struct sockaddr *nam, - struct proc *p) -{ - ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so); - struct sockaddr_hci *sa = (struct sockaddr_hci *) nam; - - if (pcb == NULL) - return (EINVAL); -#if 0 - if (ng_btsocket_hci_raw_node == NULL) - return (EINVAL); -#endif - - if (sa == NULL) - return (EINVAL); - if (sa->hci_family != AF_BLUETOOTH) - return (EAFNOSUPPORT); - if (sa->hci_len != sizeof(*sa)) - return (EINVAL); - if (sa->hci_node[0] == 0) - return (EINVAL); - - bcopy(sa, &pcb->addr, sizeof(pcb->addr)); - - return (0); -} /* ng_btsocket_hci_raw_bind */ - -/* - * Connect raw HCI socket - */ - -int -ng_btsocket_hci_raw_connect(struct socket *so, struct sockaddr *nam, - struct proc *p) -{ - ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so); - struct sockaddr_hci *sa = (struct sockaddr_hci *) nam; - - if (pcb == NULL) - return (EINVAL); -#if 0 - if (ng_btsocket_hci_raw_node == NULL) - return (EINVAL); -#endif - - if (sa == NULL) - return (EINVAL); - if (sa->hci_family != AF_BLUETOOTH) - return (EAFNOSUPPORT); - if (sa->hci_len != sizeof(*sa)) - return (EINVAL); - if (sa->hci_node[0] == 0) - return (EDESTADDRREQ); - if (bcmp(sa, &pcb->addr, sizeof(pcb->addr)) != 0) - return (EADDRNOTAVAIL); - - soisconnected(so); - - return (0); -} /* ng_btsocket_hci_raw_connect */ - -/* - * Process ioctl on socket - */ - -int -ng_btsocket_hci_raw_control(struct socket *so, u_long cmd, caddr_t data, - struct ifnet *ifp, struct proc *p) -{ - ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so); - char path[256]; -#if 0 - struct ng_mesg *msg = NULL; -#endif - int error = 0; - - if (pcb == NULL) - return (EINVAL); -#if 0 - if (ng_btsocket_hci_raw_node == NULL) - return (EINVAL); -#endif - - mtx_lock(&pcb->pcb_mtx); - - /* Check if we have device name */ - if (pcb->addr.hci_node[0] == 0) { - mtx_unlock(&pcb->pcb_mtx); - return (EHOSTUNREACH); - } - - /* Check if we have pending ioctl() */ - if (pcb->token != 0) { - mtx_unlock(&pcb->pcb_mtx); - return (EBUSY); - } - - snprintf(path, sizeof(path), "%s:", pcb->addr.hci_node); - - switch (cmd) { - case SIOC_HCI_RAW_NODE_GET_STATE: { - struct ng_btsocket_hci_raw_node_state *p = - (struct ng_btsocket_hci_raw_node_state *) data; - - error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path, - NGM_HCI_NODE_GET_STATE, - &p->state, sizeof(p->state)); - } break; - - case SIOC_HCI_RAW_NODE_INIT: - if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED) - error = ng_btsocket_hci_raw_send_ngmsg(path, - NGM_HCI_NODE_INIT, NULL, 0); - else - error = EPERM; - break; - - case SIOC_HCI_RAW_NODE_GET_DEBUG: { - struct ng_btsocket_hci_raw_node_debug *p = - (struct ng_btsocket_hci_raw_node_debug *) data; - - error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path, - NGM_HCI_NODE_GET_DEBUG, - &p->debug, sizeof(p->debug)); - } break; - - case SIOC_HCI_RAW_NODE_SET_DEBUG: { - struct ng_btsocket_hci_raw_node_debug *p = - (struct ng_btsocket_hci_raw_node_debug *) data; - - if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED) - error = ng_btsocket_hci_raw_send_ngmsg(path, - NGM_HCI_NODE_SET_DEBUG, &p->debug, - sizeof(p->debug)); - else - error = EPERM; - } break; - - case SIOC_HCI_RAW_NODE_GET_BUFFER: { - struct ng_btsocket_hci_raw_node_buffer *p = - (struct ng_btsocket_hci_raw_node_buffer *) data; - - error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path, - NGM_HCI_NODE_GET_BUFFER, - &p->buffer, sizeof(p->buffer)); - } break; - - case SIOC_HCI_RAW_NODE_GET_BDADDR: { - struct ng_btsocket_hci_raw_node_bdaddr *p = - (struct ng_btsocket_hci_raw_node_bdaddr *) data; - - error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path, - NGM_HCI_NODE_GET_BDADDR, - &p->bdaddr, sizeof(p->bdaddr)); - } break; - - case SIOC_HCI_RAW_NODE_GET_FEATURES: { - struct ng_btsocket_hci_raw_node_features *p = - (struct ng_btsocket_hci_raw_node_features *) data; - - error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path, - NGM_HCI_NODE_GET_FEATURES, - &p->features, sizeof(p->features)); - } break; - - case SIOC_HCI_RAW_NODE_GET_STAT: { - struct ng_btsocket_hci_raw_node_stat *p = - (struct ng_btsocket_hci_raw_node_stat *) data; - - error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path, - NGM_HCI_NODE_GET_STAT, - &p->stat, sizeof(p->stat)); - } break; - - case SIOC_HCI_RAW_NODE_RESET_STAT: - if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED) - error = ng_btsocket_hci_raw_send_ngmsg(path, - NGM_HCI_NODE_RESET_STAT, NULL, 0); - else - error = EPERM; - break; - - case SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE: - if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED) - error = ng_btsocket_hci_raw_send_ngmsg(path, - NGM_HCI_NODE_FLUSH_NEIGHBOR_CACHE, - NULL, 0); - else - error = EPERM; - break; - - case SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE: { - struct ng_btsocket_hci_raw_node_neighbor_cache *p = - (struct ng_btsocket_hci_raw_node_neighbor_cache *) data; -#if 0 - ng_hci_node_get_neighbor_cache_ep *p1 = NULL; - ng_hci_node_neighbor_cache_entry_ep *p2 = NULL; -#endif - - if (p->num_entries <= 0 || - p->num_entries > NG_HCI_MAX_NEIGHBOR_NUM || - p->entries == NULL) { - error = EINVAL; - break; - } - -#if 0 - NG_MKMESSAGE(msg, NGM_HCI_COOKIE, - NGM_HCI_NODE_GET_NEIGHBOR_CACHE, 0, M_NOWAIT); - if (msg == NULL) { - error = ENOMEM; - break; - } - ng_btsocket_hci_raw_get_token(&msg->header.token); - pcb->token = msg->header.token; - pcb->msg = NULL; - - NG_SEND_MSG_PATH(error, ng_btsocket_hci_raw_node, msg, path, 0); - if (error != 0) { - pcb->token = 0; - break; - } -#endif - - error = tsleep(&pcb->msg, - PZERO|PCATCH, "hcictl", - ng_btsocket_hci_raw_ioctl_timeout * hz); - pcb->token = 0; - - if (error != 0) - break; - -#if 0 - if (pcb->msg != NULL && - pcb->msg->header.cmd == NGM_HCI_NODE_GET_NEIGHBOR_CACHE) { - /* Return data back to user space */ - p1 = (ng_hci_node_get_neighbor_cache_ep *) - (pcb->msg->data); - p2 = (ng_hci_node_neighbor_cache_entry_ep *) - (p1 + 1); - - p->num_entries = min(p->num_entries, p1->num_entries); - if (p->num_entries > 0) - error = copyout((caddr_t) p2, - (caddr_t) p->entries, - p->num_entries * sizeof(*p2)); - } else - error = EINVAL; -#endif - -#if 0 - NG_FREE_MSG(pcb->msg); /* checks for != NULL */ -#endif - }break; - - case SIOC_HCI_RAW_NODE_GET_CON_LIST: { - struct ng_btsocket_hci_raw_con_list *p = - (struct ng_btsocket_hci_raw_con_list *) data; -#if 0 - ng_hci_node_con_list_ep *p1 = NULL; - ng_hci_node_con_ep *p2 = NULL; -#endif - - if (p->num_connections == 0 || - p->num_connections > NG_HCI_MAX_CON_NUM || - p->connections == NULL) { - error = EINVAL; - break; - } - -#if 0 - NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_NODE_GET_CON_LIST, - 0, M_NOWAIT); - if (msg == NULL) { - error = ENOMEM; - break; - } - ng_btsocket_hci_raw_get_token(&msg->header.token); - pcb->token = msg->header.token; - pcb->msg = NULL; - - NG_SEND_MSG_PATH(error, ng_btsocket_hci_raw_node, msg, path, 0); - if (error != 0) { - pcb->token = 0; - break; - } -#endif - - error = tsleep(&pcb->msg, - PZERO|PCATCH, "hcictl", - ng_btsocket_hci_raw_ioctl_timeout * hz); - pcb->token = 0; - - if (error != 0) - break; - -#if 0 - if (pcb->msg != NULL && - pcb->msg->header.cmd == NGM_HCI_NODE_GET_CON_LIST) { - /* Return data back to user space */ - p1 = (ng_hci_node_con_list_ep *)(pcb->msg->data); - p2 = (ng_hci_node_con_ep *)(p1 + 1); - - p->num_connections = min(p->num_connections, - p1->num_connections); - if (p->num_connections > 0) - error = copyout((caddr_t) p2, - (caddr_t) p->connections, - p->num_connections * sizeof(*p2)); - } else - error = EINVAL; -#endif - -#if 0 - NG_FREE_MSG(pcb->msg); /* checks for != NULL */ -#endif - } break; - - case SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK: { - struct ng_btsocket_hci_raw_node_link_policy_mask *p = - (struct ng_btsocket_hci_raw_node_link_policy_mask *) - data; - - error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path, - NGM_HCI_NODE_GET_LINK_POLICY_SETTINGS_MASK, - &p->policy_mask, sizeof(p->policy_mask)); - } break; - - case SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK: { - struct ng_btsocket_hci_raw_node_link_policy_mask *p = - (struct ng_btsocket_hci_raw_node_link_policy_mask *) - data; - - if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED) - error = ng_btsocket_hci_raw_send_ngmsg(path, - NGM_HCI_NODE_SET_LINK_POLICY_SETTINGS_MASK, - &p->policy_mask, - sizeof(p->policy_mask)); - else - error = EPERM; - } break; - - case SIOC_HCI_RAW_NODE_GET_PACKET_MASK: { - struct ng_btsocket_hci_raw_node_packet_mask *p = - (struct ng_btsocket_hci_raw_node_packet_mask *) data; - - error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path, - NGM_HCI_NODE_GET_PACKET_MASK, - &p->packet_mask, sizeof(p->packet_mask)); - } break; - - case SIOC_HCI_RAW_NODE_SET_PACKET_MASK: { - struct ng_btsocket_hci_raw_node_packet_mask *p = - (struct ng_btsocket_hci_raw_node_packet_mask *) data; - - if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED) - error = ng_btsocket_hci_raw_send_ngmsg(path, - NGM_HCI_NODE_SET_PACKET_MASK, - &p->packet_mask, - sizeof(p->packet_mask)); - else - error = EPERM; - } break; - - case SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH: { - struct ng_btsocket_hci_raw_node_role_switch *p = - (struct ng_btsocket_hci_raw_node_role_switch *) data; - - error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path, - NGM_HCI_NODE_GET_ROLE_SWITCH, - &p->role_switch, sizeof(p->role_switch)); - } break; - - case SIOC_HCI_RAW_NODE_SET_ROLE_SWITCH: { - struct ng_btsocket_hci_raw_node_role_switch *p = - (struct ng_btsocket_hci_raw_node_role_switch *) data; - - if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED) - error = ng_btsocket_hci_raw_send_ngmsg(path, - NGM_HCI_NODE_SET_ROLE_SWITCH, - &p->role_switch, - sizeof(p->role_switch)); - else - error = EPERM; - } break; - - default: - error = EINVAL; - break; - } - - mtx_unlock(&pcb->pcb_mtx); - - return (error); -} /* ng_btsocket_hci_raw_control */ - -/* - * Process getsockopt/setsockopt system calls - */ - -int -hci_raw_ctloutput(int op, struct socket *so, int level, - int optname, struct mbuf **m) -{ - ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so); - struct ng_btsocket_hci_raw_filter filter; - int error = 0, dir; - size_t len; - - if (pcb == NULL) - return (EINVAL); -#if 0 - if (ng_btsocket_hci_raw_node == NULL) - return (EINVAL); -#endif - - if (level != SOL_HCI_RAW) - return (0); - - mtx_lock(&pcb->pcb_mtx); - - switch (op) { - case PRCO_GETOPT: - switch (optname) { - case SO_HCI_RAW_FILTER: - len = min((*m)->m_len, sizeof(pcb->filter)); - bcopy(&pcb->filter, mtod(*m, void *), len); - break; - - case SO_HCI_RAW_DIRECTION: - len = min((*m)->m_len, sizeof(dir)); - dir = (pcb->flags & NG_BTSOCKET_HCI_RAW_DIRECTION)?1:0; - bcopy(&dir, mtod(*m, void *), len); - break; - - default: - error = EINVAL; - break; - } - break; - - case PRCO_SETOPT: - switch (optname) { - case SO_HCI_RAW_FILTER: - len = min((*m)->m_len, sizeof(pcb->filter)); - bcopy(&filter, &pcb->filter, len); - break; - - case SO_HCI_RAW_DIRECTION: - len = min((*m)->m_len, sizeof(dir)); - bcopy(mtod(*m, void *), &dir, len); - - if (dir) - pcb->flags |= NG_BTSOCKET_HCI_RAW_DIRECTION; - else - pcb->flags &= ~NG_BTSOCKET_HCI_RAW_DIRECTION; - break; - - default: - error = EINVAL; - break; - } - break; - - default: - error = EINVAL; - break; - } - - mtx_unlock(&pcb->pcb_mtx); - - return (error); -} /* ng_btsocket_hci_raw_ctloutput */ - -/* - * Detach raw HCI socket - */ - -int -ng_btsocket_hci_raw_detach(struct socket *so) -{ - ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so); - - if (pcb == NULL) - return (EINVAL); -#if 0 - if (ng_btsocket_hci_raw_node == NULL) - return (EINVAL); -#endif - - mtx_lock(&ng_btsocket_hci_raw_sockets_mtx); - mtx_lock(&pcb->pcb_mtx); - - LIST_REMOVE(pcb, next); - - mtx_unlock(&pcb->pcb_mtx); - mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx); - - mtx_destroy(&pcb->pcb_mtx); - - bzero(pcb, sizeof(*pcb)); - FREE(pcb, M_BLUETOOTH); - - ACCEPT_LOCK(); - SOCK_LOCK(so); - so->so_pcb = NULL; - sofree(so); - - return (0); -} /* ng_btsocket_hci_raw_detach */ - -/* - * Disconnect raw HCI socket - */ - -int -ng_btsocket_hci_raw_disconnect(struct socket *so) -{ - ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so); - - if (pcb == NULL) - return (EINVAL); -#if 0 - if (ng_btsocket_hci_raw_node == NULL) - return (EINVAL); -#endif - - soisdisconnected(so); - - return (0); -} /* ng_btsocket_hci_raw_disconnect */ - -/* - * Get socket peer's address - */ - -int -ng_btsocket_hci_raw_peeraddr(struct socket *so, struct sockaddr **nam) -{ - return (ng_btsocket_hci_raw_sockaddr(so, nam)); -} /* ng_btsocket_hci_raw_peeraddr */ - -/* - * Send data - */ - -int -ng_btsocket_hci_raw_send(struct socket *so, int flags, struct mbuf *m, - struct sockaddr *sa, struct mbuf *control, struct proc *p) -{ - ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so); - struct mbuf *nam = NULL; - int error = 0; - -#if 0 - if (ng_btsocket_hci_raw_node == NULL) { - error = ENETDOWN; - goto drop; - } -#endif - if (pcb == NULL) { - error = EINVAL; - goto drop; - } - if (control != NULL) { - error = EINVAL; - goto drop; - } - - if (m->m_pkthdr.len < sizeof(ng_hci_cmd_pkt_t) || - m->m_pkthdr.len > sizeof(ng_hci_cmd_pkt_t) + NG_HCI_CMD_PKT_SIZE) { - error = EMSGSIZE; - goto drop; - } - - if (m->m_len < sizeof(ng_hci_cmd_pkt_t)) { - if ((m = m_pullup(m, sizeof(ng_hci_cmd_pkt_t))) == NULL) { - error = ENOBUFS; - goto drop; - } - } - if (*mtod(m, u_int8_t *) != NG_HCI_CMD_PKT) { - error = EOPNOTSUPP; - goto drop; - } - - mtx_lock(&pcb->pcb_mtx); - - error = ng_btsocket_hci_raw_filter(pcb, m, 0); - if (error != 0) { - mtx_unlock(&pcb->pcb_mtx); - goto drop; - } - - if (sa == NULL) { - if (pcb->addr.hci_node[0] == 0) { - mtx_unlock(&pcb->pcb_mtx); - error = EDESTADDRREQ; - goto drop; - } - - sa = (struct sockaddr *) &pcb->addr; - } - - MGET(nam, M_DONTWAIT, MT_SONAME); - if (nam == NULL) { - mtx_unlock(&pcb->pcb_mtx); - error = ENOBUFS; - goto drop; - } - - nam->m_len = sizeof(struct sockaddr_hci); - bcopy(sa,mtod(nam, struct sockaddr_hci *),sizeof(struct sockaddr_hci)); - - nam->m_next = m; - m = NULL; - - mtx_unlock(&pcb->pcb_mtx); - -#if 0 - return (ng_send_fn(ng_btsocket_hci_raw_node, NULL, - ng_btsocket_hci_raw_output, nam, 0)); -#endif - ng_btsocket_hci_raw_output(nam, 0); - return (0); - -drop: - NG_FREE_M(control); /* NG_FREE_M checks for != NULL */ - NG_FREE_M(nam); - NG_FREE_M(m); - - return (error); -} /* ng_btsocket_hci_raw_send */ - -/* - * Get socket address - */ - -int -ng_btsocket_hci_raw_sockaddr(struct socket *so, struct sockaddr **nam) -{ - ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so); - struct sockaddr_hci sa; - - if (pcb == NULL) - return (EINVAL); -#if 0 - if (ng_btsocket_hci_raw_node == NULL) - return (EINVAL); -#endif - - bzero(&sa, sizeof(sa)); - sa.hci_len = sizeof(sa); - sa.hci_family = AF_BLUETOOTH; - strlcpy(sa.hci_node, pcb->addr.hci_node, sizeof(sa.hci_node)); - -#if 0 - *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); -#endif - - return ((*nam == NULL)? ENOMEM : 0); -} /* ng_btsocket_hci_raw_sockaddr */ - -int -hci_raw_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, - struct mbuf *control) -{ - ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so); - struct sockaddr *sa; - int error = 0; - - /* XXX: restrict AF_BLUETOOTH sockets to root for now */ - if ((error = suser(curproc, 0)) != 0) - return (error); - - if (req == PRU_CONTROL) - return (ng_btsocket_hci_raw_control(so, (u_long)m, - (caddr_t)nam, (struct ifnet *)control, curproc)); - - if (pcb == NULL && req != PRU_ATTACH) { - error = EINVAL; - goto release; - } - - switch (req) { - case PRU_ATTACH: - return (ng_btsocket_hci_raw_attach(so, - so->so_proto->pr_protocol, curproc)); - case PRU_DISCONNECT: - if ((so->so_state & SS_ISCONNECTED) == 0) { - error = ENOTCONN; - break; - } - /* FALLTHROUGH */ - case PRU_ABORT: - soisdisconnected(so); - /* FALLTHROUGH */ - case PRU_DETACH: - return (ng_btsocket_hci_raw_detach(so)); - case PRU_BIND: - sa = mtod(nam, struct sockaddr *); - return (ng_btsocket_hci_raw_bind(so, sa, curproc)); - case PRU_CONNECT: - sa = mtod(nam, struct sockaddr *); - return (ng_btsocket_hci_raw_connect(so, sa, curproc)); - case PRU_CONNECT2: - error = EOPNOTSUPP; - break; - case PRU_SHUTDOWN: - socantsendmore(so); - break; - case PRU_SEND: - sa = nam != NULL ? mtod(nam, struct sockaddr *) : NULL; - return (ng_btsocket_hci_raw_send(so, 0, m, sa, control, - curproc)); - case PRU_SENSE: - return (0); - case PRU_RCVOOB: - case PRU_RCVD: - case PRU_LISTEN: - case PRU_ACCEPT: - case PRU_SENDOOB: - error = EOPNOTSUPP; - break; - case PRU_SOCKADDR: - sa = mtod(nam, struct sockaddr *); - return (ng_btsocket_hci_raw_sockaddr(so, &sa)); - case PRU_PEERADDR: - sa = mtod(nam, struct sockaddr *); - return (ng_btsocket_hci_raw_peeraddr(so, &sa)); - default: - panic("hci_raw_usrreq: unexpected request %d", req); - } - -release: - if (m != NULL) - m_freem(m); - return (error); -} diff --git a/sys/netbt/hci_socket.c b/sys/netbt/hci_socket.c new file mode 100644 index 00000000000..a74a8b62ef4 --- /dev/null +++ b/sys/netbt/hci_socket.c @@ -0,0 +1,721 @@ +/* $OpenBSD: hci_socket.c,v 1.1 2007/05/30 03:42:53 uwe Exp $ */ +/* $NetBSD: hci_socket.c,v 1.10 2007/03/31 18:17:13 plunky Exp $ */ + +/*- + * Copyright (c) 2005 Iain Hibbert. + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +/* load symbolic names */ +#ifdef BLUETOOTH_DEBUG +#define PRUREQUESTS +#define PRCOREQUESTS +#endif + +#include <sys/param.h> +#include <sys/domain.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/proc.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/systm.h> + +#include <netbt/bluetooth.h> +#include <netbt/hci.h> + +/******************************************************************************* + * + * HCI SOCK_RAW Sockets - for control of Bluetooth Devices + * + */ + +/* + * the raw HCI protocol control block + */ +struct hci_pcb { + struct socket *hp_socket; /* socket */ + unsigned int hp_flags; /* flags */ + bdaddr_t hp_laddr; /* local address */ + bdaddr_t hp_raddr; /* remote address */ + struct hci_filter hp_efilter; /* user event filter */ + struct hci_filter hp_pfilter; /* user packet filter */ + LIST_ENTRY(hci_pcb) hp_next; /* next HCI pcb */ +}; + +/* hp_flags */ +#define HCI_PRIVILEGED (1<<0) /* no security filter for root */ +#define HCI_DIRECTION (1<<1) /* direction control messages */ +#define HCI_PROMISCUOUS (1<<2) /* listen to all units */ + +LIST_HEAD(hci_pcb_list, hci_pcb) hci_pcb = LIST_HEAD_INITIALIZER(hci_pcb); + +/* sysctl defaults */ +int hci_sendspace = HCI_CMD_PKT_SIZE; +int hci_recvspace = 4096; + +/* + * Security filter routines for unprivileged users. + * Allow all but a few critical events, and only permit read commands. + */ + +static int +hci_security_check_opcode(uint16_t opcode) +{ + + 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 */ + } + + return -1; /* disallowed */ +} + +static int +hci_security_check_event(uint8_t event) +{ + + switch (event) { + case HCI_EVENT_RETURN_LINK_KEYS: + case HCI_EVENT_LINK_KEY_NOTIFICATION: + case HCI_EVENT_VENDOR: + return -1; /* disallowed */ + } + + return 0; /* ok */ +} + +/* + * When command packet reaches the device, we can drop + * it from the socket buffer (called from hci_output_acl) + */ +void +hci_drop(void *arg) +{ + struct socket *so = arg; + + sbdroprecord(&so->so_snd); + sowwakeup(so); +} + +/* + * HCI socket is going away and has some pending packets. We let them + * go by design, but remove the context pointer as it will be invalid + * and we no longer need to be notified. + */ +static void +hci_cmdwait_flush(struct socket *so) +{ + struct hci_unit *unit; + //struct socket *ctx; + //struct mbuf *m; + + DPRINTF("flushing %p\n", so); + + TAILQ_FOREACH(unit, &hci_unit_list, hci_next) { +#ifdef notyet /* XXX */ + m = MBUFQ_FIRST(&unit->hci_cmdwait); + while (m != NULL) { + ctx = M_GETCTX(m, struct socket *); + if (ctx == so) + M_SETCTX(m, NULL); + + m = MBUFQ_NEXT(m); + } +#endif + } +} + +/* + * HCI send packet + * This came from userland, so check it out. + */ +static int +hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr) +{ + struct hci_unit *unit; + struct mbuf *m0; + hci_cmd_hdr_t hdr; + int err; + + KASSERT(m != NULL); + KASSERT(addr != NULL); + + /* wants at least a header to start with */ + if (m->m_pkthdr.len < sizeof(hdr)) { + err = EMSGSIZE; + goto bad; + } + m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr); + + /* only allows CMD packets to be sent */ + if (hdr.type != HCI_CMD_PKT) { + err = EINVAL; + goto bad; + } + + /* validates packet length */ + if (m->m_pkthdr.len != sizeof(hdr) + hdr.length) { + err = EMSGSIZE; + 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) { + err = ENETDOWN; + goto bad; + } + + /* makes a copy for precious to keep */ + m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT); + if (m0 == NULL) { + err = ENOMEM; + goto bad; + } + sbappendrecord(&pcb->hp_socket->so_snd, m0); +#ifdef notyet /* XXX */ + M_SETCTX(m, pcb->hp_socket); /* enable drop callback */ +#endif + + DPRINTFN(2, "(%s) opcode (%03x|%04x)\n", unit->hci_devname, + HCI_OGF(letoh16(hdr.opcode)), HCI_OCF(letoh16(hdr.opcode))); + + /* Sendss it */ + if (unit->hci_num_cmd_pkts == 0) + IF_ENQUEUE(&unit->hci_cmdwait, m); + else + hci_output_cmd(unit, m); + + return 0; + +bad: + DPRINTF("packet (%d bytes) not sent (error %d)\n", + m->m_pkthdr.len, err); + if (m) m_freem(m); + return err; +} + +/* + * User Request. + * up is socket + * m is either + * optional mbuf chain containing message + * ioctl command (PRU_CONTROL) + * nam is either + * optional mbuf chain containing an address + * ioctl data (PRU_CONTROL) + * optionally, protocol number (PRU_ATTACH) + * ctl is optional mbuf chain containing socket options + * l is pointer to process requesting action (if any) + * + * we are responsible for disposing of m and ctl if + * they are mbuf chains + */ +int +hci_usrreq(struct socket *up, int req, struct mbuf *m, + struct mbuf *nam, struct mbuf *ctl, struct proc *l) +{ + struct hci_pcb *pcb = (struct hci_pcb *)up->so_pcb; + struct sockaddr_bt *sa; + int err = 0; + +#ifdef notyet /* XXX */ + DPRINTFN(2, "%s\n", prurequests[req]); +#endif + + switch(req) { +#ifdef notyet /* XXX */ + case PRU_CONTROL: + return hci_ioctl((unsigned long)m, (void *)nam, l); +#endif + + case PRU_ATTACH: + if (pcb) + return EINVAL; + + err = soreserve(up, hci_sendspace, hci_recvspace); + if (err) + return err; + + pcb = malloc(sizeof *pcb, M_PCB, M_NOWAIT); + if (pcb == NULL) + return ENOMEM; + bzero(pcb, sizeof *pcb); + + up->so_pcb = pcb; + pcb->hp_socket = up; + +#ifdef notyet /* XXX */ + if (l == NULL || kauth_authorize_generic(l->l_cred, + KAUTH_GENERIC_ISSUSER, NULL) == 0) + pcb->hp_flags |= HCI_PRIVILEGED; +#endif + + /* + * Set default user filter. By default, socket only passes + * Command_Complete and Command_Status Events. + */ + hci_filter_set(HCI_EVENT_COMMAND_COMPL, &pcb->hp_efilter); + hci_filter_set(HCI_EVENT_COMMAND_STATUS, &pcb->hp_efilter); + hci_filter_set(HCI_EVENT_PKT, &pcb->hp_pfilter); + + LIST_INSERT_HEAD(&hci_pcb, pcb, hp_next); + + return 0; + } + + /* anything after here *requires* a pcb */ + if (pcb == NULL) { + err = EINVAL; + goto release; + } + + switch(req) { + case PRU_DISCONNECT: + bdaddr_copy(&pcb->hp_raddr, BDADDR_ANY); + + /* XXX we cannot call soisdisconnected() here, as it sets + * SS_CANTRCVMORE and SS_CANTSENDMORE. The problem being, + * that soisconnected() does not clear these and if you + * try to reconnect this socket (which is permitted) you + * get a broken pipe when you try to write any data. + */ + up->so_state &= ~SS_ISCONNECTED; + break; + + case PRU_ABORT: + soisdisconnected(up); + /* fall through to */ + case PRU_DETACH: + if (up->so_snd.sb_mb != NULL) + hci_cmdwait_flush(up); + + up->so_pcb = NULL; + LIST_REMOVE(pcb, hp_next); + free(pcb, M_PCB); + return 0; + + case PRU_BIND: + KASSERT(nam != NULL); + sa = mtod(nam, struct sockaddr_bt *); + + if (sa->bt_len != sizeof(struct sockaddr_bt)) + return EINVAL; + + if (sa->bt_family != AF_BLUETOOTH) + return EAFNOSUPPORT; + + bdaddr_copy(&pcb->hp_laddr, &sa->bt_bdaddr); + + if (bdaddr_any(&sa->bt_bdaddr)) + pcb->hp_flags |= HCI_PROMISCUOUS; + else + pcb->hp_flags &= ~HCI_PROMISCUOUS; + + return 0; + + case PRU_CONNECT: + KASSERT(nam != NULL); + sa = mtod(nam, struct sockaddr_bt *); + + if (sa->bt_len != sizeof(struct sockaddr_bt)) + return EINVAL; + + if (sa->bt_family != AF_BLUETOOTH) + return EAFNOSUPPORT; + + if (hci_unit_lookup(&sa->bt_bdaddr) == NULL) + return EADDRNOTAVAIL; + + bdaddr_copy(&pcb->hp_raddr, &sa->bt_bdaddr); + soisconnected(up); + return 0; + + case PRU_PEERADDR: + KASSERT(nam != NULL); + sa = mtod(nam, struct sockaddr_bt *); + + memset(sa, 0, sizeof(struct sockaddr_bt)); + nam->m_len = + sa->bt_len = sizeof(struct sockaddr_bt); + sa->bt_family = AF_BLUETOOTH; + bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_raddr); + return 0; + + case PRU_SOCKADDR: + KASSERT(nam != NULL); + sa = mtod(nam, struct sockaddr_bt *); + + memset(sa, 0, sizeof(struct sockaddr_bt)); + nam->m_len = + sa->bt_len = sizeof(struct sockaddr_bt); + sa->bt_family = AF_BLUETOOTH; + bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_laddr); + return 0; + + case PRU_SHUTDOWN: + socantsendmore(up); + break; + + case PRU_SEND: + sa = NULL; + if (nam) { + sa = mtod(nam, struct sockaddr_bt *); + + if (sa->bt_len != sizeof(struct sockaddr_bt)) { + err = EINVAL; + goto release; + } + + if (sa->bt_family != AF_BLUETOOTH) { + err = EAFNOSUPPORT; + goto release; + } + } + + if (ctl) /* have no use for this */ + m_freem(ctl); + + return hci_send(pcb, m, (sa ? &sa->bt_bdaddr : &pcb->hp_raddr)); + + case PRU_SENSE: + return 0; /* (no sense - Doh!) */ + + case PRU_RCVD: + case PRU_RCVOOB: + return EOPNOTSUPP; /* (no release) */ + + case PRU_ACCEPT: + case PRU_CONNECT2: + case PRU_LISTEN: + case PRU_SENDOOB: + case PRU_FASTTIMO: + case PRU_SLOWTIMO: + case PRU_PROTORCV: + case PRU_PROTOSEND: + err = EOPNOTSUPP; + break; + + default: + UNKNOWN(req); + err = EOPNOTSUPP; + break; + } + +release: + if (m) + m_freem(m); + if (ctl) + m_freem(ctl); + return err; +} + +/* + * get/set socket options + */ +int +hci_ctloutput(int req, struct socket *so, int level, + int optname, struct mbuf **opt) +{ + struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb; + struct mbuf *m; + int err = 0; + +#ifdef notyet /* XXX */ + DPRINTFN(2, "req %s\n", prcorequests[req]); +#endif + + if (pcb == NULL) + return EINVAL; + + if (level != BTPROTO_HCI) + return ENOPROTOOPT; + + switch(req) { + case PRCO_GETOPT: + m = m_get(M_WAIT, MT_SOOPTS); + switch (optname) { + case SO_HCI_EVT_FILTER: + m->m_len = sizeof(struct hci_filter); + memcpy(mtod(m, void *), &pcb->hp_efilter, m->m_len); + break; + + case SO_HCI_PKT_FILTER: + m->m_len = sizeof(struct hci_filter); + memcpy(mtod(m, void *), &pcb->hp_pfilter, m->m_len); + break; + + case SO_HCI_DIRECTION: + m->m_len = sizeof(int); + if (pcb->hp_flags & HCI_DIRECTION) + *mtod(m, int *) = 1; + else + *mtod(m, int *) = 0; + break; + + default: + err = ENOPROTOOPT; + m_freem(m); + m = NULL; + break; + } + *opt = m; + break; + + case PRCO_SETOPT: + m = *opt; + if (m) switch (optname) { + case SO_HCI_EVT_FILTER: /* set event filter */ + m->m_len = min(m->m_len, sizeof(struct hci_filter)); + memcpy(&pcb->hp_efilter, mtod(m, void *), m->m_len); + break; + + case SO_HCI_PKT_FILTER: /* set packet filter */ + m->m_len = min(m->m_len, sizeof(struct hci_filter)); + memcpy(&pcb->hp_pfilter, mtod(m, void *), m->m_len); + break; + + case SO_HCI_DIRECTION: /* request direction ctl messages */ + if (*mtod(m, int *)) + pcb->hp_flags |= HCI_DIRECTION; + else + pcb->hp_flags &= ~HCI_DIRECTION; + break; + + default: + err = ENOPROTOOPT; + break; + } + m_freem(m); + break; + + default: + err = ENOPROTOOPT; + break; + } + + return err; +} + +/* + * HCI mbuf tap routine + * + * copy packets to any raw HCI sockets that wish (and are + * permitted) to see them + */ +void +hci_mtap(struct mbuf *m, struct hci_unit *unit) +{ + struct hci_pcb *pcb; + struct mbuf *m0, *ctlmsg, **ctl; + struct sockaddr_bt sa; + uint8_t type; + uint8_t event; + uint16_t opcode; + + KASSERT(m->m_len >= sizeof(type)); + + type = *mtod(m, uint8_t *); + + memset(&sa, 0, sizeof(sa)); + sa.bt_len = sizeof(struct sockaddr_bt); + sa.bt_family = AF_BLUETOOTH; + bdaddr_copy(&sa.bt_bdaddr, &unit->hci_bdaddr); + + LIST_FOREACH(pcb, &hci_pcb, hp_next) { + /* + * filter according to source address + */ + if ((pcb->hp_flags & HCI_PROMISCUOUS) == 0 + && bdaddr_same(&pcb->hp_laddr, &sa.bt_bdaddr) == 0) + continue; + + /* + * filter according to packet type filter + */ + if (hci_filter_test(type, &pcb->hp_pfilter) == 0) + continue; + + /* + * filter according to event/security filters + */ + switch(type) { + case HCI_EVENT_PKT: + KASSERT(m->m_len >= sizeof(hci_event_hdr_t)); + + event = mtod(m, hci_event_hdr_t *)->event; + + if (hci_filter_test(event, &pcb->hp_efilter) == 0) + continue; + + if ((pcb->hp_flags & HCI_PRIVILEGED) == 0 + && hci_security_check_event(event) == -1) + continue; + break; + + case HCI_CMD_PKT: + KASSERT(m->m_len >= sizeof(hci_cmd_hdr_t)); + + opcode = letoh16(mtod(m, hci_cmd_hdr_t *)->opcode); + + if ((pcb->hp_flags & HCI_PRIVILEGED) == 0 + && hci_security_check_opcode(opcode) == -1) + continue; + break; + + case HCI_ACL_DATA_PKT: + case HCI_SCO_DATA_PKT: + default: + if ((pcb->hp_flags & HCI_PRIVILEGED) == 0) + continue; + + break; + } + + /* + * create control messages + */ + ctlmsg = NULL; + ctl = &ctlmsg; + if (pcb->hp_flags & HCI_DIRECTION) { + int dir = m->m_flags & M_LINK0 ? 1 : 0; + + *ctl = sbcreatecontrol((void *)&dir, sizeof(dir), + SCM_HCI_DIRECTION, BTPROTO_HCI); + + if (*ctl != NULL) + ctl = &((*ctl)->m_next); + } + + /* + * copy to socket + */ + m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT); + if (m0 && sbappendaddr(&pcb->hp_socket->so_rcv, + (struct sockaddr *)&sa, m0, ctlmsg)) { + sorwakeup(pcb->hp_socket); + } else { + m_freem(ctlmsg); + m_freem(m0); + } + } +} diff --git a/sys/netbt/hci_unit.c b/sys/netbt/hci_unit.c new file mode 100644 index 00000000000..e683db244a2 --- /dev/null +++ b/sys/netbt/hci_unit.c @@ -0,0 +1,529 @@ +/* $OpenBSD: hci_unit.c,v 1.1 2007/05/30 03:42:53 uwe Exp $ */ +/* $NetBSD: hci_unit.c,v 1.4 2007/03/30 20:47:03 plunky Exp $ */ + +/*- + * Copyright (c) 2005 Iain Hibbert. + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/proc.h> +#include <sys/queue.h> +#include <sys/systm.h> + +#include <netbt/bluetooth.h> +#include <netbt/hci.h> + +struct hci_unit_list hci_unit_list = TAILQ_HEAD_INITIALIZER(hci_unit_list); + +/* + * HCI Input Queue max lengths. + */ +int hci_eventq_max = 20; +int hci_aclrxq_max = 50; +int hci_scorxq_max = 50; + +/* + * bluetooth unit functions + */ + +void hci_intr(void *); + +void +hci_attach(struct hci_unit *unit) +{ + + KASSERT(unit->hci_softc != NULL); + KASSERT(unit->hci_devname != NULL); + KASSERT(unit->hci_enable != NULL); + KASSERT(unit->hci_disable != NULL); + KASSERT(unit->hci_start_cmd != NULL); + KASSERT(unit->hci_start_acl != NULL); + KASSERT(unit->hci_start_sco != NULL); + + unit->hci_eventq.ifq_maxlen = hci_eventq_max; + unit->hci_aclrxq.ifq_maxlen = hci_aclrxq_max; + unit->hci_scorxq.ifq_maxlen = hci_scorxq_max; + + TAILQ_INIT(&unit->hci_links); + LIST_INIT(&unit->hci_memos); + + TAILQ_INSERT_TAIL(&hci_unit_list, unit, hci_next); +} + +void +hci_detach(struct hci_unit *unit) +{ + + hci_disable(unit); + + TAILQ_REMOVE(&hci_unit_list, unit, hci_next); +} + +int +hci_enable(struct hci_unit *unit) +{ + int s, err; + + /* + * Bluetooth spec says that a device can accept one + * 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. + */ + unit->hci_num_cmd_pkts = 1; + unit->hci_num_acl_pkts = 0; + unit->hci_num_sco_pkts = 0; + + /* + * only allow the basic packet types until + * the features report is in + */ + unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1; + unit->hci_packet_type = unit->hci_acl_mask; + +/* XXX */ +#ifdef notyet + unit->hci_rxint = softintr_establish(IPL_SOFTNET, &hci_intr, unit); + if (unit->hci_rxint == NULL) + return EIO; +#endif +#define splraiseipl(ipl) splnet() + + s = splraiseipl(unit->hci_ipl); + err = (*unit->hci_enable)(unit); + splx(s); + if (err) + goto bad1; + + /* + * Reset the device, this will trigger initialisation + * and wake us up. + */ + unit->hci_flags |= BTF_INIT; + + err = hci_send_cmd(unit, HCI_CMD_RESET, NULL, 0); + if (err) + goto bad2; + + while (unit->hci_flags & BTF_INIT) { + err = tsleep(unit, PWAIT | PCATCH, __func__, 5 * hz); + if (err) + goto bad2; + + /* XXX + * "What If", while we were sleeping, the device + * was removed and detached? Ho Hum. + */ + } + + /* + * Attach Bluetooth Device Hub + */ + unit->hci_bthub = config_found(unit->hci_softc, + &unit->hci_bdaddr, NULL); + + return 0; + +bad2: + s = splraiseipl(unit->hci_ipl); + (*unit->hci_disable)(unit); + splx(s); + +bad1: +#ifdef notyet /* XXX */ + softintr_disestablish(unit->hci_rxint); +#endif + unit->hci_rxint = NULL; + + return err; +} + +void +hci_disable(struct hci_unit *unit) +{ + struct hci_link *link, *next; + struct hci_memo *memo; + int s, acl; + + if (unit->hci_bthub) { + config_detach(unit->hci_bthub, DETACH_FORCE); + unit->hci_bthub = NULL; + } + + if (unit->hci_rxint) { +#ifdef notyet /* XXX */ + softintr_disestablish(unit->hci_rxint); +#endif + unit->hci_rxint = NULL; + } + + s = splraiseipl(unit->hci_ipl); + (*unit->hci_disable)(unit); + splx(s); + + /* + * close down any links, take care to close SCO first since + * they may depend on ACL links. + */ + for (acl = 0 ; acl < 2 ; acl++) { + next = TAILQ_FIRST(&unit->hci_links); + while ((link = next) != NULL) { + next = TAILQ_NEXT(link, hl_next); + if (acl || link->hl_type != HCI_LINK_ACL) + hci_link_free(link, ECONNABORTED); + } + } + + while ((memo = LIST_FIRST(&unit->hci_memos)) != NULL) + hci_memo_free(memo); + + IF_PURGE(&unit->hci_eventq); + unit->hci_eventqlen = 0; + + IF_PURGE(&unit->hci_aclrxq); + unit->hci_aclrxqlen = 0; + + IF_PURGE(&unit->hci_scorxq); + unit->hci_scorxqlen = 0; + + IF_PURGE(&unit->hci_cmdq); + IF_PURGE(&unit->hci_cmdwait); + IF_PURGE(&unit->hci_acltxq); + IF_PURGE(&unit->hci_scotxq); + IF_PURGE(&unit->hci_scodone); +} + +struct hci_unit * +hci_unit_lookup(bdaddr_t *addr) +{ + struct hci_unit *unit; + + TAILQ_FOREACH(unit, &hci_unit_list, hci_next) { + if ((unit->hci_flags & BTF_UP) == 0) + continue; + + if (bdaddr_same(&unit->hci_bdaddr, addr)) + break; + } + + return unit; +} + +/* + * construct and queue a HCI command packet + */ +int +hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len) +{ + struct mbuf *m; + hci_cmd_hdr_t *p; + + KASSERT(unit != NULL); + + m = m_gethdr(M_DONTWAIT, MT_DATA); + if (m == NULL) + return ENOMEM; + + p = mtod(m, hci_cmd_hdr_t *); + p->type = HCI_CMD_PKT; + p->opcode = htole16(opcode); + p->length = len; + m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t); + + if (len) { + KASSERT(buf != NULL); + + m_copyback(m, sizeof(hci_cmd_hdr_t), len, buf); + if (m->m_pkthdr.len != (sizeof(hci_cmd_hdr_t) + len)) { + m_freem(m); + return ENOMEM; + } + } + + DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n", unit->hci_devname, + HCI_OGF(opcode), HCI_OCF(opcode)); + + /* and send it on */ + if (unit->hci_num_cmd_pkts == 0) + IF_ENQUEUE(&unit->hci_cmdwait, m); + else + hci_output_cmd(unit, m); + + return 0; +} + +/* + * Incoming packet processing. Since the code is single threaded + * in any case (IPL_SOFTNET), we handle it all in one interrupt function + * picking our way through more important packets first so that hopefully + * we will never get clogged up with bulk data. + */ +void +hci_intr(void *arg) +{ + struct hci_unit *unit = arg; + struct mbuf *m; + int s; + +another: + s = splraiseipl(unit->hci_ipl); + + if (unit->hci_eventqlen > 0) { + IF_DEQUEUE(&unit->hci_eventq, m); + unit->hci_eventqlen--; + KASSERT(m != NULL); + splx(s); + + DPRINTFN(10, "(%s) recv event, len = %d\n", + unit->hci_devname, m->m_pkthdr.len); + + m->m_flags |= M_LINK0; /* mark incoming packet */ + hci_mtap(m, unit); + hci_event(m, unit); + + goto another; + } + + if (unit->hci_scorxqlen > 0) { + IF_DEQUEUE(&unit->hci_scorxq, m); + unit->hci_scorxqlen--; + KASSERT(m != NULL); + splx(s); + + DPRINTFN(10, "(%s) recv SCO, len = %d\n", + unit->hci_devname, m->m_pkthdr.len); + + m->m_flags |= M_LINK0; /* mark incoming packet */ + hci_mtap(m, unit); + hci_sco_recv(m, unit); + + goto another; + } + + if (unit->hci_aclrxqlen > 0) { + IF_DEQUEUE(&unit->hci_aclrxq, m); + unit->hci_aclrxqlen--; + KASSERT(m != NULL); + splx(s); + + DPRINTFN(10, "(%s) recv ACL, len = %d\n", + unit->hci_devname, m->m_pkthdr.len); + + m->m_flags |= M_LINK0; /* mark incoming packet */ + hci_mtap(m, unit); + hci_acl_recv(m, unit); + + goto another; + } + + IF_DEQUEUE(&unit->hci_scodone, m); + if (m != NULL) { + struct hci_link *link; + splx(s); + + DPRINTFN(11, "(%s) complete SCO\n", + unit->hci_devname); + + TAILQ_FOREACH(link, &unit->hci_links, hl_next) { +#ifdef notyet /* XXX */ + if (link == M_GETCTX(m, struct hci_link *)) { + hci_sco_complete(link, 1); + break; + } +#endif + } + + unit->hci_num_sco_pkts++; + m_freem(m); + + goto another; + } + + splx(s); + + DPRINTFN(10, "done\n"); +} + +/********************************************************************** + * + * IO routines + * + * input & complete routines will be called from device driver + * (at unit->hci_ipl) + */ + +void +hci_input_event(struct hci_unit *unit, struct mbuf *m) +{ + + if (unit->hci_eventqlen > hci_eventq_max || unit->hci_rxint == NULL) { + DPRINTF("(%s) dropped event packet.\n", unit->hci_devname); + unit->hci_stats.err_rx++; + m_freem(m); + } else { + unit->hci_eventqlen++; + IF_ENQUEUE(&unit->hci_eventq, m); +#ifdef notyet /* XXX */ + softintr_schedule(unit->hci_rxint); +#endif + } +} + +void +hci_input_acl(struct hci_unit *unit, struct mbuf *m) +{ + + if (unit->hci_aclrxqlen > hci_aclrxq_max || unit->hci_rxint == NULL) { + DPRINTF("(%s) dropped ACL packet.\n", unit->hci_devname); + unit->hci_stats.err_rx++; + m_freem(m); + } else { + unit->hci_aclrxqlen++; + IF_ENQUEUE(&unit->hci_aclrxq, m); +#ifdef notyet /* XXX */ + softintr_schedule(unit->hci_rxint); +#endif + } +} + +void +hci_input_sco(struct hci_unit *unit, struct mbuf *m) +{ + + if (unit->hci_scorxqlen > hci_scorxq_max || unit->hci_rxint == NULL) { + DPRINTF("(%s) dropped SCO packet.\n", unit->hci_devname); + unit->hci_stats.err_rx++; + m_freem(m); + } else { + unit->hci_scorxqlen++; + IF_ENQUEUE(&unit->hci_scorxq, m); +#ifdef notyet /* XXX */ + softintr_schedule(unit->hci_rxint); +#endif + } +} + +void +hci_output_cmd(struct hci_unit *unit, struct mbuf *m) +{ +#ifdef notyet + void *arg; +#endif + int s; + + hci_mtap(m, unit); + + DPRINTFN(10, "(%s) num_cmd_pkts=%d\n", unit->hci_devname, + unit->hci_num_cmd_pkts); + + unit->hci_num_cmd_pkts--; + + /* + * If context is set, this was from a HCI raw socket + * and a record needs to be dropped from the sockbuf. + */ +#ifdef notyet /* XXX */ + arg = M_GETCTX(m, void *); + if (arg != NULL) + hci_drop(arg); +#endif + + s = splraiseipl(unit->hci_ipl); + IF_ENQUEUE(&unit->hci_cmdq, m); + if ((unit->hci_flags & BTF_XMIT_CMD) == 0) + (*unit->hci_start_cmd)(unit); + + splx(s); +} + +void +hci_output_acl(struct hci_unit *unit, struct mbuf *m) +{ + int s; + + hci_mtap(m, unit); + + DPRINTFN(10, "(%s) num_acl_pkts=%d\n", unit->hci_devname, + unit->hci_num_acl_pkts); + + unit->hci_num_acl_pkts--; + + s = splraiseipl(unit->hci_ipl); + IF_ENQUEUE(&unit->hci_acltxq, m); + if ((unit->hci_flags & BTF_XMIT_ACL) == 0) + (*unit->hci_start_acl)(unit); + + splx(s); +} + +void +hci_output_sco(struct hci_unit *unit, struct mbuf *m) +{ + int s; + + hci_mtap(m, unit); + + DPRINTFN(10, "(%s) num_sco_pkts=%d\n", unit->hci_devname, + unit->hci_num_sco_pkts); + + unit->hci_num_sco_pkts--; + + s = splraiseipl(unit->hci_ipl); + IF_ENQUEUE(&unit->hci_scotxq, m); + if ((unit->hci_flags & BTF_XMIT_SCO) == 0) + (*unit->hci_start_sco)(unit); + + splx(s); +} + +void +hci_complete_sco(struct hci_unit *unit, struct mbuf *m) +{ + + if (unit->hci_rxint == NULL) { + DPRINTFN(10, "(%s) complete SCO!\n", unit->hci_devname); + unit->hci_stats.err_rx++; + m_freem(m); + } else { + IF_ENQUEUE(&unit->hci_scodone, m); +#ifdef notyet /* XXX */ + softintr_schedule(unit->hci_rxint); +#endif + } +} diff --git a/sys/netbt/hci_var.h b/sys/netbt/hci_var.h deleted file mode 100644 index 381a670554d..00000000000 --- a/sys/netbt/hci_var.h +++ /dev/null @@ -1,96 +0,0 @@ -/* $OpenBSD: hci_var.h,v 1.2 2005/01/17 18:12:49 mickey Exp $ */ - -/* - * ng_btsocket_hci_raw.h - * - * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_btsocket_hci_raw.h,v 1.3 2003/11/14 03:45:29 emax Exp $ - */ - -#ifndef _NETGRAPH_BTSOCKET_HCI_RAW_H_ -#define _NETGRAPH_BTSOCKET_HCI_RAW_H_ - -#define NG_BTSOCKET_HCI_RAW_SENDSPACE (4 * 1024) -#define NG_BTSOCKET_HCI_RAW_RECVSPACE (4 * 1024) - -/* - * Bluetooth raw HCI socket PCB - */ - -struct ng_btsocket_hci_raw_pcb { - struct socket *so; /* socket */ - u_int32_t flags; /* flags */ -#define NG_BTSOCKET_HCI_RAW_DIRECTION (1 << 0) -#define NG_BTSOCKET_HCI_RAW_PRIVILEGED (1 << 1) - struct sockaddr_hci addr; /* local address */ - struct ng_btsocket_hci_raw_filter filter; /* filter */ - u_int32_t token; /* message token */ - struct ng_mesg *msg; /* message */ - LIST_ENTRY(ng_btsocket_hci_raw_pcb) next; /* link to next */ -#if 0 - struct mtx pcb_mtx; /* pcb mutex */ -#endif -}; -typedef struct ng_btsocket_hci_raw_pcb ng_btsocket_hci_raw_pcb_t; -typedef struct ng_btsocket_hci_raw_pcb * ng_btsocket_hci_raw_pcb_p; - -#define so2hci_raw_pcb(so) \ - ((struct ng_btsocket_hci_raw_pcb *)((so)->so_pcb)) - -/* - * Bluetooth raw HCI socket methods - */ - -#ifdef _KERNEL - -void hci_raw_init(void); - -int ng_btsocket_hci_raw_abort (struct socket *); -int ng_btsocket_hci_raw_attach (struct socket *, int, struct proc *); -int ng_btsocket_hci_raw_bind (struct socket *, struct sockaddr *, - struct proc *); -int ng_btsocket_hci_raw_connect (struct socket *, struct sockaddr *, - struct proc *); -int ng_btsocket_hci_raw_control (struct socket *, u_long, caddr_t, - struct ifnet *, struct proc *); -int hci_raw_ctloutput(int, struct socket *, int, int, struct mbuf **); -int ng_btsocket_hci_raw_detach (struct socket *); -int ng_btsocket_hci_raw_disconnect (struct socket *); -int ng_btsocket_hci_raw_peeraddr (struct socket *, struct sockaddr **); -int ng_btsocket_hci_raw_send (struct socket *, int, struct mbuf *, - struct sockaddr *, struct mbuf *, - struct proc *); -int ng_btsocket_hci_raw_sockaddr (struct socket *, struct sockaddr **); - -int hci_raw_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, - struct mbuf *); - -void ng_btsocket_hci_raw_data_input(struct mbuf *); -int ng_btsocket_hci_raw_node_rcvdata(struct ifnet *, struct mbuf *); - -#endif /* _KERNEL */ - -#endif /* ndef _NETGRAPH_BTSOCKET_HCI_RAW_H_ */ diff --git a/sys/netbt/l2cap.h b/sys/netbt/l2cap.h index 48b38396387..c99ae184e76 100644 --- a/sys/netbt/l2cap.h +++ b/sys/netbt/l2cap.h @@ -1,8 +1,36 @@ -/* $OpenBSD: l2cap.h,v 1.2 2005/01/17 18:12:49 mickey Exp $ */ +/* $OpenBSD: l2cap.h,v 1.3 2007/05/30 03:42:53 uwe Exp $ */ +/* $NetBSD: l2cap.h,v 1.5 2007/04/21 06:15:23 plunky Exp $ */ -/* - * ng_l2cap.h +/*- + * Copyright (c) 2005 Iain Hibbert. + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/*- * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> * All rights reserved. * @@ -27,34 +55,22 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_l2cap.h,v 1.2 2003/05/10 21:44:41 julian Exp $ + * $Id: l2cap.h,v 1.3 2007/05/30 03:42:53 uwe Exp $ + * $FreeBSD: src/sys/netgraph/bluetooth/include/l2cap.h,v 1.4 2005/08/31 18:13:23 emax Exp $ */ /* * This file contains everything that application needs to know about - * Link Layer Control and Adaptation Protocol (L2CAP). All information - * was obtained from Bluetooth Specification Book v1.1. + * Link Layer Control and Adaptation Protocol (L2CAP). All information + * was obtained from Bluetooth Specification Books (v1.1 and up) * * This file can be included by both kernel and userland applications. */ -#ifndef _NETGRAPH_L2CAP_H_ -#define _NETGRAPH_L2CAP_H_ +#ifndef _NETBT_L2CAP_H_ +#define _NETBT_L2CAP_H_ -/************************************************************************** - ************************************************************************** - ** Netgraph node hook name, type name and type cookie and commands - ************************************************************************** - **************************************************************************/ - -/* Netgraph node hook names */ -#define NG_L2CAP_HOOK_HCI "hci" /* HCI <-> L2CAP */ -#define NG_L2CAP_HOOK_L2C "l2c" /* L2CAP <-> Upper */ -#define NG_L2CAP_HOOK_CTL "ctl" /* L2CAP <-> User */ - -/* Node type name and type cookie */ -#define NG_L2CAP_NODE_TYPE "l2cap" -#define NGM_L2CAP_COOKIE 1000774185 +#include <sys/types.h> /************************************************************************** ************************************************************************** @@ -63,96 +79,132 @@ **************************************************************************/ /* - * Channel IDs are assigned relative to the instance of L2CAP node, i.e. - * relative to the unit. So the total number of channels that unit can have - * open at the same time is 0xffff - 0x0040 = 0xffbf (65471). This number - * does not depend on number of connections. + * Channel IDs are assigned per machine. So the total number of channels that + * a machine can have open at the same time is 0xffff - 0x0040 = 0xffbf (65471). + * This number does not depend on number of HCI connections. */ -#define NG_L2CAP_NULL_CID 0x0000 /* DO NOT USE THIS CID */ -#define NG_L2CAP_SIGNAL_CID 0x0001 /* signaling channel ID */ -#define NG_L2CAP_CLT_CID 0x0002 /* connectionless channel ID */ +#define L2CAP_NULL_CID 0x0000 /* DO NOT USE THIS CID */ +#define L2CAP_SIGNAL_CID 0x0001 /* signaling channel ID */ +#define L2CAP_CLT_CID 0x0002 /* connectionless channel ID */ /* 0x0003 - 0x003f Reserved */ -#define NG_L2CAP_FIRST_CID 0x0040 /* dynamically alloc. (start) */ -#define NG_L2CAP_LAST_CID 0xffff /* dynamically alloc. (end) */ +#define L2CAP_FIRST_CID 0x0040 /* dynamically alloc. (start) */ +#define L2CAP_LAST_CID 0xffff /* dynamically alloc. (end) */ /* L2CAP MTU */ -#define NG_L2CAP_MTU_MINIMUM 48 -#define NG_L2CAP_MTU_DEFAULT 672 -#define NG_L2CAP_MTU_MAXIMUM 0xffff +#define L2CAP_MTU_MINIMUM 48 +#define L2CAP_MTU_DEFAULT 672 +#define L2CAP_MTU_MAXIMUM 0xffff /* L2CAP flush and link timeouts */ -#define NG_L2CAP_FLUSH_TIMO_DEFAULT 0xffff /* always retransmit */ -#define NG_L2CAP_LINK_TIMO_DEFAULT 0xffff +#define L2CAP_FLUSH_TIMO_DEFAULT 0xffff /* always retransmit */ +#define L2CAP_LINK_TIMO_DEFAULT 0xffff /* L2CAP Command Reject reasons */ -#define NG_L2CAP_REJ_NOT_UNDERSTOOD 0x0000 -#define NG_L2CAP_REJ_MTU_EXCEEDED 0x0001 -#define NG_L2CAP_REJ_INVALID_CID 0x0002 +#define L2CAP_REJ_NOT_UNDERSTOOD 0x0000 +#define L2CAP_REJ_MTU_EXCEEDED 0x0001 +#define L2CAP_REJ_INVALID_CID 0x0002 /* 0x0003 - 0xffff - reserved for future use */ -/* Protocol/Service Multioplexor (PSM) values */ -#define NG_L2CAP_PSM_ANY 0x0000 /* Any/Invalid PSM */ -#define NG_L2CAP_PSM_SDP 0x0001 /* Service Discovery Protocol */ -#define NG_L2CAP_PSM_RFCOMM 0x0003 /* RFCOMM protocol */ -#define NG_L2CAP_PSM_TCP 0x0005 /* Telephony Control Protocol */ -/* 0x0006 - 0x1000 - reserved for future use */ +/* Protocol/Service Multiplexor (PSM) values */ +#define L2CAP_PSM_ANY 0x0000 /* Any/Invalid PSM */ +#define L2CAP_PSM_SDP 0x0001 /* Service Discovery Protocol */ +#define L2CAP_PSM_RFCOMM 0x0003 /* RFCOMM protocol */ +#define L2CAP_PSM_TCP 0x0005 /* Telephony Control Protocol */ +#define L2CAP_PSM_TCS 0x0007 /* TCS cordless */ +#define L2CAP_PSM_BNEP 0x000f /* Bluetooth Network */ + /* Encapsulation Protocol*/ +#define L2CAP_PSM_HID_CNTL 0x0011 /* HID Control */ +#define L2CAP_PSM_HID_INTR 0x0013 /* HID Interrupt */ +#define L2CAP_PSM_ESDP 0x0015 /* Extended Service */ + /* Discovery Profile */ +#define L2CAP_PSM_AVCTP 0x0017 /* Audio/Visual Control */ + /* Transport Protocol */ +#define L2CAP_PSM_AVDTP 0x0019 /* Audio/Visual Distribution */ + /* Transport Protocol */ +/* 0x0019 - 0x1000 - reserved for future use */ + +#define L2CAP_PSM_INVALID(psm) (((psm) & 0x0101) != 0x0001) /* L2CAP Connection response command result codes */ -#define NG_L2CAP_SUCCESS 0x0000 -#define NG_L2CAP_PENDING 0x0001 -#define NG_L2CAP_PSM_NOT_SUPPORTED 0x0002 -#define NG_L2CAP_SEQUIRY_BLOCK 0x0003 -#define NG_L2CAP_NO_RESOURCES 0x0004 -#define NG_L2CAP_TIMEOUT 0xeeee -#define NG_L2CAP_UNKNOWN 0xffff +#define L2CAP_SUCCESS 0x0000 +#define L2CAP_PENDING 0x0001 +#define L2CAP_PSM_NOT_SUPPORTED 0x0002 +#define L2CAP_SECURITY_BLOCK 0x0003 +#define L2CAP_NO_RESOURCES 0x0004 +#define L2CAP_TIMEOUT 0xeeee +#define L2CAP_UNKNOWN 0xffff /* 0x0005 - 0xffff - reserved for future use */ /* L2CAP Connection response status codes */ -#define NG_L2CAP_NO_INFO 0x0000 -#define NG_L2CAP_AUTH_PENDING 0x0001 -#define NG_L2CAP_AUTZ_PENDING 0x0002 +#define L2CAP_NO_INFO 0x0000 +#define L2CAP_AUTH_PENDING 0x0001 +#define L2CAP_AUTZ_PENDING 0x0002 /* 0x0003 - 0xffff - reserved for future use */ /* L2CAP Configuration response result codes */ -#define NG_L2CAP_UNACCEPTABLE_PARAMS 0x0001 -#define NG_L2CAP_REJECT 0x0002 -#define NG_L2CAP_UNKNOWN_OPTION 0x0003 +#define L2CAP_UNACCEPTABLE_PARAMS 0x0001 +#define L2CAP_REJECT 0x0002 +#define L2CAP_UNKNOWN_OPTION 0x0003 /* 0x0003 - 0xffff - reserved for future use */ /* L2CAP Configuration options */ -#define NG_L2CAP_OPT_CFLAG_BIT 0x0001 -#define NG_L2CAP_OPT_CFLAG(flags) ((flags) & NG_L2CAP_OPT_CFLAG_BIT) -#define NG_L2CAP_OPT_HINT_BIT 0x80 -#define NG_L2CAP_OPT_HINT(type) ((type) & NG_L2CAP_OPT_HINT_BIT) -#define NG_L2CAP_OPT_HINT_MASK 0x7f -#define NG_L2CAP_OPT_MTU 0x01 -#define NG_L2CAP_OPT_MTU_SIZE sizeof(u_int16_t) -#define NG_L2CAP_OPT_FLUSH_TIMO 0x02 -#define NG_L2CAP_OPT_FLUSH_TIMO_SIZE sizeof(u_int16_t) -#define NG_L2CAP_OPT_QOS 0x03 -#define NG_L2CAP_OPT_QOS_SIZE sizeof(ng_l2cap_flow_t) -/* 0x4 - 0xff - reserved for future use */ +#define L2CAP_OPT_CFLAG_BIT 0x0001 +#define L2CAP_OPT_CFLAG(flags) ((flags) & L2CAP_OPT_CFLAG_BIT) +#define L2CAP_OPT_HINT_BIT 0x80 +#define L2CAP_OPT_HINT(type) ((type) & L2CAP_OPT_HINT_BIT) +#define L2CAP_OPT_HINT_MASK 0x7f +#define L2CAP_OPT_MTU 0x01 +#define L2CAP_OPT_MTU_SIZE sizeof(uint16_t) +#define L2CAP_OPT_FLUSH_TIMO 0x02 +#define L2CAP_OPT_FLUSH_TIMO_SIZE sizeof(uint16_t) +#define L2CAP_OPT_QOS 0x03 +#define L2CAP_OPT_QOS_SIZE sizeof(l2cap_qos_t) +#define L2CAP_OPT_RFC 0x04 +#define L2CAP_OPT_RFC_SIZE sizeof(l2cap_rfc_t) +/* 0x05 - 0xff - reserved for future use */ /* L2CAP Information request type codes */ -#define NG_L2CAP_CONNLESS_MTU 0x0001 -/* 0x0002 - 0xffff - reserved for future use */ +#define L2CAP_CONNLESS_MTU 0x0001 +#define L2CAP_EXTENDED_FEATURES 0x0002 +/* 0x0003 - 0xffff - reserved for future use */ /* L2CAP Information response codes */ -#define NG_L2CAP_NOT_SUPPORTED 0x0001 +#define L2CAP_NOT_SUPPORTED 0x0001 /* 0x0002 - 0xffff - reserved for future use */ -/* L2CAP flow control */ -typedef struct { - u_int8_t flags; /* reserved for future use */ - u_int8_t service_type; /* service type */ - u_int32_t token_rate; /* bytes per second */ - u_int32_t token_bucket_size; /* bytes */ - u_int32_t peak_bandwidth; /* bytes per second */ - u_int32_t latency; /* microseconds */ - u_int32_t delay_variation; /* microseconds */ -} __attribute__ ((packed)) ng_l2cap_flow_t; -typedef ng_l2cap_flow_t * ng_l2cap_flow_p; +/* L2CAP Quality of Service option */ +typedef struct { + uint8_t flags; /* reserved for future use */ + uint8_t service_type; /* service type */ + uint32_t token_rate; /* bytes per second */ + uint32_t token_bucket_size; /* bytes */ + uint32_t peak_bandwidth; /* bytes per second */ + uint32_t latency; /* microseconds */ + uint32_t delay_variation; /* microseconds */ +} __attribute__ ((__packed__)) l2cap_qos_t; + +/* L2CAP QoS type */ +#define L2CAP_QOS_NO_TRAFFIC 0x00 +#define L2CAP_QOS_BEST_EFFORT 0x01 /* (default) */ +#define L2CAP_QOS_GUARANTEED 0x02 +/* 0x03 - 0xff - reserved for future use */ + +/* L2CAP Retransmission & Flow Control option */ +typedef struct { + uint8_t mode; /* RFC mode */ + uint8_t window_size; /* bytes */ + uint8_t max_transmit; /* max retransmissions */ + uint16_t retransmit_timo; /* milliseconds */ + uint16_t monitor_timo; /* milliseconds */ + uint16_t max_pdu_size; /* bytes */ +} __attribute__ ((__packed__)) l2cap_rfc_t; + +/* L2CAP RFC mode */ +#define L2CAP_RFC_BASIC 0x00 /* (default) */ +#define L2CAP_RFC_RETRANSMIT 0x01 +#define L2CAP_RFC_FLOW 0x02 +/* 0x03 - 0xff - reserved for future use */ /************************************************************************** ************************************************************************** @@ -162,501 +214,272 @@ typedef ng_l2cap_flow_t * ng_l2cap_flow_p; /* L2CAP header */ typedef struct { - u_int16_t length; /* payload size */ - u_int16_t dcid; /* destination channel ID */ -} __attribute__ ((packed)) ng_l2cap_hdr_t; + uint16_t length; /* payload size */ + uint16_t dcid; /* destination channel ID */ +} __attribute__ ((__packed__)) l2cap_hdr_t; -/* L2CAP ConnectionLess Traffic (CLT) (if destination cid == 0x2) */ +/* L2CAP ConnectionLess Traffic (dcid == L2CAP_CLT_CID) */ typedef struct { - u_int16_t psm; /* Protocol/Service Multiplexor */ -} __attribute__ ((packed)) ng_l2cap_clt_hdr_t; + uint16_t psm; /* Protocol/Service Multiplexor */ +} __attribute__ ((__packed__)) l2cap_clt_hdr_t; -#define NG_L2CAP_CLT_MTU_MAXIMUM \ - (NG_L2CAP_MTU_MAXIMUM - sizeof(ng_l2cap_clt_hdr_t)) +#define L2CAP_CLT_MTU_MAXIMUM \ + (L2CAP_MTU_MAXIMUM - sizeof(l2cap_clt_hdr_t)) -/* L2CAP command header */ +/* L2CAP Command header (dcid == L2CAP_SIGNAL_CID) */ typedef struct { - u_int8_t code; /* command OpCode */ - u_int8_t ident; /* identifier to match request and response */ - u_int16_t length; /* command parameters length */ -} __attribute__ ((packed)) ng_l2cap_cmd_hdr_t; + uint8_t code; /* command OpCode */ + uint8_t ident; /* identifier to match request and response */ + uint16_t length; /* command parameters length */ +} __attribute__ ((__packed__)) l2cap_cmd_hdr_t; /* L2CAP Command Reject */ -#define NG_L2CAP_CMD_REJ 0x01 +#define L2CAP_COMMAND_REJ 0x01 typedef struct { - u_int16_t reason; /* reason to reject command */ -/* u_int8_t data[]; -- optional data (depends on reason) */ -} __attribute__ ((packed)) ng_l2cap_cmd_rej_cp; - -/* CommandReject data */ -typedef union { - /* NG_L2CAP_REJ_MTU_EXCEEDED */ - struct { - u_int16_t mtu; /* actual signaling MTU */ - } __attribute__ ((packed)) mtu; - /* NG_L2CAP_REJ_INVALID_CID */ - struct { - u_int16_t scid; /* local CID */ - u_int16_t dcid; /* remote CID */ - } __attribute__ ((packed)) cid; -} ng_l2cap_cmd_rej_data_t; -typedef ng_l2cap_cmd_rej_data_t * ng_l2cap_cmd_rej_data_p; + uint16_t reason; /* reason to reject command */ + uint16_t data[2];/* optional data */ +} __attribute__ ((__packed__)) l2cap_cmd_rej_cp; /* L2CAP Connection Request */ -#define NG_L2CAP_CON_REQ 0x02 +#define L2CAP_CONNECT_REQ 0x02 typedef struct { - u_int16_t psm; /* Protocol/Service Multiplexor (PSM) */ - u_int16_t scid; /* source channel ID */ -} __attribute__ ((packed)) ng_l2cap_con_req_cp; + uint16_t psm; /* Protocol/Service Multiplexor (PSM) */ + uint16_t scid; /* source channel ID */ +} __attribute__ ((__packed__)) l2cap_con_req_cp; /* L2CAP Connection Response */ -#define NG_L2CAP_CON_RSP 0x03 +#define L2CAP_CONNECT_RSP 0x03 typedef struct { - u_int16_t dcid; /* destination channel ID */ - u_int16_t scid; /* source channel ID */ - u_int16_t result; /* 0x00 - success */ - u_int16_t status; /* more info if result != 0x00 */ -} __attribute__ ((packed)) ng_l2cap_con_rsp_cp; + uint16_t dcid; /* destination channel ID */ + uint16_t scid; /* source channel ID */ + uint16_t result; /* 0x00 - success */ + uint16_t status; /* more info if result != 0x00 */ +} __attribute__ ((__packed__)) l2cap_con_rsp_cp; /* L2CAP Configuration Request */ -#define NG_L2CAP_CFG_REQ 0x04 +#define L2CAP_CONFIG_REQ 0x04 typedef struct { - u_int16_t dcid; /* destination channel ID */ - u_int16_t flags; /* flags */ -/* u_int8_t options[] -- options */ -} __attribute__ ((packed)) ng_l2cap_cfg_req_cp; + uint16_t dcid; /* destination channel ID */ + uint16_t flags; /* flags */ +/* uint8_t options[] -- options */ +} __attribute__ ((__packed__)) l2cap_cfg_req_cp; /* L2CAP Configuration Response */ -#define NG_L2CAP_CFG_RSP 0x05 +#define L2CAP_CONFIG_RSP 0x05 typedef struct { - u_int16_t scid; /* source channel ID */ - u_int16_t flags; /* flags */ - u_int16_t result; /* 0x00 - success */ -/* u_int8_t options[] -- options */ -} __attribute__ ((packed)) ng_l2cap_cfg_rsp_cp; + uint16_t scid; /* source channel ID */ + uint16_t flags; /* flags */ + uint16_t result; /* 0x00 - success */ +/* uint8_t options[] -- options */ +} __attribute__ ((__packed__)) l2cap_cfg_rsp_cp; /* L2CAP configuration option */ typedef struct { - u_int8_t type; - u_int8_t length; -/* u_int8_t value[] -- option value (depends on type) */ -} __attribute__ ((packed)) ng_l2cap_cfg_opt_t; -typedef ng_l2cap_cfg_opt_t * ng_l2cap_cfg_opt_p; + uint8_t type; + uint8_t length; +/* uint8_t value[] -- option value (depends on type) */ +} __attribute__ ((__packed__)) l2cap_cfg_opt_t; /* L2CAP configuration option value */ typedef union { - u_int16_t mtu; /* NG_L2CAP_OPT_MTU */ - u_int16_t flush_timo; /* NG_L2CAP_OPT_FLUSH_TIMO */ - ng_l2cap_flow_t flow; /* NG_L2CAP_OPT_QOS */ -} ng_l2cap_cfg_opt_val_t; -typedef ng_l2cap_cfg_opt_val_t * ng_l2cap_cfg_opt_val_p; + uint16_t mtu; /* L2CAP_OPT_MTU */ + uint16_t flush_timo; /* L2CAP_OPT_FLUSH_TIMO */ + l2cap_qos_t qos; /* L2CAP_OPT_QOS */ + l2cap_rfc_t rfc; /* L2CAP_OPT_RFC */ +} l2cap_cfg_opt_val_t; /* L2CAP Disconnect Request */ -#define NG_L2CAP_DISCON_REQ 0x06 +#define L2CAP_DISCONNECT_REQ 0x06 typedef struct { - u_int16_t dcid; /* destination channel ID */ - u_int16_t scid; /* source channel ID */ -} __attribute__ ((packed)) ng_l2cap_discon_req_cp; + uint16_t dcid; /* destination channel ID */ + uint16_t scid; /* source channel ID */ +} __attribute__ ((__packed__)) l2cap_discon_req_cp; /* L2CAP Disconnect Response */ -#define NG_L2CAP_DISCON_RSP 0x07 -typedef ng_l2cap_discon_req_cp ng_l2cap_discon_rsp_cp; +#define L2CAP_DISCONNECT_RSP 0x07 +typedef l2cap_discon_req_cp l2cap_discon_rsp_cp; /* L2CAP Echo Request */ -#define NG_L2CAP_ECHO_REQ 0x08 +#define L2CAP_ECHO_REQ 0x08 /* No command parameters, only optional data */ /* L2CAP Echo Response */ -#define NG_L2CAP_ECHO_RSP 0x09 -#define NG_L2CAP_MAX_ECHO_SIZE \ - (NG_L2CAP_MTU_MAXIMUM - sizeof(ng_l2cap_cmd_hdr_t)) +#define L2CAP_ECHO_RSP 0x09 +#define L2CAP_MAX_ECHO_SIZE \ + (L2CAP_MTU_MAXIMUM - sizeof(l2cap_cmd_hdr_t)) /* No command parameters, only optional data */ /* L2CAP Information Request */ -#define NG_L2CAP_INFO_REQ 0x0a +#define L2CAP_INFO_REQ 0x0a typedef struct { - u_int16_t type; /* requested information type */ -} __attribute__ ((packed)) ng_l2cap_info_req_cp; + uint16_t type; /* requested information type */ +} __attribute__ ((__packed__)) l2cap_info_req_cp; /* L2CAP Information Response */ -#define NG_L2CAP_INFO_RSP 0x0b +#define L2CAP_INFO_RSP 0x0b typedef struct { - u_int16_t type; /* requested information type */ - u_int16_t result; /* 0x00 - success */ -/* u_int8_t info[] -- info data (depends on type) + uint16_t type; /* requested information type */ + uint16_t result; /* 0x00 - success */ +/* uint8_t info[] -- info data (depends on type) * - * NG_L2CAP_CONNLESS_MTU - 2 bytes connectionless MTU + * L2CAP_CONNLESS_MTU - 2 bytes connectionless MTU */ -} __attribute__ ((packed)) ng_l2cap_info_rsp_cp; +} __attribute__ ((__packed__)) l2cap_info_rsp_cp; typedef union { - /* NG_L2CAP_CONNLESS_MTU */ + /* L2CAP_CONNLESS_MTU */ struct { - u_int16_t mtu; - } __attribute__ ((packed)) mtu; -} ng_l2cap_info_rsp_data_t; -typedef ng_l2cap_info_rsp_data_t * ng_l2cap_info_rsp_data_p; - -/************************************************************************** - ************************************************************************** - ** Upper layer protocol interface. L2CA_xxx messages - ************************************************************************** - **************************************************************************/ - -/* - * NOTE! NOTE! NOTE! - * - * Bluetooth specification says that L2CA_xxx request must block until - * response is ready. We are not allowed to block in Netgraph, so we - * need to queue request and save some information that can be used - * later and help match request and response. - * - * The idea is to use "token" field from Netgraph message header. The - * upper layer protocol _MUST_ populate "token". L2CAP will queue request - * (using L2CAP command descriptor) and start processing. Later, when - * response is ready or timeout has occur L2CAP layer will create new - * Netgraph message, set "token" and RESP flag and send the message to - * the upper layer protocol. - * - * L2CA_xxx_Ind messages _WILL_NOT_ populate "token" and _WILL_NOT_ - * set RESP flag. There is no reason for this, because they are just - * notifications and do not require acknowlegment. - * - * NOTE: This is _NOT_ what NG_MKRESPONSE and NG_RESPOND_MSG do, however - * it is somewhat similar. - */ - -/* L2CA data packet header */ -typedef struct { - u_int32_t token; /* token to use in L2CAP_L2CA_WRITE */ - u_int16_t length; /* length of the data */ - u_int16_t lcid; /* local channel ID */ -} __attribute__ ((packed)) ng_l2cap_l2ca_hdr_t; - -/* L2CA_Connect */ -#define NGM_L2CAP_L2CA_CON 0x80 -/* Upper -> L2CAP */ -typedef struct { - u_int16_t psm; /* Protocol/Service Multiplexor */ - bdaddr_t bdaddr; /* remote unit address */ -} ng_l2cap_l2ca_con_ip; - -/* L2CAP -> Upper */ -typedef struct { - u_int16_t lcid; /* local channel ID */ - u_int16_t result; /* 0x00 - success */ - u_int16_t status; /* if result != 0x00 */ -} ng_l2cap_l2ca_con_op; - -/* L2CA_ConnectInd */ -#define NGM_L2CAP_L2CA_CON_IND 0x81 -/* L2CAP -> Upper */ -typedef struct { - bdaddr_t bdaddr; /* remote unit address */ - u_int16_t lcid; /* local channel ID */ - u_int16_t psm; /* Procotol/Service Multiplexor */ - u_int8_t ident; /* indentifier */ - u_int8_t unused; /* place holder */ -} ng_l2cap_l2ca_con_ind_ip; -/* No output parameters */ - -/* L2CA_ConnectRsp */ -#define NGM_L2CAP_L2CA_CON_RSP 0x82 -/* Upper -> L2CAP */ -typedef struct { - bdaddr_t bdaddr; /* remote unit address */ - u_int8_t ident; /* "ident" from L2CAP_ConnectInd event */ - u_int8_t unused; /* place holder */ - u_int16_t lcid; /* local channel ID */ - u_int16_t result; /* 0x00 - success */ - u_int16_t status; /* if response != 0x00 */ -} ng_l2cap_l2ca_con_rsp_ip; - -/* L2CAP -> Upper */ -typedef struct { - u_int16_t result; /* 0x00 - success */ -} ng_l2cap_l2ca_con_rsp_op; - -/* L2CA_Config */ -#define NGM_L2CAP_L2CA_CFG 0x83 -/* Upper -> L2CAP */ -typedef struct { - u_int16_t lcid; /* local channel ID */ - u_int16_t imtu; /* receiving MTU for the local channel */ - ng_l2cap_flow_t oflow; /* out flow */ - u_int16_t flush_timo; /* flush timeout (msec) */ - u_int16_t link_timo; /* link timeout (msec) */ -} ng_l2cap_l2ca_cfg_ip; - -/* L2CAP -> Upper */ -typedef struct { - u_int16_t result; /* 0x00 - success */ - u_int16_t imtu; /* sending MTU for the remote channel */ - ng_l2cap_flow_t oflow; /* out flow */ - u_int16_t flush_timo; /* flush timeout (msec) */ -} ng_l2cap_l2ca_cfg_op; - -/* L2CA_ConfigRsp */ -#define NGM_L2CAP_L2CA_CFG_RSP 0x84 -/* Upper -> L2CAP */ -typedef struct { - u_int16_t lcid; /* local channel ID */ - u_int16_t omtu; /* sending MTU for the local channel */ - ng_l2cap_flow_t iflow; /* in FLOW */ -} ng_l2cap_l2ca_cfg_rsp_ip; - -/* L2CAP -> Upper */ -typedef struct { - u_int16_t result; /* 0x00 - sucsess */ -} ng_l2cap_l2ca_cfg_rsp_op; - -/* L2CA_ConfigInd */ -#define NGM_L2CAP_L2CA_CFG_IND 0x85 -/* L2CAP -> Upper */ -typedef struct { - u_int16_t lcid; /* local channel ID */ - u_int16_t omtu; /* outgoing MTU for the local channel */ - ng_l2cap_flow_t iflow; /* in flow */ - u_int16_t flush_timo; /* flush timeout (msec) */ -} ng_l2cap_l2ca_cfg_ind_ip; -/* No output parameters */ - -/* L2CA_QoSViolationInd */ -#define NGM_L2CAP_L2CA_QOS_IND 0x86 -/* L2CAP -> Upper */ -typedef struct { - bdaddr_t bdaddr; /* remote unit address */ -} ng_l2cap_l2ca_qos_ind_ip; -/* No output parameters */ - -/* L2CA_Disconnect */ -#define NGM_L2CAP_L2CA_DISCON 0x87 -/* Upper -> L2CAP */ -typedef struct { - u_int16_t lcid; /* local channel ID */ -} ng_l2cap_l2ca_discon_ip; - -/* L2CAP -> Upper */ -typedef struct { - u_int16_t result; /* 0x00 - sucsess */ -} ng_l2cap_l2ca_discon_op; - -/* L2CA_DisconnectInd */ -#define NGM_L2CAP_L2CA_DISCON_IND 0x88 -/* L2CAP -> Upper */ -typedef ng_l2cap_l2ca_discon_ip ng_l2cap_l2ca_discon_ind_ip; -/* No output parameters */ - -/* L2CA_Write response */ -#define NGM_L2CAP_L2CA_WRITE 0x89 -/* No input parameters */ - -/* L2CAP -> Upper */ -typedef struct { - int result; /* result (0x00 - success) */ - u_int16_t length; /* amount of data written */ - u_int16_t lcid; /* local channel ID */ -} ng_l2cap_l2ca_write_op; - -/* L2CA_GroupCreate */ -#define NGM_L2CAP_L2CA_GRP_CREATE 0x8a -/* Upper -> L2CAP */ -typedef struct { - u_int16_t psm; /* Protocol/Service Multiplexor */ -} ng_l2cap_l2ca_grp_create_ip; - -/* L2CAP -> Upper */ -typedef struct { - u_int16_t lcid; /* local group channel ID */ -} ng_l2cap_l2ca_grp_create_op; - -/* L2CA_GroupClose */ -#define NGM_L2CAP_L2CA_GRP_CLOSE 0x8b -/* Upper -> L2CAP */ -typedef struct { - u_int16_t lcid; /* local group channel ID */ -} ng_l2cap_l2ca_grp_close_ip; - -#if 0 -/* L2CAP -> Upper */ - * typedef struct { - * u_int16_t result; /* 0x00 - success */ - * } ng_l2cap_l2ca_grp_close_op; -#endif - -/* L2CA_GroupAddMember */ -#define NGM_L2CAP_L2CA_GRP_ADD_MEMBER 0x8c -/* Upper -> L2CAP */ -typedef struct { - u_int16_t lcid; /* local group channel ID */ - bdaddr_t bdaddr; /* remote unit address */ -} ng_l2cap_l2ca_grp_add_member_ip; - -/* L2CAP -> Upper */ -typedef struct { - u_int16_t result; /* 0x00 - success */ -} ng_l2cap_l2ca_grp_add_member_op; - -/* L2CA_GroupRemoveMember */ -#define NGM_L2CAP_L2CA_GRP_REM_MEMBER 0x8d -/* Upper -> L2CAP */ -typedef ng_l2cap_l2ca_grp_add_member_ip ng_l2cap_l2ca_grp_rem_member_ip; - -/* L2CAP -> Upper */ -#if 0 - * typedef ng_l2cap_l2ca_grp_add_member_op ng_l2cap_l2ca_grp_rem_member_op; -#endif - -/* L2CA_GroupMembeship */ -#define NGM_L2CAP_L2CA_GRP_MEMBERSHIP 0x8e -/* Upper -> L2CAP */ -typedef struct { - u_int16_t lcid; /* local group channel ID */ -} ng_l2cap_l2ca_grp_get_members_ip; - -/* L2CAP -> Upper */ -typedef struct { - u_int16_t result; /* 0x00 - success */ - u_int16_t nmembers; /* number of group members */ -/* bdaddr_t members[] -- group memebers */ -} ng_l2cap_l2ca_grp_get_members_op; - -/* L2CA_Ping */ -#define NGM_L2CAP_L2CA_PING 0x8f -/* Upper -> L2CAP */ -typedef struct { - bdaddr_t bdaddr; /* remote unit address */ - u_int16_t echo_size; /* size of echo data in bytes */ -/* u_int8_t echo_data[] -- echo data */ -} ng_l2cap_l2ca_ping_ip; - -/* L2CAP -> Upper */ -typedef struct { - u_int16_t result; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote unit address */ - u_int16_t echo_size; /* size of echo data in bytes */ -/* u_int8_t echo_data[] -- echo data */ -} ng_l2cap_l2ca_ping_op; - -/* L2CA_GetInfo */ -#define NGM_L2CAP_L2CA_GET_INFO 0x90 -/* Upper -> L2CAP */ -typedef struct { - bdaddr_t bdaddr; /* remote unit address */ - u_int16_t info_type; /* info type */ -} ng_l2cap_l2ca_get_info_ip; - -/* L2CAP -> Upper */ -typedef struct { - u_int16_t result; /* 0x00 - success */ - u_int16_t info_size; /* size of info data in bytes */ -/* u_int8_t info_data[] -- info data */ -} ng_l2cap_l2ca_get_info_op; - -/* L2CA_EnableCLT/L2CA_DisableCLT */ -#define NGM_L2CAP_L2CA_ENABLE_CLT 0x91 -/* Upper -> L2CAP */ -typedef struct { - u_int16_t psm; /* Protocol/Service Multiplexor */ - u_int16_t enable; /* 0x00 - disable */ -} ng_l2cap_l2ca_enable_clt_ip; - -#if 0 -/* L2CAP -> Upper */ - * typedef struct { - * u_int16_t result; /* 0x00 - success */ - * } ng_l2cap_l2ca_enable_clt_op; -#endif + uint16_t mtu; + } __attribute__ ((__packed__)) mtu; +} l2cap_info_rsp_data_t; /************************************************************************** ************************************************************************** - ** L2CAP node messages + ** L2CAP Socket Definitions ************************************************************************** **************************************************************************/ -/* L2CAP connection states */ -#define NG_L2CAP_CON_CLOSED 0 /* connection closed */ -#define NG_L2CAP_W4_LP_CON_CFM 1 /* waiting... */ -#define NG_L2CAP_CON_OPEN 2 /* connection open */ - -/* L2CAP channel states */ -#define NG_L2CAP_CLOSED 0 /* channel closed */ -#define NG_L2CAP_W4_L2CAP_CON_RSP 1 /* wait for L2CAP resp. */ -#define NG_L2CAP_W4_L2CA_CON_RSP 2 /* wait for upper resp. */ -#define NG_L2CAP_CONFIG 3 /* L2CAP configuration */ -#define NG_L2CAP_OPEN 4 /* channel open */ -#define NG_L2CAP_W4_L2CAP_DISCON_RSP 5 /* wait for L2CAP discon. */ -#define NG_L2CAP_W4_L2CA_DISCON_RSP 6 /* wait for upper discon. */ - -/* Node flags */ -#define NG_L2CAP_CLT_SDP_DISABLED (1 << 0) /* disable SDP CLT */ -#define NG_L2CAP_CLT_RFCOMM_DISABLED (1 << 1) /* disable RFCOMM CLT */ -#define NG_L2CAP_CLT_TCP_DISABLED (1 << 2) /* disable TCP CLT */ - -/* Debug levels */ -#define NG_L2CAP_ALERT_LEVEL 1 -#define NG_L2CAP_ERR_LEVEL 2 -#define NG_L2CAP_WARN_LEVEL 3 -#define NG_L2CAP_INFO_LEVEL 4 - -/* Get node flags (see flags above) */ -#define NGM_L2CAP_NODE_GET_FLAGS 0x400 /* L2CAP -> User */ -typedef u_int16_t ng_l2cap_node_flags_ep; - -/* Get/Set debug level (see levels above) */ -#define NGM_L2CAP_NODE_GET_DEBUG 0x401 /* L2CAP -> User */ -#define NGM_L2CAP_NODE_SET_DEBUG 0x402 /* User -> L2CAP */ -typedef u_int16_t ng_l2cap_node_debug_ep; - -#define NGM_L2CAP_NODE_HOOK_INFO 0x409 /* L2CAP -> Upper */ -/* bdaddr_t bdaddr; -- local (source BDADDR) */ - -#define NGM_L2CAP_NODE_GET_CON_LIST 0x40a /* L2CAP -> User */ -typedef struct { - u_int32_t num_connections; /* number of connections */ -} ng_l2cap_node_con_list_ep; +/* Socket options */ +#define SO_L2CAP_IMTU 1 /* incoming MTU */ +#define SO_L2CAP_OMTU 2 /* outgoing MTU */ +#define SO_L2CAP_IQOS 3 /* incoming QoS */ +#define SO_L2CAP_OQOS 4 /* outgoing QoS */ +#define SO_L2CAP_FLUSH 5 /* flush timeout */ +#define SO_L2CAP_LM 6 /* link mode */ -/* Connection flags */ -#define NG_L2CAP_CON_TX (1 << 0) /* sending data */ -#define NG_L2CAP_CON_RX (1 << 1) /* receiving data */ -#define NG_L2CAP_CON_OUTGOING (1 << 2) /* outgoing connection */ -#define NG_L2CAP_CON_LP_TIMO (1 << 3) /* LP timeout */ -#define NG_L2CAP_CON_AUTO_DISCON_TIMO (1 << 4) /* auto discon. timeout */ +/* L2CAP link mode flags */ +#define L2CAP_LM_AUTH (1<<0) /* want authentication */ +#define L2CAP_LM_ENCRYPT (1<<1) /* want encryption */ +#define L2CAP_LM_SECURE (1<<2) /* want secured link */ -typedef struct { - u_int8_t state; /* connection state */ - u_int8_t flags; /* flags */ - int16_t pending; /* num. pending packets */ - u_int16_t con_handle; /* connection handle */ - bdaddr_t remote; /* remote bdaddr */ -} ng_l2cap_node_con_ep; +#ifdef _KERNEL -#define NG_L2CAP_MAX_CON_NUM \ - ((0xffff - sizeof(ng_l2cap_node_con_list_ep))/sizeof(ng_l2cap_node_con_ep)) +LIST_HEAD(l2cap_channel_list, l2cap_channel); -#define NGM_L2CAP_NODE_GET_CHAN_LIST 0x40b /* L2CAP -> User */ -typedef struct { - u_int32_t num_channels; /* number of channels */ -} ng_l2cap_node_chan_list_ep; - -typedef struct { - u_int32_t state; /* channel state */ +/* global variables */ +extern struct l2cap_channel_list l2cap_active_list; +extern struct l2cap_channel_list l2cap_listen_list; +extern struct pool l2cap_pdu_pool; +extern struct pool l2cap_req_pool; +extern const l2cap_qos_t l2cap_default_qos; - u_int16_t scid; /* source (local) channel ID */ - u_int16_t dcid; /* destination (remote) channel ID */ +/* sysctl variables */ +extern int l2cap_response_timeout; +extern int l2cap_response_extended_timeout; +extern int l2cap_sendspace, l2cap_recvspace; - u_int16_t imtu; /* incomming MTU */ - u_int16_t omtu; /* outgoing MTU */ +/* + * L2CAP Channel + */ +struct l2cap_channel { + struct hci_link *lc_link; /* ACL connection (down) */ + uint16_t lc_state; /* channel state */ + uint16_t lc_flags; /* channel flags */ + uint8_t lc_ident; /* cached request id */ + + uint16_t lc_lcid; /* local channel ID */ + struct sockaddr_bt lc_laddr; /* local address */ + + uint16_t lc_rcid; /* remote channel ID */ + struct sockaddr_bt lc_raddr; /* remote address */ + + int lc_mode; /* link mode */ + uint16_t lc_imtu; /* incoming mtu */ + uint16_t lc_omtu; /* outgoing mtu */ + uint16_t lc_flush; /* flush timeout */ + l2cap_qos_t lc_iqos; /* incoming QoS flow control */ + l2cap_qos_t lc_oqos; /* outgoing Qos flow control */ + + uint8_t lc_pending; /* num of pending PDUs */ + struct ifqueue lc_txq; /* transmit queue */ + + const struct btproto *lc_proto; /* upper layer callbacks */ + void *lc_upper; /* upper layer argument */ + + LIST_ENTRY(l2cap_channel)lc_ncid; /* next channel (ascending CID) */ +}; + +/* l2cap_channel state */ +#define L2CAP_CLOSED 0 /* closed */ +#define L2CAP_WAIT_SEND_CONNECT_REQ 1 /* waiting to send connect request */ +#define L2CAP_WAIT_RECV_CONNECT_RSP 2 /* waiting to recv connect response */ +#define L2CAP_WAIT_SEND_CONNECT_RSP 3 /* waiting to send connect response */ +#define L2CAP_WAIT_CONFIG 4 /* waiting for configuration */ +#define L2CAP_OPEN 5 /* user data transfer state */ +#define L2CAP_WAIT_DISCONNECT 6 /* have sent disconnect request */ + +/* l2cap_channel flags */ +#define L2CAP_SHUTDOWN (1<<0) /* channel is closing */ +#define L2CAP_WAIT_CONFIG_REQ (1<<1) /* waiting for config request */ +#define L2CAP_WAIT_CONFIG_RSP (1<<2) /* waiting for config response */ - u_int16_t psm; /* PSM */ - bdaddr_t remote; /* remote bdaddr */ -} ng_l2cap_node_chan_ep; +/* + * L2CAP Request + */ +struct l2cap_req { + struct hci_link *lr_link; /* ACL connection */ + struct l2cap_channel *lr_chan; /* channel pointer */ + uint8_t lr_code; /* request code */ + uint8_t lr_id; /* request id */ + struct timeout lr_rtx; /* response timer */ + TAILQ_ENTRY(l2cap_req) lr_next; /* next request on link */ +}; -#define NG_L2CAP_MAX_CHAN_NUM \ - ((0xffff - sizeof(ng_l2cap_node_chan_list_ep))/sizeof(ng_l2cap_node_chan_ep)) +/* + * L2CAP Protocol Data Unit + */ +struct l2cap_pdu { + struct l2cap_channel *lp_chan; /* PDU owner */ + struct ifqueue lp_data; /* PDU data */ + TAILQ_ENTRY(l2cap_pdu) lp_next; /* next PDU on link */ + int lp_pending; /* # of fragments pending */ +}; -#define NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO 0x40c /* L2CAP -> User */ -#define NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO 0x40d /* User -> L2CAP */ -typedef u_int16_t ng_l2cap_node_auto_discon_ep; +/* + * L2CAP function prototypes + */ -#endif /* ndef _NETGRAPH_L2CAP_H_ */ +struct socket; +struct mbuf; + +/* l2cap_lower.c */ +void l2cap_close(struct l2cap_channel *, int); +void l2cap_recv_frame(struct mbuf *, struct hci_link *); +int l2cap_start(struct l2cap_channel *); + +/* l2cap_misc.c */ +int l2cap_setmode(struct l2cap_channel *); +int l2cap_cid_alloc(struct l2cap_channel *); +struct l2cap_channel *l2cap_cid_lookup(uint16_t); +int l2cap_request_alloc(struct l2cap_channel *, uint8_t); +struct l2cap_req *l2cap_request_lookup(struct hci_link *, uint8_t); +void l2cap_request_free(struct l2cap_req *); +void l2cap_rtx(void *); + +/* l2cap_signal.c */ +void l2cap_recv_signal(struct mbuf *, struct hci_link *); +int l2cap_send_connect_req(struct l2cap_channel *); +int l2cap_send_config_req(struct l2cap_channel *); +int l2cap_send_disconnect_req(struct l2cap_channel *); +int l2cap_send_connect_rsp(struct hci_link *, uint8_t, uint16_t, uint16_t, uint16_t); + +/* l2cap_socket.c */ +int l2cap_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *); +int l2cap_ctloutput(int, struct socket *, int, int, struct mbuf **); + +/* l2cap_upper.c */ +int l2cap_attach(struct l2cap_channel **, const struct btproto *, void *); +int l2cap_bind(struct l2cap_channel *, struct sockaddr_bt *); +int l2cap_sockaddr(struct l2cap_channel *, struct sockaddr_bt *); +int l2cap_connect(struct l2cap_channel *, struct sockaddr_bt *); +int l2cap_peeraddr(struct l2cap_channel *, struct sockaddr_bt *); +int l2cap_disconnect(struct l2cap_channel *, int); +int l2cap_detach(struct l2cap_channel **); +int l2cap_listen(struct l2cap_channel *); +int l2cap_send(struct l2cap_channel *, struct mbuf *); +int l2cap_setopt(struct l2cap_channel *, int, void *); +int l2cap_getopt(struct l2cap_channel *, int, void *); + +#endif /* _KERNEL */ + +#endif /* _NETBT_L2CAP_H_ */ diff --git a/sys/netbt/l2cap_lower.c b/sys/netbt/l2cap_lower.c new file mode 100644 index 00000000000..ba0c9f4a4bf --- /dev/null +++ b/sys/netbt/l2cap_lower.c @@ -0,0 +1,204 @@ +/* $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 $ */ + +/*- + * Copyright (c) 2005 Iain Hibbert. + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/proc.h> +#include <sys/queue.h> +#include <sys/systm.h> + +#include <netbt/bluetooth.h> +#include <netbt/hci.h> +#include <netbt/l2cap.h> + +/**************************************************************************** + * + * L2CAP Channel Lower Layer interface + */ + +/* + * L2CAP channel is disconnected, could be: + * + * HCI layer received "Disconnect Complete" event for ACL link + * some Request timed out + * Config failed + * Other end reported invalid CID + * Normal disconnection + * Change link mode failed + */ +void +l2cap_close(struct l2cap_channel *chan, int err) +{ + struct l2cap_pdu *pdu; + struct l2cap_req *req, *n; + + if (chan->lc_state == L2CAP_CLOSED) + return; + + /* + * Since any potential PDU could be half sent we just let it go, + * but disassociate ourselves from it as links deal with ownerless + * PDU's in any case. We could try harder to flush unsent packets + * but maybe its better to leave them in the queue? + */ + TAILQ_FOREACH(pdu, &chan->lc_link->hl_txq, lp_next) { + if (pdu->lp_chan == chan) + pdu->lp_chan = NULL; + } + + /* + * and clear any outstanding requests.. + */ + req = TAILQ_FIRST(&chan->lc_link->hl_reqs); + while (req != NULL) { + n = TAILQ_NEXT(req, lr_next); + if (req->lr_chan == chan) + l2cap_request_free(req); + + req = n; + } + + chan->lc_pending = 0; + chan->lc_state = L2CAP_CLOSED; + hci_acl_close(chan->lc_link, err); + chan->lc_link = NULL; + + (*chan->lc_proto->disconnected)(chan->lc_upper, err); +} + +/* + * Process incoming L2CAP frame from ACL link. We take off the B-Frame + * header (which is present in all packets), verify the data length + * and distribute the rest of the frame to the relevant channel + * handler. + */ +void +l2cap_recv_frame(struct mbuf *m, struct hci_link *link) +{ + struct l2cap_channel *chan; + l2cap_hdr_t hdr; + + m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr); + m_adj(m, sizeof(hdr)); + + hdr.length = letoh16(hdr.length); + hdr.dcid = letoh16(hdr.dcid); + + DPRINTFN(5, "(%s) received packet (%d bytes)\n", + link->hl_unit->hci_devname, hdr.length); + + if (hdr.length != m->m_pkthdr.len) + goto failed; + + if (hdr.dcid == L2CAP_SIGNAL_CID) { + l2cap_recv_signal(m, link); + return; + } + + if (hdr.dcid == L2CAP_CLT_CID) { + m_freem(m); /* TODO */ + return; + } + + chan = l2cap_cid_lookup(hdr.dcid); + if (chan != NULL && chan->lc_link == link + && chan->lc_state == L2CAP_OPEN) { + (*chan->lc_proto->input)(chan->lc_upper, m); + return; + } + + DPRINTF("(%s) dropping %d L2CAP data bytes for unknown CID #%d\n", + link->hl_unit->hci_devname, hdr.length, hdr.dcid); + +failed: + m_freem(m); +} + +/* + * Start another L2CAP packet on its way. This is called from l2cap_send + * (when no PDU is pending) and hci_acl_start (when PDU has been placed on + * device queue). Thus we can have more than one PDU waiting at the device + * if space is available but no single channel will hog the link. + */ +int +l2cap_start(struct l2cap_channel *chan) +{ + struct mbuf *m; + int err = 0; + + if (chan->lc_state != L2CAP_OPEN) + return 0; + + if (IF_IS_EMPTY(&chan->lc_txq)) { + DPRINTFN(5, "no data, pending = %d\n", chan->lc_pending); + /* + * If we are just waiting for the queue to flush + * and it has, we may disconnect.. + */ + if (chan->lc_flags & L2CAP_SHUTDOWN + && chan->lc_pending == 0) { + chan->lc_state = L2CAP_WAIT_DISCONNECT; + err = l2cap_send_disconnect_req(chan); + if (err) + l2cap_close(chan, err); + } + + return err; + } + + /* + * We could check QoS/RFC mode here and optionally not send + * the packet if we are not ready for any reason + * + * Also to support flush timeout then we might want to start + * the timer going? (would need to keep some kind of record + * of packets sent, possibly change it so that we allocate + * the l2cap_pdu and fragment the packet, then hand it down + * and get it back when its completed). Hm. + */ + + IF_DEQUEUE(&chan->lc_txq, m); + + KASSERT(chan->lc_link != NULL); + KASSERT(m != NULL); + + DPRINTFN(5, "CID #%d sending packet (%d bytes)\n", + chan->lc_lcid, m->m_pkthdr.len); + + chan->lc_pending++; + return hci_acl_send(m, chan->lc_link, chan); +} diff --git a/sys/netbt/l2cap_misc.c b/sys/netbt/l2cap_misc.c new file mode 100644 index 00000000000..9507f8daac8 --- /dev/null +++ b/sys/netbt/l2cap_misc.c @@ -0,0 +1,260 @@ +/* $OpenBSD: l2cap_misc.c,v 1.1 2007/05/30 03:42:53 uwe Exp $ */ +/* $NetBSD: l2cap_misc.c,v 1.3 2007/04/21 06:15:23 plunky Exp $ */ + +/*- + * Copyright (c) 2005 Iain Hibbert. + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/proc.h> +#include <sys/queue.h> +#include <sys/systm.h> + +#include <netbt/bluetooth.h> +#include <netbt/hci.h> +#include <netbt/l2cap.h> + +struct l2cap_channel_list + l2cap_active_list = LIST_HEAD_INITIALIZER(l2cap_active_list); +struct l2cap_channel_list + l2cap_listen_list = LIST_HEAD_INITIALIZER(l2cap_listen_list); + +struct pool l2cap_req_pool; +struct pool l2cap_pdu_pool; +#ifdef notyet /* XXX */ +POOL_INIT(l2cap_req_pool, sizeof(struct l2cap_req), 0, 0, 0, "l2cap_req", NULL, + IPL_SOFTNET); +POOL_INIT(l2cap_pdu_pool, sizeof(struct l2cap_pdu), 0, 0, 0, "l2cap_pdu", NULL, + IPL_SOFTNET); +#endif + +const l2cap_qos_t l2cap_default_qos = { + 0, /* flags */ + L2CAP_QOS_BEST_EFFORT, /* service type */ + 0x00000000, /* token rate */ + 0x00000000, /* token bucket size */ + 0x00000000, /* peak bandwidth */ + 0xffffffff, /* latency */ + 0xffffffff /* delay variation */ +}; + +/* + * L2CAP request timeouts + */ +int l2cap_response_timeout = 30; /* seconds */ +int l2cap_response_extended_timeout = 180; /* seconds */ + +/* + * Set Link Mode on channel + */ +int +l2cap_setmode(struct l2cap_channel *chan) +{ + + KASSERT(chan != NULL); + KASSERT(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")); + + if (chan->lc_mode & L2CAP_LM_AUTH) + chan->lc_link->hl_flags |= HCI_LINK_AUTH_REQ; + + if (chan->lc_mode & L2CAP_LM_ENCRYPT) + chan->lc_link->hl_flags |= HCI_LINK_ENCRYPT_REQ; + + if (chan->lc_mode & L2CAP_LM_SECURE) + chan->lc_link->hl_flags |= HCI_LINK_SECURE_REQ; + + return hci_acl_setmode(chan->lc_link); +} + +/* + * Allocate a new Request structure & ID and set the timer going + */ +int +l2cap_request_alloc(struct l2cap_channel *chan, uint8_t code) +{ + struct hci_link *link = chan->lc_link; + struct l2cap_req *req; + int next_id; + + if (link == NULL) + return ENETDOWN; + + /* find next ID (0 is not allowed) */ + next_id = link->hl_lastid + 1; + if (next_id > 0xff) + next_id = 1; + + /* Ouroboros check */ + req = TAILQ_FIRST(&link->hl_reqs); + if (req && req->lr_id == next_id) + return ENFILE; + + req = pool_get(&l2cap_req_pool, PR_NOWAIT); + if (req == NULL) + return ENOMEM; + + req->lr_id = link->hl_lastid = next_id; + + req->lr_code = code; + req->lr_chan = chan; + req->lr_link = link; + + timeout_set(&req->lr_rtx, l2cap_rtx, req); + timeout_add(&req->lr_rtx, l2cap_response_timeout*hz); + + TAILQ_INSERT_TAIL(&link->hl_reqs, req, lr_next); + + return 0; +} + +/* + * Find a running request for this link + */ +struct l2cap_req * +l2cap_request_lookup(struct hci_link *link, uint8_t id) +{ + struct l2cap_req *req; + + TAILQ_FOREACH(req, &link->hl_reqs, lr_next) { + if (req->lr_id == id) + return req; + } + + return NULL; +} + +/* + * Halt and free a request + */ +void +l2cap_request_free(struct l2cap_req *req) +{ + struct hci_link *link = req->lr_link; + + timeout_del(&req->lr_rtx); + if (timeout_triggered(&req->lr_rtx)) + return; + + TAILQ_REMOVE(&link->hl_reqs, req, lr_next); + pool_put(&l2cap_req_pool, req); +} + +/* + * Response Timeout eXpired + * + * No response to our request, so deal with it as best we can. + * + * XXX should try again at least with ertx? + */ +void +l2cap_rtx(void *arg) +{ + struct l2cap_req *req = arg; + struct l2cap_channel *chan; + int s; + + s = splsoftnet(); + + chan = req->lr_chan; + l2cap_request_free(req); + + DPRINTF("cid %d, ident %d\n", (chan ? chan->lc_lcid : 0), req->lr_id); + + if (chan && chan->lc_state != L2CAP_CLOSED) + l2cap_close(chan, ETIMEDOUT); + + splx(s); +} + +/* + * Allocate next available CID to channel. We keep a single + * ordered list of channels, so find the first gap. + * + * If this turns out to be not enough (!), could use a + * list per HCI unit.. + */ +int +l2cap_cid_alloc(struct l2cap_channel *chan) +{ + struct l2cap_channel *used, *prev = NULL; + uint16_t cid = L2CAP_FIRST_CID; + + if (chan->lc_lcid != L2CAP_NULL_CID || chan->lc_state != L2CAP_CLOSED) + return EISCONN; + + LIST_FOREACH(used, &l2cap_active_list, lc_ncid) { + if (used->lc_lcid > cid) + break; /* found our gap */ + + KASSERT(used->lc_lcid == cid); + cid++; + + if (cid == L2CAP_LAST_CID) + return ENFILE; + + prev = used; /* for insert after */ + } + + chan->lc_lcid = cid; + + if (prev) + LIST_INSERT_AFTER(prev, chan, lc_ncid); + else + LIST_INSERT_HEAD(&l2cap_active_list, chan, lc_ncid); + + return 0; +} + +/* + * Find channel with CID + */ +struct l2cap_channel * +l2cap_cid_lookup(uint16_t cid) +{ + struct l2cap_channel *chan; + + LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) { + if (chan->lc_lcid == cid) + return chan; + + if (chan->lc_lcid > cid) + return NULL; + } + + return NULL; +} diff --git a/sys/netbt/l2cap_signal.c b/sys/netbt/l2cap_signal.c new file mode 100644 index 00000000000..33f203a2cf3 --- /dev/null +++ b/sys/netbt/l2cap_signal.c @@ -0,0 +1,1107 @@ +/* $OpenBSD: l2cap_signal.c,v 1.1 2007/05/30 03:42:53 uwe Exp $ */ +/* $NetBSD: l2cap_signal.c,v 1.8 2007/05/16 18:34:49 plunky Exp $ */ + +/*- + * Copyright (c) 2005 Iain Hibbert. + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/proc.h> +#include <sys/queue.h> +#include <sys/systm.h> + +#include <netbt/bluetooth.h> +#include <netbt/hci.h> +#include <netbt/l2cap.h> + +/******************************************************************************* + * + * L2CAP Signal processing + */ + +static void l2cap_recv_command_rej(struct mbuf *, struct hci_link *); +static void l2cap_recv_connect_req(struct mbuf *, struct hci_link *); +static void l2cap_recv_connect_rsp(struct mbuf *, struct hci_link *); +static void l2cap_recv_config_req(struct mbuf *, struct hci_link *); +static void l2cap_recv_config_rsp(struct mbuf *, struct hci_link *); +static void l2cap_recv_disconnect_req(struct mbuf *, struct hci_link *); +static void l2cap_recv_disconnect_rsp(struct mbuf *, struct hci_link *); +static void l2cap_recv_info_req(struct mbuf *, struct hci_link *); +static int l2cap_send_signal(struct hci_link *, uint8_t, uint8_t, uint16_t, void *); +static int l2cap_send_command_rej(struct hci_link *, uint8_t, uint16_t, ...); + +/* + * process incoming signal packets (CID 0x0001). Can contain multiple + * requests/responses. + */ +void +l2cap_recv_signal(struct mbuf *m, struct hci_link *link) +{ + l2cap_cmd_hdr_t cmd; + + for(;;) { + if (m->m_pkthdr.len == 0) + goto finish; + + if (m->m_pkthdr.len < sizeof(cmd)) + goto reject; + + m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); + cmd.length = letoh16(cmd.length); + + if (m->m_pkthdr.len < sizeof(cmd) + cmd.length) + goto reject; + + DPRINTFN(2, "(%s) code %d, ident %d, len %d\n", + link->hl_unit->hci_devname, + cmd.code, cmd.ident, cmd.length); + + switch (cmd.code) { + case L2CAP_COMMAND_REJ: + if (cmd.length > sizeof(l2cap_cmd_rej_cp)) + goto finish; + + l2cap_recv_command_rej(m, link); + break; + + case L2CAP_CONNECT_REQ: + if (cmd.length != sizeof(l2cap_con_req_cp)) + goto reject; + + l2cap_recv_connect_req(m, link); + break; + + case L2CAP_CONNECT_RSP: + if (cmd.length != sizeof(l2cap_con_rsp_cp)) + goto finish; + + l2cap_recv_connect_rsp(m, link); + break; + + case L2CAP_CONFIG_REQ: + l2cap_recv_config_req(m, link); + break; + + case L2CAP_CONFIG_RSP: + l2cap_recv_config_rsp(m, link); + break; + + case L2CAP_DISCONNECT_REQ: + if (cmd.length != sizeof(l2cap_discon_req_cp)) + goto reject; + + l2cap_recv_disconnect_req(m, link); + break; + + case L2CAP_DISCONNECT_RSP: + if (cmd.length != sizeof(l2cap_discon_rsp_cp)) + goto finish; + + l2cap_recv_disconnect_rsp(m, link); + break; + + case L2CAP_ECHO_REQ: + m_adj(m, sizeof(cmd) + cmd.length); + l2cap_send_signal(link, L2CAP_ECHO_RSP, cmd.ident, + 0, NULL); + break; + + case L2CAP_ECHO_RSP: + m_adj(m, sizeof(cmd) + cmd.length); + break; + + case L2CAP_INFO_REQ: + if (cmd.length != sizeof(l2cap_info_req_cp)) + goto reject; + + l2cap_recv_info_req(m, link); + break; + + case L2CAP_INFO_RSP: + m_adj(m, sizeof(cmd) + cmd.length); + break; + + default: + goto reject; + } + } + +#ifdef DIAGNOSTIC + panic("impossible!"); +#endif + +reject: + l2cap_send_command_rej(link, cmd.ident, L2CAP_REJ_NOT_UNDERSTOOD); +finish: + m_freem(m); +} + +/* + * Process Received Command Reject. For now we dont try to recover gracefully + * from this, it probably means that the link is garbled or the other end is + * insufficiently capable of handling normal traffic. (not *my* fault, no way!) + */ +static void +l2cap_recv_command_rej(struct mbuf *m, struct hci_link *link) +{ + struct l2cap_req *req; + struct l2cap_channel *chan; + l2cap_cmd_hdr_t cmd; + l2cap_cmd_rej_cp cp; + + m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); + m_adj(m, sizeof(cmd)); + + cmd.length = letoh16(cmd.length); + + m_copydata(m, 0, cmd.length, (caddr_t)&cp); + m_adj(m, cmd.length); + + req = l2cap_request_lookup(link, cmd.ident); + if (req == NULL) + return; + + switch (letoh16(cp.reason)) { + case L2CAP_REJ_NOT_UNDERSTOOD: + /* + * I dont know what to do, just move up the timeout + */ + timeout_add(&req->lr_rtx, 0); + break; + + case L2CAP_REJ_MTU_EXCEEDED: + /* + * I didnt send any commands over L2CAP_MTU_MINIMUM size, but.. + * + * XXX maybe we should resend this, instead? + */ + link->hl_mtu = letoh16(cp.data[0]); + timeout_add(&req->lr_rtx, 0); + break; + + case L2CAP_REJ_INVALID_CID: + /* + * Well, if they dont have such a channel then our channel is + * most likely closed. Make it so. + */ + chan = req->lr_chan; + l2cap_request_free(req); + if (chan != NULL && chan->lc_state != L2CAP_CLOSED) + l2cap_close(chan, ECONNABORTED); + + break; + + default: + UNKNOWN(letoh16(cp.reason)); + break; + } +} + +/* + * Process Received Connect Request. Find listening channel matching + * psm & addr and ask upper layer for a new channel. + */ +static void +l2cap_recv_connect_req(struct mbuf *m, struct hci_link *link) +{ + struct sockaddr_bt laddr, raddr; + struct l2cap_channel *chan, *new; + l2cap_cmd_hdr_t cmd; + l2cap_con_req_cp cp; + int err; + + /* extract cmd */ + m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); + m_adj(m, sizeof(cmd)); + + /* extract request */ + m_copydata(m, 0, sizeof(cp), (caddr_t)&cp); + m_adj(m, sizeof(cp)); + + cp.scid = letoh16(cp.scid); + cp.psm = letoh16(cp.psm); + + memset(&laddr, 0, sizeof(struct sockaddr_bt)); + laddr.bt_len = sizeof(struct sockaddr_bt); + laddr.bt_family = AF_BLUETOOTH; + laddr.bt_psm = cp.psm; + bdaddr_copy(&laddr.bt_bdaddr, &link->hl_unit->hci_bdaddr); + + memset(&raddr, 0, sizeof(struct sockaddr_bt)); + raddr.bt_len = sizeof(struct sockaddr_bt); + raddr.bt_family = AF_BLUETOOTH; + raddr.bt_psm = cp.psm; + bdaddr_copy(&raddr.bt_bdaddr, &link->hl_bdaddr); + + LIST_FOREACH(chan, &l2cap_listen_list, lc_ncid) { + if (chan->lc_laddr.bt_psm != laddr.bt_psm + && chan->lc_laddr.bt_psm != L2CAP_PSM_ANY) + continue; + + if (!bdaddr_same(&laddr.bt_bdaddr, &chan->lc_laddr.bt_bdaddr) + && bdaddr_any(&chan->lc_laddr.bt_bdaddr) == 0) + continue; + + new= (*chan->lc_proto->newconn)(chan->lc_upper, &laddr, &raddr); + if (new == NULL) + continue; + + err = l2cap_cid_alloc(new); + if (err) { + l2cap_send_connect_rsp(link, cmd.ident, + 0, cp.scid, + L2CAP_NO_RESOURCES); + + (*new->lc_proto->disconnected)(new->lc_upper, err); + return; + } + + new->lc_link = hci_acl_open(link->hl_unit, &link->hl_bdaddr); + KASSERT(new->lc_link == link); + + new->lc_rcid = cp.scid; + new->lc_ident = cmd.ident; + + memcpy(&new->lc_laddr, &laddr, sizeof(struct sockaddr_bt)); + memcpy(&new->lc_raddr, &raddr, sizeof(struct sockaddr_bt)); + + new->lc_mode = chan->lc_mode; + + err = l2cap_setmode(new); + if (err == EINPROGRESS) { + new->lc_state = L2CAP_WAIT_SEND_CONNECT_RSP; + (*new->lc_proto->connecting)(new->lc_upper); + return; + } + if (err) { + new->lc_state = L2CAP_CLOSED; + hci_acl_close(link, err); + new->lc_link = NULL; + + l2cap_send_connect_rsp(link, cmd.ident, + 0, cp.scid, + L2CAP_NO_RESOURCES); + + (*new->lc_proto->disconnected)(new->lc_upper, err); + return; + } + + err = l2cap_send_connect_rsp(link, cmd.ident, + new->lc_lcid, new->lc_rcid, + L2CAP_SUCCESS); + if (err) { + l2cap_close(new, err); + return; + } + + new->lc_state = L2CAP_WAIT_CONFIG; + new->lc_flags |= (L2CAP_WAIT_CONFIG_REQ | L2CAP_WAIT_CONFIG_RSP); + err = l2cap_send_config_req(new); + if (err) + l2cap_close(new, err); + + return; + } + + l2cap_send_connect_rsp(link, cmd.ident, + 0, cp.scid, + L2CAP_PSM_NOT_SUPPORTED); +} + +/* + * Process Received Connect Response. + */ +static void +l2cap_recv_connect_rsp(struct mbuf *m, struct hci_link *link) +{ + l2cap_cmd_hdr_t cmd; + l2cap_con_rsp_cp cp; + struct l2cap_req *req; + struct l2cap_channel *chan; + + m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); + m_adj(m, sizeof(cmd)); + + m_copydata(m, 0, sizeof(cp), (caddr_t)&cp); + m_adj(m, sizeof(cp)); + + cp.scid = letoh16(cp.scid); + cp.dcid = letoh16(cp.dcid); + cp.result = letoh16(cp.result); + + req = l2cap_request_lookup(link, cmd.ident); + if (req == NULL || req->lr_code != L2CAP_CONNECT_REQ) + return; + + chan = req->lr_chan; + if (chan != NULL && chan->lc_lcid != cp.scid) + return; + + if (chan == NULL || chan->lc_state != L2CAP_WAIT_RECV_CONNECT_RSP) { + l2cap_request_free(req); + return; + } + + switch (cp.result) { + case L2CAP_SUCCESS: + /* + * Ok, at this point we have a connection to the other party. We + * could indicate upstream that we are ready for business and + * wait for a "Configure Channel Request" but I'm not so sure + * that is required in our case - we will proceed directly to + * sending our config request. We set two state bits because in + * the config state we are waiting for requests and responses. + */ + l2cap_request_free(req); + chan->lc_rcid = cp.dcid; + chan->lc_state = L2CAP_WAIT_CONFIG; + chan->lc_flags |= (L2CAP_WAIT_CONFIG_REQ | L2CAP_WAIT_CONFIG_RSP); + l2cap_send_config_req(chan); + break; + + case L2CAP_PENDING: + /* XXX dont release request, should start eRTX timeout? */ + (*chan->lc_proto->connecting)(chan->lc_upper); + break; + + case L2CAP_PSM_NOT_SUPPORTED: + case L2CAP_SECURITY_BLOCK: + case L2CAP_NO_RESOURCES: + default: + l2cap_request_free(req); + l2cap_close(chan, ECONNREFUSED); + break; + } +} + +/* + * Process Received Config Reqest. + */ +static void +l2cap_recv_config_req(struct mbuf *m, struct hci_link *link) +{ + uint8_t buf[L2CAP_MTU_MINIMUM]; + l2cap_cmd_hdr_t cmd; + l2cap_cfg_req_cp cp; + l2cap_cfg_opt_t opt; + l2cap_cfg_opt_val_t val; + l2cap_cfg_rsp_cp rp; + struct l2cap_channel *chan; + int left, len; + + m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); + m_adj(m, sizeof(cmd)); + left = letoh16(cmd.length); + + if (left < sizeof(cp)) + goto reject; + + m_copydata(m, 0, sizeof(cp), (caddr_t)&cp); + m_adj(m, sizeof(cp)); + left -= sizeof(cp); + + cp.dcid = letoh16(cp.dcid); + cp.flags = letoh16(cp.flags); + + chan = l2cap_cid_lookup(cp.dcid); + if (chan == NULL || chan->lc_link != link + || chan->lc_state != L2CAP_WAIT_CONFIG + || (chan->lc_flags & L2CAP_WAIT_CONFIG_REQ) == 0) { + /* XXX we should really accept reconfiguration requests */ + l2cap_send_command_rej(link, cmd.ident, L2CAP_REJ_INVALID_CID, + L2CAP_NULL_CID, cp.dcid); + goto out; + } + + /* ready our response packet */ + rp.scid = htole16(chan->lc_rcid); + rp.flags = 0; /* "No Continuation" */ + rp.result = L2CAP_SUCCESS; + len = sizeof(rp); + + /* + * Process the packet. We build the return packet on the fly adding any + * unacceptable parameters as we go. As we can only return one result, + * unknown option takes precedence so we start our return packet anew + * and ignore option values thereafter as they will be re-sent. + * + * Since we do not support enough options to make overflowing the min + * MTU size an issue in normal use, we just reject config requests that + * make that happen. This could be because options are repeated or the + * packet is corrupted in some way. + * + * If unknown option types threaten to overflow the packet, we just + * ignore them. We can deny them next time. + */ + while (left > 0) { + if (left < sizeof(opt)) + goto reject; + + m_copydata(m, 0, sizeof(opt), (caddr_t)&opt); + m_adj(m, sizeof(opt)); + left -= sizeof(opt); + + if (left < opt.length) + goto reject; + + switch(opt.type & L2CAP_OPT_HINT_MASK) { + case L2CAP_OPT_MTU: + if (rp.result == L2CAP_UNKNOWN_OPTION) + break; + + if (opt.length != L2CAP_OPT_MTU_SIZE) + goto reject; + + m_copydata(m, 0, L2CAP_OPT_MTU_SIZE, (caddr_t)&val); + val.mtu = letoh16(val.mtu); + + /* + * XXX how do we know what the minimum acceptable MTU is + * for a channel? Spec says some profiles have a higher + * minimum but I have no way to find that out at this + * juncture.. + */ + if (val.mtu < L2CAP_MTU_MINIMUM) { + if (len + sizeof(opt) + L2CAP_OPT_MTU_SIZE > sizeof(buf)) + goto reject; + + rp.result = L2CAP_UNACCEPTABLE_PARAMS; + memcpy(buf + len, &opt, sizeof(opt)); + len += sizeof(opt); + val.mtu = htole16(L2CAP_MTU_MINIMUM); + memcpy(buf + len, &val, L2CAP_OPT_MTU_SIZE); + len += L2CAP_OPT_MTU_SIZE; + } else + chan->lc_omtu = val.mtu; + + break; + + case L2CAP_OPT_FLUSH_TIMO: + if (rp.result == L2CAP_UNKNOWN_OPTION) + break; + + if (opt.length != L2CAP_OPT_FLUSH_TIMO_SIZE) + goto reject; + + /* + * I think that this is informational only - he is + * informing us of the flush timeout he will be using. + * I dont think this affects us in any significant way, + * so just ignore this value for now. + */ + break; + + case L2CAP_OPT_QOS: + default: + /* ignore hints */ + if (opt.type & L2CAP_OPT_HINT_BIT) + break; + + /* unknown options supercede all else */ + if (rp.result != L2CAP_UNKNOWN_OPTION) { + rp.result = L2CAP_UNKNOWN_OPTION; + len = sizeof(rp); + } + + /* ignore if it don't fit */ + if (len + sizeof(opt) > sizeof(buf)) + break; + + /* return unknown option type, but no data */ + buf[len++] = opt.type; + buf[len++] = 0; + break; + } + + m_adj(m, opt.length); + left -= opt.length; + } + + rp.result = htole16(rp.result); + memcpy(buf, &rp, sizeof(rp)); + l2cap_send_signal(link, L2CAP_CONFIG_RSP, cmd.ident, len, buf); + + if ((cp.flags & L2CAP_OPT_CFLAG_BIT) == 0 + && rp.result == letoh16(L2CAP_SUCCESS)) { + + chan->lc_flags &= ~L2CAP_WAIT_CONFIG_REQ; + + if ((chan->lc_flags & L2CAP_WAIT_CONFIG_RSP) == 0) { + chan->lc_state = L2CAP_OPEN; + /* XXX how to distinguish REconfiguration? */ + (*chan->lc_proto->connected)(chan->lc_upper); + } + } + return; + +reject: + l2cap_send_command_rej(link, cmd.ident, L2CAP_REJ_NOT_UNDERSTOOD); +out: + m_adj(m, left); +} + +/* + * Process Received Config Response. + */ +static void +l2cap_recv_config_rsp(struct mbuf *m, struct hci_link *link) +{ + l2cap_cmd_hdr_t cmd; + l2cap_cfg_rsp_cp cp; + l2cap_cfg_opt_t opt; + l2cap_cfg_opt_val_t val; + struct l2cap_req *req; + struct l2cap_channel *chan; + int left; + + m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); + m_adj(m, sizeof(cmd)); + left = letoh16(cmd.length); + + if (left < sizeof(cp)) + goto out; + + m_copydata(m, 0, sizeof(cp), (caddr_t)&cp); + m_adj(m, sizeof(cp)); + left -= sizeof(cp); + + cp.scid = letoh16(cp.scid); + cp.flags = letoh16(cp.flags); + cp.result = letoh16(cp.result); + + req = l2cap_request_lookup(link, cmd.ident); + if (req == NULL || req->lr_code != L2CAP_CONFIG_REQ) + goto out; + + chan = req->lr_chan; + if (chan != NULL && chan->lc_lcid != cp.scid) + goto out; + + l2cap_request_free(req); + + if (chan == NULL || chan->lc_state != L2CAP_WAIT_CONFIG + || (chan->lc_flags & L2CAP_WAIT_CONFIG_RSP) == 0) + goto out; + + if ((cp.flags & L2CAP_OPT_CFLAG_BIT)) { + l2cap_cfg_req_cp rp; + + /* + * They have more to tell us and want another ID to + * use, so send an empty config request + */ + if (l2cap_request_alloc(chan, L2CAP_CONFIG_REQ)) + goto discon; + + rp.dcid = htole16(cp.scid); + rp.flags = 0; + + if (l2cap_send_signal(link, L2CAP_CONFIG_REQ, link->hl_lastid, + sizeof(rp), &rp)) + goto discon; + } + + switch(cp.result) { + case L2CAP_SUCCESS: + /* + * If continuation flag was not set, our config request was + * accepted. We may have to wait for their config request to + * complete, so check that but otherwise we are open + * + * There may be 'advisory' values in the packet but we just + * ignore those.. + */ + if ((cp.flags & L2CAP_OPT_CFLAG_BIT) == 0) { + chan->lc_flags &= ~L2CAP_WAIT_CONFIG_RSP; + + if ((chan->lc_flags & L2CAP_WAIT_CONFIG_REQ) == 0) { + chan->lc_state = L2CAP_OPEN; + /* XXX how to distinguish REconfiguration? */ + (*chan->lc_proto->connected)(chan->lc_upper); + } + } + goto out; + + case L2CAP_UNACCEPTABLE_PARAMS: + /* + * Packet contains unacceptable parameters with preferred values + */ + while (left > 0) { + if (left < sizeof(opt)) + goto discon; + + m_copydata(m, 0, sizeof(opt), (caddr_t)&opt); + m_adj(m, sizeof(opt)); + left -= sizeof(opt); + + if (left < opt.length) + goto discon; + + switch (opt.type) { + case L2CAP_OPT_MTU: + if (opt.length != L2CAP_OPT_MTU_SIZE) + goto discon; + + m_copydata(m, 0, L2CAP_OPT_MTU_SIZE, (caddr_t)&val); + chan->lc_imtu = letoh16(val.mtu); + if (chan->lc_imtu < L2CAP_MTU_MINIMUM) + chan->lc_imtu = L2CAP_MTU_DEFAULT; + break; + + case L2CAP_OPT_FLUSH_TIMO: + if (opt.length != L2CAP_OPT_FLUSH_TIMO_SIZE) + goto discon; + + /* + * Spec says: If we cannot honor proposed value, + * either disconnect or try again with original + * value. I can't really see why they want to + * interfere with OUR flush timeout in any case + * so we just punt for now. + */ + goto discon; + + case L2CAP_OPT_QOS: + break; + + default: + UNKNOWN(opt.type); + goto discon; + } + + m_adj(m, opt.length); + left -= opt.length; + } + + if ((cp.flags & L2CAP_OPT_CFLAG_BIT) == 0) + l2cap_send_config_req(chan); /* no state change */ + + goto out; + + case L2CAP_REJECT: + goto discon; + + case L2CAP_UNKNOWN_OPTION: + /* + * Packet contains options not understood. Turn off unknown + * options by setting them to default values (means they will + * not be requested again). + * + * If our option was already off then fail (paranoia?) + * + * XXX Should we consider that options were set for a reason? + */ + while (left > 0) { + if (left < sizeof(opt)) + goto discon; + + m_copydata(m, 0, sizeof(opt), (caddr_t)&opt); + m_adj(m, sizeof(opt)); + left -= sizeof(opt); + + if (left < opt.length) + goto discon; + + m_adj(m, opt.length); + left -= opt.length; + + switch(opt.type) { + case L2CAP_OPT_MTU: + if (chan->lc_imtu == L2CAP_MTU_DEFAULT) + goto discon; + + chan->lc_imtu = L2CAP_MTU_DEFAULT; + break; + + case L2CAP_OPT_FLUSH_TIMO: + if (chan->lc_flush == L2CAP_FLUSH_TIMO_DEFAULT) + goto discon; + + chan->lc_flush = L2CAP_FLUSH_TIMO_DEFAULT; + break; + + case L2CAP_OPT_QOS: + break; + + default: + UNKNOWN(opt.type); + goto discon; + } + } + + if ((cp.flags & L2CAP_OPT_CFLAG_BIT) == 0) + l2cap_send_config_req(chan); /* no state change */ + + goto out; + + default: + UNKNOWN(cp.result); + goto discon; + } + + DPRINTF("how did I get here!?\n"); + +discon: + l2cap_send_disconnect_req(chan); + l2cap_close(chan, ECONNABORTED); + +out: + m_adj(m, left); +} + +/* + * Process Received Disconnect Request. We must validate scid and dcid + * just in case but otherwise this connection is finished. + */ +static void +l2cap_recv_disconnect_req(struct mbuf *m, struct hci_link *link) +{ + l2cap_cmd_hdr_t cmd; + l2cap_discon_req_cp cp; + l2cap_discon_rsp_cp rp; + struct l2cap_channel *chan; + + m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); + m_adj(m, sizeof(cmd)); + + m_copydata(m, 0, sizeof(cp), (caddr_t)&cp); + m_adj(m, sizeof(cp)); + + cp.scid = letoh16(cp.scid); + cp.dcid = letoh16(cp.dcid); + + chan = l2cap_cid_lookup(cp.dcid); + if (chan == NULL || chan->lc_link != link || chan->lc_rcid != cp.scid) { + l2cap_send_command_rej(link, cmd.ident, L2CAP_REJ_INVALID_CID, + cp.dcid, cp.scid); + return; + } + + rp.dcid = htole16(chan->lc_lcid); + rp.scid = htole16(chan->lc_rcid); + l2cap_send_signal(link, L2CAP_DISCONNECT_RSP, cmd.ident, + sizeof(rp), &rp); + + if (chan->lc_state != L2CAP_CLOSED) + l2cap_close(chan, ECONNRESET); +} + +/* + * Process Received Disconnect Response. We must validate scid and dcid but + * unless we were waiting for this signal, ignore it. + */ +static void +l2cap_recv_disconnect_rsp(struct mbuf *m, struct hci_link *link) +{ + l2cap_cmd_hdr_t cmd; + l2cap_discon_rsp_cp cp; + struct l2cap_req *req; + struct l2cap_channel *chan; + + m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); + m_adj(m, sizeof(cmd)); + + m_copydata(m, 0, sizeof(cp), (caddr_t)&cp); + m_adj(m, sizeof(cp)); + + cp.scid = letoh16(cp.scid); + cp.dcid = letoh16(cp.dcid); + + req = l2cap_request_lookup(link, cmd.ident); + if (req == NULL || req->lr_code != L2CAP_DISCONNECT_REQ) + return; + + chan = req->lr_chan; + if (chan == NULL + || chan->lc_lcid != cp.scid + || chan->lc_rcid != cp.dcid) + return; + + l2cap_request_free(req); + + if (chan->lc_state != L2CAP_WAIT_DISCONNECT) + return; + + l2cap_close(chan, 0); +} + +/* + * Process Received Info Request. We must respond but alas dont + * support anything as yet so thats easy. + */ +static void +l2cap_recv_info_req(struct mbuf *m, struct hci_link *link) +{ + l2cap_cmd_hdr_t cmd; + l2cap_info_req_cp cp; + l2cap_info_rsp_cp rp; + + m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); + m_adj(m, sizeof(cmd)); + + m_copydata(m, 0, sizeof(cp), (caddr_t)&cp); + m_adj(m, sizeof(cp)); + + switch(letoh16(cp.type)) { + case L2CAP_CONNLESS_MTU: + case L2CAP_EXTENDED_FEATURES: + default: + rp.type = cp.type; + rp.result = htole16(L2CAP_NOT_SUPPORTED); + + l2cap_send_signal(link, L2CAP_INFO_RSP, cmd.ident, + sizeof(rp), &rp); + break; + } +} + +/* + * Construct signal and wrap in C-Frame for link. + */ +static int +l2cap_send_signal(struct hci_link *link, uint8_t code, uint8_t ident, + uint16_t length, void *data) +{ + struct mbuf *m; + l2cap_hdr_t *hdr; + l2cap_cmd_hdr_t *cmd; + +#ifdef DIAGNOSTIC + if (link == NULL) + return ENETDOWN; + + if (sizeof(l2cap_cmd_hdr_t) + length > link->hl_mtu) + printf("(%s) exceeding L2CAP Signal MTU for link!\n", + link->hl_unit->hci_devname); +#endif + + m = m_gethdr(M_DONTWAIT, MT_DATA); + if (m == NULL) + return ENOMEM; + + hdr = mtod(m, l2cap_hdr_t *); + cmd = (l2cap_cmd_hdr_t *)(hdr + 1); + + m->m_len = m->m_pkthdr.len = MHLEN; + + /* Command Data */ + if (length > 0) + m_copyback(m, sizeof(*hdr) + sizeof(*cmd), length, data); + + /* Command Header */ + cmd->code = code; + cmd->ident = ident; + cmd->length = htole16(length); + length += sizeof(*cmd); + + /* C-Frame Header */ + hdr->length = htole16(length); + hdr->dcid = htole16(L2CAP_SIGNAL_CID); + length += sizeof(*hdr); + + if (m->m_pkthdr.len != MAX(MHLEN, length)) { + m_freem(m); + return ENOMEM; + } + + m->m_pkthdr.len = length; + m->m_len = MIN(length, MHLEN); + + DPRINTFN(2, "(%s) code %d, ident %d, len %d\n", + link->hl_unit->hci_devname, code, ident, length); + + return hci_acl_send(m, link, NULL); +} + +/* + * Send Command Reject packet. + */ +static int +l2cap_send_command_rej(struct hci_link *link, uint8_t ident, + uint16_t reason, ...) +{ + l2cap_cmd_rej_cp cp; + int len = 0; + va_list ap; + + va_start(ap, reason); + + cp.reason = htole16(reason); + + switch (reason) { + case L2CAP_REJ_NOT_UNDERSTOOD: + len = 2; + break; + + case L2CAP_REJ_MTU_EXCEEDED: + len = 4; + cp.data[0] = va_arg(ap, int); /* SigMTU */ + cp.data[0] = htole16(cp.data[0]); + break; + + case L2CAP_REJ_INVALID_CID: + len = 6; + cp.data[0] = va_arg(ap, int); /* dcid */ + cp.data[0] = htole16(cp.data[0]); + cp.data[1] = va_arg(ap, int); /* scid */ + cp.data[1] = htole16(cp.data[1]); + break; + + default: + UNKNOWN(reason); + return EINVAL; + } + + va_end(ap); + + return l2cap_send_signal(link, L2CAP_COMMAND_REJ, ident, len, &cp); +} + +/* + * Send Connect Request + */ +int +l2cap_send_connect_req(struct l2cap_channel *chan) +{ + l2cap_con_req_cp cp; + int err; + + err = l2cap_request_alloc(chan, L2CAP_CONNECT_REQ); + if (err) + return err; + + cp.psm = htole16(chan->lc_raddr.bt_psm); + cp.scid = htole16(chan->lc_lcid); + + return l2cap_send_signal(chan->lc_link, L2CAP_CONNECT_REQ, + chan->lc_link->hl_lastid, sizeof(cp), &cp); +} + +/* + * Send Config Request + * + * For outgoing config request, we only put options in the packet if they + * differ from the default and would have to be actioned. We dont support + * enough option types to make overflowing SigMTU an issue so it can all + * go in one packet. + */ +int +l2cap_send_config_req(struct l2cap_channel *chan) +{ + l2cap_cfg_req_cp *cp; + l2cap_cfg_opt_t *opt; + l2cap_cfg_opt_val_t *val; + uint8_t *next, buf[L2CAP_MTU_MINIMUM]; + int err; + + err = l2cap_request_alloc(chan, L2CAP_CONFIG_REQ); + if (err) + return err; + + /* Config Header (4 octets) */ + cp = (l2cap_cfg_req_cp *)buf; + cp->dcid = htole16(chan->lc_rcid); + cp->flags = 0; /* "No Continuation" */ + + next = buf + sizeof(l2cap_cfg_req_cp); + + /* Incoming MTU (4 octets) */ + if (chan->lc_imtu != L2CAP_MTU_DEFAULT) { + opt = (l2cap_cfg_opt_t *)next; + opt->type = L2CAP_OPT_MTU; + opt->length = L2CAP_OPT_MTU_SIZE; + + val = (l2cap_cfg_opt_val_t *)(opt + 1); + val->mtu = htole16(chan->lc_imtu); + + next += sizeof(l2cap_cfg_opt_t) + L2CAP_OPT_MTU_SIZE; + } + + /* Flush Timeout (4 octets) */ + if (chan->lc_flush != L2CAP_FLUSH_TIMO_DEFAULT) { + opt = (l2cap_cfg_opt_t *)next; + opt->type = L2CAP_OPT_FLUSH_TIMO; + opt->length = L2CAP_OPT_FLUSH_TIMO_SIZE; + + val = (l2cap_cfg_opt_val_t *)(opt + 1); + val->flush_timo = htole16(chan->lc_flush); + + next += sizeof(l2cap_cfg_opt_t) + L2CAP_OPT_FLUSH_TIMO_SIZE; + } + + /* Outgoing QoS Flow (24 octets) */ + /* Retransmission & Flow Control (11 octets) */ + /* + * From here we need to start paying attention to SigMTU as we have + * possibly overflowed the minimum supported.. + */ + + return l2cap_send_signal(chan->lc_link, L2CAP_CONFIG_REQ, + chan->lc_link->hl_lastid, (int)(next - buf), buf); +} + +/* + * Send Disconnect Request + */ +int +l2cap_send_disconnect_req(struct l2cap_channel *chan) +{ + l2cap_discon_req_cp cp; + int err; + + err = l2cap_request_alloc(chan, L2CAP_DISCONNECT_REQ); + if (err) + return err; + + cp.dcid = htole16(chan->lc_rcid); + cp.scid = htole16(chan->lc_lcid); + + return l2cap_send_signal(chan->lc_link, L2CAP_DISCONNECT_REQ, + chan->lc_link->hl_lastid, sizeof(cp), &cp); +} + +/* + * Send Connect Response + */ +int +l2cap_send_connect_rsp(struct hci_link *link, uint8_t ident, uint16_t dcid, uint16_t scid, uint16_t result) +{ + l2cap_con_rsp_cp cp; + + memset(&cp, 0, sizeof(cp)); + cp.dcid = htole16(dcid); + cp.scid = htole16(scid); + cp.result = htole16(result); + + return l2cap_send_signal(link, L2CAP_CONNECT_RSP, ident, sizeof(cp), &cp); +} diff --git a/sys/netbt/l2cap_var.h b/sys/netbt/l2cap_var.h deleted file mode 100644 index 8ce22fcb8e8..00000000000 --- a/sys/netbt/l2cap_var.h +++ /dev/null @@ -1,215 +0,0 @@ -/* $OpenBSD: l2cap_var.h,v 1.2 2005/01/17 18:12:49 mickey Exp $ */ - -/* - * ng_btsocket_l2cap.h - * - * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h,v 1.3 2003/11/14 03:45:29 emax Exp $ - */ - -#ifndef _NETGRAPH_BTSOCKET_L2CAP_H_ -#define _NETGRAPH_BTSOCKET_L2CAP_H_ - -#include <sys/timeout.h> - -/* - * L2CAP routing entry - */ - -struct ng_hook; -struct ng_message; - -struct ng_btsocket_l2cap_rtentry { - bdaddr_t src; /* source BD_ADDR */ - struct ng_hook *hook; /* downstream hook */ - LIST_ENTRY(ng_btsocket_l2cap_rtentry) next; /* link to next */ -}; -typedef struct ng_btsocket_l2cap_rtentry ng_btsocket_l2cap_rtentry_t; -typedef struct ng_btsocket_l2cap_rtentry * ng_btsocket_l2cap_rtentry_p; - -/***************************************************************************** - ***************************************************************************** - ** SOCK_RAW L2CAP sockets ** - ***************************************************************************** - *****************************************************************************/ - -#define NG_BTSOCKET_L2CAP_RAW_SENDSPACE NG_L2CAP_MTU_DEFAULT -#define NG_BTSOCKET_L2CAP_RAW_RECVSPACE NG_L2CAP_MTU_DEFAULT - -/* - * Bluetooth raw L2CAP socket PCB - */ - -struct ng_btsocket_l2cap_raw_pcb { - struct socket *so; /* socket */ - - u_int32_t flags; /* flags */ -#define NG_BTSOCKET_L2CAP_RAW_PRIVILEGED (1 << 0) - - bdaddr_t src; /* source address */ - bdaddr_t dst; /* dest address */ - ng_btsocket_l2cap_rtentry_p rt; /* routing info */ - - u_int32_t token; /* message token */ - struct ng_mesg *msg; /* message */ - -#if 0 - struct mtx pcb_mtx; /* pcb mutex */ -#endif - - LIST_ENTRY(ng_btsocket_l2cap_raw_pcb) next; /* link to next PCB */ -}; -typedef struct ng_btsocket_l2cap_raw_pcb ng_btsocket_l2cap_raw_pcb_t; -typedef struct ng_btsocket_l2cap_raw_pcb * ng_btsocket_l2cap_raw_pcb_p; - -#define so2l2cap_raw_pcb(so) \ - ((struct ng_btsocket_l2cap_raw_pcb *)((so)->so_pcb)) - -/* - * Bluetooth raw L2CAP socket methods - */ - -#ifdef _KERNEL - -void l2cap_raw_init(void); -int ng_btsocket_l2cap_raw_abort (struct socket *); -int ng_btsocket_l2cap_raw_attach (struct socket *, int, struct proc *); -int ng_btsocket_l2cap_raw_bind (struct socket *, struct sockaddr *, - struct proc *); -int ng_btsocket_l2cap_raw_connect (struct socket *, struct sockaddr *, - struct proc *); -int ng_btsocket_l2cap_raw_control (struct socket *, u_long, caddr_t, - struct ifnet *, struct proc *); -int ng_btsocket_l2cap_raw_detach (struct socket *); -int ng_btsocket_l2cap_raw_disconnect (struct socket *); -int ng_btsocket_l2cap_raw_peeraddr (struct socket *, struct sockaddr **); -int ng_btsocket_l2cap_raw_send (struct socket *, int, struct mbuf *, - struct sockaddr *, struct mbuf *, - struct proc *); -int ng_btsocket_l2cap_raw_sockaddr (struct socket *, struct sockaddr **); - -#endif /* _KERNEL */ - -/***************************************************************************** - ***************************************************************************** - ** SOCK_SEQPACKET L2CAP sockets ** - ***************************************************************************** - *****************************************************************************/ - -#define NG_BTSOCKET_L2CAP_SENDSPACE NG_L2CAP_MTU_DEFAULT /* (64 * 1024) */ -#define NG_BTSOCKET_L2CAP_RECVSPACE (64 * 1024) - -/* - * Bluetooth L2CAP socket PCB - */ - -struct ng_btsocket_l2cap_pcb { - struct socket *so; /* Pointer to socket */ - - bdaddr_t src; /* Source address */ - bdaddr_t dst; /* Destination address */ - - u_int16_t psm; /* PSM */ - u_int16_t cid; /* Local channel ID */ - - u_int16_t flags; /* socket flags */ -#define NG_BTSOCKET_L2CAP_CLIENT (1 << 0) /* socket is client */ -#define NG_BTSOCKET_L2CAP_TIMO (1 << 1) /* timeout pending */ - - u_int8_t state; /* socket state */ -#define NG_BTSOCKET_L2CAP_CLOSED 0 /* socket closed */ -#define NG_BTSOCKET_L2CAP_CONNECTING 1 /* wait for connect */ -#define NG_BTSOCKET_L2CAP_CONFIGURING 2 /* wait for config */ -#define NG_BTSOCKET_L2CAP_OPEN 3 /* socket open */ -#define NG_BTSOCKET_L2CAP_DISCONNECTING 4 /* wait for disconnect */ - - u_int8_t cfg_state; /* config state */ -#define NG_BTSOCKET_L2CAP_CFG_IN (1 << 0) /* incoming path done */ -#define NG_BTSOCKET_L2CAP_CFG_OUT (1 << 1) /* outgoing path done */ -#define NG_BTSOCKET_L2CAP_CFG_BOTH \ - (NG_BTSOCKET_L2CAP_CFG_IN | NG_BTSOCKET_L2CAP_CFG_OUT) - -#define NG_BTSOCKET_L2CAP_CFG_IN_SENT (1 << 2) /* L2CAP ConfigReq sent */ -#define NG_BTSOCKET_L2CAP_CFG_OUT_SENT (1 << 3) /* ---/--- */ - - u_int16_t imtu; /* Incoming MTU */ - ng_l2cap_flow_t iflow; /* Input flow spec */ - - u_int16_t omtu; /* Outgoing MTU */ - ng_l2cap_flow_t oflow; /* Outgoing flow spec */ - - u_int16_t flush_timo; /* flush timeout */ - u_int16_t link_timo; /* link timeout */ - - struct timeout timo; /* timeout */ - - u_int32_t token; /* message token */ - ng_btsocket_l2cap_rtentry_p rt; /* routing info */ - -#if 0 - struct mtx pcb_mtx; /* pcb mutex */ -#endif - - LIST_ENTRY(ng_btsocket_l2cap_pcb) next; /* link to next PCB */ -}; -typedef struct ng_btsocket_l2cap_pcb ng_btsocket_l2cap_pcb_t; -typedef struct ng_btsocket_l2cap_pcb * ng_btsocket_l2cap_pcb_p; - -#define so2l2cap_pcb(so) \ - ((struct ng_btsocket_l2cap_pcb *)((so)->so_pcb)) - -/* - * Bluetooth L2CAP socket methods - */ - -#ifdef _KERNEL - -void l2cap_init(void); -int ng_btsocket_l2cap_abort (struct socket *); -int ng_btsocket_l2cap_accept (struct socket *, struct sockaddr **); -int ng_btsocket_l2cap_attach (struct socket *, int, struct proc *); -int ng_btsocket_l2cap_bind (struct socket *, struct sockaddr *, - struct proc *); -int ng_btsocket_l2cap_connect (struct socket *, struct sockaddr *, - struct proc *); -int ng_btsocket_l2cap_control (struct socket *, u_long, caddr_t, - struct ifnet *, struct proc *); -int l2cap_raw_ctloutput(int, struct socket *, int, int, struct mbuf **); -int ng_btsocket_l2cap_detach (struct socket *); -int ng_btsocket_l2cap_disconnect (struct socket *); -int ng_btsocket_l2cap_listen (struct socket *, struct proc *); -int ng_btsocket_l2cap_peeraddr (struct socket *, struct sockaddr **); -int ng_btsocket_l2cap_send (struct socket *, int, struct mbuf *, - struct sockaddr *, struct mbuf *, - struct proc *); -int ng_btsocket_l2cap_sockaddr (struct socket *, struct sockaddr **); - -int l2cap_raw_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, - struct mbuf *); - -#endif /* _KERNEL */ - -#endif /* _NETGRAPH_BTSOCKET_L2CAP_H_ */ diff --git a/sys/netbt/rfcomm_var.h b/sys/netbt/rfcomm_var.h deleted file mode 100644 index 3695291a38e..00000000000 --- a/sys/netbt/rfcomm_var.h +++ /dev/null @@ -1,337 +0,0 @@ -/* $OpenBSD: rfcomm_var.h,v 1.2 2005/01/17 18:12:49 mickey Exp $ */ - -/* - * ng_btsocket_rfcomm.h - * - * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h,v 1.2 2003/11/14 03:45:29 emax Exp $ - */ - -#ifndef _NETGRAPH_BTSOCKET_RFCOMM_H_ -#define _NETGRAPH_BTSOCKET_RFCOMM_H_ - -/***************************************************************************** - ***************************************************************************** - ** RFCOMM ** - ***************************************************************************** - *****************************************************************************/ - -/* XXX FIXME this does not belong here */ - -#define RFCOMM_DEFAULT_MTU 127 -#define RFCOMM_MAX_MTU 1024 - -#define RFCOMM_DEFAULT_CREDITS 7 -#define RFCOMM_MAX_CREDITS 40 - -/* RFCOMM frame types */ -#define RFCOMM_FRAME_SABM 0x2f -#define RFCOMM_FRAME_DISC 0x43 -#define RFCOMM_FRAME_UA 0x63 -#define RFCOMM_FRAME_DM 0x0f -#define RFCOMM_FRAME_UIH 0xef - -/* RFCOMM MCC commands */ -#define RFCOMM_MCC_TEST 0x08 /* Test */ -#define RFCOMM_MCC_FCON 0x28 /* Flow Control on */ -#define RFCOMM_MCC_FCOFF 0x18 /* Flow Control off */ -#define RFCOMM_MCC_MSC 0x38 /* Modem Status Command */ -#define RFCOMM_MCC_RPN 0x24 /* Remote Port Negotiation */ -#define RFCOMM_MCC_RLS 0x14 /* Remote Line Status */ -#define RFCOMM_MCC_PN 0x20 /* Port Negotiation */ -#define RFCOMM_MCC_NSC 0x04 /* Non Supported Command */ - -/* RFCOMM modem signals */ -#define RFCOMM_MODEM_FC 0x02 /* Flow Control asserted */ -#define RFCOMM_MODEM_RTC 0x04 /* Ready To Communicate */ -#define RFCOMM_MODEM_RTR 0x08 /* Ready To Receive */ -#define RFCOMM_MODEM_IC 0x40 /* Incomming Call */ -#define RFCOMM_MODEM_DV 0x80 /* Data Valid */ - -/* RPN parameters - baud rate */ -#define RFCOMM_RPN_BR_2400 0x0 -#define RFCOMM_RPN_BR_4800 0x1 -#define RFCOMM_RPN_BR_7200 0x2 -#define RFCOMM_RPN_BR_9600 0x3 -#define RFCOMM_RPN_BR_19200 0x4 -#define RFCOMM_RPN_BR_38400 0x5 -#define RFCOMM_RPN_BR_57600 0x6 -#define RFCOMM_RPN_BR_115200 0x7 -#define RFCOMM_RPN_BR_230400 0x8 - -/* RPN parameters - data bits */ -#define RFCOMM_RPN_DATA_5 0x0 -#define RFCOMM_RPN_DATA_6 0x1 -#define RFCOMM_RPN_DATA_7 0x2 -#define RFCOMM_RPN_DATA_8 0x3 - -/* RPN parameters - stop bit */ -#define RFCOMM_RPN_STOP_1 0 -#define RFCOMM_RPN_STOP_15 1 - -/* RPN parameters - parity */ -#define RFCOMM_RPN_PARITY_NONE 0x0 -#define RFCOMM_RPN_PARITY_ODD 0x4 -#define RFCOMM_RPN_PARITY_EVEN 0x5 -#define RFCOMM_RPN_PARITY_MARK 0x6 -#define RFCOMM_RPN_PARITY_SPACE 0x7 - -/* RPN parameters - flow control */ -#define RFCOMM_RPN_FLOW_NONE 0x00 -#define RFCOMM_RPN_XON_CHAR 0x11 -#define RFCOMM_RPN_XOFF_CHAR 0x13 - -/* RPN parameters - mask */ -#define RFCOMM_RPN_PM_BITRATE 0x0001 -#define RFCOMM_RPN_PM_DATA 0x0002 -#define RFCOMM_RPN_PM_STOP 0x0004 -#define RFCOMM_RPN_PM_PARITY 0x0008 -#define RFCOMM_RPN_PM_PARITY_TYPE 0x0010 -#define RFCOMM_RPN_PM_XON 0x0020 -#define RFCOMM_RPN_PM_XOFF 0x0040 -#define RFCOMM_RPN_PM_FLOW 0x3F00 -#define RFCOMM_RPN_PM_ALL 0x3F7F - -/* RFCOMM frame header */ -struct rfcomm_frame_hdr -{ - u_int8_t address; - u_int8_t control; - u_int8_t length; /* Actual size could be 2 bytes */ -} __attribute__ ((packed)); - -/* RFCOMM command frame header */ -struct rfcomm_cmd_hdr -{ - u_int8_t address; - u_int8_t control; - u_int8_t length; - u_int8_t fcs; -} __attribute__ ((packed)); - -/* RFCOMM MCC command header */ -struct rfcomm_mcc_hdr -{ - u_int8_t type; - u_int8_t length; /* XXX FIXME Can actual size be 2 bytes?? */ -} __attribute__ ((packed)); - -/* RFCOMM MSC command */ -struct rfcomm_mcc_msc -{ - u_int8_t address; - u_int8_t modem; -} __attribute__ ((packed)); - -/* RFCOMM RPN command */ -struct rfcomm_mcc_rpn -{ - u_int8_t dlci; - u_int8_t bit_rate; - u_int8_t line_settings; - u_int8_t flow_control; - u_int8_t xon_char; - u_int8_t xoff_char; - u_int16_t param_mask; -} __attribute__ ((packed)); - -/* RFCOMM RLS command */ -struct rfcomm_mcc_rls -{ - u_int8_t address; - u_int8_t status; -} __attribute__ ((packed)); - -/* RFCOMM PN command */ -struct rfcomm_mcc_pn -{ - u_int8_t dlci; - u_int8_t flow_control; - u_int8_t priority; - u_int8_t ack_timer; - u_int16_t mtu; - u_int8_t max_retrans; - u_int8_t credits; -} __attribute__ ((packed)); - -/* RFCOMM frame parsing macros */ -#define RFCOMM_DLCI(b) (((b) & 0xfc) >> 2) -#define RFCOMM_CHANNEL(b) (((b) & 0xf8) >> 3) -#define RFCOMM_DIRECTION(b) (((b) & 0x04) >> 2) -#define RFCOMM_TYPE(b) (((b) & 0xef)) - -#define RFCOMM_EA(b) (((b) & 0x01)) -#define RFCOMM_CR(b) (((b) & 0x02) >> 1) -#define RFCOMM_PF(b) (((b) & 0x10) >> 4) - -#define RFCOMM_SRVCHANNEL(dlci) ((dlci) >> 1) - -#define RFCOMM_MKADDRESS(cr, dlci) \ - ((((dlci) & 0x3f) << 2) | ((cr) << 1) | 0x01) - -#define RFCOMM_MKCONTROL(type, pf) ((((type) & 0xef) | ((pf) << 4))) -#define RFCOMM_MKDLCI(dir, channel) ((((channel) & 0x1f) << 1) | (dir)) - -#define RFCOMM_MKLEN8(len) (((len) << 1) | 1) -#define RFCOMM_MKLEN16(len) ((len) << 1) - -/* RFCOMM MCC macros */ -#define RFCOMM_MCC_TYPE(b) (((b) & 0xfc) >> 2) -#define RFCOMM_MCC_LENGTH(b) (((b) & 0xfe) >> 1) -#define RFCOMM_MKMCC_TYPE(cr, type) ((((type) << 2) | ((cr) << 1) | 0x01)) - -/* RPN macros */ -#define RFCOMM_RPN_DATA_BITS(line) ((line) & 0x3) -#define RFCOMM_RPN_STOP_BITS(line) (((line) >> 2) & 0x1) -#define RFCOMM_RPN_PARITY(line) (((line) >> 3) & 0x3) -#define RFCOMM_MKRPN_LINE_SETTINGS(data, stop, parity) \ - (((data) & 0x3) | (((stop) & 0x1) << 2) | (((parity) & 0x3) << 3)) - -/***************************************************************************** - ***************************************************************************** - ** SOCK_STREAM RFCOMM sockets ** - ***************************************************************************** - *****************************************************************************/ - -#define NG_BTSOCKET_RFCOMM_SENDSPACE \ - (RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10) -#define NG_BTSOCKET_RFCOMM_RECVSPACE \ - (RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10) - -/* - * Bluetooth RFCOMM session. One L2CAP connection == one RFCOMM session - */ - -struct ng_btsocket_rfcomm_pcb; -struct ng_btsocket_rfcomm_session; - -struct ng_btsocket_rfcomm_session { - struct socket *l2so; /* L2CAP socket */ - - u_int16_t state; /* session state */ -#define NG_BTSOCKET_RFCOMM_SESSION_CLOSED 0 -#define NG_BTSOCKET_RFCOMM_SESSION_LISTENING 1 -#define NG_BTSOCKET_RFCOMM_SESSION_CONNECTING 2 -#define NG_BTSOCKET_RFCOMM_SESSION_CONNECTED 3 -#define NG_BTSOCKET_RFCOMM_SESSION_OPEN 4 -#define NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING 5 - - u_int16_t flags; /* session flags */ -#define NG_BTSOCKET_RFCOMM_SESSION_INITIATOR (1 << 0) /* initiator */ -#define NG_BTSOCKET_RFCOMM_SESSION_LFC (1 << 1) /* local flow */ -#define NG_BTSOCKET_RFCOMM_SESSION_RFC (1 << 2) /* remote flow */ - -#define INITIATOR(s) \ - (((s)->flags & NG_BTSOCKET_RFCOMM_SESSION_INITIATOR)? 1 : 0) - - u_int16_t mtu; /* default MTU */ - struct ng_bt_mbufq outq; /* outgoing queue */ - - struct mtx session_mtx; /* session lock */ - LIST_HEAD(, ng_btsocket_rfcomm_pcb) dlcs; /* active DLC */ - - LIST_ENTRY(ng_btsocket_rfcomm_session) next; /* link to next */ -}; -typedef struct ng_btsocket_rfcomm_session ng_btsocket_rfcomm_session_t; -typedef struct ng_btsocket_rfcomm_session * ng_btsocket_rfcomm_session_p; - -/* - * Bluetooth RFCOMM socket PCB (DLC) - */ - -struct ng_btsocket_rfcomm_pcb { - struct socket *so; /* RFCOMM socket */ - struct ng_btsocket_rfcomm_session *session; /* RFCOMM session */ - - u_int16_t flags; /* DLC flags */ -#define NG_BTSOCKET_RFCOMM_DLC_TIMO (1 << 0) /* timeout pending */ -#define NG_BTSOCKET_RFCOMM_DLC_CFC (1 << 1) /* credit flow ctrl */ -#define NG_BTSOCKET_RFCOMM_DLC_TIMEDOUT (1 << 2) /* timeout happend */ -#define NG_BTSOCKET_RFCOMM_DLC_DETACHED (1 << 3) /* DLC detached */ -#define NG_BTSOCKET_RFCOMM_DLC_SENDING (1 << 4) /* send pending */ - - u_int16_t state; /* DLC state */ -#define NG_BTSOCKET_RFCOMM_DLC_CLOSED 0 -#define NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT 1 -#define NG_BTSOCKET_RFCOMM_DLC_CONFIGURING 2 -#define NG_BTSOCKET_RFCOMM_DLC_CONNECTING 3 -#define NG_BTSOCKET_RFCOMM_DLC_CONNECTED 4 -#define NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING 5 - - bdaddr_t src; /* source address */ - bdaddr_t dst; /* dest. address */ - - u_int8_t channel; /* RFCOMM channel */ - u_int8_t dlci; /* RFCOMM DLCI */ - - u_int8_t lmodem; /* local mdm signls */ - u_int8_t rmodem; /* remote -/- */ - - u_int16_t mtu; /* MTU */ - int16_t rx_cred; /* RX credits */ - int16_t tx_cred; /* TX credits */ - - struct mtx pcb_mtx; /* PCB lock */ - struct callout_handle timo; /* timeout */ - - LIST_ENTRY(ng_btsocket_rfcomm_pcb) session_next;/* link to next */ - LIST_ENTRY(ng_btsocket_rfcomm_pcb) next; /* link to next */ -}; -typedef struct ng_btsocket_rfcomm_pcb ng_btsocket_rfcomm_pcb_t; -typedef struct ng_btsocket_rfcomm_pcb * ng_btsocket_rfcomm_pcb_p; - -#define so2rfcomm_pcb(so) \ - ((struct ng_btsocket_rfcomm_pcb *)((so)->so_pcb)) - -/* - * Bluetooth RFCOMM socket methods - */ - -#ifdef _KERNEL - -void ng_btsocket_rfcomm_init (void); -int ng_btsocket_rfcomm_abort (struct socket *); -int ng_btsocket_rfcomm_accept (struct socket *, struct sockaddr **); -int ng_btsocket_rfcomm_attach (struct socket *, int, struct thread *); -int ng_btsocket_rfcomm_bind (struct socket *, struct sockaddr *, - struct thread *); -int ng_btsocket_rfcomm_connect (struct socket *, struct sockaddr *, - struct thread *); -int ng_btsocket_rfcomm_control (struct socket *, u_long, caddr_t, - struct ifnet *, struct thread *); -int ng_btsocket_rfcomm_ctloutput (struct socket *, struct sockopt *); -int ng_btsocket_rfcomm_detach (struct socket *); -int ng_btsocket_rfcomm_disconnect (struct socket *); -int ng_btsocket_rfcomm_listen (struct socket *, struct thread *); -int ng_btsocket_rfcomm_peeraddr (struct socket *, struct sockaddr **); -int ng_btsocket_rfcomm_send (struct socket *, int, struct mbuf *, - struct sockaddr *, struct mbuf *, - struct thread *); -int ng_btsocket_rfcomm_sockaddr (struct socket *, struct sockaddr **); - -#endif /* _KERNEL */ - -#endif /* _NETGRAPH_BTSOCKET_RFCOMM_H_ */ diff --git a/sys/netbt/sco.h b/sys/netbt/sco.h new file mode 100644 index 00000000000..0d0be27ff5c --- /dev/null +++ b/sys/netbt/sco.h @@ -0,0 +1,86 @@ +/* $OpenBSD: sco.h,v 1.1 2007/05/30 03:42:53 uwe Exp $ */ +/* $NetBSD: sco.h,v 1.2 2006/07/26 10:20:56 tron Exp $ */ + +/*- + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _NETBT_SCO_H_ +#define _NETBT_SCO_H_ + +#define SO_SCO_MTU 1 +#define SO_SCO_HANDLE 2 + +#ifdef _KERNEL +/* + * SCO protocol control block + */ +struct sco_pcb { + struct hci_link *sp_link; /* SCO link */ + unsigned int sp_flags; /* flags */ + bdaddr_t sp_laddr; /* local address */ + bdaddr_t sp_raddr; /* remote address */ + unsigned int sp_mtu; /* link MTU */ + int sp_pending; /* number of packets pending */ + + const struct btproto *sp_proto; /* upper layer protocol */ + void *sp_upper; /* upper layer argument */ + + LIST_ENTRY(sco_pcb) sp_next; +}; + +LIST_HEAD(sco_pcb_list, sco_pcb); +extern struct sco_pcb_list sco_pcb; + +/* sp_flags */ +#define SP_LISTENING (1<<0) /* is listening pcb */ + +/* sco_socket.c */ +struct socket; +extern int sco_sendspace; +extern int sco_recvspace; +int sco_usrreq(struct socket *, int, struct mbuf *, + struct mbuf *, struct mbuf *, struct proc *); +int sco_ctloutput(int, struct socket *, int, int, struct mbuf **); + +/* sco_upper.c */ +int sco_attach(struct sco_pcb **, const struct btproto *, void *); +int sco_bind(struct sco_pcb *, struct sockaddr_bt *); +int sco_sockaddr(struct sco_pcb *, struct sockaddr_bt *); +int sco_connect(struct sco_pcb *, struct sockaddr_bt *); +int sco_peeraddr(struct sco_pcb *, struct sockaddr_bt *); +int sco_disconnect(struct sco_pcb *, int); +int sco_detach(struct sco_pcb **); +int sco_listen(struct sco_pcb *); +int sco_send(struct sco_pcb *, struct mbuf *); +int sco_setopt(struct sco_pcb *, int, void *); +int sco_getopt(struct sco_pcb *, int, void *); + +#endif /* _KERNEL */ + +#endif /* _NETBT_SCO_H_ */ |