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