1878ed226SJulian Elischer /* 2878ed226SJulian Elischer * ng_l2cap_cmds.c 3c398230bSWarner Losh */ 4c398230bSWarner Losh 5c398230bSWarner Losh /*- 6*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 7fe267a55SPedro F. Giffuni * 8878ed226SJulian Elischer * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 9878ed226SJulian Elischer * All rights reserved. 10878ed226SJulian Elischer * 11878ed226SJulian Elischer * Redistribution and use in source and binary forms, with or without 12878ed226SJulian Elischer * modification, are permitted provided that the following conditions 13878ed226SJulian Elischer * are met: 14878ed226SJulian Elischer * 1. Redistributions of source code must retain the above copyright 15878ed226SJulian Elischer * notice, this list of conditions and the following disclaimer. 16878ed226SJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 17878ed226SJulian Elischer * notice, this list of conditions and the following disclaimer in the 18878ed226SJulian Elischer * documentation and/or other materials provided with the distribution. 19878ed226SJulian Elischer * 20878ed226SJulian Elischer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21878ed226SJulian Elischer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22878ed226SJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23878ed226SJulian Elischer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24878ed226SJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25878ed226SJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26878ed226SJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27878ed226SJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28878ed226SJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29878ed226SJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30878ed226SJulian Elischer * SUCH DAMAGE. 31878ed226SJulian Elischer * 320986ab12SMaksim Yevmenkin * $Id: ng_l2cap_cmds.c,v 1.2 2003/09/08 19:11:45 max Exp $ 33878ed226SJulian Elischer * $FreeBSD$ 34878ed226SJulian Elischer */ 35878ed226SJulian Elischer 36878ed226SJulian Elischer #include <sys/param.h> 37878ed226SJulian Elischer #include <sys/systm.h> 38878ed226SJulian Elischer #include <sys/kernel.h> 39878ed226SJulian Elischer #include <sys/endian.h> 40878ed226SJulian Elischer #include <sys/malloc.h> 41878ed226SJulian Elischer #include <sys/mbuf.h> 42878ed226SJulian Elischer #include <sys/queue.h> 43878ed226SJulian Elischer #include <netgraph/ng_message.h> 44878ed226SJulian Elischer #include <netgraph/netgraph.h> 45b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_bluetooth.h> 46b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_hci.h> 47b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_l2cap.h> 48b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_var.h> 49b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h> 50b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h> 51b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h> 52b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h> 53b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h> 54878ed226SJulian Elischer 55878ed226SJulian Elischer /****************************************************************************** 56878ed226SJulian Elischer ****************************************************************************** 57878ed226SJulian Elischer ** L2CAP commands processing module 58878ed226SJulian Elischer ****************************************************************************** 59878ed226SJulian Elischer ******************************************************************************/ 60878ed226SJulian Elischer 61878ed226SJulian Elischer /* 62878ed226SJulian Elischer * Process L2CAP command queue on connection 63878ed226SJulian Elischer */ 64878ed226SJulian Elischer 65878ed226SJulian Elischer void 66878ed226SJulian Elischer ng_l2cap_con_wakeup(ng_l2cap_con_p con) 67878ed226SJulian Elischer { 68878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 69878ed226SJulian Elischer struct mbuf *m = NULL; 70878ed226SJulian Elischer int error = 0; 71878ed226SJulian Elischer 72878ed226SJulian Elischer /* Find first non-pending command in the queue */ 73878ed226SJulian Elischer TAILQ_FOREACH(cmd, &con->cmd_list, next) { 74878ed226SJulian Elischer KASSERT((cmd->con == con), 75878ed226SJulian Elischer ("%s: %s - invalid connection pointer!\n", 76878ed226SJulian Elischer __func__, NG_NODE_NAME(con->l2cap->node))); 77878ed226SJulian Elischer 78878ed226SJulian Elischer if (!(cmd->flags & NG_L2CAP_CMD_PENDING)) 79878ed226SJulian Elischer break; 80878ed226SJulian Elischer } 81878ed226SJulian Elischer 82878ed226SJulian Elischer if (cmd == NULL) 83878ed226SJulian Elischer return; 84878ed226SJulian Elischer 85878ed226SJulian Elischer /* Detach command packet */ 86878ed226SJulian Elischer m = cmd->aux; 87878ed226SJulian Elischer cmd->aux = NULL; 88878ed226SJulian Elischer 89878ed226SJulian Elischer /* Process command */ 90878ed226SJulian Elischer switch (cmd->code) { 91878ed226SJulian Elischer case NG_L2CAP_DISCON_RSP: 92878ed226SJulian Elischer case NG_L2CAP_ECHO_RSP: 93878ed226SJulian Elischer case NG_L2CAP_INFO_RSP: 944301b251SMaksim Yevmenkin /* 954301b251SMaksim Yevmenkin * Do not check return ng_l2cap_lp_send() value, because 964301b251SMaksim Yevmenkin * in these cases we do not really have a graceful way out. 974301b251SMaksim Yevmenkin * ECHO and INFO responses are internal to the stack and not 984301b251SMaksim Yevmenkin * visible to user. REJect is just being nice to remote end 994301b251SMaksim Yevmenkin * (otherwise remote end will timeout anyway). DISCON is 1004301b251SMaksim Yevmenkin * probably most interesting here, however, if it fails 1014301b251SMaksim Yevmenkin * there is nothing we can do anyway. 1024301b251SMaksim Yevmenkin */ 1034301b251SMaksim Yevmenkin 1044301b251SMaksim Yevmenkin (void) ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m); 105878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd); 106878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 107878ed226SJulian Elischer break; 108fbc48c2bSTakanori Watanabe case NG_L2CAP_CMD_REJ: 109fbc48c2bSTakanori Watanabe (void) ng_l2cap_lp_send(con, 110fbc48c2bSTakanori Watanabe (con->linktype == NG_HCI_LINK_ACL)? 111fbc48c2bSTakanori Watanabe NG_L2CAP_SIGNAL_CID: 112fbc48c2bSTakanori Watanabe NG_L2CAP_LESIGNAL_CID 113fbc48c2bSTakanori Watanabe , m); 114fbc48c2bSTakanori Watanabe ng_l2cap_unlink_cmd(cmd); 115fbc48c2bSTakanori Watanabe ng_l2cap_free_cmd(cmd); 116fbc48c2bSTakanori Watanabe break; 117878ed226SJulian Elischer 118878ed226SJulian Elischer case NG_L2CAP_CON_REQ: 119878ed226SJulian Elischer error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m); 120878ed226SJulian Elischer if (error != 0) { 121878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, 122878ed226SJulian Elischer NG_L2CAP_NO_RESOURCES, 0); 123878ed226SJulian Elischer ng_l2cap_free_chan(cmd->ch); /* will free commands */ 124878ed226SJulian Elischer } else 125878ed226SJulian Elischer ng_l2cap_command_timeout(cmd, 126878ed226SJulian Elischer bluetooth_l2cap_rtx_timeout()); 127878ed226SJulian Elischer break; 128878ed226SJulian Elischer case NG_L2CAP_CON_RSP: 129878ed226SJulian Elischer error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m); 130878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd); 131878ed226SJulian Elischer if (cmd->ch != NULL) { 132878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_rsp(cmd->ch, cmd->token, 133878ed226SJulian Elischer (error == 0)? NG_L2CAP_SUCCESS : 134878ed226SJulian Elischer NG_L2CAP_NO_RESOURCES); 135878ed226SJulian Elischer if (error != 0) 136878ed226SJulian Elischer ng_l2cap_free_chan(cmd->ch); 137878ed226SJulian Elischer } 138878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 139878ed226SJulian Elischer break; 140878ed226SJulian Elischer 141878ed226SJulian Elischer case NG_L2CAP_CFG_REQ: 142878ed226SJulian Elischer error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m); 143878ed226SJulian Elischer if (error != 0) { 144878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token, 145878ed226SJulian Elischer NG_L2CAP_NO_RESOURCES); 146878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd); 147878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 148878ed226SJulian Elischer } else 149878ed226SJulian Elischer ng_l2cap_command_timeout(cmd, 150878ed226SJulian Elischer bluetooth_l2cap_rtx_timeout()); 151878ed226SJulian Elischer break; 152878ed226SJulian Elischer 153878ed226SJulian Elischer case NG_L2CAP_CFG_RSP: 154878ed226SJulian Elischer error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m); 155878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd); 156878ed226SJulian Elischer if (cmd->ch != NULL) 157878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp_rsp(cmd->ch, cmd->token, 158878ed226SJulian Elischer (error == 0)? NG_L2CAP_SUCCESS : 159878ed226SJulian Elischer NG_L2CAP_NO_RESOURCES); 160878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 161878ed226SJulian Elischer break; 162878ed226SJulian Elischer 163878ed226SJulian Elischer case NG_L2CAP_DISCON_REQ: 164878ed226SJulian Elischer error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m); 165878ed226SJulian Elischer ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token, 166878ed226SJulian Elischer (error == 0)? NG_L2CAP_SUCCESS : NG_L2CAP_NO_RESOURCES); 167878ed226SJulian Elischer if (error != 0) 168878ed226SJulian Elischer ng_l2cap_free_chan(cmd->ch); /* XXX free channel */ 169878ed226SJulian Elischer else 170878ed226SJulian Elischer ng_l2cap_command_timeout(cmd, 171878ed226SJulian Elischer bluetooth_l2cap_rtx_timeout()); 172878ed226SJulian Elischer break; 173878ed226SJulian Elischer 174878ed226SJulian Elischer case NG_L2CAP_ECHO_REQ: 175878ed226SJulian Elischer error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m); 176878ed226SJulian Elischer if (error != 0) { 177878ed226SJulian Elischer ng_l2cap_l2ca_ping_rsp(con, cmd->token, 178878ed226SJulian Elischer NG_L2CAP_NO_RESOURCES, NULL); 179878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd); 180878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 181878ed226SJulian Elischer } else 182878ed226SJulian Elischer ng_l2cap_command_timeout(cmd, 183878ed226SJulian Elischer bluetooth_l2cap_rtx_timeout()); 184878ed226SJulian Elischer break; 185878ed226SJulian Elischer 186878ed226SJulian Elischer case NG_L2CAP_INFO_REQ: 187878ed226SJulian Elischer error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m); 188878ed226SJulian Elischer if (error != 0) { 189878ed226SJulian Elischer ng_l2cap_l2ca_get_info_rsp(con, cmd->token, 190878ed226SJulian Elischer NG_L2CAP_NO_RESOURCES, NULL); 191878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd); 192878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 193878ed226SJulian Elischer } else 194878ed226SJulian Elischer ng_l2cap_command_timeout(cmd, 195878ed226SJulian Elischer bluetooth_l2cap_rtx_timeout()); 196878ed226SJulian Elischer break; 197878ed226SJulian Elischer 198878ed226SJulian Elischer case NGM_L2CAP_L2CA_WRITE: { 199878ed226SJulian Elischer int length = m->m_pkthdr.len; 200878ed226SJulian Elischer 201878ed226SJulian Elischer if (cmd->ch->dcid == NG_L2CAP_CLT_CID) { 202878ed226SJulian Elischer m = ng_l2cap_prepend(m, sizeof(ng_l2cap_clt_hdr_t)); 203878ed226SJulian Elischer if (m == NULL) 204878ed226SJulian Elischer error = ENOBUFS; 205878ed226SJulian Elischer else 206878ed226SJulian Elischer mtod(m, ng_l2cap_clt_hdr_t *)->psm = 207878ed226SJulian Elischer htole16(cmd->ch->psm); 208878ed226SJulian Elischer } 209878ed226SJulian Elischer 210878ed226SJulian Elischer if (error == 0) 211878ed226SJulian Elischer error = ng_l2cap_lp_send(con, cmd->ch->dcid, m); 212878ed226SJulian Elischer 213878ed226SJulian Elischer ng_l2cap_l2ca_write_rsp(cmd->ch, cmd->token, 214878ed226SJulian Elischer (error == 0)? NG_L2CAP_SUCCESS : NG_L2CAP_NO_RESOURCES, 215878ed226SJulian Elischer length); 216878ed226SJulian Elischer 217878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd); 218878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 219878ed226SJulian Elischer } break; 220fbc48c2bSTakanori Watanabe case NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE: 221fbc48c2bSTakanori Watanabe error = ng_l2cap_lp_send(con, NG_L2CAP_LESIGNAL_CID, m); 222fbc48c2bSTakanori Watanabe ng_l2cap_unlink_cmd(cmd); 223fbc48c2bSTakanori Watanabe ng_l2cap_free_cmd(cmd); 224fbc48c2bSTakanori Watanabe break; 225fbc48c2bSTakanori Watanabe case NG_L2CAP_CMD_PARAM_UPDATE_REQUEST: 226fbc48c2bSTakanori Watanabe /*TBD.*/ 227878ed226SJulian Elischer /* XXX FIXME add other commands */ 228878ed226SJulian Elischer default: 2290986ab12SMaksim Yevmenkin panic( 2300986ab12SMaksim Yevmenkin "%s: %s - unknown command code=%d\n", 2310986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(con->l2cap->node), cmd->code); 232878ed226SJulian Elischer break; 233878ed226SJulian Elischer } 234878ed226SJulian Elischer } /* ng_l2cap_con_wakeup */ 235878ed226SJulian Elischer 236878ed226SJulian Elischer /* 237878ed226SJulian Elischer * We have failed to open ACL connection to the remote unit. Could be negative 238878ed226SJulian Elischer * confirmation or timeout. So fail any "delayed" commands, notify upper layer, 239878ed226SJulian Elischer * remove all channels and remove connection descriptor. 240878ed226SJulian Elischer */ 241878ed226SJulian Elischer 242878ed226SJulian Elischer void 243878ed226SJulian Elischer ng_l2cap_con_fail(ng_l2cap_con_p con, u_int16_t result) 244878ed226SJulian Elischer { 245878ed226SJulian Elischer ng_l2cap_p l2cap = con->l2cap; 246878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL; 247878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL; 248878ed226SJulian Elischer 249878ed226SJulian Elischer NG_L2CAP_INFO( 250878ed226SJulian Elischer "%s: %s - ACL connection failed, result=%d\n", 251878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), result); 252878ed226SJulian Elischer 25382e1beccSMaksim Yevmenkin /* Connection is dying */ 25482e1beccSMaksim Yevmenkin con->flags |= NG_L2CAP_CON_DYING; 25582e1beccSMaksim Yevmenkin 256878ed226SJulian Elischer /* Clean command queue */ 257878ed226SJulian Elischer while (!TAILQ_EMPTY(&con->cmd_list)) { 258878ed226SJulian Elischer cmd = TAILQ_FIRST(&con->cmd_list); 259878ed226SJulian Elischer 260878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd); 261878ed226SJulian Elischer if(cmd->flags & NG_L2CAP_CMD_PENDING) 262878ed226SJulian Elischer ng_l2cap_command_untimeout(cmd); 263878ed226SJulian Elischer 264878ed226SJulian Elischer KASSERT((cmd->con == con), 265878ed226SJulian Elischer ("%s: %s - invalid connection pointer!\n", 2660986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(l2cap->node))); 267878ed226SJulian Elischer 268878ed226SJulian Elischer switch (cmd->code) { 269878ed226SJulian Elischer case NG_L2CAP_CMD_REJ: 270878ed226SJulian Elischer case NG_L2CAP_DISCON_RSP: 271878ed226SJulian Elischer case NG_L2CAP_ECHO_RSP: 272878ed226SJulian Elischer case NG_L2CAP_INFO_RSP: 273fbc48c2bSTakanori Watanabe case NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE: 274878ed226SJulian Elischer break; 275878ed226SJulian Elischer 276878ed226SJulian Elischer case NG_L2CAP_CON_REQ: 277878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, result, 0); 278878ed226SJulian Elischer break; 279878ed226SJulian Elischer 280878ed226SJulian Elischer case NG_L2CAP_CON_RSP: 281878ed226SJulian Elischer if (cmd->ch != NULL) 282878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_rsp(cmd->ch, cmd->token, 283878ed226SJulian Elischer result); 284878ed226SJulian Elischer break; 285878ed226SJulian Elischer 286878ed226SJulian Elischer case NG_L2CAP_CFG_REQ: 287878ed226SJulian Elischer case NG_L2CAP_CFG_RSP: 288878ed226SJulian Elischer case NGM_L2CAP_L2CA_WRITE: 289878ed226SJulian Elischer ng_l2cap_l2ca_discon_ind(cmd->ch); 290878ed226SJulian Elischer break; 291878ed226SJulian Elischer 292878ed226SJulian Elischer case NG_L2CAP_DISCON_REQ: 293878ed226SJulian Elischer ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token, 294878ed226SJulian Elischer NG_L2CAP_SUCCESS); 295878ed226SJulian Elischer break; 296878ed226SJulian Elischer 297878ed226SJulian Elischer case NG_L2CAP_ECHO_REQ: 298878ed226SJulian Elischer ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token, 299878ed226SJulian Elischer result, NULL); 300878ed226SJulian Elischer break; 301878ed226SJulian Elischer 302878ed226SJulian Elischer case NG_L2CAP_INFO_REQ: 303878ed226SJulian Elischer ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token, 304878ed226SJulian Elischer result, NULL); 305878ed226SJulian Elischer break; 306878ed226SJulian Elischer 307878ed226SJulian Elischer /* XXX FIXME add other commands */ 308878ed226SJulian Elischer 309878ed226SJulian Elischer default: 3100986ab12SMaksim Yevmenkin panic( 3110986ab12SMaksim Yevmenkin "%s: %s - unexpected command code=%d\n", 3120986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(l2cap->node), cmd->code); 313878ed226SJulian Elischer break; 314878ed226SJulian Elischer } 315878ed226SJulian Elischer 316878ed226SJulian Elischer if (cmd->ch != NULL) 317878ed226SJulian Elischer ng_l2cap_free_chan(cmd->ch); 318878ed226SJulian Elischer 319878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 320878ed226SJulian Elischer } 321878ed226SJulian Elischer 322878ed226SJulian Elischer /* 323878ed226SJulian Elischer * There still might be channels (in OPEN state?) that 3247a2b450fSEitan Adler * did not submit any commands, so disconnect them 325878ed226SJulian Elischer */ 326878ed226SJulian Elischer 327878ed226SJulian Elischer LIST_FOREACH(ch, &l2cap->chan_list, next) 328878ed226SJulian Elischer if (ch->con == con) 329878ed226SJulian Elischer ng_l2cap_l2ca_discon_ind(ch); 330878ed226SJulian Elischer 331878ed226SJulian Elischer /* Free connection descriptor */ 332878ed226SJulian Elischer ng_l2cap_free_con(con); 333878ed226SJulian Elischer } /* ng_l2cap_con_fail */ 334878ed226SJulian Elischer 335878ed226SJulian Elischer /* 336878ed226SJulian Elischer * Process L2CAP command timeout. In general - notify upper layer and destroy 337053359b7SPedro F. Giffuni * channel. Do not pay much attention to return code, just do our best. 338878ed226SJulian Elischer */ 339878ed226SJulian Elischer 340878ed226SJulian Elischer void 341878ed226SJulian Elischer ng_l2cap_process_command_timeout(node_p node, hook_p hook, void *arg1, int arg2) 342878ed226SJulian Elischer { 3430986ab12SMaksim Yevmenkin ng_l2cap_p l2cap = NULL; 3440986ab12SMaksim Yevmenkin ng_l2cap_con_p con = NULL; 3450986ab12SMaksim Yevmenkin ng_l2cap_cmd_p cmd = NULL; 3460986ab12SMaksim Yevmenkin u_int16_t con_handle = (arg2 & 0x0ffff); 3470986ab12SMaksim Yevmenkin u_int8_t ident = ((arg2 >> 16) & 0xff); 348878ed226SJulian Elischer 3490986ab12SMaksim Yevmenkin if (NG_NODE_NOT_VALID(node)) { 3500986ab12SMaksim Yevmenkin printf("%s: Netgraph node is not valid\n", __func__); 3510986ab12SMaksim Yevmenkin return; 3520986ab12SMaksim Yevmenkin } 3530986ab12SMaksim Yevmenkin 3540986ab12SMaksim Yevmenkin l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node); 3550986ab12SMaksim Yevmenkin 3560986ab12SMaksim Yevmenkin con = ng_l2cap_con_by_handle(l2cap, con_handle); 3570986ab12SMaksim Yevmenkin if (con == NULL) { 3580986ab12SMaksim Yevmenkin NG_L2CAP_ALERT( 3590986ab12SMaksim Yevmenkin "%s: %s - could not find connection, con_handle=%d\n", 3600986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(node), con_handle); 3610986ab12SMaksim Yevmenkin return; 3620986ab12SMaksim Yevmenkin } 3630986ab12SMaksim Yevmenkin 3640986ab12SMaksim Yevmenkin cmd = ng_l2cap_cmd_by_ident(con, ident); 3650986ab12SMaksim Yevmenkin if (cmd == NULL) { 3660986ab12SMaksim Yevmenkin NG_L2CAP_ALERT( 3670986ab12SMaksim Yevmenkin "%s: %s - could not find command, con_handle=%d, ident=%d\n", 3680986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(node), con_handle, ident); 3690986ab12SMaksim Yevmenkin return; 3700986ab12SMaksim Yevmenkin } 371878ed226SJulian Elischer 372878ed226SJulian Elischer cmd->flags &= ~NG_L2CAP_CMD_PENDING; 373878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd); 374878ed226SJulian Elischer 375878ed226SJulian Elischer switch (cmd->code) { 376878ed226SJulian Elischer case NG_L2CAP_CON_REQ: 377878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT, 0); 378878ed226SJulian Elischer ng_l2cap_free_chan(cmd->ch); 379878ed226SJulian Elischer break; 380878ed226SJulian Elischer 381878ed226SJulian Elischer case NG_L2CAP_CFG_REQ: 382878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT); 383878ed226SJulian Elischer break; 384878ed226SJulian Elischer 385878ed226SJulian Elischer case NG_L2CAP_DISCON_REQ: 386878ed226SJulian Elischer ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT); 387878ed226SJulian Elischer ng_l2cap_free_chan(cmd->ch); /* XXX free channel */ 388878ed226SJulian Elischer break; 389878ed226SJulian Elischer 390878ed226SJulian Elischer case NG_L2CAP_ECHO_REQ: 391878ed226SJulian Elischer /* Echo request timed out. Let the upper layer know */ 392878ed226SJulian Elischer ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token, 393878ed226SJulian Elischer NG_L2CAP_TIMEOUT, NULL); 394878ed226SJulian Elischer break; 395878ed226SJulian Elischer 396878ed226SJulian Elischer case NG_L2CAP_INFO_REQ: 397878ed226SJulian Elischer /* Info request timed out. Let the upper layer know */ 398878ed226SJulian Elischer ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token, 399878ed226SJulian Elischer NG_L2CAP_TIMEOUT, NULL); 400878ed226SJulian Elischer break; 401878ed226SJulian Elischer 402878ed226SJulian Elischer /* XXX FIXME add other commands */ 403878ed226SJulian Elischer 404878ed226SJulian Elischer default: 4050986ab12SMaksim Yevmenkin panic( 4060986ab12SMaksim Yevmenkin "%s: %s - unexpected command code=%d\n", 4070986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(l2cap->node), cmd->code); 408878ed226SJulian Elischer break; 409878ed226SJulian Elischer } 410878ed226SJulian Elischer 411878ed226SJulian Elischer ng_l2cap_free_cmd(cmd); 412878ed226SJulian Elischer } /* ng_l2cap_process_command_timeout */ 413