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; 133*3a601a23STakanori Watanabe }else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){ 134*3a601a23STakanori Watanabe _ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_SMP_CID, 135*3a601a23STakanori Watanabe NG_L2CAP_SMP_CID, 0, 0); 136*3a601a23STakanori Watanabe cmd->aux->m_flags |= M_PROTO2; 137fbc48c2bSTakanori Watanabe }else{ 138878ed226SJulian Elischer _ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid); 139fbc48c2bSTakanori Watanabe } 140878ed226SJulian Elischer if (cmd->aux == NULL) { 141878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 142878ed226SJulian Elischer ng_l2cap_free_chan(ch); 143878ed226SJulian Elischer error = ENOBUFS; 144878ed226SJulian Elischer goto out; 145878ed226SJulian Elischer } 146878ed226SJulian Elischer 147878ed226SJulian Elischer ch->state = NG_L2CAP_W4_L2CAP_CON_RSP; 148878ed226SJulian Elischer 149878ed226SJulian Elischer /* Link command to the queue */ 150878ed226SJulian Elischer ng_l2cap_link_cmd(ch->con, cmd); 151878ed226SJulian Elischer ng_l2cap_lp_deliver(ch->con); 152878ed226SJulian Elischer out: 153878ed226SJulian Elischer return (error); 154878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_req */ 155878ed226SJulian Elischer 156878ed226SJulian Elischer /* 157878ed226SJulian Elischer * Send L2CA_Connect response to the upper layer protocol. 158878ed226SJulian Elischer */ 159878ed226SJulian Elischer 160878ed226SJulian Elischer int 161878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result, 162878ed226SJulian Elischer u_int16_t status) 163878ed226SJulian Elischer { 164878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 165878ed226SJulian Elischer struct ng_mesg *msg = NULL; 166878ed226SJulian Elischer ng_l2cap_l2ca_con_op *op = NULL; 167878ed226SJulian Elischer int error = 0; 168878ed226SJulian Elischer 169878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 170878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 171878ed226SJulian Elischer NG_L2CAP_ERR( 172878ed226SJulian Elischer "%s: %s - unable to send L2CA_Connect response message. " \ 173878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 174878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 175878ed226SJulian Elischer 176878ed226SJulian Elischer return (ENOTCONN); 177878ed226SJulian Elischer } 178878ed226SJulian Elischer 179878ed226SJulian Elischer /* Create and send L2CA_Connect response message */ 180878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON, 181878ed226SJulian Elischer sizeof(*op), M_NOWAIT); 182878ed226SJulian Elischer if (msg == NULL) 183878ed226SJulian Elischer error = ENOMEM; 184878ed226SJulian Elischer else { 185878ed226SJulian Elischer msg->header.token = token; 186878ed226SJulian Elischer msg->header.flags |= NGF_RESP; 187878ed226SJulian Elischer 188878ed226SJulian Elischer op = (ng_l2cap_l2ca_con_op *)(msg->data); 189878ed226SJulian Elischer 190878ed226SJulian Elischer /* 191878ed226SJulian Elischer * XXX Spec. says we should only populate LCID when result == 0 192878ed226SJulian Elischer * What about PENDING? What the heck, for now always populate 193878ed226SJulian Elischer * LCID :) 194878ed226SJulian Elischer */ 195fbc48c2bSTakanori Watanabe if(ch->scid == NG_L2CAP_ATT_CID){ 196fbc48c2bSTakanori Watanabe op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT; 197fbc48c2bSTakanori Watanabe op->lcid = ch->con->con_handle; 198*3a601a23STakanori Watanabe }else if(ch->scid == NG_L2CAP_SMP_CID){ 199*3a601a23STakanori Watanabe op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP; 200*3a601a23STakanori Watanabe op->lcid = ch->con->con_handle; 201fbc48c2bSTakanori Watanabe }else{ 202fbc48c2bSTakanori Watanabe op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)? 203fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR : 204fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_LE; 205878ed226SJulian Elischer op->lcid = ch->scid; 206fbc48c2bSTakanori Watanabe } 207*3a601a23STakanori Watanabe op->encryption = ch->con->encryption; 208878ed226SJulian Elischer op->result = result; 209878ed226SJulian Elischer op->status = status; 210878ed226SJulian Elischer 2114ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 212878ed226SJulian Elischer } 213878ed226SJulian Elischer 214878ed226SJulian Elischer return (error); 215878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_rsp */ 216878ed226SJulian Elischer 217878ed226SJulian Elischer /* 218878ed226SJulian Elischer * Process L2CA_ConnectRsp request from the upper layer protocol. 219878ed226SJulian Elischer */ 220878ed226SJulian Elischer 221878ed226SJulian Elischer int 222878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 223878ed226SJulian Elischer { 224878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_ip *ip = NULL; 225878ed226SJulian Elischer ng_l2cap_con_p con = NULL; 226878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL; 227878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 228878ed226SJulian Elischer u_int16_t dcid; 229878ed226SJulian Elischer int error = 0; 230878ed226SJulian Elischer 231878ed226SJulian Elischer /* Check message */ 232878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) { 233878ed226SJulian Elischer NG_L2CAP_ALERT( 234878ed226SJulian Elischer "%s: %s - invalid L2CA_ConnectRsp request message size, size=%d\n", 235878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), 236878ed226SJulian Elischer msg->header.arglen); 237878ed226SJulian Elischer error = EMSGSIZE; 238878ed226SJulian Elischer goto out; 239878ed226SJulian Elischer } 240878ed226SJulian Elischer 241878ed226SJulian Elischer ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data); 242878ed226SJulian Elischer 243878ed226SJulian Elischer /* Check if we have this channel */ 244*3a601a23STakanori Watanabe if((ip->lcid != NG_L2CAP_ATT_CID)&& 245*3a601a23STakanori Watanabe (ip->lcid != NG_L2CAP_SMP_CID)){ 246fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid 247fbc48c2bSTakanori Watanabe ,(ip->linktype == NG_HCI_LINK_ACL)? 248fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR: 249fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_LE); 250fbc48c2bSTakanori Watanabe }else{ 251fbc48c2bSTakanori Watanabe // For now not support on ATT device. 252fbc48c2bSTakanori Watanabe ch = NULL; 253fbc48c2bSTakanori Watanabe } 254878ed226SJulian Elischer if (ch == NULL) { 255878ed226SJulian Elischer NG_L2CAP_ALERT( 256878ed226SJulian Elischer "%s: %s - unexpected L2CA_ConnectRsp request message. " \ 257878ed226SJulian Elischer "Channel does not exist, lcid=%d\n", 258878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 259878ed226SJulian Elischer error = ENOENT; 260878ed226SJulian Elischer goto out; 261878ed226SJulian Elischer } 262878ed226SJulian Elischer 263878ed226SJulian Elischer /* Check channel state */ 264878ed226SJulian Elischer if (ch->state != NG_L2CAP_W4_L2CA_CON_RSP) { 265878ed226SJulian Elischer NG_L2CAP_ERR( 266878ed226SJulian Elischer "%s: %s - unexpected L2CA_ConnectRsp request message. " \ 267878ed226SJulian Elischer "Invalid channel state, state=%d, lcid=%d\n", 268878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->state, 269878ed226SJulian Elischer ip->lcid); 270878ed226SJulian Elischer error = EINVAL; 271878ed226SJulian Elischer goto out; 272878ed226SJulian Elischer } 273878ed226SJulian Elischer 274878ed226SJulian Elischer dcid = ch->dcid; 275878ed226SJulian Elischer con = ch->con; 276878ed226SJulian Elischer 277878ed226SJulian Elischer /* 278878ed226SJulian Elischer * Now we are pretty much sure it is our response. So create and send 279878ed226SJulian Elischer * L2CAP_ConnectRsp message to our peer. 280878ed226SJulian Elischer */ 281878ed226SJulian Elischer 282878ed226SJulian Elischer if (ch->ident != ip->ident) 283878ed226SJulian Elischer NG_L2CAP_WARN( 284878ed226SJulian Elischer "%s: %s - channel ident and response ident do not match, scid=%d, ident=%d. " \ 285878ed226SJulian Elischer "Will use response ident=%d\n", 286878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->scid, 287878ed226SJulian Elischer ch->ident, ip->ident); 288878ed226SJulian Elischer 289878ed226SJulian Elischer /* Check result */ 290878ed226SJulian Elischer switch (ip->result) { 291878ed226SJulian Elischer case NG_L2CAP_SUCCESS: 292*3a601a23STakanori Watanabe ch->state = ((ch->scid == NG_L2CAP_ATT_CID)|| 293*3a601a23STakanori Watanabe (ch->scid == NG_L2CAP_SMP_CID))? 294fbc48c2bSTakanori Watanabe NG_L2CAP_OPEN : NG_L2CAP_CONFIG; 295878ed226SJulian Elischer ch->cfg_state = 0; 296878ed226SJulian Elischer break; 297878ed226SJulian Elischer 298878ed226SJulian Elischer case NG_L2CAP_PENDING: 299878ed226SJulian Elischer break; 300878ed226SJulian Elischer 301878ed226SJulian Elischer default: 302878ed226SJulian Elischer ng_l2cap_free_chan(ch); 303878ed226SJulian Elischer ch = NULL; 304878ed226SJulian Elischer break; 305878ed226SJulian Elischer } 306878ed226SJulian Elischer 307878ed226SJulian Elischer /* Create L2CAP command */ 308878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(con, ch, ip->ident, NG_L2CAP_CON_RSP, 309878ed226SJulian Elischer msg->header.token); 310878ed226SJulian Elischer if (cmd == NULL) { 311878ed226SJulian Elischer if (ch != NULL) 312878ed226SJulian Elischer ng_l2cap_free_chan(ch); 313878ed226SJulian Elischer 314878ed226SJulian Elischer error = ENOMEM; 315878ed226SJulian Elischer goto out; 316878ed226SJulian Elischer } 317878ed226SJulian Elischer 318878ed226SJulian Elischer _ng_l2cap_con_rsp(cmd->aux, cmd->ident, ip->lcid, dcid, 319878ed226SJulian Elischer ip->result, ip->status); 320878ed226SJulian Elischer if (cmd->aux == NULL) { 321878ed226SJulian Elischer if (ch != NULL) 322878ed226SJulian Elischer ng_l2cap_free_chan(ch); 323878ed226SJulian Elischer 324878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 325878ed226SJulian Elischer error = ENOBUFS; 326878ed226SJulian Elischer goto out; 327878ed226SJulian Elischer } 328878ed226SJulian Elischer 329878ed226SJulian Elischer /* Link command to the queue */ 330878ed226SJulian Elischer ng_l2cap_link_cmd(con, cmd); 331878ed226SJulian Elischer ng_l2cap_lp_deliver(con); 332878ed226SJulian Elischer out: 333878ed226SJulian Elischer return (error); 334878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_rsp_req */ 335878ed226SJulian Elischer 336*3a601a23STakanori Watanabe int ng_l2cap_l2ca_encryption_change(ng_l2cap_chan_p ch, uint16_t result) 337*3a601a23STakanori Watanabe { 338*3a601a23STakanori Watanabe ng_l2cap_p l2cap = ch->con->l2cap; 339*3a601a23STakanori Watanabe struct ng_mesg *msg = NULL; 340*3a601a23STakanori Watanabe ng_l2cap_l2ca_enc_chg_op *op = NULL; 341*3a601a23STakanori Watanabe int error = 0; 342*3a601a23STakanori Watanabe 343*3a601a23STakanori Watanabe /* Check if upstream hook is connected and valid */ 344*3a601a23STakanori Watanabe if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 345*3a601a23STakanori Watanabe NG_L2CAP_ERR( 346*3a601a23STakanori Watanabe "%s: %s - unable to send L2CA_ConnectRsp response message. " \ 347*3a601a23STakanori Watanabe "Hook is not connected or valid, psm=%d\n", 348*3a601a23STakanori Watanabe __func__, NG_NODE_NAME(l2cap->node), ch->psm); 349*3a601a23STakanori Watanabe 350*3a601a23STakanori Watanabe return (ENOTCONN); 351*3a601a23STakanori Watanabe } 352*3a601a23STakanori Watanabe 353*3a601a23STakanori Watanabe /* Create and send L2CA_ConnectRsp response message */ 354*3a601a23STakanori Watanabe NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENC_CHANGE, 355*3a601a23STakanori Watanabe sizeof(*op), M_NOWAIT); 356*3a601a23STakanori Watanabe if (msg == NULL) 357*3a601a23STakanori Watanabe error = ENOMEM; 358*3a601a23STakanori Watanabe else { 359*3a601a23STakanori Watanabe msg->header.token = 0; 360*3a601a23STakanori Watanabe msg->header.flags |= NGF_RESP; 361*3a601a23STakanori Watanabe 362*3a601a23STakanori Watanabe op = (ng_l2cap_l2ca_enc_chg_op *)(msg->data); 363*3a601a23STakanori Watanabe op->result = result; 364*3a601a23STakanori Watanabe if(ch->scid ==NG_L2CAP_ATT_CID|| 365*3a601a23STakanori Watanabe ch->scid ==NG_L2CAP_SMP_CID){ 366*3a601a23STakanori Watanabe op->lcid = ch->con->con_handle; 367*3a601a23STakanori Watanabe op->idtype = (ch->scid==NG_L2CAP_ATT_CID)? 368*3a601a23STakanori Watanabe NG_L2CAP_L2CA_IDTYPE_ATT: 369*3a601a23STakanori Watanabe NG_L2CAP_L2CA_IDTYPE_SMP; 370*3a601a23STakanori Watanabe }else{ 371*3a601a23STakanori Watanabe op->idtype =(ch->con->linktype ==NG_HCI_LINK_ACL)? 372*3a601a23STakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR: 373*3a601a23STakanori Watanabe NG_L2CAP_L2CA_IDTYPE_LE; 374*3a601a23STakanori Watanabe } 375*3a601a23STakanori Watanabe 376*3a601a23STakanori Watanabe 377*3a601a23STakanori Watanabe NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 378*3a601a23STakanori Watanabe } 379*3a601a23STakanori Watanabe 380*3a601a23STakanori Watanabe return (error); 381*3a601a23STakanori Watanabe 382*3a601a23STakanori Watanabe } 383878ed226SJulian Elischer /* 384878ed226SJulian Elischer * Send L2CAP_ConnectRsp response to the upper layer 385878ed226SJulian Elischer */ 386878ed226SJulian Elischer 387878ed226SJulian Elischer int 388878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 389878ed226SJulian Elischer { 390878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 391878ed226SJulian Elischer struct ng_mesg *msg = NULL; 392878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_op *op = NULL; 393878ed226SJulian Elischer int error = 0; 394878ed226SJulian Elischer 395878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 396878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 397878ed226SJulian Elischer NG_L2CAP_ERR( 398878ed226SJulian Elischer "%s: %s - unable to send L2CA_ConnectRsp response message. " \ 399878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 400878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 401878ed226SJulian Elischer 402878ed226SJulian Elischer return (ENOTCONN); 403878ed226SJulian Elischer } 404878ed226SJulian Elischer 405878ed226SJulian Elischer /* Create and send L2CA_ConnectRsp response message */ 406878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_RSP, 407878ed226SJulian Elischer sizeof(*op), M_NOWAIT); 408878ed226SJulian Elischer if (msg == NULL) 409878ed226SJulian Elischer error = ENOMEM; 410878ed226SJulian Elischer else { 411878ed226SJulian Elischer msg->header.token = token; 412878ed226SJulian Elischer msg->header.flags |= NGF_RESP; 413878ed226SJulian Elischer 414878ed226SJulian Elischer op = (ng_l2cap_l2ca_con_rsp_op *)(msg->data); 415878ed226SJulian Elischer op->result = result; 416878ed226SJulian Elischer 4174ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 418878ed226SJulian Elischer } 419878ed226SJulian Elischer 420878ed226SJulian Elischer return (error); 421878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_rsp_rsp */ 422878ed226SJulian Elischer 423878ed226SJulian Elischer /* 424878ed226SJulian Elischer * Send L2CA_ConnectInd message to the upper layer protocol. 425878ed226SJulian Elischer */ 426878ed226SJulian Elischer 427878ed226SJulian Elischer int 428878ed226SJulian Elischer ng_l2cap_l2ca_con_ind(ng_l2cap_chan_p ch) 429878ed226SJulian Elischer { 430878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 431878ed226SJulian Elischer struct ng_mesg *msg = NULL; 432878ed226SJulian Elischer ng_l2cap_l2ca_con_ind_ip *ip = NULL; 433878ed226SJulian Elischer int error = 0; 434878ed226SJulian Elischer 435878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 436878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 437878ed226SJulian Elischer NG_L2CAP_ERR( 438878ed226SJulian Elischer "%s: %s - unable to send L2CA_ConnectInd message. " \ 439878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 440878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 441878ed226SJulian Elischer 442878ed226SJulian Elischer return (ENOTCONN); 443878ed226SJulian Elischer } 444878ed226SJulian Elischer 445878ed226SJulian Elischer /* Create and send L2CA_ConnectInd message */ 446878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_IND, 447878ed226SJulian Elischer sizeof(*ip), M_NOWAIT); 448878ed226SJulian Elischer if (msg == NULL) 449878ed226SJulian Elischer error = ENOMEM; 450878ed226SJulian Elischer else { 451878ed226SJulian Elischer ip = (ng_l2cap_l2ca_con_ind_ip *)(msg->data); 452878ed226SJulian Elischer 453878ed226SJulian Elischer bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr)); 454878ed226SJulian Elischer ip->lcid = ch->scid; 455878ed226SJulian Elischer ip->psm = ch->psm; 456878ed226SJulian Elischer ip->ident = ch->ident; 45799043514STakanori Watanabe ip->linktype = ch->con->linktype; 458*3a601a23STakanori Watanabe 4594ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 460878ed226SJulian Elischer } 461878ed226SJulian Elischer 462878ed226SJulian Elischer return (error); 463878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_ind */ 464878ed226SJulian Elischer 465878ed226SJulian Elischer /* 466878ed226SJulian Elischer * Process L2CA_Config request from the upper layer protocol 467878ed226SJulian Elischer */ 468878ed226SJulian Elischer 469878ed226SJulian Elischer int 470878ed226SJulian Elischer ng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 471878ed226SJulian Elischer { 472878ed226SJulian Elischer ng_l2cap_l2ca_cfg_ip *ip = NULL; 473878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL; 474878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 475878ed226SJulian Elischer struct mbuf *opt = NULL; 476878ed226SJulian Elischer u_int16_t *mtu = NULL, *flush_timo = NULL; 477878ed226SJulian Elischer ng_l2cap_flow_p flow = NULL; 478878ed226SJulian Elischer int error = 0; 479878ed226SJulian Elischer 480878ed226SJulian Elischer /* Check message */ 481878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) { 482878ed226SJulian Elischer NG_L2CAP_ALERT( 483878ed226SJulian Elischer "%s: %s - Invalid L2CA_Config request message size, size=%d\n", 484878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), 485878ed226SJulian Elischer msg->header.arglen); 486878ed226SJulian Elischer error = EMSGSIZE; 487878ed226SJulian Elischer goto out; 488878ed226SJulian Elischer } 489878ed226SJulian Elischer 490878ed226SJulian Elischer ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data); 491878ed226SJulian Elischer 492878ed226SJulian Elischer /* Check if we have this channel */ 493fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, NG_L2CAP_L2CA_IDTYPE_BREDR); 494878ed226SJulian Elischer if (ch == NULL) { 495878ed226SJulian Elischer NG_L2CAP_ERR( 496878ed226SJulian Elischer "%s: %s - unexpected L2CA_Config request message. " \ 497878ed226SJulian Elischer "Channel does not exist, lcid=%d\n", 498878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 499878ed226SJulian Elischer error = ENOENT; 500878ed226SJulian Elischer goto out; 501878ed226SJulian Elischer } 502878ed226SJulian Elischer 503878ed226SJulian Elischer /* Check channel state */ 504878ed226SJulian Elischer if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG) { 505878ed226SJulian Elischer NG_L2CAP_ERR( 506878ed226SJulian Elischer "%s: %s - unexpected L2CA_Config request message. " \ 507878ed226SJulian Elischer "Invalid channel state, state=%d, lcid=%d\n", 508878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->state, 509878ed226SJulian Elischer ch->scid); 510878ed226SJulian Elischer error = EINVAL; 511878ed226SJulian Elischer goto out; 512878ed226SJulian Elischer } 513878ed226SJulian Elischer 514878ed226SJulian Elischer /* Set requested channel configuration options */ 515878ed226SJulian Elischer ch->imtu = ip->imtu; 516878ed226SJulian Elischer bcopy(&ip->oflow, &ch->oflow, sizeof(ch->oflow)); 517878ed226SJulian Elischer ch->flush_timo = ip->flush_timo; 518878ed226SJulian Elischer ch->link_timo = ip->link_timo; 519878ed226SJulian Elischer 520878ed226SJulian Elischer /* Compare channel settings with defaults */ 521878ed226SJulian Elischer if (ch->imtu != NG_L2CAP_MTU_DEFAULT) 522878ed226SJulian Elischer mtu = &ch->imtu; 523878ed226SJulian Elischer if (ch->flush_timo != NG_L2CAP_FLUSH_TIMO_DEFAULT) 524878ed226SJulian Elischer flush_timo = &ch->flush_timo; 525878ed226SJulian Elischer if (bcmp(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)) != 0) 526878ed226SJulian Elischer flow = &ch->oflow; 527878ed226SJulian Elischer 528878ed226SJulian Elischer /* Create configuration options */ 529878ed226SJulian Elischer _ng_l2cap_build_cfg_options(opt, mtu, flush_timo, flow); 530878ed226SJulian Elischer if (opt == NULL) { 531878ed226SJulian Elischer error = ENOBUFS; 532878ed226SJulian Elischer goto out; 533878ed226SJulian Elischer } 534878ed226SJulian Elischer 535878ed226SJulian Elischer /* Create L2CAP command descriptor */ 536878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con), 537878ed226SJulian Elischer NG_L2CAP_CFG_REQ, msg->header.token); 538878ed226SJulian Elischer if (cmd == NULL) { 539878ed226SJulian Elischer NG_FREE_M(opt); 540878ed226SJulian Elischer error = ENOMEM; 541878ed226SJulian Elischer goto out; 542878ed226SJulian Elischer } 543878ed226SJulian Elischer 544878ed226SJulian Elischer if (cmd->ident == NG_L2CAP_NULL_IDENT) { 545878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 546878ed226SJulian Elischer NG_FREE_M(opt); 547878ed226SJulian Elischer error = EIO; 548878ed226SJulian Elischer goto out; 549878ed226SJulian Elischer } 550878ed226SJulian Elischer 551878ed226SJulian Elischer /* Create L2CAP command packet */ 552878ed226SJulian Elischer _ng_l2cap_cfg_req(cmd->aux, cmd->ident, ch->dcid, 0, opt); 553878ed226SJulian Elischer if (cmd->aux == NULL) { 554878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 555878ed226SJulian Elischer error = ENOBUFS; 556878ed226SJulian Elischer goto out; 557878ed226SJulian Elischer } 558878ed226SJulian Elischer 559878ed226SJulian Elischer /* Adjust channel state for re-configuration */ 560878ed226SJulian Elischer if (ch->state == NG_L2CAP_OPEN) { 561*3a601a23STakanori Watanabe ch->state = ((ch->scid == NG_L2CAP_ATT_CID)|| 562*3a601a23STakanori Watanabe (ch->scid == NG_L2CAP_SMP_CID))? 563fbc48c2bSTakanori Watanabe NG_L2CAP_OPEN : NG_L2CAP_CONFIG; 564878ed226SJulian Elischer ch->cfg_state = 0; 565878ed226SJulian Elischer } 566878ed226SJulian Elischer 567878ed226SJulian Elischer /* Link command to the queue */ 568878ed226SJulian Elischer ng_l2cap_link_cmd(ch->con, cmd); 569878ed226SJulian Elischer ng_l2cap_lp_deliver(ch->con); 570878ed226SJulian Elischer out: 571878ed226SJulian Elischer return (error); 572878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_req */ 573878ed226SJulian Elischer 574878ed226SJulian Elischer /* 575878ed226SJulian Elischer * Send L2CA_Config response to the upper layer protocol 576878ed226SJulian Elischer */ 577878ed226SJulian Elischer 578878ed226SJulian Elischer int 579878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 580878ed226SJulian Elischer { 581878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 582878ed226SJulian Elischer struct ng_mesg *msg = NULL; 583878ed226SJulian Elischer ng_l2cap_l2ca_cfg_op *op = NULL; 584878ed226SJulian Elischer int error = 0; 585878ed226SJulian Elischer 586878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 587878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 588878ed226SJulian Elischer NG_L2CAP_ERR( 589878ed226SJulian Elischer "%s: %s - unable to send L2CA_Config response message. " \ 590878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 591878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 592878ed226SJulian Elischer 593878ed226SJulian Elischer return (ENOTCONN); 594878ed226SJulian Elischer } 595878ed226SJulian Elischer 596878ed226SJulian Elischer /* Create and send L2CA_Config response message */ 597878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG, 598878ed226SJulian Elischer sizeof(*op), M_NOWAIT); 599878ed226SJulian Elischer if (msg == NULL) 600878ed226SJulian Elischer error = ENOMEM; 601878ed226SJulian Elischer else { 602878ed226SJulian Elischer msg->header.token = token; 603878ed226SJulian Elischer msg->header.flags |= NGF_RESP; 604878ed226SJulian Elischer 605878ed226SJulian Elischer op = (ng_l2cap_l2ca_cfg_op *)(msg->data); 606878ed226SJulian Elischer op->result = result; 607878ed226SJulian Elischer op->imtu = ch->imtu; 608878ed226SJulian Elischer bcopy(&ch->oflow, &op->oflow, sizeof(op->oflow)); 609878ed226SJulian Elischer op->flush_timo = ch->flush_timo; 610878ed226SJulian Elischer 6114ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 612878ed226SJulian Elischer 613878ed226SJulian Elischer if (error == 0 && result == NG_L2CAP_SUCCESS) { 614878ed226SJulian Elischer ch->cfg_state |= NG_L2CAP_CFG_IN; 615878ed226SJulian Elischer 616878ed226SJulian Elischer if (ch->cfg_state == NG_L2CAP_CFG_BOTH) 617878ed226SJulian Elischer ch->state = NG_L2CAP_OPEN; 618878ed226SJulian Elischer } 619878ed226SJulian Elischer } 620878ed226SJulian Elischer 621878ed226SJulian Elischer return (error); 622878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_rsp */ 623878ed226SJulian Elischer 624878ed226SJulian Elischer /* 625878ed226SJulian Elischer * Process L2CA_ConfigRsp request from the upper layer protocol 626878ed226SJulian Elischer * 627878ed226SJulian Elischer * XXX XXX XXX 628878ed226SJulian Elischer * 629878ed226SJulian Elischer * NOTE: The Bluetooth specification says that Configuration_Response 630878ed226SJulian Elischer * (L2CA_ConfigRsp) should be used to issue response to configuration request 631878ed226SJulian Elischer * indication. The minor problem here is L2CAP command ident. We should use 632878ed226SJulian Elischer * ident from original L2CAP request to make sure our peer can match request 633878ed226SJulian Elischer * and response. For some reason Bluetooth specification does not include 634878ed226SJulian Elischer * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems 635878ed226SJulian Elischer * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident 636878ed226SJulian Elischer * field. So we should store last known L2CAP request command ident in channel. 637878ed226SJulian Elischer * Also it seems that upper layer can not reject configuration request, as 638878ed226SJulian Elischer * Configuration_Response message does not have status/reason field. 639878ed226SJulian Elischer */ 640878ed226SJulian Elischer 641878ed226SJulian Elischer int 642878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 643878ed226SJulian Elischer { 644878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp_ip *ip = NULL; 645878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL; 646878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 647878ed226SJulian Elischer struct mbuf *opt = NULL; 648878ed226SJulian Elischer u_int16_t *mtu = NULL; 649878ed226SJulian Elischer ng_l2cap_flow_p flow = NULL; 650878ed226SJulian Elischer int error = 0; 651878ed226SJulian Elischer 652878ed226SJulian Elischer /* Check message */ 653878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) { 654878ed226SJulian Elischer NG_L2CAP_ALERT( 655878ed226SJulian Elischer "%s: %s - invalid L2CA_ConfigRsp request message size, size=%d\n", 656878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), 657878ed226SJulian Elischer msg->header.arglen); 658878ed226SJulian Elischer error = EMSGSIZE; 659878ed226SJulian Elischer goto out; 660878ed226SJulian Elischer } 661878ed226SJulian Elischer 662878ed226SJulian Elischer ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data); 663878ed226SJulian Elischer 664878ed226SJulian Elischer /* Check if we have this channel */ 665fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, 666fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR); 667878ed226SJulian Elischer if (ch == NULL) { 668878ed226SJulian Elischer NG_L2CAP_ERR( 669878ed226SJulian Elischer "%s: %s - unexpected L2CA_ConfigRsp request message. " \ 670878ed226SJulian Elischer "Channel does not exist, lcid=%d\n", 671878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 672878ed226SJulian Elischer error = ENOENT; 673878ed226SJulian Elischer goto out; 674878ed226SJulian Elischer } 675878ed226SJulian Elischer 676878ed226SJulian Elischer /* Check channel state */ 677878ed226SJulian Elischer if (ch->state != NG_L2CAP_CONFIG) { 678878ed226SJulian Elischer NG_L2CAP_ERR( 679878ed226SJulian Elischer "%s: %s - unexpected L2CA_ConfigRsp request message. " \ 680878ed226SJulian Elischer "Invalid channel state, state=%d, lcid=%d\n", 681878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->state, 682878ed226SJulian Elischer ch->scid); 683878ed226SJulian Elischer error = EINVAL; 684878ed226SJulian Elischer goto out; 685878ed226SJulian Elischer } 686878ed226SJulian Elischer 687878ed226SJulian Elischer /* Set channel settings */ 688878ed226SJulian Elischer if (ip->omtu != ch->omtu) { 689878ed226SJulian Elischer ch->omtu = ip->omtu; 690878ed226SJulian Elischer mtu = &ch->omtu; 691878ed226SJulian Elischer } 692878ed226SJulian Elischer 693878ed226SJulian Elischer if (bcmp(&ip->iflow, &ch->iflow, sizeof(ch->iflow)) != 0) { 694878ed226SJulian Elischer bcopy(&ip->iflow, &ch->iflow, sizeof(ch->iflow)); 695878ed226SJulian Elischer flow = &ch->iflow; 696878ed226SJulian Elischer } 697878ed226SJulian Elischer 698878ed226SJulian Elischer if (mtu != NULL || flow != NULL) { 699878ed226SJulian Elischer _ng_l2cap_build_cfg_options(opt, mtu, NULL, flow); 700878ed226SJulian Elischer if (opt == NULL) { 701878ed226SJulian Elischer error = ENOBUFS; 702878ed226SJulian Elischer goto out; 703878ed226SJulian Elischer } 704878ed226SJulian Elischer } 705878ed226SJulian Elischer 706878ed226SJulian Elischer /* Create L2CAP command */ 707878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(ch->con, ch, ch->ident, NG_L2CAP_CFG_RSP, 708878ed226SJulian Elischer msg->header.token); 709878ed226SJulian Elischer if (cmd == NULL) { 710878ed226SJulian Elischer NG_FREE_M(opt); 711878ed226SJulian Elischer error = ENOMEM; 712878ed226SJulian Elischer goto out; 713878ed226SJulian Elischer } 714878ed226SJulian Elischer 715878ed226SJulian Elischer _ng_l2cap_cfg_rsp(cmd->aux,cmd->ident,ch->dcid,0,NG_L2CAP_SUCCESS,opt); 716878ed226SJulian Elischer if (cmd->aux == NULL) { 717878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 718878ed226SJulian Elischer error = ENOBUFS; 719878ed226SJulian Elischer goto out; 720878ed226SJulian Elischer } 721878ed226SJulian Elischer 722878ed226SJulian Elischer /* XXX FIXME - not here ??? */ 723878ed226SJulian Elischer ch->cfg_state |= NG_L2CAP_CFG_OUT; 724878ed226SJulian Elischer if (ch->cfg_state == NG_L2CAP_CFG_BOTH) 725878ed226SJulian Elischer ch->state = NG_L2CAP_OPEN; 726878ed226SJulian Elischer 727878ed226SJulian Elischer /* Link command to the queue */ 728878ed226SJulian Elischer ng_l2cap_link_cmd(ch->con, cmd); 729878ed226SJulian Elischer ng_l2cap_lp_deliver(ch->con); 730878ed226SJulian Elischer out: 731878ed226SJulian Elischer return (error); 732878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_rsp_req */ 733878ed226SJulian Elischer 734878ed226SJulian Elischer /* 735878ed226SJulian Elischer * Send L2CA_ConfigRsp response to the upper layer protocol 736878ed226SJulian Elischer */ 737878ed226SJulian Elischer 738878ed226SJulian Elischer int 739878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 740878ed226SJulian Elischer { 741878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 742878ed226SJulian Elischer struct ng_mesg *msg = NULL; 743878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp_op *op = NULL; 744878ed226SJulian Elischer int error = 0; 745878ed226SJulian Elischer 746878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 747878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 748878ed226SJulian Elischer NG_L2CAP_ERR( 749878ed226SJulian Elischer "%s: %s - unable to send L2CA_ConfigRsp response message. " \ 750878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 751878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 752878ed226SJulian Elischer 753878ed226SJulian Elischer return (ENOTCONN); 754878ed226SJulian Elischer } 755878ed226SJulian Elischer 756878ed226SJulian Elischer /* Create and send L2CA_ConfigRsp response message */ 757878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP, 758878ed226SJulian Elischer sizeof(*op), M_NOWAIT); 759878ed226SJulian Elischer if (msg == NULL) 760878ed226SJulian Elischer error = ENOMEM; 761878ed226SJulian Elischer else { 762878ed226SJulian Elischer msg->header.token = token; 763878ed226SJulian Elischer msg->header.flags |= NGF_RESP; 764878ed226SJulian Elischer 765878ed226SJulian Elischer op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data); 766878ed226SJulian Elischer op->result = result; 767878ed226SJulian Elischer 7684ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 769878ed226SJulian Elischer } 770878ed226SJulian Elischer 771878ed226SJulian Elischer return (error); 772878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_rsp_rsp */ 773878ed226SJulian Elischer 774878ed226SJulian Elischer /* 775878ed226SJulian Elischer * Send L2CA_ConfigInd message to the upper layer protocol 776878ed226SJulian Elischer * 777878ed226SJulian Elischer * XXX XXX XXX 778878ed226SJulian Elischer * 779878ed226SJulian Elischer * NOTE: The Bluetooth specification says that Configuration_Response 780878ed226SJulian Elischer * (L2CA_ConfigRsp) should be used to issue response to configuration request 781878ed226SJulian Elischer * indication. The minor problem here is L2CAP command ident. We should use 782878ed226SJulian Elischer * ident from original L2CAP request to make sure our peer can match request 783878ed226SJulian Elischer * and response. For some reason Bluetooth specification does not include 784878ed226SJulian Elischer * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems 785878ed226SJulian Elischer * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident 786878ed226SJulian Elischer * field. So we should store last known L2CAP request command ident in channel. 787878ed226SJulian Elischer * Also it seems that upper layer can not reject configuration request, as 788878ed226SJulian Elischer * Configuration_Response message does not have status/reason field. 789878ed226SJulian Elischer */ 790878ed226SJulian Elischer 791878ed226SJulian Elischer int 792878ed226SJulian Elischer ng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch) 793878ed226SJulian Elischer { 794878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 795878ed226SJulian Elischer struct ng_mesg *msg = NULL; 796878ed226SJulian Elischer ng_l2cap_l2ca_cfg_ind_ip *ip = NULL; 797878ed226SJulian Elischer int error = 0; 798878ed226SJulian Elischer 799878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 800878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 801878ed226SJulian Elischer NG_L2CAP_ERR( 802878ed226SJulian Elischer "%s: %s - Unable to send L2CA_ConfigInd message. " \ 803878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 804878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 805878ed226SJulian Elischer 806878ed226SJulian Elischer return (ENOTCONN); 807878ed226SJulian Elischer } 808878ed226SJulian Elischer 809878ed226SJulian Elischer /* Create and send L2CA_ConnectInd message */ 810878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_IND, 811878ed226SJulian Elischer sizeof(*ip), M_NOWAIT); 812878ed226SJulian Elischer if (msg == NULL) 813878ed226SJulian Elischer error = ENOMEM; 814878ed226SJulian Elischer else { 815878ed226SJulian Elischer ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data); 816878ed226SJulian Elischer ip->lcid = ch->scid; 817878ed226SJulian Elischer ip->omtu = ch->omtu; 818878ed226SJulian Elischer bcopy(&ch->iflow, &ip->iflow, sizeof(ip->iflow)); 819878ed226SJulian Elischer ip->flush_timo = ch->flush_timo; 820878ed226SJulian Elischer 8214ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 822878ed226SJulian Elischer } 823878ed226SJulian Elischer 824878ed226SJulian Elischer return (error); 825878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_ind */ 826878ed226SJulian Elischer 827878ed226SJulian Elischer /* 828878ed226SJulian Elischer * Process L2CA_Write event 829878ed226SJulian Elischer */ 830878ed226SJulian Elischer 831878ed226SJulian Elischer int 832878ed226SJulian Elischer ng_l2cap_l2ca_write_req(ng_l2cap_p l2cap, struct mbuf *m) 833878ed226SJulian Elischer { 834878ed226SJulian Elischer ng_l2cap_l2ca_hdr_t *l2ca_hdr = NULL; 835878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL; 836878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 837878ed226SJulian Elischer int error = 0; 838878ed226SJulian Elischer u_int32_t token = 0; 839878ed226SJulian Elischer 840878ed226SJulian Elischer /* Make sure we can access L2CA data packet header */ 841878ed226SJulian Elischer if (m->m_pkthdr.len < sizeof(*l2ca_hdr)) { 842878ed226SJulian Elischer NG_L2CAP_ERR( 843878ed226SJulian Elischer "%s: %s - L2CA Data packet too small, len=%d\n", 844878ed226SJulian Elischer __func__,NG_NODE_NAME(l2cap->node),m->m_pkthdr.len); 845878ed226SJulian Elischer error = EMSGSIZE; 846878ed226SJulian Elischer goto drop; 847878ed226SJulian Elischer } 848878ed226SJulian Elischer 849878ed226SJulian Elischer /* Get L2CA data packet header */ 850878ed226SJulian Elischer NG_L2CAP_M_PULLUP(m, sizeof(*l2ca_hdr)); 851878ed226SJulian Elischer if (m == NULL) 852878ed226SJulian Elischer return (ENOBUFS); 853878ed226SJulian Elischer 854878ed226SJulian Elischer l2ca_hdr = mtod(m, ng_l2cap_l2ca_hdr_t *); 855878ed226SJulian Elischer token = l2ca_hdr->token; 856878ed226SJulian Elischer m_adj(m, sizeof(*l2ca_hdr)); 857878ed226SJulian Elischer 858878ed226SJulian Elischer /* Verify payload size */ 859878ed226SJulian Elischer if (l2ca_hdr->length != m->m_pkthdr.len) { 860878ed226SJulian Elischer NG_L2CAP_ERR( 861878ed226SJulian Elischer "%s: %s - invalid L2CA Data packet. " \ 862878ed226SJulian Elischer "Payload length does not match, length=%d, len=%d\n", 863878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->length, 864878ed226SJulian Elischer m->m_pkthdr.len); 865878ed226SJulian Elischer error = EMSGSIZE; 866878ed226SJulian Elischer goto drop; 867878ed226SJulian Elischer } 868878ed226SJulian Elischer 869878ed226SJulian Elischer /* Check channel ID */ 870fbc48c2bSTakanori Watanabe if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){ 871fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID, 872fbc48c2bSTakanori Watanabe l2ca_hdr->lcid); 873*3a601a23STakanori Watanabe } else if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){ 874*3a601a23STakanori Watanabe ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID, 875*3a601a23STakanori Watanabe l2ca_hdr->lcid); 876fbc48c2bSTakanori Watanabe }else{ 877878ed226SJulian Elischer if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) { 878878ed226SJulian Elischer NG_L2CAP_ERR( 879878ed226SJulian Elischer "%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n", 880fbc48c2bSTakanori Watanabe __func__, NG_NODE_NAME(l2cap->node), 881fbc48c2bSTakanori Watanabe l2ca_hdr->lcid); 882878ed226SJulian Elischer error = EINVAL; 883878ed226SJulian Elischer goto drop; 884878ed226SJulian Elischer } 885878ed226SJulian Elischer 886878ed226SJulian Elischer /* Verify that we have the channel and make sure it is open */ 887fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid, 888fbc48c2bSTakanori Watanabe l2ca_hdr->idtype); 889fbc48c2bSTakanori Watanabe } 890fbc48c2bSTakanori Watanabe 891878ed226SJulian Elischer if (ch == NULL) { 892878ed226SJulian Elischer NG_L2CAP_ERR( 893878ed226SJulian Elischer "%s: %s - invalid L2CA Data packet. Channel does not exist, cid=%d\n", 894878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid); 895878ed226SJulian Elischer error = ENOENT; 896878ed226SJulian Elischer goto drop; 897878ed226SJulian Elischer } 898878ed226SJulian Elischer 899878ed226SJulian Elischer if (ch->state != NG_L2CAP_OPEN) { 900878ed226SJulian Elischer NG_L2CAP_ERR( 901878ed226SJulian Elischer "%s: %s - invalid L2CA Data packet. Invalid channel state, scid=%d, state=%d\n", 902878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->scid, 903878ed226SJulian Elischer ch->state); 904878ed226SJulian Elischer error = EHOSTDOWN; 905878ed226SJulian Elischer goto drop; /* XXX not always - re-configure */ 906878ed226SJulian Elischer } 907878ed226SJulian Elischer 908878ed226SJulian Elischer /* Create L2CAP command descriptor */ 909878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(ch->con, ch, 0, NGM_L2CAP_L2CA_WRITE, token); 910878ed226SJulian Elischer if (cmd == NULL) { 911878ed226SJulian Elischer error = ENOMEM; 912878ed226SJulian Elischer goto drop; 913878ed226SJulian Elischer } 914878ed226SJulian Elischer 915878ed226SJulian Elischer /* Attach data packet and link command to the queue */ 916878ed226SJulian Elischer cmd->aux = m; 917878ed226SJulian Elischer ng_l2cap_link_cmd(ch->con, cmd); 918878ed226SJulian Elischer ng_l2cap_lp_deliver(ch->con); 919878ed226SJulian Elischer 920878ed226SJulian Elischer return (error); 921878ed226SJulian Elischer drop: 922878ed226SJulian Elischer NG_FREE_M(m); 923878ed226SJulian Elischer 924878ed226SJulian Elischer return (error); 925878ed226SJulian Elischer } /* ng_l2cap_l2ca_write_req */ 926878ed226SJulian Elischer 927878ed226SJulian Elischer /* 928878ed226SJulian Elischer * Send L2CA_Write response 929878ed226SJulian Elischer */ 930878ed226SJulian Elischer 931878ed226SJulian Elischer int 932878ed226SJulian Elischer ng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result, 933878ed226SJulian Elischer u_int16_t length) 934878ed226SJulian Elischer { 935878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 936878ed226SJulian Elischer struct ng_mesg *msg = NULL; 937878ed226SJulian Elischer ng_l2cap_l2ca_write_op *op = NULL; 938878ed226SJulian Elischer int error = 0; 939878ed226SJulian Elischer 940878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 941878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 942878ed226SJulian Elischer NG_L2CAP_ERR( 943878ed226SJulian Elischer "%s: %s - unable to send L2CA_WriteRsp message. " \ 944878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 945878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 946878ed226SJulian Elischer 947878ed226SJulian Elischer return (ENOTCONN); 948878ed226SJulian Elischer } 949878ed226SJulian Elischer 950878ed226SJulian Elischer /* Create and send L2CA_WriteRsp message */ 951878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_WRITE, 952878ed226SJulian Elischer sizeof(*op), M_NOWAIT); 953878ed226SJulian Elischer if (msg == NULL) 954878ed226SJulian Elischer error = ENOMEM; 955878ed226SJulian Elischer else { 956878ed226SJulian Elischer msg->header.token = token; 957878ed226SJulian Elischer msg->header.flags |= NGF_RESP; 958878ed226SJulian Elischer 959878ed226SJulian Elischer op = (ng_l2cap_l2ca_write_op *)(msg->data); 960878ed226SJulian Elischer op->result = result; 961878ed226SJulian Elischer op->length = length; 962fbc48c2bSTakanori Watanabe if(ch->scid == NG_L2CAP_ATT_CID){ 963fbc48c2bSTakanori Watanabe op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT; 964fbc48c2bSTakanori Watanabe op->lcid = ch->con->con_handle; 965*3a601a23STakanori Watanabe }else if(ch->scid == NG_L2CAP_SMP_CID){ 966*3a601a23STakanori Watanabe op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP; 967*3a601a23STakanori Watanabe op->lcid = ch->con->con_handle; 968fbc48c2bSTakanori Watanabe }else{ 969fbc48c2bSTakanori Watanabe op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)? 970fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR : 971fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_LE; 972878ed226SJulian Elischer op->lcid = ch->scid; 973878ed226SJulian Elischer 974fbc48c2bSTakanori Watanabe } 9754ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 976878ed226SJulian Elischer } 977878ed226SJulian Elischer 978878ed226SJulian Elischer return (error); 979878ed226SJulian Elischer } /* ng_l2cap_l2ca_write_rsp */ 980878ed226SJulian Elischer 981878ed226SJulian Elischer /* 982878ed226SJulian Elischer * Receive packet from the lower layer protocol and send it to the upper 983878ed226SJulian Elischer * layer protocol (L2CAP_Read) 984878ed226SJulian Elischer */ 985878ed226SJulian Elischer 986878ed226SJulian Elischer int 987878ed226SJulian Elischer ng_l2cap_l2ca_receive(ng_l2cap_con_p con) 988878ed226SJulian Elischer { 989878ed226SJulian Elischer ng_l2cap_p l2cap = con->l2cap; 990878ed226SJulian Elischer ng_l2cap_hdr_t *hdr = NULL; 991878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL; 992878ed226SJulian Elischer int error = 0; 993fbc48c2bSTakanori Watanabe int idtype; 994fbc48c2bSTakanori Watanabe uint16_t *idp; 995*3a601a23STakanori Watanabe int silent = 0; 996878ed226SJulian Elischer 997878ed226SJulian Elischer NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr)); 998878ed226SJulian Elischer if (con->rx_pkt == NULL) 999878ed226SJulian Elischer return (ENOBUFS); 1000878ed226SJulian Elischer 1001878ed226SJulian Elischer hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *); 1002878ed226SJulian Elischer 1003878ed226SJulian Elischer /* Check channel */ 1004fbc48c2bSTakanori Watanabe 1005fbc48c2bSTakanori Watanabe if(hdr->dcid == NG_L2CAP_ATT_CID){ 1006fbc48c2bSTakanori Watanabe idtype = NG_L2CAP_L2CA_IDTYPE_ATT; 1007fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID, 1008fbc48c2bSTakanori Watanabe con->con_handle); 1009fbc48c2bSTakanori Watanabe /* 1010fbc48c2bSTakanori Watanabe * Here,ATT channel is distinguished by 1011fbc48c2bSTakanori Watanabe * connection handle 1012fbc48c2bSTakanori Watanabe */ 1013fbc48c2bSTakanori Watanabe hdr->dcid = con->con_handle; 1014*3a601a23STakanori Watanabe silent = 1; 1015*3a601a23STakanori Watanabe }else if(hdr->dcid == NG_L2CAP_SMP_CID){ 1016*3a601a23STakanori Watanabe idtype = NG_L2CAP_L2CA_IDTYPE_SMP; 1017*3a601a23STakanori Watanabe ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID, 1018*3a601a23STakanori Watanabe con->con_handle); 1019*3a601a23STakanori Watanabe /* 1020*3a601a23STakanori Watanabe * Here,SMP channel is distinguished by 1021*3a601a23STakanori Watanabe * connection handle 1022*3a601a23STakanori Watanabe */ 1023*3a601a23STakanori Watanabe silent = 1; 1024*3a601a23STakanori Watanabe hdr->dcid = con->con_handle; 1025fbc48c2bSTakanori Watanabe }else{ 1026fbc48c2bSTakanori Watanabe idtype = (con->linktype==NG_HCI_LINK_ACL)? 1027fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR: 1028fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_LE; 1029fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, hdr->dcid, idtype); 1030fbc48c2bSTakanori Watanabe } 1031878ed226SJulian Elischer if (ch == NULL) { 1032*3a601a23STakanori Watanabe if(!silent) 1033878ed226SJulian Elischer NG_L2CAP_ERR( 1034fbc48c2bSTakanori Watanabe "%s: %s - unexpected L2CAP data packet. Channel does not exist, cid=%d, idtype=%d\n", 1035fbc48c2bSTakanori Watanabe __func__, NG_NODE_NAME(l2cap->node), hdr->dcid, idtype); 1036878ed226SJulian Elischer error = ENOENT; 1037878ed226SJulian Elischer goto drop; 1038878ed226SJulian Elischer } 1039878ed226SJulian Elischer 1040878ed226SJulian Elischer /* Check channel state */ 1041878ed226SJulian Elischer if (ch->state != NG_L2CAP_OPEN) { 1042878ed226SJulian Elischer NG_L2CAP_WARN( 1043878ed226SJulian Elischer "%s: %s - unexpected L2CAP data packet. " \ 1044878ed226SJulian Elischer "Invalid channel state, cid=%d, state=%d\n", 1045878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->scid, 1046878ed226SJulian Elischer ch->state); 1047878ed226SJulian Elischer error = EHOSTDOWN; /* XXX not always - re-configuration */ 1048878ed226SJulian Elischer goto drop; 1049878ed226SJulian Elischer } 1050878ed226SJulian Elischer 1051878ed226SJulian Elischer /* Check payload size and channel's MTU */ 1052878ed226SJulian Elischer if (hdr->length > ch->imtu) { 1053878ed226SJulian Elischer NG_L2CAP_ERR( 1054878ed226SJulian Elischer "%s: %s - invalid L2CAP data packet. " \ 1055878ed226SJulian Elischer "Packet too big, length=%d, imtu=%d, cid=%d\n", 1056878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), hdr->length, 1057878ed226SJulian Elischer ch->imtu, ch->scid); 1058878ed226SJulian Elischer error = EMSGSIZE; 1059878ed226SJulian Elischer goto drop; 1060878ed226SJulian Elischer } 1061878ed226SJulian Elischer 1062878ed226SJulian Elischer /* 1063878ed226SJulian Elischer * If we got here then everything looks good and we can sent packet 1064878ed226SJulian Elischer * to the upper layer protocol. 1065878ed226SJulian Elischer */ 1066878ed226SJulian Elischer 1067878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 1068878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1069878ed226SJulian Elischer NG_L2CAP_ERR( 1070878ed226SJulian Elischer "%s: %s - unable to send L2CAP data packet. " \ 1071878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 1072878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1073878ed226SJulian Elischer error = ENOTCONN; 1074878ed226SJulian Elischer goto drop; 1075878ed226SJulian Elischer } 1076fbc48c2bSTakanori Watanabe M_PREPEND(con->rx_pkt, sizeof(uint16_t), M_NOWAIT); 1077fbc48c2bSTakanori Watanabe if(con->rx_pkt == NULL) 1078fbc48c2bSTakanori Watanabe goto drop; 1079fbc48c2bSTakanori Watanabe idp = mtod(con->rx_pkt, uint16_t *); 1080fbc48c2bSTakanori Watanabe *idp = idtype; 1081878ed226SJulian Elischer 1082878ed226SJulian Elischer NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt); 1083878ed226SJulian Elischer con->rx_pkt = NULL; 1084878ed226SJulian Elischer drop: 1085878ed226SJulian Elischer NG_FREE_M(con->rx_pkt); /* checks for != NULL */ 1086878ed226SJulian Elischer 1087878ed226SJulian Elischer return (error); 1088878ed226SJulian Elischer } /* ng_l2cap_receive */ 1089878ed226SJulian Elischer 1090878ed226SJulian Elischer /* 1091878ed226SJulian Elischer * Receive connectioless (multicast) packet from the lower layer protocol and 1092878ed226SJulian Elischer * send it to the upper layer protocol 1093878ed226SJulian Elischer */ 1094878ed226SJulian Elischer 1095878ed226SJulian Elischer int 1096878ed226SJulian Elischer ng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con) 1097878ed226SJulian Elischer { 1098878ed226SJulian Elischer struct _clt_pkt { 1099878ed226SJulian Elischer ng_l2cap_hdr_t h; 1100878ed226SJulian Elischer ng_l2cap_clt_hdr_t c_h; 1101878ed226SJulian Elischer } __attribute__ ((packed)) *hdr = NULL; 1102878ed226SJulian Elischer ng_l2cap_p l2cap = con->l2cap; 1103878ed226SJulian Elischer int length, error = 0; 1104878ed226SJulian Elischer 1105878ed226SJulian Elischer NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr)); 1106878ed226SJulian Elischer if (con->rx_pkt == NULL) 1107878ed226SJulian Elischer return (ENOBUFS); 1108878ed226SJulian Elischer 1109878ed226SJulian Elischer hdr = mtod(con->rx_pkt, struct _clt_pkt *); 1110878ed226SJulian Elischer 1111878ed226SJulian Elischer /* Check packet */ 1112878ed226SJulian Elischer length = con->rx_pkt->m_pkthdr.len - sizeof(*hdr); 1113878ed226SJulian Elischer if (length < 0) { 1114878ed226SJulian Elischer NG_L2CAP_ERR( 1115878ed226SJulian Elischer "%s: %s - invalid L2CAP CLT data packet. Packet too small, length=%d\n", 1116878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), length); 1117878ed226SJulian Elischer error = EMSGSIZE; 1118878ed226SJulian Elischer goto drop; 1119878ed226SJulian Elischer } 1120878ed226SJulian Elischer 1121878ed226SJulian Elischer /* Check payload size against CLT MTU */ 1122878ed226SJulian Elischer if (length > NG_L2CAP_MTU_DEFAULT) { 1123878ed226SJulian Elischer NG_L2CAP_ERR( 1124878ed226SJulian Elischer "%s: %s - invalid L2CAP CLT data packet. Packet too big, length=%d, mtu=%d\n", 1125878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), length, 1126878ed226SJulian Elischer NG_L2CAP_MTU_DEFAULT); 1127878ed226SJulian Elischer error = EMSGSIZE; 1128878ed226SJulian Elischer goto drop; 1129878ed226SJulian Elischer } 1130878ed226SJulian Elischer 1131878ed226SJulian Elischer hdr->c_h.psm = le16toh(hdr->c_h.psm); 1132878ed226SJulian Elischer 1133878ed226SJulian Elischer /* 1134878ed226SJulian Elischer * If we got here then everything looks good and we can sent packet 1135878ed226SJulian Elischer * to the upper layer protocol. 1136878ed226SJulian Elischer */ 1137878ed226SJulian Elischer 1138878ed226SJulian Elischer /* Select upstream hook based on PSM */ 1139878ed226SJulian Elischer switch (hdr->c_h.psm) { 1140878ed226SJulian Elischer case NG_L2CAP_PSM_SDP: 1141878ed226SJulian Elischer if (l2cap->flags & NG_L2CAP_CLT_SDP_DISABLED) 1142878ed226SJulian Elischer goto drop; 1143878ed226SJulian Elischer break; 1144878ed226SJulian Elischer 1145878ed226SJulian Elischer case NG_L2CAP_PSM_RFCOMM: 1146878ed226SJulian Elischer if (l2cap->flags & NG_L2CAP_CLT_RFCOMM_DISABLED) 1147878ed226SJulian Elischer goto drop; 1148878ed226SJulian Elischer break; 1149878ed226SJulian Elischer 1150878ed226SJulian Elischer case NG_L2CAP_PSM_TCP: 1151878ed226SJulian Elischer if (l2cap->flags & NG_L2CAP_CLT_TCP_DISABLED) 1152878ed226SJulian Elischer goto drop; 1153878ed226SJulian Elischer break; 1154878ed226SJulian Elischer } 1155878ed226SJulian Elischer 1156878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 1157878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1158878ed226SJulian Elischer NG_L2CAP_ERR( 1159878ed226SJulian Elischer "%s: %s - unable to send L2CAP CLT data packet. " \ 1160878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 1161878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), hdr->c_h.psm); 1162878ed226SJulian Elischer error = ENOTCONN; 1163878ed226SJulian Elischer goto drop; 1164878ed226SJulian Elischer } 1165878ed226SJulian Elischer 1166878ed226SJulian Elischer NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt); 1167878ed226SJulian Elischer con->rx_pkt = NULL; 1168878ed226SJulian Elischer drop: 1169878ed226SJulian Elischer NG_FREE_M(con->rx_pkt); /* checks for != NULL */ 1170878ed226SJulian Elischer 1171878ed226SJulian Elischer return (error); 1172878ed226SJulian Elischer } /* ng_l2cap_l2ca_clt_receive */ 1173878ed226SJulian Elischer 1174878ed226SJulian Elischer /* 1175878ed226SJulian Elischer * Send L2CA_QoSViolationInd to the upper layer protocol 1176878ed226SJulian Elischer */ 1177878ed226SJulian Elischer 1178878ed226SJulian Elischer int 1179878ed226SJulian Elischer ng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch) 1180878ed226SJulian Elischer { 1181878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 1182878ed226SJulian Elischer struct ng_mesg *msg = NULL; 1183878ed226SJulian Elischer ng_l2cap_l2ca_qos_ind_ip *ip = NULL; 1184878ed226SJulian Elischer int error = 0; 1185878ed226SJulian Elischer 1186878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 1187878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1188878ed226SJulian Elischer NG_L2CAP_ERR( 1189878ed226SJulian Elischer "%s: %s - unable to send L2CA_QoSViolationInd message. " \ 1190878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 1191878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1192878ed226SJulian Elischer 1193878ed226SJulian Elischer return (ENOTCONN); 1194878ed226SJulian Elischer } 1195878ed226SJulian Elischer 1196878ed226SJulian Elischer /* Create and send L2CA_QoSViolationInd message */ 1197878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_QOS_IND, 1198878ed226SJulian Elischer sizeof(*ip), M_NOWAIT); 1199878ed226SJulian Elischer if (msg == NULL) 1200878ed226SJulian Elischer error = ENOMEM; 1201878ed226SJulian Elischer else { 1202878ed226SJulian Elischer ip = (ng_l2cap_l2ca_qos_ind_ip *)(msg->data); 1203878ed226SJulian Elischer bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr)); 12044ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1205878ed226SJulian Elischer } 1206878ed226SJulian Elischer 1207878ed226SJulian Elischer return (error); 1208878ed226SJulian Elischer } /* ng_l2cap_l2ca_qos_ind */ 1209878ed226SJulian Elischer 1210878ed226SJulian Elischer /* 1211878ed226SJulian Elischer * Process L2CA_Disconnect request from the upper layer protocol. 1212878ed226SJulian Elischer */ 1213878ed226SJulian Elischer 1214878ed226SJulian Elischer int 1215878ed226SJulian Elischer ng_l2cap_l2ca_discon_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1216878ed226SJulian Elischer { 1217878ed226SJulian Elischer ng_l2cap_l2ca_discon_ip *ip = NULL; 1218878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL; 1219878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 1220878ed226SJulian Elischer int error = 0; 1221878ed226SJulian Elischer 1222878ed226SJulian Elischer /* Check message */ 1223878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) { 1224878ed226SJulian Elischer NG_L2CAP_ALERT( 1225878ed226SJulian Elischer "%s: %s - invalid L2CA_Disconnect request message size, size=%d\n", 1226878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), 1227878ed226SJulian Elischer msg->header.arglen); 1228878ed226SJulian Elischer error = EMSGSIZE; 1229878ed226SJulian Elischer goto out; 1230878ed226SJulian Elischer } 1231878ed226SJulian Elischer 1232878ed226SJulian Elischer ip = (ng_l2cap_l2ca_discon_ip *)(msg->data); 1233878ed226SJulian Elischer 1234fbc48c2bSTakanori Watanabe 1235fbc48c2bSTakanori Watanabe if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){ 1236fbc48c2bSTakanori Watanabe /* Don't send Disconnect request on L2CAP Layer*/ 1237fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID, 1238fbc48c2bSTakanori Watanabe ip->lcid); 1239fbc48c2bSTakanori Watanabe 1240fbc48c2bSTakanori Watanabe if(ch != NULL){ 1241fbc48c2bSTakanori Watanabe ng_l2cap_free_chan(ch); 1242fbc48c2bSTakanori Watanabe }else{ 1243fbc48c2bSTakanori Watanabe NG_L2CAP_ERR( 1244fbc48c2bSTakanori Watanabe "%s: %s - unexpected L2CA_Disconnect request message. " \ 1245fbc48c2bSTakanori Watanabe "Channel does not exist, conhandle=%d\n", 1246fbc48c2bSTakanori Watanabe __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 1247fbc48c2bSTakanori Watanabe error = EINVAL; 1248fbc48c2bSTakanori Watanabe } 1249fbc48c2bSTakanori Watanabe goto out; 1250*3a601a23STakanori Watanabe }else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){ 1251*3a601a23STakanori Watanabe /* Don't send Disconnect request on L2CAP Layer*/ 1252*3a601a23STakanori Watanabe ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID, 1253*3a601a23STakanori Watanabe ip->lcid); 1254*3a601a23STakanori Watanabe 1255*3a601a23STakanori Watanabe if(ch != NULL){ 1256*3a601a23STakanori Watanabe ng_l2cap_free_chan(ch); 1257*3a601a23STakanori Watanabe }else{ 1258*3a601a23STakanori Watanabe NG_L2CAP_ERR( 1259*3a601a23STakanori Watanabe "%s: %s - unexpected L2CA_Disconnect request message. " \ 1260*3a601a23STakanori Watanabe "Channel does not exist, conhandle=%d\n", 1261*3a601a23STakanori Watanabe __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 1262*3a601a23STakanori Watanabe error = EINVAL; 1263*3a601a23STakanori Watanabe } 1264*3a601a23STakanori Watanabe goto out; 1265fbc48c2bSTakanori Watanabe }else{ 1266878ed226SJulian Elischer /* Check if we have this channel */ 1267fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, ip->idtype); 1268fbc48c2bSTakanori Watanabe } 1269878ed226SJulian Elischer if (ch == NULL) { 1270878ed226SJulian Elischer NG_L2CAP_ERR( 1271878ed226SJulian Elischer "%s: %s - unexpected L2CA_Disconnect request message. " \ 1272878ed226SJulian Elischer "Channel does not exist, lcid=%d\n", 1273878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 1274878ed226SJulian Elischer error = ENOENT; 1275878ed226SJulian Elischer goto out; 1276878ed226SJulian Elischer } 1277878ed226SJulian Elischer 1278878ed226SJulian Elischer /* Check channel state */ 1279878ed226SJulian Elischer if (ch->state != NG_L2CAP_CONFIG && ch->state != NG_L2CAP_OPEN && 1280878ed226SJulian Elischer ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) { 1281878ed226SJulian Elischer NG_L2CAP_ERR( 1282878ed226SJulian Elischer "%s: %s - unexpected L2CA_Disconnect request message. " \ 1283878ed226SJulian Elischer "Invalid channel state, state=%d, lcid=%d\n", 1284878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->state, 1285878ed226SJulian Elischer ch->scid); 1286878ed226SJulian Elischer error = EINVAL; 1287878ed226SJulian Elischer goto out; 1288878ed226SJulian Elischer } 1289878ed226SJulian Elischer 1290878ed226SJulian Elischer /* Create and send L2CAP_DisconReq message */ 1291878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con), 1292878ed226SJulian Elischer NG_L2CAP_DISCON_REQ, msg->header.token); 1293878ed226SJulian Elischer if (cmd == NULL) { 1294878ed226SJulian Elischer ng_l2cap_free_chan(ch); 1295878ed226SJulian Elischer error = ENOMEM; 1296878ed226SJulian Elischer goto out; 1297878ed226SJulian Elischer } 1298878ed226SJulian Elischer 1299878ed226SJulian Elischer if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1300878ed226SJulian Elischer ng_l2cap_free_chan(ch); 1301878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 1302878ed226SJulian Elischer error = EIO; 1303878ed226SJulian Elischer goto out; 1304878ed226SJulian Elischer } 1305878ed226SJulian Elischer 1306878ed226SJulian Elischer _ng_l2cap_discon_req(cmd->aux, cmd->ident, ch->dcid, ch->scid); 1307878ed226SJulian Elischer if (cmd->aux == NULL) { 1308878ed226SJulian Elischer ng_l2cap_free_chan(ch); 1309878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 1310878ed226SJulian Elischer error = ENOBUFS; 1311878ed226SJulian Elischer goto out; 1312878ed226SJulian Elischer } 1313878ed226SJulian Elischer 1314878ed226SJulian Elischer ch->state = NG_L2CAP_W4_L2CAP_DISCON_RSP; 1315878ed226SJulian Elischer 1316878ed226SJulian Elischer /* Link command to the queue */ 1317878ed226SJulian Elischer ng_l2cap_link_cmd(ch->con, cmd); 1318878ed226SJulian Elischer ng_l2cap_lp_deliver(ch->con); 1319878ed226SJulian Elischer out: 1320878ed226SJulian Elischer return (error); 1321878ed226SJulian Elischer } /* ng_l2cap_l2ca_discon_req */ 1322878ed226SJulian Elischer 1323878ed226SJulian Elischer /* 1324878ed226SJulian Elischer * Send L2CA_Disconnect response to the upper layer protocol 1325878ed226SJulian Elischer */ 1326878ed226SJulian Elischer 1327878ed226SJulian Elischer int 1328878ed226SJulian Elischer ng_l2cap_l2ca_discon_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 1329878ed226SJulian Elischer { 1330878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 1331878ed226SJulian Elischer struct ng_mesg *msg = NULL; 1332878ed226SJulian Elischer ng_l2cap_l2ca_discon_op *op = NULL; 1333878ed226SJulian Elischer int error = 0; 1334878ed226SJulian Elischer 1335878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 1336878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1337878ed226SJulian Elischer NG_L2CAP_ERR( 1338878ed226SJulian Elischer "%s: %s - unable to send L2CA_Disconnect response message. " \ 1339878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 1340878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1341878ed226SJulian Elischer 1342878ed226SJulian Elischer return (ENOTCONN); 1343878ed226SJulian Elischer } 1344878ed226SJulian Elischer 1345878ed226SJulian Elischer /* Create and send L2CA_Disconnect response message */ 1346878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON, 1347878ed226SJulian Elischer sizeof(*op), M_NOWAIT); 1348878ed226SJulian Elischer if (msg == NULL) 1349878ed226SJulian Elischer error = ENOMEM; 1350878ed226SJulian Elischer else { 1351878ed226SJulian Elischer msg->header.token = token; 1352878ed226SJulian Elischer msg->header.flags |= NGF_RESP; 1353878ed226SJulian Elischer 1354878ed226SJulian Elischer op = (ng_l2cap_l2ca_discon_op *)(msg->data); 1355878ed226SJulian Elischer op->result = result; 1356878ed226SJulian Elischer 13574ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1358878ed226SJulian Elischer } 1359878ed226SJulian Elischer 1360878ed226SJulian Elischer return (error); 1361878ed226SJulian Elischer } /* ng_l2cap_l2ca_discon_rsp */ 1362878ed226SJulian Elischer 1363878ed226SJulian Elischer /* 1364878ed226SJulian Elischer * Send L2CA_DisconnectInd message to the upper layer protocol. 1365878ed226SJulian Elischer */ 1366878ed226SJulian Elischer 1367878ed226SJulian Elischer int 1368878ed226SJulian Elischer ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch) 1369878ed226SJulian Elischer { 1370878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap; 1371878ed226SJulian Elischer struct ng_mesg *msg = NULL; 1372878ed226SJulian Elischer ng_l2cap_l2ca_discon_ind_ip *ip = NULL; 1373878ed226SJulian Elischer int error = 0; 1374878ed226SJulian Elischer 1375878ed226SJulian Elischer /* Check if upstream hook is connected and valid */ 1376878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1377878ed226SJulian Elischer NG_L2CAP_ERR( 1378878ed226SJulian Elischer "%s: %s - unable to send L2CA_DisconnectInd message. " \ 1379878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n", 1380878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1381878ed226SJulian Elischer 1382878ed226SJulian Elischer return (ENOTCONN); 1383878ed226SJulian Elischer } 1384878ed226SJulian Elischer 1385878ed226SJulian Elischer /* Create and send L2CA_DisconnectInd message */ 1386878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND, 1387878ed226SJulian Elischer sizeof(*ip), M_NOWAIT); 1388878ed226SJulian Elischer if (msg == NULL) 1389878ed226SJulian Elischer error = ENOMEM; 1390878ed226SJulian Elischer else { 1391878ed226SJulian Elischer ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data); 1392878ed226SJulian Elischer ip->lcid = ch->scid; 13934ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1394878ed226SJulian Elischer } 1395878ed226SJulian Elischer 1396878ed226SJulian Elischer return (error); 1397878ed226SJulian Elischer } /* ng_l2cap_l2ca_discon_ind */ 1398878ed226SJulian Elischer 1399878ed226SJulian Elischer /* 1400878ed226SJulian Elischer * Process L2CA_GroupCreate request from the upper layer protocol. 1401878ed226SJulian Elischer * XXX FIXME 1402878ed226SJulian Elischer */ 1403878ed226SJulian Elischer 1404878ed226SJulian Elischer int 1405878ed226SJulian Elischer ng_l2cap_l2ca_grp_create(ng_l2cap_p l2cap, struct ng_mesg *msg) 1406878ed226SJulian Elischer { 1407878ed226SJulian Elischer return (ENOTSUP); 1408878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_create */ 1409878ed226SJulian Elischer 1410878ed226SJulian Elischer /* 1411878ed226SJulian Elischer * Process L2CA_GroupClose request from the upper layer protocol 1412878ed226SJulian Elischer * XXX FIXME 1413878ed226SJulian Elischer */ 1414878ed226SJulian Elischer 1415878ed226SJulian Elischer int 1416878ed226SJulian Elischer ng_l2cap_l2ca_grp_close(ng_l2cap_p l2cap, struct ng_mesg *msg) 1417878ed226SJulian Elischer { 1418878ed226SJulian Elischer return (ENOTSUP); 1419878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_close */ 1420878ed226SJulian Elischer 1421878ed226SJulian Elischer /* 1422878ed226SJulian Elischer * Process L2CA_GroupAddMember request from the upper layer protocol. 1423878ed226SJulian Elischer * XXX FIXME 1424878ed226SJulian Elischer */ 1425878ed226SJulian Elischer 1426878ed226SJulian Elischer int 1427878ed226SJulian Elischer ng_l2cap_l2ca_grp_add_member_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1428878ed226SJulian Elischer { 1429878ed226SJulian Elischer return (ENOTSUP); 1430878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_add_member_req */ 1431878ed226SJulian Elischer 1432878ed226SJulian Elischer /* 1433878ed226SJulian Elischer * Send L2CA_GroupAddMember response to the upper layer protocol. 1434878ed226SJulian Elischer * XXX FIXME 1435878ed226SJulian Elischer */ 1436878ed226SJulian Elischer 1437878ed226SJulian Elischer int 1438878ed226SJulian Elischer ng_l2cap_l2ca_grp_add_member_rsp(ng_l2cap_chan_p ch, u_int32_t token, 1439878ed226SJulian Elischer u_int16_t result) 1440878ed226SJulian Elischer { 1441878ed226SJulian Elischer return (0); 1442878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_add_member_rsp */ 1443878ed226SJulian Elischer 1444878ed226SJulian Elischer /* 1445878ed226SJulian Elischer * Process L2CA_GroupDeleteMember request from the upper layer protocol 1446878ed226SJulian Elischer * XXX FIXME 1447878ed226SJulian Elischer */ 1448878ed226SJulian Elischer 1449878ed226SJulian Elischer int 1450878ed226SJulian Elischer ng_l2cap_l2ca_grp_rem_member(ng_l2cap_p l2cap, struct ng_mesg *msg) 1451878ed226SJulian Elischer { 1452878ed226SJulian Elischer return (ENOTSUP); 1453878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_rem_member */ 1454878ed226SJulian Elischer 1455878ed226SJulian Elischer /* 1456878ed226SJulian Elischer * Process L2CA_GroupGetMembers request from the upper layer protocol 1457878ed226SJulian Elischer * XXX FIXME 1458878ed226SJulian Elischer */ 1459878ed226SJulian Elischer 1460878ed226SJulian Elischer int 1461878ed226SJulian Elischer ng_l2cap_l2ca_grp_get_members(ng_l2cap_p l2cap, struct ng_mesg *msg) 1462878ed226SJulian Elischer { 1463878ed226SJulian Elischer return (ENOTSUP); 1464878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_get_members */ 1465878ed226SJulian Elischer 1466878ed226SJulian Elischer /* 1467878ed226SJulian Elischer * Process L2CA_Ping request from the upper layer protocol 1468878ed226SJulian Elischer */ 1469878ed226SJulian Elischer 1470878ed226SJulian Elischer int 1471878ed226SJulian Elischer ng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1472878ed226SJulian Elischer { 1473878ed226SJulian Elischer ng_l2cap_l2ca_ping_ip *ip = NULL; 1474878ed226SJulian Elischer ng_l2cap_con_p con = NULL; 1475878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 1476878ed226SJulian Elischer int error = 0; 1477878ed226SJulian Elischer 1478878ed226SJulian Elischer /* Verify message */ 1479878ed226SJulian Elischer if (msg->header.arglen < sizeof(*ip)) { 1480878ed226SJulian Elischer NG_L2CAP_ALERT( 1481878ed226SJulian Elischer "%s: %s - invalid L2CA_Ping request message size, size=%d\n", 1482878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), 1483878ed226SJulian Elischer msg->header.arglen); 1484878ed226SJulian Elischer error = EMSGSIZE; 1485878ed226SJulian Elischer goto out; 1486878ed226SJulian Elischer } 1487878ed226SJulian Elischer 1488878ed226SJulian Elischer ip = (ng_l2cap_l2ca_ping_ip *)(msg->data); 1489878ed226SJulian Elischer if (ip->echo_size > NG_L2CAP_MAX_ECHO_SIZE) { 1490878ed226SJulian Elischer NG_L2CAP_WARN( 1491878ed226SJulian Elischer "%s: %s - invalid L2CA_Ping request. Echo size is too big, echo_size=%d\n", 1492878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ip->echo_size); 1493878ed226SJulian Elischer error = EMSGSIZE; 1494878ed226SJulian Elischer goto out; 1495878ed226SJulian Elischer } 1496878ed226SJulian Elischer 1497878ed226SJulian Elischer /* Check if we have connection to the unit */ 1498fbc48c2bSTakanori Watanabe con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL); 1499878ed226SJulian Elischer if (con == NULL) { 1500878ed226SJulian Elischer /* Submit LP_ConnectReq to the lower layer */ 1501fbc48c2bSTakanori Watanabe error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL); 1502878ed226SJulian Elischer if (error != 0) { 1503878ed226SJulian Elischer NG_L2CAP_ERR( 1504878ed226SJulian Elischer "%s: %s - unable to send LP_ConnectReq message, error=%d\n", 1505878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), error); 1506878ed226SJulian Elischer goto out; 1507878ed226SJulian Elischer } 1508878ed226SJulian Elischer 1509878ed226SJulian Elischer /* This should not fail */ 1510fbc48c2bSTakanori Watanabe con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL); 1511878ed226SJulian Elischer KASSERT((con != NULL), 1512878ed226SJulian Elischer ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node))); 1513878ed226SJulian Elischer } 1514878ed226SJulian Elischer 1515878ed226SJulian Elischer /* Create L2CAP command descriptor */ 1516878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con), 1517878ed226SJulian Elischer NG_L2CAP_ECHO_REQ, msg->header.token); 1518878ed226SJulian Elischer if (cmd == NULL) { 1519878ed226SJulian Elischer error = ENOMEM; 1520878ed226SJulian Elischer goto out; 1521878ed226SJulian Elischer } 1522878ed226SJulian Elischer 1523878ed226SJulian Elischer if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1524878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 1525878ed226SJulian Elischer error = EIO; 1526878ed226SJulian Elischer goto out; 1527878ed226SJulian Elischer } 1528878ed226SJulian Elischer 1529878ed226SJulian Elischer /* Create L2CAP command packet */ 1530878ed226SJulian Elischer _ng_l2cap_echo_req(cmd->aux, cmd->ident, 1531878ed226SJulian Elischer msg->data + sizeof(*ip), ip->echo_size); 1532878ed226SJulian Elischer if (cmd->aux == NULL) { 1533878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 1534878ed226SJulian Elischer error = ENOBUFS; 1535878ed226SJulian Elischer goto out; 1536878ed226SJulian Elischer } 1537878ed226SJulian Elischer 1538878ed226SJulian Elischer /* Link command to the queue */ 1539878ed226SJulian Elischer ng_l2cap_link_cmd(con, cmd); 1540878ed226SJulian Elischer ng_l2cap_lp_deliver(con); 1541878ed226SJulian Elischer out: 1542878ed226SJulian Elischer return (error); 1543878ed226SJulian Elischer } /* ng_l2cap_l2ca_ping_req */ 1544878ed226SJulian Elischer 1545878ed226SJulian Elischer /* 1546878ed226SJulian Elischer * Send L2CA_Ping response to the upper layer protocol 1547878ed226SJulian Elischer */ 1548878ed226SJulian Elischer 1549878ed226SJulian Elischer int 1550878ed226SJulian Elischer ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result, 1551878ed226SJulian Elischer struct mbuf *data) 1552878ed226SJulian Elischer { 1553878ed226SJulian Elischer ng_l2cap_p l2cap = con->l2cap; 1554878ed226SJulian Elischer struct ng_mesg *msg = NULL; 1555878ed226SJulian Elischer ng_l2cap_l2ca_ping_op *op = NULL; 1556878ed226SJulian Elischer int error = 0, size = 0; 1557878ed226SJulian Elischer 1558878ed226SJulian Elischer /* Check if control hook is connected and valid */ 1559878ed226SJulian Elischer if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) { 1560878ed226SJulian Elischer NG_L2CAP_WARN( 1561878ed226SJulian Elischer "%s: %s - unable to send L2CA_Ping response message. " \ 1562878ed226SJulian Elischer "Hook is not connected or valid\n", 1563878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node)); 1564878ed226SJulian Elischer error = ENOTCONN; 1565878ed226SJulian Elischer goto out; 1566878ed226SJulian Elischer } 1567878ed226SJulian Elischer 1568878ed226SJulian Elischer size = (data == NULL)? 0 : data->m_pkthdr.len; 1569878ed226SJulian Elischer 1570878ed226SJulian Elischer /* Create and send L2CA_Ping response message */ 1571878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_PING, 1572878ed226SJulian Elischer sizeof(*op) + size, M_NOWAIT); 1573878ed226SJulian Elischer if (msg == NULL) 1574878ed226SJulian Elischer error = ENOMEM; 1575878ed226SJulian Elischer else { 1576878ed226SJulian Elischer msg->header.token = token; 1577878ed226SJulian Elischer msg->header.flags |= NGF_RESP; 1578878ed226SJulian Elischer 1579878ed226SJulian Elischer op = (ng_l2cap_l2ca_ping_op *)(msg->data); 1580878ed226SJulian Elischer op->result = result; 1581878ed226SJulian Elischer bcopy(&con->remote, &op->bdaddr, sizeof(op->bdaddr)); 1582878ed226SJulian Elischer if (data != NULL && size > 0) { 1583878ed226SJulian Elischer op->echo_size = size; 1584878ed226SJulian Elischer m_copydata(data, 0, size, (caddr_t) op + sizeof(*op)); 1585878ed226SJulian Elischer } 1586878ed226SJulian Elischer 15874ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1588878ed226SJulian Elischer } 1589878ed226SJulian Elischer out: 1590878ed226SJulian Elischer NG_FREE_M(data); 1591878ed226SJulian Elischer 1592878ed226SJulian Elischer return (error); 1593878ed226SJulian Elischer } /* ng_l2cap_l2ca_ping_rsp */ 1594878ed226SJulian Elischer 1595878ed226SJulian Elischer /* 1596878ed226SJulian Elischer * Process L2CA_GetInfo request from the upper layer protocol 1597878ed226SJulian Elischer */ 1598878ed226SJulian Elischer 1599878ed226SJulian Elischer int 1600878ed226SJulian Elischer ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1601878ed226SJulian Elischer { 1602878ed226SJulian Elischer ng_l2cap_l2ca_get_info_ip *ip = NULL; 1603878ed226SJulian Elischer ng_l2cap_con_p con = NULL; 1604878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 1605878ed226SJulian Elischer int error = 0; 1606878ed226SJulian Elischer 1607878ed226SJulian Elischer /* Verify message */ 1608878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) { 1609878ed226SJulian Elischer NG_L2CAP_ALERT( 1610878ed226SJulian Elischer "%s: %s - invalid L2CA_GetInfo request message size, size=%d\n", 1611878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), 1612878ed226SJulian Elischer msg->header.arglen); 1613878ed226SJulian Elischer error = EMSGSIZE; 1614878ed226SJulian Elischer goto out; 1615878ed226SJulian Elischer } 1616878ed226SJulian Elischer 1617878ed226SJulian Elischer ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data); 1618878ed226SJulian Elischer 1619878ed226SJulian Elischer /* Check if we have connection to the unit */ 1620fbc48c2bSTakanori Watanabe con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr,ip->linktype); 1621878ed226SJulian Elischer if (con == NULL) { 1622878ed226SJulian Elischer /* Submit LP_ConnectReq to the lower layer */ 1623fbc48c2bSTakanori Watanabe error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype); 1624878ed226SJulian Elischer if (error != 0) { 1625878ed226SJulian Elischer NG_L2CAP_ERR( 1626878ed226SJulian Elischer "%s: %s - unable to send LP_ConnectReq message, error=%d\n", 1627878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), error); 1628878ed226SJulian Elischer goto out; 1629878ed226SJulian Elischer } 1630878ed226SJulian Elischer 1631878ed226SJulian Elischer /* This should not fail */ 1632fbc48c2bSTakanori Watanabe con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype); 1633878ed226SJulian Elischer KASSERT((con != NULL), 1634878ed226SJulian Elischer ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node))); 1635878ed226SJulian Elischer } 1636878ed226SJulian Elischer 1637878ed226SJulian Elischer /* Create L2CAP command descriptor */ 1638878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con), 1639878ed226SJulian Elischer NG_L2CAP_INFO_REQ, msg->header.token); 1640878ed226SJulian Elischer if (cmd == NULL) { 1641878ed226SJulian Elischer error = ENOMEM; 1642878ed226SJulian Elischer goto out; 1643878ed226SJulian Elischer } 1644878ed226SJulian Elischer 1645878ed226SJulian Elischer if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1646878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 1647878ed226SJulian Elischer error = EIO; 1648878ed226SJulian Elischer goto out; 1649878ed226SJulian Elischer } 1650878ed226SJulian Elischer 1651878ed226SJulian Elischer /* Create L2CAP command packet */ 1652878ed226SJulian Elischer _ng_l2cap_info_req(cmd->aux, cmd->ident, ip->info_type); 1653878ed226SJulian Elischer if (cmd->aux == NULL) { 1654878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 1655878ed226SJulian Elischer error = ENOBUFS; 1656878ed226SJulian Elischer goto out; 1657878ed226SJulian Elischer } 1658878ed226SJulian Elischer 1659878ed226SJulian Elischer /* Link command to the queue */ 1660878ed226SJulian Elischer ng_l2cap_link_cmd(con, cmd); 1661878ed226SJulian Elischer ng_l2cap_lp_deliver(con); 1662878ed226SJulian Elischer out: 1663878ed226SJulian Elischer return (error); 1664878ed226SJulian Elischer } /* ng_l2cap_l2ca_get_info_req */ 1665878ed226SJulian Elischer 1666878ed226SJulian Elischer /* 1667878ed226SJulian Elischer * Send L2CA_GetInfo response to the upper layer protocol 1668878ed226SJulian Elischer */ 1669878ed226SJulian Elischer 1670878ed226SJulian Elischer int 1671878ed226SJulian Elischer ng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con, u_int32_t token, 1672878ed226SJulian Elischer u_int16_t result, struct mbuf *data) 1673878ed226SJulian Elischer { 1674878ed226SJulian Elischer ng_l2cap_p l2cap = con->l2cap; 1675878ed226SJulian Elischer struct ng_mesg *msg = NULL; 1676878ed226SJulian Elischer ng_l2cap_l2ca_get_info_op *op = NULL; 1677878ed226SJulian Elischer int error = 0, size; 1678878ed226SJulian Elischer 1679878ed226SJulian Elischer /* Check if control hook is connected and valid */ 1680878ed226SJulian Elischer if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) { 1681878ed226SJulian Elischer NG_L2CAP_WARN( 1682878ed226SJulian Elischer "%s: %s - unable to send L2CA_GetInfo response message. " \ 1683878ed226SJulian Elischer "Hook is not connected or valid\n", 1684878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node)); 1685878ed226SJulian Elischer error = ENOTCONN; 1686878ed226SJulian Elischer goto out; 1687878ed226SJulian Elischer } 1688878ed226SJulian Elischer 1689878ed226SJulian Elischer size = (data == NULL)? 0 : data->m_pkthdr.len; 1690878ed226SJulian Elischer 1691878ed226SJulian Elischer /* Create and send L2CA_GetInfo response message */ 1692878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_GET_INFO, 1693878ed226SJulian Elischer sizeof(*op) + size, M_NOWAIT); 1694878ed226SJulian Elischer if (msg == NULL) 1695878ed226SJulian Elischer error = ENOMEM; 1696878ed226SJulian Elischer else { 1697878ed226SJulian Elischer msg->header.token = token; 1698878ed226SJulian Elischer msg->header.flags |= NGF_RESP; 1699878ed226SJulian Elischer 1700878ed226SJulian Elischer op = (ng_l2cap_l2ca_get_info_op *)(msg->data); 1701878ed226SJulian Elischer op->result = result; 1702878ed226SJulian Elischer if (data != NULL && size > 0) { 1703878ed226SJulian Elischer op->info_size = size; 1704878ed226SJulian Elischer m_copydata(data, 0, size, (caddr_t) op + sizeof(*op)); 1705878ed226SJulian Elischer } 1706878ed226SJulian Elischer 17074ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1708878ed226SJulian Elischer } 1709878ed226SJulian Elischer out: 1710878ed226SJulian Elischer NG_FREE_M(data); 1711878ed226SJulian Elischer 1712878ed226SJulian Elischer return (error); 1713878ed226SJulian Elischer } /* ng_l2cap_l2ca_get_info_rsp */ 1714878ed226SJulian Elischer 1715878ed226SJulian Elischer /* 1716878ed226SJulian Elischer * Process L2CA_EnableCLT message from the upper layer protocol 1717878ed226SJulian Elischer * XXX convert to NGN_L2CAP_NODE_SET_FLAGS? 1718878ed226SJulian Elischer */ 1719878ed226SJulian Elischer 1720878ed226SJulian Elischer int 1721878ed226SJulian Elischer ng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg) 1722878ed226SJulian Elischer { 1723878ed226SJulian Elischer ng_l2cap_l2ca_enable_clt_ip *ip = NULL; 1724878ed226SJulian Elischer int error = 0; 1725878ed226SJulian Elischer #if 0 1726878ed226SJulian Elischer * ng_l2cap_l2ca_enable_clt_op *op = NULL; 1727878ed226SJulian Elischer * u_int16_t result; 1728878ed226SJulian Elischer * u_int32_t token; 1729878ed226SJulian Elischer #endif 1730878ed226SJulian Elischer 1731878ed226SJulian Elischer /* Check message */ 1732878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) { 1733878ed226SJulian Elischer NG_L2CAP_ALERT( 1734878ed226SJulian Elischer "%s: %s - invalid L2CA_EnableCLT message size, size=%d\n", 1735878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), 1736878ed226SJulian Elischer msg->header.arglen); 1737878ed226SJulian Elischer 1738878ed226SJulian Elischer return (EMSGSIZE); 1739878ed226SJulian Elischer } 1740878ed226SJulian Elischer 1741878ed226SJulian Elischer /* Process request */ 1742878ed226SJulian Elischer ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data); 1743878ed226SJulian Elischer #if 0 1744878ed226SJulian Elischer * result = NG_L2CAP_SUCCESS; 1745878ed226SJulian Elischer #endif 1746878ed226SJulian Elischer 1747878ed226SJulian Elischer switch (ip->psm) 1748878ed226SJulian Elischer { 1749878ed226SJulian Elischer case 0: 1750878ed226SJulian Elischer /* Special case: disable/enable all PSM */ 1751878ed226SJulian Elischer if (ip->enable) 1752878ed226SJulian Elischer l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED | 1753878ed226SJulian Elischer NG_L2CAP_CLT_RFCOMM_DISABLED | 1754878ed226SJulian Elischer NG_L2CAP_CLT_TCP_DISABLED); 1755878ed226SJulian Elischer else 1756878ed226SJulian Elischer l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED | 1757878ed226SJulian Elischer NG_L2CAP_CLT_RFCOMM_DISABLED | 1758878ed226SJulian Elischer NG_L2CAP_CLT_TCP_DISABLED); 1759878ed226SJulian Elischer break; 1760878ed226SJulian Elischer 1761878ed226SJulian Elischer case NG_L2CAP_PSM_SDP: 1762878ed226SJulian Elischer if (ip->enable) 1763878ed226SJulian Elischer l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED; 1764878ed226SJulian Elischer else 1765878ed226SJulian Elischer l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED; 1766878ed226SJulian Elischer break; 1767878ed226SJulian Elischer 1768878ed226SJulian Elischer case NG_L2CAP_PSM_RFCOMM: 1769878ed226SJulian Elischer if (ip->enable) 1770878ed226SJulian Elischer l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED; 1771878ed226SJulian Elischer else 1772878ed226SJulian Elischer l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED; 1773878ed226SJulian Elischer break; 1774878ed226SJulian Elischer 1775878ed226SJulian Elischer case NG_L2CAP_PSM_TCP: 1776878ed226SJulian Elischer if (ip->enable) 1777878ed226SJulian Elischer l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED; 1778878ed226SJulian Elischer else 1779878ed226SJulian Elischer l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED; 1780878ed226SJulian Elischer break; 1781878ed226SJulian Elischer 1782878ed226SJulian Elischer default: 1783878ed226SJulian Elischer NG_L2CAP_ERR( 1784878ed226SJulian Elischer "%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm); 1785878ed226SJulian Elischer #if 0 1786878ed226SJulian Elischer * result = NG_L2CAP_PSM_NOT_SUPPORTED; 1787878ed226SJulian Elischer #endif 1788878ed226SJulian Elischer error = ENOTSUP; 1789878ed226SJulian Elischer break; 1790878ed226SJulian Elischer } 1791878ed226SJulian Elischer 1792878ed226SJulian Elischer #if 0 1793878ed226SJulian Elischer * /* Create and send response message */ 1794878ed226SJulian Elischer * token = msg->header.token; 1795878ed226SJulian Elischer * NG_FREE_MSG(msg); 1796878ed226SJulian Elischer * NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT, 1797878ed226SJulian Elischer * sizeof(*op), M_NOWAIT); 1798878ed226SJulian Elischer * if (msg == NULL) 1799878ed226SJulian Elischer * error = ENOMEM; 1800878ed226SJulian Elischer * else { 1801878ed226SJulian Elischer * msg->header.token = token; 1802878ed226SJulian Elischer * msg->header.flags |= NGF_RESP; 1803878ed226SJulian Elischer * 1804878ed226SJulian Elischer * op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data); 1805878ed226SJulian Elischer * op->result = result; 1806878ed226SJulian Elischer * } 1807878ed226SJulian Elischer * 1808878ed226SJulian Elischer * /* Send response to control hook */ 1809878ed226SJulian Elischer * if (l2cap->ctl != NULL && NG_HOOK_IS_VALID(l2cap->ctl)) 18104ae439a3SMaksim Yevmenkin * NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1811878ed226SJulian Elischer #endif 1812878ed226SJulian Elischer 1813878ed226SJulian Elischer return (error); 1814878ed226SJulian Elischer } /* ng_l2cap_l2ca_enable_clt */ 1815878ed226SJulian Elischer 1816