ng_hci_misc.c revision 128076
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 *
28121054Semax * $Id: ng_hci_misc.c,v 1.5 2003/09/08 18:57:51 max Exp $
29107120Sjulian * $FreeBSD: head/sys/netgraph/bluetooth/hci/ng_hci_misc.c 128076 2004-04-09 23:01:42Z emax $
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
54107120Sjulian/*
55107120Sjulian * Give packet to RAW hook
56107120Sjulian * Assumes input mbuf is read only.
57107120Sjulian */
58107120Sjulian
59107120Sjulianvoid
60107120Sjulianng_hci_mtap(ng_hci_unit_p unit, struct mbuf *m0)
61107120Sjulian{
62107120Sjulian	struct mbuf	*m = NULL;
63107120Sjulian	int		 error = 0;
64107120Sjulian
65107120Sjulian	if (unit->raw != NULL && NG_HOOK_IS_VALID(unit->raw)) {
66111119Simp		m = m_dup(m0, M_DONTWAIT);
67107120Sjulian		if (m != NULL)
68107120Sjulian			NG_SEND_DATA_ONLY(error, unit->raw, m);
69107120Sjulian
70107120Sjulian		if (error != 0)
71107120Sjulian			NG_HCI_INFO(
72107120Sjulian"%s: %s - Could not forward packet, error=%d\n",
73107120Sjulian				__func__, NG_NODE_NAME(unit->node), error);
74107120Sjulian	}
75107120Sjulian} /* ng_hci_mtap */
76107120Sjulian
77107120Sjulian/*
78107120Sjulian * Send notification to the upper layer's
79107120Sjulian */
80107120Sjulian
81107120Sjulianvoid
82107120Sjulianng_hci_node_is_up(node_p node, hook_p hook, void *arg1, int arg2)
83107120Sjulian{
84107120Sjulian	ng_hci_unit_p		 unit = NULL;
85107120Sjulian	struct ng_mesg		*msg = NULL;
86107120Sjulian	ng_hci_node_up_ep	*ep = NULL;
87107120Sjulian	int			 error;
88107120Sjulian
89107120Sjulian	if (node == NULL || NG_NODE_NOT_VALID(node) ||
90107120Sjulian	    hook == NULL || NG_HOOK_NOT_VALID(hook))
91107120Sjulian		return;
92107120Sjulian
93107120Sjulian	unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node);
94107120Sjulian	if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY)
95107120Sjulian		return;
96107120Sjulian
97107120Sjulian	if (hook != unit->acl && hook != unit->sco)
98107120Sjulian		return;
99107120Sjulian
100107120Sjulian	NG_MKMESSAGE(msg,NGM_HCI_COOKIE,NGM_HCI_NODE_UP,sizeof(*ep),M_NOWAIT);
101107120Sjulian	if (msg != NULL) {
102107120Sjulian		ep = (ng_hci_node_up_ep *)(msg->data);
103107120Sjulian
104107120Sjulian		if (hook == unit->acl) {
105107120Sjulian			NG_HCI_BUFF_ACL_SIZE(unit->buffer, ep->pkt_size);
106107120Sjulian			NG_HCI_BUFF_ACL_TOTAL(unit->buffer, ep->num_pkts);
107107120Sjulian		} else {
108107120Sjulian			NG_HCI_BUFF_SCO_SIZE(unit->buffer, ep->pkt_size);
109107120Sjulian			NG_HCI_BUFF_SCO_TOTAL(unit->buffer, ep->num_pkts);
110107120Sjulian		}
111107120Sjulian
112107120Sjulian		bcopy(&unit->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));
113107120Sjulian
114128076Semax		NG_SEND_MSG_HOOK(error, node, msg, hook, 0);
115107120Sjulian	} else
116107120Sjulian		error = ENOMEM;
117107120Sjulian
118107120Sjulian	if (error != 0)
119107120Sjulian		NG_HCI_INFO(
120107120Sjulian"%s: %s - failed to send NODE_UP message to hook \"%s\", error=%d\n",
121107120Sjulian			__func__, NG_NODE_NAME(unit->node),
122107120Sjulian			NG_HOOK_NAME(hook), error);
123107120Sjulian} /* ng_hci_node_is_up */
124107120Sjulian
125107120Sjulian/*
126107120Sjulian * Clean unit (helper)
127107120Sjulian */
128107120Sjulian
129107120Sjulianvoid
130107120Sjulianng_hci_unit_clean(ng_hci_unit_p unit, int reason)
131107120Sjulian{
132107120Sjulian	int	size;
133107120Sjulian
134107120Sjulian	/* Drain command queue */
135107120Sjulian	if (unit->state & NG_HCI_UNIT_COMMAND_PENDING)
136107120Sjulian		ng_hci_command_untimeout(unit);
137107120Sjulian
138107120Sjulian	NG_BT_MBUFQ_DRAIN(&unit->cmdq);
139107120Sjulian	NG_HCI_BUFF_CMD_SET(unit->buffer, 1);
140107120Sjulian
141107120Sjulian	/* Clean up connection list */
142107120Sjulian	while (!LIST_EMPTY(&unit->con_list)) {
143107120Sjulian		ng_hci_unit_con_p	con = LIST_FIRST(&unit->con_list);
144107120Sjulian
145121054Semax		/* Remove all timeouts (if any) */
146121054Semax		if (con->flags & NG_HCI_CON_TIMEOUT_PENDING)
147121054Semax			ng_hci_con_untimeout(con);
148121054Semax
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;
257121054Semax	static int		fake_con_handle = 0x0f00;
258107120Sjulian
259107120Sjulian	MALLOC(con, ng_hci_unit_con_p, sizeof(*con), M_NETGRAPH_HCI,
260107120Sjulian		M_NOWAIT | M_ZERO);
261107120Sjulian	if (con != NULL) {
262107120Sjulian		con->unit = unit;
263107120Sjulian		con->state = NG_HCI_CON_CLOSED;
264121054Semax
265121054Semax		/*
266121054Semax		 * XXX
267121054Semax		 *
268121054Semax		 * Assign fake connection handle to the connection descriptor.
269121054Semax		 * Bluetooth specification marks 0x0f00 - 0x0fff connection
270121054Semax		 * handles as reserved. We need this fake connection handles
271121054Semax		 * for timeouts. Connection handle will be passed as argument
272121054Semax		 * to timeout so when timeout happens we can find the right
273121054Semax		 * connection descriptor. We can not pass pointers, because
274121054Semax		 * timeouts are external (to Netgraph) events and there might
275121054Semax		 * be a race when node/hook goes down and timeout event already
276121054Semax		 * went into node's queue
277121054Semax		 */
278121054Semax
279121054Semax		con->con_handle = fake_con_handle ++;
280121054Semax		if (fake_con_handle > 0x0fff)
281121054Semax			fake_con_handle = 0x0f00;
282121054Semax
283107120Sjulian		con->link_type = link_type;
284107120Sjulian
285107120Sjulian		if (con->link_type == NG_HCI_LINK_ACL)
286107120Sjulian			NG_HCI_BUFF_ACL_TOTAL(unit->buffer, num_pkts);
287107120Sjulian		else
288107120Sjulian			NG_HCI_BUFF_SCO_TOTAL(unit->buffer, num_pkts);
289107120Sjulian
290107120Sjulian		NG_BT_ITEMQ_INIT(&con->conq, num_pkts);
291107120Sjulian
292107120Sjulian		callout_handle_init(&con->con_timo);
293107120Sjulian
294107120Sjulian		LIST_INSERT_HEAD(&unit->con_list, con, next);
295107120Sjulian	}
296107120Sjulian
297107120Sjulian	return (con);
298107120Sjulian} /* ng_hci_new_con */
299107120Sjulian
300107120Sjulian/*
301107120Sjulian * Free connection descriptor
302107120Sjulian */
303107120Sjulian
304107120Sjulianvoid
305107120Sjulianng_hci_free_con(ng_hci_unit_con_p con)
306107120Sjulian{
307107120Sjulian	LIST_REMOVE(con, next);
308107120Sjulian
309107120Sjulian	/*
310107120Sjulian	 * If we have pending packets then assume that Host Controller has
311107120Sjulian	 * flushed these packets and we can free them too
312107120Sjulian	 */
313107120Sjulian
314107120Sjulian	if (con->link_type == NG_HCI_LINK_ACL)
315107120Sjulian		NG_HCI_BUFF_ACL_FREE(con->unit->buffer, con->pending);
316107120Sjulian	else
317107120Sjulian		NG_HCI_BUFF_SCO_FREE(con->unit->buffer, con->pending);
318107120Sjulian
319107120Sjulian	NG_BT_ITEMQ_DESTROY(&con->conq);
320107120Sjulian
321107120Sjulian	bzero(con, sizeof(*con));
322107120Sjulian	FREE(con, M_NETGRAPH_HCI);
323107120Sjulian} /* ng_hci_free_con */
324107120Sjulian
325107120Sjulian/*
326107120Sjulian * Lookup connection for given unit and connection handle.
327107120Sjulian */
328107120Sjulian
329107120Sjulianng_hci_unit_con_p
330107120Sjulianng_hci_con_by_handle(ng_hci_unit_p unit, int con_handle)
331107120Sjulian{
332107120Sjulian	ng_hci_unit_con_p	con = NULL;
333107120Sjulian
334107120Sjulian	LIST_FOREACH(con, &unit->con_list, next)
335107120Sjulian		if (con->con_handle == con_handle)
336107120Sjulian			break;
337107120Sjulian
338107120Sjulian	return (con);
339107120Sjulian} /* ng_hci_con_by_handle */
340107120Sjulian
341107120Sjulian/*
342107120Sjulian * Lookup connection for given unit, link type and remove unit address
343107120Sjulian */
344107120Sjulian
345107120Sjulianng_hci_unit_con_p
346107120Sjulianng_hci_con_by_bdaddr(ng_hci_unit_p unit, bdaddr_p bdaddr, int link_type)
347107120Sjulian{
348107120Sjulian	ng_hci_unit_con_p	con = NULL;
349107120Sjulian
350107120Sjulian	LIST_FOREACH(con, &unit->con_list, next)
351107120Sjulian		if (con->link_type == link_type &&
352107120Sjulian		    bcmp(&con->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0)
353107120Sjulian			break;
354107120Sjulian
355107120Sjulian	return (con);
356107120Sjulian} /* ng_hci_con_by_bdaddr */
357107120Sjulian
358107120Sjulian/*
359107120Sjulian * Set HCI command timeout
360121054Semax * XXX FIXME: check unit->cmd_timo.callout != NULL
361107120Sjulian */
362107120Sjulian
363121054Semaxint
364107120Sjulianng_hci_command_timeout(ng_hci_unit_p unit)
365107120Sjulian{
366121054Semax	if (unit->state & NG_HCI_UNIT_COMMAND_PENDING)
367121054Semax		panic(
368121054Semax"%s: %s - Duplicated command timeout!\n", __func__, NG_NODE_NAME(unit->node));
369121054Semax
370121054Semax	unit->state |= NG_HCI_UNIT_COMMAND_PENDING;
371121054Semax	unit->cmd_timo = ng_timeout(unit->node, NULL,
372121054Semax				bluetooth_hci_command_timeout(),
373121054Semax				ng_hci_process_command_timeout, NULL, 0);
374121054Semax
375121054Semax	return (0);
376107120Sjulian} /* ng_hci_command_timeout */
377107120Sjulian
378107120Sjulian/*
379107120Sjulian * Unset HCI command timeout
380107120Sjulian */
381107120Sjulian
382121054Semaxint
383107120Sjulianng_hci_command_untimeout(ng_hci_unit_p unit)
384107120Sjulian{
385121054Semax	if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
386121054Semax		panic(
387121054Semax"%s: %s - No command timeout!\n", __func__, NG_NODE_NAME(unit->node));
388107120Sjulian
389121054Semax	if (ng_untimeout(unit->cmd_timo, unit->node) == 0)
390121054Semax		return (ETIMEDOUT);
391107120Sjulian
392121054Semax	unit->state &= ~NG_HCI_UNIT_COMMAND_PENDING;
393107120Sjulian
394121054Semax	return (0);
395121054Semax} /* ng_hci_command_untimeout */
396107120Sjulian
397107120Sjulian/*
398107120Sjulian * Set HCI connection timeout
399121054Semax * XXX FIXME: check unit->cmd_timo.callout != NULL
400107120Sjulian */
401107120Sjulian
402121054Semaxint
403107120Sjulianng_hci_con_timeout(ng_hci_unit_con_p con)
404107120Sjulian{
405121054Semax	if (con->flags & NG_HCI_CON_TIMEOUT_PENDING)
406121054Semax		panic(
407121054Semax"%s: %s - Duplicated connection timeout!\n",
408121054Semax			__func__, NG_NODE_NAME(con->unit->node));
409121054Semax
410121054Semax	con->flags |= NG_HCI_CON_TIMEOUT_PENDING;
411121054Semax	con->con_timo = ng_timeout(con->unit->node, NULL,
412121054Semax				bluetooth_hci_connect_timeout(),
413121054Semax				ng_hci_process_con_timeout, NULL,
414121054Semax				con->con_handle);
415121054Semax
416121054Semax	return (0);
417107120Sjulian} /* ng_hci_con_timeout */
418107120Sjulian
419107120Sjulian/*
420107120Sjulian * Unset HCI connection timeout
421107120Sjulian */
422107120Sjulian
423121054Semaxint
424107120Sjulianng_hci_con_untimeout(ng_hci_unit_con_p con)
425107120Sjulian{
426121054Semax	if (!(con->flags & NG_HCI_CON_TIMEOUT_PENDING))
427121054Semax		panic(
428121054Semax"%s: %s - No connection timeout!\n", __func__, NG_NODE_NAME(con->unit->node));
429107120Sjulian
430121054Semax	if (ng_untimeout(con->con_timo, con->unit->node) == 0)
431121054Semax		return (ETIMEDOUT);
432107120Sjulian
433121054Semax	con->flags &= ~NG_HCI_CON_TIMEOUT_PENDING;
434107120Sjulian
435121054Semax	return (0);
436121054Semax} /* ng_hci_con_untimeout */
437107120Sjulian
438107120Sjulian#if 0
439107120Sjulian/*
440107120Sjulian * Convert numeric error code/reason to a string
441107120Sjulian */
442107120Sjulian
443107120Sjulianchar const * const
444107120Sjulianng_hci_str_error(u_int16_t code)
445107120Sjulian{
446107120Sjulian#define	LAST_ERROR_CODE			((sizeof(s)/sizeof(s[0]))-1)
447107120Sjulian	static char const * const	s[] = {
448107120Sjulian	/* 0x00 */ "No error",
449107120Sjulian	/* 0x01 */ "Unknown HCI command",
450107120Sjulian	/* 0x02 */ "No connection",
451107120Sjulian	/* 0x03 */ "Hardware failure",
452107120Sjulian	/* 0x04 */ "Page timeout",
453107120Sjulian	/* 0x05 */ "Authentication failure",
454107120Sjulian	/* 0x06 */ "Key missing",
455107120Sjulian	/* 0x07 */ "Memory full",
456107120Sjulian	/* 0x08 */ "Connection timeout",
457107120Sjulian	/* 0x09 */ "Max number of connections",
458107120Sjulian	/* 0x0a */ "Max number of SCO connections to a unit",
459107120Sjulian	/* 0x0b */ "ACL connection already exists",
460107120Sjulian	/* 0x0c */ "Command disallowed",
461107120Sjulian	/* 0x0d */ "Host rejected due to limited resources",
462107120Sjulian	/* 0x0e */ "Host rejected due to securiity reasons",
463107120Sjulian	/* 0x0f */ "Host rejected due to remote unit is a personal unit",
464107120Sjulian	/* 0x10 */ "Host timeout",
465107120Sjulian	/* 0x11 */ "Unsupported feature or parameter value",
466107120Sjulian	/* 0x12 */ "Invalid HCI command parameter",
467107120Sjulian	/* 0x13 */ "Other end terminated connection: User ended connection",
468107120Sjulian	/* 0x14 */ "Other end terminated connection: Low resources",
469107120Sjulian	/* 0x15 */ "Other end terminated connection: About to power off",
470107120Sjulian	/* 0x16 */ "Connection terminated by local host",
471107120Sjulian	/* 0x17 */ "Repeated attempts",
472107120Sjulian	/* 0x18 */ "Pairing not allowed",
473107120Sjulian	/* 0x19 */ "Unknown LMP PDU",
474107120Sjulian	/* 0x1a */ "Unsupported remote feature",
475107120Sjulian	/* 0x1b */ "SCO offset rejected",
476107120Sjulian	/* 0x1c */ "SCO interval rejected",
477107120Sjulian	/* 0x1d */ "SCO air mode rejected",
478107120Sjulian	/* 0x1e */ "Invalid LMP parameters",
479107120Sjulian	/* 0x1f */ "Unspecified error",
480107120Sjulian	/* 0x20 */ "Unsupported LMP parameter value",
481107120Sjulian	/* 0x21 */ "Role change not allowed",
482107120Sjulian	/* 0x22 */ "LMP response timeout",
483107120Sjulian	/* 0x23 */ "LMP error transaction collision",
484107120Sjulian	/* 0x24 */ "LMP PSU not allowed",
485107120Sjulian	/* 0x25 */ "Encryption mode not acceptable",
486107120Sjulian	/* 0x26 */ "Unit key used",
487107120Sjulian	/* 0x27 */ "QoS is not supported",
488107120Sjulian	/* 0x28 */ "Instant passed",
489107120Sjulian	/* 0x29 */ "Paring with unit key not supported",
490107120Sjulian	/* SHOULD ALWAYS BE LAST */ "Unknown error"
491107120Sjulian	};
492107120Sjulian
493107120Sjulian	return ((code >= LAST_ERROR_CODE)? s[LAST_ERROR_CODE] : s[code]);
494107120Sjulian} /* ng_hci_str_error */
495107120Sjulian#endif
496107120Sjulian
497