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 */ 84107120Sjulian con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr); 85107120Sjulian if (con == NULL) { 86107120Sjulian /* Submit LP_ConnectReq to the lower layer */ 87107120Sjulian error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr); 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 */ 96107120Sjulian con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr); 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 106107120Sjulian ch = ng_l2cap_new_chan(l2cap, con, ip->psm); 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 */ 129107120Sjulian _ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid); 130107120Sjulian if (cmd->aux == NULL) { 131107120Sjulian ng_l2cap_free_cmd(cmd); 132107120Sjulian ng_l2cap_free_chan(ch); 133107120Sjulian error = ENOBUFS; 134107120Sjulian goto out; 135107120Sjulian } 136107120Sjulian 137107120Sjulian ch->state = NG_L2CAP_W4_L2CAP_CON_RSP; 138107120Sjulian 139107120Sjulian /* Link command to the queue */ 140107120Sjulian ng_l2cap_link_cmd(ch->con, cmd); 141107120Sjulian ng_l2cap_lp_deliver(ch->con); 142107120Sjulianout: 143107120Sjulian return (error); 144107120Sjulian} /* ng_l2cap_l2ca_con_req */ 145107120Sjulian 146107120Sjulian/* 147107120Sjulian * Send L2CA_Connect response to the upper layer protocol. 148107120Sjulian */ 149107120Sjulian 150107120Sjulianint 151107120Sjulianng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result, 152107120Sjulian u_int16_t status) 153107120Sjulian{ 154107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 155107120Sjulian struct ng_mesg *msg = NULL; 156107120Sjulian ng_l2cap_l2ca_con_op *op = NULL; 157107120Sjulian int error = 0; 158107120Sjulian 159107120Sjulian /* Check if upstream hook is connected and valid */ 160107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 161107120Sjulian NG_L2CAP_ERR( 162107120Sjulian"%s: %s - unable to send L2CA_Connect response message. " \ 163107120Sjulian"Hook is not connected or valid, psm=%d\n", 164107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 165107120Sjulian 166107120Sjulian return (ENOTCONN); 167107120Sjulian } 168107120Sjulian 169107120Sjulian /* Create and send L2CA_Connect response message */ 170107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON, 171107120Sjulian sizeof(*op), M_NOWAIT); 172107120Sjulian if (msg == NULL) 173107120Sjulian error = ENOMEM; 174107120Sjulian else { 175107120Sjulian msg->header.token = token; 176107120Sjulian msg->header.flags |= NGF_RESP; 177107120Sjulian 178107120Sjulian op = (ng_l2cap_l2ca_con_op *)(msg->data); 179107120Sjulian 180107120Sjulian /* 181107120Sjulian * XXX Spec. says we should only populate LCID when result == 0 182107120Sjulian * What about PENDING? What the heck, for now always populate 183107120Sjulian * LCID :) 184107120Sjulian */ 185107120Sjulian 186107120Sjulian op->lcid = ch->scid; 187107120Sjulian op->result = result; 188107120Sjulian op->status = status; 189107120Sjulian 190128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 191107120Sjulian } 192107120Sjulian 193107120Sjulian return (error); 194107120Sjulian} /* ng_l2cap_l2ca_con_rsp */ 195107120Sjulian 196107120Sjulian/* 197107120Sjulian * Process L2CA_ConnectRsp request from the upper layer protocol. 198107120Sjulian */ 199107120Sjulian 200107120Sjulianint 201107120Sjulianng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 202107120Sjulian{ 203107120Sjulian ng_l2cap_l2ca_con_rsp_ip *ip = NULL; 204107120Sjulian ng_l2cap_con_p con = NULL; 205107120Sjulian ng_l2cap_chan_p ch = NULL; 206107120Sjulian ng_l2cap_cmd_p cmd = NULL; 207107120Sjulian u_int16_t dcid; 208107120Sjulian int error = 0; 209107120Sjulian 210107120Sjulian /* Check message */ 211107120Sjulian if (msg->header.arglen != sizeof(*ip)) { 212107120Sjulian NG_L2CAP_ALERT( 213107120Sjulian"%s: %s - invalid L2CA_ConnectRsp request message size, size=%d\n", 214107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 215107120Sjulian msg->header.arglen); 216107120Sjulian error = EMSGSIZE; 217107120Sjulian goto out; 218107120Sjulian } 219107120Sjulian 220107120Sjulian ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data); 221107120Sjulian 222107120Sjulian /* Check if we have this channel */ 223107120Sjulian ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid); 224107120Sjulian if (ch == NULL) { 225107120Sjulian NG_L2CAP_ALERT( 226107120Sjulian"%s: %s - unexpected L2CA_ConnectRsp request message. " \ 227107120Sjulian"Channel does not exist, lcid=%d\n", 228107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 229107120Sjulian error = ENOENT; 230107120Sjulian goto out; 231107120Sjulian } 232107120Sjulian 233107120Sjulian /* Check channel state */ 234107120Sjulian if (ch->state != NG_L2CAP_W4_L2CA_CON_RSP) { 235107120Sjulian NG_L2CAP_ERR( 236107120Sjulian"%s: %s - unexpected L2CA_ConnectRsp request message. " \ 237107120Sjulian"Invalid channel state, state=%d, lcid=%d\n", 238107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->state, 239107120Sjulian ip->lcid); 240107120Sjulian error = EINVAL; 241107120Sjulian goto out; 242107120Sjulian } 243107120Sjulian 244107120Sjulian dcid = ch->dcid; 245107120Sjulian con = ch->con; 246107120Sjulian 247107120Sjulian /* 248107120Sjulian * Now we are pretty much sure it is our response. So create and send 249107120Sjulian * L2CAP_ConnectRsp message to our peer. 250107120Sjulian */ 251107120Sjulian 252107120Sjulian if (ch->ident != ip->ident) 253107120Sjulian NG_L2CAP_WARN( 254107120Sjulian"%s: %s - channel ident and response ident do not match, scid=%d, ident=%d. " \ 255107120Sjulian"Will use response ident=%d\n", 256107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->scid, 257107120Sjulian ch->ident, ip->ident); 258107120Sjulian 259107120Sjulian /* Check result */ 260107120Sjulian switch (ip->result) { 261107120Sjulian case NG_L2CAP_SUCCESS: 262107120Sjulian ch->state = NG_L2CAP_CONFIG; 263107120Sjulian ch->cfg_state = 0; 264107120Sjulian break; 265107120Sjulian 266107120Sjulian case NG_L2CAP_PENDING: 267107120Sjulian break; 268107120Sjulian 269107120Sjulian default: 270107120Sjulian ng_l2cap_free_chan(ch); 271107120Sjulian ch = NULL; 272107120Sjulian break; 273107120Sjulian } 274107120Sjulian 275107120Sjulian /* Create L2CAP command */ 276107120Sjulian cmd = ng_l2cap_new_cmd(con, ch, ip->ident, NG_L2CAP_CON_RSP, 277107120Sjulian msg->header.token); 278107120Sjulian if (cmd == NULL) { 279107120Sjulian if (ch != NULL) 280107120Sjulian ng_l2cap_free_chan(ch); 281107120Sjulian 282107120Sjulian error = ENOMEM; 283107120Sjulian goto out; 284107120Sjulian } 285107120Sjulian 286107120Sjulian _ng_l2cap_con_rsp(cmd->aux, cmd->ident, ip->lcid, dcid, 287107120Sjulian ip->result, ip->status); 288107120Sjulian if (cmd->aux == NULL) { 289107120Sjulian if (ch != NULL) 290107120Sjulian ng_l2cap_free_chan(ch); 291107120Sjulian 292107120Sjulian ng_l2cap_free_cmd(cmd); 293107120Sjulian error = ENOBUFS; 294107120Sjulian goto out; 295107120Sjulian } 296107120Sjulian 297107120Sjulian /* Link command to the queue */ 298107120Sjulian ng_l2cap_link_cmd(con, cmd); 299107120Sjulian ng_l2cap_lp_deliver(con); 300107120Sjulianout: 301107120Sjulian return (error); 302107120Sjulian} /* ng_l2cap_l2ca_con_rsp_req */ 303107120Sjulian 304107120Sjulian/* 305107120Sjulian * Send L2CAP_ConnectRsp response to the upper layer 306107120Sjulian */ 307107120Sjulian 308107120Sjulianint 309107120Sjulianng_l2cap_l2ca_con_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 310107120Sjulian{ 311107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 312107120Sjulian struct ng_mesg *msg = NULL; 313107120Sjulian ng_l2cap_l2ca_con_rsp_op *op = NULL; 314107120Sjulian int error = 0; 315107120Sjulian 316107120Sjulian /* Check if upstream hook is connected and valid */ 317107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 318107120Sjulian NG_L2CAP_ERR( 319107120Sjulian"%s: %s - unable to send L2CA_ConnectRsp response message. " \ 320107120Sjulian"Hook is not connected or valid, psm=%d\n", 321107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 322107120Sjulian 323107120Sjulian return (ENOTCONN); 324107120Sjulian } 325107120Sjulian 326107120Sjulian /* Create and send L2CA_ConnectRsp response message */ 327107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_RSP, 328107120Sjulian sizeof(*op), M_NOWAIT); 329107120Sjulian if (msg == NULL) 330107120Sjulian error = ENOMEM; 331107120Sjulian else { 332107120Sjulian msg->header.token = token; 333107120Sjulian msg->header.flags |= NGF_RESP; 334107120Sjulian 335107120Sjulian op = (ng_l2cap_l2ca_con_rsp_op *)(msg->data); 336107120Sjulian op->result = result; 337107120Sjulian 338128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 339107120Sjulian } 340107120Sjulian 341107120Sjulian return (error); 342107120Sjulian} /* ng_l2cap_l2ca_con_rsp_rsp */ 343107120Sjulian 344107120Sjulian/* 345107120Sjulian * Send L2CA_ConnectInd message to the upper layer protocol. 346107120Sjulian */ 347107120Sjulian 348107120Sjulianint 349107120Sjulianng_l2cap_l2ca_con_ind(ng_l2cap_chan_p ch) 350107120Sjulian{ 351107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 352107120Sjulian struct ng_mesg *msg = NULL; 353107120Sjulian ng_l2cap_l2ca_con_ind_ip *ip = NULL; 354107120Sjulian int error = 0; 355107120Sjulian 356107120Sjulian /* Check if upstream hook is connected and valid */ 357107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 358107120Sjulian NG_L2CAP_ERR( 359107120Sjulian"%s: %s - unable to send L2CA_ConnectInd message. " \ 360107120Sjulian"Hook is not connected or valid, psm=%d\n", 361107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 362107120Sjulian 363107120Sjulian return (ENOTCONN); 364107120Sjulian } 365107120Sjulian 366107120Sjulian /* Create and send L2CA_ConnectInd message */ 367107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_IND, 368107120Sjulian sizeof(*ip), M_NOWAIT); 369107120Sjulian if (msg == NULL) 370107120Sjulian error = ENOMEM; 371107120Sjulian else { 372107120Sjulian ip = (ng_l2cap_l2ca_con_ind_ip *)(msg->data); 373107120Sjulian 374107120Sjulian bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr)); 375107120Sjulian ip->lcid = ch->scid; 376107120Sjulian ip->psm = ch->psm; 377107120Sjulian ip->ident = ch->ident; 378107120Sjulian 379128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 380107120Sjulian } 381107120Sjulian 382107120Sjulian return (error); 383107120Sjulian} /* ng_l2cap_l2ca_con_ind */ 384107120Sjulian 385107120Sjulian/* 386107120Sjulian * Process L2CA_Config request from the upper layer protocol 387107120Sjulian */ 388107120Sjulian 389107120Sjulianint 390107120Sjulianng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 391107120Sjulian{ 392107120Sjulian ng_l2cap_l2ca_cfg_ip *ip = NULL; 393107120Sjulian ng_l2cap_chan_p ch = NULL; 394107120Sjulian ng_l2cap_cmd_p cmd = NULL; 395107120Sjulian struct mbuf *opt = NULL; 396107120Sjulian u_int16_t *mtu = NULL, *flush_timo = NULL; 397107120Sjulian ng_l2cap_flow_p flow = NULL; 398107120Sjulian int error = 0; 399107120Sjulian 400107120Sjulian /* Check message */ 401107120Sjulian if (msg->header.arglen != sizeof(*ip)) { 402107120Sjulian NG_L2CAP_ALERT( 403107120Sjulian"%s: %s - Invalid L2CA_Config request message size, size=%d\n", 404107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 405107120Sjulian msg->header.arglen); 406107120Sjulian error = EMSGSIZE; 407107120Sjulian goto out; 408107120Sjulian } 409107120Sjulian 410107120Sjulian ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data); 411107120Sjulian 412107120Sjulian /* Check if we have this channel */ 413107120Sjulian ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid); 414107120Sjulian if (ch == NULL) { 415107120Sjulian NG_L2CAP_ERR( 416107120Sjulian"%s: %s - unexpected L2CA_Config request message. " \ 417107120Sjulian"Channel does not exist, lcid=%d\n", 418107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 419107120Sjulian error = ENOENT; 420107120Sjulian goto out; 421107120Sjulian } 422107120Sjulian 423107120Sjulian /* Check channel state */ 424107120Sjulian if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG) { 425107120Sjulian NG_L2CAP_ERR( 426107120Sjulian"%s: %s - unexpected L2CA_Config request message. " \ 427107120Sjulian"Invalid channel state, state=%d, lcid=%d\n", 428107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->state, 429107120Sjulian ch->scid); 430107120Sjulian error = EINVAL; 431107120Sjulian goto out; 432107120Sjulian } 433107120Sjulian 434107120Sjulian /* Set requested channel configuration options */ 435107120Sjulian ch->imtu = ip->imtu; 436107120Sjulian bcopy(&ip->oflow, &ch->oflow, sizeof(ch->oflow)); 437107120Sjulian ch->flush_timo = ip->flush_timo; 438107120Sjulian ch->link_timo = ip->link_timo; 439107120Sjulian 440107120Sjulian /* Compare channel settings with defaults */ 441107120Sjulian if (ch->imtu != NG_L2CAP_MTU_DEFAULT) 442107120Sjulian mtu = &ch->imtu; 443107120Sjulian if (ch->flush_timo != NG_L2CAP_FLUSH_TIMO_DEFAULT) 444107120Sjulian flush_timo = &ch->flush_timo; 445107120Sjulian if (bcmp(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)) != 0) 446107120Sjulian flow = &ch->oflow; 447107120Sjulian 448107120Sjulian /* Create configuration options */ 449107120Sjulian _ng_l2cap_build_cfg_options(opt, mtu, flush_timo, flow); 450107120Sjulian if (opt == NULL) { 451107120Sjulian error = ENOBUFS; 452107120Sjulian goto out; 453107120Sjulian } 454107120Sjulian 455107120Sjulian /* Create L2CAP command descriptor */ 456107120Sjulian cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con), 457107120Sjulian NG_L2CAP_CFG_REQ, msg->header.token); 458107120Sjulian if (cmd == NULL) { 459107120Sjulian NG_FREE_M(opt); 460107120Sjulian error = ENOMEM; 461107120Sjulian goto out; 462107120Sjulian } 463107120Sjulian 464107120Sjulian if (cmd->ident == NG_L2CAP_NULL_IDENT) { 465107120Sjulian ng_l2cap_free_cmd(cmd); 466107120Sjulian NG_FREE_M(opt); 467107120Sjulian error = EIO; 468107120Sjulian goto out; 469107120Sjulian } 470107120Sjulian 471107120Sjulian /* Create L2CAP command packet */ 472107120Sjulian _ng_l2cap_cfg_req(cmd->aux, cmd->ident, ch->dcid, 0, opt); 473107120Sjulian if (cmd->aux == NULL) { 474107120Sjulian ng_l2cap_free_cmd(cmd); 475107120Sjulian error = ENOBUFS; 476107120Sjulian goto out; 477107120Sjulian } 478107120Sjulian 479107120Sjulian /* Adjust channel state for re-configuration */ 480107120Sjulian if (ch->state == NG_L2CAP_OPEN) { 481107120Sjulian ch->state = NG_L2CAP_CONFIG; 482107120Sjulian ch->cfg_state = 0; 483107120Sjulian } 484107120Sjulian 485107120Sjulian /* Link command to the queue */ 486107120Sjulian ng_l2cap_link_cmd(ch->con, cmd); 487107120Sjulian ng_l2cap_lp_deliver(ch->con); 488107120Sjulianout: 489107120Sjulian return (error); 490107120Sjulian} /* ng_l2cap_l2ca_cfg_req */ 491107120Sjulian 492107120Sjulian/* 493107120Sjulian * Send L2CA_Config response to the upper layer protocol 494107120Sjulian */ 495107120Sjulian 496107120Sjulianint 497107120Sjulianng_l2cap_l2ca_cfg_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 498107120Sjulian{ 499107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 500107120Sjulian struct ng_mesg *msg = NULL; 501107120Sjulian ng_l2cap_l2ca_cfg_op *op = NULL; 502107120Sjulian int error = 0; 503107120Sjulian 504107120Sjulian /* Check if upstream hook is connected and valid */ 505107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 506107120Sjulian NG_L2CAP_ERR( 507107120Sjulian"%s: %s - unable to send L2CA_Config response message. " \ 508107120Sjulian"Hook is not connected or valid, psm=%d\n", 509107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 510107120Sjulian 511107120Sjulian return (ENOTCONN); 512107120Sjulian } 513107120Sjulian 514107120Sjulian /* Create and send L2CA_Config response message */ 515107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG, 516107120Sjulian sizeof(*op), M_NOWAIT); 517107120Sjulian if (msg == NULL) 518107120Sjulian error = ENOMEM; 519107120Sjulian else { 520107120Sjulian msg->header.token = token; 521107120Sjulian msg->header.flags |= NGF_RESP; 522107120Sjulian 523107120Sjulian op = (ng_l2cap_l2ca_cfg_op *)(msg->data); 524107120Sjulian op->result = result; 525107120Sjulian op->imtu = ch->imtu; 526107120Sjulian bcopy(&ch->oflow, &op->oflow, sizeof(op->oflow)); 527107120Sjulian op->flush_timo = ch->flush_timo; 528107120Sjulian 529128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 530107120Sjulian 531107120Sjulian if (error == 0 && result == NG_L2CAP_SUCCESS) { 532107120Sjulian ch->cfg_state |= NG_L2CAP_CFG_IN; 533107120Sjulian 534107120Sjulian if (ch->cfg_state == NG_L2CAP_CFG_BOTH) 535107120Sjulian ch->state = NG_L2CAP_OPEN; 536107120Sjulian } 537107120Sjulian } 538107120Sjulian 539107120Sjulian return (error); 540107120Sjulian} /* ng_l2cap_l2ca_cfg_rsp */ 541107120Sjulian 542107120Sjulian/* 543107120Sjulian * Process L2CA_ConfigRsp request from the upper layer protocol 544107120Sjulian * 545107120Sjulian * XXX XXX XXX 546107120Sjulian * 547107120Sjulian * NOTE: The Bluetooth specification says that Configuration_Response 548107120Sjulian * (L2CA_ConfigRsp) should be used to issue response to configuration request 549107120Sjulian * indication. The minor problem here is L2CAP command ident. We should use 550107120Sjulian * ident from original L2CAP request to make sure our peer can match request 551107120Sjulian * and response. For some reason Bluetooth specification does not include 552107120Sjulian * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems 553107120Sjulian * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident 554107120Sjulian * field. So we should store last known L2CAP request command ident in channel. 555107120Sjulian * Also it seems that upper layer can not reject configuration request, as 556107120Sjulian * Configuration_Response message does not have status/reason field. 557107120Sjulian */ 558107120Sjulian 559107120Sjulianint 560107120Sjulianng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 561107120Sjulian{ 562107120Sjulian ng_l2cap_l2ca_cfg_rsp_ip *ip = NULL; 563107120Sjulian ng_l2cap_chan_p ch = NULL; 564107120Sjulian ng_l2cap_cmd_p cmd = NULL; 565107120Sjulian struct mbuf *opt = NULL; 566107120Sjulian u_int16_t *mtu = NULL; 567107120Sjulian ng_l2cap_flow_p flow = NULL; 568107120Sjulian int error = 0; 569107120Sjulian 570107120Sjulian /* Check message */ 571107120Sjulian if (msg->header.arglen != sizeof(*ip)) { 572107120Sjulian NG_L2CAP_ALERT( 573107120Sjulian"%s: %s - invalid L2CA_ConfigRsp request message size, size=%d\n", 574107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 575107120Sjulian msg->header.arglen); 576107120Sjulian error = EMSGSIZE; 577107120Sjulian goto out; 578107120Sjulian } 579107120Sjulian 580107120Sjulian ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data); 581107120Sjulian 582107120Sjulian /* Check if we have this channel */ 583107120Sjulian ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid); 584107120Sjulian if (ch == NULL) { 585107120Sjulian NG_L2CAP_ERR( 586107120Sjulian"%s: %s - unexpected L2CA_ConfigRsp request message. " \ 587107120Sjulian"Channel does not exist, lcid=%d\n", 588107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 589107120Sjulian error = ENOENT; 590107120Sjulian goto out; 591107120Sjulian } 592107120Sjulian 593107120Sjulian /* Check channel state */ 594107120Sjulian if (ch->state != NG_L2CAP_CONFIG) { 595107120Sjulian NG_L2CAP_ERR( 596107120Sjulian"%s: %s - unexpected L2CA_ConfigRsp request message. " \ 597107120Sjulian"Invalid channel state, state=%d, lcid=%d\n", 598107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->state, 599107120Sjulian ch->scid); 600107120Sjulian error = EINVAL; 601107120Sjulian goto out; 602107120Sjulian } 603107120Sjulian 604107120Sjulian /* Set channel settings */ 605107120Sjulian if (ip->omtu != ch->omtu) { 606107120Sjulian ch->omtu = ip->omtu; 607107120Sjulian mtu = &ch->omtu; 608107120Sjulian } 609107120Sjulian 610107120Sjulian if (bcmp(&ip->iflow, &ch->iflow, sizeof(ch->iflow)) != 0) { 611107120Sjulian bcopy(&ip->iflow, &ch->iflow, sizeof(ch->iflow)); 612107120Sjulian flow = &ch->iflow; 613107120Sjulian } 614107120Sjulian 615107120Sjulian if (mtu != NULL || flow != NULL) { 616107120Sjulian _ng_l2cap_build_cfg_options(opt, mtu, NULL, flow); 617107120Sjulian if (opt == NULL) { 618107120Sjulian error = ENOBUFS; 619107120Sjulian goto out; 620107120Sjulian } 621107120Sjulian } 622107120Sjulian 623107120Sjulian /* Create L2CAP command */ 624107120Sjulian cmd = ng_l2cap_new_cmd(ch->con, ch, ch->ident, NG_L2CAP_CFG_RSP, 625107120Sjulian msg->header.token); 626107120Sjulian if (cmd == NULL) { 627107120Sjulian NG_FREE_M(opt); 628107120Sjulian error = ENOMEM; 629107120Sjulian goto out; 630107120Sjulian } 631107120Sjulian 632107120Sjulian _ng_l2cap_cfg_rsp(cmd->aux,cmd->ident,ch->dcid,0,NG_L2CAP_SUCCESS,opt); 633107120Sjulian if (cmd->aux == NULL) { 634107120Sjulian ng_l2cap_free_cmd(cmd); 635107120Sjulian error = ENOBUFS; 636107120Sjulian goto out; 637107120Sjulian } 638107120Sjulian 639107120Sjulian /* XXX FIXME - not here ??? */ 640107120Sjulian ch->cfg_state |= NG_L2CAP_CFG_OUT; 641107120Sjulian if (ch->cfg_state == NG_L2CAP_CFG_BOTH) 642107120Sjulian ch->state = NG_L2CAP_OPEN; 643107120Sjulian 644107120Sjulian /* Link command to the queue */ 645107120Sjulian ng_l2cap_link_cmd(ch->con, cmd); 646107120Sjulian ng_l2cap_lp_deliver(ch->con); 647107120Sjulianout: 648107120Sjulian return (error); 649107120Sjulian} /* ng_l2cap_l2ca_cfg_rsp_req */ 650107120Sjulian 651107120Sjulian/* 652107120Sjulian * Send L2CA_ConfigRsp response to the upper layer protocol 653107120Sjulian */ 654107120Sjulian 655107120Sjulianint 656107120Sjulianng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 657107120Sjulian{ 658107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 659107120Sjulian struct ng_mesg *msg = NULL; 660107120Sjulian ng_l2cap_l2ca_cfg_rsp_op *op = NULL; 661107120Sjulian int error = 0; 662107120Sjulian 663107120Sjulian /* Check if upstream hook is connected and valid */ 664107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 665107120Sjulian NG_L2CAP_ERR( 666107120Sjulian"%s: %s - unable to send L2CA_ConfigRsp response message. " \ 667107120Sjulian"Hook is not connected or valid, psm=%d\n", 668107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 669107120Sjulian 670107120Sjulian return (ENOTCONN); 671107120Sjulian } 672107120Sjulian 673107120Sjulian /* Create and send L2CA_ConfigRsp response message */ 674107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP, 675107120Sjulian sizeof(*op), M_NOWAIT); 676107120Sjulian if (msg == NULL) 677107120Sjulian error = ENOMEM; 678107120Sjulian else { 679107120Sjulian msg->header.token = token; 680107120Sjulian msg->header.flags |= NGF_RESP; 681107120Sjulian 682107120Sjulian op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data); 683107120Sjulian op->result = result; 684107120Sjulian 685128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 686107120Sjulian } 687107120Sjulian 688107120Sjulian return (error); 689107120Sjulian} /* ng_l2cap_l2ca_cfg_rsp_rsp */ 690107120Sjulian 691107120Sjulian/* 692107120Sjulian * Send L2CA_ConfigInd message to the upper layer protocol 693107120Sjulian * 694107120Sjulian * XXX XXX XXX 695107120Sjulian * 696107120Sjulian * NOTE: The Bluetooth specification says that Configuration_Response 697107120Sjulian * (L2CA_ConfigRsp) should be used to issue response to configuration request 698107120Sjulian * indication. The minor problem here is L2CAP command ident. We should use 699107120Sjulian * ident from original L2CAP request to make sure our peer can match request 700107120Sjulian * and response. For some reason Bluetooth specification does not include 701107120Sjulian * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems 702107120Sjulian * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident 703107120Sjulian * field. So we should store last known L2CAP request command ident in channel. 704107120Sjulian * Also it seems that upper layer can not reject configuration request, as 705107120Sjulian * Configuration_Response message does not have status/reason field. 706107120Sjulian */ 707107120Sjulian 708107120Sjulianint 709107120Sjulianng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch) 710107120Sjulian{ 711107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 712107120Sjulian struct ng_mesg *msg = NULL; 713107120Sjulian ng_l2cap_l2ca_cfg_ind_ip *ip = NULL; 714107120Sjulian int error = 0; 715107120Sjulian 716107120Sjulian /* Check if upstream hook is connected and valid */ 717107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 718107120Sjulian NG_L2CAP_ERR( 719107120Sjulian"%s: %s - Unable to send L2CA_ConfigInd message. " \ 720107120Sjulian"Hook is not connected or valid, psm=%d\n", 721107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 722107120Sjulian 723107120Sjulian return (ENOTCONN); 724107120Sjulian } 725107120Sjulian 726107120Sjulian /* Create and send L2CA_ConnectInd message */ 727107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_IND, 728107120Sjulian sizeof(*ip), M_NOWAIT); 729107120Sjulian if (msg == NULL) 730107120Sjulian error = ENOMEM; 731107120Sjulian else { 732107120Sjulian ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data); 733107120Sjulian ip->lcid = ch->scid; 734107120Sjulian ip->omtu = ch->omtu; 735107120Sjulian bcopy(&ch->iflow, &ip->iflow, sizeof(ip->iflow)); 736107120Sjulian ip->flush_timo = ch->flush_timo; 737107120Sjulian 738128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 739107120Sjulian } 740107120Sjulian 741107120Sjulian return (error); 742107120Sjulian} /* ng_l2cap_l2ca_cfg_ind */ 743107120Sjulian 744107120Sjulian/* 745107120Sjulian * Process L2CA_Write event 746107120Sjulian */ 747107120Sjulian 748107120Sjulianint 749107120Sjulianng_l2cap_l2ca_write_req(ng_l2cap_p l2cap, struct mbuf *m) 750107120Sjulian{ 751107120Sjulian ng_l2cap_l2ca_hdr_t *l2ca_hdr = NULL; 752107120Sjulian ng_l2cap_chan_p ch = NULL; 753107120Sjulian ng_l2cap_cmd_p cmd = NULL; 754107120Sjulian int error = 0; 755107120Sjulian u_int32_t token = 0; 756107120Sjulian 757107120Sjulian /* Make sure we can access L2CA data packet header */ 758107120Sjulian if (m->m_pkthdr.len < sizeof(*l2ca_hdr)) { 759107120Sjulian NG_L2CAP_ERR( 760107120Sjulian"%s: %s - L2CA Data packet too small, len=%d\n", 761107120Sjulian __func__,NG_NODE_NAME(l2cap->node),m->m_pkthdr.len); 762107120Sjulian error = EMSGSIZE; 763107120Sjulian goto drop; 764107120Sjulian } 765107120Sjulian 766107120Sjulian /* Get L2CA data packet header */ 767107120Sjulian NG_L2CAP_M_PULLUP(m, sizeof(*l2ca_hdr)); 768107120Sjulian if (m == NULL) 769107120Sjulian return (ENOBUFS); 770107120Sjulian 771107120Sjulian l2ca_hdr = mtod(m, ng_l2cap_l2ca_hdr_t *); 772107120Sjulian token = l2ca_hdr->token; 773107120Sjulian m_adj(m, sizeof(*l2ca_hdr)); 774107120Sjulian 775107120Sjulian /* Verify payload size */ 776107120Sjulian if (l2ca_hdr->length != m->m_pkthdr.len) { 777107120Sjulian NG_L2CAP_ERR( 778107120Sjulian"%s: %s - invalid L2CA Data packet. " \ 779107120Sjulian"Payload length does not match, length=%d, len=%d\n", 780107120Sjulian __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->length, 781107120Sjulian m->m_pkthdr.len); 782107120Sjulian error = EMSGSIZE; 783107120Sjulian goto drop; 784107120Sjulian } 785107120Sjulian 786107120Sjulian /* Check channel ID */ 787107120Sjulian if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) { 788107120Sjulian NG_L2CAP_ERR( 789107120Sjulian"%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n", 790107120Sjulian __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid); 791107120Sjulian error = EINVAL; 792107120Sjulian goto drop; 793107120Sjulian } 794107120Sjulian 795107120Sjulian /* Verify that we have the channel and make sure it is open */ 796107120Sjulian ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid); 797107120Sjulian if (ch == NULL) { 798107120Sjulian NG_L2CAP_ERR( 799107120Sjulian"%s: %s - invalid L2CA Data packet. Channel does not exist, cid=%d\n", 800107120Sjulian __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid); 801107120Sjulian error = ENOENT; 802107120Sjulian goto drop; 803107120Sjulian } 804107120Sjulian 805107120Sjulian if (ch->state != NG_L2CAP_OPEN) { 806107120Sjulian NG_L2CAP_ERR( 807107120Sjulian"%s: %s - invalid L2CA Data packet. Invalid channel state, scid=%d, state=%d\n", 808107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->scid, 809107120Sjulian ch->state); 810107120Sjulian error = EHOSTDOWN; 811107120Sjulian goto drop; /* XXX not always - re-configure */ 812107120Sjulian } 813107120Sjulian 814107120Sjulian /* Create L2CAP command descriptor */ 815107120Sjulian cmd = ng_l2cap_new_cmd(ch->con, ch, 0, NGM_L2CAP_L2CA_WRITE, token); 816107120Sjulian if (cmd == NULL) { 817107120Sjulian error = ENOMEM; 818107120Sjulian goto drop; 819107120Sjulian } 820107120Sjulian 821107120Sjulian /* Attach data packet and link command to the queue */ 822107120Sjulian cmd->aux = m; 823107120Sjulian ng_l2cap_link_cmd(ch->con, cmd); 824107120Sjulian ng_l2cap_lp_deliver(ch->con); 825107120Sjulian 826107120Sjulian return (error); 827107120Sjuliandrop: 828107120Sjulian NG_FREE_M(m); 829107120Sjulian 830107120Sjulian return (error); 831107120Sjulian} /* ng_l2cap_l2ca_write_req */ 832107120Sjulian 833107120Sjulian/* 834107120Sjulian * Send L2CA_Write response 835107120Sjulian */ 836107120Sjulian 837107120Sjulianint 838107120Sjulianng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result, 839107120Sjulian u_int16_t length) 840107120Sjulian{ 841107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 842107120Sjulian struct ng_mesg *msg = NULL; 843107120Sjulian ng_l2cap_l2ca_write_op *op = NULL; 844107120Sjulian int error = 0; 845107120Sjulian 846107120Sjulian /* Check if upstream hook is connected and valid */ 847107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 848107120Sjulian NG_L2CAP_ERR( 849107120Sjulian"%s: %s - unable to send L2CA_WriteRsp message. " \ 850107120Sjulian"Hook is not connected or valid, psm=%d\n", 851107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 852107120Sjulian 853107120Sjulian return (ENOTCONN); 854107120Sjulian } 855107120Sjulian 856107120Sjulian /* Create and send L2CA_WriteRsp message */ 857107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_WRITE, 858107120Sjulian sizeof(*op), M_NOWAIT); 859107120Sjulian if (msg == NULL) 860107120Sjulian error = ENOMEM; 861107120Sjulian else { 862107120Sjulian msg->header.token = token; 863107120Sjulian msg->header.flags |= NGF_RESP; 864107120Sjulian 865107120Sjulian op = (ng_l2cap_l2ca_write_op *)(msg->data); 866107120Sjulian op->result = result; 867107120Sjulian op->length = length; 868107120Sjulian op->lcid = ch->scid; 869107120Sjulian 870128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 871107120Sjulian } 872107120Sjulian 873107120Sjulian return (error); 874107120Sjulian} /* ng_l2cap_l2ca_write_rsp */ 875107120Sjulian 876107120Sjulian/* 877107120Sjulian * Receive packet from the lower layer protocol and send it to the upper 878107120Sjulian * layer protocol (L2CAP_Read) 879107120Sjulian */ 880107120Sjulian 881107120Sjulianint 882107120Sjulianng_l2cap_l2ca_receive(ng_l2cap_con_p con) 883107120Sjulian{ 884107120Sjulian ng_l2cap_p l2cap = con->l2cap; 885107120Sjulian ng_l2cap_hdr_t *hdr = NULL; 886107120Sjulian ng_l2cap_chan_p ch = NULL; 887107120Sjulian int error = 0; 888107120Sjulian 889107120Sjulian NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr)); 890107120Sjulian if (con->rx_pkt == NULL) 891107120Sjulian return (ENOBUFS); 892107120Sjulian 893107120Sjulian hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *); 894107120Sjulian 895107120Sjulian /* Check channel */ 896107120Sjulian ch = ng_l2cap_chan_by_scid(l2cap, hdr->dcid); 897107120Sjulian if (ch == NULL) { 898107120Sjulian NG_L2CAP_ERR( 899107120Sjulian"%s: %s - unexpected L2CAP data packet. Channel does not exist, cid=%d\n", 900107120Sjulian __func__, NG_NODE_NAME(l2cap->node), hdr->dcid); 901107120Sjulian error = ENOENT; 902107120Sjulian goto drop; 903107120Sjulian } 904107120Sjulian 905107120Sjulian /* Check channel state */ 906107120Sjulian if (ch->state != NG_L2CAP_OPEN) { 907107120Sjulian NG_L2CAP_WARN( 908107120Sjulian"%s: %s - unexpected L2CAP data packet. " \ 909107120Sjulian"Invalid channel state, cid=%d, state=%d\n", 910107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->scid, 911107120Sjulian ch->state); 912107120Sjulian error = EHOSTDOWN; /* XXX not always - re-configuration */ 913107120Sjulian goto drop; 914107120Sjulian } 915107120Sjulian 916107120Sjulian /* Check payload size and channel's MTU */ 917107120Sjulian if (hdr->length > ch->imtu) { 918107120Sjulian NG_L2CAP_ERR( 919107120Sjulian"%s: %s - invalid L2CAP data packet. " \ 920107120Sjulian"Packet too big, length=%d, imtu=%d, cid=%d\n", 921107120Sjulian __func__, NG_NODE_NAME(l2cap->node), hdr->length, 922107120Sjulian ch->imtu, ch->scid); 923107120Sjulian error = EMSGSIZE; 924107120Sjulian goto drop; 925107120Sjulian } 926107120Sjulian 927107120Sjulian /* 928107120Sjulian * If we got here then everything looks good and we can sent packet 929107120Sjulian * to the upper layer protocol. 930107120Sjulian */ 931107120Sjulian 932107120Sjulian /* Check if upstream hook is connected and valid */ 933107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 934107120Sjulian NG_L2CAP_ERR( 935107120Sjulian"%s: %s - unable to send L2CAP data packet. " \ 936107120Sjulian"Hook is not connected or valid, psm=%d\n", 937107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 938107120Sjulian error = ENOTCONN; 939107120Sjulian goto drop; 940107120Sjulian } 941107120Sjulian 942107120Sjulian NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt); 943107120Sjulian con->rx_pkt = NULL; 944107120Sjuliandrop: 945107120Sjulian NG_FREE_M(con->rx_pkt); /* checks for != NULL */ 946107120Sjulian 947107120Sjulian return (error); 948107120Sjulian} /* ng_l2cap_receive */ 949107120Sjulian 950107120Sjulian/* 951107120Sjulian * Receive connectioless (multicast) packet from the lower layer protocol and 952107120Sjulian * send it to the upper layer protocol 953107120Sjulian */ 954107120Sjulian 955107120Sjulianint 956107120Sjulianng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con) 957107120Sjulian{ 958107120Sjulian struct _clt_pkt { 959107120Sjulian ng_l2cap_hdr_t h; 960107120Sjulian ng_l2cap_clt_hdr_t c_h; 961107120Sjulian } __attribute__ ((packed)) *hdr = NULL; 962107120Sjulian ng_l2cap_p l2cap = con->l2cap; 963107120Sjulian int length, error = 0; 964107120Sjulian 965107120Sjulian NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr)); 966107120Sjulian if (con->rx_pkt == NULL) 967107120Sjulian return (ENOBUFS); 968107120Sjulian 969107120Sjulian hdr = mtod(con->rx_pkt, struct _clt_pkt *); 970107120Sjulian 971107120Sjulian /* Check packet */ 972107120Sjulian length = con->rx_pkt->m_pkthdr.len - sizeof(*hdr); 973107120Sjulian if (length < 0) { 974107120Sjulian NG_L2CAP_ERR( 975107120Sjulian"%s: %s - invalid L2CAP CLT data packet. Packet too small, length=%d\n", 976107120Sjulian __func__, NG_NODE_NAME(l2cap->node), length); 977107120Sjulian error = EMSGSIZE; 978107120Sjulian goto drop; 979107120Sjulian } 980107120Sjulian 981107120Sjulian /* Check payload size against CLT MTU */ 982107120Sjulian if (length > NG_L2CAP_MTU_DEFAULT) { 983107120Sjulian NG_L2CAP_ERR( 984107120Sjulian"%s: %s - invalid L2CAP CLT data packet. Packet too big, length=%d, mtu=%d\n", 985107120Sjulian __func__, NG_NODE_NAME(l2cap->node), length, 986107120Sjulian NG_L2CAP_MTU_DEFAULT); 987107120Sjulian error = EMSGSIZE; 988107120Sjulian goto drop; 989107120Sjulian } 990107120Sjulian 991107120Sjulian hdr->c_h.psm = le16toh(hdr->c_h.psm); 992107120Sjulian 993107120Sjulian /* 994107120Sjulian * If we got here then everything looks good and we can sent packet 995107120Sjulian * to the upper layer protocol. 996107120Sjulian */ 997107120Sjulian 998107120Sjulian /* Select upstream hook based on PSM */ 999107120Sjulian switch (hdr->c_h.psm) { 1000107120Sjulian case NG_L2CAP_PSM_SDP: 1001107120Sjulian if (l2cap->flags & NG_L2CAP_CLT_SDP_DISABLED) 1002107120Sjulian goto drop; 1003107120Sjulian break; 1004107120Sjulian 1005107120Sjulian case NG_L2CAP_PSM_RFCOMM: 1006107120Sjulian if (l2cap->flags & NG_L2CAP_CLT_RFCOMM_DISABLED) 1007107120Sjulian goto drop; 1008107120Sjulian break; 1009107120Sjulian 1010107120Sjulian case NG_L2CAP_PSM_TCP: 1011107120Sjulian if (l2cap->flags & NG_L2CAP_CLT_TCP_DISABLED) 1012107120Sjulian goto drop; 1013107120Sjulian break; 1014107120Sjulian } 1015107120Sjulian 1016107120Sjulian /* Check if upstream hook is connected and valid */ 1017107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1018107120Sjulian NG_L2CAP_ERR( 1019107120Sjulian"%s: %s - unable to send L2CAP CLT data packet. " \ 1020107120Sjulian"Hook is not connected or valid, psm=%d\n", 1021107120Sjulian __func__, NG_NODE_NAME(l2cap->node), hdr->c_h.psm); 1022107120Sjulian error = ENOTCONN; 1023107120Sjulian goto drop; 1024107120Sjulian } 1025107120Sjulian 1026107120Sjulian NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt); 1027107120Sjulian con->rx_pkt = NULL; 1028107120Sjuliandrop: 1029107120Sjulian NG_FREE_M(con->rx_pkt); /* checks for != NULL */ 1030107120Sjulian 1031107120Sjulian return (error); 1032107120Sjulian} /* ng_l2cap_l2ca_clt_receive */ 1033107120Sjulian 1034107120Sjulian/* 1035107120Sjulian * Send L2CA_QoSViolationInd to the upper layer protocol 1036107120Sjulian */ 1037107120Sjulian 1038107120Sjulianint 1039107120Sjulianng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch) 1040107120Sjulian{ 1041107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 1042107120Sjulian struct ng_mesg *msg = NULL; 1043107120Sjulian ng_l2cap_l2ca_qos_ind_ip *ip = NULL; 1044107120Sjulian int error = 0; 1045107120Sjulian 1046107120Sjulian /* Check if upstream hook is connected and valid */ 1047107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1048107120Sjulian NG_L2CAP_ERR( 1049107120Sjulian"%s: %s - unable to send L2CA_QoSViolationInd message. " \ 1050107120Sjulian"Hook is not connected or valid, psm=%d\n", 1051107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1052107120Sjulian 1053107120Sjulian return (ENOTCONN); 1054107120Sjulian } 1055107120Sjulian 1056107120Sjulian /* Create and send L2CA_QoSViolationInd message */ 1057107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_QOS_IND, 1058107120Sjulian sizeof(*ip), M_NOWAIT); 1059107120Sjulian if (msg == NULL) 1060107120Sjulian error = ENOMEM; 1061107120Sjulian else { 1062107120Sjulian ip = (ng_l2cap_l2ca_qos_ind_ip *)(msg->data); 1063107120Sjulian bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr)); 1064128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1065107120Sjulian } 1066107120Sjulian 1067107120Sjulian return (error); 1068107120Sjulian} /* ng_l2cap_l2ca_qos_ind */ 1069107120Sjulian 1070107120Sjulian/* 1071107120Sjulian * Process L2CA_Disconnect request from the upper layer protocol. 1072107120Sjulian */ 1073107120Sjulian 1074107120Sjulianint 1075107120Sjulianng_l2cap_l2ca_discon_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1076107120Sjulian{ 1077107120Sjulian ng_l2cap_l2ca_discon_ip *ip = NULL; 1078107120Sjulian ng_l2cap_chan_p ch = NULL; 1079107120Sjulian ng_l2cap_cmd_p cmd = NULL; 1080107120Sjulian int error = 0; 1081107120Sjulian 1082107120Sjulian /* Check message */ 1083107120Sjulian if (msg->header.arglen != sizeof(*ip)) { 1084107120Sjulian NG_L2CAP_ALERT( 1085107120Sjulian"%s: %s - invalid L2CA_Disconnect request message size, size=%d\n", 1086107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 1087107120Sjulian msg->header.arglen); 1088107120Sjulian error = EMSGSIZE; 1089107120Sjulian goto out; 1090107120Sjulian } 1091107120Sjulian 1092107120Sjulian ip = (ng_l2cap_l2ca_discon_ip *)(msg->data); 1093107120Sjulian 1094107120Sjulian /* Check if we have this channel */ 1095107120Sjulian ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid); 1096107120Sjulian if (ch == NULL) { 1097107120Sjulian NG_L2CAP_ERR( 1098107120Sjulian"%s: %s - unexpected L2CA_Disconnect request message. " \ 1099107120Sjulian"Channel does not exist, lcid=%d\n", 1100107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 1101107120Sjulian error = ENOENT; 1102107120Sjulian goto out; 1103107120Sjulian } 1104107120Sjulian 1105107120Sjulian /* Check channel state */ 1106107120Sjulian if (ch->state != NG_L2CAP_CONFIG && ch->state != NG_L2CAP_OPEN && 1107107120Sjulian ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) { 1108107120Sjulian NG_L2CAP_ERR( 1109107120Sjulian"%s: %s - unexpected L2CA_Disconnect request message. " \ 1110107120Sjulian"Invalid channel state, state=%d, lcid=%d\n", 1111107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->state, 1112107120Sjulian ch->scid); 1113107120Sjulian error = EINVAL; 1114107120Sjulian goto out; 1115107120Sjulian } 1116107120Sjulian 1117107120Sjulian /* Create and send L2CAP_DisconReq message */ 1118107120Sjulian cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con), 1119107120Sjulian NG_L2CAP_DISCON_REQ, msg->header.token); 1120107120Sjulian if (cmd == NULL) { 1121107120Sjulian ng_l2cap_free_chan(ch); 1122107120Sjulian error = ENOMEM; 1123107120Sjulian goto out; 1124107120Sjulian } 1125107120Sjulian 1126107120Sjulian if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1127107120Sjulian ng_l2cap_free_chan(ch); 1128107120Sjulian ng_l2cap_free_cmd(cmd); 1129107120Sjulian error = EIO; 1130107120Sjulian goto out; 1131107120Sjulian } 1132107120Sjulian 1133107120Sjulian _ng_l2cap_discon_req(cmd->aux, cmd->ident, ch->dcid, ch->scid); 1134107120Sjulian if (cmd->aux == NULL) { 1135107120Sjulian ng_l2cap_free_chan(ch); 1136107120Sjulian ng_l2cap_free_cmd(cmd); 1137107120Sjulian error = ENOBUFS; 1138107120Sjulian goto out; 1139107120Sjulian } 1140107120Sjulian 1141107120Sjulian ch->state = NG_L2CAP_W4_L2CAP_DISCON_RSP; 1142107120Sjulian 1143107120Sjulian /* Link command to the queue */ 1144107120Sjulian ng_l2cap_link_cmd(ch->con, cmd); 1145107120Sjulian ng_l2cap_lp_deliver(ch->con); 1146107120Sjulianout: 1147107120Sjulian return (error); 1148107120Sjulian} /* ng_l2cap_l2ca_discon_req */ 1149107120Sjulian 1150107120Sjulian/* 1151107120Sjulian * Send L2CA_Disconnect response to the upper layer protocol 1152107120Sjulian */ 1153107120Sjulian 1154107120Sjulianint 1155107120Sjulianng_l2cap_l2ca_discon_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 1156107120Sjulian{ 1157107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 1158107120Sjulian struct ng_mesg *msg = NULL; 1159107120Sjulian ng_l2cap_l2ca_discon_op *op = NULL; 1160107120Sjulian int error = 0; 1161107120Sjulian 1162107120Sjulian /* Check if upstream hook is connected and valid */ 1163107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1164107120Sjulian NG_L2CAP_ERR( 1165107120Sjulian"%s: %s - unable to send L2CA_Disconnect response message. " \ 1166107120Sjulian"Hook is not connected or valid, psm=%d\n", 1167107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1168107120Sjulian 1169107120Sjulian return (ENOTCONN); 1170107120Sjulian } 1171107120Sjulian 1172107120Sjulian /* Create and send L2CA_Disconnect response message */ 1173107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON, 1174107120Sjulian sizeof(*op), M_NOWAIT); 1175107120Sjulian if (msg == NULL) 1176107120Sjulian error = ENOMEM; 1177107120Sjulian else { 1178107120Sjulian msg->header.token = token; 1179107120Sjulian msg->header.flags |= NGF_RESP; 1180107120Sjulian 1181107120Sjulian op = (ng_l2cap_l2ca_discon_op *)(msg->data); 1182107120Sjulian op->result = result; 1183107120Sjulian 1184128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1185107120Sjulian } 1186107120Sjulian 1187107120Sjulian return (error); 1188107120Sjulian} /* ng_l2cap_l2ca_discon_rsp */ 1189107120Sjulian 1190107120Sjulian/* 1191107120Sjulian * Send L2CA_DisconnectInd message to the upper layer protocol. 1192107120Sjulian */ 1193107120Sjulian 1194107120Sjulianint 1195107120Sjulianng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch) 1196107120Sjulian{ 1197107120Sjulian ng_l2cap_p l2cap = ch->con->l2cap; 1198107120Sjulian struct ng_mesg *msg = NULL; 1199107120Sjulian ng_l2cap_l2ca_discon_ind_ip *ip = NULL; 1200107120Sjulian int error = 0; 1201107120Sjulian 1202107120Sjulian /* Check if upstream hook is connected and valid */ 1203107120Sjulian if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1204107120Sjulian NG_L2CAP_ERR( 1205107120Sjulian"%s: %s - unable to send L2CA_DisconnectInd message. " \ 1206107120Sjulian"Hook is not connected or valid, psm=%d\n", 1207107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1208107120Sjulian 1209107120Sjulian return (ENOTCONN); 1210107120Sjulian } 1211107120Sjulian 1212107120Sjulian /* Create and send L2CA_DisconnectInd message */ 1213107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND, 1214107120Sjulian sizeof(*ip), M_NOWAIT); 1215107120Sjulian if (msg == NULL) 1216107120Sjulian error = ENOMEM; 1217107120Sjulian else { 1218107120Sjulian ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data); 1219107120Sjulian ip->lcid = ch->scid; 1220128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1221107120Sjulian } 1222107120Sjulian 1223107120Sjulian return (error); 1224107120Sjulian} /* ng_l2cap_l2ca_discon_ind */ 1225107120Sjulian 1226107120Sjulian/* 1227107120Sjulian * Process L2CA_GroupCreate request from the upper layer protocol. 1228107120Sjulian * XXX FIXME 1229107120Sjulian */ 1230107120Sjulian 1231107120Sjulianint 1232107120Sjulianng_l2cap_l2ca_grp_create(ng_l2cap_p l2cap, struct ng_mesg *msg) 1233107120Sjulian{ 1234107120Sjulian return (ENOTSUP); 1235107120Sjulian} /* ng_l2cap_l2ca_grp_create */ 1236107120Sjulian 1237107120Sjulian/* 1238107120Sjulian * Process L2CA_GroupClose request from the upper layer protocol 1239107120Sjulian * XXX FIXME 1240107120Sjulian */ 1241107120Sjulian 1242107120Sjulianint 1243107120Sjulianng_l2cap_l2ca_grp_close(ng_l2cap_p l2cap, struct ng_mesg *msg) 1244107120Sjulian{ 1245107120Sjulian return (ENOTSUP); 1246107120Sjulian} /* ng_l2cap_l2ca_grp_close */ 1247107120Sjulian 1248107120Sjulian/* 1249107120Sjulian * Process L2CA_GroupAddMember request from the upper layer protocol. 1250107120Sjulian * XXX FIXME 1251107120Sjulian */ 1252107120Sjulian 1253107120Sjulianint 1254107120Sjulianng_l2cap_l2ca_grp_add_member_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1255107120Sjulian{ 1256107120Sjulian return (ENOTSUP); 1257107120Sjulian} /* ng_l2cap_l2ca_grp_add_member_req */ 1258107120Sjulian 1259107120Sjulian/* 1260107120Sjulian * Send L2CA_GroupAddMember response to the upper layer protocol. 1261107120Sjulian * XXX FIXME 1262107120Sjulian */ 1263107120Sjulian 1264107120Sjulianint 1265107120Sjulianng_l2cap_l2ca_grp_add_member_rsp(ng_l2cap_chan_p ch, u_int32_t token, 1266107120Sjulian u_int16_t result) 1267107120Sjulian{ 1268107120Sjulian return (0); 1269107120Sjulian} /* ng_l2cap_l2ca_grp_add_member_rsp */ 1270107120Sjulian 1271107120Sjulian/* 1272107120Sjulian * Process L2CA_GroupDeleteMember request from the upper layer protocol 1273107120Sjulian * XXX FIXME 1274107120Sjulian */ 1275107120Sjulian 1276107120Sjulianint 1277107120Sjulianng_l2cap_l2ca_grp_rem_member(ng_l2cap_p l2cap, struct ng_mesg *msg) 1278107120Sjulian{ 1279107120Sjulian return (ENOTSUP); 1280107120Sjulian} /* ng_l2cap_l2ca_grp_rem_member */ 1281107120Sjulian 1282107120Sjulian/* 1283107120Sjulian * Process L2CA_GroupGetMembers request from the upper layer protocol 1284107120Sjulian * XXX FIXME 1285107120Sjulian */ 1286107120Sjulian 1287107120Sjulianint 1288107120Sjulianng_l2cap_l2ca_grp_get_members(ng_l2cap_p l2cap, struct ng_mesg *msg) 1289107120Sjulian{ 1290107120Sjulian return (ENOTSUP); 1291107120Sjulian} /* ng_l2cap_l2ca_grp_get_members */ 1292107120Sjulian 1293107120Sjulian/* 1294107120Sjulian * Process L2CA_Ping request from the upper layer protocol 1295107120Sjulian */ 1296107120Sjulian 1297107120Sjulianint 1298107120Sjulianng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1299107120Sjulian{ 1300107120Sjulian ng_l2cap_l2ca_ping_ip *ip = NULL; 1301107120Sjulian ng_l2cap_con_p con = NULL; 1302107120Sjulian ng_l2cap_cmd_p cmd = NULL; 1303107120Sjulian int error = 0; 1304107120Sjulian 1305107120Sjulian /* Verify message */ 1306107120Sjulian if (msg->header.arglen < sizeof(*ip)) { 1307107120Sjulian NG_L2CAP_ALERT( 1308107120Sjulian"%s: %s - invalid L2CA_Ping request message size, size=%d\n", 1309107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 1310107120Sjulian msg->header.arglen); 1311107120Sjulian error = EMSGSIZE; 1312107120Sjulian goto out; 1313107120Sjulian } 1314107120Sjulian 1315107120Sjulian ip = (ng_l2cap_l2ca_ping_ip *)(msg->data); 1316107120Sjulian if (ip->echo_size > NG_L2CAP_MAX_ECHO_SIZE) { 1317107120Sjulian NG_L2CAP_WARN( 1318107120Sjulian"%s: %s - invalid L2CA_Ping request. Echo size is too big, echo_size=%d\n", 1319107120Sjulian __func__, NG_NODE_NAME(l2cap->node), ip->echo_size); 1320107120Sjulian error = EMSGSIZE; 1321107120Sjulian goto out; 1322107120Sjulian } 1323107120Sjulian 1324107120Sjulian /* Check if we have connection to the unit */ 1325107120Sjulian con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr); 1326107120Sjulian if (con == NULL) { 1327107120Sjulian /* Submit LP_ConnectReq to the lower layer */ 1328107120Sjulian error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr); 1329107120Sjulian if (error != 0) { 1330107120Sjulian NG_L2CAP_ERR( 1331107120Sjulian"%s: %s - unable to send LP_ConnectReq message, error=%d\n", 1332107120Sjulian __func__, NG_NODE_NAME(l2cap->node), error); 1333107120Sjulian goto out; 1334107120Sjulian } 1335107120Sjulian 1336107120Sjulian /* This should not fail */ 1337107120Sjulian con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr); 1338107120Sjulian KASSERT((con != NULL), 1339107120Sjulian("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node))); 1340107120Sjulian } 1341107120Sjulian 1342107120Sjulian /* Create L2CAP command descriptor */ 1343107120Sjulian cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con), 1344107120Sjulian NG_L2CAP_ECHO_REQ, msg->header.token); 1345107120Sjulian if (cmd == NULL) { 1346107120Sjulian error = ENOMEM; 1347107120Sjulian goto out; 1348107120Sjulian } 1349107120Sjulian 1350107120Sjulian if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1351107120Sjulian ng_l2cap_free_cmd(cmd); 1352107120Sjulian error = EIO; 1353107120Sjulian goto out; 1354107120Sjulian } 1355107120Sjulian 1356107120Sjulian /* Create L2CAP command packet */ 1357107120Sjulian _ng_l2cap_echo_req(cmd->aux, cmd->ident, 1358107120Sjulian msg->data + sizeof(*ip), ip->echo_size); 1359107120Sjulian if (cmd->aux == NULL) { 1360107120Sjulian ng_l2cap_free_cmd(cmd); 1361107120Sjulian error = ENOBUFS; 1362107120Sjulian goto out; 1363107120Sjulian } 1364107120Sjulian 1365107120Sjulian /* Link command to the queue */ 1366107120Sjulian ng_l2cap_link_cmd(con, cmd); 1367107120Sjulian ng_l2cap_lp_deliver(con); 1368107120Sjulianout: 1369107120Sjulian return (error); 1370107120Sjulian} /* ng_l2cap_l2ca_ping_req */ 1371107120Sjulian 1372107120Sjulian/* 1373107120Sjulian * Send L2CA_Ping response to the upper layer protocol 1374107120Sjulian */ 1375107120Sjulian 1376107120Sjulianint 1377107120Sjulianng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result, 1378107120Sjulian struct mbuf *data) 1379107120Sjulian{ 1380107120Sjulian ng_l2cap_p l2cap = con->l2cap; 1381107120Sjulian struct ng_mesg *msg = NULL; 1382107120Sjulian ng_l2cap_l2ca_ping_op *op = NULL; 1383107120Sjulian int error = 0, size = 0; 1384107120Sjulian 1385107120Sjulian /* Check if control hook is connected and valid */ 1386107120Sjulian if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) { 1387107120Sjulian NG_L2CAP_WARN( 1388107120Sjulian"%s: %s - unable to send L2CA_Ping response message. " \ 1389107120Sjulian"Hook is not connected or valid\n", 1390107120Sjulian __func__, NG_NODE_NAME(l2cap->node)); 1391107120Sjulian error = ENOTCONN; 1392107120Sjulian goto out; 1393107120Sjulian } 1394107120Sjulian 1395107120Sjulian size = (data == NULL)? 0 : data->m_pkthdr.len; 1396107120Sjulian 1397107120Sjulian /* Create and send L2CA_Ping response message */ 1398107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_PING, 1399107120Sjulian sizeof(*op) + size, M_NOWAIT); 1400107120Sjulian if (msg == NULL) 1401107120Sjulian error = ENOMEM; 1402107120Sjulian else { 1403107120Sjulian msg->header.token = token; 1404107120Sjulian msg->header.flags |= NGF_RESP; 1405107120Sjulian 1406107120Sjulian op = (ng_l2cap_l2ca_ping_op *)(msg->data); 1407107120Sjulian op->result = result; 1408107120Sjulian bcopy(&con->remote, &op->bdaddr, sizeof(op->bdaddr)); 1409107120Sjulian if (data != NULL && size > 0) { 1410107120Sjulian op->echo_size = size; 1411107120Sjulian m_copydata(data, 0, size, (caddr_t) op + sizeof(*op)); 1412107120Sjulian } 1413107120Sjulian 1414128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1415107120Sjulian } 1416107120Sjulianout: 1417107120Sjulian NG_FREE_M(data); 1418107120Sjulian 1419107120Sjulian return (error); 1420107120Sjulian} /* ng_l2cap_l2ca_ping_rsp */ 1421107120Sjulian 1422107120Sjulian/* 1423107120Sjulian * Process L2CA_GetInfo request from the upper layer protocol 1424107120Sjulian */ 1425107120Sjulian 1426107120Sjulianint 1427107120Sjulianng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1428107120Sjulian{ 1429107120Sjulian ng_l2cap_l2ca_get_info_ip *ip = NULL; 1430107120Sjulian ng_l2cap_con_p con = NULL; 1431107120Sjulian ng_l2cap_cmd_p cmd = NULL; 1432107120Sjulian int error = 0; 1433107120Sjulian 1434107120Sjulian /* Verify message */ 1435107120Sjulian if (msg->header.arglen != sizeof(*ip)) { 1436107120Sjulian NG_L2CAP_ALERT( 1437107120Sjulian"%s: %s - invalid L2CA_GetInfo request message size, size=%d\n", 1438107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 1439107120Sjulian msg->header.arglen); 1440107120Sjulian error = EMSGSIZE; 1441107120Sjulian goto out; 1442107120Sjulian } 1443107120Sjulian 1444107120Sjulian ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data); 1445107120Sjulian 1446107120Sjulian /* Check if we have connection to the unit */ 1447107120Sjulian con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr); 1448107120Sjulian if (con == NULL) { 1449107120Sjulian /* Submit LP_ConnectReq to the lower layer */ 1450107120Sjulian error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr); 1451107120Sjulian if (error != 0) { 1452107120Sjulian NG_L2CAP_ERR( 1453107120Sjulian"%s: %s - unable to send LP_ConnectReq message, error=%d\n", 1454107120Sjulian __func__, NG_NODE_NAME(l2cap->node), error); 1455107120Sjulian goto out; 1456107120Sjulian } 1457107120Sjulian 1458107120Sjulian /* This should not fail */ 1459107120Sjulian con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr); 1460107120Sjulian KASSERT((con != NULL), 1461107120Sjulian("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node))); 1462107120Sjulian } 1463107120Sjulian 1464107120Sjulian /* Create L2CAP command descriptor */ 1465107120Sjulian cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con), 1466107120Sjulian NG_L2CAP_INFO_REQ, msg->header.token); 1467107120Sjulian if (cmd == NULL) { 1468107120Sjulian error = ENOMEM; 1469107120Sjulian goto out; 1470107120Sjulian } 1471107120Sjulian 1472107120Sjulian if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1473107120Sjulian ng_l2cap_free_cmd(cmd); 1474107120Sjulian error = EIO; 1475107120Sjulian goto out; 1476107120Sjulian } 1477107120Sjulian 1478107120Sjulian /* Create L2CAP command packet */ 1479107120Sjulian _ng_l2cap_info_req(cmd->aux, cmd->ident, ip->info_type); 1480107120Sjulian if (cmd->aux == NULL) { 1481107120Sjulian ng_l2cap_free_cmd(cmd); 1482107120Sjulian error = ENOBUFS; 1483107120Sjulian goto out; 1484107120Sjulian } 1485107120Sjulian 1486107120Sjulian /* Link command to the queue */ 1487107120Sjulian ng_l2cap_link_cmd(con, cmd); 1488107120Sjulian ng_l2cap_lp_deliver(con); 1489107120Sjulianout: 1490107120Sjulian return (error); 1491107120Sjulian} /* ng_l2cap_l2ca_get_info_req */ 1492107120Sjulian 1493107120Sjulian/* 1494107120Sjulian * Send L2CA_GetInfo response to the upper layer protocol 1495107120Sjulian */ 1496107120Sjulian 1497107120Sjulianint 1498107120Sjulianng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con, u_int32_t token, 1499107120Sjulian u_int16_t result, struct mbuf *data) 1500107120Sjulian{ 1501107120Sjulian ng_l2cap_p l2cap = con->l2cap; 1502107120Sjulian struct ng_mesg *msg = NULL; 1503107120Sjulian ng_l2cap_l2ca_get_info_op *op = NULL; 1504107120Sjulian int error = 0, size; 1505107120Sjulian 1506107120Sjulian /* Check if control hook is connected and valid */ 1507107120Sjulian if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) { 1508107120Sjulian NG_L2CAP_WARN( 1509107120Sjulian"%s: %s - unable to send L2CA_GetInfo response message. " \ 1510107120Sjulian"Hook is not connected or valid\n", 1511107120Sjulian __func__, NG_NODE_NAME(l2cap->node)); 1512107120Sjulian error = ENOTCONN; 1513107120Sjulian goto out; 1514107120Sjulian } 1515107120Sjulian 1516107120Sjulian size = (data == NULL)? 0 : data->m_pkthdr.len; 1517107120Sjulian 1518107120Sjulian /* Create and send L2CA_GetInfo response message */ 1519107120Sjulian NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_GET_INFO, 1520107120Sjulian sizeof(*op) + size, M_NOWAIT); 1521107120Sjulian if (msg == NULL) 1522107120Sjulian error = ENOMEM; 1523107120Sjulian else { 1524107120Sjulian msg->header.token = token; 1525107120Sjulian msg->header.flags |= NGF_RESP; 1526107120Sjulian 1527107120Sjulian op = (ng_l2cap_l2ca_get_info_op *)(msg->data); 1528107120Sjulian op->result = result; 1529107120Sjulian if (data != NULL && size > 0) { 1530107120Sjulian op->info_size = size; 1531107120Sjulian m_copydata(data, 0, size, (caddr_t) op + sizeof(*op)); 1532107120Sjulian } 1533107120Sjulian 1534128076Semax NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1535107120Sjulian } 1536107120Sjulianout: 1537107120Sjulian NG_FREE_M(data); 1538107120Sjulian 1539107120Sjulian return (error); 1540107120Sjulian} /* ng_l2cap_l2ca_get_info_rsp */ 1541107120Sjulian 1542107120Sjulian/* 1543107120Sjulian * Process L2CA_EnableCLT message from the upper layer protocol 1544107120Sjulian * XXX convert to NGN_L2CAP_NODE_SET_FLAGS? 1545107120Sjulian */ 1546107120Sjulian 1547107120Sjulianint 1548107120Sjulianng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg) 1549107120Sjulian{ 1550107120Sjulian ng_l2cap_l2ca_enable_clt_ip *ip = NULL; 1551107120Sjulian int error = 0; 1552107120Sjulian#if 0 1553107120Sjulian * ng_l2cap_l2ca_enable_clt_op *op = NULL; 1554107120Sjulian * u_int16_t result; 1555107120Sjulian * u_int32_t token; 1556107120Sjulian#endif 1557107120Sjulian 1558107120Sjulian /* Check message */ 1559107120Sjulian if (msg->header.arglen != sizeof(*ip)) { 1560107120Sjulian NG_L2CAP_ALERT( 1561107120Sjulian"%s: %s - invalid L2CA_EnableCLT message size, size=%d\n", 1562107120Sjulian __func__, NG_NODE_NAME(l2cap->node), 1563107120Sjulian msg->header.arglen); 1564107120Sjulian 1565107120Sjulian return (EMSGSIZE); 1566107120Sjulian } 1567107120Sjulian 1568107120Sjulian /* Process request */ 1569107120Sjulian ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data); 1570107120Sjulian#if 0 1571107120Sjulian * result = NG_L2CAP_SUCCESS; 1572107120Sjulian#endif 1573107120Sjulian 1574107120Sjulian switch (ip->psm) 1575107120Sjulian { 1576107120Sjulian case 0: 1577107120Sjulian /* Special case: disable/enable all PSM */ 1578107120Sjulian if (ip->enable) 1579107120Sjulian l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED | 1580107120Sjulian NG_L2CAP_CLT_RFCOMM_DISABLED | 1581107120Sjulian NG_L2CAP_CLT_TCP_DISABLED); 1582107120Sjulian else 1583107120Sjulian l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED | 1584107120Sjulian NG_L2CAP_CLT_RFCOMM_DISABLED | 1585107120Sjulian NG_L2CAP_CLT_TCP_DISABLED); 1586107120Sjulian break; 1587107120Sjulian 1588107120Sjulian case NG_L2CAP_PSM_SDP: 1589107120Sjulian if (ip->enable) 1590107120Sjulian l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED; 1591107120Sjulian else 1592107120Sjulian l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED; 1593107120Sjulian break; 1594107120Sjulian 1595107120Sjulian case NG_L2CAP_PSM_RFCOMM: 1596107120Sjulian if (ip->enable) 1597107120Sjulian l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED; 1598107120Sjulian else 1599107120Sjulian l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED; 1600107120Sjulian break; 1601107120Sjulian 1602107120Sjulian case NG_L2CAP_PSM_TCP: 1603107120Sjulian if (ip->enable) 1604107120Sjulian l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED; 1605107120Sjulian else 1606107120Sjulian l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED; 1607107120Sjulian break; 1608107120Sjulian 1609107120Sjulian default: 1610107120Sjulian NG_L2CAP_ERR( 1611107120Sjulian"%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm); 1612107120Sjulian#if 0 1613107120Sjulian * result = NG_L2CAP_PSM_NOT_SUPPORTED; 1614107120Sjulian#endif 1615107120Sjulian error = ENOTSUP; 1616107120Sjulian break; 1617107120Sjulian } 1618107120Sjulian 1619107120Sjulian#if 0 1620107120Sjulian * /* Create and send response message */ 1621107120Sjulian * token = msg->header.token; 1622107120Sjulian * NG_FREE_MSG(msg); 1623107120Sjulian * NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT, 1624107120Sjulian * sizeof(*op), M_NOWAIT); 1625107120Sjulian * if (msg == NULL) 1626107120Sjulian * error = ENOMEM; 1627107120Sjulian * else { 1628107120Sjulian * msg->header.token = token; 1629107120Sjulian * msg->header.flags |= NGF_RESP; 1630107120Sjulian * 1631107120Sjulian * op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data); 1632107120Sjulian * op->result = result; 1633107120Sjulian * } 1634107120Sjulian * 1635107120Sjulian * /* Send response to control hook */ 1636107120Sjulian * if (l2cap->ctl != NULL && NG_HOOK_IS_VALID(l2cap->ctl)) 1637128076Semax * NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1638107120Sjulian#endif 1639107120Sjulian 1640107120Sjulian return (error); 1641107120Sjulian} /* ng_l2cap_l2ca_enable_clt */ 1642107120Sjulian 1643