1107120Sjulian/* 2107120Sjulian * ng_l2cap_llpi.c 3139823Simp */ 4139823Simp 5139823Simp/*- 6107120Sjulian * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 7107120Sjulian * All rights reserved. 8107120Sjulian * 9107120Sjulian * Redistribution and use in source and binary forms, with or without 10107120Sjulian * modification, are permitted provided that the following conditions 11107120Sjulian * are met: 12107120Sjulian * 1. Redistributions of source code must retain the above copyright 13107120Sjulian * notice, this list of conditions and the following disclaimer. 14107120Sjulian * 2. Redistributions in binary form must reproduce the above copyright 15107120Sjulian * notice, this list of conditions and the following disclaimer in the 16107120Sjulian * documentation and/or other materials provided with the distribution. 17107120Sjulian * 18107120Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19107120Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20107120Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21107120Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22107120Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23107120Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24107120Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25107120Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26107120Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27107120Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28107120Sjulian * SUCH DAMAGE. 29107120Sjulian * 30121054Semax * $Id: ng_l2cap_llpi.c,v 1.5 2003/09/08 19:11:45 max Exp $ 31107120Sjulian * $FreeBSD$ 32107120Sjulian */ 33107120Sjulian 34107120Sjulian#include <sys/param.h> 35107120Sjulian#include <sys/systm.h> 36107120Sjulian#include <sys/kernel.h> 37107120Sjulian#include <sys/endian.h> 38107120Sjulian#include <sys/malloc.h> 39107120Sjulian#include <sys/mbuf.h> 40107120Sjulian#include <sys/queue.h> 41107120Sjulian#include <netgraph/ng_message.h> 42107120Sjulian#include <netgraph/netgraph.h> 43128688Semax#include <netgraph/bluetooth/include/ng_bluetooth.h> 44128688Semax#include <netgraph/bluetooth/include/ng_hci.h> 45128688Semax#include <netgraph/bluetooth/include/ng_l2cap.h> 46128688Semax#include <netgraph/bluetooth/l2cap/ng_l2cap_var.h> 47128688Semax#include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h> 48128688Semax#include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h> 49128688Semax#include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h> 50128688Semax#include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h> 51128688Semax#include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h> 52107120Sjulian 53107120Sjulian/****************************************************************************** 54107120Sjulian ****************************************************************************** 55107120Sjulian ** Lower Layer Protocol (HCI) Interface module 56107120Sjulian ****************************************************************************** 57107120Sjulian ******************************************************************************/ 58107120Sjulian 59107120Sjulian/* 60107120Sjulian * Send LP_ConnectReq event to the lower layer protocol. Create new connection 61107120Sjulian * descriptor and initialize it. Create LP_ConnectReq event and send it to the 62107120Sjulian * lower layer, then adjust connection state and start timer. The function WILL 63107120Sjulian * FAIL if connection to the remote unit already exists. 64107120Sjulian */ 65107120Sjulian 66107120Sjulianint 67281198Stakawatang_l2cap_lp_con_req(ng_l2cap_p l2cap, bdaddr_p bdaddr, int type) 68107120Sjulian{ 69107120Sjulian struct ng_mesg *msg = NULL; 70107120Sjulian ng_hci_lp_con_req_ep *ep = NULL; 71107120Sjulian ng_l2cap_con_p con = NULL; 72107120Sjulian int error = 0; 73107120Sjulian 74107120Sjulian /* Verify that we DO NOT have connection to the remote unit */ 75281198Stakawata con = ng_l2cap_con_by_addr(l2cap, bdaddr, type); 76107120Sjulian if (con != NULL) { 77107120Sjulian NG_L2CAP_ALERT( 78107120Sjulian"%s: %s - unexpected LP_ConnectReq event. " \ 79107120Sjulian"Connection already exists, state=%d, con_handle=%d\n", 80107120Sjulian __func__, NG_NODE_NAME(l2cap->node), con->state, 81107120Sjulian con->con_handle); 82107120Sjulian 83107120Sjulian return (EEXIST); 84107120Sjulian } 85107120Sjulian 86107120Sjulian /* Check if lower layer protocol is still connected */ 87107120Sjulian if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) { 88107120Sjulian NG_L2CAP_ERR( 89107120Sjulian"%s: %s - hook \"%s\" is not connected or valid\n", 90107120Sjulian __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI); 91107120Sjulian 92107120Sjulian return (ENOTCONN); 93107120Sjulian } 94107120Sjulian 95107120Sjulian /* Create and intialize new connection descriptor */ 96281198Stakawata con = ng_l2cap_new_con(l2cap, bdaddr, type); 97107120Sjulian if (con == NULL) 98107120Sjulian return (ENOMEM); 99107120Sjulian 100107120Sjulian /* Create and send LP_ConnectReq event */ 101107120Sjulian NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_REQ, 102107120Sjulian sizeof(*ep), M_NOWAIT); 103107120Sjulian if (msg == NULL) { 104107120Sjulian ng_l2cap_free_con(con); 105107120Sjulian 106107120Sjulian return (ENOMEM); 107107120Sjulian } 108107120Sjulian 109107120Sjulian ep = (ng_hci_lp_con_req_ep *) (msg->data); 110107120Sjulian bcopy(bdaddr, &ep->bdaddr, sizeof(ep->bdaddr)); 111281198Stakawata ep->link_type = type; 112107120Sjulian 113114878Sjulian con->flags |= NG_L2CAP_CON_OUTGOING; 114107120Sjulian con->state = NG_L2CAP_W4_LP_CON_CFM; 115107120Sjulian ng_l2cap_lp_timeout(con); 116107120Sjulian 117128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0); 118114878Sjulian if (error != 0) { 119187454Semax if (ng_l2cap_lp_untimeout(con) == 0) 120187454Semax ng_l2cap_free_con(con); 121121054Semax 122187454Semax /* 123187454Semax * Do not free connection if ng_l2cap_lp_untimeout() failed 124187454Semax * let timeout handler deal with it. Always return error to 125187454Semax * the caller. 126187454Semax */ 127114878Sjulian } 128107120Sjulian 129107120Sjulian return (error); 130107120Sjulian} /* ng_l2cap_lp_con_req */ 131107120Sjulian 132107120Sjulian/* 133107120Sjulian * Process LP_ConnectCfm event from the lower layer protocol. It could be 134107120Sjulian * positive or negative. Verify remote unit address then stop the timer and 135107120Sjulian * process event. 136107120Sjulian */ 137107120Sjulian 138107120Sjulianint 139107120Sjulianng_l2cap_lp_con_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg) 140107120Sjulian{ 141107120Sjulian ng_hci_lp_con_cfm_ep *ep = NULL; 142107120Sjulian ng_l2cap_con_p con = NULL; 143107120Sjulian int error = 0; 144107120Sjulian 145107120Sjulian /* Check message */ 146107120Sjulian if (msg->header.arglen != sizeof(*ep)) { 147107120Sjulian NG_L2CAP_ALERT( 148107120Sjulian"%s: %s - invalid LP_ConnectCfm[Neg] message size\n", 149107120Sjulian __func__, NG_NODE_NAME(l2cap->node)); 150107120Sjulian error = EMSGSIZE; 151107120Sjulian goto out; 152107120Sjulian } 153107120Sjulian 154107120Sjulian ep = (ng_hci_lp_con_cfm_ep *) (msg->data); 155107120Sjulian /* Check if we have requested/accepted this connection */ 156281198Stakawata con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr, ep->link_type); 157107120Sjulian if (con == NULL) { 158107120Sjulian NG_L2CAP_ERR( 159107120Sjulian"%s: %s - unexpected LP_ConnectCfm event. Connection does not exist\n", 160107120Sjulian __func__, NG_NODE_NAME(l2cap->node)); 161107120Sjulian error = ENOENT; 162107120Sjulian goto out; 163107120Sjulian } 164107120Sjulian 165107120Sjulian /* Check connection state */ 166107120Sjulian if (con->state != NG_L2CAP_W4_LP_CON_CFM) { 167107120Sjulian NG_L2CAP_ALERT( 168107120Sjulian"%s: %s - unexpected LP_ConnectCfm event. " \ 169107120Sjulian"Invalid connection state, state=%d, con_handle=%d\n", 170107120Sjulian __func__, NG_NODE_NAME(l2cap->node), con->state, 171107120Sjulian con->con_handle); 172107120Sjulian error = EINVAL; 173107120Sjulian goto out; 174107120Sjulian } 175107120Sjulian 176107120Sjulian /* 177107120Sjulian * Looks like it is our confirmation. It is safe now to cancel 178121054Semax * connection timer and notify upper layer. If timeout already 179121054Semax * happened then ignore connection confirmation and let timeout 180121054Semax * handle that. 181107120Sjulian */ 182107120Sjulian 183121054Semax if ((error = ng_l2cap_lp_untimeout(con)) != 0) 184121054Semax goto out; 185107120Sjulian 186107120Sjulian if (ep->status == 0) { 187107120Sjulian con->state = NG_L2CAP_CON_OPEN; 188107120Sjulian con->con_handle = ep->con_handle; 189107120Sjulian ng_l2cap_lp_deliver(con); 190114878Sjulian } else /* Negative confirmation - remove connection descriptor */ 191107120Sjulian ng_l2cap_con_fail(con, ep->status); 192107120Sjulianout: 193107120Sjulian return (error); 194107120Sjulian} /* ng_l2cap_lp_con_cfm */ 195107120Sjulian 196107120Sjulian/* 197107120Sjulian * Process LP_ConnectInd event from the lower layer protocol. This is a good 198107120Sjulian * place to put some extra check on remote unit address and/or class. We could 199107120Sjulian * even forward this information to control hook (or check against internal 200107120Sjulian * black list) and thus implement some kind of firewall. But for now be simple 201107120Sjulian * and create new connection descriptor, start timer and send LP_ConnectRsp 202107120Sjulian * event (i.e. accept connection). 203107120Sjulian */ 204107120Sjulian 205107120Sjulianint 206107120Sjulianng_l2cap_lp_con_ind(ng_l2cap_p l2cap, struct ng_mesg *msg) 207107120Sjulian{ 208107120Sjulian ng_hci_lp_con_ind_ep *ep = NULL; 209107120Sjulian ng_hci_lp_con_rsp_ep *rp = NULL; 210107120Sjulian struct ng_mesg *rsp = NULL; 211107120Sjulian ng_l2cap_con_p con = NULL; 212107120Sjulian int error = 0; 213107120Sjulian 214107120Sjulian /* Check message */ 215107120Sjulian if (msg->header.arglen != sizeof(*ep)) { 216107120Sjulian NG_L2CAP_ALERT( 217107120Sjulian"%s: %s - invalid LP_ConnectInd message size\n", 218107120Sjulian __func__, NG_NODE_NAME(l2cap->node)); 219187454Semax 220187454Semax return (EMSGSIZE); 221107120Sjulian } 222107120Sjulian 223107120Sjulian ep = (ng_hci_lp_con_ind_ep *) (msg->data); 224107120Sjulian 225107120Sjulian /* Make sure we have only one connection to the remote unit */ 226281198Stakawata con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr, ep->link_type); 227107120Sjulian if (con != NULL) { 228107120Sjulian NG_L2CAP_ALERT( 229107120Sjulian"%s: %s - unexpected LP_ConnectInd event. " \ 230107120Sjulian"Connection already exists, state=%d, con_handle=%d\n", 231107120Sjulian __func__, NG_NODE_NAME(l2cap->node), con->state, 232107120Sjulian con->con_handle); 233187454Semax 234187454Semax return (EEXIST); 235107120Sjulian } 236107120Sjulian 237107120Sjulian /* Check if lower layer protocol is still connected */ 238107120Sjulian if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) { 239107120Sjulian NG_L2CAP_ERR( 240107120Sjulian"%s: %s - hook \"%s\" is not connected or valid", 241107120Sjulian __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI); 242187454Semax 243187454Semax return (ENOTCONN); 244107120Sjulian } 245107120Sjulian 246107120Sjulian /* Create and intialize new connection descriptor */ 247281198Stakawata con = ng_l2cap_new_con(l2cap, &ep->bdaddr, ep->link_type); 248187454Semax if (con == NULL) 249187454Semax return (ENOMEM); 250107120Sjulian 251107120Sjulian /* Create and send LP_ConnectRsp event */ 252107120Sjulian NG_MKMESSAGE(rsp, NGM_HCI_COOKIE, NGM_HCI_LP_CON_RSP, 253107120Sjulian sizeof(*rp), M_NOWAIT); 254148518Semax if (rsp == NULL) { 255107120Sjulian ng_l2cap_free_con(con); 256187454Semax 257187454Semax return (ENOMEM); 258107120Sjulian } 259107120Sjulian 260107120Sjulian rp = (ng_hci_lp_con_rsp_ep *)(rsp->data); 261107120Sjulian rp->status = 0x00; /* accept connection */ 262107120Sjulian rp->link_type = NG_HCI_LINK_ACL; 263107120Sjulian bcopy(&ep->bdaddr, &rp->bdaddr, sizeof(rp->bdaddr)); 264107120Sjulian 265107120Sjulian con->state = NG_L2CAP_W4_LP_CON_CFM; 266107120Sjulian ng_l2cap_lp_timeout(con); 267107120Sjulian 268128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, rsp, l2cap->hci, 0); 269114878Sjulian if (error != 0) { 270187454Semax if (ng_l2cap_lp_untimeout(con) == 0) 271187454Semax ng_l2cap_free_con(con); 272121054Semax 273187454Semax /* 274187454Semax * Do not free connection if ng_l2cap_lp_untimeout() failed 275187454Semax * let timeout handler deal with it. Always return error to 276187454Semax * the caller. 277187454Semax */ 278114878Sjulian } 279187454Semax 280107120Sjulian return (error); 281187454Semax} /* ng_l2cap_lp_con_ind */ 282107120Sjulian 283107120Sjulian/* 284107120Sjulian * Process LP_DisconnectInd event from the lower layer protocol. We have been 285107120Sjulian * disconnected from the remote unit. So notify the upper layer protocol. 286107120Sjulian */ 287107120Sjulian 288107120Sjulianint 289107120Sjulianng_l2cap_lp_discon_ind(ng_l2cap_p l2cap, struct ng_mesg *msg) 290107120Sjulian{ 291107120Sjulian ng_hci_lp_discon_ind_ep *ep = NULL; 292107120Sjulian ng_l2cap_con_p con = NULL; 293107120Sjulian int error = 0; 294107120Sjulian 295107120Sjulian /* Check message */ 296107120Sjulian if (msg->header.arglen != sizeof(*ep)) { 297107120Sjulian NG_L2CAP_ALERT( 298107120Sjulian"%s: %s - invalid LP_DisconnectInd message size\n", 299107120Sjulian __func__, NG_NODE_NAME(l2cap->node)); 300107120Sjulian error = EMSGSIZE; 301107120Sjulian goto out; 302107120Sjulian } 303107120Sjulian 304107120Sjulian ep = (ng_hci_lp_discon_ind_ep *) (msg->data); 305107120Sjulian 306107120Sjulian /* Check if we have this connection */ 307107120Sjulian con = ng_l2cap_con_by_handle(l2cap, ep->con_handle); 308107120Sjulian if (con == NULL) { 309107120Sjulian NG_L2CAP_ERR( 310107120Sjulian"%s: %s - unexpected LP_DisconnectInd event. " \ 311107120Sjulian"Connection does not exist, con_handle=%d\n", 312107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ep->con_handle); 313107120Sjulian error = ENOENT; 314107120Sjulian goto out; 315107120Sjulian } 316107120Sjulian 317107120Sjulian /* XXX Verify connection state -- do we need to check this? */ 318107120Sjulian if (con->state != NG_L2CAP_CON_OPEN) { 319107120Sjulian NG_L2CAP_ERR( 320107120Sjulian"%s: %s - unexpected LP_DisconnectInd event. " \ 321107120Sjulian"Invalid connection state, state=%d, con_handle=%d\n", 322107120Sjulian __func__, NG_NODE_NAME(l2cap->node), con->state, 323107120Sjulian con->con_handle); 324107120Sjulian error = EINVAL; 325107120Sjulian goto out; 326107120Sjulian } 327107120Sjulian 328121054Semax /* 329121054Semax * Notify upper layer and remove connection 330121054Semax * Note: The connection could have auto disconnect timeout set. Try 331121054Semax * to remove it. If auto disconnect timeout happened then ignore 332121054Semax * disconnect indication and let timeout handle that. 333121054Semax */ 334121054Semax 335114878Sjulian if (con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO) 336121054Semax if ((error = ng_l2cap_discon_untimeout(con)) != 0) 337121054Semax return (error); 338114878Sjulian 339107120Sjulian ng_l2cap_con_fail(con, ep->reason); 340107120Sjulianout: 341107120Sjulian return (error); 342107120Sjulian} /* ng_l2cap_lp_discon_ind */ 343107120Sjulian 344107120Sjulian/* 345107120Sjulian * Send LP_QoSSetupReq event to the lower layer protocol 346107120Sjulian */ 347107120Sjulian 348107120Sjulianint 349107120Sjulianng_l2cap_lp_qos_req(ng_l2cap_p l2cap, u_int16_t con_handle, 350107120Sjulian ng_l2cap_flow_p flow) 351107120Sjulian{ 352107120Sjulian struct ng_mesg *msg = NULL; 353107120Sjulian ng_hci_lp_qos_req_ep *ep = NULL; 354107120Sjulian ng_l2cap_con_p con = NULL; 355107120Sjulian int error = 0; 356107120Sjulian 357107120Sjulian /* Verify that we have this connection */ 358107120Sjulian con = ng_l2cap_con_by_handle(l2cap, con_handle); 359107120Sjulian if (con == NULL) { 360107120Sjulian NG_L2CAP_ERR( 361107120Sjulian"%s: %s - unexpected LP_QoSSetupReq event. " \ 362107120Sjulian"Connection does not exist, con_handle=%d\n", 363107120Sjulian __func__, NG_NODE_NAME(l2cap->node), con_handle); 364107120Sjulian 365107120Sjulian return (ENOENT); 366107120Sjulian } 367107120Sjulian 368107120Sjulian /* Verify connection state */ 369107120Sjulian if (con->state != NG_L2CAP_CON_OPEN) { 370107120Sjulian NG_L2CAP_ERR( 371107120Sjulian"%s: %s - unexpected LP_QoSSetupReq event. " \ 372107120Sjulian"Invalid connection state, state=%d, con_handle=%d\n", 373107120Sjulian __func__, NG_NODE_NAME(l2cap->node), con->state, 374107120Sjulian con->con_handle); 375107120Sjulian 376107120Sjulian return (EINVAL); 377107120Sjulian } 378107120Sjulian 379107120Sjulian /* Check if lower layer protocol is still connected */ 380107120Sjulian if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) { 381107120Sjulian NG_L2CAP_ERR( 382107120Sjulian"%s: %s - hook \"%s\" is not connected or valid", 383107120Sjulian __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI); 384107120Sjulian 385107120Sjulian return (ENOTCONN); 386107120Sjulian } 387107120Sjulian 388107120Sjulian /* Create and send LP_QoSSetupReq event */ 389107120Sjulian NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_REQ, 390107120Sjulian sizeof(*ep), M_NOWAIT); 391107120Sjulian if (msg == NULL) 392107120Sjulian return (ENOMEM); 393107120Sjulian 394107120Sjulian ep = (ng_hci_lp_qos_req_ep *) (msg->data); 395107120Sjulian ep->con_handle = con_handle; 396107120Sjulian ep->flags = flow->flags; 397107120Sjulian ep->service_type = flow->service_type; 398107120Sjulian ep->token_rate = flow->token_rate; 399107120Sjulian ep->peak_bandwidth = flow->peak_bandwidth; 400107120Sjulian ep->latency = flow->latency; 401107120Sjulian ep->delay_variation = flow->delay_variation; 402107120Sjulian 403128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0); 404107120Sjulian 405107120Sjulian return (error); 406107120Sjulian} /* ng_l2cap_lp_con_req */ 407107120Sjulian 408107120Sjulian/* 409107120Sjulian * Process LP_QoSSetupCfm from the lower layer protocol 410107120Sjulian */ 411107120Sjulian 412107120Sjulianint 413107120Sjulianng_l2cap_lp_qos_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg) 414107120Sjulian{ 415107120Sjulian ng_hci_lp_qos_cfm_ep *ep = NULL; 416107120Sjulian int error = 0; 417107120Sjulian 418107120Sjulian /* Check message */ 419107120Sjulian if (msg->header.arglen != sizeof(*ep)) { 420107120Sjulian NG_L2CAP_ALERT( 421107120Sjulian"%s: %s - invalid LP_QoSSetupCfm[Neg] message size\n", 422107120Sjulian __func__, NG_NODE_NAME(l2cap->node)); 423107120Sjulian error = EMSGSIZE; 424107120Sjulian goto out; 425107120Sjulian } 426107120Sjulian 427107120Sjulian ep = (ng_hci_lp_qos_cfm_ep *) (msg->data); 428107120Sjulian /* XXX FIXME do something */ 429107120Sjulianout: 430107120Sjulian return (error); 431107120Sjulian} /* ng_l2cap_lp_qos_cfm */ 432107120Sjulian 433107120Sjulian/* 434107120Sjulian * Process LP_QoSViolationInd event from the lower layer protocol. Lower 435107120Sjulian * layer protocol has detected QoS Violation, so we MUST notify the 436107120Sjulian * upper layer. 437107120Sjulian */ 438107120Sjulian 439107120Sjulianint 440107120Sjulianng_l2cap_lp_qos_ind(ng_l2cap_p l2cap, struct ng_mesg *msg) 441107120Sjulian{ 442107120Sjulian ng_hci_lp_qos_ind_ep *ep = NULL; 443107120Sjulian ng_l2cap_con_p con = NULL; 444107120Sjulian int error = 0; 445107120Sjulian 446107120Sjulian /* Check message */ 447107120Sjulian if (msg->header.arglen != sizeof(*ep)) { 448107120Sjulian NG_L2CAP_ALERT( 449107120Sjulian"%s: %s - invalid LP_QoSViolation message size\n", 450107120Sjulian __func__, NG_NODE_NAME(l2cap->node)); 451107120Sjulian error = EMSGSIZE; 452107120Sjulian goto out; 453107120Sjulian } 454107120Sjulian 455107120Sjulian ep = (ng_hci_lp_qos_ind_ep *) (msg->data); 456107120Sjulian 457107120Sjulian /* Check if we have this connection */ 458107120Sjulian con = ng_l2cap_con_by_handle(l2cap, ep->con_handle); 459107120Sjulian if (con == NULL) { 460107120Sjulian NG_L2CAP_ERR( 461107120Sjulian"%s: %s - unexpected LP_QoSViolationInd event. " \ 462107120Sjulian"Connection does not exist, con_handle=%d\n", 463107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ep->con_handle); 464107120Sjulian error = ENOENT; 465107120Sjulian goto out; 466107120Sjulian } 467107120Sjulian 468107120Sjulian /* Verify connection state */ 469107120Sjulian if (con->state != NG_L2CAP_CON_OPEN) { 470107120Sjulian NG_L2CAP_ERR( 471107120Sjulian"%s: %s - unexpected LP_QoSViolationInd event. " \ 472107120Sjulian"Invalid connection state, state=%d, con_handle=%d\n", 473107120Sjulian __func__, NG_NODE_NAME(l2cap->node), con->state, 474107120Sjulian con->con_handle); 475107120Sjulian error = EINVAL; 476107120Sjulian goto out; 477107120Sjulian } 478107120Sjulian 479107120Sjulian /* XXX FIXME Notify upper layer and terminate channels if required */ 480107120Sjulianout: 481107120Sjulian return (error); 482107120Sjulian} /* ng_l2cap_qos_ind */ 483107120Sjulian 484290038Stakawataint 485290038Stakawatang_l2cap_lp_enc_change(ng_l2cap_p l2cap, struct ng_mesg *msg) 486290038Stakawata{ 487290038Stakawata ng_hci_lp_enc_change_ep *ep = NULL; 488290038Stakawata ng_l2cap_con_p con = NULL; 489290038Stakawata int error = 0; 490290038Stakawata ng_l2cap_chan_p ch = NULL; 491290038Stakawata /* Check message */ 492290038Stakawata if (msg->header.arglen != sizeof(*ep)) { 493290038Stakawata NG_L2CAP_ALERT( 494290038Stakawata"%s: %s - invalid LP_ENCChange message size\n", 495290038Stakawata __func__, NG_NODE_NAME(l2cap->node)); 496290038Stakawata error = EMSGSIZE; 497290038Stakawata goto out; 498290038Stakawata } 499290038Stakawata 500290038Stakawata ep = (ng_hci_lp_enc_change_ep *) (msg->data); 501290038Stakawata 502290038Stakawata /* Check if we have this connection */ 503290038Stakawata con = ng_l2cap_con_by_handle(l2cap, ep->con_handle); 504290038Stakawata if (con == NULL) { 505290038Stakawata NG_L2CAP_ERR( 506290038Stakawata"%s: %s - unexpected LP_Enc Change Event. " \ 507290038Stakawata"Connection does not exist, con_handle=%d\n", 508290038Stakawata __func__, NG_NODE_NAME(l2cap->node), ep->con_handle); 509290038Stakawata error = ENOENT; 510290038Stakawata goto out; 511290038Stakawata } 512290038Stakawata 513290038Stakawata /* Verify connection state */ 514290038Stakawata if (con->state != NG_L2CAP_CON_OPEN) { 515290038Stakawata NG_L2CAP_ERR( 516290038Stakawata"%s: %s - unexpected ENC_CHANGE event. " \ 517290038Stakawata"Invalid connection state, state=%d, con_handle=%d\n", 518290038Stakawata __func__, NG_NODE_NAME(l2cap->node), con->state, 519290038Stakawata con->con_handle); 520290038Stakawata error = EINVAL; 521290038Stakawata goto out; 522290038Stakawata } 523290038Stakawata 524290038Stakawata con->encryption = ep->status; 525290038Stakawata 526290038Stakawata LIST_FOREACH(ch, &l2cap->chan_list, next){ 527290038Stakawata if((ch->con->con_handle == ep->con_handle) && 528290038Stakawata (ch->con->linktype == ep->link_type)) 529290038Stakawata ng_l2cap_l2ca_encryption_change(ch, ep->status); 530290038Stakawata } 531290038Stakawata 532290038Stakawataout: 533290038Stakawata return (error); 534290038Stakawata} /* ng_l2cap_enc_change */ 535290038Stakawata 536107120Sjulian/* 537107120Sjulian * Prepare L2CAP packet. Prepend packet with L2CAP packet header and then 538107120Sjulian * segment it according to HCI MTU. 539107120Sjulian */ 540107120Sjulian 541107120Sjulianint 542107120Sjulianng_l2cap_lp_send(ng_l2cap_con_p con, u_int16_t dcid, struct mbuf *m0) 543107120Sjulian{ 544107120Sjulian ng_l2cap_p l2cap = con->l2cap; 545107120Sjulian ng_l2cap_hdr_t *l2cap_hdr = NULL; 546107120Sjulian ng_hci_acldata_pkt_t *acl_hdr = NULL; 547107120Sjulian struct mbuf *m_last = NULL, *m = NULL; 548107120Sjulian int len, flag = NG_HCI_PACKET_START; 549107120Sjulian 550107120Sjulian KASSERT((con->tx_pkt == NULL), 551107120Sjulian("%s: %s - another packet pending?!\n", __func__, NG_NODE_NAME(l2cap->node))); 552107120Sjulian KASSERT((l2cap->pkt_size > 0), 553107120Sjulian("%s: %s - invalid l2cap->pkt_size?!\n", __func__, NG_NODE_NAME(l2cap->node))); 554107120Sjulian 555107120Sjulian /* Prepend mbuf with L2CAP header */ 556107120Sjulian m0 = ng_l2cap_prepend(m0, sizeof(*l2cap_hdr)); 557107120Sjulian if (m0 == NULL) { 558107120Sjulian NG_L2CAP_ALERT( 559128076Semax"%s: %s - ng_l2cap_prepend(%zd) failed\n", 560107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 561107120Sjulian sizeof(*l2cap_hdr)); 562107120Sjulian 563107120Sjulian goto fail; 564107120Sjulian } 565107120Sjulian 566107120Sjulian l2cap_hdr = mtod(m0, ng_l2cap_hdr_t *); 567107120Sjulian l2cap_hdr->length = htole16(m0->m_pkthdr.len - sizeof(*l2cap_hdr)); 568107120Sjulian l2cap_hdr->dcid = htole16(dcid); 569107120Sjulian 570107120Sjulian /* 571107120Sjulian * Segment single L2CAP packet according to the HCI layer MTU. Convert 572107120Sjulian * each segment into ACL data packet and prepend it with ACL data packet 573107120Sjulian * header. Link all segments together via m_nextpkt link. 574107120Sjulian * 575107120Sjulian * XXX BC (Broadcast flag) will always be 0 (zero). 576107120Sjulian */ 577107120Sjulian 578107120Sjulian while (m0 != NULL) { 579107120Sjulian /* Check length of the packet against HCI MTU */ 580107120Sjulian len = m0->m_pkthdr.len; 581107120Sjulian if (len > l2cap->pkt_size) { 582243882Sglebius m = m_split(m0, l2cap->pkt_size, M_NOWAIT); 583107120Sjulian if (m == NULL) { 584107120Sjulian NG_L2CAP_ALERT( 585107120Sjulian"%s: %s - m_split(%d) failed\n", __func__, NG_NODE_NAME(l2cap->node), 586107120Sjulian l2cap->pkt_size); 587107120Sjulian goto fail; 588107120Sjulian } 589107120Sjulian 590107120Sjulian len = l2cap->pkt_size; 591107120Sjulian } 592107120Sjulian 593107120Sjulian /* Convert packet fragment into ACL data packet */ 594107120Sjulian m0 = ng_l2cap_prepend(m0, sizeof(*acl_hdr)); 595107120Sjulian if (m0 == NULL) { 596107120Sjulian NG_L2CAP_ALERT( 597128076Semax"%s: %s - ng_l2cap_prepend(%zd) failed\n", 598107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 599107120Sjulian sizeof(*acl_hdr)); 600107120Sjulian goto fail; 601107120Sjulian } 602107120Sjulian 603107120Sjulian acl_hdr = mtod(m0, ng_hci_acldata_pkt_t *); 604107120Sjulian acl_hdr->type = NG_HCI_ACL_DATA_PKT; 605107120Sjulian acl_hdr->length = htole16(len); 606107120Sjulian acl_hdr->con_handle = htole16(NG_HCI_MK_CON_HANDLE( 607107120Sjulian con->con_handle, flag, 0)); 608107120Sjulian 609107120Sjulian /* Add fragment to the chain */ 610107120Sjulian m0->m_nextpkt = NULL; 611107120Sjulian 612107120Sjulian if (con->tx_pkt == NULL) 613107120Sjulian con->tx_pkt = m_last = m0; 614107120Sjulian else { 615107120Sjulian m_last->m_nextpkt = m0; 616107120Sjulian m_last = m0; 617107120Sjulian } 618107120Sjulian 619107120Sjulian NG_L2CAP_INFO( 620107120Sjulian"%s: %s - attaching ACL packet, con_handle=%d, PB=%#x, length=%d\n", 621107120Sjulian __func__, NG_NODE_NAME(l2cap->node), con->con_handle, 622107120Sjulian flag, len); 623107120Sjulian 624107120Sjulian m0 = m; 625107120Sjulian m = NULL; 626107120Sjulian flag = NG_HCI_PACKET_FRAGMENT; 627107120Sjulian } 628107120Sjulian 629107120Sjulian return (0); 630107120Sjulianfail: 631107120Sjulian NG_FREE_M(m0); 632107120Sjulian NG_FREE_M(m); 633107120Sjulian 634107120Sjulian while (con->tx_pkt != NULL) { 635107120Sjulian m = con->tx_pkt->m_nextpkt; 636107120Sjulian m_freem(con->tx_pkt); 637107120Sjulian con->tx_pkt = m; 638107120Sjulian } 639107120Sjulian 640107120Sjulian return (ENOBUFS); 641107120Sjulian} /* ng_l2cap_lp_send */ 642107120Sjulian 643107120Sjulian/* 644107120Sjulian * Receive ACL data packet from the HCI layer. First strip ACL packet header 645107120Sjulian * and get connection handle, PB (Packet Boundary) flag and payload length. 646107120Sjulian * Then find connection descriptor and verify its state. Then process ACL 647107120Sjulian * packet as follows. 648107120Sjulian * 649107120Sjulian * 1) If we got first segment (pb == NG_HCI_PACKET_START) then extract L2CAP 650107120Sjulian * header and get total length of the L2CAP packet. Then start new L2CAP 651107120Sjulian * packet. 652107120Sjulian * 653107120Sjulian * 2) If we got other (then first :) segment (pb == NG_HCI_PACKET_FRAGMENT) 654107120Sjulian * then add segment to the packet. 655107120Sjulian */ 656107120Sjulian 657107120Sjulianint 658107120Sjulianng_l2cap_lp_receive(ng_l2cap_p l2cap, struct mbuf *m) 659107120Sjulian{ 660107120Sjulian ng_hci_acldata_pkt_t *acl_hdr = NULL; 661107120Sjulian ng_l2cap_hdr_t *l2cap_hdr = NULL; 662107120Sjulian ng_l2cap_con_p con = NULL; 663107120Sjulian u_int16_t con_handle, length, pb; 664107120Sjulian int error = 0; 665107120Sjulian 666107120Sjulian /* Check ACL data packet */ 667107120Sjulian if (m->m_pkthdr.len < sizeof(*acl_hdr)) { 668107120Sjulian NG_L2CAP_ERR( 669107120Sjulian"%s: %s - invalid ACL data packet. Packet too small, length=%d\n", 670107120Sjulian __func__, NG_NODE_NAME(l2cap->node), m->m_pkthdr.len); 671107120Sjulian error = EMSGSIZE; 672107120Sjulian goto drop; 673107120Sjulian } 674107120Sjulian 675107120Sjulian /* Strip ACL data packet header */ 676107120Sjulian NG_L2CAP_M_PULLUP(m, sizeof(*acl_hdr)); 677107120Sjulian if (m == NULL) 678107120Sjulian return (ENOBUFS); 679107120Sjulian 680107120Sjulian acl_hdr = mtod(m, ng_hci_acldata_pkt_t *); 681107120Sjulian m_adj(m, sizeof(*acl_hdr)); 682107120Sjulian 683107120Sjulian /* Get ACL connection handle, PB flag and payload length */ 684107120Sjulian acl_hdr->con_handle = le16toh(acl_hdr->con_handle); 685107120Sjulian con_handle = NG_HCI_CON_HANDLE(acl_hdr->con_handle); 686107120Sjulian pb = NG_HCI_PB_FLAG(acl_hdr->con_handle); 687107120Sjulian length = le16toh(acl_hdr->length); 688107120Sjulian 689107120Sjulian NG_L2CAP_INFO( 690107120Sjulian"%s: %s - got ACL data packet, con_handle=%d, PB=%#x, length=%d\n", 691107120Sjulian __func__, NG_NODE_NAME(l2cap->node), con_handle, pb, length); 692107120Sjulian 693107120Sjulian /* Get connection descriptor */ 694107120Sjulian con = ng_l2cap_con_by_handle(l2cap, con_handle); 695107120Sjulian if (con == NULL) { 696107120Sjulian NG_L2CAP_ERR( 697107120Sjulian"%s: %s - unexpected ACL data packet. " \ 698107120Sjulian"Connection does not exist, con_handle=%d\n", 699107120Sjulian __func__, NG_NODE_NAME(l2cap->node), con_handle); 700107120Sjulian error = ENOENT; 701107120Sjulian goto drop; 702107120Sjulian } 703107120Sjulian 704107120Sjulian /* Verify connection state */ 705107120Sjulian if (con->state != NG_L2CAP_CON_OPEN) { 706107120Sjulian NG_L2CAP_ERR( 707107120Sjulian"%s: %s - unexpected ACL data packet. Invalid connection state=%d\n", 708107120Sjulian __func__, NG_NODE_NAME(l2cap->node), con->state); 709107120Sjulian error = EHOSTDOWN; 710107120Sjulian goto drop; 711107120Sjulian } 712107120Sjulian 713107120Sjulian /* Process packet */ 714107120Sjulian if (pb == NG_HCI_PACKET_START) { 715107120Sjulian if (con->rx_pkt != NULL) { 716107120Sjulian NG_L2CAP_ERR( 717107120Sjulian"%s: %s - dropping incomplete L2CAP packet, got %d bytes, want %d bytes\n", 718107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 719107120Sjulian con->rx_pkt->m_pkthdr.len, con->rx_pkt_len); 720107120Sjulian NG_FREE_M(con->rx_pkt); 721107120Sjulian con->rx_pkt_len = 0; 722107120Sjulian } 723107120Sjulian 724107120Sjulian /* Get L2CAP header */ 725107120Sjulian if (m->m_pkthdr.len < sizeof(*l2cap_hdr)) { 726107120Sjulian NG_L2CAP_ERR( 727107120Sjulian"%s: %s - invalid L2CAP packet start fragment. Packet too small, length=%d\n", 728107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 729107120Sjulian m->m_pkthdr.len); 730107120Sjulian error = EMSGSIZE; 731107120Sjulian goto drop; 732107120Sjulian } 733107120Sjulian 734107120Sjulian NG_L2CAP_M_PULLUP(m, sizeof(*l2cap_hdr)); 735107120Sjulian if (m == NULL) 736107120Sjulian return (ENOBUFS); 737107120Sjulian 738107120Sjulian l2cap_hdr = mtod(m, ng_l2cap_hdr_t *); 739107120Sjulian 740107120Sjulian NG_L2CAP_INFO( 741107120Sjulian"%s: %s - staring new L2CAP packet, con_handle=%d, length=%d\n", 742107120Sjulian __func__, NG_NODE_NAME(l2cap->node), con_handle, 743107120Sjulian le16toh(l2cap_hdr->length)); 744107120Sjulian 745107120Sjulian /* Start new L2CAP packet */ 746107120Sjulian con->rx_pkt = m; 747107120Sjulian con->rx_pkt_len = le16toh(l2cap_hdr->length)+sizeof(*l2cap_hdr); 748107120Sjulian } else if (pb == NG_HCI_PACKET_FRAGMENT) { 749107120Sjulian if (con->rx_pkt == NULL) { 750107120Sjulian NG_L2CAP_ERR( 751107120Sjulian"%s: %s - unexpected ACL data packet fragment, con_handle=%d\n", 752107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 753107120Sjulian con->con_handle); 754107120Sjulian goto drop; 755107120Sjulian } 756107120Sjulian 757107120Sjulian /* Add fragment to the L2CAP packet */ 758107120Sjulian m_cat(con->rx_pkt, m); 759107120Sjulian con->rx_pkt->m_pkthdr.len += length; 760107120Sjulian } else { 761107120Sjulian NG_L2CAP_ERR( 762107120Sjulian"%s: %s - invalid ACL data packet. Invalid PB flag=%#x\n", 763107120Sjulian __func__, NG_NODE_NAME(l2cap->node), pb); 764107120Sjulian error = EINVAL; 765107120Sjulian goto drop; 766107120Sjulian } 767107120Sjulian 768107120Sjulian con->rx_pkt_len -= length; 769107120Sjulian if (con->rx_pkt_len < 0) { 770107120Sjulian NG_L2CAP_ALERT( 771107120Sjulian"%s: %s - packet length mismatch. Got %d bytes, offset %d bytes\n", 772107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 773107120Sjulian con->rx_pkt->m_pkthdr.len, con->rx_pkt_len); 774107120Sjulian NG_FREE_M(con->rx_pkt); 775107120Sjulian con->rx_pkt_len = 0; 776107120Sjulian } else if (con->rx_pkt_len == 0) { 777107120Sjulian /* OK, we have got complete L2CAP packet, so process it */ 778107120Sjulian error = ng_l2cap_receive(con); 779107120Sjulian con->rx_pkt = NULL; 780107120Sjulian con->rx_pkt_len = 0; 781107120Sjulian } 782107120Sjulian 783107120Sjulian return (error); 784107120Sjulian 785107120Sjuliandrop: 786107120Sjulian NG_FREE_M(m); 787107120Sjulian 788107120Sjulian return (error); 789107120Sjulian} /* ng_l2cap_lp_receive */ 790107120Sjulian 791107120Sjulian/* 792107120Sjulian * Send queued ACL packets to the HCI layer 793107120Sjulian */ 794107120Sjulian 795107120Sjulianvoid 796107120Sjulianng_l2cap_lp_deliver(ng_l2cap_con_p con) 797107120Sjulian{ 798107120Sjulian ng_l2cap_p l2cap = con->l2cap; 799107120Sjulian struct mbuf *m = NULL; 800107120Sjulian int error; 801107120Sjulian 802107120Sjulian /* Check connection */ 803107120Sjulian if (con->state != NG_L2CAP_CON_OPEN) 804107120Sjulian return; 805107120Sjulian 806107120Sjulian if (con->tx_pkt == NULL) 807107120Sjulian ng_l2cap_con_wakeup(con); 808107120Sjulian 809107120Sjulian if (con->tx_pkt == NULL) 810107120Sjulian return; 811107120Sjulian 812107120Sjulian /* Check if lower layer protocol is still connected */ 813107120Sjulian if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) { 814107120Sjulian NG_L2CAP_ERR( 815107120Sjulian"%s: %s - hook \"%s\" is not connected or valid", 816107120Sjulian __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI); 817107120Sjulian 818107120Sjulian goto drop; /* XXX what to do with "pending"? */ 819107120Sjulian } 820107120Sjulian 821107120Sjulian /* Send ACL data packets */ 822107120Sjulian while (con->pending < con->l2cap->num_pkts && con->tx_pkt != NULL) { 823107120Sjulian m = con->tx_pkt; 824107120Sjulian con->tx_pkt = con->tx_pkt->m_nextpkt; 825107120Sjulian m->m_nextpkt = NULL; 826107120Sjulian 827281198Stakawata if(m->m_flags &M_PROTO2){ 828281198Stakawata ng_l2cap_lp_receive(con->l2cap, m); 829281198Stakawata continue; 830281198Stakawata } 831107120Sjulian NG_L2CAP_INFO( 832107120Sjulian"%s: %s - sending ACL packet, con_handle=%d, len=%d\n", 833107120Sjulian __func__, NG_NODE_NAME(l2cap->node), con->con_handle, 834107120Sjulian m->m_pkthdr.len); 835107120Sjulian 836107120Sjulian NG_SEND_DATA_ONLY(error, l2cap->hci, m); 837107120Sjulian if (error != 0) { 838107120Sjulian NG_L2CAP_ERR( 839107120Sjulian"%s: %s - could not send ACL data packet, con_handle=%d, error=%d\n", 840107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 841107120Sjulian con->con_handle, error); 842107120Sjulian 843107120Sjulian goto drop; /* XXX what to do with "pending"? */ 844107120Sjulian } 845107120Sjulian 846107120Sjulian con->pending ++; 847107120Sjulian } 848107120Sjulian 849107120Sjulian NG_L2CAP_INFO( 850107120Sjulian"%s: %s - %d ACL packets have been sent, con_handle=%d\n", 851107120Sjulian __func__, NG_NODE_NAME(l2cap->node), con->pending, 852107120Sjulian con->con_handle); 853107120Sjulian 854107120Sjulian return; 855107120Sjulian 856107120Sjuliandrop: 857107120Sjulian while (con->tx_pkt != NULL) { 858107120Sjulian m = con->tx_pkt->m_nextpkt; 859107120Sjulian m_freem(con->tx_pkt); 860107120Sjulian con->tx_pkt = m; 861107120Sjulian } 862107120Sjulian} /* ng_l2cap_lp_deliver */ 863107120Sjulian 864107120Sjulian/* 865107120Sjulian * Process connection timeout. Remove connection from the list. If there 866107120Sjulian * are any channels that wait for the connection then notify them. Free 867107120Sjulian * connection descriptor. 868107120Sjulian */ 869107120Sjulian 870107120Sjulianvoid 871121054Semaxng_l2cap_process_lp_timeout(node_p node, hook_p hook, void *arg1, int con_handle) 872107120Sjulian{ 873121054Semax ng_l2cap_p l2cap = NULL; 874121054Semax ng_l2cap_con_p con = NULL; 875107120Sjulian 876121054Semax if (NG_NODE_NOT_VALID(node)) { 877121054Semax printf("%s: Netgraph node is not valid\n", __func__); 878121054Semax return; 879121054Semax } 880107120Sjulian 881121054Semax l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node); 882121054Semax con = ng_l2cap_con_by_handle(l2cap, con_handle); 883121054Semax 884121054Semax if (con == NULL) { 885121054Semax NG_L2CAP_ALERT( 886121054Semax"%s: %s - could not find connection, con_handle=%d\n", 887121054Semax __func__, NG_NODE_NAME(node), con_handle); 888121054Semax return; 889121054Semax } 890121054Semax 891121054Semax if (!(con->flags & NG_L2CAP_CON_LP_TIMO)) { 892121054Semax NG_L2CAP_ALERT( 893121054Semax"%s: %s - no pending LP timeout, con_handle=%d, state=%d, flags=%#x\n", 894121054Semax __func__, NG_NODE_NAME(node), con_handle, con->state, 895121054Semax con->flags); 896121054Semax return; 897121054Semax } 898121054Semax 899107120Sjulian /* 900107120Sjulian * Notify channels that connection has timed out. This will remove 901107120Sjulian * connection, channels and pending commands. 902107120Sjulian */ 903107120Sjulian 904114878Sjulian con->flags &= ~NG_L2CAP_CON_LP_TIMO; 905107120Sjulian ng_l2cap_con_fail(con, NG_L2CAP_TIMEOUT); 906107120Sjulian} /* ng_l2cap_process_lp_timeout */ 907107120Sjulian 908114878Sjulian/* 909114878Sjulian * Process auto disconnect timeout and send LP_DisconReq event to the 910114878Sjulian * lower layer protocol 911114878Sjulian */ 912114878Sjulian 913114878Sjulianvoid 914121054Semaxng_l2cap_process_discon_timeout(node_p node, hook_p hook, void *arg1, int con_handle) 915114878Sjulian{ 916121054Semax ng_l2cap_p l2cap = NULL; 917121054Semax ng_l2cap_con_p con = NULL; 918114878Sjulian struct ng_mesg *msg = NULL; 919114878Sjulian ng_hci_lp_discon_req_ep *ep = NULL; 920114878Sjulian int error; 921114878Sjulian 922121054Semax if (NG_NODE_NOT_VALID(node)) { 923121054Semax printf("%s: Netgraph node is not valid\n", __func__); 924121054Semax return; 925121054Semax } 926121054Semax 927121054Semax l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node); 928121054Semax con = ng_l2cap_con_by_handle(l2cap, con_handle); 929121054Semax 930121054Semax if (con == NULL) { 931121054Semax NG_L2CAP_ALERT( 932121054Semax"%s: %s - could not find connection, con_handle=%d\n", 933121054Semax __func__, NG_NODE_NAME(node), con_handle); 934121054Semax return; 935121054Semax } 936121054Semax 937121054Semax if (!(con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO)) { 938121054Semax NG_L2CAP_ALERT( 939121054Semax"%s: %s - no pending disconnect timeout, con_handle=%d, state=%d, flags=%#x\n", 940121054Semax __func__, NG_NODE_NAME(node), con_handle, con->state, 941121054Semax con->flags); 942121054Semax return; 943121054Semax } 944121054Semax 945114878Sjulian con->flags &= ~NG_L2CAP_CON_AUTO_DISCON_TIMO; 946114878Sjulian 947114878Sjulian /* Check if lower layer protocol is still connected */ 948114878Sjulian if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) { 949114878Sjulian NG_L2CAP_ERR( 950114878Sjulian"%s: %s - hook \"%s\" is not connected or valid\n", 951114878Sjulian __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI); 952114878Sjulian return; 953114878Sjulian } 954114878Sjulian 955114878Sjulian /* Create and send LP_DisconReq event */ 956114878Sjulian NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_REQ, 957114878Sjulian sizeof(*ep), M_NOWAIT); 958114878Sjulian if (msg == NULL) 959114878Sjulian return; 960114878Sjulian 961114878Sjulian ep = (ng_hci_lp_discon_req_ep *) (msg->data); 962114878Sjulian ep->con_handle = con->con_handle; 963114878Sjulian ep->reason = 0x13; /* User Ended Connection */ 964114878Sjulian 965128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0); 966114878Sjulian} /* ng_l2cap_process_discon_timeout */ 967114878Sjulian 968