6 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * $Id: ng_l2cap_cmds.c,v 1.2 2003/09/08 19:11:45 max Exp $
31 * $FreeBSD: src/sys/netgraph/bluetooth/l2cap/ng_l2cap_cmds.c,v 1.7 2007/03/28 21:25:56 emax Exp $
32 * $DragonFly: src/sys/netgraph7/bluetooth/l2cap/ng_l2cap_cmds.c,v 1.2 2008/06/26 23:05:40 dillon Exp $
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/endian.h>
39 #include <sys/malloc.h>
41 #include <sys/queue.h>
42 #include "ng_message.h"
44 #include "bluetooth/include/ng_bluetooth.h"
45 #include "bluetooth/include/ng_hci.h"
46 #include "bluetooth/include/ng_l2cap.h"
47 #include "bluetooth/l2cap/ng_l2cap_var.h"
48 #include "bluetooth/l2cap/ng_l2cap_cmds.h"
49 #include "bluetooth/l2cap/ng_l2cap_evnt.h"
50 #include "bluetooth/l2cap/ng_l2cap_llpi.h"
51 #include "bluetooth/l2cap/ng_l2cap_ulpi.h"
52 #include "bluetooth/l2cap/ng_l2cap_misc.h"
54 /******************************************************************************
55 ******************************************************************************
56 ** L2CAP commands processing module
57 ******************************************************************************
58 ******************************************************************************/
61 * Process L2CAP command queue on connection
65 ng_l2cap_con_wakeup(ng_l2cap_con_p con)
67 ng_l2cap_cmd_p cmd = NULL;
68 struct mbuf *m = NULL;
71 /* Find first non-pending command in the queue */
72 TAILQ_FOREACH(cmd, &con->cmd_list, next) {
73 KASSERT((cmd->con == con),
74 ("%s: %s - invalid connection pointer!\n",
75 __func__, NG_NODE_NAME(con->l2cap->node)));
77 if (!(cmd->flags & NG_L2CAP_CMD_PENDING))
84 /* Detach command packet */
90 case NG_L2CAP_CMD_REJ:
91 case NG_L2CAP_DISCON_RSP:
92 case NG_L2CAP_ECHO_RSP:
93 case NG_L2CAP_INFO_RSP:
95 * Do not check return ng_l2cap_lp_send() value, because
96 * in these cases we do not really have a graceful way out.
97 * ECHO and INFO responses are internal to the stack and not
98 * visible to user. REJect is just being nice to remote end
99 * (otherwise remote end will timeout anyway). DISCON is
100 * probably most interesting here, however, if it fails
101 * there is nothing we can do anyway.
104 (void) ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
105 ng_l2cap_unlink_cmd(cmd);
106 ng_l2cap_free_cmd(cmd);
109 case NG_L2CAP_CON_REQ:
110 error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
112 ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token,
113 NG_L2CAP_NO_RESOURCES, 0);
114 ng_l2cap_free_chan(cmd->ch); /* will free commands */
116 ng_l2cap_command_timeout(cmd,
117 bluetooth_l2cap_rtx_timeout());
120 case NG_L2CAP_CON_RSP:
121 error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
122 ng_l2cap_unlink_cmd(cmd);
123 if (cmd->ch != NULL) {
124 ng_l2cap_l2ca_con_rsp_rsp(cmd->ch, cmd->token,
125 (error == 0)? NG_L2CAP_SUCCESS :
126 NG_L2CAP_NO_RESOURCES);
128 ng_l2cap_free_chan(cmd->ch);
130 ng_l2cap_free_cmd(cmd);
133 case NG_L2CAP_CFG_REQ:
134 error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
136 ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token,
137 NG_L2CAP_NO_RESOURCES);
138 ng_l2cap_unlink_cmd(cmd);
139 ng_l2cap_free_cmd(cmd);
141 ng_l2cap_command_timeout(cmd,
142 bluetooth_l2cap_rtx_timeout());
145 case NG_L2CAP_CFG_RSP:
146 error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
147 ng_l2cap_unlink_cmd(cmd);
149 ng_l2cap_l2ca_cfg_rsp_rsp(cmd->ch, cmd->token,
150 (error == 0)? NG_L2CAP_SUCCESS :
151 NG_L2CAP_NO_RESOURCES);
152 ng_l2cap_free_cmd(cmd);
155 case NG_L2CAP_DISCON_REQ:
156 error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
157 ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token,
158 (error == 0)? NG_L2CAP_SUCCESS : NG_L2CAP_NO_RESOURCES);
160 ng_l2cap_free_chan(cmd->ch); /* XXX free channel */
162 ng_l2cap_command_timeout(cmd,
163 bluetooth_l2cap_rtx_timeout());
166 case NG_L2CAP_ECHO_REQ:
167 error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
169 ng_l2cap_l2ca_ping_rsp(con, cmd->token,
170 NG_L2CAP_NO_RESOURCES, NULL);
171 ng_l2cap_unlink_cmd(cmd);
172 ng_l2cap_free_cmd(cmd);
174 ng_l2cap_command_timeout(cmd,
175 bluetooth_l2cap_rtx_timeout());
178 case NG_L2CAP_INFO_REQ:
179 error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
181 ng_l2cap_l2ca_get_info_rsp(con, cmd->token,
182 NG_L2CAP_NO_RESOURCES, NULL);
183 ng_l2cap_unlink_cmd(cmd);
184 ng_l2cap_free_cmd(cmd);
186 ng_l2cap_command_timeout(cmd,
187 bluetooth_l2cap_rtx_timeout());
190 case NGM_L2CAP_L2CA_WRITE: {
191 int length = m->m_pkthdr.len;
193 if (cmd->ch->dcid == NG_L2CAP_CLT_CID) {
194 m = ng_l2cap_prepend(m, sizeof(ng_l2cap_clt_hdr_t));
198 mtod(m, ng_l2cap_clt_hdr_t *)->psm =
199 htole16(cmd->ch->psm);
203 error = ng_l2cap_lp_send(con, cmd->ch->dcid, m);
205 ng_l2cap_l2ca_write_rsp(cmd->ch, cmd->token,
206 (error == 0)? NG_L2CAP_SUCCESS : NG_L2CAP_NO_RESOURCES,
209 ng_l2cap_unlink_cmd(cmd);
210 ng_l2cap_free_cmd(cmd);
213 /* XXX FIXME add other commands */
217 "%s: %s - unknown command code=%d\n",
218 __func__, NG_NODE_NAME(con->l2cap->node), cmd->code);
221 } /* ng_l2cap_con_wakeup */
224 * We have failed to open ACL connection to the remote unit. Could be negative
225 * confirmation or timeout. So fail any "delayed" commands, notify upper layer,
226 * remove all channels and remove connection descriptor.
230 ng_l2cap_con_fail(ng_l2cap_con_p con, u_int16_t result)
232 ng_l2cap_p l2cap = con->l2cap;
233 ng_l2cap_cmd_p cmd = NULL;
234 ng_l2cap_chan_p ch = NULL;
237 "%s: %s - ACL connection failed, result=%d\n",
238 __func__, NG_NODE_NAME(l2cap->node), result);
240 /* Connection is dying */
241 con->flags |= NG_L2CAP_CON_DYING;
243 /* Clean command queue */
244 while (!TAILQ_EMPTY(&con->cmd_list)) {
245 cmd = TAILQ_FIRST(&con->cmd_list);
247 ng_l2cap_unlink_cmd(cmd);
248 if(cmd->flags & NG_L2CAP_CMD_PENDING)
249 ng_l2cap_command_untimeout(cmd);
251 KASSERT((cmd->con == con),
252 ("%s: %s - invalid connection pointer!\n",
253 __func__, NG_NODE_NAME(l2cap->node)));
256 case NG_L2CAP_CMD_REJ:
257 case NG_L2CAP_DISCON_RSP:
258 case NG_L2CAP_ECHO_RSP:
259 case NG_L2CAP_INFO_RSP:
262 case NG_L2CAP_CON_REQ:
263 ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, result, 0);
266 case NG_L2CAP_CON_RSP:
268 ng_l2cap_l2ca_con_rsp_rsp(cmd->ch, cmd->token,
272 case NG_L2CAP_CFG_REQ:
273 case NG_L2CAP_CFG_RSP:
274 case NGM_L2CAP_L2CA_WRITE:
275 ng_l2cap_l2ca_discon_ind(cmd->ch);
278 case NG_L2CAP_DISCON_REQ:
279 ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token,
283 case NG_L2CAP_ECHO_REQ:
284 ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
288 case NG_L2CAP_INFO_REQ:
289 ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
293 /* XXX FIXME add other commands */
297 "%s: %s - unexpected command code=%d\n",
298 __func__, NG_NODE_NAME(l2cap->node), cmd->code);
303 ng_l2cap_free_chan(cmd->ch);
305 ng_l2cap_free_cmd(cmd);
309 * There still might be channels (in OPEN state?) that
310 * did not submit any commands, so diconnect them
313 LIST_FOREACH(ch, &l2cap->chan_list, next)
315 ng_l2cap_l2ca_discon_ind(ch);
317 /* Free connection descriptor */
318 ng_l2cap_free_con(con);
319 } /* ng_l2cap_con_fail */
322 * Process L2CAP command timeout. In general - notify upper layer and destroy
323 * channel. Do not pay much attension to return code, just do our best.
327 ng_l2cap_process_command_timeout(node_p node, hook_p hook, void *arg1, int arg2)
329 ng_l2cap_p l2cap = NULL;
330 ng_l2cap_con_p con = NULL;
331 ng_l2cap_cmd_p cmd = NULL;
332 u_int16_t con_handle = (arg2 & 0x0ffff);
333 u_int8_t ident = ((arg2 >> 16) & 0xff);
335 if (NG_NODE_NOT_VALID(node)) {
336 printf("%s: Netgraph node is not valid\n", __func__);
340 l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
342 con = ng_l2cap_con_by_handle(l2cap, con_handle);
345 "%s: %s - could not find connection, con_handle=%d\n",
346 __func__, NG_NODE_NAME(node), con_handle);
350 cmd = ng_l2cap_cmd_by_ident(con, ident);
353 "%s: %s - could not find command, con_handle=%d, ident=%d\n",
354 __func__, NG_NODE_NAME(node), con_handle, ident);
358 cmd->flags &= ~NG_L2CAP_CMD_PENDING;
359 ng_l2cap_unlink_cmd(cmd);
362 case NG_L2CAP_CON_REQ:
363 ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT, 0);
364 ng_l2cap_free_chan(cmd->ch);
367 case NG_L2CAP_CFG_REQ:
368 ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT);
371 case NG_L2CAP_DISCON_REQ:
372 ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT);
373 ng_l2cap_free_chan(cmd->ch); /* XXX free channel */
376 case NG_L2CAP_ECHO_REQ:
377 /* Echo request timed out. Let the upper layer know */
378 ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
379 NG_L2CAP_TIMEOUT, NULL);
382 case NG_L2CAP_INFO_REQ:
383 /* Info request timed out. Let the upper layer know */
384 ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
385 NG_L2CAP_TIMEOUT, NULL);
388 /* XXX FIXME add other commands */
392 "%s: %s - unexpected command code=%d\n",
393 __func__, NG_NODE_NAME(l2cap->node), cmd->code);
397 ng_l2cap_free_cmd(cmd);
398 } /* ng_l2cap_process_command_timeout */