ng_hci_misc.c revision 111119
1107120Sjulian/*
2107120Sjulian * ng_hci_misc.c
3107120Sjulian *
4107120Sjulian * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
5107120Sjulian * All rights reserved.
6107120Sjulian *
7107120Sjulian * Redistribution and use in source and binary forms, with or without
8107120Sjulian * modification, are permitted provided that the following conditions
9107120Sjulian * are met:
10107120Sjulian * 1. Redistributions of source code must retain the above copyright
11107120Sjulian *    notice, this list of conditions and the following disclaimer.
12107120Sjulian * 2. Redistributions in binary form must reproduce the above copyright
13107120Sjulian *    notice, this list of conditions and the following disclaimer in the
14107120Sjulian *    documentation and/or other materials provided with the distribution.
15107120Sjulian *
16107120Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17107120Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18107120Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19107120Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20107120Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21107120Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22107120Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23107120Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24107120Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25107120Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26107120Sjulian * SUCH DAMAGE.
27107120Sjulian *
28107120Sjulian * $Id: ng_hci_misc.c,v 1.18 2002/10/30 00:18:19 max Exp $
29107120Sjulian * $FreeBSD: head/sys/netgraph/bluetooth/hci/ng_hci_misc.c 111119 2003-02-19 05:47:46Z imp $
30107120Sjulian */
31107120Sjulian
32107120Sjulian#include <sys/param.h>
33107120Sjulian#include <sys/systm.h>
34107120Sjulian#include <sys/kernel.h>
35107120Sjulian#include <sys/malloc.h>
36107120Sjulian#include <sys/mbuf.h>
37107120Sjulian#include <sys/queue.h>
38107120Sjulian#include <netgraph/ng_message.h>
39107120Sjulian#include <netgraph/netgraph.h>
40107120Sjulian#include "ng_bluetooth.h"
41107120Sjulian#include "ng_hci.h"
42107120Sjulian#include "ng_hci_var.h"
43107120Sjulian#include "ng_hci_cmds.h"
44107120Sjulian#include "ng_hci_evnt.h"
45107120Sjulian#include "ng_hci_ulpi.h"
46107120Sjulian#include "ng_hci_misc.h"
47107120Sjulian
48107120Sjulian/******************************************************************************
49107120Sjulian ******************************************************************************
50107120Sjulian **                              Utility routines
51107120Sjulian ******************************************************************************
52107120Sjulian ******************************************************************************/
53107120Sjulian
54107120Sjulianstatic void	ng_hci_command_queue_timeout		(void *);
55107120Sjulianstatic void	ng_hci_con_queue_timeout		(void *);
56107120Sjulianstatic void	ng_hci_con_queue_watchdog_timeout	(void *);
57107120Sjulian
58107120Sjulian/*
59107120Sjulian * Give packet to RAW hook
60107120Sjulian * Assumes input mbuf is read only.
61107120Sjulian */
62107120Sjulian
63107120Sjulianvoid
64107120Sjulianng_hci_mtap(ng_hci_unit_p unit, struct mbuf *m0)
65107120Sjulian{
66107120Sjulian	struct mbuf	*m = NULL;
67107120Sjulian	int		 error = 0;
68107120Sjulian
69107120Sjulian	if (unit->raw != NULL && NG_HOOK_IS_VALID(unit->raw)) {
70111119Simp		m = m_dup(m0, M_DONTWAIT);
71107120Sjulian		if (m != NULL)
72107120Sjulian			NG_SEND_DATA_ONLY(error, unit->raw, m);
73107120Sjulian
74107120Sjulian		if (error != 0)
75107120Sjulian			NG_HCI_INFO(
76107120Sjulian"%s: %s - Could not forward packet, error=%d\n",
77107120Sjulian				__func__, NG_NODE_NAME(unit->node), error);
78107120Sjulian	}
79107120Sjulian} /* ng_hci_mtap */
80107120Sjulian
81107120Sjulian/*
82107120Sjulian * Send notification to the upper layer's
83107120Sjulian */
84107120Sjulian
85107120Sjulianvoid
86107120Sjulianng_hci_node_is_up(node_p node, hook_p hook, void *arg1, int arg2)
87107120Sjulian{
88107120Sjulian	ng_hci_unit_p		 unit = NULL;
89107120Sjulian	struct ng_mesg		*msg = NULL;
90107120Sjulian	ng_hci_node_up_ep	*ep = NULL;
91107120Sjulian	int			 error;
92107120Sjulian
93107120Sjulian	if (node == NULL || NG_NODE_NOT_VALID(node) ||
94107120Sjulian	    hook == NULL || NG_HOOK_NOT_VALID(hook))
95107120Sjulian		return;
96107120Sjulian
97107120Sjulian	unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node);
98107120Sjulian	if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY)
99107120Sjulian		return;
100107120Sjulian
101107120Sjulian	if (hook != unit->acl && hook != unit->sco)
102107120Sjulian		return;
103107120Sjulian
104107120Sjulian	NG_MKMESSAGE(msg,NGM_HCI_COOKIE,NGM_HCI_NODE_UP,sizeof(*ep),M_NOWAIT);
105107120Sjulian	if (msg != NULL) {
106107120Sjulian		ep = (ng_hci_node_up_ep *)(msg->data);
107107120Sjulian
108107120Sjulian		if (hook == unit->acl) {
109107120Sjulian			NG_HCI_BUFF_ACL_SIZE(unit->buffer, ep->pkt_size);
110107120Sjulian			NG_HCI_BUFF_ACL_TOTAL(unit->buffer, ep->num_pkts);
111107120Sjulian		} else {
112107120Sjulian			NG_HCI_BUFF_SCO_SIZE(unit->buffer, ep->pkt_size);
113107120Sjulian			NG_HCI_BUFF_SCO_TOTAL(unit->buffer, ep->num_pkts);
114107120Sjulian		}
115107120Sjulian
116107120Sjulian		bcopy(&unit->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));
117107120Sjulian
118107120Sjulian		NG_SEND_MSG_HOOK(error, node, msg, hook, NULL);
119107120Sjulian	} else
120107120Sjulian		error = ENOMEM;
121107120Sjulian
122107120Sjulian	if (error != 0)
123107120Sjulian		NG_HCI_INFO(
124107120Sjulian"%s: %s - failed to send NODE_UP message to hook \"%s\", error=%d\n",
125107120Sjulian			__func__, NG_NODE_NAME(unit->node),
126107120Sjulian			NG_HOOK_NAME(hook), error);
127107120Sjulian} /* ng_hci_node_is_up */
128107120Sjulian
129107120Sjulian/*
130107120Sjulian * Clean unit (helper)
131107120Sjulian */
132107120Sjulian
133107120Sjulianvoid
134107120Sjulianng_hci_unit_clean(ng_hci_unit_p unit, int reason)
135107120Sjulian{
136107120Sjulian	int	size;
137107120Sjulian
138107120Sjulian	/* Drain command queue */
139107120Sjulian	if (unit->state & NG_HCI_UNIT_COMMAND_PENDING)
140107120Sjulian		ng_hci_command_untimeout(unit);
141107120Sjulian
142107120Sjulian	NG_BT_MBUFQ_DRAIN(&unit->cmdq);
143107120Sjulian	NG_HCI_BUFF_CMD_SET(unit->buffer, 1);
144107120Sjulian
145107120Sjulian	/* Clean up connection list */
146107120Sjulian	while (!LIST_EMPTY(&unit->con_list)) {
147107120Sjulian		ng_hci_unit_con_p	con = LIST_FIRST(&unit->con_list);
148107120Sjulian
149107120Sjulian		/*
150107120Sjulian		 * Notify upper layer protocol and destroy connection
151107120Sjulian		 * descriptor. Do not really care about the result.
152107120Sjulian		 */
153107120Sjulian
154107120Sjulian		ng_hci_lp_discon_ind(con, reason);
155107120Sjulian		ng_hci_free_con(con);
156107120Sjulian	}
157107120Sjulian
158107120Sjulian	NG_HCI_BUFF_ACL_TOTAL(unit->buffer, size);
159107120Sjulian	NG_HCI_BUFF_ACL_FREE(unit->buffer, size);
160107120Sjulian
161107120Sjulian	NG_HCI_BUFF_SCO_TOTAL(unit->buffer, size);
162107120Sjulian	NG_HCI_BUFF_SCO_FREE(unit->buffer, size);
163107120Sjulian
164107120Sjulian	/* Clean up neighbors list */
165107120Sjulian	ng_hci_flush_neighbor_cache(unit);
166107120Sjulian} /* ng_hci_unit_clean */
167107120Sjulian
168107120Sjulian/*
169107120Sjulian * Allocate and link new unit neighbor cache entry
170107120Sjulian */
171107120Sjulian
172107120Sjulianng_hci_neighbor_p
173107120Sjulianng_hci_new_neighbor(ng_hci_unit_p unit)
174107120Sjulian{
175107120Sjulian	ng_hci_neighbor_p	n = NULL;
176107120Sjulian
177107120Sjulian	MALLOC(n, ng_hci_neighbor_p, sizeof(*n), M_NETGRAPH_HCI,
178107120Sjulian		M_NOWAIT | M_ZERO);
179107120Sjulian	if (n != NULL) {
180107120Sjulian		getmicrotime(&n->updated);
181107120Sjulian		LIST_INSERT_HEAD(&unit->neighbors, n, next);
182107120Sjulian	}
183107120Sjulian
184107120Sjulian	return (n);
185107120Sjulian} /* ng_hci_new_neighbor */
186107120Sjulian
187107120Sjulian/*
188107120Sjulian * Free unit neighbor cache entry
189107120Sjulian */
190107120Sjulian
191107120Sjulianvoid
192107120Sjulianng_hci_free_neighbor(ng_hci_neighbor_p n)
193107120Sjulian{
194107120Sjulian	LIST_REMOVE(n, next);
195107120Sjulian	bzero(n, sizeof(*n));
196107120Sjulian	FREE(n, M_NETGRAPH_HCI);
197107120Sjulian} /* ng_hci_free_neighbor */
198107120Sjulian
199107120Sjulian/*
200107120Sjulian * Flush neighbor cache
201107120Sjulian */
202107120Sjulian
203107120Sjulianvoid
204107120Sjulianng_hci_flush_neighbor_cache(ng_hci_unit_p unit)
205107120Sjulian{
206107120Sjulian	while (!LIST_EMPTY(&unit->neighbors))
207107120Sjulian		ng_hci_free_neighbor(LIST_FIRST(&unit->neighbors));
208107120Sjulian} /* ng_hci_flush_neighbor_cache */
209107120Sjulian
210107120Sjulian/*
211107120Sjulian * Lookup unit in neighbor cache
212107120Sjulian */
213107120Sjulian
214107120Sjulianng_hci_neighbor_p
215107120Sjulianng_hci_get_neighbor(ng_hci_unit_p unit, bdaddr_p bdaddr)
216107120Sjulian{
217107120Sjulian	ng_hci_neighbor_p	n = NULL;
218107120Sjulian
219107120Sjulian	for (n = LIST_FIRST(&unit->neighbors); n != NULL; ) {
220107120Sjulian		ng_hci_neighbor_p	nn = LIST_NEXT(n, next);
221107120Sjulian
222107120Sjulian		if (!ng_hci_neighbor_stale(n)) {
223107120Sjulian			if (bcmp(&n->bdaddr, bdaddr, sizeof(*bdaddr)) == 0)
224107120Sjulian				break;
225107120Sjulian		} else
226107120Sjulian			ng_hci_free_neighbor(n); /* remove old entry */
227107120Sjulian
228107120Sjulian		n = nn;
229107120Sjulian	}
230107120Sjulian
231107120Sjulian	return (n);
232107120Sjulian} /* ng_hci_get_neighbor */
233107120Sjulian
234107120Sjulian/*
235107120Sjulian * Check if neighbor entry is stale
236107120Sjulian */
237107120Sjulian
238107120Sjulianint
239107120Sjulianng_hci_neighbor_stale(ng_hci_neighbor_p n)
240107120Sjulian{
241107120Sjulian	struct timeval	now;
242107120Sjulian
243107120Sjulian	getmicrotime(&now);
244107120Sjulian
245107120Sjulian	return (now.tv_sec - n->updated.tv_sec > bluetooth_hci_max_neighbor_age());
246107120Sjulian} /* ng_hci_neighbor_stale */
247107120Sjulian
248107120Sjulian/*
249107120Sjulian * Allocate and link new connection descriptor
250107120Sjulian */
251107120Sjulian
252107120Sjulianng_hci_unit_con_p
253107120Sjulianng_hci_new_con(ng_hci_unit_p unit, int link_type)
254107120Sjulian{
255107120Sjulian	ng_hci_unit_con_p	con = NULL;
256107120Sjulian	int			num_pkts;
257107120Sjulian
258107120Sjulian	MALLOC(con, ng_hci_unit_con_p, sizeof(*con), M_NETGRAPH_HCI,
259107120Sjulian		M_NOWAIT | M_ZERO);
260107120Sjulian	if (con != NULL) {
261107120Sjulian		con->unit = unit;
262107120Sjulian		con->state = NG_HCI_CON_CLOSED;
263107120Sjulian		con->link_type = link_type;
264107120Sjulian
265107120Sjulian		if (con->link_type == NG_HCI_LINK_ACL)
266107120Sjulian			NG_HCI_BUFF_ACL_TOTAL(unit->buffer, num_pkts);
267107120Sjulian		else
268107120Sjulian			NG_HCI_BUFF_SCO_TOTAL(unit->buffer, num_pkts);
269107120Sjulian
270107120Sjulian		NG_BT_ITEMQ_INIT(&con->conq, num_pkts);
271107120Sjulian
272107120Sjulian		callout_handle_init(&con->con_timo);
273107120Sjulian		callout_handle_init(&con->watchdog_timo);
274107120Sjulian
275107120Sjulian		LIST_INSERT_HEAD(&unit->con_list, con, next);
276107120Sjulian	}
277107120Sjulian
278107120Sjulian	return (con);
279107120Sjulian} /* ng_hci_new_con */
280107120Sjulian
281107120Sjulian/*
282107120Sjulian * Free connection descriptor
283107120Sjulian */
284107120Sjulian
285107120Sjulianvoid
286107120Sjulianng_hci_free_con(ng_hci_unit_con_p con)
287107120Sjulian{
288107120Sjulian	LIST_REMOVE(con, next);
289107120Sjulian
290107120Sjulian	/* Remove all timeouts (if any) */
291107120Sjulian	if (con->flags & NG_HCI_CON_TIMEOUT_PENDING)
292107120Sjulian		ng_hci_con_untimeout(con);
293107120Sjulian
294107120Sjulian	if (con->flags & NG_HCI_CON_WATCHDOG_TIMEOUT_PENDING)
295107120Sjulian		ng_hci_con_watchdog_untimeout(con);
296107120Sjulian
297107120Sjulian	/*
298107120Sjulian	 * If we have pending packets then assume that Host Controller has
299107120Sjulian	 * flushed these packets and we can free them too
300107120Sjulian	 */
301107120Sjulian
302107120Sjulian	if (con->link_type == NG_HCI_LINK_ACL)
303107120Sjulian		NG_HCI_BUFF_ACL_FREE(con->unit->buffer, con->pending);
304107120Sjulian	else
305107120Sjulian		NG_HCI_BUFF_SCO_FREE(con->unit->buffer, con->pending);
306107120Sjulian
307107120Sjulian	NG_BT_ITEMQ_DESTROY(&con->conq);
308107120Sjulian
309107120Sjulian	bzero(con, sizeof(*con));
310107120Sjulian	FREE(con, M_NETGRAPH_HCI);
311107120Sjulian} /* ng_hci_free_con */
312107120Sjulian
313107120Sjulian/*
314107120Sjulian * Lookup connection for given unit and connection handle.
315107120Sjulian */
316107120Sjulian
317107120Sjulianng_hci_unit_con_p
318107120Sjulianng_hci_con_by_handle(ng_hci_unit_p unit, int con_handle)
319107120Sjulian{
320107120Sjulian	ng_hci_unit_con_p	con = NULL;
321107120Sjulian
322107120Sjulian	LIST_FOREACH(con, &unit->con_list, next)
323107120Sjulian		if (con->con_handle == con_handle)
324107120Sjulian			break;
325107120Sjulian
326107120Sjulian	return (con);
327107120Sjulian} /* ng_hci_con_by_handle */
328107120Sjulian
329107120Sjulian/*
330107120Sjulian * Lookup connection for given unit, link type and remove unit address
331107120Sjulian */
332107120Sjulian
333107120Sjulianng_hci_unit_con_p
334107120Sjulianng_hci_con_by_bdaddr(ng_hci_unit_p unit, bdaddr_p bdaddr, int link_type)
335107120Sjulian{
336107120Sjulian	ng_hci_unit_con_p	con = NULL;
337107120Sjulian
338107120Sjulian	LIST_FOREACH(con, &unit->con_list, next)
339107120Sjulian		if (con->link_type == link_type &&
340107120Sjulian		    bcmp(&con->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0)
341107120Sjulian			break;
342107120Sjulian
343107120Sjulian	return (con);
344107120Sjulian} /* ng_hci_con_by_bdaddr */
345107120Sjulian
346107120Sjulian/*
347107120Sjulian * Set HCI command timeout
348107120Sjulian */
349107120Sjulian
350107120Sjulianvoid
351107120Sjulianng_hci_command_timeout(ng_hci_unit_p unit)
352107120Sjulian{
353107120Sjulian	if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) {
354107120Sjulian		NG_NODE_REF(unit->node);
355107120Sjulian		unit->state |= NG_HCI_UNIT_COMMAND_PENDING;
356107120Sjulian		unit->cmd_timo = timeout(ng_hci_command_queue_timeout, unit,
357107120Sjulian					bluetooth_hci_command_timeout());
358107120Sjulian	} else
359107120Sjulian		KASSERT(0,
360107120Sjulian("%s: %s - Duplicated command timeout!\n", __func__, NG_NODE_NAME(unit->node)));
361107120Sjulian} /* ng_hci_command_timeout */
362107120Sjulian
363107120Sjulian/*
364107120Sjulian * Unset HCI command timeout
365107120Sjulian */
366107120Sjulian
367107120Sjulianvoid
368107120Sjulianng_hci_command_untimeout(ng_hci_unit_p unit)
369107120Sjulian{
370107120Sjulian	if (unit->state & NG_HCI_UNIT_COMMAND_PENDING) {
371107120Sjulian		unit->state &= ~NG_HCI_UNIT_COMMAND_PENDING;
372107120Sjulian		untimeout(ng_hci_command_queue_timeout, unit, unit->cmd_timo);
373107120Sjulian		NG_NODE_UNREF(unit->node);
374107120Sjulian	} else
375107120Sjulian		KASSERT(0,
376107120Sjulian("%s: %s - No command timeout!\n", __func__, NG_NODE_NAME(unit->node)));
377107120Sjulian} /* ng_hci_command_untimeout */
378107120Sjulian
379107120Sjulian/*
380107120Sjulian * OK timeout has happend, so queue timeout processing function
381107120Sjulian */
382107120Sjulian
383107120Sjulianstatic void
384107120Sjulianng_hci_command_queue_timeout(void *context)
385107120Sjulian{
386107120Sjulian	ng_hci_unit_p	unit = (ng_hci_unit_p) context;
387107120Sjulian	node_p		node = unit->node;
388107120Sjulian
389107120Sjulian	if (NG_NODE_IS_VALID(node))
390107120Sjulian		ng_send_fn(node,NULL,&ng_hci_process_command_timeout,unit,0);
391107120Sjulian
392107120Sjulian	NG_NODE_UNREF(node);
393107120Sjulian} /* ng_hci_command_queue_timeout */
394107120Sjulian
395107120Sjulian/*
396107120Sjulian * Set HCI connection timeout
397107120Sjulian */
398107120Sjulian
399107120Sjulianvoid
400107120Sjulianng_hci_con_timeout(ng_hci_unit_con_p con)
401107120Sjulian{
402107120Sjulian	if (!(con->flags & NG_HCI_CON_TIMEOUT_PENDING)) {
403107120Sjulian		NG_NODE_REF(con->unit->node);
404107120Sjulian		con->flags |= NG_HCI_CON_TIMEOUT_PENDING;
405107120Sjulian		con->con_timo = timeout(ng_hci_con_queue_timeout, con,
406107120Sjulian					bluetooth_hci_connect_timeout());
407107120Sjulian	} else
408107120Sjulian		KASSERT(0,
409107120Sjulian("%s: %s - Duplicated connection timeout!\n",
410107120Sjulian			__func__, NG_NODE_NAME(con->unit->node)));
411107120Sjulian} /* ng_hci_con_timeout */
412107120Sjulian
413107120Sjulian/*
414107120Sjulian * Unset HCI connection timeout
415107120Sjulian */
416107120Sjulian
417107120Sjulianvoid
418107120Sjulianng_hci_con_untimeout(ng_hci_unit_con_p con)
419107120Sjulian{
420107120Sjulian	if (con->flags & NG_HCI_CON_TIMEOUT_PENDING) {
421107120Sjulian		con->flags &= ~NG_HCI_CON_TIMEOUT_PENDING;
422107120Sjulian		untimeout(ng_hci_con_queue_timeout, con, con->con_timo);
423107120Sjulian		NG_NODE_UNREF(con->unit->node);
424107120Sjulian	} else
425107120Sjulian		KASSERT(0,
426107120Sjulian("%s: %s - No connection timeout!\n", __func__, NG_NODE_NAME(con->unit->node)));
427107120Sjulian} /* ng_hci_con_untimeout */
428107120Sjulian
429107120Sjulian/*
430107120Sjulian * OK timeout has happend, so queue timeout processing function
431107120Sjulian */
432107120Sjulian
433107120Sjulianstatic void
434107120Sjulianng_hci_con_queue_timeout(void *context)
435107120Sjulian{
436107120Sjulian	ng_hci_unit_con_p	con = (ng_hci_unit_con_p) context;
437107120Sjulian	node_p			node = con->unit->node;
438107120Sjulian
439107120Sjulian	if (NG_NODE_IS_VALID(node))
440107120Sjulian		ng_send_fn(node, NULL, &ng_hci_process_con_timeout, con, 0);
441107120Sjulian
442107120Sjulian	NG_NODE_UNREF(node);
443107120Sjulian} /* ng_hci_con_queue_timeout */
444107120Sjulian
445107120Sjulian/*
446107120Sjulian * Set HCI connection watchdog timeout
447107120Sjulian */
448107120Sjulian
449107120Sjulianvoid
450107120Sjulianng_hci_con_watchdog_timeout(ng_hci_unit_con_p con)
451107120Sjulian{
452107120Sjulian	if (!(con->flags & NG_HCI_CON_WATCHDOG_TIMEOUT_PENDING)) {
453107120Sjulian		NG_NODE_REF(con->unit->node);
454107120Sjulian		con->flags |= NG_HCI_CON_WATCHDOG_TIMEOUT_PENDING;
455107120Sjulian		con->watchdog_timo = timeout(ng_hci_con_queue_watchdog_timeout,
456107120Sjulian					con, bluetooth_hci_watchdog_timeout());
457107120Sjulian	} else
458107120Sjulian		KASSERT(0,
459107120Sjulian("%s: %s - Duplicated connection watchdog timeout!\n",
460107120Sjulian			__func__, NG_NODE_NAME(con->unit->node)));
461107120Sjulian} /* ng_hci_con_watchdog_timeout */
462107120Sjulian
463107120Sjulian/*
464107120Sjulian * Unset HCI connection watchdog timeout
465107120Sjulian */
466107120Sjulian
467107120Sjulianvoid
468107120Sjulianng_hci_con_watchdog_untimeout(ng_hci_unit_con_p con)
469107120Sjulian{
470107120Sjulian	if (con->flags & NG_HCI_CON_WATCHDOG_TIMEOUT_PENDING) {
471107120Sjulian		con->flags &= ~NG_HCI_CON_WATCHDOG_TIMEOUT_PENDING;
472107120Sjulian		untimeout(ng_hci_con_queue_watchdog_timeout, con,
473107120Sjulian			con->watchdog_timo);
474107120Sjulian		NG_NODE_UNREF(con->unit->node);
475107120Sjulian	} else
476107120Sjulian		KASSERT(0,
477107120Sjulian("%s: %s - No connection watchdog timeout!\n",
478107120Sjulian			 __func__, NG_NODE_NAME(con->unit->node)));
479107120Sjulian} /* ng_hci_con_watchdog_untimeout */
480107120Sjulian
481107120Sjulian/*
482107120Sjulian * OK timeout has happend, so queue timeout processing function
483107120Sjulian */
484107120Sjulian
485107120Sjulianstatic void
486107120Sjulianng_hci_con_queue_watchdog_timeout(void *context)
487107120Sjulian{
488107120Sjulian	ng_hci_unit_con_p	con = (ng_hci_unit_con_p) context;
489107120Sjulian	node_p			node = con->unit->node;
490107120Sjulian
491107120Sjulian	if (NG_NODE_IS_VALID(node))
492107120Sjulian		ng_send_fn(node, NULL, &ng_hci_process_con_watchdog_timeout,
493107120Sjulian			con, 0);
494107120Sjulian
495107120Sjulian	NG_NODE_UNREF(node);
496107120Sjulian} /* ng_hci_con_queue_watchdog_timeout */
497107120Sjulian
498107120Sjulian#if 0
499107120Sjulian/*
500107120Sjulian * Convert numeric error code/reason to a string
501107120Sjulian */
502107120Sjulian
503107120Sjulianchar const * const
504107120Sjulianng_hci_str_error(u_int16_t code)
505107120Sjulian{
506107120Sjulian#define	LAST_ERROR_CODE			((sizeof(s)/sizeof(s[0]))-1)
507107120Sjulian	static char const * const	s[] = {
508107120Sjulian	/* 0x00 */ "No error",
509107120Sjulian	/* 0x01 */ "Unknown HCI command",
510107120Sjulian	/* 0x02 */ "No connection",
511107120Sjulian	/* 0x03 */ "Hardware failure",
512107120Sjulian	/* 0x04 */ "Page timeout",
513107120Sjulian	/* 0x05 */ "Authentication failure",
514107120Sjulian	/* 0x06 */ "Key missing",
515107120Sjulian	/* 0x07 */ "Memory full",
516107120Sjulian	/* 0x08 */ "Connection timeout",
517107120Sjulian	/* 0x09 */ "Max number of connections",
518107120Sjulian	/* 0x0a */ "Max number of SCO connections to a unit",
519107120Sjulian	/* 0x0b */ "ACL connection already exists",
520107120Sjulian	/* 0x0c */ "Command disallowed",
521107120Sjulian	/* 0x0d */ "Host rejected due to limited resources",
522107120Sjulian	/* 0x0e */ "Host rejected due to securiity reasons",
523107120Sjulian	/* 0x0f */ "Host rejected due to remote unit is a personal unit",
524107120Sjulian	/* 0x10 */ "Host timeout",
525107120Sjulian	/* 0x11 */ "Unsupported feature or parameter value",
526107120Sjulian	/* 0x12 */ "Invalid HCI command parameter",
527107120Sjulian	/* 0x13 */ "Other end terminated connection: User ended connection",
528107120Sjulian	/* 0x14 */ "Other end terminated connection: Low resources",
529107120Sjulian	/* 0x15 */ "Other end terminated connection: About to power off",
530107120Sjulian	/* 0x16 */ "Connection terminated by local host",
531107120Sjulian	/* 0x17 */ "Repeated attempts",
532107120Sjulian	/* 0x18 */ "Pairing not allowed",
533107120Sjulian	/* 0x19 */ "Unknown LMP PDU",
534107120Sjulian	/* 0x1a */ "Unsupported remote feature",
535107120Sjulian	/* 0x1b */ "SCO offset rejected",
536107120Sjulian	/* 0x1c */ "SCO interval rejected",
537107120Sjulian	/* 0x1d */ "SCO air mode rejected",
538107120Sjulian	/* 0x1e */ "Invalid LMP parameters",
539107120Sjulian	/* 0x1f */ "Unspecified error",
540107120Sjulian	/* 0x20 */ "Unsupported LMP parameter value",
541107120Sjulian	/* 0x21 */ "Role change not allowed",
542107120Sjulian	/* 0x22 */ "LMP response timeout",
543107120Sjulian	/* 0x23 */ "LMP error transaction collision",
544107120Sjulian	/* 0x24 */ "LMP PSU not allowed",
545107120Sjulian	/* 0x25 */ "Encryption mode not acceptable",
546107120Sjulian	/* 0x26 */ "Unit key used",
547107120Sjulian	/* 0x27 */ "QoS is not supported",
548107120Sjulian	/* 0x28 */ "Instant passed",
549107120Sjulian	/* 0x29 */ "Paring with unit key not supported",
550107120Sjulian	/* SHOULD ALWAYS BE LAST */ "Unknown error"
551107120Sjulian	};
552107120Sjulian
553107120Sjulian	return ((code >= LAST_ERROR_CODE)? s[LAST_ERROR_CODE] : s[code]);
554107120Sjulian} /* ng_hci_str_error */
555107120Sjulian#endif
556107120Sjulian
557