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 $
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/endian.h>
38 #include <sys/malloc.h>
40 #include <sys/queue.h>
41 #include <netgraph/ng_message.h>
42 #include <netgraph/netgraph.h>
43 #include <netgraph/bluetooth/include/ng_bluetooth.h>
44 #include <netgraph/bluetooth/include/ng_hci.h>
45 #include <netgraph/bluetooth/include/ng_l2cap.h>
46 #include <netgraph/bluetooth/l2cap/ng_l2cap_var.h>
47 #include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h>
48 #include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h>
49 #include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h>
50 #include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>
51 #include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>
53 /******************************************************************************
54 ******************************************************************************
55 ** L2CAP commands processing module
56 ******************************************************************************
57 ******************************************************************************/
60 * Process L2CAP command queue on connection
64 ng_l2cap_con_wakeup(ng_l2cap_con_p con
)
66 ng_l2cap_cmd_p cmd
= NULL
;
67 struct mbuf
*m
= NULL
;
70 /* Find first non-pending command in the queue */
71 TAILQ_FOREACH(cmd
, &con
->cmd_list
, next
) {
72 KASSERT((cmd
->con
== con
),
73 ("%s: %s - invalid connection pointer!\n",
74 __func__
, NG_NODE_NAME(con
->l2cap
->node
)));
76 if (!(cmd
->flags
& NG_L2CAP_CMD_PENDING
))
83 /* Detach command packet */
89 case NG_L2CAP_CMD_REJ
:
90 case NG_L2CAP_DISCON_RSP
:
91 case NG_L2CAP_ECHO_RSP
:
92 case NG_L2CAP_INFO_RSP
:
94 * Do not check return ng_l2cap_lp_send() value, because
95 * in these cases we do not really have a graceful way out.
96 * ECHO and INFO responses are internal to the stack and not
97 * visible to user. REJect is just being nice to remote end
98 * (otherwise remote end will timeout anyway). DISCON is
99 * probably most interesting here, however, if it fails
100 * there is nothing we can do anyway.
103 (void) ng_l2cap_lp_send(con
, NG_L2CAP_SIGNAL_CID
, m
);
104 ng_l2cap_unlink_cmd(cmd
);
105 ng_l2cap_free_cmd(cmd
);
108 case NG_L2CAP_CON_REQ
:
109 error
= ng_l2cap_lp_send(con
, NG_L2CAP_SIGNAL_CID
, m
);
111 ng_l2cap_l2ca_con_rsp(cmd
->ch
, cmd
->token
,
112 NG_L2CAP_NO_RESOURCES
, 0);
113 ng_l2cap_free_chan(cmd
->ch
); /* will free commands */
115 ng_l2cap_command_timeout(cmd
,
116 bluetooth_l2cap_rtx_timeout());
119 case NG_L2CAP_CON_RSP
:
120 error
= ng_l2cap_lp_send(con
, NG_L2CAP_SIGNAL_CID
, m
);
121 ng_l2cap_unlink_cmd(cmd
);
122 if (cmd
->ch
!= NULL
) {
123 ng_l2cap_l2ca_con_rsp_rsp(cmd
->ch
, cmd
->token
,
124 (error
== 0)? NG_L2CAP_SUCCESS
:
125 NG_L2CAP_NO_RESOURCES
);
127 ng_l2cap_free_chan(cmd
->ch
);
129 ng_l2cap_free_cmd(cmd
);
132 case NG_L2CAP_CFG_REQ
:
133 error
= ng_l2cap_lp_send(con
, NG_L2CAP_SIGNAL_CID
, m
);
135 ng_l2cap_l2ca_cfg_rsp(cmd
->ch
, cmd
->token
,
136 NG_L2CAP_NO_RESOURCES
);
137 ng_l2cap_unlink_cmd(cmd
);
138 ng_l2cap_free_cmd(cmd
);
140 ng_l2cap_command_timeout(cmd
,
141 bluetooth_l2cap_rtx_timeout());
144 case NG_L2CAP_CFG_RSP
:
145 error
= ng_l2cap_lp_send(con
, NG_L2CAP_SIGNAL_CID
, m
);
146 ng_l2cap_unlink_cmd(cmd
);
148 ng_l2cap_l2ca_cfg_rsp_rsp(cmd
->ch
, cmd
->token
,
149 (error
== 0)? NG_L2CAP_SUCCESS
:
150 NG_L2CAP_NO_RESOURCES
);
151 ng_l2cap_free_cmd(cmd
);
154 case NG_L2CAP_DISCON_REQ
:
155 error
= ng_l2cap_lp_send(con
, NG_L2CAP_SIGNAL_CID
, m
);
156 ng_l2cap_l2ca_discon_rsp(cmd
->ch
, cmd
->token
,
157 (error
== 0)? NG_L2CAP_SUCCESS
: NG_L2CAP_NO_RESOURCES
);
159 ng_l2cap_free_chan(cmd
->ch
); /* XXX free channel */
161 ng_l2cap_command_timeout(cmd
,
162 bluetooth_l2cap_rtx_timeout());
165 case NG_L2CAP_ECHO_REQ
:
166 error
= ng_l2cap_lp_send(con
, NG_L2CAP_SIGNAL_CID
, m
);
168 ng_l2cap_l2ca_ping_rsp(con
, cmd
->token
,
169 NG_L2CAP_NO_RESOURCES
, NULL
);
170 ng_l2cap_unlink_cmd(cmd
);
171 ng_l2cap_free_cmd(cmd
);
173 ng_l2cap_command_timeout(cmd
,
174 bluetooth_l2cap_rtx_timeout());
177 case NG_L2CAP_INFO_REQ
:
178 error
= ng_l2cap_lp_send(con
, NG_L2CAP_SIGNAL_CID
, m
);
180 ng_l2cap_l2ca_get_info_rsp(con
, cmd
->token
,
181 NG_L2CAP_NO_RESOURCES
, NULL
);
182 ng_l2cap_unlink_cmd(cmd
);
183 ng_l2cap_free_cmd(cmd
);
185 ng_l2cap_command_timeout(cmd
,
186 bluetooth_l2cap_rtx_timeout());
189 case NGM_L2CAP_L2CA_WRITE
: {
190 int length
= m
->m_pkthdr
.len
;
192 if (cmd
->ch
->dcid
== NG_L2CAP_CLT_CID
) {
193 m
= ng_l2cap_prepend(m
, sizeof(ng_l2cap_clt_hdr_t
));
197 mtod(m
, ng_l2cap_clt_hdr_t
*)->psm
=
198 htole16(cmd
->ch
->psm
);
202 error
= ng_l2cap_lp_send(con
, cmd
->ch
->dcid
, m
);
204 ng_l2cap_l2ca_write_rsp(cmd
->ch
, cmd
->token
,
205 (error
== 0)? NG_L2CAP_SUCCESS
: NG_L2CAP_NO_RESOURCES
,
208 ng_l2cap_unlink_cmd(cmd
);
209 ng_l2cap_free_cmd(cmd
);
212 /* XXX FIXME add other commands */
216 "%s: %s - unknown command code=%d\n",
217 __func__
, NG_NODE_NAME(con
->l2cap
->node
), cmd
->code
);
220 } /* ng_l2cap_con_wakeup */
223 * We have failed to open ACL connection to the remote unit. Could be negative
224 * confirmation or timeout. So fail any "delayed" commands, notify upper layer,
225 * remove all channels and remove connection descriptor.
229 ng_l2cap_con_fail(ng_l2cap_con_p con
, u_int16_t result
)
231 ng_l2cap_p l2cap
= con
->l2cap
;
232 ng_l2cap_cmd_p cmd
= NULL
;
233 ng_l2cap_chan_p ch
= NULL
;
236 "%s: %s - ACL connection failed, result=%d\n",
237 __func__
, NG_NODE_NAME(l2cap
->node
), result
);
239 /* Connection is dying */
240 con
->flags
|= NG_L2CAP_CON_DYING
;
242 /* Clean command queue */
243 while (!TAILQ_EMPTY(&con
->cmd_list
)) {
244 cmd
= TAILQ_FIRST(&con
->cmd_list
);
246 ng_l2cap_unlink_cmd(cmd
);
247 if(cmd
->flags
& NG_L2CAP_CMD_PENDING
)
248 ng_l2cap_command_untimeout(cmd
);
250 KASSERT((cmd
->con
== con
),
251 ("%s: %s - invalid connection pointer!\n",
252 __func__
, NG_NODE_NAME(l2cap
->node
)));
255 case NG_L2CAP_CMD_REJ
:
256 case NG_L2CAP_DISCON_RSP
:
257 case NG_L2CAP_ECHO_RSP
:
258 case NG_L2CAP_INFO_RSP
:
261 case NG_L2CAP_CON_REQ
:
262 ng_l2cap_l2ca_con_rsp(cmd
->ch
, cmd
->token
, result
, 0);
265 case NG_L2CAP_CON_RSP
:
267 ng_l2cap_l2ca_con_rsp_rsp(cmd
->ch
, cmd
->token
,
271 case NG_L2CAP_CFG_REQ
:
272 case NG_L2CAP_CFG_RSP
:
273 case NGM_L2CAP_L2CA_WRITE
:
274 ng_l2cap_l2ca_discon_ind(cmd
->ch
);
277 case NG_L2CAP_DISCON_REQ
:
278 ng_l2cap_l2ca_discon_rsp(cmd
->ch
, cmd
->token
,
282 case NG_L2CAP_ECHO_REQ
:
283 ng_l2cap_l2ca_ping_rsp(cmd
->con
, cmd
->token
,
287 case NG_L2CAP_INFO_REQ
:
288 ng_l2cap_l2ca_get_info_rsp(cmd
->con
, cmd
->token
,
292 /* XXX FIXME add other commands */
296 "%s: %s - unexpected command code=%d\n",
297 __func__
, NG_NODE_NAME(l2cap
->node
), cmd
->code
);
302 ng_l2cap_free_chan(cmd
->ch
);
304 ng_l2cap_free_cmd(cmd
);
308 * There still might be channels (in OPEN state?) that
309 * did not submit any commands, so diconnect them
312 LIST_FOREACH(ch
, &l2cap
->chan_list
, next
)
314 ng_l2cap_l2ca_discon_ind(ch
);
316 /* Free connection descriptor */
317 ng_l2cap_free_con(con
);
318 } /* ng_l2cap_con_fail */
321 * Process L2CAP command timeout. In general - notify upper layer and destroy
322 * channel. Do not pay much attension to return code, just do our best.
326 ng_l2cap_process_command_timeout(node_p node
, hook_p hook
, void *arg1
, int arg2
)
328 ng_l2cap_p l2cap
= NULL
;
329 ng_l2cap_con_p con
= NULL
;
330 ng_l2cap_cmd_p cmd
= NULL
;
331 u_int16_t con_handle
= (arg2
& 0x0ffff);
332 u_int8_t ident
= ((arg2
>> 16) & 0xff);
334 if (NG_NODE_NOT_VALID(node
)) {
335 printf("%s: Netgraph node is not valid\n", __func__
);
339 l2cap
= (ng_l2cap_p
) NG_NODE_PRIVATE(node
);
341 con
= ng_l2cap_con_by_handle(l2cap
, con_handle
);
344 "%s: %s - could not find connection, con_handle=%d\n",
345 __func__
, NG_NODE_NAME(node
), con_handle
);
349 cmd
= ng_l2cap_cmd_by_ident(con
, ident
);
352 "%s: %s - could not find command, con_handle=%d, ident=%d\n",
353 __func__
, NG_NODE_NAME(node
), con_handle
, ident
);
357 cmd
->flags
&= ~NG_L2CAP_CMD_PENDING
;
358 ng_l2cap_unlink_cmd(cmd
);
361 case NG_L2CAP_CON_REQ
:
362 ng_l2cap_l2ca_con_rsp(cmd
->ch
, cmd
->token
, NG_L2CAP_TIMEOUT
, 0);
363 ng_l2cap_free_chan(cmd
->ch
);
366 case NG_L2CAP_CFG_REQ
:
367 ng_l2cap_l2ca_cfg_rsp(cmd
->ch
, cmd
->token
, NG_L2CAP_TIMEOUT
);
370 case NG_L2CAP_DISCON_REQ
:
371 ng_l2cap_l2ca_discon_rsp(cmd
->ch
, cmd
->token
, NG_L2CAP_TIMEOUT
);
372 ng_l2cap_free_chan(cmd
->ch
); /* XXX free channel */
375 case NG_L2CAP_ECHO_REQ
:
376 /* Echo request timed out. Let the upper layer know */
377 ng_l2cap_l2ca_ping_rsp(cmd
->con
, cmd
->token
,
378 NG_L2CAP_TIMEOUT
, NULL
);
381 case NG_L2CAP_INFO_REQ
:
382 /* Info request timed out. Let the upper layer know */
383 ng_l2cap_l2ca_get_info_rsp(cmd
->con
, cmd
->token
,
384 NG_L2CAP_TIMEOUT
, NULL
);
387 /* XXX FIXME add other commands */
391 "%s: %s - unexpected command code=%d\n",
392 __func__
, NG_NODE_NAME(l2cap
->node
), cmd
->code
);
396 ng_l2cap_free_cmd(cmd
);
397 } /* ng_l2cap_process_command_timeout */