xref: /freebsd/sys/netgraph/bluetooth/hci/ng_hci_misc.c (revision 878ed22696d5402cabd6f90932cc970ab912b7b0)
1878ed226SJulian Elischer /*
2878ed226SJulian Elischer  * ng_hci_misc.c
3878ed226SJulian Elischer  *
4878ed226SJulian Elischer  * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
5878ed226SJulian Elischer  * All rights reserved.
6878ed226SJulian Elischer  *
7878ed226SJulian Elischer  * Redistribution and use in source and binary forms, with or without
8878ed226SJulian Elischer  * modification, are permitted provided that the following conditions
9878ed226SJulian Elischer  * are met:
10878ed226SJulian Elischer  * 1. Redistributions of source code must retain the above copyright
11878ed226SJulian Elischer  *    notice, this list of conditions and the following disclaimer.
12878ed226SJulian Elischer  * 2. Redistributions in binary form must reproduce the above copyright
13878ed226SJulian Elischer  *    notice, this list of conditions and the following disclaimer in the
14878ed226SJulian Elischer  *    documentation and/or other materials provided with the distribution.
15878ed226SJulian Elischer  *
16878ed226SJulian Elischer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17878ed226SJulian Elischer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18878ed226SJulian Elischer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19878ed226SJulian Elischer  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20878ed226SJulian Elischer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21878ed226SJulian Elischer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22878ed226SJulian Elischer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23878ed226SJulian Elischer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24878ed226SJulian Elischer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25878ed226SJulian Elischer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26878ed226SJulian Elischer  * SUCH DAMAGE.
27878ed226SJulian Elischer  *
28878ed226SJulian Elischer  * $Id: ng_hci_misc.c,v 1.18 2002/10/30 00:18:19 max Exp $
29878ed226SJulian Elischer  * $FreeBSD$
30878ed226SJulian Elischer  */
31878ed226SJulian Elischer 
32878ed226SJulian Elischer #include <sys/param.h>
33878ed226SJulian Elischer #include <sys/systm.h>
34878ed226SJulian Elischer #include <sys/kernel.h>
35878ed226SJulian Elischer #include <sys/malloc.h>
36878ed226SJulian Elischer #include <sys/mbuf.h>
37878ed226SJulian Elischer #include <sys/queue.h>
38878ed226SJulian Elischer #include <netgraph/ng_message.h>
39878ed226SJulian Elischer #include <netgraph/netgraph.h>
40878ed226SJulian Elischer #include "ng_bluetooth.h"
41878ed226SJulian Elischer #include "ng_hci.h"
42878ed226SJulian Elischer #include "ng_hci_var.h"
43878ed226SJulian Elischer #include "ng_hci_cmds.h"
44878ed226SJulian Elischer #include "ng_hci_evnt.h"
45878ed226SJulian Elischer #include "ng_hci_ulpi.h"
46878ed226SJulian Elischer #include "ng_hci_misc.h"
47878ed226SJulian Elischer 
48878ed226SJulian Elischer /******************************************************************************
49878ed226SJulian Elischer  ******************************************************************************
50878ed226SJulian Elischer  **                              Utility routines
51878ed226SJulian Elischer  ******************************************************************************
52878ed226SJulian Elischer  ******************************************************************************/
53878ed226SJulian Elischer 
54878ed226SJulian Elischer static void	ng_hci_command_queue_timeout		(void *);
55878ed226SJulian Elischer static void	ng_hci_con_queue_timeout		(void *);
56878ed226SJulian Elischer static void	ng_hci_con_queue_watchdog_timeout	(void *);
57878ed226SJulian Elischer 
58878ed226SJulian Elischer /*
59878ed226SJulian Elischer  * Give packet to RAW hook
60878ed226SJulian Elischer  * Assumes input mbuf is read only.
61878ed226SJulian Elischer  */
62878ed226SJulian Elischer 
63878ed226SJulian Elischer void
64878ed226SJulian Elischer ng_hci_mtap(ng_hci_unit_p unit, struct mbuf *m0)
65878ed226SJulian Elischer {
66878ed226SJulian Elischer 	struct mbuf	*m = NULL;
67878ed226SJulian Elischer 	int		 error = 0;
68878ed226SJulian Elischer 
69878ed226SJulian Elischer 	if (unit->raw != NULL && NG_HOOK_IS_VALID(unit->raw)) {
70878ed226SJulian Elischer 		m = m_dup(m0, M_DONTWAIT);
71878ed226SJulian Elischer 		if (m != NULL)
72878ed226SJulian Elischer 			NG_SEND_DATA_ONLY(error, unit->raw, m);
73878ed226SJulian Elischer 
74878ed226SJulian Elischer 		if (error != 0)
75878ed226SJulian Elischer 			NG_HCI_INFO(
76878ed226SJulian Elischer "%s: %s - Could not forward packet, error=%d\n",
77878ed226SJulian Elischer 				__func__, NG_NODE_NAME(unit->node), error);
78878ed226SJulian Elischer 	}
79878ed226SJulian Elischer } /* ng_hci_mtap */
80878ed226SJulian Elischer 
81878ed226SJulian Elischer /*
82878ed226SJulian Elischer  * Send notification to the upper layer's
83878ed226SJulian Elischer  */
84878ed226SJulian Elischer 
85878ed226SJulian Elischer void
86878ed226SJulian Elischer ng_hci_node_is_up(node_p node, hook_p hook, void *arg1, int arg2)
87878ed226SJulian Elischer {
88878ed226SJulian Elischer 	ng_hci_unit_p		 unit = NULL;
89878ed226SJulian Elischer 	struct ng_mesg		*msg = NULL;
90878ed226SJulian Elischer 	ng_hci_node_up_ep	*ep = NULL;
91878ed226SJulian Elischer 	int			 error;
92878ed226SJulian Elischer 
93878ed226SJulian Elischer 	if (node == NULL || NG_NODE_NOT_VALID(node) ||
94878ed226SJulian Elischer 	    hook == NULL || NG_HOOK_NOT_VALID(hook))
95878ed226SJulian Elischer 		return;
96878ed226SJulian Elischer 
97878ed226SJulian Elischer 	unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node);
98878ed226SJulian Elischer 	if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY)
99878ed226SJulian Elischer 		return;
100878ed226SJulian Elischer 
101878ed226SJulian Elischer 	if (hook != unit->acl && hook != unit->sco)
102878ed226SJulian Elischer 		return;
103878ed226SJulian Elischer 
104878ed226SJulian Elischer 	NG_MKMESSAGE(msg,NGM_HCI_COOKIE,NGM_HCI_NODE_UP,sizeof(*ep),M_NOWAIT);
105878ed226SJulian Elischer 	if (msg != NULL) {
106878ed226SJulian Elischer 		ep = (ng_hci_node_up_ep *)(msg->data);
107878ed226SJulian Elischer 
108878ed226SJulian Elischer 		if (hook == unit->acl) {
109878ed226SJulian Elischer 			NG_HCI_BUFF_ACL_SIZE(unit->buffer, ep->pkt_size);
110878ed226SJulian Elischer 			NG_HCI_BUFF_ACL_TOTAL(unit->buffer, ep->num_pkts);
111878ed226SJulian Elischer 		} else {
112878ed226SJulian Elischer 			NG_HCI_BUFF_SCO_SIZE(unit->buffer, ep->pkt_size);
113878ed226SJulian Elischer 			NG_HCI_BUFF_SCO_TOTAL(unit->buffer, ep->num_pkts);
114878ed226SJulian Elischer 		}
115878ed226SJulian Elischer 
116878ed226SJulian Elischer 		bcopy(&unit->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));
117878ed226SJulian Elischer 
118878ed226SJulian Elischer 		NG_SEND_MSG_HOOK(error, node, msg, hook, NULL);
119878ed226SJulian Elischer 	} else
120878ed226SJulian Elischer 		error = ENOMEM;
121878ed226SJulian Elischer 
122878ed226SJulian Elischer 	if (error != 0)
123878ed226SJulian Elischer 		NG_HCI_INFO(
124878ed226SJulian Elischer "%s: %s - failed to send NODE_UP message to hook \"%s\", error=%d\n",
125878ed226SJulian Elischer 			__func__, NG_NODE_NAME(unit->node),
126878ed226SJulian Elischer 			NG_HOOK_NAME(hook), error);
127878ed226SJulian Elischer } /* ng_hci_node_is_up */
128878ed226SJulian Elischer 
129878ed226SJulian Elischer /*
130878ed226SJulian Elischer  * Clean unit (helper)
131878ed226SJulian Elischer  */
132878ed226SJulian Elischer 
133878ed226SJulian Elischer void
134878ed226SJulian Elischer ng_hci_unit_clean(ng_hci_unit_p unit, int reason)
135878ed226SJulian Elischer {
136878ed226SJulian Elischer 	int	size;
137878ed226SJulian Elischer 
138878ed226SJulian Elischer 	/* Drain command queue */
139878ed226SJulian Elischer 	if (unit->state & NG_HCI_UNIT_COMMAND_PENDING)
140878ed226SJulian Elischer 		ng_hci_command_untimeout(unit);
141878ed226SJulian Elischer 
142878ed226SJulian Elischer 	NG_BT_MBUFQ_DRAIN(&unit->cmdq);
143878ed226SJulian Elischer 	NG_HCI_BUFF_CMD_SET(unit->buffer, 1);
144878ed226SJulian Elischer 
145878ed226SJulian Elischer 	/* Clean up connection list */
146878ed226SJulian Elischer 	while (!LIST_EMPTY(&unit->con_list)) {
147878ed226SJulian Elischer 		ng_hci_unit_con_p	con = LIST_FIRST(&unit->con_list);
148878ed226SJulian Elischer 
149878ed226SJulian Elischer 		/*
150878ed226SJulian Elischer 		 * Notify upper layer protocol and destroy connection
151878ed226SJulian Elischer 		 * descriptor. Do not really care about the result.
152878ed226SJulian Elischer 		 */
153878ed226SJulian Elischer 
154878ed226SJulian Elischer 		ng_hci_lp_discon_ind(con, reason);
155878ed226SJulian Elischer 		ng_hci_free_con(con);
156878ed226SJulian Elischer 	}
157878ed226SJulian Elischer 
158878ed226SJulian Elischer 	NG_HCI_BUFF_ACL_TOTAL(unit->buffer, size);
159878ed226SJulian Elischer 	NG_HCI_BUFF_ACL_FREE(unit->buffer, size);
160878ed226SJulian Elischer 
161878ed226SJulian Elischer 	NG_HCI_BUFF_SCO_TOTAL(unit->buffer, size);
162878ed226SJulian Elischer 	NG_HCI_BUFF_SCO_FREE(unit->buffer, size);
163878ed226SJulian Elischer 
164878ed226SJulian Elischer 	/* Clean up neighbors list */
165878ed226SJulian Elischer 	ng_hci_flush_neighbor_cache(unit);
166878ed226SJulian Elischer } /* ng_hci_unit_clean */
167878ed226SJulian Elischer 
168878ed226SJulian Elischer /*
169878ed226SJulian Elischer  * Allocate and link new unit neighbor cache entry
170878ed226SJulian Elischer  */
171878ed226SJulian Elischer 
172878ed226SJulian Elischer ng_hci_neighbor_p
173878ed226SJulian Elischer ng_hci_new_neighbor(ng_hci_unit_p unit)
174878ed226SJulian Elischer {
175878ed226SJulian Elischer 	ng_hci_neighbor_p	n = NULL;
176878ed226SJulian Elischer 
177878ed226SJulian Elischer 	MALLOC(n, ng_hci_neighbor_p, sizeof(*n), M_NETGRAPH_HCI,
178878ed226SJulian Elischer 		M_NOWAIT | M_ZERO);
179878ed226SJulian Elischer 	if (n != NULL) {
180878ed226SJulian Elischer 		getmicrotime(&n->updated);
181878ed226SJulian Elischer 		LIST_INSERT_HEAD(&unit->neighbors, n, next);
182878ed226SJulian Elischer 	}
183878ed226SJulian Elischer 
184878ed226SJulian Elischer 	return (n);
185878ed226SJulian Elischer } /* ng_hci_new_neighbor */
186878ed226SJulian Elischer 
187878ed226SJulian Elischer /*
188878ed226SJulian Elischer  * Free unit neighbor cache entry
189878ed226SJulian Elischer  */
190878ed226SJulian Elischer 
191878ed226SJulian Elischer void
192878ed226SJulian Elischer ng_hci_free_neighbor(ng_hci_neighbor_p n)
193878ed226SJulian Elischer {
194878ed226SJulian Elischer 	LIST_REMOVE(n, next);
195878ed226SJulian Elischer 	bzero(n, sizeof(*n));
196878ed226SJulian Elischer 	FREE(n, M_NETGRAPH_HCI);
197878ed226SJulian Elischer } /* ng_hci_free_neighbor */
198878ed226SJulian Elischer 
199878ed226SJulian Elischer /*
200878ed226SJulian Elischer  * Flush neighbor cache
201878ed226SJulian Elischer  */
202878ed226SJulian Elischer 
203878ed226SJulian Elischer void
204878ed226SJulian Elischer ng_hci_flush_neighbor_cache(ng_hci_unit_p unit)
205878ed226SJulian Elischer {
206878ed226SJulian Elischer 	while (!LIST_EMPTY(&unit->neighbors))
207878ed226SJulian Elischer 		ng_hci_free_neighbor(LIST_FIRST(&unit->neighbors));
208878ed226SJulian Elischer } /* ng_hci_flush_neighbor_cache */
209878ed226SJulian Elischer 
210878ed226SJulian Elischer /*
211878ed226SJulian Elischer  * Lookup unit in neighbor cache
212878ed226SJulian Elischer  */
213878ed226SJulian Elischer 
214878ed226SJulian Elischer ng_hci_neighbor_p
215878ed226SJulian Elischer ng_hci_get_neighbor(ng_hci_unit_p unit, bdaddr_p bdaddr)
216878ed226SJulian Elischer {
217878ed226SJulian Elischer 	ng_hci_neighbor_p	n = NULL;
218878ed226SJulian Elischer 
219878ed226SJulian Elischer 	for (n = LIST_FIRST(&unit->neighbors); n != NULL; ) {
220878ed226SJulian Elischer 		ng_hci_neighbor_p	nn = LIST_NEXT(n, next);
221878ed226SJulian Elischer 
222878ed226SJulian Elischer 		if (!ng_hci_neighbor_stale(n)) {
223878ed226SJulian Elischer 			if (bcmp(&n->bdaddr, bdaddr, sizeof(*bdaddr)) == 0)
224878ed226SJulian Elischer 				break;
225878ed226SJulian Elischer 		} else
226878ed226SJulian Elischer 			ng_hci_free_neighbor(n); /* remove old entry */
227878ed226SJulian Elischer 
228878ed226SJulian Elischer 		n = nn;
229878ed226SJulian Elischer 	}
230878ed226SJulian Elischer 
231878ed226SJulian Elischer 	return (n);
232878ed226SJulian Elischer } /* ng_hci_get_neighbor */
233878ed226SJulian Elischer 
234878ed226SJulian Elischer /*
235878ed226SJulian Elischer  * Check if neighbor entry is stale
236878ed226SJulian Elischer  */
237878ed226SJulian Elischer 
238878ed226SJulian Elischer int
239878ed226SJulian Elischer ng_hci_neighbor_stale(ng_hci_neighbor_p n)
240878ed226SJulian Elischer {
241878ed226SJulian Elischer 	struct timeval	now;
242878ed226SJulian Elischer 
243878ed226SJulian Elischer 	getmicrotime(&now);
244878ed226SJulian Elischer 
245878ed226SJulian Elischer 	return (now.tv_sec - n->updated.tv_sec > bluetooth_hci_max_neighbor_age());
246878ed226SJulian Elischer } /* ng_hci_neighbor_stale */
247878ed226SJulian Elischer 
248878ed226SJulian Elischer /*
249878ed226SJulian Elischer  * Allocate and link new connection descriptor
250878ed226SJulian Elischer  */
251878ed226SJulian Elischer 
252878ed226SJulian Elischer ng_hci_unit_con_p
253878ed226SJulian Elischer ng_hci_new_con(ng_hci_unit_p unit, int link_type)
254878ed226SJulian Elischer {
255878ed226SJulian Elischer 	ng_hci_unit_con_p	con = NULL;
256878ed226SJulian Elischer 	int			num_pkts;
257878ed226SJulian Elischer 
258878ed226SJulian Elischer 	MALLOC(con, ng_hci_unit_con_p, sizeof(*con), M_NETGRAPH_HCI,
259878ed226SJulian Elischer 		M_NOWAIT | M_ZERO);
260878ed226SJulian Elischer 	if (con != NULL) {
261878ed226SJulian Elischer 		con->unit = unit;
262878ed226SJulian Elischer 		con->state = NG_HCI_CON_CLOSED;
263878ed226SJulian Elischer 		con->link_type = link_type;
264878ed226SJulian Elischer 
265878ed226SJulian Elischer 		if (con->link_type == NG_HCI_LINK_ACL)
266878ed226SJulian Elischer 			NG_HCI_BUFF_ACL_TOTAL(unit->buffer, num_pkts);
267878ed226SJulian Elischer 		else
268878ed226SJulian Elischer 			NG_HCI_BUFF_SCO_TOTAL(unit->buffer, num_pkts);
269878ed226SJulian Elischer 
270878ed226SJulian Elischer 		NG_BT_ITEMQ_INIT(&con->conq, num_pkts);
271878ed226SJulian Elischer 
272878ed226SJulian Elischer 		callout_handle_init(&con->con_timo);
273878ed226SJulian Elischer 		callout_handle_init(&con->watchdog_timo);
274878ed226SJulian Elischer 
275878ed226SJulian Elischer 		LIST_INSERT_HEAD(&unit->con_list, con, next);
276878ed226SJulian Elischer 	}
277878ed226SJulian Elischer 
278878ed226SJulian Elischer 	return (con);
279878ed226SJulian Elischer } /* ng_hci_new_con */
280878ed226SJulian Elischer 
281878ed226SJulian Elischer /*
282878ed226SJulian Elischer  * Free connection descriptor
283878ed226SJulian Elischer  */
284878ed226SJulian Elischer 
285878ed226SJulian Elischer void
286878ed226SJulian Elischer ng_hci_free_con(ng_hci_unit_con_p con)
287878ed226SJulian Elischer {
288878ed226SJulian Elischer 	LIST_REMOVE(con, next);
289878ed226SJulian Elischer 
290878ed226SJulian Elischer 	/* Remove all timeouts (if any) */
291878ed226SJulian Elischer 	if (con->flags & NG_HCI_CON_TIMEOUT_PENDING)
292878ed226SJulian Elischer 		ng_hci_con_untimeout(con);
293878ed226SJulian Elischer 
294878ed226SJulian Elischer 	if (con->flags & NG_HCI_CON_WATCHDOG_TIMEOUT_PENDING)
295878ed226SJulian Elischer 		ng_hci_con_watchdog_untimeout(con);
296878ed226SJulian Elischer 
297878ed226SJulian Elischer 	/*
298878ed226SJulian Elischer 	 * If we have pending packets then assume that Host Controller has
299878ed226SJulian Elischer 	 * flushed these packets and we can free them too
300878ed226SJulian Elischer 	 */
301878ed226SJulian Elischer 
302878ed226SJulian Elischer 	if (con->link_type == NG_HCI_LINK_ACL)
303878ed226SJulian Elischer 		NG_HCI_BUFF_ACL_FREE(con->unit->buffer, con->pending);
304878ed226SJulian Elischer 	else
305878ed226SJulian Elischer 		NG_HCI_BUFF_SCO_FREE(con->unit->buffer, con->pending);
306878ed226SJulian Elischer 
307878ed226SJulian Elischer 	NG_BT_ITEMQ_DESTROY(&con->conq);
308878ed226SJulian Elischer 
309878ed226SJulian Elischer 	bzero(con, sizeof(*con));
310878ed226SJulian Elischer 	FREE(con, M_NETGRAPH_HCI);
311878ed226SJulian Elischer } /* ng_hci_free_con */
312878ed226SJulian Elischer 
313878ed226SJulian Elischer /*
314878ed226SJulian Elischer  * Lookup connection for given unit and connection handle.
315878ed226SJulian Elischer  */
316878ed226SJulian Elischer 
317878ed226SJulian Elischer ng_hci_unit_con_p
318878ed226SJulian Elischer ng_hci_con_by_handle(ng_hci_unit_p unit, int con_handle)
319878ed226SJulian Elischer {
320878ed226SJulian Elischer 	ng_hci_unit_con_p	con = NULL;
321878ed226SJulian Elischer 
322878ed226SJulian Elischer 	LIST_FOREACH(con, &unit->con_list, next)
323878ed226SJulian Elischer 		if (con->con_handle == con_handle)
324878ed226SJulian Elischer 			break;
325878ed226SJulian Elischer 
326878ed226SJulian Elischer 	return (con);
327878ed226SJulian Elischer } /* ng_hci_con_by_handle */
328878ed226SJulian Elischer 
329878ed226SJulian Elischer /*
330878ed226SJulian Elischer  * Lookup connection for given unit, link type and remove unit address
331878ed226SJulian Elischer  */
332878ed226SJulian Elischer 
333878ed226SJulian Elischer ng_hci_unit_con_p
334878ed226SJulian Elischer ng_hci_con_by_bdaddr(ng_hci_unit_p unit, bdaddr_p bdaddr, int link_type)
335878ed226SJulian Elischer {
336878ed226SJulian Elischer 	ng_hci_unit_con_p	con = NULL;
337878ed226SJulian Elischer 
338878ed226SJulian Elischer 	LIST_FOREACH(con, &unit->con_list, next)
339878ed226SJulian Elischer 		if (con->link_type == link_type &&
340878ed226SJulian Elischer 		    bcmp(&con->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0)
341878ed226SJulian Elischer 			break;
342878ed226SJulian Elischer 
343878ed226SJulian Elischer 	return (con);
344878ed226SJulian Elischer } /* ng_hci_con_by_bdaddr */
345878ed226SJulian Elischer 
346878ed226SJulian Elischer /*
347878ed226SJulian Elischer  * Set HCI command timeout
348878ed226SJulian Elischer  */
349878ed226SJulian Elischer 
350878ed226SJulian Elischer void
351878ed226SJulian Elischer ng_hci_command_timeout(ng_hci_unit_p unit)
352878ed226SJulian Elischer {
353878ed226SJulian Elischer 	if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) {
354878ed226SJulian Elischer 		NG_NODE_REF(unit->node);
355878ed226SJulian Elischer 		unit->state |= NG_HCI_UNIT_COMMAND_PENDING;
356878ed226SJulian Elischer 		unit->cmd_timo = timeout(ng_hci_command_queue_timeout, unit,
357878ed226SJulian Elischer 					bluetooth_hci_command_timeout());
358878ed226SJulian Elischer 	} else
359878ed226SJulian Elischer 		KASSERT(0,
360878ed226SJulian Elischer ("%s: %s - Duplicated command timeout!\n", __func__, NG_NODE_NAME(unit->node)));
361878ed226SJulian Elischer } /* ng_hci_command_timeout */
362878ed226SJulian Elischer 
363878ed226SJulian Elischer /*
364878ed226SJulian Elischer  * Unset HCI command timeout
365878ed226SJulian Elischer  */
366878ed226SJulian Elischer 
367878ed226SJulian Elischer void
368878ed226SJulian Elischer ng_hci_command_untimeout(ng_hci_unit_p unit)
369878ed226SJulian Elischer {
370878ed226SJulian Elischer 	if (unit->state & NG_HCI_UNIT_COMMAND_PENDING) {
371878ed226SJulian Elischer 		unit->state &= ~NG_HCI_UNIT_COMMAND_PENDING;
372878ed226SJulian Elischer 		untimeout(ng_hci_command_queue_timeout, unit, unit->cmd_timo);
373878ed226SJulian Elischer 		NG_NODE_UNREF(unit->node);
374878ed226SJulian Elischer 	} else
375878ed226SJulian Elischer 		KASSERT(0,
376878ed226SJulian Elischer ("%s: %s - No command timeout!\n", __func__, NG_NODE_NAME(unit->node)));
377878ed226SJulian Elischer } /* ng_hci_command_untimeout */
378878ed226SJulian Elischer 
379878ed226SJulian Elischer /*
380878ed226SJulian Elischer  * OK timeout has happend, so queue timeout processing function
381878ed226SJulian Elischer  */
382878ed226SJulian Elischer 
383878ed226SJulian Elischer static void
384878ed226SJulian Elischer ng_hci_command_queue_timeout(void *context)
385878ed226SJulian Elischer {
386878ed226SJulian Elischer 	ng_hci_unit_p	unit = (ng_hci_unit_p) context;
387878ed226SJulian Elischer 	node_p		node = unit->node;
388878ed226SJulian Elischer 
389878ed226SJulian Elischer 	if (NG_NODE_IS_VALID(node))
390878ed226SJulian Elischer 		ng_send_fn(node,NULL,&ng_hci_process_command_timeout,unit,0);
391878ed226SJulian Elischer 
392878ed226SJulian Elischer 	NG_NODE_UNREF(node);
393878ed226SJulian Elischer } /* ng_hci_command_queue_timeout */
394878ed226SJulian Elischer 
395878ed226SJulian Elischer /*
396878ed226SJulian Elischer  * Set HCI connection timeout
397878ed226SJulian Elischer  */
398878ed226SJulian Elischer 
399878ed226SJulian Elischer void
400878ed226SJulian Elischer ng_hci_con_timeout(ng_hci_unit_con_p con)
401878ed226SJulian Elischer {
402878ed226SJulian Elischer 	if (!(con->flags & NG_HCI_CON_TIMEOUT_PENDING)) {
403878ed226SJulian Elischer 		NG_NODE_REF(con->unit->node);
404878ed226SJulian Elischer 		con->flags |= NG_HCI_CON_TIMEOUT_PENDING;
405878ed226SJulian Elischer 		con->con_timo = timeout(ng_hci_con_queue_timeout, con,
406878ed226SJulian Elischer 					bluetooth_hci_connect_timeout());
407878ed226SJulian Elischer 	} else
408878ed226SJulian Elischer 		KASSERT(0,
409878ed226SJulian Elischer ("%s: %s - Duplicated connection timeout!\n",
410878ed226SJulian Elischer 			__func__, NG_NODE_NAME(con->unit->node)));
411878ed226SJulian Elischer } /* ng_hci_con_timeout */
412878ed226SJulian Elischer 
413878ed226SJulian Elischer /*
414878ed226SJulian Elischer  * Unset HCI connection timeout
415878ed226SJulian Elischer  */
416878ed226SJulian Elischer 
417878ed226SJulian Elischer void
418878ed226SJulian Elischer ng_hci_con_untimeout(ng_hci_unit_con_p con)
419878ed226SJulian Elischer {
420878ed226SJulian Elischer 	if (con->flags & NG_HCI_CON_TIMEOUT_PENDING) {
421878ed226SJulian Elischer 		con->flags &= ~NG_HCI_CON_TIMEOUT_PENDING;
422878ed226SJulian Elischer 		untimeout(ng_hci_con_queue_timeout, con, con->con_timo);
423878ed226SJulian Elischer 		NG_NODE_UNREF(con->unit->node);
424878ed226SJulian Elischer 	} else
425878ed226SJulian Elischer 		KASSERT(0,
426878ed226SJulian Elischer ("%s: %s - No connection timeout!\n", __func__, NG_NODE_NAME(con->unit->node)));
427878ed226SJulian Elischer } /* ng_hci_con_untimeout */
428878ed226SJulian Elischer 
429878ed226SJulian Elischer /*
430878ed226SJulian Elischer  * OK timeout has happend, so queue timeout processing function
431878ed226SJulian Elischer  */
432878ed226SJulian Elischer 
433878ed226SJulian Elischer static void
434878ed226SJulian Elischer ng_hci_con_queue_timeout(void *context)
435878ed226SJulian Elischer {
436878ed226SJulian Elischer 	ng_hci_unit_con_p	con = (ng_hci_unit_con_p) context;
437878ed226SJulian Elischer 	node_p			node = con->unit->node;
438878ed226SJulian Elischer 
439878ed226SJulian Elischer 	if (NG_NODE_IS_VALID(node))
440878ed226SJulian Elischer 		ng_send_fn(node, NULL, &ng_hci_process_con_timeout, con, 0);
441878ed226SJulian Elischer 
442878ed226SJulian Elischer 	NG_NODE_UNREF(node);
443878ed226SJulian Elischer } /* ng_hci_con_queue_timeout */
444878ed226SJulian Elischer 
445878ed226SJulian Elischer /*
446878ed226SJulian Elischer  * Set HCI connection watchdog timeout
447878ed226SJulian Elischer  */
448878ed226SJulian Elischer 
449878ed226SJulian Elischer void
450878ed226SJulian Elischer ng_hci_con_watchdog_timeout(ng_hci_unit_con_p con)
451878ed226SJulian Elischer {
452878ed226SJulian Elischer 	if (!(con->flags & NG_HCI_CON_WATCHDOG_TIMEOUT_PENDING)) {
453878ed226SJulian Elischer 		NG_NODE_REF(con->unit->node);
454878ed226SJulian Elischer 		con->flags |= NG_HCI_CON_WATCHDOG_TIMEOUT_PENDING;
455878ed226SJulian Elischer 		con->watchdog_timo = timeout(ng_hci_con_queue_watchdog_timeout,
456878ed226SJulian Elischer 					con, bluetooth_hci_watchdog_timeout());
457878ed226SJulian Elischer 	} else
458878ed226SJulian Elischer 		KASSERT(0,
459878ed226SJulian Elischer ("%s: %s - Duplicated connection watchdog timeout!\n",
460878ed226SJulian Elischer 			__func__, NG_NODE_NAME(con->unit->node)));
461878ed226SJulian Elischer } /* ng_hci_con_watchdog_timeout */
462878ed226SJulian Elischer 
463878ed226SJulian Elischer /*
464878ed226SJulian Elischer  * Unset HCI connection watchdog timeout
465878ed226SJulian Elischer  */
466878ed226SJulian Elischer 
467878ed226SJulian Elischer void
468878ed226SJulian Elischer ng_hci_con_watchdog_untimeout(ng_hci_unit_con_p con)
469878ed226SJulian Elischer {
470878ed226SJulian Elischer 	if (con->flags & NG_HCI_CON_WATCHDOG_TIMEOUT_PENDING) {
471878ed226SJulian Elischer 		con->flags &= ~NG_HCI_CON_WATCHDOG_TIMEOUT_PENDING;
472878ed226SJulian Elischer 		untimeout(ng_hci_con_queue_watchdog_timeout, con,
473878ed226SJulian Elischer 			con->watchdog_timo);
474878ed226SJulian Elischer 		NG_NODE_UNREF(con->unit->node);
475878ed226SJulian Elischer 	} else
476878ed226SJulian Elischer 		KASSERT(0,
477878ed226SJulian Elischer ("%s: %s - No connection watchdog timeout!\n",
478878ed226SJulian Elischer 			 __func__, NG_NODE_NAME(con->unit->node)));
479878ed226SJulian Elischer } /* ng_hci_con_watchdog_untimeout */
480878ed226SJulian Elischer 
481878ed226SJulian Elischer /*
482878ed226SJulian Elischer  * OK timeout has happend, so queue timeout processing function
483878ed226SJulian Elischer  */
484878ed226SJulian Elischer 
485878ed226SJulian Elischer static void
486878ed226SJulian Elischer ng_hci_con_queue_watchdog_timeout(void *context)
487878ed226SJulian Elischer {
488878ed226SJulian Elischer 	ng_hci_unit_con_p	con = (ng_hci_unit_con_p) context;
489878ed226SJulian Elischer 	node_p			node = con->unit->node;
490878ed226SJulian Elischer 
491878ed226SJulian Elischer 	if (NG_NODE_IS_VALID(node))
492878ed226SJulian Elischer 		ng_send_fn(node, NULL, &ng_hci_process_con_watchdog_timeout,
493878ed226SJulian Elischer 			con, 0);
494878ed226SJulian Elischer 
495878ed226SJulian Elischer 	NG_NODE_UNREF(node);
496878ed226SJulian Elischer } /* ng_hci_con_queue_watchdog_timeout */
497878ed226SJulian Elischer 
498878ed226SJulian Elischer #if 0
499878ed226SJulian Elischer /*
500878ed226SJulian Elischer  * Convert numeric error code/reason to a string
501878ed226SJulian Elischer  */
502878ed226SJulian Elischer 
503878ed226SJulian Elischer char const * const
504878ed226SJulian Elischer ng_hci_str_error(u_int16_t code)
505878ed226SJulian Elischer {
506878ed226SJulian Elischer #define	LAST_ERROR_CODE			((sizeof(s)/sizeof(s[0]))-1)
507878ed226SJulian Elischer 	static char const * const	s[] = {
508878ed226SJulian Elischer 	/* 0x00 */ "No error",
509878ed226SJulian Elischer 	/* 0x01 */ "Unknown HCI command",
510878ed226SJulian Elischer 	/* 0x02 */ "No connection",
511878ed226SJulian Elischer 	/* 0x03 */ "Hardware failure",
512878ed226SJulian Elischer 	/* 0x04 */ "Page timeout",
513878ed226SJulian Elischer 	/* 0x05 */ "Authentication failure",
514878ed226SJulian Elischer 	/* 0x06 */ "Key missing",
515878ed226SJulian Elischer 	/* 0x07 */ "Memory full",
516878ed226SJulian Elischer 	/* 0x08 */ "Connection timeout",
517878ed226SJulian Elischer 	/* 0x09 */ "Max number of connections",
518878ed226SJulian Elischer 	/* 0x0a */ "Max number of SCO connections to a unit",
519878ed226SJulian Elischer 	/* 0x0b */ "ACL connection already exists",
520878ed226SJulian Elischer 	/* 0x0c */ "Command disallowed",
521878ed226SJulian Elischer 	/* 0x0d */ "Host rejected due to limited resources",
522878ed226SJulian Elischer 	/* 0x0e */ "Host rejected due to securiity reasons",
523878ed226SJulian Elischer 	/* 0x0f */ "Host rejected due to remote unit is a personal unit",
524878ed226SJulian Elischer 	/* 0x10 */ "Host timeout",
525878ed226SJulian Elischer 	/* 0x11 */ "Unsupported feature or parameter value",
526878ed226SJulian Elischer 	/* 0x12 */ "Invalid HCI command parameter",
527878ed226SJulian Elischer 	/* 0x13 */ "Other end terminated connection: User ended connection",
528878ed226SJulian Elischer 	/* 0x14 */ "Other end terminated connection: Low resources",
529878ed226SJulian Elischer 	/* 0x15 */ "Other end terminated connection: About to power off",
530878ed226SJulian Elischer 	/* 0x16 */ "Connection terminated by local host",
531878ed226SJulian Elischer 	/* 0x17 */ "Repeated attempts",
532878ed226SJulian Elischer 	/* 0x18 */ "Pairing not allowed",
533878ed226SJulian Elischer 	/* 0x19 */ "Unknown LMP PDU",
534878ed226SJulian Elischer 	/* 0x1a */ "Unsupported remote feature",
535878ed226SJulian Elischer 	/* 0x1b */ "SCO offset rejected",
536878ed226SJulian Elischer 	/* 0x1c */ "SCO interval rejected",
537878ed226SJulian Elischer 	/* 0x1d */ "SCO air mode rejected",
538878ed226SJulian Elischer 	/* 0x1e */ "Invalid LMP parameters",
539878ed226SJulian Elischer 	/* 0x1f */ "Unspecified error",
540878ed226SJulian Elischer 	/* 0x20 */ "Unsupported LMP parameter value",
541878ed226SJulian Elischer 	/* 0x21 */ "Role change not allowed",
542878ed226SJulian Elischer 	/* 0x22 */ "LMP response timeout",
543878ed226SJulian Elischer 	/* 0x23 */ "LMP error transaction collision",
544878ed226SJulian Elischer 	/* 0x24 */ "LMP PSU not allowed",
545878ed226SJulian Elischer 	/* 0x25 */ "Encryption mode not acceptable",
546878ed226SJulian Elischer 	/* 0x26 */ "Unit key used",
547878ed226SJulian Elischer 	/* 0x27 */ "QoS is not supported",
548878ed226SJulian Elischer 	/* 0x28 */ "Instant passed",
549878ed226SJulian Elischer 	/* 0x29 */ "Paring with unit key not supported",
550878ed226SJulian Elischer 	/* SHOULD ALWAYS BE LAST */ "Unknown error"
551878ed226SJulian Elischer 	};
552878ed226SJulian Elischer 
553878ed226SJulian Elischer 	return ((code >= LAST_ERROR_CODE)? s[LAST_ERROR_CODE] : s[code]);
554878ed226SJulian Elischer } /* ng_hci_str_error */
555878ed226SJulian Elischer #endif
556878ed226SJulian Elischer 
557