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