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