xref: /dflybsd-src/sys/netgraph7/bluetooth/hci/ng_hci_misc.c (revision b5523eac31a95e6876e05e20e6fe836ec3a45202)
1b06ebda0SMatthew Dillon /*
2b06ebda0SMatthew Dillon  * ng_hci_misc.c
3b06ebda0SMatthew Dillon  */
4b06ebda0SMatthew Dillon 
5b06ebda0SMatthew Dillon /*-
6b06ebda0SMatthew Dillon  * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
7b06ebda0SMatthew Dillon  * All rights reserved.
8b06ebda0SMatthew Dillon  *
9b06ebda0SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
10b06ebda0SMatthew Dillon  * modification, are permitted provided that the following conditions
11b06ebda0SMatthew Dillon  * are met:
12b06ebda0SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
13b06ebda0SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
14b06ebda0SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
15b06ebda0SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in the
16b06ebda0SMatthew Dillon  *    documentation and/or other materials provided with the distribution.
17b06ebda0SMatthew Dillon  *
18b06ebda0SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19b06ebda0SMatthew Dillon  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20b06ebda0SMatthew Dillon  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21b06ebda0SMatthew Dillon  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22b06ebda0SMatthew Dillon  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23b06ebda0SMatthew Dillon  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24b06ebda0SMatthew Dillon  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25b06ebda0SMatthew Dillon  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26b06ebda0SMatthew Dillon  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27b06ebda0SMatthew Dillon  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28b06ebda0SMatthew Dillon  * SUCH DAMAGE.
29b06ebda0SMatthew Dillon  *
30b06ebda0SMatthew Dillon  * $Id: ng_hci_misc.c,v 1.5 2003/09/08 18:57:51 max Exp $
31b06ebda0SMatthew Dillon  * $FreeBSD: src/sys/netgraph/bluetooth/hci/ng_hci_misc.c,v 1.10 2005/01/07 01:45:43 imp Exp $
32b06ebda0SMatthew Dillon  */
33b06ebda0SMatthew Dillon 
34b06ebda0SMatthew Dillon #include <sys/param.h>
35b06ebda0SMatthew Dillon #include <sys/systm.h>
36b06ebda0SMatthew Dillon #include <sys/kernel.h>
37b06ebda0SMatthew Dillon #include <sys/malloc.h>
38b06ebda0SMatthew Dillon #include <sys/mbuf.h>
39b06ebda0SMatthew Dillon #include <sys/queue.h>
40e85b99abSSascha Wildner #include <netgraph7/ng_message.h>
41e85b99abSSascha Wildner #include <netgraph7/netgraph.h>
42e85b99abSSascha Wildner #include <netgraph7/bluetooth/include/ng_bluetooth.h>
43e85b99abSSascha Wildner #include <netgraph7/bluetooth/include/ng_hci.h>
44e85b99abSSascha Wildner #include <netgraph7/bluetooth/hci/ng_hci_var.h>
45e85b99abSSascha Wildner #include <netgraph7/bluetooth/hci/ng_hci_cmds.h>
46e85b99abSSascha Wildner #include <netgraph7/bluetooth/hci/ng_hci_evnt.h>
47e85b99abSSascha Wildner #include <netgraph7/bluetooth/hci/ng_hci_ulpi.h>
48e85b99abSSascha Wildner #include <netgraph7/bluetooth/hci/ng_hci_misc.h>
49b06ebda0SMatthew Dillon 
50b06ebda0SMatthew Dillon /******************************************************************************
51b06ebda0SMatthew Dillon  ******************************************************************************
52b06ebda0SMatthew Dillon  **                              Utility routines
53b06ebda0SMatthew Dillon  ******************************************************************************
54b06ebda0SMatthew Dillon  ******************************************************************************/
55b06ebda0SMatthew Dillon 
56b06ebda0SMatthew Dillon /*
57b06ebda0SMatthew Dillon  * Give packet to RAW hook
58b06ebda0SMatthew Dillon  * Assumes input mbuf is read only.
59b06ebda0SMatthew Dillon  */
60b06ebda0SMatthew Dillon 
61b06ebda0SMatthew Dillon void
ng_hci_mtap(ng_hci_unit_p unit,struct mbuf * m0)62b06ebda0SMatthew Dillon ng_hci_mtap(ng_hci_unit_p unit, struct mbuf *m0)
63b06ebda0SMatthew Dillon {
64b06ebda0SMatthew Dillon 	struct mbuf	*m = NULL;
65b06ebda0SMatthew Dillon 	int		 error = 0;
66b06ebda0SMatthew Dillon 
67b06ebda0SMatthew Dillon 	if (unit->raw != NULL && NG_HOOK_IS_VALID(unit->raw)) {
68*b5523eacSSascha Wildner 		m = m_dup(m0, M_NOWAIT);
69b06ebda0SMatthew Dillon 		if (m != NULL)
70b06ebda0SMatthew Dillon 			NG_SEND_DATA_ONLY(error, unit->raw, m);
71b06ebda0SMatthew Dillon 
72b06ebda0SMatthew Dillon 		if (error != 0)
73b06ebda0SMatthew Dillon 			NG_HCI_INFO(
74b06ebda0SMatthew Dillon "%s: %s - Could not forward packet, error=%d\n",
75b06ebda0SMatthew Dillon 				__func__, NG_NODE_NAME(unit->node), error);
76b06ebda0SMatthew Dillon 	}
77b06ebda0SMatthew Dillon } /* ng_hci_mtap */
78b06ebda0SMatthew Dillon 
79b06ebda0SMatthew Dillon /*
80b06ebda0SMatthew Dillon  * Send notification to the upper layer's
81b06ebda0SMatthew Dillon  */
82b06ebda0SMatthew Dillon 
83b06ebda0SMatthew Dillon void
ng_hci_node_is_up(node_p node,hook_p hook,void * arg1,int arg2)84b06ebda0SMatthew Dillon ng_hci_node_is_up(node_p node, hook_p hook, void *arg1, int arg2)
85b06ebda0SMatthew Dillon {
86b06ebda0SMatthew Dillon 	ng_hci_unit_p		 unit = NULL;
87b06ebda0SMatthew Dillon 	struct ng_mesg		*msg = NULL;
88b06ebda0SMatthew Dillon 	ng_hci_node_up_ep	*ep = NULL;
89b06ebda0SMatthew Dillon 	int			 error;
90b06ebda0SMatthew Dillon 
91b06ebda0SMatthew Dillon 	if (node == NULL || NG_NODE_NOT_VALID(node) ||
92b06ebda0SMatthew Dillon 	    hook == NULL || NG_HOOK_NOT_VALID(hook))
93b06ebda0SMatthew Dillon 		return;
94b06ebda0SMatthew Dillon 
95b06ebda0SMatthew Dillon 	unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node);
96b06ebda0SMatthew Dillon 	if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY)
97b06ebda0SMatthew Dillon 		return;
98b06ebda0SMatthew Dillon 
99b06ebda0SMatthew Dillon 	if (hook != unit->acl && hook != unit->sco)
100b06ebda0SMatthew Dillon 		return;
101b06ebda0SMatthew Dillon 
1025a975a3dSMatthew Dillon 	NG_MKMESSAGE(msg,NGM_HCI_COOKIE,NGM_HCI_NODE_UP,sizeof(*ep),M_WAITOK | M_NULLOK);
103b06ebda0SMatthew Dillon 	if (msg != NULL) {
104b06ebda0SMatthew Dillon 		ep = (ng_hci_node_up_ep *)(msg->data);
105b06ebda0SMatthew Dillon 
106b06ebda0SMatthew Dillon 		if (hook == unit->acl) {
107b06ebda0SMatthew Dillon 			NG_HCI_BUFF_ACL_SIZE(unit->buffer, ep->pkt_size);
108b06ebda0SMatthew Dillon 			NG_HCI_BUFF_ACL_TOTAL(unit->buffer, ep->num_pkts);
109b06ebda0SMatthew Dillon 		} else {
110b06ebda0SMatthew Dillon 			NG_HCI_BUFF_SCO_SIZE(unit->buffer, ep->pkt_size);
111b06ebda0SMatthew Dillon 			NG_HCI_BUFF_SCO_TOTAL(unit->buffer, ep->num_pkts);
112b06ebda0SMatthew Dillon 		}
113b06ebda0SMatthew Dillon 
114b06ebda0SMatthew Dillon 		bcopy(&unit->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));
115b06ebda0SMatthew Dillon 
116b06ebda0SMatthew Dillon 		NG_SEND_MSG_HOOK(error, node, msg, hook, 0);
117b06ebda0SMatthew Dillon 	} else
118b06ebda0SMatthew Dillon 		error = ENOMEM;
119b06ebda0SMatthew Dillon 
120b06ebda0SMatthew Dillon 	if (error != 0)
121b06ebda0SMatthew Dillon 		NG_HCI_INFO(
122b06ebda0SMatthew Dillon "%s: %s - failed to send NODE_UP message to hook \"%s\", error=%d\n",
123b06ebda0SMatthew Dillon 			__func__, NG_NODE_NAME(unit->node),
124b06ebda0SMatthew Dillon 			NG_HOOK_NAME(hook), error);
125b06ebda0SMatthew Dillon } /* ng_hci_node_is_up */
126b06ebda0SMatthew Dillon 
127b06ebda0SMatthew Dillon /*
128b06ebda0SMatthew Dillon  * Clean unit (helper)
129b06ebda0SMatthew Dillon  */
130b06ebda0SMatthew Dillon 
131b06ebda0SMatthew Dillon void
ng_hci_unit_clean(ng_hci_unit_p unit,int reason)132b06ebda0SMatthew Dillon ng_hci_unit_clean(ng_hci_unit_p unit, int reason)
133b06ebda0SMatthew Dillon {
134b06ebda0SMatthew Dillon 	int	size;
135b06ebda0SMatthew Dillon 
136b06ebda0SMatthew Dillon 	/* Drain command queue */
137b06ebda0SMatthew Dillon 	if (unit->state & NG_HCI_UNIT_COMMAND_PENDING)
138b06ebda0SMatthew Dillon 		ng_hci_command_untimeout(unit);
139b06ebda0SMatthew Dillon 
140b06ebda0SMatthew Dillon 	NG_BT_MBUFQ_DRAIN(&unit->cmdq);
141b06ebda0SMatthew Dillon 	NG_HCI_BUFF_CMD_SET(unit->buffer, 1);
142b06ebda0SMatthew Dillon 
143b06ebda0SMatthew Dillon 	/* Clean up connection list */
144b06ebda0SMatthew Dillon 	while (!LIST_EMPTY(&unit->con_list)) {
145b06ebda0SMatthew Dillon 		ng_hci_unit_con_p	con = LIST_FIRST(&unit->con_list);
146b06ebda0SMatthew Dillon 
147b06ebda0SMatthew Dillon 		/* Remove all timeouts (if any) */
148b06ebda0SMatthew Dillon 		if (con->flags & NG_HCI_CON_TIMEOUT_PENDING)
149b06ebda0SMatthew Dillon 			ng_hci_con_untimeout(con);
150b06ebda0SMatthew Dillon 
151b06ebda0SMatthew Dillon 		/*
152b06ebda0SMatthew Dillon 		 * Notify upper layer protocol and destroy connection
153b06ebda0SMatthew Dillon 		 * descriptor. Do not really care about the result.
154b06ebda0SMatthew Dillon 		 */
155b06ebda0SMatthew Dillon 
156b06ebda0SMatthew Dillon 		ng_hci_lp_discon_ind(con, reason);
157b06ebda0SMatthew Dillon 		ng_hci_free_con(con);
158b06ebda0SMatthew Dillon 	}
159b06ebda0SMatthew Dillon 
160b06ebda0SMatthew Dillon 	NG_HCI_BUFF_ACL_TOTAL(unit->buffer, size);
161b06ebda0SMatthew Dillon 	NG_HCI_BUFF_ACL_FREE(unit->buffer, size);
162b06ebda0SMatthew Dillon 
163b06ebda0SMatthew Dillon 	NG_HCI_BUFF_SCO_TOTAL(unit->buffer, size);
164b06ebda0SMatthew Dillon 	NG_HCI_BUFF_SCO_FREE(unit->buffer, size);
165b06ebda0SMatthew Dillon 
166b06ebda0SMatthew Dillon 	/* Clean up neighbors list */
167b06ebda0SMatthew Dillon 	ng_hci_flush_neighbor_cache(unit);
168b06ebda0SMatthew Dillon } /* ng_hci_unit_clean */
169b06ebda0SMatthew Dillon 
170b06ebda0SMatthew Dillon /*
171b06ebda0SMatthew Dillon  * Allocate and link new unit neighbor cache entry
172b06ebda0SMatthew Dillon  */
173b06ebda0SMatthew Dillon 
174b06ebda0SMatthew Dillon ng_hci_neighbor_p
ng_hci_new_neighbor(ng_hci_unit_p unit)175b06ebda0SMatthew Dillon ng_hci_new_neighbor(ng_hci_unit_p unit)
176b06ebda0SMatthew Dillon {
177b06ebda0SMatthew Dillon 	ng_hci_neighbor_p	n = NULL;
178b06ebda0SMatthew Dillon 
179fc025606SSascha Wildner 	n = kmalloc(sizeof(*n), M_NETGRAPH_HCI, M_WAITOK | M_NULLOK | M_ZERO);
180b06ebda0SMatthew Dillon 	if (n != NULL) {
181b06ebda0SMatthew Dillon 		getmicrotime(&n->updated);
182b06ebda0SMatthew Dillon 		LIST_INSERT_HEAD(&unit->neighbors, n, next);
183b06ebda0SMatthew Dillon 	}
184b06ebda0SMatthew Dillon 
185b06ebda0SMatthew Dillon 	return (n);
186b06ebda0SMatthew Dillon } /* ng_hci_new_neighbor */
187b06ebda0SMatthew Dillon 
188b06ebda0SMatthew Dillon /*
189b06ebda0SMatthew Dillon  * Free unit neighbor cache entry
190b06ebda0SMatthew Dillon  */
191b06ebda0SMatthew Dillon 
192b06ebda0SMatthew Dillon void
ng_hci_free_neighbor(ng_hci_neighbor_p n)193b06ebda0SMatthew Dillon ng_hci_free_neighbor(ng_hci_neighbor_p n)
194b06ebda0SMatthew Dillon {
195b06ebda0SMatthew Dillon 	LIST_REMOVE(n, next);
196b06ebda0SMatthew Dillon 	bzero(n, sizeof(*n));
197fc025606SSascha Wildner 	kfree(n, M_NETGRAPH_HCI);
198b06ebda0SMatthew Dillon } /* ng_hci_free_neighbor */
199b06ebda0SMatthew Dillon 
200b06ebda0SMatthew Dillon /*
201b06ebda0SMatthew Dillon  * Flush neighbor cache
202b06ebda0SMatthew Dillon  */
203b06ebda0SMatthew Dillon 
204b06ebda0SMatthew Dillon void
ng_hci_flush_neighbor_cache(ng_hci_unit_p unit)205b06ebda0SMatthew Dillon ng_hci_flush_neighbor_cache(ng_hci_unit_p unit)
206b06ebda0SMatthew Dillon {
207b06ebda0SMatthew Dillon 	while (!LIST_EMPTY(&unit->neighbors))
208b06ebda0SMatthew Dillon 		ng_hci_free_neighbor(LIST_FIRST(&unit->neighbors));
209b06ebda0SMatthew Dillon } /* ng_hci_flush_neighbor_cache */
210b06ebda0SMatthew Dillon 
211b06ebda0SMatthew Dillon /*
212b06ebda0SMatthew Dillon  * Lookup unit in neighbor cache
213b06ebda0SMatthew Dillon  */
214b06ebda0SMatthew Dillon 
215b06ebda0SMatthew Dillon ng_hci_neighbor_p
ng_hci_get_neighbor(ng_hci_unit_p unit,bdaddr_p bdaddr)216b06ebda0SMatthew Dillon ng_hci_get_neighbor(ng_hci_unit_p unit, bdaddr_p bdaddr)
217b06ebda0SMatthew Dillon {
218b06ebda0SMatthew Dillon 	ng_hci_neighbor_p	n = NULL;
219b06ebda0SMatthew Dillon 
220b06ebda0SMatthew Dillon 	for (n = LIST_FIRST(&unit->neighbors); n != NULL; ) {
221b06ebda0SMatthew Dillon 		ng_hci_neighbor_p	nn = LIST_NEXT(n, next);
222b06ebda0SMatthew Dillon 
223b06ebda0SMatthew Dillon 		if (!ng_hci_neighbor_stale(n)) {
224b06ebda0SMatthew Dillon 			if (bcmp(&n->bdaddr, bdaddr, sizeof(*bdaddr)) == 0)
225b06ebda0SMatthew Dillon 				break;
226b06ebda0SMatthew Dillon 		} else
227b06ebda0SMatthew Dillon 			ng_hci_free_neighbor(n); /* remove old entry */
228b06ebda0SMatthew Dillon 
229b06ebda0SMatthew Dillon 		n = nn;
230b06ebda0SMatthew Dillon 	}
231b06ebda0SMatthew Dillon 
232b06ebda0SMatthew Dillon 	return (n);
233b06ebda0SMatthew Dillon } /* ng_hci_get_neighbor */
234b06ebda0SMatthew Dillon 
235b06ebda0SMatthew Dillon /*
236b06ebda0SMatthew Dillon  * Check if neighbor entry is stale
237b06ebda0SMatthew Dillon  */
238b06ebda0SMatthew Dillon 
239b06ebda0SMatthew Dillon int
ng_hci_neighbor_stale(ng_hci_neighbor_p n)240b06ebda0SMatthew Dillon ng_hci_neighbor_stale(ng_hci_neighbor_p n)
241b06ebda0SMatthew Dillon {
242b06ebda0SMatthew Dillon 	struct timeval	now;
243b06ebda0SMatthew Dillon 
244b06ebda0SMatthew Dillon 	getmicrotime(&now);
245b06ebda0SMatthew Dillon 
246b06ebda0SMatthew Dillon 	return (now.tv_sec - n->updated.tv_sec > bluetooth_hci_max_neighbor_age());
247b06ebda0SMatthew Dillon } /* ng_hci_neighbor_stale */
248b06ebda0SMatthew Dillon 
249b06ebda0SMatthew Dillon /*
250b06ebda0SMatthew Dillon  * Allocate and link new connection descriptor
251b06ebda0SMatthew Dillon  */
252b06ebda0SMatthew Dillon 
253b06ebda0SMatthew Dillon ng_hci_unit_con_p
ng_hci_new_con(ng_hci_unit_p unit,int link_type)254b06ebda0SMatthew Dillon ng_hci_new_con(ng_hci_unit_p unit, int link_type)
255b06ebda0SMatthew Dillon {
256b06ebda0SMatthew Dillon 	ng_hci_unit_con_p	con = NULL;
257b06ebda0SMatthew Dillon 	int			num_pkts;
258b06ebda0SMatthew Dillon 	static int		fake_con_handle = 0x0f00;
259b06ebda0SMatthew Dillon 
260fc025606SSascha Wildner 	con = kmalloc(sizeof(*con), M_NETGRAPH_HCI,
2615a975a3dSMatthew Dillon 		      M_WAITOK | M_NULLOK | M_ZERO);
262b06ebda0SMatthew Dillon 	if (con != NULL) {
263b06ebda0SMatthew Dillon 		con->unit = unit;
264b06ebda0SMatthew Dillon 		con->state = NG_HCI_CON_CLOSED;
265b06ebda0SMatthew Dillon 
266b06ebda0SMatthew Dillon 		/*
267b06ebda0SMatthew Dillon 		 * XXX
268b06ebda0SMatthew Dillon 		 *
269b06ebda0SMatthew Dillon 		 * Assign fake connection handle to the connection descriptor.
270b06ebda0SMatthew Dillon 		 * Bluetooth specification marks 0x0f00 - 0x0fff connection
271b06ebda0SMatthew Dillon 		 * handles as reserved. We need this fake connection handles
272b06ebda0SMatthew Dillon 		 * for timeouts. Connection handle will be passed as argument
273b06ebda0SMatthew Dillon 		 * to timeout so when timeout happens we can find the right
274b06ebda0SMatthew Dillon 		 * connection descriptor. We can not pass pointers, because
275b06ebda0SMatthew Dillon 		 * timeouts are external (to Netgraph) events and there might
276b06ebda0SMatthew Dillon 		 * be a race when node/hook goes down and timeout event already
277b06ebda0SMatthew Dillon 		 * went into node's queue
278b06ebda0SMatthew Dillon 		 */
279b06ebda0SMatthew Dillon 
280b06ebda0SMatthew Dillon 		con->con_handle = fake_con_handle ++;
281b06ebda0SMatthew Dillon 		if (fake_con_handle > 0x0fff)
282b06ebda0SMatthew Dillon 			fake_con_handle = 0x0f00;
283b06ebda0SMatthew Dillon 
284b06ebda0SMatthew Dillon 		con->link_type = link_type;
285b06ebda0SMatthew Dillon 
286b06ebda0SMatthew Dillon 		if (con->link_type == NG_HCI_LINK_ACL)
287b06ebda0SMatthew Dillon 			NG_HCI_BUFF_ACL_TOTAL(unit->buffer, num_pkts);
288b06ebda0SMatthew Dillon 		else
289b06ebda0SMatthew Dillon 			NG_HCI_BUFF_SCO_TOTAL(unit->buffer, num_pkts);
290b06ebda0SMatthew Dillon 
291b06ebda0SMatthew Dillon 		NG_BT_ITEMQ_INIT(&con->conq, num_pkts);
292b06ebda0SMatthew Dillon 
293b06ebda0SMatthew Dillon 		ng_callout_init(&con->con_timo);
294b06ebda0SMatthew Dillon 
295b06ebda0SMatthew Dillon 		LIST_INSERT_HEAD(&unit->con_list, con, next);
296b06ebda0SMatthew Dillon 	}
297b06ebda0SMatthew Dillon 
298b06ebda0SMatthew Dillon 	return (con);
299b06ebda0SMatthew Dillon } /* ng_hci_new_con */
300b06ebda0SMatthew Dillon 
301b06ebda0SMatthew Dillon /*
302b06ebda0SMatthew Dillon  * Free connection descriptor
303b06ebda0SMatthew Dillon  */
304b06ebda0SMatthew Dillon 
305b06ebda0SMatthew Dillon void
ng_hci_free_con(ng_hci_unit_con_p con)306b06ebda0SMatthew Dillon ng_hci_free_con(ng_hci_unit_con_p con)
307b06ebda0SMatthew Dillon {
308b06ebda0SMatthew Dillon 	LIST_REMOVE(con, next);
309b06ebda0SMatthew Dillon 
310b06ebda0SMatthew Dillon 	/*
311b06ebda0SMatthew Dillon 	 * If we have pending packets then assume that Host Controller has
312b06ebda0SMatthew Dillon 	 * flushed these packets and we can free them too
313b06ebda0SMatthew Dillon 	 */
314b06ebda0SMatthew Dillon 
315b06ebda0SMatthew Dillon 	if (con->link_type == NG_HCI_LINK_ACL)
316b06ebda0SMatthew Dillon 		NG_HCI_BUFF_ACL_FREE(con->unit->buffer, con->pending);
317b06ebda0SMatthew Dillon 	else
318b06ebda0SMatthew Dillon 		NG_HCI_BUFF_SCO_FREE(con->unit->buffer, con->pending);
319b06ebda0SMatthew Dillon 
320b06ebda0SMatthew Dillon 	NG_BT_ITEMQ_DESTROY(&con->conq);
321b06ebda0SMatthew Dillon 
322b06ebda0SMatthew Dillon 	bzero(con, sizeof(*con));
323fc025606SSascha Wildner 	kfree(con, M_NETGRAPH_HCI);
324b06ebda0SMatthew Dillon } /* ng_hci_free_con */
325b06ebda0SMatthew Dillon 
326b06ebda0SMatthew Dillon /*
327b06ebda0SMatthew Dillon  * Lookup connection for given unit and connection handle.
328b06ebda0SMatthew Dillon  */
329b06ebda0SMatthew Dillon 
330b06ebda0SMatthew Dillon ng_hci_unit_con_p
ng_hci_con_by_handle(ng_hci_unit_p unit,int con_handle)331b06ebda0SMatthew Dillon ng_hci_con_by_handle(ng_hci_unit_p unit, int con_handle)
332b06ebda0SMatthew Dillon {
333b06ebda0SMatthew Dillon 	ng_hci_unit_con_p	con = NULL;
334b06ebda0SMatthew Dillon 
335b06ebda0SMatthew Dillon 	LIST_FOREACH(con, &unit->con_list, next)
336b06ebda0SMatthew Dillon 		if (con->con_handle == con_handle)
337b06ebda0SMatthew Dillon 			break;
338b06ebda0SMatthew Dillon 
339b06ebda0SMatthew Dillon 	return (con);
340b06ebda0SMatthew Dillon } /* ng_hci_con_by_handle */
341b06ebda0SMatthew Dillon 
342b06ebda0SMatthew Dillon /*
343b06ebda0SMatthew Dillon  * Lookup connection for given unit, link type and remove unit address
344b06ebda0SMatthew Dillon  */
345b06ebda0SMatthew Dillon 
346b06ebda0SMatthew Dillon ng_hci_unit_con_p
ng_hci_con_by_bdaddr(ng_hci_unit_p unit,bdaddr_p bdaddr,int link_type)347b06ebda0SMatthew Dillon ng_hci_con_by_bdaddr(ng_hci_unit_p unit, bdaddr_p bdaddr, int link_type)
348b06ebda0SMatthew Dillon {
349b06ebda0SMatthew Dillon 	ng_hci_unit_con_p	con = NULL;
350b06ebda0SMatthew Dillon 
351b06ebda0SMatthew Dillon 	LIST_FOREACH(con, &unit->con_list, next)
352b06ebda0SMatthew Dillon 		if (con->link_type == link_type &&
353b06ebda0SMatthew Dillon 		    bcmp(&con->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0)
354b06ebda0SMatthew Dillon 			break;
355b06ebda0SMatthew Dillon 
356b06ebda0SMatthew Dillon 	return (con);
357b06ebda0SMatthew Dillon } /* ng_hci_con_by_bdaddr */
358b06ebda0SMatthew Dillon 
359b06ebda0SMatthew Dillon /*
360b06ebda0SMatthew Dillon  * Set HCI command timeout
361b06ebda0SMatthew Dillon  * XXX FIXME: check return code from ng_callout
362b06ebda0SMatthew Dillon  */
363b06ebda0SMatthew Dillon 
364b06ebda0SMatthew Dillon int
ng_hci_command_timeout(ng_hci_unit_p unit)365b06ebda0SMatthew Dillon ng_hci_command_timeout(ng_hci_unit_p unit)
366b06ebda0SMatthew Dillon {
367b06ebda0SMatthew Dillon 	if (unit->state & NG_HCI_UNIT_COMMAND_PENDING)
368b06ebda0SMatthew Dillon 		panic(
369b06ebda0SMatthew Dillon "%s: %s - Duplicated command timeout!\n", __func__, NG_NODE_NAME(unit->node));
370b06ebda0SMatthew Dillon 
371b06ebda0SMatthew Dillon 	unit->state |= NG_HCI_UNIT_COMMAND_PENDING;
372b06ebda0SMatthew Dillon 	ng_callout(&unit->cmd_timo, unit->node, NULL,
373b06ebda0SMatthew Dillon 				bluetooth_hci_command_timeout(),
374b06ebda0SMatthew Dillon 				ng_hci_process_command_timeout, NULL, 0);
375b06ebda0SMatthew Dillon 
376b06ebda0SMatthew Dillon 	return (0);
377b06ebda0SMatthew Dillon } /* ng_hci_command_timeout */
378b06ebda0SMatthew Dillon 
379b06ebda0SMatthew Dillon /*
380b06ebda0SMatthew Dillon  * Unset HCI command timeout
381b06ebda0SMatthew Dillon  */
382b06ebda0SMatthew Dillon 
383b06ebda0SMatthew Dillon int
ng_hci_command_untimeout(ng_hci_unit_p unit)384b06ebda0SMatthew Dillon ng_hci_command_untimeout(ng_hci_unit_p unit)
385b06ebda0SMatthew Dillon {
386b06ebda0SMatthew Dillon 	if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
387b06ebda0SMatthew Dillon 		panic(
388b06ebda0SMatthew Dillon "%s: %s - No command timeout!\n", __func__, NG_NODE_NAME(unit->node));
389b06ebda0SMatthew Dillon 
390b06ebda0SMatthew Dillon 	if (ng_uncallout(&unit->cmd_timo, unit->node) == 0)
391b06ebda0SMatthew Dillon 		return (ETIMEDOUT);
392b06ebda0SMatthew Dillon 
393b06ebda0SMatthew Dillon 	unit->state &= ~NG_HCI_UNIT_COMMAND_PENDING;
394b06ebda0SMatthew Dillon 
395b06ebda0SMatthew Dillon 	return (0);
396b06ebda0SMatthew Dillon } /* ng_hci_command_untimeout */
397b06ebda0SMatthew Dillon 
398b06ebda0SMatthew Dillon /*
399b06ebda0SMatthew Dillon  * Set HCI connection timeout
400b06ebda0SMatthew Dillon  * XXX FIXME: check return code from ng_callout
401b06ebda0SMatthew Dillon  */
402b06ebda0SMatthew Dillon 
403b06ebda0SMatthew Dillon int
ng_hci_con_timeout(ng_hci_unit_con_p con)404b06ebda0SMatthew Dillon ng_hci_con_timeout(ng_hci_unit_con_p con)
405b06ebda0SMatthew Dillon {
406b06ebda0SMatthew Dillon 	if (con->flags & NG_HCI_CON_TIMEOUT_PENDING)
407b06ebda0SMatthew Dillon 		panic(
408b06ebda0SMatthew Dillon "%s: %s - Duplicated connection timeout!\n",
409b06ebda0SMatthew Dillon 			__func__, NG_NODE_NAME(con->unit->node));
410b06ebda0SMatthew Dillon 
411b06ebda0SMatthew Dillon 	con->flags |= NG_HCI_CON_TIMEOUT_PENDING;
412b06ebda0SMatthew Dillon 	ng_callout(&con->con_timo, con->unit->node, NULL,
413b06ebda0SMatthew Dillon 				bluetooth_hci_connect_timeout(),
414b06ebda0SMatthew Dillon 				ng_hci_process_con_timeout, NULL,
415b06ebda0SMatthew Dillon 				con->con_handle);
416b06ebda0SMatthew Dillon 
417b06ebda0SMatthew Dillon 	return (0);
418b06ebda0SMatthew Dillon } /* ng_hci_con_timeout */
419b06ebda0SMatthew Dillon 
420b06ebda0SMatthew Dillon /*
421b06ebda0SMatthew Dillon  * Unset HCI connection timeout
422b06ebda0SMatthew Dillon  */
423b06ebda0SMatthew Dillon 
424b06ebda0SMatthew Dillon int
ng_hci_con_untimeout(ng_hci_unit_con_p con)425b06ebda0SMatthew Dillon ng_hci_con_untimeout(ng_hci_unit_con_p con)
426b06ebda0SMatthew Dillon {
427b06ebda0SMatthew Dillon 	if (!(con->flags & NG_HCI_CON_TIMEOUT_PENDING))
428b06ebda0SMatthew Dillon 		panic(
429b06ebda0SMatthew Dillon "%s: %s - No connection timeout!\n", __func__, NG_NODE_NAME(con->unit->node));
430b06ebda0SMatthew Dillon 
431b06ebda0SMatthew Dillon 	if (ng_uncallout(&con->con_timo, con->unit->node) == 0)
432b06ebda0SMatthew Dillon 		return (ETIMEDOUT);
433b06ebda0SMatthew Dillon 
434b06ebda0SMatthew Dillon 	con->flags &= ~NG_HCI_CON_TIMEOUT_PENDING;
435b06ebda0SMatthew Dillon 
436b06ebda0SMatthew Dillon 	return (0);
437b06ebda0SMatthew Dillon } /* ng_hci_con_untimeout */
438b06ebda0SMatthew Dillon 
439b06ebda0SMatthew Dillon #if 0
440b06ebda0SMatthew Dillon /*
441b06ebda0SMatthew Dillon  * Convert numeric error code/reason to a string
442b06ebda0SMatthew Dillon  */
443b06ebda0SMatthew Dillon 
444b06ebda0SMatthew Dillon char const * const
445b06ebda0SMatthew Dillon ng_hci_str_error(u_int16_t code)
446b06ebda0SMatthew Dillon {
447c157ff7aSSascha Wildner #define	LAST_ERROR_CODE			(NELEM(s)-1)
448b06ebda0SMatthew Dillon 	static char const * const	s[] = {
449b06ebda0SMatthew Dillon 	/* 0x00 */ "No error",
450b06ebda0SMatthew Dillon 	/* 0x01 */ "Unknown HCI command",
451b06ebda0SMatthew Dillon 	/* 0x02 */ "No connection",
452b06ebda0SMatthew Dillon 	/* 0x03 */ "Hardware failure",
453b06ebda0SMatthew Dillon 	/* 0x04 */ "Page timeout",
454b06ebda0SMatthew Dillon 	/* 0x05 */ "Authentication failure",
455b06ebda0SMatthew Dillon 	/* 0x06 */ "Key missing",
456b06ebda0SMatthew Dillon 	/* 0x07 */ "Memory full",
457b06ebda0SMatthew Dillon 	/* 0x08 */ "Connection timeout",
458b06ebda0SMatthew Dillon 	/* 0x09 */ "Max number of connections",
459b06ebda0SMatthew Dillon 	/* 0x0a */ "Max number of SCO connections to a unit",
460b06ebda0SMatthew Dillon 	/* 0x0b */ "ACL connection already exists",
461b06ebda0SMatthew Dillon 	/* 0x0c */ "Command disallowed",
462b06ebda0SMatthew Dillon 	/* 0x0d */ "Host rejected due to limited resources",
463b06ebda0SMatthew Dillon 	/* 0x0e */ "Host rejected due to securiity reasons",
464b06ebda0SMatthew Dillon 	/* 0x0f */ "Host rejected due to remote unit is a personal unit",
465b06ebda0SMatthew Dillon 	/* 0x10 */ "Host timeout",
466b06ebda0SMatthew Dillon 	/* 0x11 */ "Unsupported feature or parameter value",
467b06ebda0SMatthew Dillon 	/* 0x12 */ "Invalid HCI command parameter",
468b06ebda0SMatthew Dillon 	/* 0x13 */ "Other end terminated connection: User ended connection",
469b06ebda0SMatthew Dillon 	/* 0x14 */ "Other end terminated connection: Low resources",
470b06ebda0SMatthew Dillon 	/* 0x15 */ "Other end terminated connection: About to power off",
471b06ebda0SMatthew Dillon 	/* 0x16 */ "Connection terminated by local host",
472b06ebda0SMatthew Dillon 	/* 0x17 */ "Repeated attempts",
473b06ebda0SMatthew Dillon 	/* 0x18 */ "Pairing not allowed",
474b06ebda0SMatthew Dillon 	/* 0x19 */ "Unknown LMP PDU",
475b06ebda0SMatthew Dillon 	/* 0x1a */ "Unsupported remote feature",
476b06ebda0SMatthew Dillon 	/* 0x1b */ "SCO offset rejected",
477b06ebda0SMatthew Dillon 	/* 0x1c */ "SCO interval rejected",
478b06ebda0SMatthew Dillon 	/* 0x1d */ "SCO air mode rejected",
479b06ebda0SMatthew Dillon 	/* 0x1e */ "Invalid LMP parameters",
480b06ebda0SMatthew Dillon 	/* 0x1f */ "Unspecified error",
481b06ebda0SMatthew Dillon 	/* 0x20 */ "Unsupported LMP parameter value",
482b06ebda0SMatthew Dillon 	/* 0x21 */ "Role change not allowed",
483b06ebda0SMatthew Dillon 	/* 0x22 */ "LMP response timeout",
484b06ebda0SMatthew Dillon 	/* 0x23 */ "LMP error transaction collision",
485b06ebda0SMatthew Dillon 	/* 0x24 */ "LMP PSU not allowed",
486b06ebda0SMatthew Dillon 	/* 0x25 */ "Encryption mode not acceptable",
487b06ebda0SMatthew Dillon 	/* 0x26 */ "Unit key used",
488b06ebda0SMatthew Dillon 	/* 0x27 */ "QoS is not supported",
489b06ebda0SMatthew Dillon 	/* 0x28 */ "Instant passed",
490b06ebda0SMatthew Dillon 	/* 0x29 */ "Paring with unit key not supported",
491b06ebda0SMatthew Dillon 	/* SHOULD ALWAYS BE LAST */ "Unknown error"
492b06ebda0SMatthew Dillon 	};
493b06ebda0SMatthew Dillon 
494b06ebda0SMatthew Dillon 	return ((code >= LAST_ERROR_CODE)? s[LAST_ERROR_CODE] : s[code]);
495b06ebda0SMatthew Dillon } /* ng_hci_str_error */
496b06ebda0SMatthew Dillon #endif
497b06ebda0SMatthew Dillon 
498