1b06ebda0SMatthew Dillon /*
2b06ebda0SMatthew Dillon  * ng_l2cap_cmds.c
3b06ebda0SMatthew Dillon  */
4b06ebda0SMatthew Dillon 
5b06ebda0SMatthew Dillon /*-
6b06ebda0SMatthew Dillon  * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
7b06ebda0SMatthew Dillon  * All rights reserved.
8b06ebda0SMatthew Dillon  *
9b06ebda0SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
10b06ebda0SMatthew Dillon  * modification, are permitted provided that the following conditions
11b06ebda0SMatthew Dillon  * are met:
12b06ebda0SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
13b06ebda0SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
14b06ebda0SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
15b06ebda0SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in the
16b06ebda0SMatthew Dillon  *    documentation and/or other materials provided with the distribution.
17b06ebda0SMatthew Dillon  *
18b06ebda0SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19b06ebda0SMatthew Dillon  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20b06ebda0SMatthew Dillon  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21b06ebda0SMatthew Dillon  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22b06ebda0SMatthew Dillon  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23b06ebda0SMatthew Dillon  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24b06ebda0SMatthew Dillon  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25b06ebda0SMatthew Dillon  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26b06ebda0SMatthew Dillon  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27b06ebda0SMatthew Dillon  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28b06ebda0SMatthew Dillon  * SUCH DAMAGE.
29b06ebda0SMatthew Dillon  *
30b06ebda0SMatthew Dillon  * $Id: ng_l2cap_cmds.c,v 1.2 2003/09/08 19:11:45 max Exp $
31b06ebda0SMatthew Dillon  * $FreeBSD: src/sys/netgraph/bluetooth/l2cap/ng_l2cap_cmds.c,v 1.7 2007/03/28 21:25:56 emax Exp $
32b06ebda0SMatthew Dillon  */
33b06ebda0SMatthew Dillon 
34b06ebda0SMatthew Dillon #include <sys/param.h>
35b06ebda0SMatthew Dillon #include <sys/systm.h>
36b06ebda0SMatthew Dillon #include <sys/kernel.h>
37b06ebda0SMatthew Dillon #include <sys/endian.h>
38b06ebda0SMatthew Dillon #include <sys/malloc.h>
39b06ebda0SMatthew Dillon #include <sys/mbuf.h>
40b06ebda0SMatthew Dillon #include <sys/queue.h>
41*e85b99abSSascha Wildner #include <netgraph7/ng_message.h>
42*e85b99abSSascha Wildner #include <netgraph7/netgraph.h>
43*e85b99abSSascha Wildner #include <netgraph7/bluetooth/include/ng_bluetooth.h>
44*e85b99abSSascha Wildner #include <netgraph7/bluetooth/include/ng_hci.h>
45*e85b99abSSascha Wildner #include <netgraph7/bluetooth/include/ng_l2cap.h>
46*e85b99abSSascha Wildner #include <netgraph7/bluetooth/l2cap/ng_l2cap_var.h>
47*e85b99abSSascha Wildner #include <netgraph7/bluetooth/l2cap/ng_l2cap_cmds.h>
48*e85b99abSSascha Wildner #include <netgraph7/bluetooth/l2cap/ng_l2cap_evnt.h>
49*e85b99abSSascha Wildner #include <netgraph7/bluetooth/l2cap/ng_l2cap_llpi.h>
50*e85b99abSSascha Wildner #include <netgraph7/bluetooth/l2cap/ng_l2cap_ulpi.h>
51*e85b99abSSascha Wildner #include <netgraph7/bluetooth/l2cap/ng_l2cap_misc.h>
52b06ebda0SMatthew Dillon 
53b06ebda0SMatthew Dillon /******************************************************************************
54b06ebda0SMatthew Dillon  ******************************************************************************
55b06ebda0SMatthew Dillon  **                    L2CAP commands processing module
56b06ebda0SMatthew Dillon  ******************************************************************************
57b06ebda0SMatthew Dillon  ******************************************************************************/
58b06ebda0SMatthew Dillon 
59b06ebda0SMatthew Dillon /*
60b06ebda0SMatthew Dillon  * Process L2CAP command queue on connection
61b06ebda0SMatthew Dillon  */
62b06ebda0SMatthew Dillon 
63b06ebda0SMatthew Dillon void
ng_l2cap_con_wakeup(ng_l2cap_con_p con)64b06ebda0SMatthew Dillon ng_l2cap_con_wakeup(ng_l2cap_con_p con)
65b06ebda0SMatthew Dillon {
66b06ebda0SMatthew Dillon 	ng_l2cap_cmd_p	 cmd = NULL;
67b06ebda0SMatthew Dillon 	struct mbuf	*m = NULL;
68b06ebda0SMatthew Dillon 	int		 error = 0;
69b06ebda0SMatthew Dillon 
70b06ebda0SMatthew Dillon 	/* Find first non-pending command in the queue */
71b06ebda0SMatthew Dillon 	TAILQ_FOREACH(cmd, &con->cmd_list, next) {
72b06ebda0SMatthew Dillon 		KASSERT((cmd->con == con),
73b06ebda0SMatthew Dillon ("%s: %s - invalid connection pointer!\n",
74b06ebda0SMatthew Dillon 			__func__, NG_NODE_NAME(con->l2cap->node)));
75b06ebda0SMatthew Dillon 
76b06ebda0SMatthew Dillon 		if (!(cmd->flags & NG_L2CAP_CMD_PENDING))
77b06ebda0SMatthew Dillon 			break;
78b06ebda0SMatthew Dillon 	}
79b06ebda0SMatthew Dillon 
80b06ebda0SMatthew Dillon 	if (cmd == NULL)
81b06ebda0SMatthew Dillon 		return;
82b06ebda0SMatthew Dillon 
83b06ebda0SMatthew Dillon 	/* Detach command packet */
84b06ebda0SMatthew Dillon 	m = cmd->aux;
85b06ebda0SMatthew Dillon 	cmd->aux = NULL;
86b06ebda0SMatthew Dillon 
87b06ebda0SMatthew Dillon 	/* Process command */
88b06ebda0SMatthew Dillon 	switch (cmd->code) {
89b06ebda0SMatthew Dillon 	case NG_L2CAP_CMD_REJ:
90b06ebda0SMatthew Dillon 	case NG_L2CAP_DISCON_RSP:
91b06ebda0SMatthew Dillon 	case NG_L2CAP_ECHO_RSP:
92b06ebda0SMatthew Dillon 	case NG_L2CAP_INFO_RSP:
93b06ebda0SMatthew Dillon 		/*
94b06ebda0SMatthew Dillon 		 * Do not check return ng_l2cap_lp_send() value, because
95b06ebda0SMatthew Dillon 		 * in these cases we do not really have a graceful way out.
96b06ebda0SMatthew Dillon 		 * ECHO and INFO responses are internal to the stack and not
97b06ebda0SMatthew Dillon 		 * visible to user. REJect is just being nice to remote end
98b06ebda0SMatthew Dillon 		 * (otherwise remote end will timeout anyway). DISCON is
99b06ebda0SMatthew Dillon 		 * probably most interesting here, however, if it fails
100b06ebda0SMatthew Dillon 		 * there is nothing we can do anyway.
101b06ebda0SMatthew Dillon 		 */
102b06ebda0SMatthew Dillon 
103b06ebda0SMatthew Dillon 		(void) ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
104b06ebda0SMatthew Dillon 		ng_l2cap_unlink_cmd(cmd);
105b06ebda0SMatthew Dillon 		ng_l2cap_free_cmd(cmd);
106b06ebda0SMatthew Dillon 		break;
107b06ebda0SMatthew Dillon 
108b06ebda0SMatthew Dillon 	case NG_L2CAP_CON_REQ:
109b06ebda0SMatthew Dillon 		error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
110b06ebda0SMatthew Dillon 		if (error != 0) {
111b06ebda0SMatthew Dillon 			ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token,
112b06ebda0SMatthew Dillon 				NG_L2CAP_NO_RESOURCES, 0);
113b06ebda0SMatthew Dillon 			ng_l2cap_free_chan(cmd->ch); /* will free commands */
114b06ebda0SMatthew Dillon 		} else
115b06ebda0SMatthew Dillon 			ng_l2cap_command_timeout(cmd,
116b06ebda0SMatthew Dillon 				bluetooth_l2cap_rtx_timeout());
117b06ebda0SMatthew Dillon 		break;
118b06ebda0SMatthew Dillon 
119b06ebda0SMatthew Dillon 	case NG_L2CAP_CON_RSP:
120b06ebda0SMatthew Dillon 		error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
121b06ebda0SMatthew Dillon 		ng_l2cap_unlink_cmd(cmd);
122b06ebda0SMatthew Dillon 		if (cmd->ch != NULL) {
123b06ebda0SMatthew Dillon 			ng_l2cap_l2ca_con_rsp_rsp(cmd->ch, cmd->token,
124b06ebda0SMatthew Dillon 				(error == 0)? NG_L2CAP_SUCCESS :
125b06ebda0SMatthew Dillon 					NG_L2CAP_NO_RESOURCES);
126b06ebda0SMatthew Dillon 			if (error != 0)
127b06ebda0SMatthew Dillon 				ng_l2cap_free_chan(cmd->ch);
128b06ebda0SMatthew Dillon 		}
129b06ebda0SMatthew Dillon 		ng_l2cap_free_cmd(cmd);
130b06ebda0SMatthew Dillon 		break;
131b06ebda0SMatthew Dillon 
132b06ebda0SMatthew Dillon 	case NG_L2CAP_CFG_REQ:
133b06ebda0SMatthew Dillon 		error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
134b06ebda0SMatthew Dillon 		if (error != 0) {
135b06ebda0SMatthew Dillon 			ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token,
136b06ebda0SMatthew Dillon 				NG_L2CAP_NO_RESOURCES);
137b06ebda0SMatthew Dillon 			ng_l2cap_unlink_cmd(cmd);
138b06ebda0SMatthew Dillon 			ng_l2cap_free_cmd(cmd);
139b06ebda0SMatthew Dillon 		} else
140b06ebda0SMatthew Dillon 			ng_l2cap_command_timeout(cmd,
141b06ebda0SMatthew Dillon 				bluetooth_l2cap_rtx_timeout());
142b06ebda0SMatthew Dillon 		break;
143b06ebda0SMatthew Dillon 
144b06ebda0SMatthew Dillon 	case NG_L2CAP_CFG_RSP:
145b06ebda0SMatthew Dillon 		error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
146b06ebda0SMatthew Dillon 		ng_l2cap_unlink_cmd(cmd);
147b06ebda0SMatthew Dillon 		if (cmd->ch != NULL)
148b06ebda0SMatthew Dillon 			ng_l2cap_l2ca_cfg_rsp_rsp(cmd->ch, cmd->token,
149b06ebda0SMatthew Dillon 				(error == 0)? NG_L2CAP_SUCCESS :
150b06ebda0SMatthew Dillon 					NG_L2CAP_NO_RESOURCES);
151b06ebda0SMatthew Dillon 		ng_l2cap_free_cmd(cmd);
152b06ebda0SMatthew Dillon 		break;
153b06ebda0SMatthew Dillon 
154b06ebda0SMatthew Dillon 	case NG_L2CAP_DISCON_REQ:
155b06ebda0SMatthew Dillon 		error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
156b06ebda0SMatthew Dillon 		ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token,
157b06ebda0SMatthew Dillon 			(error == 0)? NG_L2CAP_SUCCESS : NG_L2CAP_NO_RESOURCES);
158b06ebda0SMatthew Dillon 		if (error != 0)
159b06ebda0SMatthew Dillon 			ng_l2cap_free_chan(cmd->ch); /* XXX free channel */
160b06ebda0SMatthew Dillon 		else
161b06ebda0SMatthew Dillon 			ng_l2cap_command_timeout(cmd,
162b06ebda0SMatthew Dillon 				bluetooth_l2cap_rtx_timeout());
163b06ebda0SMatthew Dillon 		break;
164b06ebda0SMatthew Dillon 
165b06ebda0SMatthew Dillon 	case NG_L2CAP_ECHO_REQ:
166b06ebda0SMatthew Dillon 		error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
167b06ebda0SMatthew Dillon 		if (error != 0) {
168b06ebda0SMatthew Dillon 			ng_l2cap_l2ca_ping_rsp(con, cmd->token,
169b06ebda0SMatthew Dillon 					NG_L2CAP_NO_RESOURCES, NULL);
170b06ebda0SMatthew Dillon 			ng_l2cap_unlink_cmd(cmd);
171b06ebda0SMatthew Dillon 			ng_l2cap_free_cmd(cmd);
172b06ebda0SMatthew Dillon 		} else
173b06ebda0SMatthew Dillon 			ng_l2cap_command_timeout(cmd,
174b06ebda0SMatthew Dillon 				bluetooth_l2cap_rtx_timeout());
175b06ebda0SMatthew Dillon 		break;
176b06ebda0SMatthew Dillon 
177b06ebda0SMatthew Dillon 	case NG_L2CAP_INFO_REQ:
178b06ebda0SMatthew Dillon 		error = ng_l2cap_lp_send(con, NG_L2CAP_SIGNAL_CID, m);
179b06ebda0SMatthew Dillon 		if (error != 0) {
180b06ebda0SMatthew Dillon 			ng_l2cap_l2ca_get_info_rsp(con, cmd->token,
181b06ebda0SMatthew Dillon 				NG_L2CAP_NO_RESOURCES, NULL);
182b06ebda0SMatthew Dillon 			ng_l2cap_unlink_cmd(cmd);
183b06ebda0SMatthew Dillon 			ng_l2cap_free_cmd(cmd);
184b06ebda0SMatthew Dillon 		} else
185b06ebda0SMatthew Dillon 			ng_l2cap_command_timeout(cmd,
186b06ebda0SMatthew Dillon 				bluetooth_l2cap_rtx_timeout());
187b06ebda0SMatthew Dillon 		break;
188b06ebda0SMatthew Dillon 
189b06ebda0SMatthew Dillon 	case NGM_L2CAP_L2CA_WRITE: {
190b06ebda0SMatthew Dillon 		int	length = m->m_pkthdr.len;
191b06ebda0SMatthew Dillon 
192b06ebda0SMatthew Dillon 		if (cmd->ch->dcid == NG_L2CAP_CLT_CID) {
193b06ebda0SMatthew Dillon 			m = ng_l2cap_prepend(m, sizeof(ng_l2cap_clt_hdr_t));
194b06ebda0SMatthew Dillon 			if (m == NULL)
195b06ebda0SMatthew Dillon 				error = ENOBUFS;
196b06ebda0SMatthew Dillon 			else
197b06ebda0SMatthew Dillon                 		mtod(m, ng_l2cap_clt_hdr_t *)->psm =
198b06ebda0SMatthew Dillon 							htole16(cmd->ch->psm);
199b06ebda0SMatthew Dillon 		}
200b06ebda0SMatthew Dillon 
201b06ebda0SMatthew Dillon 		if (error == 0)
202b06ebda0SMatthew Dillon 			error = ng_l2cap_lp_send(con, cmd->ch->dcid, m);
203b06ebda0SMatthew Dillon 
204b06ebda0SMatthew Dillon 		ng_l2cap_l2ca_write_rsp(cmd->ch, cmd->token,
205b06ebda0SMatthew Dillon 			(error == 0)? NG_L2CAP_SUCCESS : NG_L2CAP_NO_RESOURCES,
206b06ebda0SMatthew Dillon 			length);
207b06ebda0SMatthew Dillon 
208b06ebda0SMatthew Dillon 		ng_l2cap_unlink_cmd(cmd);
209b06ebda0SMatthew Dillon 		ng_l2cap_free_cmd(cmd);
210b06ebda0SMatthew Dillon 		} break;
211b06ebda0SMatthew Dillon 
212b06ebda0SMatthew Dillon 	/* XXX FIXME add other commands */
213b06ebda0SMatthew Dillon 
214b06ebda0SMatthew Dillon 	default:
215b06ebda0SMatthew Dillon 		panic(
216b06ebda0SMatthew Dillon "%s: %s - unknown command code=%d\n",
217b06ebda0SMatthew Dillon 			__func__, NG_NODE_NAME(con->l2cap->node), cmd->code);
218b06ebda0SMatthew Dillon 		break;
219b06ebda0SMatthew Dillon 	}
220b06ebda0SMatthew Dillon } /* ng_l2cap_con_wakeup */
221b06ebda0SMatthew Dillon 
222b06ebda0SMatthew Dillon /*
223b06ebda0SMatthew Dillon  * We have failed to open ACL connection to the remote unit. Could be negative
224b06ebda0SMatthew Dillon  * confirmation or timeout. So fail any "delayed" commands, notify upper layer,
225b06ebda0SMatthew Dillon  * remove all channels and remove connection descriptor.
226b06ebda0SMatthew Dillon  */
227b06ebda0SMatthew Dillon 
228b06ebda0SMatthew Dillon void
ng_l2cap_con_fail(ng_l2cap_con_p con,u_int16_t result)229b06ebda0SMatthew Dillon ng_l2cap_con_fail(ng_l2cap_con_p con, u_int16_t result)
230b06ebda0SMatthew Dillon {
231b06ebda0SMatthew Dillon 	ng_l2cap_p	l2cap = con->l2cap;
232b06ebda0SMatthew Dillon 	ng_l2cap_cmd_p	cmd = NULL;
233b06ebda0SMatthew Dillon 	ng_l2cap_chan_p	ch = NULL;
234b06ebda0SMatthew Dillon 
235b06ebda0SMatthew Dillon 	NG_L2CAP_INFO(
236b06ebda0SMatthew Dillon "%s: %s - ACL connection failed, result=%d\n",
237b06ebda0SMatthew Dillon 		__func__, NG_NODE_NAME(l2cap->node), result);
238b06ebda0SMatthew Dillon 
239b06ebda0SMatthew Dillon 	/* Connection is dying */
240b06ebda0SMatthew Dillon 	con->flags |= NG_L2CAP_CON_DYING;
241b06ebda0SMatthew Dillon 
242b06ebda0SMatthew Dillon 	/* Clean command queue */
243b06ebda0SMatthew Dillon 	while (!TAILQ_EMPTY(&con->cmd_list)) {
244b06ebda0SMatthew Dillon 		cmd = TAILQ_FIRST(&con->cmd_list);
245b06ebda0SMatthew Dillon 
246b06ebda0SMatthew Dillon 		ng_l2cap_unlink_cmd(cmd);
247b06ebda0SMatthew Dillon 		if(cmd->flags & NG_L2CAP_CMD_PENDING)
248b06ebda0SMatthew Dillon 			ng_l2cap_command_untimeout(cmd);
249b06ebda0SMatthew Dillon 
250b06ebda0SMatthew Dillon 		KASSERT((cmd->con == con),
251b06ebda0SMatthew Dillon ("%s: %s - invalid connection pointer!\n",
252b06ebda0SMatthew Dillon 			__func__, NG_NODE_NAME(l2cap->node)));
253b06ebda0SMatthew Dillon 
254b06ebda0SMatthew Dillon 		switch (cmd->code) {
255b06ebda0SMatthew Dillon 		case NG_L2CAP_CMD_REJ:
256b06ebda0SMatthew Dillon 		case NG_L2CAP_DISCON_RSP:
257b06ebda0SMatthew Dillon 		case NG_L2CAP_ECHO_RSP:
258b06ebda0SMatthew Dillon 		case NG_L2CAP_INFO_RSP:
259b06ebda0SMatthew Dillon 			break;
260b06ebda0SMatthew Dillon 
261b06ebda0SMatthew Dillon 		case NG_L2CAP_CON_REQ:
262b06ebda0SMatthew Dillon 			ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, result, 0);
263b06ebda0SMatthew Dillon 			break;
264b06ebda0SMatthew Dillon 
265b06ebda0SMatthew Dillon 		case NG_L2CAP_CON_RSP:
266b06ebda0SMatthew Dillon 			if (cmd->ch != NULL)
267b06ebda0SMatthew Dillon 				ng_l2cap_l2ca_con_rsp_rsp(cmd->ch, cmd->token,
268b06ebda0SMatthew Dillon 					result);
269b06ebda0SMatthew Dillon 			break;
270b06ebda0SMatthew Dillon 
271b06ebda0SMatthew Dillon 		case NG_L2CAP_CFG_REQ:
272b06ebda0SMatthew Dillon 		case NG_L2CAP_CFG_RSP:
273b06ebda0SMatthew Dillon 		case NGM_L2CAP_L2CA_WRITE:
274b06ebda0SMatthew Dillon 			ng_l2cap_l2ca_discon_ind(cmd->ch);
275b06ebda0SMatthew Dillon 			break;
276b06ebda0SMatthew Dillon 
277b06ebda0SMatthew Dillon 		case NG_L2CAP_DISCON_REQ:
278b06ebda0SMatthew Dillon 			ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token,
279b06ebda0SMatthew Dillon 				NG_L2CAP_SUCCESS);
280b06ebda0SMatthew Dillon 			break;
281b06ebda0SMatthew Dillon 
282b06ebda0SMatthew Dillon 		case NG_L2CAP_ECHO_REQ:
283b06ebda0SMatthew Dillon 			ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
284b06ebda0SMatthew Dillon 				result, NULL);
285b06ebda0SMatthew Dillon 			break;
286b06ebda0SMatthew Dillon 
287b06ebda0SMatthew Dillon 		case NG_L2CAP_INFO_REQ:
288b06ebda0SMatthew Dillon 			ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
289b06ebda0SMatthew Dillon 				result, NULL);
290b06ebda0SMatthew Dillon 			break;
291b06ebda0SMatthew Dillon 
292b06ebda0SMatthew Dillon 		/* XXX FIXME add other commands */
293b06ebda0SMatthew Dillon 
294b06ebda0SMatthew Dillon 		default:
295b06ebda0SMatthew Dillon 			panic(
296b06ebda0SMatthew Dillon "%s: %s - unexpected command code=%d\n",
297b06ebda0SMatthew Dillon 				__func__, NG_NODE_NAME(l2cap->node), cmd->code);
298b06ebda0SMatthew Dillon 			break;
299b06ebda0SMatthew Dillon 		}
300b06ebda0SMatthew Dillon 
301b06ebda0SMatthew Dillon 		if (cmd->ch != NULL)
302b06ebda0SMatthew Dillon 			ng_l2cap_free_chan(cmd->ch);
303b06ebda0SMatthew Dillon 
304b06ebda0SMatthew Dillon 		ng_l2cap_free_cmd(cmd);
305b06ebda0SMatthew Dillon 	}
306b06ebda0SMatthew Dillon 
307b06ebda0SMatthew Dillon 	/*
308b06ebda0SMatthew Dillon 	 * There still might be channels (in OPEN state?) that
309b06ebda0SMatthew Dillon 	 * did not submit any commands, so diconnect them
310b06ebda0SMatthew Dillon 	 */
311b06ebda0SMatthew Dillon 
312b06ebda0SMatthew Dillon 	LIST_FOREACH(ch, &l2cap->chan_list, next)
313b06ebda0SMatthew Dillon 		if (ch->con == con)
314b06ebda0SMatthew Dillon 			ng_l2cap_l2ca_discon_ind(ch);
315b06ebda0SMatthew Dillon 
316b06ebda0SMatthew Dillon 	/* Free connection descriptor */
317b06ebda0SMatthew Dillon 	ng_l2cap_free_con(con);
318b06ebda0SMatthew Dillon } /* ng_l2cap_con_fail */
319b06ebda0SMatthew Dillon 
320b06ebda0SMatthew Dillon /*
321b06ebda0SMatthew Dillon  * Process L2CAP command timeout. In general - notify upper layer and destroy
322b06ebda0SMatthew Dillon  * channel. Do not pay much attension to return code, just do our best.
323b06ebda0SMatthew Dillon  */
324b06ebda0SMatthew Dillon 
325b06ebda0SMatthew Dillon void
ng_l2cap_process_command_timeout(node_p node,hook_p hook,void * arg1,int arg2)326b06ebda0SMatthew Dillon ng_l2cap_process_command_timeout(node_p node, hook_p hook, void *arg1, int arg2)
327b06ebda0SMatthew Dillon {
328b06ebda0SMatthew Dillon 	ng_l2cap_p	l2cap = NULL;
329b06ebda0SMatthew Dillon 	ng_l2cap_con_p	con = NULL;
330b06ebda0SMatthew Dillon 	ng_l2cap_cmd_p	cmd = NULL;
331b06ebda0SMatthew Dillon 	u_int16_t	con_handle = (arg2 & 0x0ffff);
332b06ebda0SMatthew Dillon 	u_int8_t	ident = ((arg2 >> 16) & 0xff);
333b06ebda0SMatthew Dillon 
334b06ebda0SMatthew Dillon 	if (NG_NODE_NOT_VALID(node)) {
335a62226e4SSascha Wildner 		kprintf("%s: Netgraph node is not valid\n", __func__);
336b06ebda0SMatthew Dillon 		return;
337b06ebda0SMatthew Dillon 	}
338b06ebda0SMatthew Dillon 
339b06ebda0SMatthew Dillon 	l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
340b06ebda0SMatthew Dillon 
341b06ebda0SMatthew Dillon 	con = ng_l2cap_con_by_handle(l2cap, con_handle);
342b06ebda0SMatthew Dillon 	if (con == NULL) {
343b06ebda0SMatthew Dillon 		NG_L2CAP_ALERT(
344b06ebda0SMatthew Dillon "%s: %s - could not find connection, con_handle=%d\n",
345b06ebda0SMatthew Dillon 			__func__, NG_NODE_NAME(node), con_handle);
346b06ebda0SMatthew Dillon 		return;
347b06ebda0SMatthew Dillon 	}
348b06ebda0SMatthew Dillon 
349b06ebda0SMatthew Dillon 	cmd = ng_l2cap_cmd_by_ident(con, ident);
350b06ebda0SMatthew Dillon 	if (cmd == NULL) {
351b06ebda0SMatthew Dillon 		NG_L2CAP_ALERT(
352b06ebda0SMatthew Dillon "%s: %s - could not find command, con_handle=%d, ident=%d\n",
353b06ebda0SMatthew Dillon 			__func__, NG_NODE_NAME(node), con_handle, ident);
354b06ebda0SMatthew Dillon 		return;
355b06ebda0SMatthew Dillon 	}
356b06ebda0SMatthew Dillon 
357b06ebda0SMatthew Dillon 	cmd->flags &= ~NG_L2CAP_CMD_PENDING;
358b06ebda0SMatthew Dillon 	ng_l2cap_unlink_cmd(cmd);
359b06ebda0SMatthew Dillon 
360b06ebda0SMatthew Dillon 	switch (cmd->code) {
361b06ebda0SMatthew Dillon  	case NG_L2CAP_CON_REQ:
362b06ebda0SMatthew Dillon 		ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT, 0);
363b06ebda0SMatthew Dillon 		ng_l2cap_free_chan(cmd->ch);
364b06ebda0SMatthew Dillon 		break;
365b06ebda0SMatthew Dillon 
366b06ebda0SMatthew Dillon 	case NG_L2CAP_CFG_REQ:
367b06ebda0SMatthew Dillon 		ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT);
368b06ebda0SMatthew Dillon 		break;
369b06ebda0SMatthew Dillon 
370b06ebda0SMatthew Dillon  	case NG_L2CAP_DISCON_REQ:
371b06ebda0SMatthew Dillon 		ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token, NG_L2CAP_TIMEOUT);
372b06ebda0SMatthew Dillon 		ng_l2cap_free_chan(cmd->ch); /* XXX free channel */
373b06ebda0SMatthew Dillon 		break;
374b06ebda0SMatthew Dillon 
375b06ebda0SMatthew Dillon 	case NG_L2CAP_ECHO_REQ:
376b06ebda0SMatthew Dillon 		/* Echo request timed out. Let the upper layer know */
377b06ebda0SMatthew Dillon 		ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
378b06ebda0SMatthew Dillon 			NG_L2CAP_TIMEOUT, NULL);
379b06ebda0SMatthew Dillon 		break;
380b06ebda0SMatthew Dillon 
381b06ebda0SMatthew Dillon 	case NG_L2CAP_INFO_REQ:
382b06ebda0SMatthew Dillon 		/* Info request timed out. Let the upper layer know */
383b06ebda0SMatthew Dillon 		ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
384b06ebda0SMatthew Dillon 			NG_L2CAP_TIMEOUT, NULL);
385b06ebda0SMatthew Dillon 		break;
386b06ebda0SMatthew Dillon 
387b06ebda0SMatthew Dillon 	/* XXX FIXME add other commands */
388b06ebda0SMatthew Dillon 
389b06ebda0SMatthew Dillon 	default:
390b06ebda0SMatthew Dillon 		panic(
391b06ebda0SMatthew Dillon "%s: %s - unexpected command code=%d\n",
392b06ebda0SMatthew Dillon 			__func__, NG_NODE_NAME(l2cap->node), cmd->code);
393b06ebda0SMatthew Dillon 		break;
394b06ebda0SMatthew Dillon 	}
395b06ebda0SMatthew Dillon 
396b06ebda0SMatthew Dillon 	ng_l2cap_free_cmd(cmd);
397b06ebda0SMatthew Dillon } /* ng_l2cap_process_command_timeout */
398b06ebda0SMatthew Dillon 
399