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 */
34878ed226SJulian Elischer
35878ed226SJulian Elischer #include <sys/param.h>
36878ed226SJulian Elischer #include <sys/systm.h>
37878ed226SJulian Elischer #include <sys/kernel.h>
38878ed226SJulian Elischer #include <sys/endian.h>
39878ed226SJulian Elischer #include <sys/malloc.h>
40878ed226SJulian Elischer #include <sys/mbuf.h>
41878ed226SJulian Elischer #include <sys/queue.h>
42878ed226SJulian Elischer #include <netgraph/ng_message.h>
43878ed226SJulian Elischer #include <netgraph/netgraph.h>
44b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_bluetooth.h>
45b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_hci.h>
46b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_l2cap.h>
47b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_var.h>
48b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h>
49b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h>
50b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h>
51b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>
52b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>
53878ed226SJulian Elischer
54878ed226SJulian Elischer /******************************************************************************
55878ed226SJulian Elischer ******************************************************************************
56878ed226SJulian Elischer ** L2CAP commands processing module
57878ed226SJulian Elischer ******************************************************************************
58878ed226SJulian Elischer ******************************************************************************/
59878ed226SJulian Elischer
60878ed226SJulian Elischer /*
61878ed226SJulian Elischer * Process L2CAP command queue on connection
62878ed226SJulian Elischer */
63878ed226SJulian Elischer
64878ed226SJulian Elischer void
ng_l2cap_con_wakeup(ng_l2cap_con_p con)65878ed226SJulian Elischer ng_l2cap_con_wakeup(ng_l2cap_con_p con)
66878ed226SJulian Elischer {
67878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL;
68878ed226SJulian Elischer struct mbuf *m = NULL;
69878ed226SJulian Elischer int error = 0;
70878ed226SJulian Elischer
71878ed226SJulian Elischer /* Find first non-pending command in the queue */
72878ed226SJulian Elischer TAILQ_FOREACH(cmd, &con->cmd_list, next) {
73878ed226SJulian Elischer KASSERT((cmd->con == con),
74878ed226SJulian Elischer ("%s: %s - invalid connection pointer!\n",
75878ed226SJulian Elischer __func__, NG_NODE_NAME(con->l2cap->node)));
76878ed226SJulian Elischer
77878ed226SJulian Elischer if (!(cmd->flags & NG_L2CAP_CMD_PENDING))
78878ed226SJulian Elischer break;
79878ed226SJulian Elischer }
80878ed226SJulian Elischer
81878ed226SJulian Elischer if (cmd == NULL)
82878ed226SJulian Elischer return;
83878ed226SJulian Elischer
84878ed226SJulian Elischer /* Detach command packet */
85878ed226SJulian Elischer m = cmd->aux;
86878ed226SJulian Elischer cmd->aux = NULL;
87878ed226SJulian Elischer
88878ed226SJulian Elischer /* Process command */
89878ed226SJulian Elischer switch (cmd->code) {
90878ed226SJulian Elischer case NG_L2CAP_DISCON_RSP:
91878ed226SJulian Elischer case NG_L2CAP_ECHO_RSP:
92878ed226SJulian Elischer case NG_L2CAP_INFO_RSP:
934301b251SMaksim Yevmenkin /*
944301b251SMaksim Yevmenkin * Do not check return ng_l2cap_lp_send() value, because
954301b251SMaksim Yevmenkin * in these cases we do not really have a graceful way out.
964301b251SMaksim Yevmenkin * ECHO and INFO responses are internal to the stack and not
974301b251SMaksim Yevmenkin * visible to user. REJect is just being nice to remote end
984301b251SMaksim Yevmenkin * (otherwise remote end will timeout anyway). DISCON is
994301b251SMaksim Yevmenkin * probably most interesting here, however, if it fails
1004301b251SMaksim Yevmenkin * there is nothing we can do anyway.
1014301b251SMaksim Yevmenkin */
1024301b251SMaksim Yevmenkin
1034301b251SMaksim Yevmenkin (void) ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
104878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd);
105878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
106878ed226SJulian Elischer break;
107fbc48c2bSTakanori Watanabe case NG_L2CAP_CMD_REJ:
108fbc48c2bSTakanori Watanabe (void) ng_l2cap_lp_send(con,
109fbc48c2bSTakanori Watanabe (con->linktype == NG_HCI_LINK_ACL)?
110fbc48c2bSTakanori Watanabe NG_L2CAP_SIGNAL_CID:
111fbc48c2bSTakanori Watanabe NG_L2CAP_LESIGNAL_CID
112fbc48c2bSTakanori Watanabe , m);
113fbc48c2bSTakanori Watanabe ng_l2cap_unlink_cmd(cmd);
114fbc48c2bSTakanori Watanabe ng_l2cap_free_cmd(cmd);
115fbc48c2bSTakanori Watanabe break;
116878ed226SJulian Elischer
117878ed226SJulian Elischer case NG_L2CAP_CON_REQ:
118878ed226SJulian Elischer error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
119878ed226SJulian Elischer if (error != 0) {
120878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token,
121878ed226SJulian Elischer NG_L2CAP_NO_RESOURCES, 0);
122878ed226SJulian Elischer ng_l2cap_free_chan(cmd->ch); /* will free commands */
123878ed226SJulian Elischer } else
124878ed226SJulian Elischer ng_l2cap_command_timeout(cmd,
125878ed226SJulian Elischer bluetooth_l2cap_rtx_timeout());
126878ed226SJulian Elischer break;
127878ed226SJulian Elischer case NG_L2CAP_CON_RSP:
128878ed226SJulian Elischer error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
129878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd);
130878ed226SJulian Elischer if (cmd->ch != NULL) {
131878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_rsp(cmd->ch, cmd->token,
132878ed226SJulian Elischer (error == 0)? NG_L2CAP_SUCCESS :
133878ed226SJulian Elischer NG_L2CAP_NO_RESOURCES);
134878ed226SJulian Elischer if (error != 0)
135878ed226SJulian Elischer ng_l2cap_free_chan(cmd->ch);
136878ed226SJulian Elischer }
137878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
138878ed226SJulian Elischer break;
139878ed226SJulian Elischer
140878ed226SJulian Elischer case NG_L2CAP_CFG_REQ:
141878ed226SJulian Elischer error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
142878ed226SJulian Elischer if (error != 0) {
143878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token,
144878ed226SJulian Elischer NG_L2CAP_NO_RESOURCES);
145878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd);
146878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
147878ed226SJulian Elischer } else
148878ed226SJulian Elischer ng_l2cap_command_timeout(cmd,
149878ed226SJulian Elischer bluetooth_l2cap_rtx_timeout());
150878ed226SJulian Elischer break;
151878ed226SJulian Elischer
152878ed226SJulian Elischer case NG_L2CAP_CFG_RSP:
153878ed226SJulian Elischer error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
154878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd);
155878ed226SJulian Elischer if (cmd->ch != NULL)
156878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp_rsp(cmd->ch, cmd->token,
157878ed226SJulian Elischer (error == 0)? NG_L2CAP_SUCCESS :
158878ed226SJulian Elischer NG_L2CAP_NO_RESOURCES);
159878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
160878ed226SJulian Elischer break;
161878ed226SJulian Elischer
162878ed226SJulian Elischer case NG_L2CAP_DISCON_REQ:
163878ed226SJulian Elischer error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
164878ed226SJulian Elischer ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token,
165878ed226SJulian Elischer (error == 0)? NG_L2CAP_SUCCESS : NG_L2CAP_NO_RESOURCES);
166878ed226SJulian Elischer if (error != 0)
167878ed226SJulian Elischer ng_l2cap_free_chan(cmd->ch); /* XXX free channel */
168878ed226SJulian Elischer else
169878ed226SJulian Elischer ng_l2cap_command_timeout(cmd,
170878ed226SJulian Elischer bluetooth_l2cap_rtx_timeout());
171878ed226SJulian Elischer break;
172878ed226SJulian Elischer
173878ed226SJulian Elischer case NG_L2CAP_ECHO_REQ:
174878ed226SJulian Elischer error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
175878ed226SJulian Elischer if (error != 0) {
176878ed226SJulian Elischer ng_l2cap_l2ca_ping_rsp(con, cmd->token,
177878ed226SJulian Elischer NG_L2CAP_NO_RESOURCES, NULL);
178878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd);
179878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
180878ed226SJulian Elischer } else
181878ed226SJulian Elischer ng_l2cap_command_timeout(cmd,
182878ed226SJulian Elischer bluetooth_l2cap_rtx_timeout());
183878ed226SJulian Elischer break;
184878ed226SJulian Elischer
185878ed226SJulian Elischer case NG_L2CAP_INFO_REQ:
186878ed226SJulian Elischer error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
187878ed226SJulian Elischer if (error != 0) {
188878ed226SJulian Elischer ng_l2cap_l2ca_get_info_rsp(con, cmd->token,
189878ed226SJulian Elischer NG_L2CAP_NO_RESOURCES, NULL);
190878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd);
191878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
192878ed226SJulian Elischer } else
193878ed226SJulian Elischer ng_l2cap_command_timeout(cmd,
194878ed226SJulian Elischer bluetooth_l2cap_rtx_timeout());
195878ed226SJulian Elischer break;
196878ed226SJulian Elischer
197878ed226SJulian Elischer case NGM_L2CAP_L2CA_WRITE: {
198878ed226SJulian Elischer int length = m->m_pkthdr.len;
199878ed226SJulian Elischer
200878ed226SJulian Elischer if (cmd->ch->dcid == NG_L2CAP_CLT_CID) {
201878ed226SJulian Elischer m = ng_l2cap_prepend(m, sizeof(ng_l2cap_clt_hdr_t));
202878ed226SJulian Elischer if (m == NULL)
203878ed226SJulian Elischer error = ENOBUFS;
204878ed226SJulian Elischer else
205878ed226SJulian Elischer mtod(m, ng_l2cap_clt_hdr_t *)->psm =
206878ed226SJulian Elischer htole16(cmd->ch->psm);
207878ed226SJulian Elischer }
208878ed226SJulian Elischer
209878ed226SJulian Elischer if (error == 0)
210878ed226SJulian Elischer error = ng_l2cap_lp_send(con, cmd->ch->dcid, m);
211878ed226SJulian Elischer
212878ed226SJulian Elischer ng_l2cap_l2ca_write_rsp(cmd->ch, cmd->token,
213878ed226SJulian Elischer (error == 0)? NG_L2CAP_SUCCESS : NG_L2CAP_NO_RESOURCES,
214878ed226SJulian Elischer length);
215878ed226SJulian Elischer
216878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd);
217878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
218878ed226SJulian Elischer } break;
219fbc48c2bSTakanori Watanabe case NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE:
220fbc48c2bSTakanori Watanabe error = ng_l2cap_lp_send(con, NG_L2CAP_LESIGNAL_CID, m);
221fbc48c2bSTakanori Watanabe ng_l2cap_unlink_cmd(cmd);
222fbc48c2bSTakanori Watanabe ng_l2cap_free_cmd(cmd);
223fbc48c2bSTakanori Watanabe break;
224fbc48c2bSTakanori Watanabe case NG_L2CAP_CMD_PARAM_UPDATE_REQUEST:
225fbc48c2bSTakanori Watanabe /*TBD.*/
226878ed226SJulian Elischer /* XXX FIXME add other commands */
227878ed226SJulian Elischer default:
2280986ab12SMaksim Yevmenkin panic(
2290986ab12SMaksim Yevmenkin "%s: %s - unknown command code=%d\n",
2300986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(con->l2cap->node), cmd->code);
231878ed226SJulian Elischer break;
232878ed226SJulian Elischer }
233878ed226SJulian Elischer } /* ng_l2cap_con_wakeup */
234878ed226SJulian Elischer
235878ed226SJulian Elischer /*
236878ed226SJulian Elischer * We have failed to open ACL connection to the remote unit. Could be negative
237878ed226SJulian Elischer * confirmation or timeout. So fail any "delayed" commands, notify upper layer,
238878ed226SJulian Elischer * remove all channels and remove connection descriptor.
239878ed226SJulian Elischer */
240878ed226SJulian Elischer
241878ed226SJulian Elischer void
ng_l2cap_con_fail(ng_l2cap_con_p con,u_int16_t result)242878ed226SJulian Elischer ng_l2cap_con_fail(ng_l2cap_con_p con, u_int16_t result)
243878ed226SJulian Elischer {
244878ed226SJulian Elischer ng_l2cap_p l2cap = con->l2cap;
245878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL;
246878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL;
247878ed226SJulian Elischer
248878ed226SJulian Elischer NG_L2CAP_INFO(
249878ed226SJulian Elischer "%s: %s - ACL connection failed, result=%d\n",
250878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), result);
251878ed226SJulian Elischer
25282e1beccSMaksim Yevmenkin /* Connection is dying */
25382e1beccSMaksim Yevmenkin con->flags |= NG_L2CAP_CON_DYING;
25482e1beccSMaksim Yevmenkin
255878ed226SJulian Elischer /* Clean command queue */
256878ed226SJulian Elischer while (!TAILQ_EMPTY(&con->cmd_list)) {
257878ed226SJulian Elischer cmd = TAILQ_FIRST(&con->cmd_list);
258878ed226SJulian Elischer
259878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd);
260878ed226SJulian Elischer if(cmd->flags & NG_L2CAP_CMD_PENDING)
261878ed226SJulian Elischer ng_l2cap_command_untimeout(cmd);
262878ed226SJulian Elischer
263878ed226SJulian Elischer KASSERT((cmd->con == con),
264878ed226SJulian Elischer ("%s: %s - invalid connection pointer!\n",
2650986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(l2cap->node)));
266878ed226SJulian Elischer
267878ed226SJulian Elischer switch (cmd->code) {
268878ed226SJulian Elischer case NG_L2CAP_CMD_REJ:
269878ed226SJulian Elischer case NG_L2CAP_DISCON_RSP:
270878ed226SJulian Elischer case NG_L2CAP_ECHO_RSP:
271878ed226SJulian Elischer case NG_L2CAP_INFO_RSP:
272fbc48c2bSTakanori Watanabe case NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE:
273878ed226SJulian Elischer break;
274878ed226SJulian Elischer
275878ed226SJulian Elischer case NG_L2CAP_CON_REQ:
276878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, result, 0);
277878ed226SJulian Elischer break;
278878ed226SJulian Elischer
279878ed226SJulian Elischer case NG_L2CAP_CON_RSP:
280878ed226SJulian Elischer if (cmd->ch != NULL)
281878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_rsp(cmd->ch, cmd->token,
282878ed226SJulian Elischer result);
283878ed226SJulian Elischer break;
284878ed226SJulian Elischer
285878ed226SJulian Elischer case NG_L2CAP_CFG_REQ:
286878ed226SJulian Elischer case NG_L2CAP_CFG_RSP:
287878ed226SJulian Elischer case NGM_L2CAP_L2CA_WRITE:
288878ed226SJulian Elischer ng_l2cap_l2ca_discon_ind(cmd->ch);
289878ed226SJulian Elischer break;
290878ed226SJulian Elischer
291878ed226SJulian Elischer case NG_L2CAP_DISCON_REQ:
292878ed226SJulian Elischer ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token,
293878ed226SJulian Elischer NG_L2CAP_SUCCESS);
294878ed226SJulian Elischer break;
295878ed226SJulian Elischer
296878ed226SJulian Elischer case NG_L2CAP_ECHO_REQ:
297878ed226SJulian Elischer ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
298878ed226SJulian Elischer result, NULL);
299878ed226SJulian Elischer break;
300878ed226SJulian Elischer
301878ed226SJulian Elischer case NG_L2CAP_INFO_REQ:
302878ed226SJulian Elischer ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
303878ed226SJulian Elischer result, NULL);
304878ed226SJulian Elischer break;
305878ed226SJulian Elischer
306878ed226SJulian Elischer /* XXX FIXME add other commands */
307878ed226SJulian Elischer
308878ed226SJulian Elischer default:
3090986ab12SMaksim Yevmenkin panic(
3100986ab12SMaksim Yevmenkin "%s: %s - unexpected command code=%d\n",
3110986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(l2cap->node), cmd->code);
312878ed226SJulian Elischer break;
313878ed226SJulian Elischer }
314878ed226SJulian Elischer
315878ed226SJulian Elischer if (cmd->ch != NULL)
316878ed226SJulian Elischer ng_l2cap_free_chan(cmd->ch);
317878ed226SJulian Elischer
318878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
319878ed226SJulian Elischer }
320878ed226SJulian Elischer
321878ed226SJulian Elischer /*
322878ed226SJulian Elischer * There still might be channels (in OPEN state?) that
3237a2b450fSEitan Adler * did not submit any commands, so disconnect them
324878ed226SJulian Elischer */
325878ed226SJulian Elischer
326878ed226SJulian Elischer LIST_FOREACH(ch, &l2cap->chan_list, next)
327878ed226SJulian Elischer if (ch->con == con)
328878ed226SJulian Elischer ng_l2cap_l2ca_discon_ind(ch);
329878ed226SJulian Elischer
330878ed226SJulian Elischer /* Free connection descriptor */
331878ed226SJulian Elischer ng_l2cap_free_con(con);
332878ed226SJulian Elischer } /* ng_l2cap_con_fail */
333878ed226SJulian Elischer
334878ed226SJulian Elischer /*
335878ed226SJulian Elischer * Process L2CAP command timeout. In general - notify upper layer and destroy
336053359b7SPedro F. Giffuni * channel. Do not pay much attention to return code, just do our best.
337878ed226SJulian Elischer */
338878ed226SJulian Elischer
339878ed226SJulian Elischer void
ng_l2cap_process_command_timeout(node_p node,hook_p hook,void * arg1,int arg2)340878ed226SJulian Elischer ng_l2cap_process_command_timeout(node_p node, hook_p hook, void *arg1, int arg2)
341878ed226SJulian Elischer {
3420986ab12SMaksim Yevmenkin ng_l2cap_p l2cap = NULL;
3430986ab12SMaksim Yevmenkin ng_l2cap_con_p con = NULL;
3440986ab12SMaksim Yevmenkin ng_l2cap_cmd_p cmd = NULL;
3450986ab12SMaksim Yevmenkin u_int16_t con_handle = (arg2 & 0x0ffff);
3460986ab12SMaksim Yevmenkin u_int8_t ident = ((arg2 >> 16) & 0xff);
347878ed226SJulian Elischer
3480986ab12SMaksim Yevmenkin if (NG_NODE_NOT_VALID(node)) {
3490986ab12SMaksim Yevmenkin printf("%s: Netgraph node is not valid\n", __func__);
3500986ab12SMaksim Yevmenkin return;
3510986ab12SMaksim Yevmenkin }
3520986ab12SMaksim Yevmenkin
3530986ab12SMaksim Yevmenkin l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
3540986ab12SMaksim Yevmenkin
3550986ab12SMaksim Yevmenkin con = ng_l2cap_con_by_handle(l2cap, con_handle);
3560986ab12SMaksim Yevmenkin if (con == NULL) {
3570986ab12SMaksim Yevmenkin NG_L2CAP_ALERT(
3580986ab12SMaksim Yevmenkin "%s: %s - could not find connection, con_handle=%d\n",
3590986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(node), con_handle);
3600986ab12SMaksim Yevmenkin return;
3610986ab12SMaksim Yevmenkin }
3620986ab12SMaksim Yevmenkin
3630986ab12SMaksim Yevmenkin cmd = ng_l2cap_cmd_by_ident(con, ident);
3640986ab12SMaksim Yevmenkin if (cmd == NULL) {
3650986ab12SMaksim Yevmenkin NG_L2CAP_ALERT(
3660986ab12SMaksim Yevmenkin "%s: %s - could not find command, con_handle=%d, ident=%d\n",
3670986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(node), con_handle, ident);
3680986ab12SMaksim Yevmenkin return;
3690986ab12SMaksim Yevmenkin }
370878ed226SJulian Elischer
371878ed226SJulian Elischer cmd->flags &= ~NG_L2CAP_CMD_PENDING;
372878ed226SJulian Elischer ng_l2cap_unlink_cmd(cmd);
373878ed226SJulian Elischer
374878ed226SJulian Elischer switch (cmd->code) {
375878ed226SJulian Elischer case NG_L2CAP_CON_REQ:
376878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT, 0);
377878ed226SJulian Elischer ng_l2cap_free_chan(cmd->ch);
378878ed226SJulian Elischer break;
379878ed226SJulian Elischer
380878ed226SJulian Elischer case NG_L2CAP_CFG_REQ:
381878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT);
382878ed226SJulian Elischer break;
383878ed226SJulian Elischer
384878ed226SJulian Elischer case NG_L2CAP_DISCON_REQ:
385878ed226SJulian Elischer ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT);
386878ed226SJulian Elischer ng_l2cap_free_chan(cmd->ch); /* XXX free channel */
387878ed226SJulian Elischer break;
388878ed226SJulian Elischer
389878ed226SJulian Elischer case NG_L2CAP_ECHO_REQ:
390878ed226SJulian Elischer /* Echo request timed out. Let the upper layer know */
391878ed226SJulian Elischer ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
392878ed226SJulian Elischer NG_L2CAP_TIMEOUT, NULL);
393878ed226SJulian Elischer break;
394878ed226SJulian Elischer
395878ed226SJulian Elischer case NG_L2CAP_INFO_REQ:
396878ed226SJulian Elischer /* Info request timed out. Let the upper layer know */
397878ed226SJulian Elischer ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
398878ed226SJulian Elischer NG_L2CAP_TIMEOUT, NULL);
399878ed226SJulian Elischer break;
400878ed226SJulian Elischer
401878ed226SJulian Elischer /* XXX FIXME add other commands */
402878ed226SJulian Elischer
403878ed226SJulian Elischer default:
4040986ab12SMaksim Yevmenkin panic(
4050986ab12SMaksim Yevmenkin "%s: %s - unexpected command code=%d\n",
4060986ab12SMaksim Yevmenkin __func__, NG_NODE_NAME(l2cap->node), cmd->code);
407878ed226SJulian Elischer break;
408878ed226SJulian Elischer }
409878ed226SJulian Elischer
410878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
411878ed226SJulian Elischer } /* ng_l2cap_process_command_timeout */
412