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