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