1878ed226SJulian Elischer /* 2878ed226SJulian Elischer * ng_l2cap_ulpi.c 3c398230bSWarner Losh */ 4c398230bSWarner Losh 5c398230bSWarner Losh /*- 6878ed226SJulian Elischer * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 7878ed226SJulian Elischer * All rights reserved. 8878ed226SJulian Elischer * 9878ed226SJulian Elischer * Redistribution and use in source and binary forms, with or without 10878ed226SJulian Elischer * modification, are permitted provided that the following conditions 11878ed226SJulian Elischer * are met: 12878ed226SJulian Elischer * 1. Redistributions of source code must retain the above copyright 13878ed226SJulian Elischer * notice, this list of conditions and the following disclaimer. 14878ed226SJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 15878ed226SJulian Elischer * notice, this list of conditions and the following disclaimer in the 16878ed226SJulian Elischer * documentation and/or other materials provided with the distribution. 17878ed226SJulian Elischer * 18878ed226SJulian Elischer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19878ed226SJulian Elischer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20878ed226SJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21878ed226SJulian Elischer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22878ed226SJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23878ed226SJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24878ed226SJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25878ed226SJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26878ed226SJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27878ed226SJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28878ed226SJulian Elischer * SUCH DAMAGE. 29878ed226SJulian Elischer * 30f2bb1caeSJulian Elischer * $Id: ng_l2cap_ulpi.c,v 1.1 2002/11/24 19:47:06 max Exp $ 31878ed226SJulian Elischer * $FreeBSD$ 32878ed226SJulian Elischer */ 33878ed226SJulian Elischer 34878ed226SJulian Elischer #include <sys/param.h> 35878ed226SJulian Elischer #include <sys/systm.h> 36878ed226SJulian Elischer #include <sys/kernel.h> 37878ed226SJulian Elischer #include <sys/endian.h> 38878ed226SJulian Elischer #include <sys/malloc.h> 39878ed226SJulian Elischer #include <sys/mbuf.h> 40878ed226SJulian Elischer #include <sys/queue.h> 41878ed226SJulian Elischer #include <netgraph/ng_message.h> 42878ed226SJulian Elischer #include <netgraph/netgraph.h> 43b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_hci.h> 44b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_l2cap.h> 45b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_var.h> 46b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h> 47b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h> 48b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h> 49b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h> 50b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h> 51878ed226SJulian Elischer 52878ed226SJulian Elischer /****************************************************************************** 53878ed226SJulian Elischer ****************************************************************************** 54878ed226SJulian Elischer ** Upper Layer Protocol Interface module 55878ed226SJulian Elischer ****************************************************************************** 56878ed226SJulian Elischer ******************************************************************************/ 57878ed226SJulian Elischer 58878ed226SJulian Elischer /* 59878ed226SJulian Elischer * Process L2CA_Connect request from the upper layer protocol. 60878ed226SJulian Elischer */ 61878ed226SJulian Elischer 62878ed226SJulian Elischer int 63878ed226SJulian Elischer ng_l2cap_l2ca_con_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 64878ed226SJulian Elischer { 65878ed226SJulian Elischer ng_l2cap_l2ca_con_ip *ip = NULL; 66878ed226SJulian Elischer ng_l2cap_con_p con = NULL; 67878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL; 68878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 69878ed226SJulian Elischer int error = 0; 70878ed226SJulian Elischer 71878ed226SJulian Elischer /* Check message */ 72878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) { 73878ed226SJulian Elischer NG_L2CAP_ALERT( 74878ed226SJulian Elischer "%s: %s - invalid L2CA_Connect request message size, size=%d\n", 75878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), 76878ed226SJulian Elischer msg->header.arglen); 77878ed226SJulian Elischer error = EMSGSIZE; 78878ed226SJulian Elischer goto out; 79878ed226SJulian Elischer } 80878ed226SJulian Elischer 81878ed226SJulian Elischer ip = (ng_l2cap_l2ca_con_ip *)(msg->data); 82878ed226SJulian Elischer 83878ed226SJulian Elischer /* Check if we have connection to the remote unit */ 84fbc48c2bSTakanori Watanabe con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype); 85878ed226SJulian Elischer if (con == NULL) { 86878ed226SJulian Elischer /* Submit LP_ConnectReq to the lower layer */ 87fbc48c2bSTakanori Watanabe error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype); 88878ed226SJulian Elischer if (error != 0) { 89878ed226SJulian Elischer NG_L2CAP_ERR( 90878ed226SJulian Elischer "%s: %s - unable to send LP_ConnectReq message, error=%d\n", 91878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), error); 92878ed226SJulian Elischer goto out; 93878ed226SJulian Elischer } 94878ed226SJulian Elischer 95878ed226SJulian Elischer /* This should not fail */ 96fbc48c2bSTakanori Watanabe con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype); 97878ed226SJulian Elischer KASSERT((con != NULL), 98878ed226SJulian Elischer ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node))); 99878ed226SJulian Elischer } 100878ed226SJulian Elischer 101878ed226SJulian Elischer /* 102878ed226SJulian Elischer * Create new empty channel descriptor. In case of any failure do 103878ed226SJulian Elischer * not touch connection descriptor. 104878ed226SJulian Elischer */ 105878ed226SJulian Elischer 106fbc48c2bSTakanori Watanabe ch = ng_l2cap_new_chan(l2cap, con, ip->psm, ip->idtype); 107878ed226SJulian Elischer if (ch == NULL) { 108878ed226SJulian Elischer error = ENOMEM; 109878ed226SJulian Elischer goto out; 110878ed226SJulian Elischer } 111878ed226SJulian Elischer 112878ed226SJulian Elischer /* Now create L2CAP_ConnectReq command */ 113878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(con), 114878ed226SJulian Elischer NG_L2CAP_CON_REQ, msg->header.token); 115878ed226SJulian Elischer if (cmd == NULL) { 116878ed226SJulian Elischer ng_l2cap_free_chan(ch); 117878ed226SJulian Elischer error = ENOMEM; 118878ed226SJulian Elischer goto out; 119878ed226SJulian Elischer } 120878ed226SJulian Elischer 121878ed226SJulian Elischer if (cmd->ident == NG_L2CAP_NULL_IDENT) { 122878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 123878ed226SJulian Elischer ng_l2cap_free_chan(ch); 124878ed226SJulian Elischer error = EIO; 125878ed226SJulian Elischer goto out; 126878ed226SJulian Elischer } 127878ed226SJulian Elischer 128878ed226SJulian Elischer /* Create L2CAP command packet */ 129fbc48c2bSTakanori Watanabe if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){ 130fbc48c2bSTakanori Watanabe _ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_ATT_CID, 131fbc48c2bSTakanori Watanabe NG_L2CAP_ATT_CID, 0, 0); 132fbc48c2bSTakanori Watanabe cmd->aux->m_flags |= M_PROTO2; 133fbc48c2bSTakanori Watanabe }else{ 134878ed226SJulian Elischer _ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid); 135fbc48c2bSTakanori Watanabe } 136878ed226SJulian Elischer if (cmd->aux == NULL) { 137878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 138878ed226SJulian Elischer ng_l2cap_free_chan(ch); 139878ed226SJulian Elischer error = ENOBUFS; 140878ed226SJulian Elischer goto out; 141878ed226SJulian Elischer } 142878ed226SJulian Elischer 143878ed226SJulian Elischer ch->state = NG_L2CAP_W4_L2CAP_CON_RSP; 144878ed226SJulian Elischer 145878ed226SJulian Elischer /* Link command to the queue */ 146878ed226SJulian Elischer ng_l2cap_link_cmd(ch->con, cmd); 147878ed226SJulian Elischer ng_l2cap_lp_deliver(ch->con); 148878ed226SJulian Elischer out: 149878ed226SJulian Elischer return (error); 150878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_req */ 151878ed226SJulian Elischer 152878ed226SJulian Elischer /* 153878ed226SJulian Elischer * Send L2CA_Connect response to the upper layer protocol. 154878ed226SJulian Elischer */ 155878ed226SJulian Elischer 156878ed226SJulian Elischer int 157878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result, 158878ed226SJulian Elischer u_int16_t status) 159878ed226SJulian Elischer { 160878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 161878ed226SJulian Elischer struct ng_mesg *msg = NULL; 162878ed226SJulian Elischer ng_l2cap_l2ca_con_op *op = NULL; 163878ed226SJulian Elischer int error = 0; 164878ed226SJulian Elischer 165878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 166878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 167878ed226SJulian Elischer NG_L2CAP_ERR( 168878ed226SJulian Elischer "%s: %s - unable to send L2CA_Connect response message. " \ 169878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 170878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 171878ed226SJulian Elischer 172878ed226SJulian Elischer return (ENOTCONN); 173878ed226SJulian Elischer } 174878ed226SJulian Elischer 175878ed226SJulian Elischer /* Create and send L2CA_Connect response message */ 176878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON, 177878ed226SJulian Elischer sizeof(*op), M_NOWAIT); 178878ed226SJulian Elischer if (msg == NULL) 179878ed226SJulian Elischer error = ENOMEM; 180878ed226SJulian Elischer else { 181878ed226SJulian Elischer msg->header.token = token; 182878ed226SJulian Elischer msg->header.flags |= NGF_RESP; 183878ed226SJulian Elischer 184878ed226SJulian Elischer op = (ng_l2cap_l2ca_con_op *)(msg->data); 185878ed226SJulian Elischer 186878ed226SJulian Elischer /* 187878ed226SJulian Elischer * XXX Spec. says we should only populate LCID when result == 0 188878ed226SJulian Elischer * What about PENDING? What the heck, for now always populate 189878ed226SJulian Elischer * LCID :) 190878ed226SJulian Elischer */ 191fbc48c2bSTakanori Watanabe if(ch->scid == NG_L2CAP_ATT_CID){ 192fbc48c2bSTakanori Watanabe op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT; 193fbc48c2bSTakanori Watanabe op->lcid = ch->con->con_handle; 194fbc48c2bSTakanori Watanabe }else{ 195fbc48c2bSTakanori Watanabe op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)? 196fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR : 197fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_LE; 198878ed226SJulian Elischer op->lcid = ch->scid; 199fbc48c2bSTakanori Watanabe } 200fbc48c2bSTakanori Watanabe 201878ed226SJulian Elischer op->result = result; 202878ed226SJulian Elischer op->status = status; 203878ed226SJulian Elischer 2044ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 205878ed226SJulian Elischer } 206878ed226SJulian Elischer 207878ed226SJulian Elischer return (error); 208878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_rsp */ 209878ed226SJulian Elischer 210878ed226SJulian Elischer /* 211878ed226SJulian Elischer * Process L2CA_ConnectRsp request from the upper layer protocol. 212878ed226SJulian Elischer */ 213878ed226SJulian Elischer 214878ed226SJulian Elischer int 215878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 216878ed226SJulian Elischer { 217878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_ip *ip = NULL; 218878ed226SJulian Elischer ng_l2cap_con_p con = NULL; 219878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL; 220878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 221878ed226SJulian Elischer u_int16_t dcid; 222878ed226SJulian Elischer int error = 0; 223878ed226SJulian Elischer 224878ed226SJulian Elischer /* Check message */ 225878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) { 226878ed226SJulian Elischer NG_L2CAP_ALERT( 227878ed226SJulian Elischer "%s: %s - invalid L2CA_ConnectRsp request message size, size=%d\n", 228878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), 229878ed226SJulian Elischer msg->header.arglen); 230878ed226SJulian Elischer error = EMSGSIZE; 231878ed226SJulian Elischer goto out; 232878ed226SJulian Elischer } 233878ed226SJulian Elischer 234878ed226SJulian Elischer ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data); 235878ed226SJulian Elischer 236878ed226SJulian Elischer /* Check if we have this channel */ 237fbc48c2bSTakanori Watanabe if(ip->lcid != NG_L2CAP_ATT_CID){ 238fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid 239fbc48c2bSTakanori Watanabe ,(ip->linktype == NG_HCI_LINK_ACL)? 240fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR: 241fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_LE); 242fbc48c2bSTakanori Watanabe }else{ 243fbc48c2bSTakanori Watanabe // For now not support on ATT device. 244fbc48c2bSTakanori Watanabe ch = NULL; 245fbc48c2bSTakanori Watanabe } 246878ed226SJulian Elischer if (ch == NULL) { 247878ed226SJulian Elischer NG_L2CAP_ALERT( 248878ed226SJulian Elischer "%s: %s - unexpected L2CA_ConnectRsp request message. " \ 249878ed226SJulian Elischer "Channel does not exist, lcid=%d\n", 250878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 251878ed226SJulian Elischer error = ENOENT; 252878ed226SJulian Elischer goto out; 253878ed226SJulian Elischer } 254878ed226SJulian Elischer 255878ed226SJulian Elischer /* Check channel state */ 256878ed226SJulian Elischer if (ch->state != NG_L2CAP_W4_L2CA_CON_RSP) { 257878ed226SJulian Elischer NG_L2CAP_ERR( 258878ed226SJulian Elischer "%s: %s - unexpected L2CA_ConnectRsp request message. " \ 259878ed226SJulian Elischer "Invalid channel state, state=%d, lcid=%d\n", 260878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->state, 261878ed226SJulian Elischer ip->lcid); 262878ed226SJulian Elischer error = EINVAL; 263878ed226SJulian Elischer goto out; 264878ed226SJulian Elischer } 265878ed226SJulian Elischer 266878ed226SJulian Elischer dcid = ch->dcid; 267878ed226SJulian Elischer con = ch->con; 268878ed226SJulian Elischer 269878ed226SJulian Elischer /* 270878ed226SJulian Elischer * Now we are pretty much sure it is our response. So create and send 271878ed226SJulian Elischer * L2CAP_ConnectRsp message to our peer. 272878ed226SJulian Elischer */ 273878ed226SJulian Elischer 274878ed226SJulian Elischer if (ch->ident != ip->ident) 275878ed226SJulian Elischer NG_L2CAP_WARN( 276878ed226SJulian Elischer "%s: %s - channel ident and response ident do not match, scid=%d, ident=%d. " \ 277878ed226SJulian Elischer "Will use response ident=%d\n", 278878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->scid, 279878ed226SJulian Elischer ch->ident, ip->ident); 280878ed226SJulian Elischer 281878ed226SJulian Elischer /* Check result */ 282878ed226SJulian Elischer switch (ip->result) { 283878ed226SJulian Elischer case NG_L2CAP_SUCCESS: 284fbc48c2bSTakanori Watanabe ch->state = (ch->scid == NG_L2CAP_ATT_CID)? 285fbc48c2bSTakanori Watanabe NG_L2CAP_OPEN : NG_L2CAP_CONFIG; 286878ed226SJulian Elischer ch->cfg_state = 0; 287878ed226SJulian Elischer break; 288878ed226SJulian Elischer 289878ed226SJulian Elischer case NG_L2CAP_PENDING: 290878ed226SJulian Elischer break; 291878ed226SJulian Elischer 292878ed226SJulian Elischer default: 293878ed226SJulian Elischer ng_l2cap_free_chan(ch); 294878ed226SJulian Elischer ch = NULL; 295878ed226SJulian Elischer break; 296878ed226SJulian Elischer } 297878ed226SJulian Elischer 298878ed226SJulian Elischer /* Create L2CAP command */ 299878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(con, ch, ip->ident, NG_L2CAP_CON_RSP, 300878ed226SJulian Elischer msg->header.token); 301878ed226SJulian Elischer if (cmd == NULL) { 302878ed226SJulian Elischer if (ch != NULL) 303878ed226SJulian Elischer ng_l2cap_free_chan(ch); 304878ed226SJulian Elischer 305878ed226SJulian Elischer error = ENOMEM; 306878ed226SJulian Elischer goto out; 307878ed226SJulian Elischer } 308878ed226SJulian Elischer 309878ed226SJulian Elischer _ng_l2cap_con_rsp(cmd->aux, cmd->ident, ip->lcid, dcid, 310878ed226SJulian Elischer ip->result, ip->status); 311878ed226SJulian Elischer if (cmd->aux == NULL) { 312878ed226SJulian Elischer if (ch != NULL) 313878ed226SJulian Elischer ng_l2cap_free_chan(ch); 314878ed226SJulian Elischer 315878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 316878ed226SJulian Elischer error = ENOBUFS; 317878ed226SJulian Elischer goto out; 318878ed226SJulian Elischer } 319878ed226SJulian Elischer 320878ed226SJulian Elischer /* Link command to the queue */ 321878ed226SJulian Elischer ng_l2cap_link_cmd(con, cmd); 322878ed226SJulian Elischer ng_l2cap_lp_deliver(con); 323878ed226SJulian Elischer out: 324878ed226SJulian Elischer return (error); 325878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_rsp_req */ 326878ed226SJulian Elischer 327878ed226SJulian Elischer /* 328878ed226SJulian Elischer * Send L2CAP_ConnectRsp response to the upper layer 329878ed226SJulian Elischer */ 330878ed226SJulian Elischer 331878ed226SJulian Elischer int 332878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 333878ed226SJulian Elischer { 334878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 335878ed226SJulian Elischer struct ng_mesg *msg = NULL; 336878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_op *op = NULL; 337878ed226SJulian Elischer int error = 0; 338878ed226SJulian Elischer 339878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 340878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 341878ed226SJulian Elischer NG_L2CAP_ERR( 342878ed226SJulian Elischer "%s: %s - unable to send L2CA_ConnectRsp response message. " \ 343878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 344878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 345878ed226SJulian Elischer 346878ed226SJulian Elischer return (ENOTCONN); 347878ed226SJulian Elischer } 348878ed226SJulian Elischer 349878ed226SJulian Elischer /* Create and send L2CA_ConnectRsp response message */ 350878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_RSP, 351878ed226SJulian Elischer sizeof(*op), M_NOWAIT); 352878ed226SJulian Elischer if (msg == NULL) 353878ed226SJulian Elischer error = ENOMEM; 354878ed226SJulian Elischer else { 355878ed226SJulian Elischer msg->header.token = token; 356878ed226SJulian Elischer msg->header.flags |= NGF_RESP; 357878ed226SJulian Elischer 358878ed226SJulian Elischer op = (ng_l2cap_l2ca_con_rsp_op *)(msg->data); 359878ed226SJulian Elischer op->result = result; 360878ed226SJulian Elischer 3614ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 362878ed226SJulian Elischer } 363878ed226SJulian Elischer 364878ed226SJulian Elischer return (error); 365878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_rsp_rsp */ 366878ed226SJulian Elischer 367878ed226SJulian Elischer /* 368878ed226SJulian Elischer * Send L2CA_ConnectInd message to the upper layer protocol. 369878ed226SJulian Elischer */ 370878ed226SJulian Elischer 371878ed226SJulian Elischer int 372878ed226SJulian Elischer ng_l2cap_l2ca_con_ind(ng_l2cap_chan_p ch) 373878ed226SJulian Elischer { 374878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 375878ed226SJulian Elischer struct ng_mesg *msg = NULL; 376878ed226SJulian Elischer ng_l2cap_l2ca_con_ind_ip *ip = NULL; 377878ed226SJulian Elischer int error = 0; 378878ed226SJulian Elischer 379878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 380878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 381878ed226SJulian Elischer NG_L2CAP_ERR( 382878ed226SJulian Elischer "%s: %s - unable to send L2CA_ConnectInd message. " \ 383878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 384878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 385878ed226SJulian Elischer 386878ed226SJulian Elischer return (ENOTCONN); 387878ed226SJulian Elischer } 388878ed226SJulian Elischer 389878ed226SJulian Elischer /* Create and send L2CA_ConnectInd message */ 390878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_IND, 391878ed226SJulian Elischer sizeof(*ip), M_NOWAIT); 392878ed226SJulian Elischer if (msg == NULL) 393878ed226SJulian Elischer error = ENOMEM; 394878ed226SJulian Elischer else { 395878ed226SJulian Elischer ip = (ng_l2cap_l2ca_con_ind_ip *)(msg->data); 396878ed226SJulian Elischer 397878ed226SJulian Elischer bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr)); 398878ed226SJulian Elischer ip->lcid = ch->scid; 399878ed226SJulian Elischer ip->psm = ch->psm; 400878ed226SJulian Elischer ip->ident = ch->ident; 401*99043514STakanori Watanabe ip->linktype = ch->con->linktype; 4024ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 403878ed226SJulian Elischer } 404878ed226SJulian Elischer 405878ed226SJulian Elischer return (error); 406878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_ind */ 407878ed226SJulian Elischer 408878ed226SJulian Elischer /* 409878ed226SJulian Elischer * Process L2CA_Config request from the upper layer protocol 410878ed226SJulian Elischer */ 411878ed226SJulian Elischer 412878ed226SJulian Elischer int 413878ed226SJulian Elischer ng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 414878ed226SJulian Elischer { 415878ed226SJulian Elischer ng_l2cap_l2ca_cfg_ip *ip = NULL; 416878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL; 417878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 418878ed226SJulian Elischer struct mbuf *opt = NULL; 419878ed226SJulian Elischer u_int16_t *mtu = NULL, *flush_timo = NULL; 420878ed226SJulian Elischer ng_l2cap_flow_p flow = NULL; 421878ed226SJulian Elischer int error = 0; 422878ed226SJulian Elischer 423878ed226SJulian Elischer /* Check message */ 424878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) { 425878ed226SJulian Elischer NG_L2CAP_ALERT( 426878ed226SJulian Elischer "%s: %s - Invalid L2CA_Config request message size, size=%d\n", 427878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), 428878ed226SJulian Elischer msg->header.arglen); 429878ed226SJulian Elischer error = EMSGSIZE; 430878ed226SJulian Elischer goto out; 431878ed226SJulian Elischer } 432878ed226SJulian Elischer 433878ed226SJulian Elischer ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data); 434878ed226SJulian Elischer 435878ed226SJulian Elischer /* Check if we have this channel */ 436fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, NG_L2CAP_L2CA_IDTYPE_BREDR); 437878ed226SJulian Elischer if (ch == NULL) { 438878ed226SJulian Elischer NG_L2CAP_ERR( 439878ed226SJulian Elischer "%s: %s - unexpected L2CA_Config request message. " \ 440878ed226SJulian Elischer "Channel does not exist, lcid=%d\n", 441878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 442878ed226SJulian Elischer error = ENOENT; 443878ed226SJulian Elischer goto out; 444878ed226SJulian Elischer } 445878ed226SJulian Elischer 446878ed226SJulian Elischer /* Check channel state */ 447878ed226SJulian Elischer if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG) { 448878ed226SJulian Elischer NG_L2CAP_ERR( 449878ed226SJulian Elischer "%s: %s - unexpected L2CA_Config request message. " \ 450878ed226SJulian Elischer "Invalid channel state, state=%d, lcid=%d\n", 451878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->state, 452878ed226SJulian Elischer ch->scid); 453878ed226SJulian Elischer error = EINVAL; 454878ed226SJulian Elischer goto out; 455878ed226SJulian Elischer } 456878ed226SJulian Elischer 457878ed226SJulian Elischer /* Set requested channel configuration options */ 458878ed226SJulian Elischer ch->imtu = ip->imtu; 459878ed226SJulian Elischer bcopy(&ip->oflow, &ch->oflow, sizeof(ch->oflow)); 460878ed226SJulian Elischer ch->flush_timo = ip->flush_timo; 461878ed226SJulian Elischer ch->link_timo = ip->link_timo; 462878ed226SJulian Elischer 463878ed226SJulian Elischer /* Compare channel settings with defaults */ 464878ed226SJulian Elischer if (ch->imtu != NG_L2CAP_MTU_DEFAULT) 465878ed226SJulian Elischer mtu = &ch->imtu; 466878ed226SJulian Elischer if (ch->flush_timo != NG_L2CAP_FLUSH_TIMO_DEFAULT) 467878ed226SJulian Elischer flush_timo = &ch->flush_timo; 468878ed226SJulian Elischer if (bcmp(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)) != 0) 469878ed226SJulian Elischer flow = &ch->oflow; 470878ed226SJulian Elischer 471878ed226SJulian Elischer /* Create configuration options */ 472878ed226SJulian Elischer _ng_l2cap_build_cfg_options(opt, mtu, flush_timo, flow); 473878ed226SJulian Elischer if (opt == NULL) { 474878ed226SJulian Elischer error = ENOBUFS; 475878ed226SJulian Elischer goto out; 476878ed226SJulian Elischer } 477878ed226SJulian Elischer 478878ed226SJulian Elischer /* Create L2CAP command descriptor */ 479878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con), 480878ed226SJulian Elischer NG_L2CAP_CFG_REQ, msg->header.token); 481878ed226SJulian Elischer if (cmd == NULL) { 482878ed226SJulian Elischer NG_FREE_M(opt); 483878ed226SJulian Elischer error = ENOMEM; 484878ed226SJulian Elischer goto out; 485878ed226SJulian Elischer } 486878ed226SJulian Elischer 487878ed226SJulian Elischer if (cmd->ident == NG_L2CAP_NULL_IDENT) { 488878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 489878ed226SJulian Elischer NG_FREE_M(opt); 490878ed226SJulian Elischer error = EIO; 491878ed226SJulian Elischer goto out; 492878ed226SJulian Elischer } 493878ed226SJulian Elischer 494878ed226SJulian Elischer /* Create L2CAP command packet */ 495878ed226SJulian Elischer _ng_l2cap_cfg_req(cmd->aux, cmd->ident, ch->dcid, 0, opt); 496878ed226SJulian Elischer if (cmd->aux == NULL) { 497878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 498878ed226SJulian Elischer error = ENOBUFS; 499878ed226SJulian Elischer goto out; 500878ed226SJulian Elischer } 501878ed226SJulian Elischer 502878ed226SJulian Elischer /* Adjust channel state for re-configuration */ 503878ed226SJulian Elischer if (ch->state == NG_L2CAP_OPEN) { 504fbc48c2bSTakanori Watanabe ch->state = (ch->scid == NG_L2CAP_ATT_CID)? 505fbc48c2bSTakanori Watanabe NG_L2CAP_OPEN : NG_L2CAP_CONFIG; 506878ed226SJulian Elischer ch->cfg_state = 0; 507878ed226SJulian Elischer } 508878ed226SJulian Elischer 509878ed226SJulian Elischer /* Link command to the queue */ 510878ed226SJulian Elischer ng_l2cap_link_cmd(ch->con, cmd); 511878ed226SJulian Elischer ng_l2cap_lp_deliver(ch->con); 512878ed226SJulian Elischer out: 513878ed226SJulian Elischer return (error); 514878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_req */ 515878ed226SJulian Elischer 516878ed226SJulian Elischer /* 517878ed226SJulian Elischer * Send L2CA_Config response to the upper layer protocol 518878ed226SJulian Elischer */ 519878ed226SJulian Elischer 520878ed226SJulian Elischer int 521878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 522878ed226SJulian Elischer { 523878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 524878ed226SJulian Elischer struct ng_mesg *msg = NULL; 525878ed226SJulian Elischer ng_l2cap_l2ca_cfg_op *op = NULL; 526878ed226SJulian Elischer int error = 0; 527878ed226SJulian Elischer 528878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 529878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 530878ed226SJulian Elischer NG_L2CAP_ERR( 531878ed226SJulian Elischer "%s: %s - unable to send L2CA_Config response message. " \ 532878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 533878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 534878ed226SJulian Elischer 535878ed226SJulian Elischer return (ENOTCONN); 536878ed226SJulian Elischer } 537878ed226SJulian Elischer 538878ed226SJulian Elischer /* Create and send L2CA_Config response message */ 539878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG, 540878ed226SJulian Elischer sizeof(*op), M_NOWAIT); 541878ed226SJulian Elischer if (msg == NULL) 542878ed226SJulian Elischer error = ENOMEM; 543878ed226SJulian Elischer else { 544878ed226SJulian Elischer msg->header.token = token; 545878ed226SJulian Elischer msg->header.flags |= NGF_RESP; 546878ed226SJulian Elischer 547878ed226SJulian Elischer op = (ng_l2cap_l2ca_cfg_op *)(msg->data); 548878ed226SJulian Elischer op->result = result; 549878ed226SJulian Elischer op->imtu = ch->imtu; 550878ed226SJulian Elischer bcopy(&ch->oflow, &op->oflow, sizeof(op->oflow)); 551878ed226SJulian Elischer op->flush_timo = ch->flush_timo; 552878ed226SJulian Elischer 5534ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 554878ed226SJulian Elischer 555878ed226SJulian Elischer if (error == 0 && result == NG_L2CAP_SUCCESS) { 556878ed226SJulian Elischer ch->cfg_state |= NG_L2CAP_CFG_IN; 557878ed226SJulian Elischer 558878ed226SJulian Elischer if (ch->cfg_state == NG_L2CAP_CFG_BOTH) 559878ed226SJulian Elischer ch->state = NG_L2CAP_OPEN; 560878ed226SJulian Elischer } 561878ed226SJulian Elischer } 562878ed226SJulian Elischer 563878ed226SJulian Elischer return (error); 564878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_rsp */ 565878ed226SJulian Elischer 566878ed226SJulian Elischer /* 567878ed226SJulian Elischer * Process L2CA_ConfigRsp request from the upper layer protocol 568878ed226SJulian Elischer * 569878ed226SJulian Elischer * XXX XXX XXX 570878ed226SJulian Elischer * 571878ed226SJulian Elischer * NOTE: The Bluetooth specification says that Configuration_Response 572878ed226SJulian Elischer * (L2CA_ConfigRsp) should be used to issue response to configuration request 573878ed226SJulian Elischer * indication. The minor problem here is L2CAP command ident. We should use 574878ed226SJulian Elischer * ident from original L2CAP request to make sure our peer can match request 575878ed226SJulian Elischer * and response. For some reason Bluetooth specification does not include 576878ed226SJulian Elischer * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems 577878ed226SJulian Elischer * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident 578878ed226SJulian Elischer * field. So we should store last known L2CAP request command ident in channel. 579878ed226SJulian Elischer * Also it seems that upper layer can not reject configuration request, as 580878ed226SJulian Elischer * Configuration_Response message does not have status/reason field. 581878ed226SJulian Elischer */ 582878ed226SJulian Elischer 583878ed226SJulian Elischer int 584878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 585878ed226SJulian Elischer { 586878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp_ip *ip = NULL; 587878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL; 588878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 589878ed226SJulian Elischer struct mbuf *opt = NULL; 590878ed226SJulian Elischer u_int16_t *mtu = NULL; 591878ed226SJulian Elischer ng_l2cap_flow_p flow = NULL; 592878ed226SJulian Elischer int error = 0; 593878ed226SJulian Elischer 594878ed226SJulian Elischer /* Check message */ 595878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) { 596878ed226SJulian Elischer NG_L2CAP_ALERT( 597878ed226SJulian Elischer "%s: %s - invalid L2CA_ConfigRsp request message size, size=%d\n", 598878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), 599878ed226SJulian Elischer msg->header.arglen); 600878ed226SJulian Elischer error = EMSGSIZE; 601878ed226SJulian Elischer goto out; 602878ed226SJulian Elischer } 603878ed226SJulian Elischer 604878ed226SJulian Elischer ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data); 605878ed226SJulian Elischer 606878ed226SJulian Elischer /* Check if we have this channel */ 607fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, 608fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR); 609878ed226SJulian Elischer if (ch == NULL) { 610878ed226SJulian Elischer NG_L2CAP_ERR( 611878ed226SJulian Elischer "%s: %s - unexpected L2CA_ConfigRsp request message. " \ 612878ed226SJulian Elischer "Channel does not exist, lcid=%d\n", 613878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 614878ed226SJulian Elischer error = ENOENT; 615878ed226SJulian Elischer goto out; 616878ed226SJulian Elischer } 617878ed226SJulian Elischer 618878ed226SJulian Elischer /* Check channel state */ 619878ed226SJulian Elischer if (ch->state != NG_L2CAP_CONFIG) { 620878ed226SJulian Elischer NG_L2CAP_ERR( 621878ed226SJulian Elischer "%s: %s - unexpected L2CA_ConfigRsp request message. " \ 622878ed226SJulian Elischer "Invalid channel state, state=%d, lcid=%d\n", 623878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->state, 624878ed226SJulian Elischer ch->scid); 625878ed226SJulian Elischer error = EINVAL; 626878ed226SJulian Elischer goto out; 627878ed226SJulian Elischer } 628878ed226SJulian Elischer 629878ed226SJulian Elischer /* Set channel settings */ 630878ed226SJulian Elischer if (ip->omtu != ch->omtu) { 631878ed226SJulian Elischer ch->omtu = ip->omtu; 632878ed226SJulian Elischer mtu = &ch->omtu; 633878ed226SJulian Elischer } 634878ed226SJulian Elischer 635878ed226SJulian Elischer if (bcmp(&ip->iflow, &ch->iflow, sizeof(ch->iflow)) != 0) { 636878ed226SJulian Elischer bcopy(&ip->iflow, &ch->iflow, sizeof(ch->iflow)); 637878ed226SJulian Elischer flow = &ch->iflow; 638878ed226SJulian Elischer } 639878ed226SJulian Elischer 640878ed226SJulian Elischer if (mtu != NULL || flow != NULL) { 641878ed226SJulian Elischer _ng_l2cap_build_cfg_options(opt, mtu, NULL, flow); 642878ed226SJulian Elischer if (opt == NULL) { 643878ed226SJulian Elischer error = ENOBUFS; 644878ed226SJulian Elischer goto out; 645878ed226SJulian Elischer } 646878ed226SJulian Elischer } 647878ed226SJulian Elischer 648878ed226SJulian Elischer /* Create L2CAP command */ 649878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(ch->con, ch, ch->ident, NG_L2CAP_CFG_RSP, 650878ed226SJulian Elischer msg->header.token); 651878ed226SJulian Elischer if (cmd == NULL) { 652878ed226SJulian Elischer NG_FREE_M(opt); 653878ed226SJulian Elischer error = ENOMEM; 654878ed226SJulian Elischer goto out; 655878ed226SJulian Elischer } 656878ed226SJulian Elischer 657878ed226SJulian Elischer _ng_l2cap_cfg_rsp(cmd->aux,cmd->ident,ch->dcid,0,NG_L2CAP_SUCCESS,opt); 658878ed226SJulian Elischer if (cmd->aux == NULL) { 659878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 660878ed226SJulian Elischer error = ENOBUFS; 661878ed226SJulian Elischer goto out; 662878ed226SJulian Elischer } 663878ed226SJulian Elischer 664878ed226SJulian Elischer /* XXX FIXME - not here ??? */ 665878ed226SJulian Elischer ch->cfg_state |= NG_L2CAP_CFG_OUT; 666878ed226SJulian Elischer if (ch->cfg_state == NG_L2CAP_CFG_BOTH) 667878ed226SJulian Elischer ch->state = NG_L2CAP_OPEN; 668878ed226SJulian Elischer 669878ed226SJulian Elischer /* Link command to the queue */ 670878ed226SJulian Elischer ng_l2cap_link_cmd(ch->con, cmd); 671878ed226SJulian Elischer ng_l2cap_lp_deliver(ch->con); 672878ed226SJulian Elischer out: 673878ed226SJulian Elischer return (error); 674878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_rsp_req */ 675878ed226SJulian Elischer 676878ed226SJulian Elischer /* 677878ed226SJulian Elischer * Send L2CA_ConfigRsp response to the upper layer protocol 678878ed226SJulian Elischer */ 679878ed226SJulian Elischer 680878ed226SJulian Elischer int 681878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 682878ed226SJulian Elischer { 683878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 684878ed226SJulian Elischer struct ng_mesg *msg = NULL; 685878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp_op *op = NULL; 686878ed226SJulian Elischer int error = 0; 687878ed226SJulian Elischer 688878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 689878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 690878ed226SJulian Elischer NG_L2CAP_ERR( 691878ed226SJulian Elischer "%s: %s - unable to send L2CA_ConfigRsp response message. " \ 692878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 693878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 694878ed226SJulian Elischer 695878ed226SJulian Elischer return (ENOTCONN); 696878ed226SJulian Elischer } 697878ed226SJulian Elischer 698878ed226SJulian Elischer /* Create and send L2CA_ConfigRsp response message */ 699878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP, 700878ed226SJulian Elischer sizeof(*op), M_NOWAIT); 701878ed226SJulian Elischer if (msg == NULL) 702878ed226SJulian Elischer error = ENOMEM; 703878ed226SJulian Elischer else { 704878ed226SJulian Elischer msg->header.token = token; 705878ed226SJulian Elischer msg->header.flags |= NGF_RESP; 706878ed226SJulian Elischer 707878ed226SJulian Elischer op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data); 708878ed226SJulian Elischer op->result = result; 709878ed226SJulian Elischer 7104ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 711878ed226SJulian Elischer } 712878ed226SJulian Elischer 713878ed226SJulian Elischer return (error); 714878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_rsp_rsp */ 715878ed226SJulian Elischer 716878ed226SJulian Elischer /* 717878ed226SJulian Elischer * Send L2CA_ConfigInd message to the upper layer protocol 718878ed226SJulian Elischer * 719878ed226SJulian Elischer * XXX XXX XXX 720878ed226SJulian Elischer * 721878ed226SJulian Elischer * NOTE: The Bluetooth specification says that Configuration_Response 722878ed226SJulian Elischer * (L2CA_ConfigRsp) should be used to issue response to configuration request 723878ed226SJulian Elischer * indication. The minor problem here is L2CAP command ident. We should use 724878ed226SJulian Elischer * ident from original L2CAP request to make sure our peer can match request 725878ed226SJulian Elischer * and response. For some reason Bluetooth specification does not include 726878ed226SJulian Elischer * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems 727878ed226SJulian Elischer * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident 728878ed226SJulian Elischer * field. So we should store last known L2CAP request command ident in channel. 729878ed226SJulian Elischer * Also it seems that upper layer can not reject configuration request, as 730878ed226SJulian Elischer * Configuration_Response message does not have status/reason field. 731878ed226SJulian Elischer */ 732878ed226SJulian Elischer 733878ed226SJulian Elischer int 734878ed226SJulian Elischer ng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch) 735878ed226SJulian Elischer { 736878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 737878ed226SJulian Elischer struct ng_mesg *msg = NULL; 738878ed226SJulian Elischer ng_l2cap_l2ca_cfg_ind_ip *ip = NULL; 739878ed226SJulian Elischer int error = 0; 740878ed226SJulian Elischer 741878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 742878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 743878ed226SJulian Elischer NG_L2CAP_ERR( 744878ed226SJulian Elischer "%s: %s - Unable to send L2CA_ConfigInd message. " \ 745878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 746878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 747878ed226SJulian Elischer 748878ed226SJulian Elischer return (ENOTCONN); 749878ed226SJulian Elischer } 750878ed226SJulian Elischer 751878ed226SJulian Elischer /* Create and send L2CA_ConnectInd message */ 752878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_IND, 753878ed226SJulian Elischer sizeof(*ip), M_NOWAIT); 754878ed226SJulian Elischer if (msg == NULL) 755878ed226SJulian Elischer error = ENOMEM; 756878ed226SJulian Elischer else { 757878ed226SJulian Elischer ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data); 758878ed226SJulian Elischer ip->lcid = ch->scid; 759878ed226SJulian Elischer ip->omtu = ch->omtu; 760878ed226SJulian Elischer bcopy(&ch->iflow, &ip->iflow, sizeof(ip->iflow)); 761878ed226SJulian Elischer ip->flush_timo = ch->flush_timo; 762878ed226SJulian Elischer 7634ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 764878ed226SJulian Elischer } 765878ed226SJulian Elischer 766878ed226SJulian Elischer return (error); 767878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_ind */ 768878ed226SJulian Elischer 769878ed226SJulian Elischer /* 770878ed226SJulian Elischer * Process L2CA_Write event 771878ed226SJulian Elischer */ 772878ed226SJulian Elischer 773878ed226SJulian Elischer int 774878ed226SJulian Elischer ng_l2cap_l2ca_write_req(ng_l2cap_p l2cap, struct mbuf *m) 775878ed226SJulian Elischer { 776878ed226SJulian Elischer ng_l2cap_l2ca_hdr_t *l2ca_hdr = NULL; 777878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL; 778878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 779878ed226SJulian Elischer int error = 0; 780878ed226SJulian Elischer u_int32_t token = 0; 781878ed226SJulian Elischer 782878ed226SJulian Elischer /* Make sure we can access L2CA data packet header */ 783878ed226SJulian Elischer if (m->m_pkthdr.len < sizeof(*l2ca_hdr)) { 784878ed226SJulian Elischer NG_L2CAP_ERR( 785878ed226SJulian Elischer "%s: %s - L2CA Data packet too small, len=%d\n", 786878ed226SJulian Elischer __func__,NG_NODE_NAME(l2cap->node),m->m_pkthdr.len); 787878ed226SJulian Elischer error = EMSGSIZE; 788878ed226SJulian Elischer goto drop; 789878ed226SJulian Elischer } 790878ed226SJulian Elischer 791878ed226SJulian Elischer /* Get L2CA data packet header */ 792878ed226SJulian Elischer NG_L2CAP_M_PULLUP(m, sizeof(*l2ca_hdr)); 793878ed226SJulian Elischer if (m == NULL) 794878ed226SJulian Elischer return (ENOBUFS); 795878ed226SJulian Elischer 796878ed226SJulian Elischer l2ca_hdr = mtod(m, ng_l2cap_l2ca_hdr_t *); 797878ed226SJulian Elischer token = l2ca_hdr->token; 798878ed226SJulian Elischer m_adj(m, sizeof(*l2ca_hdr)); 799878ed226SJulian Elischer 800878ed226SJulian Elischer /* Verify payload size */ 801878ed226SJulian Elischer if (l2ca_hdr->length != m->m_pkthdr.len) { 802878ed226SJulian Elischer NG_L2CAP_ERR( 803878ed226SJulian Elischer "%s: %s - invalid L2CA Data packet. " \ 804878ed226SJulian Elischer "Payload length does not match, length=%d, len=%d\n", 805878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->length, 806878ed226SJulian Elischer m->m_pkthdr.len); 807878ed226SJulian Elischer error = EMSGSIZE; 808878ed226SJulian Elischer goto drop; 809878ed226SJulian Elischer } 810878ed226SJulian Elischer 811878ed226SJulian Elischer /* Check channel ID */ 812fbc48c2bSTakanori Watanabe if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){ 813fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID, 814fbc48c2bSTakanori Watanabe l2ca_hdr->lcid); 815fbc48c2bSTakanori Watanabe } else{ 816878ed226SJulian Elischer if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) { 817878ed226SJulian Elischer NG_L2CAP_ERR( 818878ed226SJulian Elischer "%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n", 819fbc48c2bSTakanori Watanabe __func__, NG_NODE_NAME(l2cap->node), 820fbc48c2bSTakanori Watanabe l2ca_hdr->lcid); 821878ed226SJulian Elischer error = EINVAL; 822878ed226SJulian Elischer goto drop; 823878ed226SJulian Elischer } 824878ed226SJulian Elischer 825878ed226SJulian Elischer /* Verify that we have the channel and make sure it is open */ 826fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid, 827fbc48c2bSTakanori Watanabe l2ca_hdr->idtype); 828fbc48c2bSTakanori Watanabe } 829fbc48c2bSTakanori Watanabe 830878ed226SJulian Elischer if (ch == NULL) { 831878ed226SJulian Elischer NG_L2CAP_ERR( 832878ed226SJulian Elischer "%s: %s - invalid L2CA Data packet. Channel does not exist, cid=%d\n", 833878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid); 834878ed226SJulian Elischer error = ENOENT; 835878ed226SJulian Elischer goto drop; 836878ed226SJulian Elischer } 837878ed226SJulian Elischer 838878ed226SJulian Elischer if (ch->state != NG_L2CAP_OPEN) { 839878ed226SJulian Elischer NG_L2CAP_ERR( 840878ed226SJulian Elischer "%s: %s - invalid L2CA Data packet. Invalid channel state, scid=%d, state=%d\n", 841878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->scid, 842878ed226SJulian Elischer ch->state); 843878ed226SJulian Elischer error = EHOSTDOWN; 844878ed226SJulian Elischer goto drop; /* XXX not always - re-configure */ 845878ed226SJulian Elischer } 846878ed226SJulian Elischer 847878ed226SJulian Elischer /* Create L2CAP command descriptor */ 848878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(ch->con, ch, 0, NGM_L2CAP_L2CA_WRITE, token); 849878ed226SJulian Elischer if (cmd == NULL) { 850878ed226SJulian Elischer error = ENOMEM; 851878ed226SJulian Elischer goto drop; 852878ed226SJulian Elischer } 853878ed226SJulian Elischer 854878ed226SJulian Elischer /* Attach data packet and link command to the queue */ 855878ed226SJulian Elischer cmd->aux = m; 856878ed226SJulian Elischer ng_l2cap_link_cmd(ch->con, cmd); 857878ed226SJulian Elischer ng_l2cap_lp_deliver(ch->con); 858878ed226SJulian Elischer 859878ed226SJulian Elischer return (error); 860878ed226SJulian Elischer drop: 861878ed226SJulian Elischer NG_FREE_M(m); 862878ed226SJulian Elischer 863878ed226SJulian Elischer return (error); 864878ed226SJulian Elischer } /* ng_l2cap_l2ca_write_req */ 865878ed226SJulian Elischer 866878ed226SJulian Elischer /* 867878ed226SJulian Elischer * Send L2CA_Write response 868878ed226SJulian Elischer */ 869878ed226SJulian Elischer 870878ed226SJulian Elischer int 871878ed226SJulian Elischer ng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result, 872878ed226SJulian Elischer u_int16_t length) 873878ed226SJulian Elischer { 874878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 875878ed226SJulian Elischer struct ng_mesg *msg = NULL; 876878ed226SJulian Elischer ng_l2cap_l2ca_write_op *op = NULL; 877878ed226SJulian Elischer int error = 0; 878878ed226SJulian Elischer 879878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 880878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 881878ed226SJulian Elischer NG_L2CAP_ERR( 882878ed226SJulian Elischer "%s: %s - unable to send L2CA_WriteRsp message. " \ 883878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 884878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 885878ed226SJulian Elischer 886878ed226SJulian Elischer return (ENOTCONN); 887878ed226SJulian Elischer } 888878ed226SJulian Elischer 889878ed226SJulian Elischer /* Create and send L2CA_WriteRsp message */ 890878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_WRITE, 891878ed226SJulian Elischer sizeof(*op), M_NOWAIT); 892878ed226SJulian Elischer if (msg == NULL) 893878ed226SJulian Elischer error = ENOMEM; 894878ed226SJulian Elischer else { 895878ed226SJulian Elischer msg->header.token = token; 896878ed226SJulian Elischer msg->header.flags |= NGF_RESP; 897878ed226SJulian Elischer 898878ed226SJulian Elischer op = (ng_l2cap_l2ca_write_op *)(msg->data); 899878ed226SJulian Elischer op->result = result; 900878ed226SJulian Elischer op->length = length; 901fbc48c2bSTakanori Watanabe if(ch->scid == NG_L2CAP_ATT_CID){ 902fbc48c2bSTakanori Watanabe op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT; 903fbc48c2bSTakanori Watanabe op->lcid = ch->con->con_handle; 904fbc48c2bSTakanori Watanabe }else{ 905fbc48c2bSTakanori Watanabe op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)? 906fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR : 907fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_LE; 908878ed226SJulian Elischer op->lcid = ch->scid; 909878ed226SJulian Elischer 910fbc48c2bSTakanori Watanabe } 9114ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 912878ed226SJulian Elischer } 913878ed226SJulian Elischer 914878ed226SJulian Elischer return (error); 915878ed226SJulian Elischer } /* ng_l2cap_l2ca_write_rsp */ 916878ed226SJulian Elischer 917878ed226SJulian Elischer /* 918878ed226SJulian Elischer * Receive packet from the lower layer protocol and send it to the upper 919878ed226SJulian Elischer * layer protocol (L2CAP_Read) 920878ed226SJulian Elischer */ 921878ed226SJulian Elischer 922878ed226SJulian Elischer int 923878ed226SJulian Elischer ng_l2cap_l2ca_receive(ng_l2cap_con_p con) 924878ed226SJulian Elischer { 925878ed226SJulian Elischer ng_l2cap_p l2cap = con->l2cap; 926878ed226SJulian Elischer ng_l2cap_hdr_t *hdr = NULL; 927878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL; 928878ed226SJulian Elischer int error = 0; 929fbc48c2bSTakanori Watanabe int idtype; 930fbc48c2bSTakanori Watanabe uint16_t *idp; 931878ed226SJulian Elischer 932878ed226SJulian Elischer NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr)); 933878ed226SJulian Elischer if (con->rx_pkt == NULL) 934878ed226SJulian Elischer return (ENOBUFS); 935878ed226SJulian Elischer 936878ed226SJulian Elischer hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *); 937878ed226SJulian Elischer 938878ed226SJulian Elischer /* Check channel */ 939fbc48c2bSTakanori Watanabe 940fbc48c2bSTakanori Watanabe if(hdr->dcid == NG_L2CAP_ATT_CID){ 941fbc48c2bSTakanori Watanabe idtype = NG_L2CAP_L2CA_IDTYPE_ATT; 942fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID, 943fbc48c2bSTakanori Watanabe con->con_handle); 944fbc48c2bSTakanori Watanabe /* 945fbc48c2bSTakanori Watanabe * Here,ATT channel is distinguished by 946fbc48c2bSTakanori Watanabe * connection handle 947fbc48c2bSTakanori Watanabe */ 948fbc48c2bSTakanori Watanabe hdr->dcid = con->con_handle; 949fbc48c2bSTakanori Watanabe }else{ 950fbc48c2bSTakanori Watanabe idtype = (con->linktype==NG_HCI_LINK_ACL)? 951fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR: 952fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_LE; 953fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, hdr->dcid, idtype); 954fbc48c2bSTakanori Watanabe } 955878ed226SJulian Elischer if (ch == NULL) { 956878ed226SJulian Elischer NG_L2CAP_ERR( 957fbc48c2bSTakanori Watanabe "%s: %s - unexpected L2CAP data packet. Channel does not exist, cid=%d, idtype=%d\n", 958fbc48c2bSTakanori Watanabe __func__, NG_NODE_NAME(l2cap->node), hdr->dcid, idtype); 959878ed226SJulian Elischer error = ENOENT; 960878ed226SJulian Elischer goto drop; 961878ed226SJulian Elischer } 962878ed226SJulian Elischer 963878ed226SJulian Elischer /* Check channel state */ 964878ed226SJulian Elischer if (ch->state != NG_L2CAP_OPEN) { 965878ed226SJulian Elischer NG_L2CAP_WARN( 966878ed226SJulian Elischer "%s: %s - unexpected L2CAP data packet. " \ 967878ed226SJulian Elischer "Invalid channel state, cid=%d, state=%d\n", 968878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->scid, 969878ed226SJulian Elischer ch->state); 970878ed226SJulian Elischer error = EHOSTDOWN; /* XXX not always - re-configuration */ 971878ed226SJulian Elischer goto drop; 972878ed226SJulian Elischer } 973878ed226SJulian Elischer 974878ed226SJulian Elischer /* Check payload size and channel's MTU */ 975878ed226SJulian Elischer if (hdr->length > ch->imtu) { 976878ed226SJulian Elischer NG_L2CAP_ERR( 977878ed226SJulian Elischer "%s: %s - invalid L2CAP data packet. " \ 978878ed226SJulian Elischer "Packet too big, length=%d, imtu=%d, cid=%d\n", 979878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), hdr->length, 980878ed226SJulian Elischer ch->imtu, ch->scid); 981878ed226SJulian Elischer error = EMSGSIZE; 982878ed226SJulian Elischer goto drop; 983878ed226SJulian Elischer } 984878ed226SJulian Elischer 985878ed226SJulian Elischer /* 986878ed226SJulian Elischer * If we got here then everything looks good and we can sent packet 987878ed226SJulian Elischer * to the upper layer protocol. 988878ed226SJulian Elischer */ 989878ed226SJulian Elischer 990878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 991878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 992878ed226SJulian Elischer NG_L2CAP_ERR( 993878ed226SJulian Elischer "%s: %s - unable to send L2CAP data packet. " \ 994878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 995878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 996878ed226SJulian Elischer error = ENOTCONN; 997878ed226SJulian Elischer goto drop; 998878ed226SJulian Elischer } 999fbc48c2bSTakanori Watanabe M_PREPEND(con->rx_pkt, sizeof(uint16_t), M_NOWAIT); 1000fbc48c2bSTakanori Watanabe if(con->rx_pkt == NULL) 1001fbc48c2bSTakanori Watanabe goto drop; 1002fbc48c2bSTakanori Watanabe idp = mtod(con->rx_pkt, uint16_t *); 1003fbc48c2bSTakanori Watanabe *idp = idtype; 1004878ed226SJulian Elischer 1005878ed226SJulian Elischer NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt); 1006878ed226SJulian Elischer con->rx_pkt = NULL; 1007878ed226SJulian Elischer drop: 1008878ed226SJulian Elischer NG_FREE_M(con->rx_pkt); /* checks for != NULL */ 1009878ed226SJulian Elischer 1010878ed226SJulian Elischer return (error); 1011878ed226SJulian Elischer } /* ng_l2cap_receive */ 1012878ed226SJulian Elischer 1013878ed226SJulian Elischer /* 1014878ed226SJulian Elischer * Receive connectioless (multicast) packet from the lower layer protocol and 1015878ed226SJulian Elischer * send it to the upper layer protocol 1016878ed226SJulian Elischer */ 1017878ed226SJulian Elischer 1018878ed226SJulian Elischer int 1019878ed226SJulian Elischer ng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con) 1020878ed226SJulian Elischer { 1021878ed226SJulian Elischer struct _clt_pkt { 1022878ed226SJulian Elischer ng_l2cap_hdr_t h; 1023878ed226SJulian Elischer ng_l2cap_clt_hdr_t c_h; 1024878ed226SJulian Elischer } __attribute__ ((packed)) *hdr = NULL; 1025878ed226SJulian Elischer ng_l2cap_p l2cap = con->l2cap; 1026878ed226SJulian Elischer int length, error = 0; 1027878ed226SJulian Elischer 1028878ed226SJulian Elischer NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr)); 1029878ed226SJulian Elischer if (con->rx_pkt == NULL) 1030878ed226SJulian Elischer return (ENOBUFS); 1031878ed226SJulian Elischer 1032878ed226SJulian Elischer hdr = mtod(con->rx_pkt, struct _clt_pkt *); 1033878ed226SJulian Elischer 1034878ed226SJulian Elischer /* Check packet */ 1035878ed226SJulian Elischer length = con->rx_pkt->m_pkthdr.len - sizeof(*hdr); 1036878ed226SJulian Elischer if (length < 0) { 1037878ed226SJulian Elischer NG_L2CAP_ERR( 1038878ed226SJulian Elischer "%s: %s - invalid L2CAP CLT data packet. Packet too small, length=%d\n", 1039878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), length); 1040878ed226SJulian Elischer error = EMSGSIZE; 1041878ed226SJulian Elischer goto drop; 1042878ed226SJulian Elischer } 1043878ed226SJulian Elischer 1044878ed226SJulian Elischer /* Check payload size against CLT MTU */ 1045878ed226SJulian Elischer if (length > NG_L2CAP_MTU_DEFAULT) { 1046878ed226SJulian Elischer NG_L2CAP_ERR( 1047878ed226SJulian Elischer "%s: %s - invalid L2CAP CLT data packet. Packet too big, length=%d, mtu=%d\n", 1048878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), length, 1049878ed226SJulian Elischer NG_L2CAP_MTU_DEFAULT); 1050878ed226SJulian Elischer error = EMSGSIZE; 1051878ed226SJulian Elischer goto drop; 1052878ed226SJulian Elischer } 1053878ed226SJulian Elischer 1054878ed226SJulian Elischer hdr->c_h.psm = le16toh(hdr->c_h.psm); 1055878ed226SJulian Elischer 1056878ed226SJulian Elischer /* 1057878ed226SJulian Elischer * If we got here then everything looks good and we can sent packet 1058878ed226SJulian Elischer * to the upper layer protocol. 1059878ed226SJulian Elischer */ 1060878ed226SJulian Elischer 1061878ed226SJulian Elischer /* Select upstream hook based on PSM */ 1062878ed226SJulian Elischer switch (hdr->c_h.psm) { 1063878ed226SJulian Elischer case NG_L2CAP_PSM_SDP: 1064878ed226SJulian Elischer if (l2cap->flags & NG_L2CAP_CLT_SDP_DISABLED) 1065878ed226SJulian Elischer goto drop; 1066878ed226SJulian Elischer break; 1067878ed226SJulian Elischer 1068878ed226SJulian Elischer case NG_L2CAP_PSM_RFCOMM: 1069878ed226SJulian Elischer if (l2cap->flags & NG_L2CAP_CLT_RFCOMM_DISABLED) 1070878ed226SJulian Elischer goto drop; 1071878ed226SJulian Elischer break; 1072878ed226SJulian Elischer 1073878ed226SJulian Elischer case NG_L2CAP_PSM_TCP: 1074878ed226SJulian Elischer if (l2cap->flags & NG_L2CAP_CLT_TCP_DISABLED) 1075878ed226SJulian Elischer goto drop; 1076878ed226SJulian Elischer break; 1077878ed226SJulian Elischer } 1078878ed226SJulian Elischer 1079878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 1080878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1081878ed226SJulian Elischer NG_L2CAP_ERR( 1082878ed226SJulian Elischer "%s: %s - unable to send L2CAP CLT data packet. " \ 1083878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 1084878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), hdr->c_h.psm); 1085878ed226SJulian Elischer error = ENOTCONN; 1086878ed226SJulian Elischer goto drop; 1087878ed226SJulian Elischer } 1088878ed226SJulian Elischer 1089878ed226SJulian Elischer NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt); 1090878ed226SJulian Elischer con->rx_pkt = NULL; 1091878ed226SJulian Elischer drop: 1092878ed226SJulian Elischer NG_FREE_M(con->rx_pkt); /* checks for != NULL */ 1093878ed226SJulian Elischer 1094878ed226SJulian Elischer return (error); 1095878ed226SJulian Elischer } /* ng_l2cap_l2ca_clt_receive */ 1096878ed226SJulian Elischer 1097878ed226SJulian Elischer /* 1098878ed226SJulian Elischer * Send L2CA_QoSViolationInd to the upper layer protocol 1099878ed226SJulian Elischer */ 1100878ed226SJulian Elischer 1101878ed226SJulian Elischer int 1102878ed226SJulian Elischer ng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch) 1103878ed226SJulian Elischer { 1104878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 1105878ed226SJulian Elischer struct ng_mesg *msg = NULL; 1106878ed226SJulian Elischer ng_l2cap_l2ca_qos_ind_ip *ip = NULL; 1107878ed226SJulian Elischer int error = 0; 1108878ed226SJulian Elischer 1109878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 1110878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1111878ed226SJulian Elischer NG_L2CAP_ERR( 1112878ed226SJulian Elischer "%s: %s - unable to send L2CA_QoSViolationInd message. " \ 1113878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 1114878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1115878ed226SJulian Elischer 1116878ed226SJulian Elischer return (ENOTCONN); 1117878ed226SJulian Elischer } 1118878ed226SJulian Elischer 1119878ed226SJulian Elischer /* Create and send L2CA_QoSViolationInd message */ 1120878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_QOS_IND, 1121878ed226SJulian Elischer sizeof(*ip), M_NOWAIT); 1122878ed226SJulian Elischer if (msg == NULL) 1123878ed226SJulian Elischer error = ENOMEM; 1124878ed226SJulian Elischer else { 1125878ed226SJulian Elischer ip = (ng_l2cap_l2ca_qos_ind_ip *)(msg->data); 1126878ed226SJulian Elischer bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr)); 11274ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1128878ed226SJulian Elischer } 1129878ed226SJulian Elischer 1130878ed226SJulian Elischer return (error); 1131878ed226SJulian Elischer } /* ng_l2cap_l2ca_qos_ind */ 1132878ed226SJulian Elischer 1133878ed226SJulian Elischer /* 1134878ed226SJulian Elischer * Process L2CA_Disconnect request from the upper layer protocol. 1135878ed226SJulian Elischer */ 1136878ed226SJulian Elischer 1137878ed226SJulian Elischer int 1138878ed226SJulian Elischer ng_l2cap_l2ca_discon_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1139878ed226SJulian Elischer { 1140878ed226SJulian Elischer ng_l2cap_l2ca_discon_ip *ip = NULL; 1141878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL; 1142878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 1143878ed226SJulian Elischer int error = 0; 1144878ed226SJulian Elischer 1145878ed226SJulian Elischer /* Check message */ 1146878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) { 1147878ed226SJulian Elischer NG_L2CAP_ALERT( 1148878ed226SJulian Elischer "%s: %s - invalid L2CA_Disconnect request message size, size=%d\n", 1149878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), 1150878ed226SJulian Elischer msg->header.arglen); 1151878ed226SJulian Elischer error = EMSGSIZE; 1152878ed226SJulian Elischer goto out; 1153878ed226SJulian Elischer } 1154878ed226SJulian Elischer 1155878ed226SJulian Elischer ip = (ng_l2cap_l2ca_discon_ip *)(msg->data); 1156878ed226SJulian Elischer 1157fbc48c2bSTakanori Watanabe 1158fbc48c2bSTakanori Watanabe if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){ 1159fbc48c2bSTakanori Watanabe /* Don't send Disconnect request on L2CAP Layer*/ 1160fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID, 1161fbc48c2bSTakanori Watanabe ip->lcid); 1162fbc48c2bSTakanori Watanabe 1163fbc48c2bSTakanori Watanabe if(ch != NULL){ 1164fbc48c2bSTakanori Watanabe ng_l2cap_free_chan(ch); 1165fbc48c2bSTakanori Watanabe }else{ 1166fbc48c2bSTakanori Watanabe NG_L2CAP_ERR( 1167fbc48c2bSTakanori Watanabe "%s: %s - unexpected L2CA_Disconnect request message. " \ 1168fbc48c2bSTakanori Watanabe "Channel does not exist, conhandle=%d\n", 1169fbc48c2bSTakanori Watanabe __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 1170fbc48c2bSTakanori Watanabe error = EINVAL; 1171fbc48c2bSTakanori Watanabe } 1172fbc48c2bSTakanori Watanabe goto out; 1173fbc48c2bSTakanori Watanabe }else{ 1174878ed226SJulian Elischer /* Check if we have this channel */ 1175fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, ip->idtype); 1176fbc48c2bSTakanori Watanabe } 1177878ed226SJulian Elischer if (ch == NULL) { 1178878ed226SJulian Elischer NG_L2CAP_ERR( 1179878ed226SJulian Elischer "%s: %s - unexpected L2CA_Disconnect request message. " \ 1180878ed226SJulian Elischer "Channel does not exist, lcid=%d\n", 1181878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 1182878ed226SJulian Elischer error = ENOENT; 1183878ed226SJulian Elischer goto out; 1184878ed226SJulian Elischer } 1185878ed226SJulian Elischer 1186878ed226SJulian Elischer /* Check channel state */ 1187878ed226SJulian Elischer if (ch->state != NG_L2CAP_CONFIG && ch->state != NG_L2CAP_OPEN && 1188878ed226SJulian Elischer ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) { 1189878ed226SJulian Elischer NG_L2CAP_ERR( 1190878ed226SJulian Elischer "%s: %s - unexpected L2CA_Disconnect request message. " \ 1191878ed226SJulian Elischer "Invalid channel state, state=%d, lcid=%d\n", 1192878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->state, 1193878ed226SJulian Elischer ch->scid); 1194878ed226SJulian Elischer error = EINVAL; 1195878ed226SJulian Elischer goto out; 1196878ed226SJulian Elischer } 1197878ed226SJulian Elischer 1198878ed226SJulian Elischer /* Create and send L2CAP_DisconReq message */ 1199878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con), 1200878ed226SJulian Elischer NG_L2CAP_DISCON_REQ, msg->header.token); 1201878ed226SJulian Elischer if (cmd == NULL) { 1202878ed226SJulian Elischer ng_l2cap_free_chan(ch); 1203878ed226SJulian Elischer error = ENOMEM; 1204878ed226SJulian Elischer goto out; 1205878ed226SJulian Elischer } 1206878ed226SJulian Elischer 1207878ed226SJulian Elischer if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1208878ed226SJulian Elischer ng_l2cap_free_chan(ch); 1209878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 1210878ed226SJulian Elischer error = EIO; 1211878ed226SJulian Elischer goto out; 1212878ed226SJulian Elischer } 1213878ed226SJulian Elischer 1214878ed226SJulian Elischer _ng_l2cap_discon_req(cmd->aux, cmd->ident, ch->dcid, ch->scid); 1215878ed226SJulian Elischer if (cmd->aux == NULL) { 1216878ed226SJulian Elischer ng_l2cap_free_chan(ch); 1217878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 1218878ed226SJulian Elischer error = ENOBUFS; 1219878ed226SJulian Elischer goto out; 1220878ed226SJulian Elischer } 1221878ed226SJulian Elischer 1222878ed226SJulian Elischer ch->state = NG_L2CAP_W4_L2CAP_DISCON_RSP; 1223878ed226SJulian Elischer 1224878ed226SJulian Elischer /* Link command to the queue */ 1225878ed226SJulian Elischer ng_l2cap_link_cmd(ch->con, cmd); 1226878ed226SJulian Elischer ng_l2cap_lp_deliver(ch->con); 1227878ed226SJulian Elischer out: 1228878ed226SJulian Elischer return (error); 1229878ed226SJulian Elischer } /* ng_l2cap_l2ca_discon_req */ 1230878ed226SJulian Elischer 1231878ed226SJulian Elischer /* 1232878ed226SJulian Elischer * Send L2CA_Disconnect response to the upper layer protocol 1233878ed226SJulian Elischer */ 1234878ed226SJulian Elischer 1235878ed226SJulian Elischer int 1236878ed226SJulian Elischer ng_l2cap_l2ca_discon_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 1237878ed226SJulian Elischer { 1238878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 1239878ed226SJulian Elischer struct ng_mesg *msg = NULL; 1240878ed226SJulian Elischer ng_l2cap_l2ca_discon_op *op = NULL; 1241878ed226SJulian Elischer int error = 0; 1242878ed226SJulian Elischer 1243878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 1244878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1245878ed226SJulian Elischer NG_L2CAP_ERR( 1246878ed226SJulian Elischer "%s: %s - unable to send L2CA_Disconnect response message. " \ 1247878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 1248878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1249878ed226SJulian Elischer 1250878ed226SJulian Elischer return (ENOTCONN); 1251878ed226SJulian Elischer } 1252878ed226SJulian Elischer 1253878ed226SJulian Elischer /* Create and send L2CA_Disconnect response message */ 1254878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON, 1255878ed226SJulian Elischer sizeof(*op), M_NOWAIT); 1256878ed226SJulian Elischer if (msg == NULL) 1257878ed226SJulian Elischer error = ENOMEM; 1258878ed226SJulian Elischer else { 1259878ed226SJulian Elischer msg->header.token = token; 1260878ed226SJulian Elischer msg->header.flags |= NGF_RESP; 1261878ed226SJulian Elischer 1262878ed226SJulian Elischer op = (ng_l2cap_l2ca_discon_op *)(msg->data); 1263878ed226SJulian Elischer op->result = result; 1264878ed226SJulian Elischer 12654ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1266878ed226SJulian Elischer } 1267878ed226SJulian Elischer 1268878ed226SJulian Elischer return (error); 1269878ed226SJulian Elischer } /* ng_l2cap_l2ca_discon_rsp */ 1270878ed226SJulian Elischer 1271878ed226SJulian Elischer /* 1272878ed226SJulian Elischer * Send L2CA_DisconnectInd message to the upper layer protocol. 1273878ed226SJulian Elischer */ 1274878ed226SJulian Elischer 1275878ed226SJulian Elischer int 1276878ed226SJulian Elischer ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch) 1277878ed226SJulian Elischer { 1278878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 1279878ed226SJulian Elischer struct ng_mesg *msg = NULL; 1280878ed226SJulian Elischer ng_l2cap_l2ca_discon_ind_ip *ip = NULL; 1281878ed226SJulian Elischer int error = 0; 1282878ed226SJulian Elischer 1283878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 1284878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1285878ed226SJulian Elischer NG_L2CAP_ERR( 1286878ed226SJulian Elischer "%s: %s - unable to send L2CA_DisconnectInd message. " \ 1287878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 1288878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1289878ed226SJulian Elischer 1290878ed226SJulian Elischer return (ENOTCONN); 1291878ed226SJulian Elischer } 1292878ed226SJulian Elischer 1293878ed226SJulian Elischer /* Create and send L2CA_DisconnectInd message */ 1294878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND, 1295878ed226SJulian Elischer sizeof(*ip), M_NOWAIT); 1296878ed226SJulian Elischer if (msg == NULL) 1297878ed226SJulian Elischer error = ENOMEM; 1298878ed226SJulian Elischer else { 1299878ed226SJulian Elischer ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data); 1300878ed226SJulian Elischer ip->lcid = ch->scid; 13014ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1302878ed226SJulian Elischer } 1303878ed226SJulian Elischer 1304878ed226SJulian Elischer return (error); 1305878ed226SJulian Elischer } /* ng_l2cap_l2ca_discon_ind */ 1306878ed226SJulian Elischer 1307878ed226SJulian Elischer /* 1308878ed226SJulian Elischer * Process L2CA_GroupCreate request from the upper layer protocol. 1309878ed226SJulian Elischer * XXX FIXME 1310878ed226SJulian Elischer */ 1311878ed226SJulian Elischer 1312878ed226SJulian Elischer int 1313878ed226SJulian Elischer ng_l2cap_l2ca_grp_create(ng_l2cap_p l2cap, struct ng_mesg *msg) 1314878ed226SJulian Elischer { 1315878ed226SJulian Elischer return (ENOTSUP); 1316878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_create */ 1317878ed226SJulian Elischer 1318878ed226SJulian Elischer /* 1319878ed226SJulian Elischer * Process L2CA_GroupClose request from the upper layer protocol 1320878ed226SJulian Elischer * XXX FIXME 1321878ed226SJulian Elischer */ 1322878ed226SJulian Elischer 1323878ed226SJulian Elischer int 1324878ed226SJulian Elischer ng_l2cap_l2ca_grp_close(ng_l2cap_p l2cap, struct ng_mesg *msg) 1325878ed226SJulian Elischer { 1326878ed226SJulian Elischer return (ENOTSUP); 1327878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_close */ 1328878ed226SJulian Elischer 1329878ed226SJulian Elischer /* 1330878ed226SJulian Elischer * Process L2CA_GroupAddMember request from the upper layer protocol. 1331878ed226SJulian Elischer * XXX FIXME 1332878ed226SJulian Elischer */ 1333878ed226SJulian Elischer 1334878ed226SJulian Elischer int 1335878ed226SJulian Elischer ng_l2cap_l2ca_grp_add_member_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1336878ed226SJulian Elischer { 1337878ed226SJulian Elischer return (ENOTSUP); 1338878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_add_member_req */ 1339878ed226SJulian Elischer 1340878ed226SJulian Elischer /* 1341878ed226SJulian Elischer * Send L2CA_GroupAddMember response to the upper layer protocol. 1342878ed226SJulian Elischer * XXX FIXME 1343878ed226SJulian Elischer */ 1344878ed226SJulian Elischer 1345878ed226SJulian Elischer int 1346878ed226SJulian Elischer ng_l2cap_l2ca_grp_add_member_rsp(ng_l2cap_chan_p ch, u_int32_t token, 1347878ed226SJulian Elischer u_int16_t result) 1348878ed226SJulian Elischer { 1349878ed226SJulian Elischer return (0); 1350878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_add_member_rsp */ 1351878ed226SJulian Elischer 1352878ed226SJulian Elischer /* 1353878ed226SJulian Elischer * Process L2CA_GroupDeleteMember request from the upper layer protocol 1354878ed226SJulian Elischer * XXX FIXME 1355878ed226SJulian Elischer */ 1356878ed226SJulian Elischer 1357878ed226SJulian Elischer int 1358878ed226SJulian Elischer ng_l2cap_l2ca_grp_rem_member(ng_l2cap_p l2cap, struct ng_mesg *msg) 1359878ed226SJulian Elischer { 1360878ed226SJulian Elischer return (ENOTSUP); 1361878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_rem_member */ 1362878ed226SJulian Elischer 1363878ed226SJulian Elischer /* 1364878ed226SJulian Elischer * Process L2CA_GroupGetMembers request from the upper layer protocol 1365878ed226SJulian Elischer * XXX FIXME 1366878ed226SJulian Elischer */ 1367878ed226SJulian Elischer 1368878ed226SJulian Elischer int 1369878ed226SJulian Elischer ng_l2cap_l2ca_grp_get_members(ng_l2cap_p l2cap, struct ng_mesg *msg) 1370878ed226SJulian Elischer { 1371878ed226SJulian Elischer return (ENOTSUP); 1372878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_get_members */ 1373878ed226SJulian Elischer 1374878ed226SJulian Elischer /* 1375878ed226SJulian Elischer * Process L2CA_Ping request from the upper layer protocol 1376878ed226SJulian Elischer */ 1377878ed226SJulian Elischer 1378878ed226SJulian Elischer int 1379878ed226SJulian Elischer ng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1380878ed226SJulian Elischer { 1381878ed226SJulian Elischer ng_l2cap_l2ca_ping_ip *ip = NULL; 1382878ed226SJulian Elischer ng_l2cap_con_p con = NULL; 1383878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 1384878ed226SJulian Elischer int error = 0; 1385878ed226SJulian Elischer 1386878ed226SJulian Elischer /* Verify message */ 1387878ed226SJulian Elischer if (msg->header.arglen < sizeof(*ip)) { 1388878ed226SJulian Elischer NG_L2CAP_ALERT( 1389878ed226SJulian Elischer "%s: %s - invalid L2CA_Ping request message size, size=%d\n", 1390878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), 1391878ed226SJulian Elischer msg->header.arglen); 1392878ed226SJulian Elischer error = EMSGSIZE; 1393878ed226SJulian Elischer goto out; 1394878ed226SJulian Elischer } 1395878ed226SJulian Elischer 1396878ed226SJulian Elischer ip = (ng_l2cap_l2ca_ping_ip *)(msg->data); 1397878ed226SJulian Elischer if (ip->echo_size > NG_L2CAP_MAX_ECHO_SIZE) { 1398878ed226SJulian Elischer NG_L2CAP_WARN( 1399878ed226SJulian Elischer "%s: %s - invalid L2CA_Ping request. Echo size is too big, echo_size=%d\n", 1400878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ip->echo_size); 1401878ed226SJulian Elischer error = EMSGSIZE; 1402878ed226SJulian Elischer goto out; 1403878ed226SJulian Elischer } 1404878ed226SJulian Elischer 1405878ed226SJulian Elischer /* Check if we have connection to the unit */ 1406fbc48c2bSTakanori Watanabe con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL); 1407878ed226SJulian Elischer if (con == NULL) { 1408878ed226SJulian Elischer /* Submit LP_ConnectReq to the lower layer */ 1409fbc48c2bSTakanori Watanabe error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL); 1410878ed226SJulian Elischer if (error != 0) { 1411878ed226SJulian Elischer NG_L2CAP_ERR( 1412878ed226SJulian Elischer "%s: %s - unable to send LP_ConnectReq message, error=%d\n", 1413878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), error); 1414878ed226SJulian Elischer goto out; 1415878ed226SJulian Elischer } 1416878ed226SJulian Elischer 1417878ed226SJulian Elischer /* This should not fail */ 1418fbc48c2bSTakanori Watanabe con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL); 1419878ed226SJulian Elischer KASSERT((con != NULL), 1420878ed226SJulian Elischer ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node))); 1421878ed226SJulian Elischer } 1422878ed226SJulian Elischer 1423878ed226SJulian Elischer /* Create L2CAP command descriptor */ 1424878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con), 1425878ed226SJulian Elischer NG_L2CAP_ECHO_REQ, msg->header.token); 1426878ed226SJulian Elischer if (cmd == NULL) { 1427878ed226SJulian Elischer error = ENOMEM; 1428878ed226SJulian Elischer goto out; 1429878ed226SJulian Elischer } 1430878ed226SJulian Elischer 1431878ed226SJulian Elischer if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1432878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 1433878ed226SJulian Elischer error = EIO; 1434878ed226SJulian Elischer goto out; 1435878ed226SJulian Elischer } 1436878ed226SJulian Elischer 1437878ed226SJulian Elischer /* Create L2CAP command packet */ 1438878ed226SJulian Elischer _ng_l2cap_echo_req(cmd->aux, cmd->ident, 1439878ed226SJulian Elischer msg->data + sizeof(*ip), ip->echo_size); 1440878ed226SJulian Elischer if (cmd->aux == NULL) { 1441878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 1442878ed226SJulian Elischer error = ENOBUFS; 1443878ed226SJulian Elischer goto out; 1444878ed226SJulian Elischer } 1445878ed226SJulian Elischer 1446878ed226SJulian Elischer /* Link command to the queue */ 1447878ed226SJulian Elischer ng_l2cap_link_cmd(con, cmd); 1448878ed226SJulian Elischer ng_l2cap_lp_deliver(con); 1449878ed226SJulian Elischer out: 1450878ed226SJulian Elischer return (error); 1451878ed226SJulian Elischer } /* ng_l2cap_l2ca_ping_req */ 1452878ed226SJulian Elischer 1453878ed226SJulian Elischer /* 1454878ed226SJulian Elischer * Send L2CA_Ping response to the upper layer protocol 1455878ed226SJulian Elischer */ 1456878ed226SJulian Elischer 1457878ed226SJulian Elischer int 1458878ed226SJulian Elischer ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result, 1459878ed226SJulian Elischer struct mbuf *data) 1460878ed226SJulian Elischer { 1461878ed226SJulian Elischer ng_l2cap_p l2cap = con->l2cap; 1462878ed226SJulian Elischer struct ng_mesg *msg = NULL; 1463878ed226SJulian Elischer ng_l2cap_l2ca_ping_op *op = NULL; 1464878ed226SJulian Elischer int error = 0, size = 0; 1465878ed226SJulian Elischer 1466878ed226SJulian Elischer /* Check if control hook is connected and valid */ 1467878ed226SJulian Elischer if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) { 1468878ed226SJulian Elischer NG_L2CAP_WARN( 1469878ed226SJulian Elischer "%s: %s - unable to send L2CA_Ping response message. " \ 1470878ed226SJulian Elischer "Hook is not connected or valid\n", 1471878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node)); 1472878ed226SJulian Elischer error = ENOTCONN; 1473878ed226SJulian Elischer goto out; 1474878ed226SJulian Elischer } 1475878ed226SJulian Elischer 1476878ed226SJulian Elischer size = (data == NULL)? 0 : data->m_pkthdr.len; 1477878ed226SJulian Elischer 1478878ed226SJulian Elischer /* Create and send L2CA_Ping response message */ 1479878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_PING, 1480878ed226SJulian Elischer sizeof(*op) + size, M_NOWAIT); 1481878ed226SJulian Elischer if (msg == NULL) 1482878ed226SJulian Elischer error = ENOMEM; 1483878ed226SJulian Elischer else { 1484878ed226SJulian Elischer msg->header.token = token; 1485878ed226SJulian Elischer msg->header.flags |= NGF_RESP; 1486878ed226SJulian Elischer 1487878ed226SJulian Elischer op = (ng_l2cap_l2ca_ping_op *)(msg->data); 1488878ed226SJulian Elischer op->result = result; 1489878ed226SJulian Elischer bcopy(&con->remote, &op->bdaddr, sizeof(op->bdaddr)); 1490878ed226SJulian Elischer if (data != NULL && size > 0) { 1491878ed226SJulian Elischer op->echo_size = size; 1492878ed226SJulian Elischer m_copydata(data, 0, size, (caddr_t) op + sizeof(*op)); 1493878ed226SJulian Elischer } 1494878ed226SJulian Elischer 14954ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1496878ed226SJulian Elischer } 1497878ed226SJulian Elischer out: 1498878ed226SJulian Elischer NG_FREE_M(data); 1499878ed226SJulian Elischer 1500878ed226SJulian Elischer return (error); 1501878ed226SJulian Elischer } /* ng_l2cap_l2ca_ping_rsp */ 1502878ed226SJulian Elischer 1503878ed226SJulian Elischer /* 1504878ed226SJulian Elischer * Process L2CA_GetInfo request from the upper layer protocol 1505878ed226SJulian Elischer */ 1506878ed226SJulian Elischer 1507878ed226SJulian Elischer int 1508878ed226SJulian Elischer ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1509878ed226SJulian Elischer { 1510878ed226SJulian Elischer ng_l2cap_l2ca_get_info_ip *ip = NULL; 1511878ed226SJulian Elischer ng_l2cap_con_p con = NULL; 1512878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 1513878ed226SJulian Elischer int error = 0; 1514878ed226SJulian Elischer 1515878ed226SJulian Elischer /* Verify message */ 1516878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) { 1517878ed226SJulian Elischer NG_L2CAP_ALERT( 1518878ed226SJulian Elischer "%s: %s - invalid L2CA_GetInfo request message size, size=%d\n", 1519878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), 1520878ed226SJulian Elischer msg->header.arglen); 1521878ed226SJulian Elischer error = EMSGSIZE; 1522878ed226SJulian Elischer goto out; 1523878ed226SJulian Elischer } 1524878ed226SJulian Elischer 1525878ed226SJulian Elischer ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data); 1526878ed226SJulian Elischer 1527878ed226SJulian Elischer /* Check if we have connection to the unit */ 1528fbc48c2bSTakanori Watanabe con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr,ip->linktype); 1529878ed226SJulian Elischer if (con == NULL) { 1530878ed226SJulian Elischer /* Submit LP_ConnectReq to the lower layer */ 1531fbc48c2bSTakanori Watanabe error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype); 1532878ed226SJulian Elischer if (error != 0) { 1533878ed226SJulian Elischer NG_L2CAP_ERR( 1534878ed226SJulian Elischer "%s: %s - unable to send LP_ConnectReq message, error=%d\n", 1535878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), error); 1536878ed226SJulian Elischer goto out; 1537878ed226SJulian Elischer } 1538878ed226SJulian Elischer 1539878ed226SJulian Elischer /* This should not fail */ 1540fbc48c2bSTakanori Watanabe con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype); 1541878ed226SJulian Elischer KASSERT((con != NULL), 1542878ed226SJulian Elischer ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node))); 1543878ed226SJulian Elischer } 1544878ed226SJulian Elischer 1545878ed226SJulian Elischer /* Create L2CAP command descriptor */ 1546878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con), 1547878ed226SJulian Elischer NG_L2CAP_INFO_REQ, msg->header.token); 1548878ed226SJulian Elischer if (cmd == NULL) { 1549878ed226SJulian Elischer error = ENOMEM; 1550878ed226SJulian Elischer goto out; 1551878ed226SJulian Elischer } 1552878ed226SJulian Elischer 1553878ed226SJulian Elischer if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1554878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 1555878ed226SJulian Elischer error = EIO; 1556878ed226SJulian Elischer goto out; 1557878ed226SJulian Elischer } 1558878ed226SJulian Elischer 1559878ed226SJulian Elischer /* Create L2CAP command packet */ 1560878ed226SJulian Elischer _ng_l2cap_info_req(cmd->aux, cmd->ident, ip->info_type); 1561878ed226SJulian Elischer if (cmd->aux == NULL) { 1562878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 1563878ed226SJulian Elischer error = ENOBUFS; 1564878ed226SJulian Elischer goto out; 1565878ed226SJulian Elischer } 1566878ed226SJulian Elischer 1567878ed226SJulian Elischer /* Link command to the queue */ 1568878ed226SJulian Elischer ng_l2cap_link_cmd(con, cmd); 1569878ed226SJulian Elischer ng_l2cap_lp_deliver(con); 1570878ed226SJulian Elischer out: 1571878ed226SJulian Elischer return (error); 1572878ed226SJulian Elischer } /* ng_l2cap_l2ca_get_info_req */ 1573878ed226SJulian Elischer 1574878ed226SJulian Elischer /* 1575878ed226SJulian Elischer * Send L2CA_GetInfo response to the upper layer protocol 1576878ed226SJulian Elischer */ 1577878ed226SJulian Elischer 1578878ed226SJulian Elischer int 1579878ed226SJulian Elischer ng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con, u_int32_t token, 1580878ed226SJulian Elischer u_int16_t result, struct mbuf *data) 1581878ed226SJulian Elischer { 1582878ed226SJulian Elischer ng_l2cap_p l2cap = con->l2cap; 1583878ed226SJulian Elischer struct ng_mesg *msg = NULL; 1584878ed226SJulian Elischer ng_l2cap_l2ca_get_info_op *op = NULL; 1585878ed226SJulian Elischer int error = 0, size; 1586878ed226SJulian Elischer 1587878ed226SJulian Elischer /* Check if control hook is connected and valid */ 1588878ed226SJulian Elischer if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) { 1589878ed226SJulian Elischer NG_L2CAP_WARN( 1590878ed226SJulian Elischer "%s: %s - unable to send L2CA_GetInfo response message. " \ 1591878ed226SJulian Elischer "Hook is not connected or valid\n", 1592878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node)); 1593878ed226SJulian Elischer error = ENOTCONN; 1594878ed226SJulian Elischer goto out; 1595878ed226SJulian Elischer } 1596878ed226SJulian Elischer 1597878ed226SJulian Elischer size = (data == NULL)? 0 : data->m_pkthdr.len; 1598878ed226SJulian Elischer 1599878ed226SJulian Elischer /* Create and send L2CA_GetInfo response message */ 1600878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_GET_INFO, 1601878ed226SJulian Elischer sizeof(*op) + size, M_NOWAIT); 1602878ed226SJulian Elischer if (msg == NULL) 1603878ed226SJulian Elischer error = ENOMEM; 1604878ed226SJulian Elischer else { 1605878ed226SJulian Elischer msg->header.token = token; 1606878ed226SJulian Elischer msg->header.flags |= NGF_RESP; 1607878ed226SJulian Elischer 1608878ed226SJulian Elischer op = (ng_l2cap_l2ca_get_info_op *)(msg->data); 1609878ed226SJulian Elischer op->result = result; 1610878ed226SJulian Elischer if (data != NULL && size > 0) { 1611878ed226SJulian Elischer op->info_size = size; 1612878ed226SJulian Elischer m_copydata(data, 0, size, (caddr_t) op + sizeof(*op)); 1613878ed226SJulian Elischer } 1614878ed226SJulian Elischer 16154ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1616878ed226SJulian Elischer } 1617878ed226SJulian Elischer out: 1618878ed226SJulian Elischer NG_FREE_M(data); 1619878ed226SJulian Elischer 1620878ed226SJulian Elischer return (error); 1621878ed226SJulian Elischer } /* ng_l2cap_l2ca_get_info_rsp */ 1622878ed226SJulian Elischer 1623878ed226SJulian Elischer /* 1624878ed226SJulian Elischer * Process L2CA_EnableCLT message from the upper layer protocol 1625878ed226SJulian Elischer * XXX convert to NGN_L2CAP_NODE_SET_FLAGS? 1626878ed226SJulian Elischer */ 1627878ed226SJulian Elischer 1628878ed226SJulian Elischer int 1629878ed226SJulian Elischer ng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg) 1630878ed226SJulian Elischer { 1631878ed226SJulian Elischer ng_l2cap_l2ca_enable_clt_ip *ip = NULL; 1632878ed226SJulian Elischer int error = 0; 1633878ed226SJulian Elischer #if 0 1634878ed226SJulian Elischer * ng_l2cap_l2ca_enable_clt_op *op = NULL; 1635878ed226SJulian Elischer * u_int16_t result; 1636878ed226SJulian Elischer * u_int32_t token; 1637878ed226SJulian Elischer #endif 1638878ed226SJulian Elischer 1639878ed226SJulian Elischer /* Check message */ 1640878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) { 1641878ed226SJulian Elischer NG_L2CAP_ALERT( 1642878ed226SJulian Elischer "%s: %s - invalid L2CA_EnableCLT message size, size=%d\n", 1643878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), 1644878ed226SJulian Elischer msg->header.arglen); 1645878ed226SJulian Elischer 1646878ed226SJulian Elischer return (EMSGSIZE); 1647878ed226SJulian Elischer } 1648878ed226SJulian Elischer 1649878ed226SJulian Elischer /* Process request */ 1650878ed226SJulian Elischer ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data); 1651878ed226SJulian Elischer #if 0 1652878ed226SJulian Elischer * result = NG_L2CAP_SUCCESS; 1653878ed226SJulian Elischer #endif 1654878ed226SJulian Elischer 1655878ed226SJulian Elischer switch (ip->psm) 1656878ed226SJulian Elischer { 1657878ed226SJulian Elischer case 0: 1658878ed226SJulian Elischer /* Special case: disable/enable all PSM */ 1659878ed226SJulian Elischer if (ip->enable) 1660878ed226SJulian Elischer l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED | 1661878ed226SJulian Elischer NG_L2CAP_CLT_RFCOMM_DISABLED | 1662878ed226SJulian Elischer NG_L2CAP_CLT_TCP_DISABLED); 1663878ed226SJulian Elischer else 1664878ed226SJulian Elischer l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED | 1665878ed226SJulian Elischer NG_L2CAP_CLT_RFCOMM_DISABLED | 1666878ed226SJulian Elischer NG_L2CAP_CLT_TCP_DISABLED); 1667878ed226SJulian Elischer break; 1668878ed226SJulian Elischer 1669878ed226SJulian Elischer case NG_L2CAP_PSM_SDP: 1670878ed226SJulian Elischer if (ip->enable) 1671878ed226SJulian Elischer l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED; 1672878ed226SJulian Elischer else 1673878ed226SJulian Elischer l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED; 1674878ed226SJulian Elischer break; 1675878ed226SJulian Elischer 1676878ed226SJulian Elischer case NG_L2CAP_PSM_RFCOMM: 1677878ed226SJulian Elischer if (ip->enable) 1678878ed226SJulian Elischer l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED; 1679878ed226SJulian Elischer else 1680878ed226SJulian Elischer l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED; 1681878ed226SJulian Elischer break; 1682878ed226SJulian Elischer 1683878ed226SJulian Elischer case NG_L2CAP_PSM_TCP: 1684878ed226SJulian Elischer if (ip->enable) 1685878ed226SJulian Elischer l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED; 1686878ed226SJulian Elischer else 1687878ed226SJulian Elischer l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED; 1688878ed226SJulian Elischer break; 1689878ed226SJulian Elischer 1690878ed226SJulian Elischer default: 1691878ed226SJulian Elischer NG_L2CAP_ERR( 1692878ed226SJulian Elischer "%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm); 1693878ed226SJulian Elischer #if 0 1694878ed226SJulian Elischer * result = NG_L2CAP_PSM_NOT_SUPPORTED; 1695878ed226SJulian Elischer #endif 1696878ed226SJulian Elischer error = ENOTSUP; 1697878ed226SJulian Elischer break; 1698878ed226SJulian Elischer } 1699878ed226SJulian Elischer 1700878ed226SJulian Elischer #if 0 1701878ed226SJulian Elischer * /* Create and send response message */ 1702878ed226SJulian Elischer * token = msg->header.token; 1703878ed226SJulian Elischer * NG_FREE_MSG(msg); 1704878ed226SJulian Elischer * NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT, 1705878ed226SJulian Elischer * sizeof(*op), M_NOWAIT); 1706878ed226SJulian Elischer * if (msg == NULL) 1707878ed226SJulian Elischer * error = ENOMEM; 1708878ed226SJulian Elischer * else { 1709878ed226SJulian Elischer * msg->header.token = token; 1710878ed226SJulian Elischer * msg->header.flags |= NGF_RESP; 1711878ed226SJulian Elischer * 1712878ed226SJulian Elischer * op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data); 1713878ed226SJulian Elischer * op->result = result; 1714878ed226SJulian Elischer * } 1715878ed226SJulian Elischer * 1716878ed226SJulian Elischer * /* Send response to control hook */ 1717878ed226SJulian Elischer * if (l2cap->ctl != NULL && NG_HOOK_IS_VALID(l2cap->ctl)) 17184ae439a3SMaksim Yevmenkin * NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1719878ed226SJulian Elischer #endif 1720878ed226SJulian Elischer 1721878ed226SJulian Elischer return (error); 1722878ed226SJulian Elischer } /* ng_l2cap_l2ca_enable_clt */ 1723878ed226SJulian Elischer 1724