1107120Sjulian/* 2107120Sjulian * ng_l2cap_ulpi.c 3139823Simp */ 4139823Simp 5139823Simp/*- 6107120Sjulian * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 7107120Sjulian * All rights reserved. 8107120Sjulian * 9107120Sjulian * Redistribution and use in source and binary forms, with or without 10107120Sjulian * modification, are permitted provided that the following conditions 11107120Sjulian * are met: 12107120Sjulian * 1. Redistributions of source code must retain the above copyright 13107120Sjulian * notice, this list of conditions and the following disclaimer. 14107120Sjulian * 2. Redistributions in binary form must reproduce the above copyright 15107120Sjulian * notice, this list of conditions and the following disclaimer in the 16107120Sjulian * documentation and/or other materials provided with the distribution. 17107120Sjulian * 18107120Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19107120Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20107120Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21107120Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22107120Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23107120Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24107120Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25107120Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26107120Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27107120Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28107120Sjulian * SUCH DAMAGE. 29107120Sjulian * 30114878Sjulian * $Id: ng_l2cap_ulpi.c,v 1.1 2002/11/24 19:47:06 max Exp $ 31107120Sjulian * $FreeBSD$ 32107120Sjulian */ 33107120Sjulian 34107120Sjulian#include <sys/param.h> 35107120Sjulian#include <sys/systm.h> 36107120Sjulian#include <sys/kernel.h> 37107120Sjulian#include <sys/endian.h> 38107120Sjulian#include <sys/malloc.h> 39107120Sjulian#include <sys/mbuf.h> 40107120Sjulian#include <sys/queue.h> 41107120Sjulian#include <netgraph/ng_message.h> 42107120Sjulian#include <netgraph/netgraph.h> 43128688Semax#include <netgraph/bluetooth/include/ng_hci.h> 44128688Semax#include <netgraph/bluetooth/include/ng_l2cap.h> 45128688Semax#include <netgraph/bluetooth/l2cap/ng_l2cap_var.h> 46128688Semax#include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h> 47128688Semax#include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h> 48128688Semax#include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h> 49128688Semax#include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h> 50128688Semax#include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h> 51107120Sjulian 52107120Sjulian/****************************************************************************** 53107120Sjulian ****************************************************************************** 54107120Sjulian ** Upper Layer Protocol Interface module 55107120Sjulian ****************************************************************************** 56107120Sjulian ******************************************************************************/ 57107120Sjulian 58107120Sjulian/* 59107120Sjulian * Process L2CA_Connect request from the upper layer protocol. 60107120Sjulian */ 61107120Sjulian 62107120Sjulianint 63107120Sjulianng_l2cap_l2ca_con_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 64107120Sjulian{ 65107120Sjulian ng_l2cap_l2ca_con_ip *ip = NULL; 66107120Sjulian ng_l2cap_con_p con = NULL; 67107120Sjulian ng_l2cap_chan_p ch = NULL; 68107120Sjulian ng_l2cap_cmd_p cmd = NULL; 69107120Sjulian int error = 0; 70107120Sjulian 71107120Sjulian /* Check message */ 72107120Sjulian if (msg->header.arglen != sizeof(*ip)) { 73107120Sjulian NG_L2CAP_ALERT( 74107120Sjulian"%s: %s - invalid L2CA_Connect request message size, size=%d\n", 75107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 76107120Sjulian msg->header.arglen); 77107120Sjulian error = EMSGSIZE; 78107120Sjulian goto out; 79107120Sjulian } 80107120Sjulian 81107120Sjulian ip = (ng_l2cap_l2ca_con_ip *)(msg->data); 82107120Sjulian 83107120Sjulian /* Check if we have connection to the remote unit */ 84281198Stakawata con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype); 85107120Sjulian if (con == NULL) { 86107120Sjulian /* Submit LP_ConnectReq to the lower layer */ 87281198Stakawata error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype); 88107120Sjulian if (error != 0) { 89107120Sjulian NG_L2CAP_ERR( 90107120Sjulian"%s: %s - unable to send LP_ConnectReq message, error=%d\n", 91107120Sjulian __func__, NG_NODE_NAME(l2cap->node), error); 92107120Sjulian goto out; 93107120Sjulian } 94107120Sjulian 95107120Sjulian /* This should not fail */ 96281198Stakawata con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype); 97107120Sjulian KASSERT((con != NULL), 98107120Sjulian("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node))); 99107120Sjulian } 100107120Sjulian 101107120Sjulian /* 102107120Sjulian * Create new empty channel descriptor. In case of any failure do 103107120Sjulian * not touch connection descriptor. 104107120Sjulian */ 105107120Sjulian 106281198Stakawata ch = ng_l2cap_new_chan(l2cap, con, ip->psm, ip->idtype); 107107120Sjulian if (ch == NULL) { 108107120Sjulian error = ENOMEM; 109107120Sjulian goto out; 110107120Sjulian } 111107120Sjulian 112107120Sjulian /* Now create L2CAP_ConnectReq command */ 113107120Sjulian cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(con), 114107120Sjulian NG_L2CAP_CON_REQ, msg->header.token); 115107120Sjulian if (cmd == NULL) { 116107120Sjulian ng_l2cap_free_chan(ch); 117107120Sjulian error = ENOMEM; 118107120Sjulian goto out; 119107120Sjulian } 120107120Sjulian 121107120Sjulian if (cmd->ident == NG_L2CAP_NULL_IDENT) { 122107120Sjulian ng_l2cap_free_cmd(cmd); 123107120Sjulian ng_l2cap_free_chan(ch); 124107120Sjulian error = EIO; 125107120Sjulian goto out; 126107120Sjulian } 127107120Sjulian 128107120Sjulian /* Create L2CAP command packet */ 129281198Stakawata if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){ 130281198Stakawata _ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_ATT_CID, 131281198Stakawata NG_L2CAP_ATT_CID, 0, 0); 132281198Stakawata cmd->aux->m_flags |= M_PROTO2; 133290038Stakawata }else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){ 134290038Stakawata _ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_SMP_CID, 135290038Stakawata NG_L2CAP_SMP_CID, 0, 0); 136290038Stakawata cmd->aux->m_flags |= M_PROTO2; 137281198Stakawata }else{ 138281198Stakawata _ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid); 139281198Stakawata } 140107120Sjulian if (cmd->aux == NULL) { 141107120Sjulian ng_l2cap_free_cmd(cmd); 142107120Sjulian ng_l2cap_free_chan(ch); 143107120Sjulian error = ENOBUFS; 144107120Sjulian goto out; 145107120Sjulian } 146107120Sjulian 147107120Sjulian ch->state = NG_L2CAP_W4_L2CAP_CON_RSP; 148107120Sjulian 149107120Sjulian /* Link command to the queue */ 150107120Sjulian ng_l2cap_link_cmd(ch->con, cmd); 151107120Sjulian ng_l2cap_lp_deliver(ch->con); 152107120Sjulianout: 153107120Sjulian return (error); 154107120Sjulian} /* ng_l2cap_l2ca_con_req */ 155107120Sjulian 156107120Sjulian/* 157107120Sjulian * Send L2CA_Connect response to the upper layer protocol. 158107120Sjulian */ 159107120Sjulian 160107120Sjulianint 161107120Sjulianng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result, 162107120Sjulian u_int16_t status) 163107120Sjulian{ 164107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 165107120Sjulian struct ng_mesg *msg = NULL; 166107120Sjulian ng_l2cap_l2ca_con_op *op = NULL; 167107120Sjulian int error = 0; 168107120Sjulian 169107120Sjulian /* Check if upstream hook is connected and valid */ 170107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 171107120Sjulian NG_L2CAP_ERR( 172107120Sjulian"%s: %s - unable to send L2CA_Connect response message. " \ 173107120Sjulian"Hook is not connected or valid, psm=%d\n", 174107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 175107120Sjulian 176107120Sjulian return (ENOTCONN); 177107120Sjulian } 178107120Sjulian 179107120Sjulian /* Create and send L2CA_Connect response message */ 180107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON, 181107120Sjulian sizeof(*op), M_NOWAIT); 182107120Sjulian if (msg == NULL) 183107120Sjulian error = ENOMEM; 184107120Sjulian else { 185107120Sjulian msg->header.token = token; 186107120Sjulian msg->header.flags |= NGF_RESP; 187107120Sjulian 188107120Sjulian op = (ng_l2cap_l2ca_con_op *)(msg->data); 189107120Sjulian 190107120Sjulian /* 191107120Sjulian * XXX Spec. says we should only populate LCID when result == 0 192107120Sjulian * What about PENDING? What the heck, for now always populate 193107120Sjulian * LCID :) 194107120Sjulian */ 195281198Stakawata if(ch->scid == NG_L2CAP_ATT_CID){ 196281198Stakawata op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT; 197281198Stakawata op->lcid = ch->con->con_handle; 198290038Stakawata }else if(ch->scid == NG_L2CAP_SMP_CID){ 199290038Stakawata op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP; 200290038Stakawata op->lcid = ch->con->con_handle; 201281198Stakawata }else{ 202281198Stakawata op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)? 203281198Stakawata NG_L2CAP_L2CA_IDTYPE_BREDR : 204281198Stakawata NG_L2CAP_L2CA_IDTYPE_LE; 205281198Stakawata op->lcid = ch->scid; 206281198Stakawata } 207290038Stakawata op->encryption = ch->con->encryption; 208107120Sjulian op->result = result; 209107120Sjulian op->status = status; 210107120Sjulian 211128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 212107120Sjulian } 213107120Sjulian 214107120Sjulian return (error); 215107120Sjulian} /* ng_l2cap_l2ca_con_rsp */ 216107120Sjulian 217107120Sjulian/* 218107120Sjulian * Process L2CA_ConnectRsp request from the upper layer protocol. 219107120Sjulian */ 220107120Sjulian 221107120Sjulianint 222107120Sjulianng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 223107120Sjulian{ 224107120Sjulian ng_l2cap_l2ca_con_rsp_ip *ip = NULL; 225107120Sjulian ng_l2cap_con_p con = NULL; 226107120Sjulian ng_l2cap_chan_p ch = NULL; 227107120Sjulian ng_l2cap_cmd_p cmd = NULL; 228107120Sjulian u_int16_t dcid; 229107120Sjulian int error = 0; 230107120Sjulian 231107120Sjulian /* Check message */ 232107120Sjulian if (msg->header.arglen != sizeof(*ip)) { 233107120Sjulian NG_L2CAP_ALERT( 234107120Sjulian"%s: %s - invalid L2CA_ConnectRsp request message size, size=%d\n", 235107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 236107120Sjulian msg->header.arglen); 237107120Sjulian error = EMSGSIZE; 238107120Sjulian goto out; 239107120Sjulian } 240107120Sjulian 241107120Sjulian ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data); 242107120Sjulian 243107120Sjulian /* Check if we have this channel */ 244290038Stakawata if((ip->lcid != NG_L2CAP_ATT_CID)&& 245290038Stakawata (ip->lcid != NG_L2CAP_SMP_CID)){ 246281198Stakawata ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid 247281198Stakawata ,(ip->linktype == NG_HCI_LINK_ACL)? 248281198Stakawata NG_L2CAP_L2CA_IDTYPE_BREDR: 249281198Stakawata NG_L2CAP_L2CA_IDTYPE_LE); 250281198Stakawata }else{ 251281198Stakawata // For now not support on ATT device. 252281198Stakawata ch = NULL; 253281198Stakawata } 254107120Sjulian if (ch == NULL) { 255107120Sjulian NG_L2CAP_ALERT( 256107120Sjulian"%s: %s - unexpected L2CA_ConnectRsp request message. " \ 257107120Sjulian"Channel does not exist, lcid=%d\n", 258107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 259107120Sjulian error = ENOENT; 260107120Sjulian goto out; 261107120Sjulian } 262107120Sjulian 263107120Sjulian /* Check channel state */ 264107120Sjulian if (ch->state != NG_L2CAP_W4_L2CA_CON_RSP) { 265107120Sjulian NG_L2CAP_ERR( 266107120Sjulian"%s: %s - unexpected L2CA_ConnectRsp request message. " \ 267107120Sjulian"Invalid channel state, state=%d, lcid=%d\n", 268107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->state, 269107120Sjulian ip->lcid); 270107120Sjulian error = EINVAL; 271107120Sjulian goto out; 272107120Sjulian } 273107120Sjulian 274107120Sjulian dcid = ch->dcid; 275107120Sjulian con = ch->con; 276107120Sjulian 277107120Sjulian /* 278107120Sjulian * Now we are pretty much sure it is our response. So create and send 279107120Sjulian * L2CAP_ConnectRsp message to our peer. 280107120Sjulian */ 281107120Sjulian 282107120Sjulian if (ch->ident != ip->ident) 283107120Sjulian NG_L2CAP_WARN( 284107120Sjulian"%s: %s - channel ident and response ident do not match, scid=%d, ident=%d. " \ 285107120Sjulian"Will use response ident=%d\n", 286107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->scid, 287107120Sjulian ch->ident, ip->ident); 288107120Sjulian 289107120Sjulian /* Check result */ 290107120Sjulian switch (ip->result) { 291107120Sjulian case NG_L2CAP_SUCCESS: 292290038Stakawata ch->state = ((ch->scid == NG_L2CAP_ATT_CID)|| 293290038Stakawata (ch->scid == NG_L2CAP_SMP_CID))? 294281198Stakawata NG_L2CAP_OPEN : NG_L2CAP_CONFIG; 295107120Sjulian ch->cfg_state = 0; 296107120Sjulian break; 297107120Sjulian 298107120Sjulian case NG_L2CAP_PENDING: 299107120Sjulian break; 300107120Sjulian 301107120Sjulian default: 302107120Sjulian ng_l2cap_free_chan(ch); 303107120Sjulian ch = NULL; 304107120Sjulian break; 305107120Sjulian } 306107120Sjulian 307107120Sjulian /* Create L2CAP command */ 308107120Sjulian cmd = ng_l2cap_new_cmd(con, ch, ip->ident, NG_L2CAP_CON_RSP, 309107120Sjulian msg->header.token); 310107120Sjulian if (cmd == NULL) { 311107120Sjulian if (ch != NULL) 312107120Sjulian ng_l2cap_free_chan(ch); 313107120Sjulian 314107120Sjulian error = ENOMEM; 315107120Sjulian goto out; 316107120Sjulian } 317107120Sjulian 318107120Sjulian _ng_l2cap_con_rsp(cmd->aux, cmd->ident, ip->lcid, dcid, 319107120Sjulian ip->result, ip->status); 320107120Sjulian if (cmd->aux == NULL) { 321107120Sjulian if (ch != NULL) 322107120Sjulian ng_l2cap_free_chan(ch); 323107120Sjulian 324107120Sjulian ng_l2cap_free_cmd(cmd); 325107120Sjulian error = ENOBUFS; 326107120Sjulian goto out; 327107120Sjulian } 328107120Sjulian 329107120Sjulian /* Link command to the queue */ 330107120Sjulian ng_l2cap_link_cmd(con, cmd); 331107120Sjulian ng_l2cap_lp_deliver(con); 332107120Sjulianout: 333107120Sjulian return (error); 334107120Sjulian} /* ng_l2cap_l2ca_con_rsp_req */ 335107120Sjulian 336290038Stakawataint ng_l2cap_l2ca_encryption_change(ng_l2cap_chan_p ch, uint16_t result) 337290038Stakawata{ 338290038Stakawata ng_l2cap_p l2cap = ch->con->l2cap; 339290038Stakawata struct ng_mesg *msg = NULL; 340290038Stakawata ng_l2cap_l2ca_enc_chg_op *op = NULL; 341290038Stakawata int error = 0; 342290038Stakawata 343290038Stakawata /* Check if upstream hook is connected and valid */ 344290038Stakawata if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 345290038Stakawata NG_L2CAP_ERR( 346290038Stakawata"%s: %s - unable to send L2CA_ConnectRsp response message. " \ 347290038Stakawata"Hook is not connected or valid, psm=%d\n", 348290038Stakawata __func__, NG_NODE_NAME(l2cap->node), ch->psm); 349290038Stakawata 350290038Stakawata return (ENOTCONN); 351290038Stakawata } 352290038Stakawata 353290038Stakawata /* Create and send L2CA_ConnectRsp response message */ 354290038Stakawata NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENC_CHANGE, 355290038Stakawata sizeof(*op), M_NOWAIT); 356290038Stakawata if (msg == NULL) 357290038Stakawata error = ENOMEM; 358290038Stakawata else { 359290038Stakawata msg->header.token = 0; 360290038Stakawata msg->header.flags |= NGF_RESP; 361290038Stakawata 362290038Stakawata op = (ng_l2cap_l2ca_enc_chg_op *)(msg->data); 363290038Stakawata op->result = result; 364290038Stakawata if(ch->scid ==NG_L2CAP_ATT_CID|| 365290038Stakawata ch->scid ==NG_L2CAP_SMP_CID){ 366290038Stakawata op->lcid = ch->con->con_handle; 367290038Stakawata op->idtype = (ch->scid==NG_L2CAP_ATT_CID)? 368290038Stakawata NG_L2CAP_L2CA_IDTYPE_ATT: 369290038Stakawata NG_L2CAP_L2CA_IDTYPE_SMP; 370290038Stakawata }else{ 371290038Stakawata op->idtype =(ch->con->linktype ==NG_HCI_LINK_ACL)? 372290038Stakawata NG_L2CAP_L2CA_IDTYPE_BREDR: 373290038Stakawata NG_L2CAP_L2CA_IDTYPE_LE; 374290038Stakawata } 375290038Stakawata 376290038Stakawata 377290038Stakawata NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 378290038Stakawata } 379290038Stakawata 380290038Stakawata return (error); 381290038Stakawata 382290038Stakawata} 383107120Sjulian/* 384107120Sjulian * Send L2CAP_ConnectRsp response to the upper layer 385107120Sjulian */ 386107120Sjulian 387107120Sjulianint 388107120Sjulianng_l2cap_l2ca_con_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 389107120Sjulian{ 390107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 391107120Sjulian struct ng_mesg *msg = NULL; 392107120Sjulian ng_l2cap_l2ca_con_rsp_op *op = NULL; 393107120Sjulian int error = 0; 394107120Sjulian 395107120Sjulian /* Check if upstream hook is connected and valid */ 396107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 397107120Sjulian NG_L2CAP_ERR( 398107120Sjulian"%s: %s - unable to send L2CA_ConnectRsp response message. " \ 399107120Sjulian"Hook is not connected or valid, psm=%d\n", 400107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 401107120Sjulian 402107120Sjulian return (ENOTCONN); 403107120Sjulian } 404107120Sjulian 405107120Sjulian /* Create and send L2CA_ConnectRsp response message */ 406107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_RSP, 407107120Sjulian sizeof(*op), M_NOWAIT); 408107120Sjulian if (msg == NULL) 409107120Sjulian error = ENOMEM; 410107120Sjulian else { 411107120Sjulian msg->header.token = token; 412107120Sjulian msg->header.flags |= NGF_RESP; 413107120Sjulian 414107120Sjulian op = (ng_l2cap_l2ca_con_rsp_op *)(msg->data); 415107120Sjulian op->result = result; 416107120Sjulian 417128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 418107120Sjulian } 419107120Sjulian 420107120Sjulian return (error); 421107120Sjulian} /* ng_l2cap_l2ca_con_rsp_rsp */ 422107120Sjulian 423107120Sjulian/* 424107120Sjulian * Send L2CA_ConnectInd message to the upper layer protocol. 425107120Sjulian */ 426107120Sjulian 427107120Sjulianint 428107120Sjulianng_l2cap_l2ca_con_ind(ng_l2cap_chan_p ch) 429107120Sjulian{ 430107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 431107120Sjulian struct ng_mesg *msg = NULL; 432107120Sjulian ng_l2cap_l2ca_con_ind_ip *ip = NULL; 433107120Sjulian int error = 0; 434107120Sjulian 435107120Sjulian /* Check if upstream hook is connected and valid */ 436107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 437107120Sjulian NG_L2CAP_ERR( 438107120Sjulian"%s: %s - unable to send L2CA_ConnectInd message. " \ 439107120Sjulian"Hook is not connected or valid, psm=%d\n", 440107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 441107120Sjulian 442107120Sjulian return (ENOTCONN); 443107120Sjulian } 444107120Sjulian 445107120Sjulian /* Create and send L2CA_ConnectInd message */ 446107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_IND, 447107120Sjulian sizeof(*ip), M_NOWAIT); 448107120Sjulian if (msg == NULL) 449107120Sjulian error = ENOMEM; 450107120Sjulian else { 451107120Sjulian ip = (ng_l2cap_l2ca_con_ind_ip *)(msg->data); 452107120Sjulian 453107120Sjulian bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr)); 454107120Sjulian ip->lcid = ch->scid; 455107120Sjulian ip->psm = ch->psm; 456107120Sjulian ip->ident = ch->ident; 457285244Stakawata ip->linktype = ch->con->linktype; 458290038Stakawata 459128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 460107120Sjulian } 461107120Sjulian 462107120Sjulian return (error); 463107120Sjulian} /* ng_l2cap_l2ca_con_ind */ 464107120Sjulian 465107120Sjulian/* 466107120Sjulian * Process L2CA_Config request from the upper layer protocol 467107120Sjulian */ 468107120Sjulian 469107120Sjulianint 470107120Sjulianng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 471107120Sjulian{ 472107120Sjulian ng_l2cap_l2ca_cfg_ip *ip = NULL; 473107120Sjulian ng_l2cap_chan_p ch = NULL; 474107120Sjulian ng_l2cap_cmd_p cmd = NULL; 475107120Sjulian struct mbuf *opt = NULL; 476107120Sjulian u_int16_t *mtu = NULL, *flush_timo = NULL; 477107120Sjulian ng_l2cap_flow_p flow = NULL; 478107120Sjulian int error = 0; 479107120Sjulian 480107120Sjulian /* Check message */ 481107120Sjulian if (msg->header.arglen != sizeof(*ip)) { 482107120Sjulian NG_L2CAP_ALERT( 483107120Sjulian"%s: %s - Invalid L2CA_Config request message size, size=%d\n", 484107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 485107120Sjulian msg->header.arglen); 486107120Sjulian error = EMSGSIZE; 487107120Sjulian goto out; 488107120Sjulian } 489107120Sjulian 490107120Sjulian ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data); 491107120Sjulian 492107120Sjulian /* Check if we have this channel */ 493281198Stakawata ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, NG_L2CAP_L2CA_IDTYPE_BREDR); 494107120Sjulian if (ch == NULL) { 495107120Sjulian NG_L2CAP_ERR( 496107120Sjulian"%s: %s - unexpected L2CA_Config request message. " \ 497107120Sjulian"Channel does not exist, lcid=%d\n", 498107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 499107120Sjulian error = ENOENT; 500107120Sjulian goto out; 501107120Sjulian } 502107120Sjulian 503107120Sjulian /* Check channel state */ 504107120Sjulian if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG) { 505107120Sjulian NG_L2CAP_ERR( 506107120Sjulian"%s: %s - unexpected L2CA_Config request message. " \ 507107120Sjulian"Invalid channel state, state=%d, lcid=%d\n", 508107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->state, 509107120Sjulian ch->scid); 510107120Sjulian error = EINVAL; 511107120Sjulian goto out; 512107120Sjulian } 513107120Sjulian 514107120Sjulian /* Set requested channel configuration options */ 515107120Sjulian ch->imtu = ip->imtu; 516107120Sjulian bcopy(&ip->oflow, &ch->oflow, sizeof(ch->oflow)); 517107120Sjulian ch->flush_timo = ip->flush_timo; 518107120Sjulian ch->link_timo = ip->link_timo; 519107120Sjulian 520107120Sjulian /* Compare channel settings with defaults */ 521107120Sjulian if (ch->imtu != NG_L2CAP_MTU_DEFAULT) 522107120Sjulian mtu = &ch->imtu; 523107120Sjulian if (ch->flush_timo != NG_L2CAP_FLUSH_TIMO_DEFAULT) 524107120Sjulian flush_timo = &ch->flush_timo; 525107120Sjulian if (bcmp(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)) != 0) 526107120Sjulian flow = &ch->oflow; 527107120Sjulian 528107120Sjulian /* Create configuration options */ 529107120Sjulian _ng_l2cap_build_cfg_options(opt, mtu, flush_timo, flow); 530107120Sjulian if (opt == NULL) { 531107120Sjulian error = ENOBUFS; 532107120Sjulian goto out; 533107120Sjulian } 534107120Sjulian 535107120Sjulian /* Create L2CAP command descriptor */ 536107120Sjulian cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con), 537107120Sjulian NG_L2CAP_CFG_REQ, msg->header.token); 538107120Sjulian if (cmd == NULL) { 539107120Sjulian NG_FREE_M(opt); 540107120Sjulian error = ENOMEM; 541107120Sjulian goto out; 542107120Sjulian } 543107120Sjulian 544107120Sjulian if (cmd->ident == NG_L2CAP_NULL_IDENT) { 545107120Sjulian ng_l2cap_free_cmd(cmd); 546107120Sjulian NG_FREE_M(opt); 547107120Sjulian error = EIO; 548107120Sjulian goto out; 549107120Sjulian } 550107120Sjulian 551107120Sjulian /* Create L2CAP command packet */ 552107120Sjulian _ng_l2cap_cfg_req(cmd->aux, cmd->ident, ch->dcid, 0, opt); 553107120Sjulian if (cmd->aux == NULL) { 554107120Sjulian ng_l2cap_free_cmd(cmd); 555107120Sjulian error = ENOBUFS; 556107120Sjulian goto out; 557107120Sjulian } 558107120Sjulian 559107120Sjulian /* Adjust channel state for re-configuration */ 560107120Sjulian if (ch->state == NG_L2CAP_OPEN) { 561290038Stakawata ch->state = ((ch->scid == NG_L2CAP_ATT_CID)|| 562290038Stakawata (ch->scid == NG_L2CAP_SMP_CID))? 563281198Stakawata NG_L2CAP_OPEN : NG_L2CAP_CONFIG; 564107120Sjulian ch->cfg_state = 0; 565107120Sjulian } 566107120Sjulian 567107120Sjulian /* Link command to the queue */ 568107120Sjulian ng_l2cap_link_cmd(ch->con, cmd); 569107120Sjulian ng_l2cap_lp_deliver(ch->con); 570107120Sjulianout: 571107120Sjulian return (error); 572107120Sjulian} /* ng_l2cap_l2ca_cfg_req */ 573107120Sjulian 574107120Sjulian/* 575107120Sjulian * Send L2CA_Config response to the upper layer protocol 576107120Sjulian */ 577107120Sjulian 578107120Sjulianint 579107120Sjulianng_l2cap_l2ca_cfg_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 580107120Sjulian{ 581107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 582107120Sjulian struct ng_mesg *msg = NULL; 583107120Sjulian ng_l2cap_l2ca_cfg_op *op = NULL; 584107120Sjulian int error = 0; 585107120Sjulian 586107120Sjulian /* Check if upstream hook is connected and valid */ 587107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 588107120Sjulian NG_L2CAP_ERR( 589107120Sjulian"%s: %s - unable to send L2CA_Config response message. " \ 590107120Sjulian"Hook is not connected or valid, psm=%d\n", 591107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 592107120Sjulian 593107120Sjulian return (ENOTCONN); 594107120Sjulian } 595107120Sjulian 596107120Sjulian /* Create and send L2CA_Config response message */ 597107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG, 598107120Sjulian sizeof(*op), M_NOWAIT); 599107120Sjulian if (msg == NULL) 600107120Sjulian error = ENOMEM; 601107120Sjulian else { 602107120Sjulian msg->header.token = token; 603107120Sjulian msg->header.flags |= NGF_RESP; 604107120Sjulian 605107120Sjulian op = (ng_l2cap_l2ca_cfg_op *)(msg->data); 606107120Sjulian op->result = result; 607107120Sjulian op->imtu = ch->imtu; 608107120Sjulian bcopy(&ch->oflow, &op->oflow, sizeof(op->oflow)); 609107120Sjulian op->flush_timo = ch->flush_timo; 610107120Sjulian 611128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 612107120Sjulian 613107120Sjulian if (error == 0 && result == NG_L2CAP_SUCCESS) { 614107120Sjulian ch->cfg_state |= NG_L2CAP_CFG_IN; 615107120Sjulian 616107120Sjulian if (ch->cfg_state == NG_L2CAP_CFG_BOTH) 617107120Sjulian ch->state = NG_L2CAP_OPEN; 618107120Sjulian } 619107120Sjulian } 620107120Sjulian 621107120Sjulian return (error); 622107120Sjulian} /* ng_l2cap_l2ca_cfg_rsp */ 623107120Sjulian 624107120Sjulian/* 625107120Sjulian * Process L2CA_ConfigRsp request from the upper layer protocol 626107120Sjulian * 627107120Sjulian * XXX XXX XXX 628107120Sjulian * 629107120Sjulian * NOTE: The Bluetooth specification says that Configuration_Response 630107120Sjulian * (L2CA_ConfigRsp) should be used to issue response to configuration request 631107120Sjulian * indication. The minor problem here is L2CAP command ident. We should use 632107120Sjulian * ident from original L2CAP request to make sure our peer can match request 633107120Sjulian * and response. For some reason Bluetooth specification does not include 634107120Sjulian * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems 635107120Sjulian * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident 636107120Sjulian * field. So we should store last known L2CAP request command ident in channel. 637107120Sjulian * Also it seems that upper layer can not reject configuration request, as 638107120Sjulian * Configuration_Response message does not have status/reason field. 639107120Sjulian */ 640107120Sjulian 641107120Sjulianint 642107120Sjulianng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 643107120Sjulian{ 644107120Sjulian ng_l2cap_l2ca_cfg_rsp_ip *ip = NULL; 645107120Sjulian ng_l2cap_chan_p ch = NULL; 646107120Sjulian ng_l2cap_cmd_p cmd = NULL; 647107120Sjulian struct mbuf *opt = NULL; 648107120Sjulian u_int16_t *mtu = NULL; 649107120Sjulian ng_l2cap_flow_p flow = NULL; 650107120Sjulian int error = 0; 651107120Sjulian 652107120Sjulian /* Check message */ 653107120Sjulian if (msg->header.arglen != sizeof(*ip)) { 654107120Sjulian NG_L2CAP_ALERT( 655107120Sjulian"%s: %s - invalid L2CA_ConfigRsp request message size, size=%d\n", 656107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 657107120Sjulian msg->header.arglen); 658107120Sjulian error = EMSGSIZE; 659107120Sjulian goto out; 660107120Sjulian } 661107120Sjulian 662107120Sjulian ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data); 663107120Sjulian 664107120Sjulian /* Check if we have this channel */ 665281198Stakawata ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, 666281198Stakawata NG_L2CAP_L2CA_IDTYPE_BREDR); 667107120Sjulian if (ch == NULL) { 668107120Sjulian NG_L2CAP_ERR( 669107120Sjulian"%s: %s - unexpected L2CA_ConfigRsp request message. " \ 670107120Sjulian"Channel does not exist, lcid=%d\n", 671107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 672107120Sjulian error = ENOENT; 673107120Sjulian goto out; 674107120Sjulian } 675107120Sjulian 676107120Sjulian /* Check channel state */ 677107120Sjulian if (ch->state != NG_L2CAP_CONFIG) { 678107120Sjulian NG_L2CAP_ERR( 679107120Sjulian"%s: %s - unexpected L2CA_ConfigRsp request message. " \ 680107120Sjulian"Invalid channel state, state=%d, lcid=%d\n", 681107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->state, 682107120Sjulian ch->scid); 683107120Sjulian error = EINVAL; 684107120Sjulian goto out; 685107120Sjulian } 686107120Sjulian 687107120Sjulian /* Set channel settings */ 688107120Sjulian if (ip->omtu != ch->omtu) { 689107120Sjulian ch->omtu = ip->omtu; 690107120Sjulian mtu = &ch->omtu; 691107120Sjulian } 692107120Sjulian 693107120Sjulian if (bcmp(&ip->iflow, &ch->iflow, sizeof(ch->iflow)) != 0) { 694107120Sjulian bcopy(&ip->iflow, &ch->iflow, sizeof(ch->iflow)); 695107120Sjulian flow = &ch->iflow; 696107120Sjulian } 697107120Sjulian 698107120Sjulian if (mtu != NULL || flow != NULL) { 699107120Sjulian _ng_l2cap_build_cfg_options(opt, mtu, NULL, flow); 700107120Sjulian if (opt == NULL) { 701107120Sjulian error = ENOBUFS; 702107120Sjulian goto out; 703107120Sjulian } 704107120Sjulian } 705107120Sjulian 706107120Sjulian /* Create L2CAP command */ 707107120Sjulian cmd = ng_l2cap_new_cmd(ch->con, ch, ch->ident, NG_L2CAP_CFG_RSP, 708107120Sjulian msg->header.token); 709107120Sjulian if (cmd == NULL) { 710107120Sjulian NG_FREE_M(opt); 711107120Sjulian error = ENOMEM; 712107120Sjulian goto out; 713107120Sjulian } 714107120Sjulian 715107120Sjulian _ng_l2cap_cfg_rsp(cmd->aux,cmd->ident,ch->dcid,0,NG_L2CAP_SUCCESS,opt); 716107120Sjulian if (cmd->aux == NULL) { 717107120Sjulian ng_l2cap_free_cmd(cmd); 718107120Sjulian error = ENOBUFS; 719107120Sjulian goto out; 720107120Sjulian } 721107120Sjulian 722107120Sjulian /* XXX FIXME - not here ??? */ 723107120Sjulian ch->cfg_state |= NG_L2CAP_CFG_OUT; 724107120Sjulian if (ch->cfg_state == NG_L2CAP_CFG_BOTH) 725107120Sjulian ch->state = NG_L2CAP_OPEN; 726107120Sjulian 727107120Sjulian /* Link command to the queue */ 728107120Sjulian ng_l2cap_link_cmd(ch->con, cmd); 729107120Sjulian ng_l2cap_lp_deliver(ch->con); 730107120Sjulianout: 731107120Sjulian return (error); 732107120Sjulian} /* ng_l2cap_l2ca_cfg_rsp_req */ 733107120Sjulian 734107120Sjulian/* 735107120Sjulian * Send L2CA_ConfigRsp response to the upper layer protocol 736107120Sjulian */ 737107120Sjulian 738107120Sjulianint 739107120Sjulianng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 740107120Sjulian{ 741107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 742107120Sjulian struct ng_mesg *msg = NULL; 743107120Sjulian ng_l2cap_l2ca_cfg_rsp_op *op = NULL; 744107120Sjulian int error = 0; 745107120Sjulian 746107120Sjulian /* Check if upstream hook is connected and valid */ 747107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 748107120Sjulian NG_L2CAP_ERR( 749107120Sjulian"%s: %s - unable to send L2CA_ConfigRsp response message. " \ 750107120Sjulian"Hook is not connected or valid, psm=%d\n", 751107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 752107120Sjulian 753107120Sjulian return (ENOTCONN); 754107120Sjulian } 755107120Sjulian 756107120Sjulian /* Create and send L2CA_ConfigRsp response message */ 757107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP, 758107120Sjulian sizeof(*op), M_NOWAIT); 759107120Sjulian if (msg == NULL) 760107120Sjulian error = ENOMEM; 761107120Sjulian else { 762107120Sjulian msg->header.token = token; 763107120Sjulian msg->header.flags |= NGF_RESP; 764107120Sjulian 765107120Sjulian op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data); 766107120Sjulian op->result = result; 767107120Sjulian 768128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 769107120Sjulian } 770107120Sjulian 771107120Sjulian return (error); 772107120Sjulian} /* ng_l2cap_l2ca_cfg_rsp_rsp */ 773107120Sjulian 774107120Sjulian/* 775107120Sjulian * Send L2CA_ConfigInd message to the upper layer protocol 776107120Sjulian * 777107120Sjulian * XXX XXX XXX 778107120Sjulian * 779107120Sjulian * NOTE: The Bluetooth specification says that Configuration_Response 780107120Sjulian * (L2CA_ConfigRsp) should be used to issue response to configuration request 781107120Sjulian * indication. The minor problem here is L2CAP command ident. We should use 782107120Sjulian * ident from original L2CAP request to make sure our peer can match request 783107120Sjulian * and response. For some reason Bluetooth specification does not include 784107120Sjulian * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems 785107120Sjulian * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident 786107120Sjulian * field. So we should store last known L2CAP request command ident in channel. 787107120Sjulian * Also it seems that upper layer can not reject configuration request, as 788107120Sjulian * Configuration_Response message does not have status/reason field. 789107120Sjulian */ 790107120Sjulian 791107120Sjulianint 792107120Sjulianng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch) 793107120Sjulian{ 794107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 795107120Sjulian struct ng_mesg *msg = NULL; 796107120Sjulian ng_l2cap_l2ca_cfg_ind_ip *ip = NULL; 797107120Sjulian int error = 0; 798107120Sjulian 799107120Sjulian /* Check if upstream hook is connected and valid */ 800107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 801107120Sjulian NG_L2CAP_ERR( 802107120Sjulian"%s: %s - Unable to send L2CA_ConfigInd message. " \ 803107120Sjulian"Hook is not connected or valid, psm=%d\n", 804107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 805107120Sjulian 806107120Sjulian return (ENOTCONN); 807107120Sjulian } 808107120Sjulian 809107120Sjulian /* Create and send L2CA_ConnectInd message */ 810107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_IND, 811107120Sjulian sizeof(*ip), M_NOWAIT); 812107120Sjulian if (msg == NULL) 813107120Sjulian error = ENOMEM; 814107120Sjulian else { 815107120Sjulian ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data); 816107120Sjulian ip->lcid = ch->scid; 817107120Sjulian ip->omtu = ch->omtu; 818107120Sjulian bcopy(&ch->iflow, &ip->iflow, sizeof(ip->iflow)); 819107120Sjulian ip->flush_timo = ch->flush_timo; 820107120Sjulian 821128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 822107120Sjulian } 823107120Sjulian 824107120Sjulian return (error); 825107120Sjulian} /* ng_l2cap_l2ca_cfg_ind */ 826107120Sjulian 827107120Sjulian/* 828107120Sjulian * Process L2CA_Write event 829107120Sjulian */ 830107120Sjulian 831107120Sjulianint 832107120Sjulianng_l2cap_l2ca_write_req(ng_l2cap_p l2cap, struct mbuf *m) 833107120Sjulian{ 834107120Sjulian ng_l2cap_l2ca_hdr_t *l2ca_hdr = NULL; 835107120Sjulian ng_l2cap_chan_p ch = NULL; 836107120Sjulian ng_l2cap_cmd_p cmd = NULL; 837107120Sjulian int error = 0; 838107120Sjulian u_int32_t token = 0; 839107120Sjulian 840107120Sjulian /* Make sure we can access L2CA data packet header */ 841107120Sjulian if (m->m_pkthdr.len < sizeof(*l2ca_hdr)) { 842107120Sjulian NG_L2CAP_ERR( 843107120Sjulian"%s: %s - L2CA Data packet too small, len=%d\n", 844107120Sjulian __func__,NG_NODE_NAME(l2cap->node),m->m_pkthdr.len); 845107120Sjulian error = EMSGSIZE; 846107120Sjulian goto drop; 847107120Sjulian } 848107120Sjulian 849107120Sjulian /* Get L2CA data packet header */ 850107120Sjulian NG_L2CAP_M_PULLUP(m, sizeof(*l2ca_hdr)); 851107120Sjulian if (m == NULL) 852107120Sjulian return (ENOBUFS); 853107120Sjulian 854107120Sjulian l2ca_hdr = mtod(m, ng_l2cap_l2ca_hdr_t *); 855107120Sjulian token = l2ca_hdr->token; 856107120Sjulian m_adj(m, sizeof(*l2ca_hdr)); 857107120Sjulian 858107120Sjulian /* Verify payload size */ 859107120Sjulian if (l2ca_hdr->length != m->m_pkthdr.len) { 860107120Sjulian NG_L2CAP_ERR( 861107120Sjulian"%s: %s - invalid L2CA Data packet. " \ 862107120Sjulian"Payload length does not match, length=%d, len=%d\n", 863107120Sjulian __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->length, 864107120Sjulian m->m_pkthdr.len); 865107120Sjulian error = EMSGSIZE; 866107120Sjulian goto drop; 867107120Sjulian } 868107120Sjulian 869107120Sjulian /* Check channel ID */ 870281198Stakawata if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){ 871281198Stakawata ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID, 872281198Stakawata l2ca_hdr->lcid); 873290038Stakawata } else if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){ 874290038Stakawata ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID, 875290038Stakawata l2ca_hdr->lcid); 876290038Stakawata }else{ 877281198Stakawata if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) { 878281198Stakawata NG_L2CAP_ERR( 879281198Stakawata "%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n", 880281198Stakawata __func__, NG_NODE_NAME(l2cap->node), 881281198Stakawata l2ca_hdr->lcid); 882281198Stakawata error = EINVAL; 883281198Stakawata goto drop; 884281198Stakawata } 885281198Stakawata 886281198Stakawata /* Verify that we have the channel and make sure it is open */ 887281198Stakawata ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid, 888281198Stakawata l2ca_hdr->idtype); 889107120Sjulian } 890281198Stakawata 891107120Sjulian if (ch == NULL) { 892107120Sjulian NG_L2CAP_ERR( 893107120Sjulian"%s: %s - invalid L2CA Data packet. Channel does not exist, cid=%d\n", 894107120Sjulian __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid); 895107120Sjulian error = ENOENT; 896107120Sjulian goto drop; 897107120Sjulian } 898107120Sjulian 899107120Sjulian if (ch->state != NG_L2CAP_OPEN) { 900107120Sjulian NG_L2CAP_ERR( 901107120Sjulian"%s: %s - invalid L2CA Data packet. Invalid channel state, scid=%d, state=%d\n", 902107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->scid, 903107120Sjulian ch->state); 904107120Sjulian error = EHOSTDOWN; 905107120Sjulian goto drop; /* XXX not always - re-configure */ 906107120Sjulian } 907107120Sjulian 908107120Sjulian /* Create L2CAP command descriptor */ 909107120Sjulian cmd = ng_l2cap_new_cmd(ch->con, ch, 0, NGM_L2CAP_L2CA_WRITE, token); 910107120Sjulian if (cmd == NULL) { 911107120Sjulian error = ENOMEM; 912107120Sjulian goto drop; 913107120Sjulian } 914107120Sjulian 915107120Sjulian /* Attach data packet and link command to the queue */ 916107120Sjulian cmd->aux = m; 917107120Sjulian ng_l2cap_link_cmd(ch->con, cmd); 918107120Sjulian ng_l2cap_lp_deliver(ch->con); 919107120Sjulian 920107120Sjulian return (error); 921107120Sjuliandrop: 922107120Sjulian NG_FREE_M(m); 923107120Sjulian 924107120Sjulian return (error); 925107120Sjulian} /* ng_l2cap_l2ca_write_req */ 926107120Sjulian 927107120Sjulian/* 928107120Sjulian * Send L2CA_Write response 929107120Sjulian */ 930107120Sjulian 931107120Sjulianint 932107120Sjulianng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result, 933107120Sjulian u_int16_t length) 934107120Sjulian{ 935107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 936107120Sjulian struct ng_mesg *msg = NULL; 937107120Sjulian ng_l2cap_l2ca_write_op *op = NULL; 938107120Sjulian int error = 0; 939107120Sjulian 940107120Sjulian /* Check if upstream hook is connected and valid */ 941107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 942107120Sjulian NG_L2CAP_ERR( 943107120Sjulian"%s: %s - unable to send L2CA_WriteRsp message. " \ 944107120Sjulian"Hook is not connected or valid, psm=%d\n", 945107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 946107120Sjulian 947107120Sjulian return (ENOTCONN); 948107120Sjulian } 949107120Sjulian 950107120Sjulian /* Create and send L2CA_WriteRsp message */ 951107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_WRITE, 952107120Sjulian sizeof(*op), M_NOWAIT); 953107120Sjulian if (msg == NULL) 954107120Sjulian error = ENOMEM; 955107120Sjulian else { 956107120Sjulian msg->header.token = token; 957107120Sjulian msg->header.flags |= NGF_RESP; 958107120Sjulian 959107120Sjulian op = (ng_l2cap_l2ca_write_op *)(msg->data); 960107120Sjulian op->result = result; 961107120Sjulian op->length = length; 962281198Stakawata if(ch->scid == NG_L2CAP_ATT_CID){ 963281198Stakawata op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT; 964281198Stakawata op->lcid = ch->con->con_handle; 965290038Stakawata }else if(ch->scid == NG_L2CAP_SMP_CID){ 966290038Stakawata op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP; 967290038Stakawata op->lcid = ch->con->con_handle; 968281198Stakawata }else{ 969281198Stakawata op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)? 970281198Stakawata NG_L2CAP_L2CA_IDTYPE_BREDR : 971281198Stakawata NG_L2CAP_L2CA_IDTYPE_LE; 972281198Stakawata op->lcid = ch->scid; 973281198Stakawata 974281198Stakawata } 975128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 976107120Sjulian } 977107120Sjulian 978107120Sjulian return (error); 979107120Sjulian} /* ng_l2cap_l2ca_write_rsp */ 980107120Sjulian 981107120Sjulian/* 982107120Sjulian * Receive packet from the lower layer protocol and send it to the upper 983107120Sjulian * layer protocol (L2CAP_Read) 984107120Sjulian */ 985107120Sjulian 986107120Sjulianint 987107120Sjulianng_l2cap_l2ca_receive(ng_l2cap_con_p con) 988107120Sjulian{ 989107120Sjulian ng_l2cap_p l2cap = con->l2cap; 990107120Sjulian ng_l2cap_hdr_t *hdr = NULL; 991107120Sjulian ng_l2cap_chan_p ch = NULL; 992107120Sjulian int error = 0; 993281198Stakawata int idtype; 994281198Stakawata uint16_t *idp; 995290038Stakawata int silent = 0; 996290038Stakawata 997107120Sjulian NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr)); 998107120Sjulian if (con->rx_pkt == NULL) 999107120Sjulian return (ENOBUFS); 1000107120Sjulian 1001107120Sjulian hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *); 1002107120Sjulian 1003107120Sjulian /* Check channel */ 1004281198Stakawata 1005281198Stakawata if(hdr->dcid == NG_L2CAP_ATT_CID){ 1006281198Stakawata idtype = NG_L2CAP_L2CA_IDTYPE_ATT; 1007281198Stakawata ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID, 1008281198Stakawata con->con_handle); 1009281198Stakawata /* 1010281198Stakawata * Here,ATT channel is distinguished by 1011281198Stakawata * connection handle 1012281198Stakawata */ 1013290038Stakawata hdr->dcid = con->con_handle; 1014290038Stakawata silent = 1; 1015290038Stakawata }else if(hdr->dcid == NG_L2CAP_SMP_CID){ 1016290038Stakawata idtype = NG_L2CAP_L2CA_IDTYPE_SMP; 1017290038Stakawata ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID, 1018290038Stakawata con->con_handle); 1019290038Stakawata /* 1020290038Stakawata * Here,SMP channel is distinguished by 1021290038Stakawata * connection handle 1022290038Stakawata */ 1023290038Stakawata silent = 1; 1024281198Stakawata hdr->dcid = con->con_handle; 1025281198Stakawata }else{ 1026281198Stakawata idtype = (con->linktype==NG_HCI_LINK_ACL)? 1027281198Stakawata NG_L2CAP_L2CA_IDTYPE_BREDR: 1028281198Stakawata NG_L2CAP_L2CA_IDTYPE_LE; 1029281198Stakawata ch = ng_l2cap_chan_by_scid(l2cap, hdr->dcid, idtype); 1030281198Stakawata } 1031107120Sjulian if (ch == NULL) { 1032290038Stakawata if(!silent) 1033290038Stakawata NG_L2CAP_ERR( 1034281198Stakawata"%s: %s - unexpected L2CAP data packet. Channel does not exist, cid=%d, idtype=%d\n", 1035281198Stakawata __func__, NG_NODE_NAME(l2cap->node), hdr->dcid, idtype); 1036107120Sjulian error = ENOENT; 1037107120Sjulian goto drop; 1038107120Sjulian } 1039107120Sjulian 1040107120Sjulian /* Check channel state */ 1041107120Sjulian if (ch->state != NG_L2CAP_OPEN) { 1042107120Sjulian NG_L2CAP_WARN( 1043107120Sjulian"%s: %s - unexpected L2CAP data packet. " \ 1044107120Sjulian"Invalid channel state, cid=%d, state=%d\n", 1045107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->scid, 1046107120Sjulian ch->state); 1047107120Sjulian error = EHOSTDOWN; /* XXX not always - re-configuration */ 1048107120Sjulian goto drop; 1049107120Sjulian } 1050107120Sjulian 1051107120Sjulian /* Check payload size and channel's MTU */ 1052107120Sjulian if (hdr->length > ch->imtu) { 1053107120Sjulian NG_L2CAP_ERR( 1054107120Sjulian"%s: %s - invalid L2CAP data packet. " \ 1055107120Sjulian"Packet too big, length=%d, imtu=%d, cid=%d\n", 1056107120Sjulian __func__, NG_NODE_NAME(l2cap->node), hdr->length, 1057107120Sjulian ch->imtu, ch->scid); 1058107120Sjulian error = EMSGSIZE; 1059107120Sjulian goto drop; 1060107120Sjulian } 1061107120Sjulian 1062107120Sjulian /* 1063107120Sjulian * If we got here then everything looks good and we can sent packet 1064107120Sjulian * to the upper layer protocol. 1065107120Sjulian */ 1066107120Sjulian 1067107120Sjulian /* Check if upstream hook is connected and valid */ 1068107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1069107120Sjulian NG_L2CAP_ERR( 1070107120Sjulian"%s: %s - unable to send L2CAP data packet. " \ 1071107120Sjulian"Hook is not connected or valid, psm=%d\n", 1072107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1073107120Sjulian error = ENOTCONN; 1074107120Sjulian goto drop; 1075107120Sjulian } 1076281198Stakawata M_PREPEND(con->rx_pkt, sizeof(uint16_t), M_NOWAIT); 1077281198Stakawata if(con->rx_pkt == NULL) 1078281198Stakawata goto drop; 1079281198Stakawata idp = mtod(con->rx_pkt, uint16_t *); 1080281198Stakawata *idp = idtype; 1081107120Sjulian 1082107120Sjulian NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt); 1083107120Sjulian con->rx_pkt = NULL; 1084107120Sjuliandrop: 1085107120Sjulian NG_FREE_M(con->rx_pkt); /* checks for != NULL */ 1086107120Sjulian 1087107120Sjulian return (error); 1088107120Sjulian} /* ng_l2cap_receive */ 1089107120Sjulian 1090107120Sjulian/* 1091107120Sjulian * Receive connectioless (multicast) packet from the lower layer protocol and 1092107120Sjulian * send it to the upper layer protocol 1093107120Sjulian */ 1094107120Sjulian 1095107120Sjulianint 1096107120Sjulianng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con) 1097107120Sjulian{ 1098107120Sjulian struct _clt_pkt { 1099107120Sjulian ng_l2cap_hdr_t h; 1100107120Sjulian ng_l2cap_clt_hdr_t c_h; 1101107120Sjulian } __attribute__ ((packed)) *hdr = NULL; 1102107120Sjulian ng_l2cap_p l2cap = con->l2cap; 1103107120Sjulian int length, error = 0; 1104107120Sjulian 1105107120Sjulian NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr)); 1106107120Sjulian if (con->rx_pkt == NULL) 1107107120Sjulian return (ENOBUFS); 1108107120Sjulian 1109107120Sjulian hdr = mtod(con->rx_pkt, struct _clt_pkt *); 1110107120Sjulian 1111107120Sjulian /* Check packet */ 1112107120Sjulian length = con->rx_pkt->m_pkthdr.len - sizeof(*hdr); 1113107120Sjulian if (length < 0) { 1114107120Sjulian NG_L2CAP_ERR( 1115107120Sjulian"%s: %s - invalid L2CAP CLT data packet. Packet too small, length=%d\n", 1116107120Sjulian __func__, NG_NODE_NAME(l2cap->node), length); 1117107120Sjulian error = EMSGSIZE; 1118107120Sjulian goto drop; 1119107120Sjulian } 1120107120Sjulian 1121107120Sjulian /* Check payload size against CLT MTU */ 1122107120Sjulian if (length > NG_L2CAP_MTU_DEFAULT) { 1123107120Sjulian NG_L2CAP_ERR( 1124107120Sjulian"%s: %s - invalid L2CAP CLT data packet. Packet too big, length=%d, mtu=%d\n", 1125107120Sjulian __func__, NG_NODE_NAME(l2cap->node), length, 1126107120Sjulian NG_L2CAP_MTU_DEFAULT); 1127107120Sjulian error = EMSGSIZE; 1128107120Sjulian goto drop; 1129107120Sjulian } 1130107120Sjulian 1131107120Sjulian hdr->c_h.psm = le16toh(hdr->c_h.psm); 1132107120Sjulian 1133107120Sjulian /* 1134107120Sjulian * If we got here then everything looks good and we can sent packet 1135107120Sjulian * to the upper layer protocol. 1136107120Sjulian */ 1137107120Sjulian 1138107120Sjulian /* Select upstream hook based on PSM */ 1139107120Sjulian switch (hdr->c_h.psm) { 1140107120Sjulian case NG_L2CAP_PSM_SDP: 1141107120Sjulian if (l2cap->flags & NG_L2CAP_CLT_SDP_DISABLED) 1142107120Sjulian goto drop; 1143107120Sjulian break; 1144107120Sjulian 1145107120Sjulian case NG_L2CAP_PSM_RFCOMM: 1146107120Sjulian if (l2cap->flags & NG_L2CAP_CLT_RFCOMM_DISABLED) 1147107120Sjulian goto drop; 1148107120Sjulian break; 1149107120Sjulian 1150107120Sjulian case NG_L2CAP_PSM_TCP: 1151107120Sjulian if (l2cap->flags & NG_L2CAP_CLT_TCP_DISABLED) 1152107120Sjulian goto drop; 1153107120Sjulian break; 1154107120Sjulian } 1155107120Sjulian 1156107120Sjulian /* Check if upstream hook is connected and valid */ 1157107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1158107120Sjulian NG_L2CAP_ERR( 1159107120Sjulian"%s: %s - unable to send L2CAP CLT data packet. " \ 1160107120Sjulian"Hook is not connected or valid, psm=%d\n", 1161107120Sjulian __func__, NG_NODE_NAME(l2cap->node), hdr->c_h.psm); 1162107120Sjulian error = ENOTCONN; 1163107120Sjulian goto drop; 1164107120Sjulian } 1165107120Sjulian 1166107120Sjulian NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt); 1167107120Sjulian con->rx_pkt = NULL; 1168107120Sjuliandrop: 1169107120Sjulian NG_FREE_M(con->rx_pkt); /* checks for != NULL */ 1170107120Sjulian 1171107120Sjulian return (error); 1172107120Sjulian} /* ng_l2cap_l2ca_clt_receive */ 1173107120Sjulian 1174107120Sjulian/* 1175107120Sjulian * Send L2CA_QoSViolationInd to the upper layer protocol 1176107120Sjulian */ 1177107120Sjulian 1178107120Sjulianint 1179107120Sjulianng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch) 1180107120Sjulian{ 1181107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 1182107120Sjulian struct ng_mesg *msg = NULL; 1183107120Sjulian ng_l2cap_l2ca_qos_ind_ip *ip = NULL; 1184107120Sjulian int error = 0; 1185107120Sjulian 1186107120Sjulian /* Check if upstream hook is connected and valid */ 1187107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1188107120Sjulian NG_L2CAP_ERR( 1189107120Sjulian"%s: %s - unable to send L2CA_QoSViolationInd message. " \ 1190107120Sjulian"Hook is not connected or valid, psm=%d\n", 1191107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1192107120Sjulian 1193107120Sjulian return (ENOTCONN); 1194107120Sjulian } 1195107120Sjulian 1196107120Sjulian /* Create and send L2CA_QoSViolationInd message */ 1197107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_QOS_IND, 1198107120Sjulian sizeof(*ip), M_NOWAIT); 1199107120Sjulian if (msg == NULL) 1200107120Sjulian error = ENOMEM; 1201107120Sjulian else { 1202107120Sjulian ip = (ng_l2cap_l2ca_qos_ind_ip *)(msg->data); 1203107120Sjulian bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr)); 1204128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1205107120Sjulian } 1206107120Sjulian 1207107120Sjulian return (error); 1208107120Sjulian} /* ng_l2cap_l2ca_qos_ind */ 1209107120Sjulian 1210107120Sjulian/* 1211107120Sjulian * Process L2CA_Disconnect request from the upper layer protocol. 1212107120Sjulian */ 1213107120Sjulian 1214107120Sjulianint 1215107120Sjulianng_l2cap_l2ca_discon_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1216107120Sjulian{ 1217107120Sjulian ng_l2cap_l2ca_discon_ip *ip = NULL; 1218107120Sjulian ng_l2cap_chan_p ch = NULL; 1219107120Sjulian ng_l2cap_cmd_p cmd = NULL; 1220107120Sjulian int error = 0; 1221107120Sjulian 1222107120Sjulian /* Check message */ 1223107120Sjulian if (msg->header.arglen != sizeof(*ip)) { 1224107120Sjulian NG_L2CAP_ALERT( 1225107120Sjulian"%s: %s - invalid L2CA_Disconnect request message size, size=%d\n", 1226107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 1227107120Sjulian msg->header.arglen); 1228107120Sjulian error = EMSGSIZE; 1229107120Sjulian goto out; 1230107120Sjulian } 1231107120Sjulian 1232107120Sjulian ip = (ng_l2cap_l2ca_discon_ip *)(msg->data); 1233107120Sjulian 1234281198Stakawata 1235281198Stakawata if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){ 1236281198Stakawata /* Don't send Disconnect request on L2CAP Layer*/ 1237281198Stakawata ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID, 1238281198Stakawata ip->lcid); 1239281198Stakawata 1240281198Stakawata if(ch != NULL){ 1241281198Stakawata ng_l2cap_free_chan(ch); 1242281198Stakawata }else{ 1243281198Stakawata NG_L2CAP_ERR( 1244281198Stakawata"%s: %s - unexpected L2CA_Disconnect request message. " \ 1245281198Stakawata"Channel does not exist, conhandle=%d\n", 1246281198Stakawata __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 1247281198Stakawata error = EINVAL; 1248281198Stakawata } 1249281198Stakawata goto out; 1250290038Stakawata }else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){ 1251290038Stakawata /* Don't send Disconnect request on L2CAP Layer*/ 1252290038Stakawata ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID, 1253290038Stakawata ip->lcid); 1254290038Stakawata 1255290038Stakawata if(ch != NULL){ 1256290038Stakawata ng_l2cap_free_chan(ch); 1257290038Stakawata }else{ 1258290038Stakawata NG_L2CAP_ERR( 1259290038Stakawata"%s: %s - unexpected L2CA_Disconnect request message. " \ 1260290038Stakawata"Channel does not exist, conhandle=%d\n", 1261290038Stakawata __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 1262290038Stakawata error = EINVAL; 1263290038Stakawata } 1264290038Stakawata goto out; 1265281198Stakawata }else{ 1266281198Stakawata /* Check if we have this channel */ 1267281198Stakawata ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, ip->idtype); 1268281198Stakawata } 1269107120Sjulian if (ch == NULL) { 1270107120Sjulian NG_L2CAP_ERR( 1271107120Sjulian"%s: %s - unexpected L2CA_Disconnect request message. " \ 1272107120Sjulian"Channel does not exist, lcid=%d\n", 1273107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 1274107120Sjulian error = ENOENT; 1275107120Sjulian goto out; 1276107120Sjulian } 1277107120Sjulian 1278107120Sjulian /* Check channel state */ 1279107120Sjulian if (ch->state != NG_L2CAP_CONFIG && ch->state != NG_L2CAP_OPEN && 1280107120Sjulian ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) { 1281107120Sjulian NG_L2CAP_ERR( 1282107120Sjulian"%s: %s - unexpected L2CA_Disconnect request message. " \ 1283107120Sjulian"Invalid channel state, state=%d, lcid=%d\n", 1284107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->state, 1285107120Sjulian ch->scid); 1286107120Sjulian error = EINVAL; 1287107120Sjulian goto out; 1288107120Sjulian } 1289107120Sjulian 1290107120Sjulian /* Create and send L2CAP_DisconReq message */ 1291107120Sjulian cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con), 1292107120Sjulian NG_L2CAP_DISCON_REQ, msg->header.token); 1293107120Sjulian if (cmd == NULL) { 1294107120Sjulian ng_l2cap_free_chan(ch); 1295107120Sjulian error = ENOMEM; 1296107120Sjulian goto out; 1297107120Sjulian } 1298107120Sjulian 1299107120Sjulian if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1300107120Sjulian ng_l2cap_free_chan(ch); 1301107120Sjulian ng_l2cap_free_cmd(cmd); 1302107120Sjulian error = EIO; 1303107120Sjulian goto out; 1304107120Sjulian } 1305107120Sjulian 1306107120Sjulian _ng_l2cap_discon_req(cmd->aux, cmd->ident, ch->dcid, ch->scid); 1307107120Sjulian if (cmd->aux == NULL) { 1308107120Sjulian ng_l2cap_free_chan(ch); 1309107120Sjulian ng_l2cap_free_cmd(cmd); 1310107120Sjulian error = ENOBUFS; 1311107120Sjulian goto out; 1312107120Sjulian } 1313107120Sjulian 1314107120Sjulian ch->state = NG_L2CAP_W4_L2CAP_DISCON_RSP; 1315107120Sjulian 1316107120Sjulian /* Link command to the queue */ 1317107120Sjulian ng_l2cap_link_cmd(ch->con, cmd); 1318107120Sjulian ng_l2cap_lp_deliver(ch->con); 1319107120Sjulianout: 1320107120Sjulian return (error); 1321107120Sjulian} /* ng_l2cap_l2ca_discon_req */ 1322107120Sjulian 1323107120Sjulian/* 1324107120Sjulian * Send L2CA_Disconnect response to the upper layer protocol 1325107120Sjulian */ 1326107120Sjulian 1327107120Sjulianint 1328107120Sjulianng_l2cap_l2ca_discon_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 1329107120Sjulian{ 1330107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 1331107120Sjulian struct ng_mesg *msg = NULL; 1332107120Sjulian ng_l2cap_l2ca_discon_op *op = NULL; 1333107120Sjulian int error = 0; 1334107120Sjulian 1335107120Sjulian /* Check if upstream hook is connected and valid */ 1336107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1337107120Sjulian NG_L2CAP_ERR( 1338107120Sjulian"%s: %s - unable to send L2CA_Disconnect response message. " \ 1339107120Sjulian"Hook is not connected or valid, psm=%d\n", 1340107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1341107120Sjulian 1342107120Sjulian return (ENOTCONN); 1343107120Sjulian } 1344107120Sjulian 1345107120Sjulian /* Create and send L2CA_Disconnect response message */ 1346107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON, 1347107120Sjulian sizeof(*op), M_NOWAIT); 1348107120Sjulian if (msg == NULL) 1349107120Sjulian error = ENOMEM; 1350107120Sjulian else { 1351107120Sjulian msg->header.token = token; 1352107120Sjulian msg->header.flags |= NGF_RESP; 1353107120Sjulian 1354107120Sjulian op = (ng_l2cap_l2ca_discon_op *)(msg->data); 1355107120Sjulian op->result = result; 1356107120Sjulian 1357128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1358107120Sjulian } 1359107120Sjulian 1360107120Sjulian return (error); 1361107120Sjulian} /* ng_l2cap_l2ca_discon_rsp */ 1362107120Sjulian 1363107120Sjulian/* 1364107120Sjulian * Send L2CA_DisconnectInd message to the upper layer protocol. 1365107120Sjulian */ 1366107120Sjulian 1367107120Sjulianint 1368107120Sjulianng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch) 1369107120Sjulian{ 1370107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 1371107120Sjulian struct ng_mesg *msg = NULL; 1372107120Sjulian ng_l2cap_l2ca_discon_ind_ip *ip = NULL; 1373107120Sjulian int error = 0; 1374107120Sjulian 1375107120Sjulian /* Check if upstream hook is connected and valid */ 1376107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1377107120Sjulian NG_L2CAP_ERR( 1378107120Sjulian"%s: %s - unable to send L2CA_DisconnectInd message. " \ 1379107120Sjulian"Hook is not connected or valid, psm=%d\n", 1380107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1381107120Sjulian 1382107120Sjulian return (ENOTCONN); 1383107120Sjulian } 1384107120Sjulian 1385107120Sjulian /* Create and send L2CA_DisconnectInd message */ 1386107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND, 1387107120Sjulian sizeof(*ip), M_NOWAIT); 1388107120Sjulian if (msg == NULL) 1389107120Sjulian error = ENOMEM; 1390107120Sjulian else { 1391107120Sjulian ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data); 1392301558Stakawata ip->idtype = ch->idtype; 1393301558Stakawata if(ch->idtype == NG_L2CAP_L2CA_IDTYPE_ATT|| 1394301558Stakawata ch->idtype == NG_L2CAP_L2CA_IDTYPE_SMP) 1395301558Stakawata ip->lcid = ch->con->con_handle; 1396301558Stakawata else 1397301558Stakawata ip->lcid = ch->scid; 1398301558Stakawata 1399128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1400107120Sjulian } 1401107120Sjulian 1402107120Sjulian return (error); 1403107120Sjulian} /* ng_l2cap_l2ca_discon_ind */ 1404107120Sjulian 1405107120Sjulian/* 1406107120Sjulian * Process L2CA_GroupCreate request from the upper layer protocol. 1407107120Sjulian * XXX FIXME 1408107120Sjulian */ 1409107120Sjulian 1410107120Sjulianint 1411107120Sjulianng_l2cap_l2ca_grp_create(ng_l2cap_p l2cap, struct ng_mesg *msg) 1412107120Sjulian{ 1413107120Sjulian return (ENOTSUP); 1414107120Sjulian} /* ng_l2cap_l2ca_grp_create */ 1415107120Sjulian 1416107120Sjulian/* 1417107120Sjulian * Process L2CA_GroupClose request from the upper layer protocol 1418107120Sjulian * XXX FIXME 1419107120Sjulian */ 1420107120Sjulian 1421107120Sjulianint 1422107120Sjulianng_l2cap_l2ca_grp_close(ng_l2cap_p l2cap, struct ng_mesg *msg) 1423107120Sjulian{ 1424107120Sjulian return (ENOTSUP); 1425107120Sjulian} /* ng_l2cap_l2ca_grp_close */ 1426107120Sjulian 1427107120Sjulian/* 1428107120Sjulian * Process L2CA_GroupAddMember request from the upper layer protocol. 1429107120Sjulian * XXX FIXME 1430107120Sjulian */ 1431107120Sjulian 1432107120Sjulianint 1433107120Sjulianng_l2cap_l2ca_grp_add_member_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1434107120Sjulian{ 1435107120Sjulian return (ENOTSUP); 1436107120Sjulian} /* ng_l2cap_l2ca_grp_add_member_req */ 1437107120Sjulian 1438107120Sjulian/* 1439107120Sjulian * Send L2CA_GroupAddMember response to the upper layer protocol. 1440107120Sjulian * XXX FIXME 1441107120Sjulian */ 1442107120Sjulian 1443107120Sjulianint 1444107120Sjulianng_l2cap_l2ca_grp_add_member_rsp(ng_l2cap_chan_p ch, u_int32_t token, 1445107120Sjulian u_int16_t result) 1446107120Sjulian{ 1447107120Sjulian return (0); 1448107120Sjulian} /* ng_l2cap_l2ca_grp_add_member_rsp */ 1449107120Sjulian 1450107120Sjulian/* 1451107120Sjulian * Process L2CA_GroupDeleteMember request from the upper layer protocol 1452107120Sjulian * XXX FIXME 1453107120Sjulian */ 1454107120Sjulian 1455107120Sjulianint 1456107120Sjulianng_l2cap_l2ca_grp_rem_member(ng_l2cap_p l2cap, struct ng_mesg *msg) 1457107120Sjulian{ 1458107120Sjulian return (ENOTSUP); 1459107120Sjulian} /* ng_l2cap_l2ca_grp_rem_member */ 1460107120Sjulian 1461107120Sjulian/* 1462107120Sjulian * Process L2CA_GroupGetMembers request from the upper layer protocol 1463107120Sjulian * XXX FIXME 1464107120Sjulian */ 1465107120Sjulian 1466107120Sjulianint 1467107120Sjulianng_l2cap_l2ca_grp_get_members(ng_l2cap_p l2cap, struct ng_mesg *msg) 1468107120Sjulian{ 1469107120Sjulian return (ENOTSUP); 1470107120Sjulian} /* ng_l2cap_l2ca_grp_get_members */ 1471107120Sjulian 1472107120Sjulian/* 1473107120Sjulian * Process L2CA_Ping request from the upper layer protocol 1474107120Sjulian */ 1475107120Sjulian 1476107120Sjulianint 1477107120Sjulianng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1478107120Sjulian{ 1479107120Sjulian ng_l2cap_l2ca_ping_ip *ip = NULL; 1480107120Sjulian ng_l2cap_con_p con = NULL; 1481107120Sjulian ng_l2cap_cmd_p cmd = NULL; 1482107120Sjulian int error = 0; 1483107120Sjulian 1484107120Sjulian /* Verify message */ 1485107120Sjulian if (msg->header.arglen < sizeof(*ip)) { 1486107120Sjulian NG_L2CAP_ALERT( 1487107120Sjulian"%s: %s - invalid L2CA_Ping request message size, size=%d\n", 1488107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 1489107120Sjulian msg->header.arglen); 1490107120Sjulian error = EMSGSIZE; 1491107120Sjulian goto out; 1492107120Sjulian } 1493107120Sjulian 1494107120Sjulian ip = (ng_l2cap_l2ca_ping_ip *)(msg->data); 1495107120Sjulian if (ip->echo_size > NG_L2CAP_MAX_ECHO_SIZE) { 1496107120Sjulian NG_L2CAP_WARN( 1497107120Sjulian"%s: %s - invalid L2CA_Ping request. Echo size is too big, echo_size=%d\n", 1498107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ip->echo_size); 1499107120Sjulian error = EMSGSIZE; 1500107120Sjulian goto out; 1501107120Sjulian } 1502107120Sjulian 1503107120Sjulian /* Check if we have connection to the unit */ 1504281198Stakawata con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL); 1505107120Sjulian if (con == NULL) { 1506107120Sjulian /* Submit LP_ConnectReq to the lower layer */ 1507281198Stakawata error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL); 1508107120Sjulian if (error != 0) { 1509107120Sjulian NG_L2CAP_ERR( 1510107120Sjulian"%s: %s - unable to send LP_ConnectReq message, error=%d\n", 1511107120Sjulian __func__, NG_NODE_NAME(l2cap->node), error); 1512107120Sjulian goto out; 1513107120Sjulian } 1514107120Sjulian 1515107120Sjulian /* This should not fail */ 1516281198Stakawata con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL); 1517107120Sjulian KASSERT((con != NULL), 1518107120Sjulian("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node))); 1519107120Sjulian } 1520107120Sjulian 1521107120Sjulian /* Create L2CAP command descriptor */ 1522107120Sjulian cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con), 1523107120Sjulian NG_L2CAP_ECHO_REQ, msg->header.token); 1524107120Sjulian if (cmd == NULL) { 1525107120Sjulian error = ENOMEM; 1526107120Sjulian goto out; 1527107120Sjulian } 1528107120Sjulian 1529107120Sjulian if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1530107120Sjulian ng_l2cap_free_cmd(cmd); 1531107120Sjulian error = EIO; 1532107120Sjulian goto out; 1533107120Sjulian } 1534107120Sjulian 1535107120Sjulian /* Create L2CAP command packet */ 1536107120Sjulian _ng_l2cap_echo_req(cmd->aux, cmd->ident, 1537107120Sjulian msg->data + sizeof(*ip), ip->echo_size); 1538107120Sjulian if (cmd->aux == NULL) { 1539107120Sjulian ng_l2cap_free_cmd(cmd); 1540107120Sjulian error = ENOBUFS; 1541107120Sjulian goto out; 1542107120Sjulian } 1543107120Sjulian 1544107120Sjulian /* Link command to the queue */ 1545107120Sjulian ng_l2cap_link_cmd(con, cmd); 1546107120Sjulian ng_l2cap_lp_deliver(con); 1547107120Sjulianout: 1548107120Sjulian return (error); 1549107120Sjulian} /* ng_l2cap_l2ca_ping_req */ 1550107120Sjulian 1551107120Sjulian/* 1552107120Sjulian * Send L2CA_Ping response to the upper layer protocol 1553107120Sjulian */ 1554107120Sjulian 1555107120Sjulianint 1556107120Sjulianng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result, 1557107120Sjulian struct mbuf *data) 1558107120Sjulian{ 1559107120Sjulian ng_l2cap_p l2cap = con->l2cap; 1560107120Sjulian struct ng_mesg *msg = NULL; 1561107120Sjulian ng_l2cap_l2ca_ping_op *op = NULL; 1562107120Sjulian int error = 0, size = 0; 1563107120Sjulian 1564107120Sjulian /* Check if control hook is connected and valid */ 1565107120Sjulian if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) { 1566107120Sjulian NG_L2CAP_WARN( 1567107120Sjulian"%s: %s - unable to send L2CA_Ping response message. " \ 1568107120Sjulian"Hook is not connected or valid\n", 1569107120Sjulian __func__, NG_NODE_NAME(l2cap->node)); 1570107120Sjulian error = ENOTCONN; 1571107120Sjulian goto out; 1572107120Sjulian } 1573107120Sjulian 1574107120Sjulian size = (data == NULL)? 0 : data->m_pkthdr.len; 1575107120Sjulian 1576107120Sjulian /* Create and send L2CA_Ping response message */ 1577107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_PING, 1578107120Sjulian sizeof(*op) + size, M_NOWAIT); 1579107120Sjulian if (msg == NULL) 1580107120Sjulian error = ENOMEM; 1581107120Sjulian else { 1582107120Sjulian msg->header.token = token; 1583107120Sjulian msg->header.flags |= NGF_RESP; 1584107120Sjulian 1585107120Sjulian op = (ng_l2cap_l2ca_ping_op *)(msg->data); 1586107120Sjulian op->result = result; 1587107120Sjulian bcopy(&con->remote, &op->bdaddr, sizeof(op->bdaddr)); 1588107120Sjulian if (data != NULL && size > 0) { 1589107120Sjulian op->echo_size = size; 1590107120Sjulian m_copydata(data, 0, size, (caddr_t) op + sizeof(*op)); 1591107120Sjulian } 1592107120Sjulian 1593128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1594107120Sjulian } 1595107120Sjulianout: 1596107120Sjulian NG_FREE_M(data); 1597107120Sjulian 1598107120Sjulian return (error); 1599107120Sjulian} /* ng_l2cap_l2ca_ping_rsp */ 1600107120Sjulian 1601107120Sjulian/* 1602107120Sjulian * Process L2CA_GetInfo request from the upper layer protocol 1603107120Sjulian */ 1604107120Sjulian 1605107120Sjulianint 1606107120Sjulianng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1607107120Sjulian{ 1608107120Sjulian ng_l2cap_l2ca_get_info_ip *ip = NULL; 1609107120Sjulian ng_l2cap_con_p con = NULL; 1610107120Sjulian ng_l2cap_cmd_p cmd = NULL; 1611107120Sjulian int error = 0; 1612107120Sjulian 1613107120Sjulian /* Verify message */ 1614107120Sjulian if (msg->header.arglen != sizeof(*ip)) { 1615107120Sjulian NG_L2CAP_ALERT( 1616107120Sjulian"%s: %s - invalid L2CA_GetInfo request message size, size=%d\n", 1617107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 1618107120Sjulian msg->header.arglen); 1619107120Sjulian error = EMSGSIZE; 1620107120Sjulian goto out; 1621107120Sjulian } 1622107120Sjulian 1623107120Sjulian ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data); 1624107120Sjulian 1625107120Sjulian /* Check if we have connection to the unit */ 1626281198Stakawata con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr,ip->linktype); 1627107120Sjulian if (con == NULL) { 1628107120Sjulian /* Submit LP_ConnectReq to the lower layer */ 1629281198Stakawata error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype); 1630107120Sjulian if (error != 0) { 1631107120Sjulian NG_L2CAP_ERR( 1632107120Sjulian"%s: %s - unable to send LP_ConnectReq message, error=%d\n", 1633107120Sjulian __func__, NG_NODE_NAME(l2cap->node), error); 1634107120Sjulian goto out; 1635107120Sjulian } 1636107120Sjulian 1637107120Sjulian /* This should not fail */ 1638281198Stakawata con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype); 1639107120Sjulian KASSERT((con != NULL), 1640107120Sjulian("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node))); 1641107120Sjulian } 1642107120Sjulian 1643107120Sjulian /* Create L2CAP command descriptor */ 1644107120Sjulian cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con), 1645107120Sjulian NG_L2CAP_INFO_REQ, msg->header.token); 1646107120Sjulian if (cmd == NULL) { 1647107120Sjulian error = ENOMEM; 1648107120Sjulian goto out; 1649107120Sjulian } 1650107120Sjulian 1651107120Sjulian if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1652107120Sjulian ng_l2cap_free_cmd(cmd); 1653107120Sjulian error = EIO; 1654107120Sjulian goto out; 1655107120Sjulian } 1656107120Sjulian 1657107120Sjulian /* Create L2CAP command packet */ 1658107120Sjulian _ng_l2cap_info_req(cmd->aux, cmd->ident, ip->info_type); 1659107120Sjulian if (cmd->aux == NULL) { 1660107120Sjulian ng_l2cap_free_cmd(cmd); 1661107120Sjulian error = ENOBUFS; 1662107120Sjulian goto out; 1663107120Sjulian } 1664107120Sjulian 1665107120Sjulian /* Link command to the queue */ 1666107120Sjulian ng_l2cap_link_cmd(con, cmd); 1667107120Sjulian ng_l2cap_lp_deliver(con); 1668107120Sjulianout: 1669107120Sjulian return (error); 1670107120Sjulian} /* ng_l2cap_l2ca_get_info_req */ 1671107120Sjulian 1672107120Sjulian/* 1673107120Sjulian * Send L2CA_GetInfo response to the upper layer protocol 1674107120Sjulian */ 1675107120Sjulian 1676107120Sjulianint 1677107120Sjulianng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con, u_int32_t token, 1678107120Sjulian u_int16_t result, struct mbuf *data) 1679107120Sjulian{ 1680107120Sjulian ng_l2cap_p l2cap = con->l2cap; 1681107120Sjulian struct ng_mesg *msg = NULL; 1682107120Sjulian ng_l2cap_l2ca_get_info_op *op = NULL; 1683107120Sjulian int error = 0, size; 1684107120Sjulian 1685107120Sjulian /* Check if control hook is connected and valid */ 1686107120Sjulian if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) { 1687107120Sjulian NG_L2CAP_WARN( 1688107120Sjulian"%s: %s - unable to send L2CA_GetInfo response message. " \ 1689107120Sjulian"Hook is not connected or valid\n", 1690107120Sjulian __func__, NG_NODE_NAME(l2cap->node)); 1691107120Sjulian error = ENOTCONN; 1692107120Sjulian goto out; 1693107120Sjulian } 1694107120Sjulian 1695107120Sjulian size = (data == NULL)? 0 : data->m_pkthdr.len; 1696107120Sjulian 1697107120Sjulian /* Create and send L2CA_GetInfo response message */ 1698107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_GET_INFO, 1699107120Sjulian sizeof(*op) + size, M_NOWAIT); 1700107120Sjulian if (msg == NULL) 1701107120Sjulian error = ENOMEM; 1702107120Sjulian else { 1703107120Sjulian msg->header.token = token; 1704107120Sjulian msg->header.flags |= NGF_RESP; 1705107120Sjulian 1706107120Sjulian op = (ng_l2cap_l2ca_get_info_op *)(msg->data); 1707107120Sjulian op->result = result; 1708107120Sjulian if (data != NULL && size > 0) { 1709107120Sjulian op->info_size = size; 1710107120Sjulian m_copydata(data, 0, size, (caddr_t) op + sizeof(*op)); 1711107120Sjulian } 1712107120Sjulian 1713128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1714107120Sjulian } 1715107120Sjulianout: 1716107120Sjulian NG_FREE_M(data); 1717107120Sjulian 1718107120Sjulian return (error); 1719107120Sjulian} /* ng_l2cap_l2ca_get_info_rsp */ 1720107120Sjulian 1721107120Sjulian/* 1722107120Sjulian * Process L2CA_EnableCLT message from the upper layer protocol 1723107120Sjulian * XXX convert to NGN_L2CAP_NODE_SET_FLAGS? 1724107120Sjulian */ 1725107120Sjulian 1726107120Sjulianint 1727107120Sjulianng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg) 1728107120Sjulian{ 1729107120Sjulian ng_l2cap_l2ca_enable_clt_ip *ip = NULL; 1730107120Sjulian int error = 0; 1731107120Sjulian#if 0 1732107120Sjulian * ng_l2cap_l2ca_enable_clt_op *op = NULL; 1733107120Sjulian * u_int16_t result; 1734107120Sjulian * u_int32_t token; 1735107120Sjulian#endif 1736107120Sjulian 1737107120Sjulian /* Check message */ 1738107120Sjulian if (msg->header.arglen != sizeof(*ip)) { 1739107120Sjulian NG_L2CAP_ALERT( 1740107120Sjulian"%s: %s - invalid L2CA_EnableCLT message size, size=%d\n", 1741107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 1742107120Sjulian msg->header.arglen); 1743107120Sjulian 1744107120Sjulian return (EMSGSIZE); 1745107120Sjulian } 1746107120Sjulian 1747107120Sjulian /* Process request */ 1748107120Sjulian ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data); 1749107120Sjulian#if 0 1750107120Sjulian * result = NG_L2CAP_SUCCESS; 1751107120Sjulian#endif 1752107120Sjulian 1753107120Sjulian switch (ip->psm) 1754107120Sjulian { 1755107120Sjulian case 0: 1756107120Sjulian /* Special case: disable/enable all PSM */ 1757107120Sjulian if (ip->enable) 1758107120Sjulian l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED | 1759107120Sjulian NG_L2CAP_CLT_RFCOMM_DISABLED | 1760107120Sjulian NG_L2CAP_CLT_TCP_DISABLED); 1761107120Sjulian else 1762107120Sjulian l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED | 1763107120Sjulian NG_L2CAP_CLT_RFCOMM_DISABLED | 1764107120Sjulian NG_L2CAP_CLT_TCP_DISABLED); 1765107120Sjulian break; 1766107120Sjulian 1767107120Sjulian case NG_L2CAP_PSM_SDP: 1768107120Sjulian if (ip->enable) 1769107120Sjulian l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED; 1770107120Sjulian else 1771107120Sjulian l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED; 1772107120Sjulian break; 1773107120Sjulian 1774107120Sjulian case NG_L2CAP_PSM_RFCOMM: 1775107120Sjulian if (ip->enable) 1776107120Sjulian l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED; 1777107120Sjulian else 1778107120Sjulian l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED; 1779107120Sjulian break; 1780107120Sjulian 1781107120Sjulian case NG_L2CAP_PSM_TCP: 1782107120Sjulian if (ip->enable) 1783107120Sjulian l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED; 1784107120Sjulian else 1785107120Sjulian l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED; 1786107120Sjulian break; 1787107120Sjulian 1788107120Sjulian default: 1789107120Sjulian NG_L2CAP_ERR( 1790107120Sjulian"%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm); 1791107120Sjulian#if 0 1792107120Sjulian * result = NG_L2CAP_PSM_NOT_SUPPORTED; 1793107120Sjulian#endif 1794107120Sjulian error = ENOTSUP; 1795107120Sjulian break; 1796107120Sjulian } 1797107120Sjulian 1798107120Sjulian#if 0 1799107120Sjulian * /* Create and send response message */ 1800107120Sjulian * token = msg->header.token; 1801107120Sjulian * NG_FREE_MSG(msg); 1802107120Sjulian * NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT, 1803107120Sjulian * sizeof(*op), M_NOWAIT); 1804107120Sjulian * if (msg == NULL) 1805107120Sjulian * error = ENOMEM; 1806107120Sjulian * else { 1807107120Sjulian * msg->header.token = token; 1808107120Sjulian * msg->header.flags |= NGF_RESP; 1809107120Sjulian * 1810107120Sjulian * op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data); 1811107120Sjulian * op->result = result; 1812107120Sjulian * } 1813107120Sjulian * 1814107120Sjulian * /* Send response to control hook */ 1815107120Sjulian * if (l2cap->ctl != NULL && NG_HOOK_IS_VALID(l2cap->ctl)) 1816128076Semax * NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1817107120Sjulian#endif 1818107120Sjulian 1819107120Sjulian return (error); 1820107120Sjulian} /* ng_l2cap_l2ca_enable_clt */ 1821107120Sjulian 1822