1878ed226SJulian Elischer /* 2878ed226SJulian Elischer * ng_hci_ulpi.c 3c398230bSWarner Losh */ 4c398230bSWarner Losh 5c398230bSWarner Losh /*- 6878ed226SJulian Elischer * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 7878ed226SJulian Elischer * All rights reserved. 8878ed226SJulian Elischer * 9878ed226SJulian Elischer * Redistribution and use in source and binary forms, with or without 10878ed226SJulian Elischer * modification, are permitted provided that the following conditions 11878ed226SJulian Elischer * are met: 12878ed226SJulian Elischer * 1. Redistributions of source code must retain the above copyright 13878ed226SJulian Elischer * notice, this list of conditions and the following disclaimer. 14878ed226SJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 15878ed226SJulian Elischer * notice, this list of conditions and the following disclaimer in the 16878ed226SJulian Elischer * documentation and/or other materials provided with the distribution. 17878ed226SJulian Elischer * 18878ed226SJulian Elischer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19878ed226SJulian Elischer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20878ed226SJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21878ed226SJulian Elischer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22878ed226SJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23878ed226SJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24878ed226SJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25878ed226SJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26878ed226SJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27878ed226SJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28878ed226SJulian Elischer * SUCH DAMAGE. 29878ed226SJulian Elischer * 300986ab12SMaksim Yevmenkin * $Id: ng_hci_ulpi.c,v 1.7 2003/09/08 18:57:51 max Exp $ 31878ed226SJulian Elischer * $FreeBSD$ 32878ed226SJulian Elischer */ 33878ed226SJulian Elischer 34878ed226SJulian Elischer #include <sys/param.h> 35878ed226SJulian Elischer #include <sys/systm.h> 36878ed226SJulian Elischer #include <sys/kernel.h> 37878ed226SJulian Elischer #include <sys/endian.h> 38878ed226SJulian Elischer #include <sys/malloc.h> 39878ed226SJulian Elischer #include <sys/mbuf.h> 40878ed226SJulian Elischer #include <sys/queue.h> 41878ed226SJulian Elischer #include <netgraph/ng_message.h> 42878ed226SJulian Elischer #include <netgraph/netgraph.h> 43b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_bluetooth.h> 44b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_hci.h> 45b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/hci/ng_hci_var.h> 46b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/hci/ng_hci_cmds.h> 47b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/hci/ng_hci_evnt.h> 48b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/hci/ng_hci_ulpi.h> 49b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/hci/ng_hci_misc.h> 50878ed226SJulian Elischer 51878ed226SJulian Elischer /****************************************************************************** 52878ed226SJulian Elischer ****************************************************************************** 53878ed226SJulian Elischer ** Upper Layer Protocol Interface module 54878ed226SJulian Elischer ****************************************************************************** 55878ed226SJulian Elischer ******************************************************************************/ 56878ed226SJulian Elischer 57878ed226SJulian Elischer static int ng_hci_lp_acl_con_req (ng_hci_unit_p, item_p, hook_p); 58878ed226SJulian Elischer static int ng_hci_lp_sco_con_req (ng_hci_unit_p, item_p, hook_p); 59878ed226SJulian Elischer 60878ed226SJulian Elischer /* 61878ed226SJulian Elischer * Process LP_ConnectReq event from the upper layer protocol 62878ed226SJulian Elischer */ 63878ed226SJulian Elischer 64878ed226SJulian Elischer int 65878ed226SJulian Elischer ng_hci_lp_con_req(ng_hci_unit_p unit, item_p item, hook_p hook) 66878ed226SJulian Elischer { 67878ed226SJulian Elischer if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) { 68878ed226SJulian Elischer NG_HCI_WARN( 69878ed226SJulian Elischer "%s: %s - unit is not ready, state=%#x\n", 70878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), unit->state); 71878ed226SJulian Elischer 72878ed226SJulian Elischer NG_FREE_ITEM(item); 73878ed226SJulian Elischer 74878ed226SJulian Elischer return (ENXIO); 75878ed226SJulian Elischer } 76878ed226SJulian Elischer 77878ed226SJulian Elischer if (NGI_MSG(item)->header.arglen != sizeof(ng_hci_lp_con_req_ep)) { 78878ed226SJulian Elischer NG_HCI_ALERT( 79878ed226SJulian Elischer "%s: %s - invalid LP_ConnectReq message size=%d\n", 80878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 81878ed226SJulian Elischer NGI_MSG(item)->header.arglen); 82878ed226SJulian Elischer 83878ed226SJulian Elischer NG_FREE_ITEM(item); 84878ed226SJulian Elischer 85878ed226SJulian Elischer return (EMSGSIZE); 86878ed226SJulian Elischer } 87878ed226SJulian Elischer 88878ed226SJulian Elischer if (((ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data))->link_type == NG_HCI_LINK_ACL) 89878ed226SJulian Elischer return (ng_hci_lp_acl_con_req(unit, item, hook)); 90878ed226SJulian Elischer 91878ed226SJulian Elischer if (hook != unit->sco) { 92878ed226SJulian Elischer NG_HCI_WARN( 93878ed226SJulian Elischer "%s: %s - LP_ConnectReq for SCO connection came from wrong hook=%p\n", 94878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), hook); 95878ed226SJulian Elischer 96878ed226SJulian Elischer NG_FREE_ITEM(item); 97878ed226SJulian Elischer 98878ed226SJulian Elischer return (EINVAL); 99878ed226SJulian Elischer } 100878ed226SJulian Elischer 101878ed226SJulian Elischer return (ng_hci_lp_sco_con_req(unit, item, hook)); 102878ed226SJulian Elischer } /* ng_hci_lp_con_req */ 103878ed226SJulian Elischer 104878ed226SJulian Elischer /* 105878ed226SJulian Elischer * Request to create new ACL connection 106878ed226SJulian Elischer */ 107878ed226SJulian Elischer 108878ed226SJulian Elischer static int 109878ed226SJulian Elischer ng_hci_lp_acl_con_req(ng_hci_unit_p unit, item_p item, hook_p hook) 110878ed226SJulian Elischer { 111878ed226SJulian Elischer struct acl_con_req { 112878ed226SJulian Elischer ng_hci_cmd_pkt_t hdr; 113878ed226SJulian Elischer ng_hci_create_con_cp cp; 114878ed226SJulian Elischer } __attribute__ ((packed)) *req = NULL; 115878ed226SJulian Elischer ng_hci_lp_con_req_ep *ep = NULL; 116878ed226SJulian Elischer ng_hci_unit_con_p con = NULL; 117878ed226SJulian Elischer ng_hci_neighbor_t *n = NULL; 118878ed226SJulian Elischer struct mbuf *m = NULL; 119878ed226SJulian Elischer int error = 0; 120878ed226SJulian Elischer 121878ed226SJulian Elischer ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data); 122878ed226SJulian Elischer 123878ed226SJulian Elischer /* 124878ed226SJulian Elischer * Only one ACL connection can exist between each pair of units. 125878ed226SJulian Elischer * So try to find ACL connection descriptor (in any state) that 126878ed226SJulian Elischer * has requested remote BD_ADDR. 127878ed226SJulian Elischer * 128878ed226SJulian Elischer * Two cases: 129878ed226SJulian Elischer * 130878ed226SJulian Elischer * 1) We do not have connection to the remote unit. This is simple. 131878ed226SJulian Elischer * Just create new connection descriptor and send HCI command to 132878ed226SJulian Elischer * create new connection. 133878ed226SJulian Elischer * 134878ed226SJulian Elischer * 2) We do have connection descriptor. We need to check connection 135878ed226SJulian Elischer * state: 136878ed226SJulian Elischer * 137f2bb1caeSJulian Elischer * 2.1) NG_HCI_CON_W4_LP_CON_RSP means that we are in the middle of 138878ed226SJulian Elischer * accepting connection from the remote unit. This is a race 139878ed226SJulian Elischer * condition. We will ignore this message. 140878ed226SJulian Elischer * 141f2bb1caeSJulian Elischer * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that upper layer already 142878ed226SJulian Elischer * requested connection or we just accepted it. In any case 143878ed226SJulian Elischer * all we need to do here is set appropriate notification bit 144878ed226SJulian Elischer * and wait. 145878ed226SJulian Elischer * 146f2bb1caeSJulian Elischer * 2.3) NG_HCI_CON_OPEN means connection is open. Just reply back 147878ed226SJulian Elischer * and let upper layer know that we have connection already. 148878ed226SJulian Elischer */ 149878ed226SJulian Elischer 150878ed226SJulian Elischer con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, NG_HCI_LINK_ACL); 151878ed226SJulian Elischer if (con != NULL) { 152878ed226SJulian Elischer switch (con->state) { 153878ed226SJulian Elischer case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */ 154878ed226SJulian Elischer error = EALREADY; 155878ed226SJulian Elischer break; 156878ed226SJulian Elischer 157878ed226SJulian Elischer case NG_HCI_CON_W4_CONN_COMPLETE: 158878ed226SJulian Elischer if (hook == unit->acl) 159878ed226SJulian Elischer con->flags |= NG_HCI_CON_NOTIFY_ACL; 160878ed226SJulian Elischer else 161878ed226SJulian Elischer con->flags |= NG_HCI_CON_NOTIFY_SCO; 162878ed226SJulian Elischer break; 163878ed226SJulian Elischer 164878ed226SJulian Elischer case NG_HCI_CON_OPEN: { 165878ed226SJulian Elischer struct ng_mesg *msg = NULL; 166878ed226SJulian Elischer ng_hci_lp_con_cfm_ep *cfm = NULL; 167878ed226SJulian Elischer 168878ed226SJulian Elischer if (hook != NULL && NG_HOOK_IS_VALID(hook)) { 169878ed226SJulian Elischer NGI_GET_MSG(item, msg); 170878ed226SJulian Elischer NG_FREE_MSG(msg); 171878ed226SJulian Elischer 172878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_HCI_COOKIE, 173878ed226SJulian Elischer NGM_HCI_LP_CON_CFM, sizeof(*cfm), 174878ed226SJulian Elischer M_NOWAIT); 175878ed226SJulian Elischer if (msg != NULL) { 176878ed226SJulian Elischer cfm = (ng_hci_lp_con_cfm_ep *)msg->data; 177878ed226SJulian Elischer cfm->status = 0; 178878ed226SJulian Elischer cfm->link_type = con->link_type; 179878ed226SJulian Elischer cfm->con_handle = con->con_handle; 180878ed226SJulian Elischer bcopy(&con->bdaddr, &cfm->bdaddr, 181878ed226SJulian Elischer sizeof(cfm->bdaddr)); 182878ed226SJulian Elischer 183878ed226SJulian Elischer /* 184878ed226SJulian Elischer * This will forward item back to 185878ed226SJulian Elischer * sender and set item to NULL 186878ed226SJulian Elischer */ 187878ed226SJulian Elischer 188878ed226SJulian Elischer _NGI_MSG(item) = msg; 189878ed226SJulian Elischer NG_FWD_ITEM_HOOK(error, item, hook); 190878ed226SJulian Elischer } else 191878ed226SJulian Elischer error = ENOMEM; 192878ed226SJulian Elischer } else 193878ed226SJulian Elischer NG_HCI_INFO( 194878ed226SJulian Elischer "%s: %s - Source hook is not valid, hook=%p\n", 195878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 196878ed226SJulian Elischer hook); 197878ed226SJulian Elischer } break; 198878ed226SJulian Elischer 199878ed226SJulian Elischer default: 2000986ab12SMaksim Yevmenkin panic( 2010986ab12SMaksim Yevmenkin "%s: %s - Invalid connection state=%d\n", 2020986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(unit->node), con->state); 203878ed226SJulian Elischer break; 204878ed226SJulian Elischer } 205878ed226SJulian Elischer 206878ed226SJulian Elischer goto out; 207878ed226SJulian Elischer } 208878ed226SJulian Elischer 209878ed226SJulian Elischer /* 210878ed226SJulian Elischer * If we got here then we need to create new ACL connection descriptor 211878ed226SJulian Elischer * and submit HCI command. First create new connection desriptor, set 212878ed226SJulian Elischer * bdaddr and notification flags. 213878ed226SJulian Elischer */ 214878ed226SJulian Elischer 215878ed226SJulian Elischer con = ng_hci_new_con(unit, NG_HCI_LINK_ACL); 216878ed226SJulian Elischer if (con == NULL) { 217878ed226SJulian Elischer error = ENOMEM; 218878ed226SJulian Elischer goto out; 219878ed226SJulian Elischer } 220878ed226SJulian Elischer 221878ed226SJulian Elischer bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr)); 222878ed226SJulian Elischer 223878ed226SJulian Elischer /* 224878ed226SJulian Elischer * Create HCI command 225878ed226SJulian Elischer */ 226878ed226SJulian Elischer 227a163d034SWarner Losh MGETHDR(m, M_DONTWAIT, MT_DATA); 228878ed226SJulian Elischer if (m == NULL) { 229878ed226SJulian Elischer ng_hci_free_con(con); 230878ed226SJulian Elischer error = ENOBUFS; 231878ed226SJulian Elischer goto out; 232878ed226SJulian Elischer } 233878ed226SJulian Elischer 234878ed226SJulian Elischer m->m_pkthdr.len = m->m_len = sizeof(*req); 235878ed226SJulian Elischer req = mtod(m, struct acl_con_req *); 236878ed226SJulian Elischer req->hdr.type = NG_HCI_CMD_PKT; 237878ed226SJulian Elischer req->hdr.length = sizeof(req->cp); 238878ed226SJulian Elischer req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 239878ed226SJulian Elischer NG_HCI_OCF_CREATE_CON)); 240878ed226SJulian Elischer 241878ed226SJulian Elischer bcopy(&ep->bdaddr, &req->cp.bdaddr, sizeof(req->cp.bdaddr)); 242878ed226SJulian Elischer 243878ed226SJulian Elischer req->cp.pkt_type = (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1); 244878ed226SJulian Elischer if (unit->features[0] & NG_HCI_LMP_3SLOT) 245878ed226SJulian Elischer req->cp.pkt_type |= (NG_HCI_PKT_DM3|NG_HCI_PKT_DH3); 246878ed226SJulian Elischer if (unit->features[0] & NG_HCI_LMP_5SLOT) 247878ed226SJulian Elischer req->cp.pkt_type |= (NG_HCI_PKT_DM5|NG_HCI_PKT_DH5); 248878ed226SJulian Elischer 249878ed226SJulian Elischer req->cp.pkt_type &= unit->packet_mask; 250f2bb1caeSJulian Elischer if ((req->cp.pkt_type & (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1| 251f2bb1caeSJulian Elischer NG_HCI_PKT_DM3|NG_HCI_PKT_DH3| 252f2bb1caeSJulian Elischer NG_HCI_PKT_DM5|NG_HCI_PKT_DH5)) == 0) 253878ed226SJulian Elischer req->cp.pkt_type = (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1); 254878ed226SJulian Elischer 255878ed226SJulian Elischer req->cp.pkt_type = htole16(req->cp.pkt_type); 256878ed226SJulian Elischer 257f2bb1caeSJulian Elischer if ((unit->features[0] & NG_HCI_LMP_SWITCH) && unit->role_switch) 258878ed226SJulian Elischer req->cp.accept_role_switch = 1; 259878ed226SJulian Elischer else 260878ed226SJulian Elischer req->cp.accept_role_switch = 0; 261878ed226SJulian Elischer 262878ed226SJulian Elischer /* 263878ed226SJulian Elischer * We may speed up connect by specifying valid parameters. 264878ed226SJulian Elischer * So check the neighbor cache. 265878ed226SJulian Elischer */ 266878ed226SJulian Elischer 267878ed226SJulian Elischer n = ng_hci_get_neighbor(unit, &ep->bdaddr); 268878ed226SJulian Elischer if (n == NULL) { 269878ed226SJulian Elischer req->cp.page_scan_rep_mode = 0; 270878ed226SJulian Elischer req->cp.page_scan_mode = 0; 271878ed226SJulian Elischer req->cp.clock_offset = 0; 272878ed226SJulian Elischer } else { 273878ed226SJulian Elischer req->cp.page_scan_rep_mode = n->page_scan_rep_mode; 274878ed226SJulian Elischer req->cp.page_scan_mode = n->page_scan_mode; 275878ed226SJulian Elischer req->cp.clock_offset = htole16(n->clock_offset); 276878ed226SJulian Elischer } 277878ed226SJulian Elischer 278878ed226SJulian Elischer /* 279878ed226SJulian Elischer * Adust connection state 280878ed226SJulian Elischer */ 281878ed226SJulian Elischer 282878ed226SJulian Elischer if (hook == unit->acl) 283878ed226SJulian Elischer con->flags |= NG_HCI_CON_NOTIFY_ACL; 284878ed226SJulian Elischer else 285878ed226SJulian Elischer con->flags |= NG_HCI_CON_NOTIFY_SCO; 286878ed226SJulian Elischer 287878ed226SJulian Elischer con->state = NG_HCI_CON_W4_CONN_COMPLETE; 288878ed226SJulian Elischer ng_hci_con_timeout(con); 289878ed226SJulian Elischer 290878ed226SJulian Elischer /* 291878ed226SJulian Elischer * Queue and send HCI command 292878ed226SJulian Elischer */ 293878ed226SJulian Elischer 294878ed226SJulian Elischer NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 295878ed226SJulian Elischer if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 296878ed226SJulian Elischer error = ng_hci_send_command(unit); 297878ed226SJulian Elischer out: 298878ed226SJulian Elischer if (item != NULL) 299878ed226SJulian Elischer NG_FREE_ITEM(item); 300878ed226SJulian Elischer 301878ed226SJulian Elischer return (error); 302878ed226SJulian Elischer } /* ng_hci_lp_acl_con_req */ 303878ed226SJulian Elischer 304878ed226SJulian Elischer /* 305878ed226SJulian Elischer * Request to create new SCO connection 306878ed226SJulian Elischer */ 307878ed226SJulian Elischer 308878ed226SJulian Elischer static int 309878ed226SJulian Elischer ng_hci_lp_sco_con_req(ng_hci_unit_p unit, item_p item, hook_p hook) 310878ed226SJulian Elischer { 311878ed226SJulian Elischer struct sco_con_req { 312878ed226SJulian Elischer ng_hci_cmd_pkt_t hdr; 313878ed226SJulian Elischer ng_hci_add_sco_con_cp cp; 314878ed226SJulian Elischer } __attribute__ ((packed)) *req = NULL; 315878ed226SJulian Elischer ng_hci_lp_con_req_ep *ep = NULL; 316878ed226SJulian Elischer ng_hci_unit_con_p acl_con = NULL, sco_con = NULL; 317878ed226SJulian Elischer struct mbuf *m = NULL; 318878ed226SJulian Elischer int error = 0; 319878ed226SJulian Elischer 320878ed226SJulian Elischer ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data); 321878ed226SJulian Elischer 322878ed226SJulian Elischer /* 323878ed226SJulian Elischer * SCO connection without ACL link 324878ed226SJulian Elischer * 325878ed226SJulian Elischer * If upper layer requests SCO connection and there is no open ACL 326878ed226SJulian Elischer * connection to the desired remote unit, we will reject the request. 327878ed226SJulian Elischer */ 328878ed226SJulian Elischer 329878ed226SJulian Elischer LIST_FOREACH(acl_con, &unit->con_list, next) 330878ed226SJulian Elischer if (acl_con->link_type == NG_HCI_LINK_ACL && 331878ed226SJulian Elischer acl_con->state == NG_HCI_CON_OPEN && 332878ed226SJulian Elischer bcmp(&acl_con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0) 333878ed226SJulian Elischer break; 334878ed226SJulian Elischer 335878ed226SJulian Elischer if (acl_con == NULL) { 336878ed226SJulian Elischer NG_HCI_INFO( 337878ed226SJulian Elischer "%s: %s - No open ACL connection to bdaddr=%x:%x:%x:%x:%x:%x\n", 338878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 339878ed226SJulian Elischer ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3], 340878ed226SJulian Elischer ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]); 341878ed226SJulian Elischer 342878ed226SJulian Elischer error = ENOENT; 343878ed226SJulian Elischer goto out; 344878ed226SJulian Elischer } 345878ed226SJulian Elischer 346878ed226SJulian Elischer /* 347878ed226SJulian Elischer * Multiple SCO connections can exist between the same pair of units. 348878ed226SJulian Elischer * We assume that multiple SCO connections have to be opened one after 349878ed226SJulian Elischer * another. 350878ed226SJulian Elischer * 351878ed226SJulian Elischer * Try to find SCO connection descriptor that matches the following: 352878ed226SJulian Elischer * 353878ed226SJulian Elischer * 1) sco_con->link_type == NG_HCI_LINK_SCO 354878ed226SJulian Elischer * 355878ed226SJulian Elischer * 2) sco_con->state == NG_HCI_CON_W4_LP_CON_RSP || 356878ed226SJulian Elischer * sco_con->state == NG_HCI_CON_W4_CONN_COMPLETE 357878ed226SJulian Elischer * 358878ed226SJulian Elischer * 3) sco_con->bdaddr == ep->bdaddr 359878ed226SJulian Elischer * 360878ed226SJulian Elischer * Two cases: 361878ed226SJulian Elischer * 362878ed226SJulian Elischer * 1) We do not have connection descriptor. This is simple. Just 363878ed226SJulian Elischer * create new connection and submit Add_SCO_Connection command. 364878ed226SJulian Elischer * 365878ed226SJulian Elischer * 2) We do have connection descriptor. We need to check the state. 366878ed226SJulian Elischer * 367878ed226SJulian Elischer * 2.1) NG_HCI_CON_W4_LP_CON_RSP means we in the middle of accepting 368878ed226SJulian Elischer * connection from the remote unit. This is a race condition and 369878ed226SJulian Elischer * we will ignore the request. 370878ed226SJulian Elischer * 371878ed226SJulian Elischer * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means upper layer already requested 372878ed226SJulian Elischer * connection or we just accepted it. 373878ed226SJulian Elischer */ 374878ed226SJulian Elischer 375878ed226SJulian Elischer LIST_FOREACH(sco_con, &unit->con_list, next) 376878ed226SJulian Elischer if (sco_con->link_type == NG_HCI_LINK_SCO && 377878ed226SJulian Elischer (sco_con->state == NG_HCI_CON_W4_LP_CON_RSP || 378878ed226SJulian Elischer sco_con->state == NG_HCI_CON_W4_CONN_COMPLETE) && 379878ed226SJulian Elischer bcmp(&sco_con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0) 380878ed226SJulian Elischer break; 381878ed226SJulian Elischer 382878ed226SJulian Elischer if (sco_con != NULL) { 383878ed226SJulian Elischer switch (sco_con->state) { 384878ed226SJulian Elischer case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */ 385878ed226SJulian Elischer error = EALREADY; 386878ed226SJulian Elischer break; 387878ed226SJulian Elischer 388878ed226SJulian Elischer case NG_HCI_CON_W4_CONN_COMPLETE: 389878ed226SJulian Elischer sco_con->flags |= NG_HCI_CON_NOTIFY_SCO; 390878ed226SJulian Elischer break; 391878ed226SJulian Elischer 392878ed226SJulian Elischer default: 3930986ab12SMaksim Yevmenkin panic( 3940986ab12SMaksim Yevmenkin "%s: %s - Inavalid connection state=%d\n", 395878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 3960986ab12SMaksim Yevmenkin sco_con->state); 397878ed226SJulian Elischer break; 398878ed226SJulian Elischer } 399878ed226SJulian Elischer 400878ed226SJulian Elischer goto out; 401878ed226SJulian Elischer } 402878ed226SJulian Elischer 403878ed226SJulian Elischer /* 404878ed226SJulian Elischer * If we got here then we need to create new SCO connection descriptor 405878ed226SJulian Elischer * and submit HCI command. 406878ed226SJulian Elischer */ 407878ed226SJulian Elischer 408878ed226SJulian Elischer sco_con = ng_hci_new_con(unit, NG_HCI_LINK_SCO); 409878ed226SJulian Elischer if (sco_con == NULL) { 410878ed226SJulian Elischer error = ENOMEM; 411878ed226SJulian Elischer goto out; 412878ed226SJulian Elischer } 413878ed226SJulian Elischer 414878ed226SJulian Elischer bcopy(&ep->bdaddr, &sco_con->bdaddr, sizeof(sco_con->bdaddr)); 415878ed226SJulian Elischer 416878ed226SJulian Elischer /* 417878ed226SJulian Elischer * Create HCI command 418878ed226SJulian Elischer */ 419878ed226SJulian Elischer 420a163d034SWarner Losh MGETHDR(m, M_DONTWAIT, MT_DATA); 421878ed226SJulian Elischer if (m == NULL) { 422878ed226SJulian Elischer ng_hci_free_con(sco_con); 423878ed226SJulian Elischer error = ENOBUFS; 424878ed226SJulian Elischer goto out; 425878ed226SJulian Elischer } 426878ed226SJulian Elischer 427878ed226SJulian Elischer m->m_pkthdr.len = m->m_len = sizeof(*req); 428878ed226SJulian Elischer req = mtod(m, struct sco_con_req *); 429878ed226SJulian Elischer req->hdr.type = NG_HCI_CMD_PKT; 430878ed226SJulian Elischer req->hdr.length = sizeof(req->cp); 431878ed226SJulian Elischer req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 432878ed226SJulian Elischer NG_HCI_OCF_ADD_SCO_CON)); 433878ed226SJulian Elischer 434878ed226SJulian Elischer req->cp.con_handle = htole16(acl_con->con_handle); 435878ed226SJulian Elischer 436878ed226SJulian Elischer req->cp.pkt_type = NG_HCI_PKT_HV1; 437878ed226SJulian Elischer if (unit->features[1] & NG_HCI_LMP_HV2_PKT) 438878ed226SJulian Elischer req->cp.pkt_type |= NG_HCI_PKT_HV2; 439878ed226SJulian Elischer if (unit->features[1] & NG_HCI_LMP_HV3_PKT) 440878ed226SJulian Elischer req->cp.pkt_type |= NG_HCI_PKT_HV3; 441878ed226SJulian Elischer 442878ed226SJulian Elischer req->cp.pkt_type &= unit->packet_mask; 443f2bb1caeSJulian Elischer if ((req->cp.pkt_type & (NG_HCI_PKT_HV1| 444f2bb1caeSJulian Elischer NG_HCI_PKT_HV2| 445f2bb1caeSJulian Elischer NG_HCI_PKT_HV3)) == 0) 446878ed226SJulian Elischer req->cp.pkt_type = NG_HCI_PKT_HV1; 447878ed226SJulian Elischer 448878ed226SJulian Elischer req->cp.pkt_type = htole16(req->cp.pkt_type); 449878ed226SJulian Elischer 450878ed226SJulian Elischer /* 451878ed226SJulian Elischer * Adust connection state 452878ed226SJulian Elischer */ 453878ed226SJulian Elischer 454878ed226SJulian Elischer sco_con->flags |= NG_HCI_CON_NOTIFY_SCO; 455878ed226SJulian Elischer 456878ed226SJulian Elischer sco_con->state = NG_HCI_CON_W4_CONN_COMPLETE; 457878ed226SJulian Elischer ng_hci_con_timeout(sco_con); 458878ed226SJulian Elischer 459878ed226SJulian Elischer /* 460878ed226SJulian Elischer * Queue and send HCI command 461878ed226SJulian Elischer */ 462878ed226SJulian Elischer 463878ed226SJulian Elischer NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 464878ed226SJulian Elischer if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 465878ed226SJulian Elischer error = ng_hci_send_command(unit); 466878ed226SJulian Elischer out: 467878ed226SJulian Elischer NG_FREE_ITEM(item); 468878ed226SJulian Elischer 469878ed226SJulian Elischer return (error); 470878ed226SJulian Elischer } /* ng_hci_lp_sco_con_req */ 471878ed226SJulian Elischer 472878ed226SJulian Elischer /* 473878ed226SJulian Elischer * Process LP_DisconnectReq event from the upper layer protocol 474878ed226SJulian Elischer */ 475878ed226SJulian Elischer 476878ed226SJulian Elischer int 477878ed226SJulian Elischer ng_hci_lp_discon_req(ng_hci_unit_p unit, item_p item, hook_p hook) 478878ed226SJulian Elischer { 479878ed226SJulian Elischer struct discon_req { 480878ed226SJulian Elischer ng_hci_cmd_pkt_t hdr; 481878ed226SJulian Elischer ng_hci_discon_cp cp; 482878ed226SJulian Elischer } __attribute__ ((packed)) *req = NULL; 483878ed226SJulian Elischer ng_hci_lp_discon_req_ep *ep = NULL; 484878ed226SJulian Elischer ng_hci_unit_con_p con = NULL; 485878ed226SJulian Elischer struct mbuf *m = NULL; 486878ed226SJulian Elischer int error = 0; 487878ed226SJulian Elischer 488878ed226SJulian Elischer /* Check if unit is ready */ 489878ed226SJulian Elischer if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) { 490878ed226SJulian Elischer NG_HCI_WARN( 491878ed226SJulian Elischer "%s: %s - unit is not ready, state=%#x\n", 492878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), unit->state); 493878ed226SJulian Elischer 494878ed226SJulian Elischer error = ENXIO; 495878ed226SJulian Elischer goto out; 496878ed226SJulian Elischer } 497878ed226SJulian Elischer 498878ed226SJulian Elischer if (NGI_MSG(item)->header.arglen != sizeof(*ep)) { 499878ed226SJulian Elischer NG_HCI_ALERT( 500878ed226SJulian Elischer "%s: %s - invalid LP_DisconnectReq message size=%d\n", 501878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 502878ed226SJulian Elischer NGI_MSG(item)->header.arglen); 503878ed226SJulian Elischer 504878ed226SJulian Elischer error = EMSGSIZE; 505878ed226SJulian Elischer goto out; 506878ed226SJulian Elischer } 507878ed226SJulian Elischer 508878ed226SJulian Elischer ep = (ng_hci_lp_discon_req_ep *)(NGI_MSG(item)->data); 509878ed226SJulian Elischer 510878ed226SJulian Elischer con = ng_hci_con_by_handle(unit, ep->con_handle); 511878ed226SJulian Elischer if (con == NULL) { 512878ed226SJulian Elischer NG_HCI_ERR( 513878ed226SJulian Elischer "%s: %s - invalid connection handle=%d\n", 514878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), ep->con_handle); 515878ed226SJulian Elischer 516878ed226SJulian Elischer error = ENOENT; 517878ed226SJulian Elischer goto out; 518878ed226SJulian Elischer } 519878ed226SJulian Elischer 520878ed226SJulian Elischer if (con->state != NG_HCI_CON_OPEN) { 521878ed226SJulian Elischer NG_HCI_ERR( 522878ed226SJulian Elischer "%s: %s - invalid connection state=%d, handle=%d\n", 523878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), con->state, 524878ed226SJulian Elischer ep->con_handle); 525878ed226SJulian Elischer 526878ed226SJulian Elischer error = EINVAL; 527878ed226SJulian Elischer goto out; 528878ed226SJulian Elischer } 529878ed226SJulian Elischer 530878ed226SJulian Elischer /* 531878ed226SJulian Elischer * Create HCI command 532878ed226SJulian Elischer */ 533878ed226SJulian Elischer 534a163d034SWarner Losh MGETHDR(m, M_DONTWAIT, MT_DATA); 535878ed226SJulian Elischer if (m == NULL) { 536878ed226SJulian Elischer error = ENOBUFS; 537878ed226SJulian Elischer goto out; 538878ed226SJulian Elischer } 539878ed226SJulian Elischer 540878ed226SJulian Elischer m->m_pkthdr.len = m->m_len = sizeof(*req); 541878ed226SJulian Elischer req = mtod(m, struct discon_req *); 542878ed226SJulian Elischer req->hdr.type = NG_HCI_CMD_PKT; 543878ed226SJulian Elischer req->hdr.length = sizeof(req->cp); 544878ed226SJulian Elischer req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 545878ed226SJulian Elischer NG_HCI_OCF_DISCON)); 546878ed226SJulian Elischer 547878ed226SJulian Elischer req->cp.con_handle = htole16(ep->con_handle); 548878ed226SJulian Elischer req->cp.reason = ep->reason; 549878ed226SJulian Elischer 550878ed226SJulian Elischer /* 551878ed226SJulian Elischer * Queue and send HCI command 552878ed226SJulian Elischer */ 553878ed226SJulian Elischer 554878ed226SJulian Elischer NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 555878ed226SJulian Elischer if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 556878ed226SJulian Elischer error = ng_hci_send_command(unit); 557878ed226SJulian Elischer out: 558878ed226SJulian Elischer NG_FREE_ITEM(item); 559878ed226SJulian Elischer 560878ed226SJulian Elischer return (error); 561878ed226SJulian Elischer } /* ng_hci_lp_discon_req */ 562878ed226SJulian Elischer 563878ed226SJulian Elischer /* 564878ed226SJulian Elischer * Send LP_ConnectCfm event to the upper layer protocol 565878ed226SJulian Elischer */ 566878ed226SJulian Elischer 567878ed226SJulian Elischer int 568878ed226SJulian Elischer ng_hci_lp_con_cfm(ng_hci_unit_con_p con, int status) 569878ed226SJulian Elischer { 570878ed226SJulian Elischer ng_hci_unit_p unit = con->unit; 571878ed226SJulian Elischer struct ng_mesg *msg = NULL; 572878ed226SJulian Elischer ng_hci_lp_con_cfm_ep *ep = NULL; 573878ed226SJulian Elischer int error; 574878ed226SJulian Elischer 575878ed226SJulian Elischer /* 576878ed226SJulian Elischer * Check who wants to be notified. For ACL links both ACL and SCO 577878ed226SJulian Elischer * upstream hooks will be notified (if required). For SCO links 578878ed226SJulian Elischer * only SCO upstream hook will receive notification 579878ed226SJulian Elischer */ 580878ed226SJulian Elischer 581878ed226SJulian Elischer if (con->link_type == NG_HCI_LINK_ACL && 582878ed226SJulian Elischer con->flags & NG_HCI_CON_NOTIFY_ACL) { 583878ed226SJulian Elischer if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { 584878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM, 585878ed226SJulian Elischer sizeof(*ep), M_NOWAIT); 586878ed226SJulian Elischer if (msg != NULL) { 587878ed226SJulian Elischer ep = (ng_hci_lp_con_cfm_ep *) msg->data; 588878ed226SJulian Elischer ep->status = status; 589878ed226SJulian Elischer ep->link_type = con->link_type; 590878ed226SJulian Elischer ep->con_handle = con->con_handle; 591878ed226SJulian Elischer bcopy(&con->bdaddr, &ep->bdaddr, 592878ed226SJulian Elischer sizeof(ep->bdaddr)); 593878ed226SJulian Elischer 594878ed226SJulian Elischer NG_SEND_MSG_HOOK(error, unit->node, msg, 5954ae439a3SMaksim Yevmenkin unit->acl, 0); 596878ed226SJulian Elischer } 597878ed226SJulian Elischer } else 598878ed226SJulian Elischer NG_HCI_INFO( 599878ed226SJulian Elischer "%s: %s - ACL hook not valid, hook=%p\n", 600878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), unit->acl); 601878ed226SJulian Elischer 602878ed226SJulian Elischer con->flags &= ~NG_HCI_CON_NOTIFY_ACL; 603878ed226SJulian Elischer } 604878ed226SJulian Elischer 605878ed226SJulian Elischer if (con->flags & NG_HCI_CON_NOTIFY_SCO) { 606878ed226SJulian Elischer if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) { 607878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM, 608878ed226SJulian Elischer sizeof(*ep), M_NOWAIT); 609878ed226SJulian Elischer if (msg != NULL) { 610878ed226SJulian Elischer ep = (ng_hci_lp_con_cfm_ep *) msg->data; 611878ed226SJulian Elischer ep->status = status; 612878ed226SJulian Elischer ep->link_type = con->link_type; 613878ed226SJulian Elischer ep->con_handle = con->con_handle; 614878ed226SJulian Elischer bcopy(&con->bdaddr, &ep->bdaddr, 615878ed226SJulian Elischer sizeof(ep->bdaddr)); 616878ed226SJulian Elischer 617878ed226SJulian Elischer NG_SEND_MSG_HOOK(error, unit->node, msg, 6184ae439a3SMaksim Yevmenkin unit->sco, 0); 619878ed226SJulian Elischer } 620878ed226SJulian Elischer } else 621878ed226SJulian Elischer NG_HCI_INFO( 622878ed226SJulian Elischer "%s: %s - SCO hook not valid, hook=%p\n", 623878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), unit->acl); 624878ed226SJulian Elischer 625878ed226SJulian Elischer con->flags &= ~NG_HCI_CON_NOTIFY_SCO; 626878ed226SJulian Elischer } 627878ed226SJulian Elischer 628878ed226SJulian Elischer return (0); 629878ed226SJulian Elischer } /* ng_hci_lp_con_cfm */ 630878ed226SJulian Elischer 631878ed226SJulian Elischer /* 632878ed226SJulian Elischer * Send LP_ConnectInd event to the upper layer protocol 633878ed226SJulian Elischer */ 634878ed226SJulian Elischer 635878ed226SJulian Elischer int 636878ed226SJulian Elischer ng_hci_lp_con_ind(ng_hci_unit_con_p con, u_int8_t *uclass) 637878ed226SJulian Elischer { 638878ed226SJulian Elischer ng_hci_unit_p unit = con->unit; 639878ed226SJulian Elischer struct ng_mesg *msg = NULL; 640878ed226SJulian Elischer ng_hci_lp_con_ind_ep *ep = NULL; 641878ed226SJulian Elischer hook_p hook = NULL; 642878ed226SJulian Elischer int error = 0; 643878ed226SJulian Elischer 644878ed226SJulian Elischer /* 645878ed226SJulian Elischer * Connection_Request event is generated for specific link type. 646878ed226SJulian Elischer * Use link_type to select upstream hook. 647878ed226SJulian Elischer */ 648878ed226SJulian Elischer 649878ed226SJulian Elischer if (con->link_type == NG_HCI_LINK_ACL) 650878ed226SJulian Elischer hook = unit->acl; 651878ed226SJulian Elischer else 652878ed226SJulian Elischer hook = unit->sco; 653878ed226SJulian Elischer 654878ed226SJulian Elischer if (hook != NULL && NG_HOOK_IS_VALID(hook)) { 655878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_IND, 656878ed226SJulian Elischer sizeof(*ep), M_NOWAIT); 657878ed226SJulian Elischer if (msg == NULL) 658878ed226SJulian Elischer return (ENOMEM); 659878ed226SJulian Elischer 660878ed226SJulian Elischer ep = (ng_hci_lp_con_ind_ep *)(msg->data); 661878ed226SJulian Elischer ep->link_type = con->link_type; 662878ed226SJulian Elischer bcopy(uclass, ep->uclass, sizeof(ep->uclass)); 663878ed226SJulian Elischer bcopy(&con->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr)); 664878ed226SJulian Elischer 6654ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, unit->node, msg, hook, 0); 666878ed226SJulian Elischer } else { 667878ed226SJulian Elischer NG_HCI_WARN( 668878ed226SJulian Elischer "%s: %s - Upstream hook is not connected or not valid, hook=%p\n", 669878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), hook); 670878ed226SJulian Elischer 671878ed226SJulian Elischer error = ENOTCONN; 672878ed226SJulian Elischer } 673878ed226SJulian Elischer 674878ed226SJulian Elischer return (error); 675878ed226SJulian Elischer } /* ng_hci_lp_con_ind */ 676878ed226SJulian Elischer 677878ed226SJulian Elischer /* 678878ed226SJulian Elischer * Process LP_ConnectRsp event from the upper layer protocol 679878ed226SJulian Elischer */ 680878ed226SJulian Elischer 681878ed226SJulian Elischer int 682878ed226SJulian Elischer ng_hci_lp_con_rsp(ng_hci_unit_p unit, item_p item, hook_p hook) 683878ed226SJulian Elischer { 684878ed226SJulian Elischer struct con_rsp_req { 685878ed226SJulian Elischer ng_hci_cmd_pkt_t hdr; 686878ed226SJulian Elischer union { 687878ed226SJulian Elischer ng_hci_accept_con_cp acc; 688878ed226SJulian Elischer ng_hci_reject_con_cp rej; 689878ed226SJulian Elischer } __attribute__ ((packed)) cp; 690878ed226SJulian Elischer } __attribute__ ((packed)) *req = NULL; 691878ed226SJulian Elischer ng_hci_lp_con_rsp_ep *ep = NULL; 692878ed226SJulian Elischer ng_hci_unit_con_p con = NULL; 693878ed226SJulian Elischer struct mbuf *m = NULL; 694878ed226SJulian Elischer int error = 0; 695878ed226SJulian Elischer 696878ed226SJulian Elischer /* Check if unit is ready */ 697878ed226SJulian Elischer if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) { 698878ed226SJulian Elischer NG_HCI_WARN( 699878ed226SJulian Elischer "%s: %s - unit is not ready, state=%#x\n", 700878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), unit->state); 701878ed226SJulian Elischer 702878ed226SJulian Elischer error = ENXIO; 703878ed226SJulian Elischer goto out; 704878ed226SJulian Elischer } 705878ed226SJulian Elischer 706878ed226SJulian Elischer if (NGI_MSG(item)->header.arglen != sizeof(*ep)) { 707878ed226SJulian Elischer NG_HCI_ALERT( 708878ed226SJulian Elischer "%s: %s - invalid LP_ConnectRsp message size=%d\n", 709878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 710878ed226SJulian Elischer NGI_MSG(item)->header.arglen); 711878ed226SJulian Elischer 712878ed226SJulian Elischer error = EMSGSIZE; 713878ed226SJulian Elischer goto out; 714878ed226SJulian Elischer } 715878ed226SJulian Elischer 716878ed226SJulian Elischer ep = (ng_hci_lp_con_rsp_ep *)(NGI_MSG(item)->data); 717878ed226SJulian Elischer 718878ed226SJulian Elischer /* 719878ed226SJulian Elischer * Here we have to deal with race. Upper layers might send conflicting 720878ed226SJulian Elischer * requests. One might send Accept and other Reject. We will not try 721878ed226SJulian Elischer * to solve all the problems, so first request will always win. 722878ed226SJulian Elischer * 723878ed226SJulian Elischer * Try to find connection that matches the following: 724878ed226SJulian Elischer * 725878ed226SJulian Elischer * 1) con->link_type == ep->link_type 726878ed226SJulian Elischer * 727878ed226SJulian Elischer * 2) con->state == NG_HCI_CON_W4_LP_CON_RSP || 728878ed226SJulian Elischer * con->state == NG_HCI_CON_W4_CONN_COMPLETE 729878ed226SJulian Elischer * 730878ed226SJulian Elischer * 3) con->bdaddr == ep->bdaddr 731878ed226SJulian Elischer * 732878ed226SJulian Elischer * Two cases: 733878ed226SJulian Elischer * 734878ed226SJulian Elischer * 1) We do not have connection descriptor. Could be bogus request or 735878ed226SJulian Elischer * we have rejected connection already. 736878ed226SJulian Elischer * 737878ed226SJulian Elischer * 2) We do have connection descriptor. Then we need to check state: 738878ed226SJulian Elischer * 739878ed226SJulian Elischer * 2.1) NG_HCI_CON_W4_LP_CON_RSP means upper layer has requested 740878ed226SJulian Elischer * connection and it is a first response from the upper layer. 741878ed226SJulian Elischer * if "status == 0" (Accept) then we will send Accept_Connection 742878ed226SJulian Elischer * command and change connection state to W4_CONN_COMPLETE, else 743878ed226SJulian Elischer * send reject and delete connection. 744878ed226SJulian Elischer * 745878ed226SJulian Elischer * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that we already accepted 746878ed226SJulian Elischer * connection. If "status == 0" we just need to link request 747878ed226SJulian Elischer * and wait, else ignore Reject request. 748878ed226SJulian Elischer */ 749878ed226SJulian Elischer 750878ed226SJulian Elischer LIST_FOREACH(con, &unit->con_list, next) 751878ed226SJulian Elischer if (con->link_type == ep->link_type && 752878ed226SJulian Elischer (con->state == NG_HCI_CON_W4_LP_CON_RSP || 753878ed226SJulian Elischer con->state == NG_HCI_CON_W4_CONN_COMPLETE) && 754878ed226SJulian Elischer bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0) 755878ed226SJulian Elischer break; 756878ed226SJulian Elischer 757878ed226SJulian Elischer if (con == NULL) { 758878ed226SJulian Elischer /* Reject for non-existing connection is fine */ 759878ed226SJulian Elischer error = (ep->status == 0)? ENOENT : 0; 760878ed226SJulian Elischer goto out; 761878ed226SJulian Elischer } 762878ed226SJulian Elischer 763878ed226SJulian Elischer /* 7640986ab12SMaksim Yevmenkin * Remove connection timeout and check connection state. 7650986ab12SMaksim Yevmenkin * Note: if ng_hci_con_untimeout() fails (returns non-zero value) then 7660986ab12SMaksim Yevmenkin * timeout already happened and event went into node's queue. 767878ed226SJulian Elischer */ 768878ed226SJulian Elischer 7690986ab12SMaksim Yevmenkin if ((error = ng_hci_con_untimeout(con)) != 0) 7700986ab12SMaksim Yevmenkin goto out; 771878ed226SJulian Elischer 772878ed226SJulian Elischer switch (con->state) { 773878ed226SJulian Elischer case NG_HCI_CON_W4_LP_CON_RSP: 774878ed226SJulian Elischer 775878ed226SJulian Elischer /* 776878ed226SJulian Elischer * Create HCI command 777878ed226SJulian Elischer */ 778878ed226SJulian Elischer 779a163d034SWarner Losh MGETHDR(m, M_DONTWAIT, MT_DATA); 780878ed226SJulian Elischer if (m == NULL) { 781878ed226SJulian Elischer error = ENOBUFS; 782878ed226SJulian Elischer goto out; 783878ed226SJulian Elischer } 784878ed226SJulian Elischer 785878ed226SJulian Elischer req = mtod(m, struct con_rsp_req *); 786878ed226SJulian Elischer req->hdr.type = NG_HCI_CMD_PKT; 787878ed226SJulian Elischer 788878ed226SJulian Elischer if (ep->status == 0) { 789878ed226SJulian Elischer req->hdr.length = sizeof(req->cp.acc); 790878ed226SJulian Elischer req->hdr.opcode = htole16(NG_HCI_OPCODE( 791878ed226SJulian Elischer NG_HCI_OGF_LINK_CONTROL, 792878ed226SJulian Elischer NG_HCI_OCF_ACCEPT_CON)); 793878ed226SJulian Elischer 794878ed226SJulian Elischer bcopy(&ep->bdaddr, &req->cp.acc.bdaddr, 795878ed226SJulian Elischer sizeof(req->cp.acc.bdaddr)); 796878ed226SJulian Elischer 797878ed226SJulian Elischer /* 798878ed226SJulian Elischer * We are accepting connection, so if we support role 799f2bb1caeSJulian Elischer * switch and role switch was enabled then set role to 800f2bb1caeSJulian Elischer * NG_HCI_ROLE_MASTER and let LM peform role switch. 801f2bb1caeSJulian Elischer * Otherwise we remain slave. In this case LM WILL NOT 802f2bb1caeSJulian Elischer * perform role switch. 803878ed226SJulian Elischer */ 804878ed226SJulian Elischer 805f2bb1caeSJulian Elischer if ((unit->features[0] & NG_HCI_LMP_SWITCH) && 806f2bb1caeSJulian Elischer unit->role_switch) 807878ed226SJulian Elischer req->cp.acc.role = NG_HCI_ROLE_MASTER; 808878ed226SJulian Elischer else 809878ed226SJulian Elischer req->cp.acc.role = NG_HCI_ROLE_SLAVE; 810878ed226SJulian Elischer 811878ed226SJulian Elischer /* 812878ed226SJulian Elischer * Adjust connection state 813878ed226SJulian Elischer */ 814878ed226SJulian Elischer 815878ed226SJulian Elischer if (hook == unit->acl) 816878ed226SJulian Elischer con->flags |= NG_HCI_CON_NOTIFY_ACL; 817878ed226SJulian Elischer else 818878ed226SJulian Elischer con->flags |= NG_HCI_CON_NOTIFY_SCO; 819878ed226SJulian Elischer 820878ed226SJulian Elischer con->state = NG_HCI_CON_W4_CONN_COMPLETE; 821878ed226SJulian Elischer ng_hci_con_timeout(con); 822878ed226SJulian Elischer } else { 823878ed226SJulian Elischer req->hdr.length = sizeof(req->cp.rej); 824878ed226SJulian Elischer req->hdr.opcode = htole16(NG_HCI_OPCODE( 825878ed226SJulian Elischer NG_HCI_OGF_LINK_CONTROL, 826878ed226SJulian Elischer NG_HCI_OCF_REJECT_CON)); 827878ed226SJulian Elischer 828878ed226SJulian Elischer bcopy(&ep->bdaddr, &req->cp.rej.bdaddr, 829878ed226SJulian Elischer sizeof(req->cp.rej.bdaddr)); 830878ed226SJulian Elischer 831878ed226SJulian Elischer req->cp.rej.reason = ep->status; 832878ed226SJulian Elischer 833878ed226SJulian Elischer /* 834878ed226SJulian Elischer * Free connection descritor 835878ed226SJulian Elischer * Item will be deleted just before return. 836878ed226SJulian Elischer */ 837878ed226SJulian Elischer 838878ed226SJulian Elischer ng_hci_free_con(con); 839878ed226SJulian Elischer } 840878ed226SJulian Elischer 841878ed226SJulian Elischer m->m_pkthdr.len = m->m_len = sizeof(req->hdr) + req->hdr.length; 842878ed226SJulian Elischer 843878ed226SJulian Elischer /* Queue and send HCI command */ 844878ed226SJulian Elischer NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 845878ed226SJulian Elischer if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 846878ed226SJulian Elischer error = ng_hci_send_command(unit); 847878ed226SJulian Elischer break; 848878ed226SJulian Elischer 849878ed226SJulian Elischer case NG_HCI_CON_W4_CONN_COMPLETE: 850878ed226SJulian Elischer if (ep->status == 0) { 851878ed226SJulian Elischer if (hook == unit->acl) 852878ed226SJulian Elischer con->flags |= NG_HCI_CON_NOTIFY_ACL; 853878ed226SJulian Elischer else 854878ed226SJulian Elischer con->flags |= NG_HCI_CON_NOTIFY_SCO; 855878ed226SJulian Elischer } else 856878ed226SJulian Elischer error = EPERM; 857878ed226SJulian Elischer break; 858878ed226SJulian Elischer 859878ed226SJulian Elischer default: 8600986ab12SMaksim Yevmenkin panic( 8610986ab12SMaksim Yevmenkin "%s: %s - Invalid connection state=%d\n", 8620986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(unit->node), con->state); 863878ed226SJulian Elischer break; 864878ed226SJulian Elischer } 865878ed226SJulian Elischer out: 866878ed226SJulian Elischer NG_FREE_ITEM(item); 867878ed226SJulian Elischer 868878ed226SJulian Elischer return (error); 869878ed226SJulian Elischer } /* ng_hci_lp_con_rsp */ 870878ed226SJulian Elischer 871878ed226SJulian Elischer /* 872878ed226SJulian Elischer * Send LP_DisconnectInd to the upper layer protocol 873878ed226SJulian Elischer */ 874878ed226SJulian Elischer 875878ed226SJulian Elischer int 876878ed226SJulian Elischer ng_hci_lp_discon_ind(ng_hci_unit_con_p con, int reason) 877878ed226SJulian Elischer { 878878ed226SJulian Elischer ng_hci_unit_p unit = con->unit; 879878ed226SJulian Elischer struct ng_mesg *msg = NULL; 880878ed226SJulian Elischer ng_hci_lp_discon_ind_ep *ep = NULL; 881878ed226SJulian Elischer int error = 0; 882878ed226SJulian Elischer 883878ed226SJulian Elischer /* 884878ed226SJulian Elischer * Disconnect_Complete event is generated for specific connection 885878ed226SJulian Elischer * handle. For ACL connection handles both ACL and SCO upstream 886878ed226SJulian Elischer * hooks will receive notification. For SCO connection handles 887878ed226SJulian Elischer * only SCO upstream hook will receive notification. 888878ed226SJulian Elischer */ 889878ed226SJulian Elischer 890878ed226SJulian Elischer if (con->link_type == NG_HCI_LINK_ACL) { 891878ed226SJulian Elischer if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { 892878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_HCI_COOKIE, 893878ed226SJulian Elischer NGM_HCI_LP_DISCON_IND, sizeof(*ep), M_NOWAIT); 894878ed226SJulian Elischer if (msg == NULL) 895878ed226SJulian Elischer return (ENOMEM); 896878ed226SJulian Elischer 897878ed226SJulian Elischer ep = (ng_hci_lp_discon_ind_ep *) msg->data; 898878ed226SJulian Elischer ep->reason = reason; 899878ed226SJulian Elischer ep->link_type = con->link_type; 900878ed226SJulian Elischer ep->con_handle = con->con_handle; 901878ed226SJulian Elischer 9024ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error,unit->node,msg,unit->acl,0); 903878ed226SJulian Elischer } else 904878ed226SJulian Elischer NG_HCI_INFO( 905878ed226SJulian Elischer "%s: %s - ACL hook is not connected or not valid, hook=%p\n", 906878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), unit->acl); 907878ed226SJulian Elischer } 908878ed226SJulian Elischer 909878ed226SJulian Elischer if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) { 910878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_IND, 911878ed226SJulian Elischer sizeof(*ep), M_NOWAIT); 912878ed226SJulian Elischer if (msg == NULL) 913878ed226SJulian Elischer return (ENOMEM); 914878ed226SJulian Elischer 915878ed226SJulian Elischer ep = (ng_hci_lp_discon_ind_ep *) msg->data; 916878ed226SJulian Elischer ep->reason = reason; 917878ed226SJulian Elischer ep->link_type = con->link_type; 918878ed226SJulian Elischer ep->con_handle = con->con_handle; 919878ed226SJulian Elischer 9204ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, unit->node, msg, unit->sco, 0); 921878ed226SJulian Elischer } else 922878ed226SJulian Elischer NG_HCI_INFO( 923878ed226SJulian Elischer "%s: %s - SCO hook is not connected or not valid, hook=%p\n", 924878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), unit->sco); 925878ed226SJulian Elischer 926878ed226SJulian Elischer return (0); 927878ed226SJulian Elischer } /* ng_hci_lp_discon_ind */ 928878ed226SJulian Elischer 929878ed226SJulian Elischer /* 930878ed226SJulian Elischer * Process LP_QoSReq action from the upper layer protocol 931878ed226SJulian Elischer */ 932878ed226SJulian Elischer 933878ed226SJulian Elischer int 934878ed226SJulian Elischer ng_hci_lp_qos_req(ng_hci_unit_p unit, item_p item, hook_p hook) 935878ed226SJulian Elischer { 936878ed226SJulian Elischer struct qos_setup_req { 937878ed226SJulian Elischer ng_hci_cmd_pkt_t hdr; 938878ed226SJulian Elischer ng_hci_qos_setup_cp cp; 939878ed226SJulian Elischer } __attribute__ ((packed)) *req = NULL; 940878ed226SJulian Elischer ng_hci_lp_qos_req_ep *ep = NULL; 941878ed226SJulian Elischer ng_hci_unit_con_p con = NULL; 942878ed226SJulian Elischer struct mbuf *m = NULL; 943878ed226SJulian Elischer int error = 0; 944878ed226SJulian Elischer 945878ed226SJulian Elischer /* Check if unit is ready */ 946878ed226SJulian Elischer if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) { 947878ed226SJulian Elischer NG_HCI_WARN( 948878ed226SJulian Elischer "%s: %s - unit is not ready, state=%#x\n", 949878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), unit->state); 950878ed226SJulian Elischer 951878ed226SJulian Elischer error = ENXIO; 952878ed226SJulian Elischer goto out; 953878ed226SJulian Elischer } 954878ed226SJulian Elischer 955878ed226SJulian Elischer if (NGI_MSG(item)->header.arglen != sizeof(*ep)) { 956878ed226SJulian Elischer NG_HCI_ALERT( 957878ed226SJulian Elischer "%s: %s - invalid LP_QoSSetupReq message size=%d\n", 958878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 959878ed226SJulian Elischer NGI_MSG(item)->header.arglen); 960878ed226SJulian Elischer 961878ed226SJulian Elischer error = EMSGSIZE; 962878ed226SJulian Elischer goto out; 963878ed226SJulian Elischer } 964878ed226SJulian Elischer 965878ed226SJulian Elischer ep = (ng_hci_lp_qos_req_ep *)(NGI_MSG(item)->data); 966878ed226SJulian Elischer 967878ed226SJulian Elischer con = ng_hci_con_by_handle(unit, ep->con_handle); 968878ed226SJulian Elischer if (con == NULL) { 969878ed226SJulian Elischer NG_HCI_ERR( 970878ed226SJulian Elischer "%s: %s - invalid connection handle=%d\n", 971878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), ep->con_handle); 972878ed226SJulian Elischer 973878ed226SJulian Elischer error = EINVAL; 974878ed226SJulian Elischer goto out; 975878ed226SJulian Elischer } 976878ed226SJulian Elischer 977878ed226SJulian Elischer if (con->link_type != NG_HCI_LINK_ACL) { 978878ed226SJulian Elischer NG_HCI_ERR("%s: %s - invalid link type=%d\n", 979878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), con->link_type); 980878ed226SJulian Elischer 981878ed226SJulian Elischer error = EINVAL; 982878ed226SJulian Elischer goto out; 983878ed226SJulian Elischer } 984878ed226SJulian Elischer 985878ed226SJulian Elischer if (con->state != NG_HCI_CON_OPEN) { 986878ed226SJulian Elischer NG_HCI_ERR( 987878ed226SJulian Elischer "%s: %s - invalid connection state=%d, handle=%d\n", 988878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), con->state, 989878ed226SJulian Elischer con->con_handle); 990878ed226SJulian Elischer 991878ed226SJulian Elischer error = EINVAL; 992878ed226SJulian Elischer goto out; 993878ed226SJulian Elischer } 994878ed226SJulian Elischer 995878ed226SJulian Elischer /* 996878ed226SJulian Elischer * Create HCI command 997878ed226SJulian Elischer */ 998878ed226SJulian Elischer 999a163d034SWarner Losh MGETHDR(m, M_DONTWAIT, MT_DATA); 1000878ed226SJulian Elischer if (m == NULL) { 1001878ed226SJulian Elischer error = ENOBUFS; 1002878ed226SJulian Elischer goto out; 1003878ed226SJulian Elischer } 1004878ed226SJulian Elischer 1005878ed226SJulian Elischer m->m_pkthdr.len = m->m_len = sizeof(*req); 1006878ed226SJulian Elischer req = mtod(m, struct qos_setup_req *); 1007878ed226SJulian Elischer req->hdr.type = NG_HCI_CMD_PKT; 1008878ed226SJulian Elischer req->hdr.length = sizeof(req->cp); 1009878ed226SJulian Elischer req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY, 1010878ed226SJulian Elischer NG_HCI_OCF_QOS_SETUP)); 1011878ed226SJulian Elischer 1012878ed226SJulian Elischer req->cp.con_handle = htole16(ep->con_handle); 1013878ed226SJulian Elischer req->cp.flags = ep->flags; 1014878ed226SJulian Elischer req->cp.service_type = ep->service_type; 1015878ed226SJulian Elischer req->cp.token_rate = htole32(ep->token_rate); 1016878ed226SJulian Elischer req->cp.peak_bandwidth = htole32(ep->peak_bandwidth); 1017878ed226SJulian Elischer req->cp.latency = htole32(ep->latency); 1018878ed226SJulian Elischer req->cp.delay_variation = htole32(ep->delay_variation); 1019878ed226SJulian Elischer 1020878ed226SJulian Elischer /* 1021878ed226SJulian Elischer * Adjust connection state 1022878ed226SJulian Elischer */ 1023878ed226SJulian Elischer 1024878ed226SJulian Elischer if (hook == unit->acl) 1025878ed226SJulian Elischer con->flags |= NG_HCI_CON_NOTIFY_ACL; 1026878ed226SJulian Elischer else 1027878ed226SJulian Elischer con->flags |= NG_HCI_CON_NOTIFY_SCO; 1028878ed226SJulian Elischer 1029878ed226SJulian Elischer /* 1030878ed226SJulian Elischer * Queue and send HCI command 1031878ed226SJulian Elischer */ 1032878ed226SJulian Elischer 1033878ed226SJulian Elischer NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 1034878ed226SJulian Elischer if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 1035878ed226SJulian Elischer error = ng_hci_send_command(unit); 1036878ed226SJulian Elischer out: 1037878ed226SJulian Elischer NG_FREE_ITEM(item); 1038878ed226SJulian Elischer 1039878ed226SJulian Elischer return (error); 1040878ed226SJulian Elischer } /* ng_hci_lp_qos_req */ 1041878ed226SJulian Elischer 1042878ed226SJulian Elischer /* 1043878ed226SJulian Elischer * Send LP_QoSCfm event to the upper layer protocol 1044878ed226SJulian Elischer */ 1045878ed226SJulian Elischer 1046878ed226SJulian Elischer int 1047878ed226SJulian Elischer ng_hci_lp_qos_cfm(ng_hci_unit_con_p con, int status) 1048878ed226SJulian Elischer { 1049878ed226SJulian Elischer ng_hci_unit_p unit = con->unit; 1050878ed226SJulian Elischer struct ng_mesg *msg = NULL; 1051878ed226SJulian Elischer ng_hci_lp_qos_cfm_ep *ep = NULL; 1052878ed226SJulian Elischer int error; 1053878ed226SJulian Elischer 1054878ed226SJulian Elischer if (con->flags & NG_HCI_CON_NOTIFY_ACL) { 1055878ed226SJulian Elischer if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { 1056878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_CFM, 1057878ed226SJulian Elischer sizeof(*ep), M_NOWAIT); 1058878ed226SJulian Elischer if (msg != NULL) { 1059878ed226SJulian Elischer ep = (ng_hci_lp_qos_cfm_ep *) msg->data; 1060878ed226SJulian Elischer ep->status = status; 1061878ed226SJulian Elischer ep->con_handle = con->con_handle; 1062878ed226SJulian Elischer 1063878ed226SJulian Elischer NG_SEND_MSG_HOOK(error, unit->node, msg, 10644ae439a3SMaksim Yevmenkin unit->acl, 0); 1065878ed226SJulian Elischer } 1066878ed226SJulian Elischer } else 1067878ed226SJulian Elischer NG_HCI_INFO( 1068878ed226SJulian Elischer "%s: %s - ACL hook not valid, hook=%p\n", 1069878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), unit->acl); 1070878ed226SJulian Elischer 1071878ed226SJulian Elischer con->flags &= ~NG_HCI_CON_NOTIFY_ACL; 1072878ed226SJulian Elischer } 1073878ed226SJulian Elischer 1074878ed226SJulian Elischer if (con->flags & NG_HCI_CON_NOTIFY_SCO) { 1075878ed226SJulian Elischer if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) { 1076878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_CFM, 1077878ed226SJulian Elischer sizeof(*ep), M_NOWAIT); 1078878ed226SJulian Elischer if (msg != NULL) { 1079878ed226SJulian Elischer ep = (ng_hci_lp_qos_cfm_ep *) msg->data; 1080878ed226SJulian Elischer ep->status = status; 1081878ed226SJulian Elischer ep->con_handle = con->con_handle; 1082878ed226SJulian Elischer 1083878ed226SJulian Elischer NG_SEND_MSG_HOOK(error, unit->node, msg, 10844ae439a3SMaksim Yevmenkin unit->sco, 0); 1085878ed226SJulian Elischer } 1086878ed226SJulian Elischer } else 1087878ed226SJulian Elischer NG_HCI_INFO( 1088878ed226SJulian Elischer "%s: %s - SCO hook not valid, hook=%p\n", 1089878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), unit->sco); 1090878ed226SJulian Elischer 1091878ed226SJulian Elischer con->flags &= ~NG_HCI_CON_NOTIFY_SCO; 1092878ed226SJulian Elischer } 1093878ed226SJulian Elischer 1094878ed226SJulian Elischer return (0); 1095878ed226SJulian Elischer } /* ng_hci_lp_qos_cfm */ 1096878ed226SJulian Elischer 1097878ed226SJulian Elischer /* 1098878ed226SJulian Elischer * Send LP_QoSViolationInd event to the upper layer protocol 1099878ed226SJulian Elischer */ 1100878ed226SJulian Elischer 1101878ed226SJulian Elischer int 1102878ed226SJulian Elischer ng_hci_lp_qos_ind(ng_hci_unit_con_p con) 1103878ed226SJulian Elischer { 1104878ed226SJulian Elischer ng_hci_unit_p unit = con->unit; 1105878ed226SJulian Elischer struct ng_mesg *msg = NULL; 1106878ed226SJulian Elischer ng_hci_lp_qos_ind_ep *ep = NULL; 1107878ed226SJulian Elischer int error; 1108878ed226SJulian Elischer 1109878ed226SJulian Elischer /* 1110878ed226SJulian Elischer * QoS Violation can only be generated for ACL connection handles. 1111878ed226SJulian Elischer * Both ACL and SCO upstream hooks will receive notification. 1112878ed226SJulian Elischer */ 1113878ed226SJulian Elischer 1114878ed226SJulian Elischer if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { 1115878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_IND, 1116878ed226SJulian Elischer sizeof(*ep), M_NOWAIT); 1117878ed226SJulian Elischer if (msg == NULL) 1118878ed226SJulian Elischer return (ENOMEM); 1119878ed226SJulian Elischer 1120878ed226SJulian Elischer ep = (ng_hci_lp_qos_ind_ep *) msg->data; 1121878ed226SJulian Elischer ep->con_handle = con->con_handle; 1122878ed226SJulian Elischer 11234ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, unit->node, msg, unit->acl, 0); 1124878ed226SJulian Elischer } else 1125878ed226SJulian Elischer NG_HCI_INFO( 1126878ed226SJulian Elischer "%s: %s - ACL hook is not connected or not valid, hook=%p\n", 1127878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), unit->acl); 1128878ed226SJulian Elischer 1129878ed226SJulian Elischer if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) { 1130878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_IND, 1131878ed226SJulian Elischer sizeof(*ep), M_NOWAIT); 1132878ed226SJulian Elischer if (msg == NULL) 1133878ed226SJulian Elischer return (ENOMEM); 1134878ed226SJulian Elischer 1135878ed226SJulian Elischer ep = (ng_hci_lp_qos_ind_ep *) msg->data; 1136878ed226SJulian Elischer ep->con_handle = con->con_handle; 1137878ed226SJulian Elischer 11384ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, unit->node, msg, unit->sco, 0); 1139878ed226SJulian Elischer } else 1140878ed226SJulian Elischer NG_HCI_INFO( 1141878ed226SJulian Elischer "%s: %s - SCO hook is not connected or not valid, hook=%p\n", 1142878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), unit->sco); 1143878ed226SJulian Elischer 1144878ed226SJulian Elischer return (0); 1145878ed226SJulian Elischer } /* ng_hci_lp_qos_ind */ 1146878ed226SJulian Elischer 1147878ed226SJulian Elischer /* 1148878ed226SJulian Elischer * Process connection timeout 1149878ed226SJulian Elischer */ 1150878ed226SJulian Elischer 1151878ed226SJulian Elischer void 11520986ab12SMaksim Yevmenkin ng_hci_process_con_timeout(node_p node, hook_p hook, void *arg1, int con_handle) 1153878ed226SJulian Elischer { 11540986ab12SMaksim Yevmenkin ng_hci_unit_p unit = NULL; 11550986ab12SMaksim Yevmenkin ng_hci_unit_con_p con = NULL; 1156878ed226SJulian Elischer 11570986ab12SMaksim Yevmenkin if (NG_NODE_NOT_VALID(node)) { 11580986ab12SMaksim Yevmenkin printf("%s: Netgraph node is not valid\n", __func__); 11590986ab12SMaksim Yevmenkin return; 11600986ab12SMaksim Yevmenkin } 11610986ab12SMaksim Yevmenkin 11620986ab12SMaksim Yevmenkin unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node); 11630986ab12SMaksim Yevmenkin con = ng_hci_con_by_handle(unit, con_handle); 11640986ab12SMaksim Yevmenkin 11650986ab12SMaksim Yevmenkin if (con == NULL) { 11660986ab12SMaksim Yevmenkin NG_HCI_ALERT( 11670986ab12SMaksim Yevmenkin "%s: %s - could not find connection, handle=%d\n", 11680986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(node), con_handle); 11690986ab12SMaksim Yevmenkin return; 11700986ab12SMaksim Yevmenkin } 11710986ab12SMaksim Yevmenkin 11720986ab12SMaksim Yevmenkin if (!(con->flags & NG_HCI_CON_TIMEOUT_PENDING)) { 11730986ab12SMaksim Yevmenkin NG_HCI_ALERT( 11740986ab12SMaksim Yevmenkin "%s: %s - no pending connection timeout, handle=%d, state=%d, flags=%#x\n", 11750986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(node), con_handle, con->state, 11760986ab12SMaksim Yevmenkin con->flags); 11770986ab12SMaksim Yevmenkin return; 11780986ab12SMaksim Yevmenkin } 1179878ed226SJulian Elischer 1180878ed226SJulian Elischer con->flags &= ~NG_HCI_CON_TIMEOUT_PENDING; 1181878ed226SJulian Elischer 1182878ed226SJulian Elischer /* 1183878ed226SJulian Elischer * We expect to receive connection timeout in one of the following 1184878ed226SJulian Elischer * states: 1185878ed226SJulian Elischer * 1186f2bb1caeSJulian Elischer * 1) NG_HCI_CON_W4_LP_CON_RSP means that upper layer has not responded 1187878ed226SJulian Elischer * to our LP_CON_IND. Do nothing and destroy connection. Remote peer 1188878ed226SJulian Elischer * most likely already gave up on us. 1189878ed226SJulian Elischer * 1190f2bb1caeSJulian Elischer * 2) NG_HCI_CON_W4_CONN_COMPLETE means upper layer requested connection 1191878ed226SJulian Elischer * (or we in the process of accepting it) and baseband has timedout 1192878ed226SJulian Elischer * on us. Inform upper layers and send LP_CON_CFM. 1193878ed226SJulian Elischer */ 1194878ed226SJulian Elischer 1195878ed226SJulian Elischer switch (con->state) { 1196878ed226SJulian Elischer case NG_HCI_CON_W4_LP_CON_RSP: 1197878ed226SJulian Elischer break; 1198878ed226SJulian Elischer 1199878ed226SJulian Elischer case NG_HCI_CON_W4_CONN_COMPLETE: 1200878ed226SJulian Elischer ng_hci_lp_con_cfm(con, 0xee); 1201878ed226SJulian Elischer break; 1202878ed226SJulian Elischer 1203878ed226SJulian Elischer default: 12040986ab12SMaksim Yevmenkin panic( 12050986ab12SMaksim Yevmenkin "%s: %s - Invalid connection state=%d\n", 12060986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(node), con->state); 1207878ed226SJulian Elischer break; 1208878ed226SJulian Elischer } 1209878ed226SJulian Elischer 1210878ed226SJulian Elischer ng_hci_free_con(con); 1211878ed226SJulian Elischer } /* ng_hci_process_con_timeout */ 1212878ed226SJulian Elischer 1213