1b06ebda0SMatthew Dillon /*
2b06ebda0SMatthew Dillon  * ng_l2cap_misc.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_misc.c,v 1.5 2003/09/08 19:11:45 max Exp $
31b06ebda0SMatthew Dillon  * $FreeBSD: src/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.c,v 1.12 2005/08/31 18:13:23 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/malloc.h>
38b06ebda0SMatthew Dillon #include <sys/mbuf.h>
39b06ebda0SMatthew Dillon #include <sys/queue.h>
40e85b99abSSascha Wildner #include <netgraph7/ng_message.h>
41e85b99abSSascha Wildner #include <netgraph7/netgraph.h>
42e85b99abSSascha Wildner #include <netgraph7/bluetooth/include/ng_bluetooth.h>
43e85b99abSSascha Wildner #include <netgraph7/bluetooth/include/ng_hci.h>
44e85b99abSSascha Wildner #include <netgraph7/bluetooth/include/ng_l2cap.h>
45e85b99abSSascha Wildner #include <netgraph7/bluetooth/l2cap/ng_l2cap_var.h>
46e85b99abSSascha Wildner #include <netgraph7/bluetooth/l2cap/ng_l2cap_cmds.h>
47e85b99abSSascha Wildner #include <netgraph7/bluetooth/l2cap/ng_l2cap_evnt.h>
48e85b99abSSascha Wildner #include <netgraph7/bluetooth/l2cap/ng_l2cap_llpi.h>
49e85b99abSSascha Wildner #include <netgraph7/bluetooth/l2cap/ng_l2cap_ulpi.h>
50e85b99abSSascha Wildner #include <netgraph7/bluetooth/l2cap/ng_l2cap_misc.h>
51b06ebda0SMatthew Dillon 
52b06ebda0SMatthew Dillon static u_int16_t	ng_l2cap_get_cid	(ng_l2cap_p);
53b06ebda0SMatthew Dillon 
54b06ebda0SMatthew Dillon /******************************************************************************
55b06ebda0SMatthew Dillon  ******************************************************************************
56b06ebda0SMatthew Dillon  **                              Utility routines
57b06ebda0SMatthew Dillon  ******************************************************************************
58b06ebda0SMatthew Dillon  ******************************************************************************/
59b06ebda0SMatthew Dillon 
60b06ebda0SMatthew Dillon /*
61b06ebda0SMatthew Dillon  * Send hook information to the upper layer
62b06ebda0SMatthew Dillon  */
63b06ebda0SMatthew Dillon 
64b06ebda0SMatthew Dillon void
ng_l2cap_send_hook_info(node_p node,hook_p hook,void * arg1,int arg2)65b06ebda0SMatthew Dillon ng_l2cap_send_hook_info(node_p node, hook_p hook, void *arg1, int arg2)
66b06ebda0SMatthew Dillon {
67b06ebda0SMatthew Dillon 	ng_l2cap_p	 l2cap = NULL;
68b06ebda0SMatthew Dillon 	struct ng_mesg	*msg = NULL;
69b06ebda0SMatthew Dillon 	int		 error = 0;
70b06ebda0SMatthew Dillon 
71b06ebda0SMatthew Dillon 	if (node == NULL || NG_NODE_NOT_VALID(node) ||
72b06ebda0SMatthew Dillon 	    hook == NULL || NG_HOOK_NOT_VALID(hook))
73b06ebda0SMatthew Dillon 		return;
74b06ebda0SMatthew Dillon 
75b06ebda0SMatthew Dillon 	l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
76b06ebda0SMatthew Dillon 	if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci) ||
77b06ebda0SMatthew Dillon 	    bcmp(&l2cap->bdaddr, NG_HCI_BDADDR_ANY, sizeof(l2cap->bdaddr)) == 0)
78b06ebda0SMatthew Dillon 		return;
79b06ebda0SMatthew Dillon 
80b06ebda0SMatthew Dillon 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_HOOK_INFO,
815a975a3dSMatthew Dillon 		sizeof(bdaddr_t), M_WAITOK | M_NULLOK);
82b06ebda0SMatthew Dillon 	if (msg != NULL) {
83b06ebda0SMatthew Dillon 		bcopy(&l2cap->bdaddr, msg->data, sizeof(bdaddr_t));
84b06ebda0SMatthew Dillon 		NG_SEND_MSG_HOOK(error, node, msg, hook, 0);
85b06ebda0SMatthew Dillon 	} else
86b06ebda0SMatthew Dillon 		error = ENOMEM;
87b06ebda0SMatthew Dillon 
88b06ebda0SMatthew Dillon 	if (error != 0)
89b06ebda0SMatthew Dillon 		NG_L2CAP_INFO(
90b06ebda0SMatthew Dillon "%s: %s - failed to send HOOK_INFO message to hook \"%s\", error=%d\n",
91b06ebda0SMatthew Dillon 			__func__, NG_NODE_NAME(l2cap->node), NG_HOOK_NAME(hook),
92b06ebda0SMatthew Dillon 			error);
93b06ebda0SMatthew Dillon } /* ng_l2cap_send_hook_info */
94b06ebda0SMatthew Dillon 
95b06ebda0SMatthew Dillon /*
96b06ebda0SMatthew Dillon  * Create new connection descriptor for the "remote" unit.
97b06ebda0SMatthew Dillon  * Will link connection descriptor to the l2cap node.
98b06ebda0SMatthew Dillon  */
99b06ebda0SMatthew Dillon 
100b06ebda0SMatthew Dillon ng_l2cap_con_p
ng_l2cap_new_con(ng_l2cap_p l2cap,bdaddr_p bdaddr)101b06ebda0SMatthew Dillon ng_l2cap_new_con(ng_l2cap_p l2cap, bdaddr_p bdaddr)
102b06ebda0SMatthew Dillon {
103b06ebda0SMatthew Dillon 	static int	fake_con_handle = 0x0f00;
104b06ebda0SMatthew Dillon 	ng_l2cap_con_p	con = NULL;
105b06ebda0SMatthew Dillon 
106b06ebda0SMatthew Dillon 	/* Create new connection descriptor */
107fc025606SSascha Wildner 	con = kmalloc(sizeof(*con), M_NETGRAPH_L2CAP,
1085a975a3dSMatthew Dillon 		      M_WAITOK | M_NULLOK | M_ZERO);
109b06ebda0SMatthew Dillon 	if (con == NULL)
110b06ebda0SMatthew Dillon 		return (NULL);
111b06ebda0SMatthew Dillon 
112b06ebda0SMatthew Dillon 	con->l2cap = l2cap;
113b06ebda0SMatthew Dillon 	con->state = NG_L2CAP_CON_CLOSED;
114b06ebda0SMatthew Dillon 
115b06ebda0SMatthew Dillon 	/*
116b06ebda0SMatthew Dillon 	 * XXX
117b06ebda0SMatthew Dillon 	 *
118b06ebda0SMatthew Dillon 	 * Assign fake connection handle to the connection descriptor.
119b06ebda0SMatthew Dillon 	 * Bluetooth specification marks 0x0f00 - 0x0fff connection
120b06ebda0SMatthew Dillon 	 * handles as reserved. We need this fake connection handles
121b06ebda0SMatthew Dillon 	 * for timeouts. Connection handle will be passed as argument
122b06ebda0SMatthew Dillon 	 * to timeout so when timeout happens we can find the right
123b06ebda0SMatthew Dillon 	 * connection descriptor. We can not pass pointers, because
124b06ebda0SMatthew Dillon 	 * timeouts are external (to Netgraph) events and there might
125b06ebda0SMatthew Dillon 	 * be a race when node/hook goes down and timeout event already
126b06ebda0SMatthew Dillon 	 * went into node's queue
127b06ebda0SMatthew Dillon 	 */
128b06ebda0SMatthew Dillon 
129b06ebda0SMatthew Dillon 	con->con_handle = fake_con_handle ++;
130b06ebda0SMatthew Dillon 	if (fake_con_handle > 0x0fff)
131b06ebda0SMatthew Dillon 		fake_con_handle = 0x0f00;
132b06ebda0SMatthew Dillon 
133b06ebda0SMatthew Dillon 	bcopy(bdaddr, &con->remote, sizeof(con->remote));
134b06ebda0SMatthew Dillon 	ng_callout_init(&con->con_timo);
135b06ebda0SMatthew Dillon 
136b06ebda0SMatthew Dillon 	con->ident = NG_L2CAP_FIRST_IDENT - 1;
137b06ebda0SMatthew Dillon 	TAILQ_INIT(&con->cmd_list);
138b06ebda0SMatthew Dillon 
139b06ebda0SMatthew Dillon 	/* Link connection */
140b06ebda0SMatthew Dillon 	LIST_INSERT_HEAD(&l2cap->con_list, con, next);
141b06ebda0SMatthew Dillon 
142b06ebda0SMatthew Dillon 	return (con);
143b06ebda0SMatthew Dillon } /* ng_l2cap_new_con */
144b06ebda0SMatthew Dillon 
145b06ebda0SMatthew Dillon /*
146b06ebda0SMatthew Dillon  * Add reference to the connection descriptor
147b06ebda0SMatthew Dillon  */
148b06ebda0SMatthew Dillon 
149b06ebda0SMatthew Dillon void
ng_l2cap_con_ref(ng_l2cap_con_p con)150b06ebda0SMatthew Dillon ng_l2cap_con_ref(ng_l2cap_con_p con)
151b06ebda0SMatthew Dillon {
152b06ebda0SMatthew Dillon 	con->refcnt ++;
153b06ebda0SMatthew Dillon 
154b06ebda0SMatthew Dillon 	if (con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO) {
155b06ebda0SMatthew Dillon 		if ((con->state != NG_L2CAP_CON_OPEN) ||
156b06ebda0SMatthew Dillon 		    (con->flags & NG_L2CAP_CON_OUTGOING) == 0)
157b06ebda0SMatthew Dillon 			panic(
158b06ebda0SMatthew Dillon "%s: %s - bad auto disconnect timeout, state=%d, flags=%#x\n",
159b06ebda0SMatthew Dillon 				__func__, NG_NODE_NAME(con->l2cap->node),
160b06ebda0SMatthew Dillon 				con->state, con->flags);
161b06ebda0SMatthew Dillon 
162b06ebda0SMatthew Dillon 		ng_l2cap_discon_untimeout(con);
163b06ebda0SMatthew Dillon 	}
164b06ebda0SMatthew Dillon } /* ng_l2cap_con_ref */
165b06ebda0SMatthew Dillon 
166b06ebda0SMatthew Dillon /*
167b06ebda0SMatthew Dillon  * Remove reference from the connection descriptor
168b06ebda0SMatthew Dillon  */
169b06ebda0SMatthew Dillon 
170b06ebda0SMatthew Dillon void
ng_l2cap_con_unref(ng_l2cap_con_p con)171b06ebda0SMatthew Dillon ng_l2cap_con_unref(ng_l2cap_con_p con)
172b06ebda0SMatthew Dillon {
173b06ebda0SMatthew Dillon 	con->refcnt --;
174b06ebda0SMatthew Dillon 
175b06ebda0SMatthew Dillon 	if (con->refcnt < 0)
176b06ebda0SMatthew Dillon 		panic(
177b06ebda0SMatthew Dillon "%s: %s - con->refcnt < 0\n", __func__, NG_NODE_NAME(con->l2cap->node));
178b06ebda0SMatthew Dillon 
179b06ebda0SMatthew Dillon 	/*
180b06ebda0SMatthew Dillon 	 * Set auto disconnect timer only if the following conditions are met:
181b06ebda0SMatthew Dillon 	 * 1) we have no reference on the connection
182b06ebda0SMatthew Dillon 	 * 2) connection is in OPEN state
183b06ebda0SMatthew Dillon 	 * 3) it is an outgoing connection
184b06ebda0SMatthew Dillon 	 * 4) disconnect timeout > 0
185b06ebda0SMatthew Dillon 	 * 5) connection is not dying
186b06ebda0SMatthew Dillon 	 */
187b06ebda0SMatthew Dillon 
188b06ebda0SMatthew Dillon 	if ((con->refcnt == 0) &&
189b06ebda0SMatthew Dillon 	    (con->state == NG_L2CAP_CON_OPEN) &&
190b06ebda0SMatthew Dillon 	    (con->flags & NG_L2CAP_CON_OUTGOING) &&
191b06ebda0SMatthew Dillon 	    (con->l2cap->discon_timo > 0) &&
192b06ebda0SMatthew Dillon 	    ((con->flags & NG_L2CAP_CON_DYING) == 0))
193b06ebda0SMatthew Dillon 		ng_l2cap_discon_timeout(con);
194b06ebda0SMatthew Dillon } /* ng_l2cap_con_unref */
195b06ebda0SMatthew Dillon 
196b06ebda0SMatthew Dillon /*
197b06ebda0SMatthew Dillon  * Set auto disconnect timeout
198b06ebda0SMatthew Dillon  * XXX FIXME: check return code from ng_callout
199b06ebda0SMatthew Dillon  */
200b06ebda0SMatthew Dillon 
201b06ebda0SMatthew Dillon int
ng_l2cap_discon_timeout(ng_l2cap_con_p con)202b06ebda0SMatthew Dillon ng_l2cap_discon_timeout(ng_l2cap_con_p con)
203b06ebda0SMatthew Dillon {
204b06ebda0SMatthew Dillon 	if (con->flags & (NG_L2CAP_CON_LP_TIMO|NG_L2CAP_CON_AUTO_DISCON_TIMO))
205b06ebda0SMatthew Dillon 		panic(
206b06ebda0SMatthew Dillon "%s: %s - invalid timeout, state=%d, flags=%#x\n",
207b06ebda0SMatthew Dillon 			__func__, NG_NODE_NAME(con->l2cap->node),
208b06ebda0SMatthew Dillon 			con->state, con->flags);
209b06ebda0SMatthew Dillon 
210b06ebda0SMatthew Dillon 	con->flags |= NG_L2CAP_CON_AUTO_DISCON_TIMO;
211b06ebda0SMatthew Dillon 	ng_callout(&con->con_timo, con->l2cap->node, NULL,
212b06ebda0SMatthew Dillon 				con->l2cap->discon_timo * hz,
213b06ebda0SMatthew Dillon 				ng_l2cap_process_discon_timeout, NULL,
214b06ebda0SMatthew Dillon 				con->con_handle);
215b06ebda0SMatthew Dillon 
216b06ebda0SMatthew Dillon 	return (0);
217b06ebda0SMatthew Dillon } /* ng_l2cap_discon_timeout */
218b06ebda0SMatthew Dillon 
219b06ebda0SMatthew Dillon /*
220b06ebda0SMatthew Dillon  * Unset auto disconnect timeout
221b06ebda0SMatthew Dillon  */
222b06ebda0SMatthew Dillon 
223b06ebda0SMatthew Dillon int
ng_l2cap_discon_untimeout(ng_l2cap_con_p con)224b06ebda0SMatthew Dillon ng_l2cap_discon_untimeout(ng_l2cap_con_p con)
225b06ebda0SMatthew Dillon {
226b06ebda0SMatthew Dillon 	if (!(con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO))
227b06ebda0SMatthew Dillon 		panic(
228b06ebda0SMatthew Dillon "%s: %s - no disconnect timeout, state=%d, flags=%#x\n",
229b06ebda0SMatthew Dillon 			__func__,  NG_NODE_NAME(con->l2cap->node),
230b06ebda0SMatthew Dillon 			con->state, con->flags);
231b06ebda0SMatthew Dillon 
232b06ebda0SMatthew Dillon 	if (ng_uncallout(&con->con_timo, con->l2cap->node) == 0)
233b06ebda0SMatthew Dillon 		return (ETIMEDOUT);
234b06ebda0SMatthew Dillon 
235b06ebda0SMatthew Dillon 	con->flags &= ~NG_L2CAP_CON_AUTO_DISCON_TIMO;
236b06ebda0SMatthew Dillon 
237b06ebda0SMatthew Dillon 	return (0);
238b06ebda0SMatthew Dillon } /* ng_l2cap_discon_untimeout */
239b06ebda0SMatthew Dillon 
240b06ebda0SMatthew Dillon /*
241b06ebda0SMatthew Dillon  * Free connection descriptor. Will unlink connection and free everything.
242b06ebda0SMatthew Dillon  */
243b06ebda0SMatthew Dillon 
244b06ebda0SMatthew Dillon void
ng_l2cap_free_con(ng_l2cap_con_p con)245b06ebda0SMatthew Dillon ng_l2cap_free_con(ng_l2cap_con_p con)
246b06ebda0SMatthew Dillon {
247b06ebda0SMatthew Dillon 	ng_l2cap_chan_p f = NULL, n = NULL;
248b06ebda0SMatthew Dillon 
249b06ebda0SMatthew Dillon 	con->state = NG_L2CAP_CON_CLOSED;
250b06ebda0SMatthew Dillon 
251b06ebda0SMatthew Dillon 	while (con->tx_pkt != NULL) {
252b06ebda0SMatthew Dillon 		struct mbuf	*m = con->tx_pkt->m_nextpkt;
253b06ebda0SMatthew Dillon 
254b06ebda0SMatthew Dillon 		m_freem(con->tx_pkt);
255b06ebda0SMatthew Dillon 		con->tx_pkt = m;
256b06ebda0SMatthew Dillon 	}
257b06ebda0SMatthew Dillon 
258b06ebda0SMatthew Dillon 	NG_FREE_M(con->rx_pkt);
259b06ebda0SMatthew Dillon 
260b06ebda0SMatthew Dillon 	for (f = LIST_FIRST(&con->l2cap->chan_list); f != NULL; ) {
261b06ebda0SMatthew Dillon 		n = LIST_NEXT(f, next);
262b06ebda0SMatthew Dillon 
263b06ebda0SMatthew Dillon 		if (f->con == con)
264b06ebda0SMatthew Dillon 			ng_l2cap_free_chan(f);
265b06ebda0SMatthew Dillon 
266b06ebda0SMatthew Dillon 		f = n;
267b06ebda0SMatthew Dillon 	}
268b06ebda0SMatthew Dillon 
269b06ebda0SMatthew Dillon 	while (!TAILQ_EMPTY(&con->cmd_list)) {
270b06ebda0SMatthew Dillon 		ng_l2cap_cmd_p	cmd = TAILQ_FIRST(&con->cmd_list);
271b06ebda0SMatthew Dillon 
272b06ebda0SMatthew Dillon 		ng_l2cap_unlink_cmd(cmd);
273b06ebda0SMatthew Dillon 		if (cmd->flags & NG_L2CAP_CMD_PENDING)
274b06ebda0SMatthew Dillon 			ng_l2cap_command_untimeout(cmd);
275b06ebda0SMatthew Dillon 		ng_l2cap_free_cmd(cmd);
276b06ebda0SMatthew Dillon 	}
277b06ebda0SMatthew Dillon 
278b06ebda0SMatthew Dillon 	if (con->flags & (NG_L2CAP_CON_AUTO_DISCON_TIMO|NG_L2CAP_CON_LP_TIMO))
279b06ebda0SMatthew Dillon 		panic(
280b06ebda0SMatthew Dillon "%s: %s - timeout pending! state=%d, flags=%#x\n",
281b06ebda0SMatthew Dillon 			__func__,  NG_NODE_NAME(con->l2cap->node),
282b06ebda0SMatthew Dillon 			con->state, con->flags);
283b06ebda0SMatthew Dillon 
284b06ebda0SMatthew Dillon 	LIST_REMOVE(con, next);
285b06ebda0SMatthew Dillon 
286b06ebda0SMatthew Dillon 	bzero(con, sizeof(*con));
287fc025606SSascha Wildner 	kfree(con, M_NETGRAPH_L2CAP);
288b06ebda0SMatthew Dillon } /* ng_l2cap_free_con */
289b06ebda0SMatthew Dillon 
290b06ebda0SMatthew Dillon /*
291b06ebda0SMatthew Dillon  * Get connection by "remote" address
292b06ebda0SMatthew Dillon  */
293b06ebda0SMatthew Dillon 
294b06ebda0SMatthew Dillon ng_l2cap_con_p
ng_l2cap_con_by_addr(ng_l2cap_p l2cap,bdaddr_p bdaddr)295b06ebda0SMatthew Dillon ng_l2cap_con_by_addr(ng_l2cap_p l2cap, bdaddr_p bdaddr)
296b06ebda0SMatthew Dillon {
297b06ebda0SMatthew Dillon 	ng_l2cap_con_p	con = NULL;
298b06ebda0SMatthew Dillon 
299b06ebda0SMatthew Dillon 	LIST_FOREACH(con, &l2cap->con_list, next)
300b06ebda0SMatthew Dillon 		if (bcmp(bdaddr, &con->remote, sizeof(con->remote)) == 0)
301b06ebda0SMatthew Dillon 			break;
302b06ebda0SMatthew Dillon 
303b06ebda0SMatthew Dillon 	return (con);
304b06ebda0SMatthew Dillon } /* ng_l2cap_con_by_addr */
305b06ebda0SMatthew Dillon 
306b06ebda0SMatthew Dillon /*
307b06ebda0SMatthew Dillon  * Get connection by "handle"
308b06ebda0SMatthew Dillon  */
309b06ebda0SMatthew Dillon 
310b06ebda0SMatthew Dillon ng_l2cap_con_p
ng_l2cap_con_by_handle(ng_l2cap_p l2cap,u_int16_t con_handle)311b06ebda0SMatthew Dillon ng_l2cap_con_by_handle(ng_l2cap_p l2cap, u_int16_t con_handle)
312b06ebda0SMatthew Dillon {
313b06ebda0SMatthew Dillon 	ng_l2cap_con_p	con = NULL;
314b06ebda0SMatthew Dillon 
315b06ebda0SMatthew Dillon 	LIST_FOREACH(con, &l2cap->con_list, next)
316b06ebda0SMatthew Dillon 		if (con->con_handle == con_handle)
317b06ebda0SMatthew Dillon 			break;
318b06ebda0SMatthew Dillon 
319b06ebda0SMatthew Dillon 	return (con);
320b06ebda0SMatthew Dillon } /* ng_l2cap_con_by_handle */
321b06ebda0SMatthew Dillon 
322b06ebda0SMatthew Dillon /*
323b06ebda0SMatthew Dillon  * Allocate new L2CAP channel descriptor on "con" conection with "psm".
324b06ebda0SMatthew Dillon  * Will link the channel to the l2cap node
325b06ebda0SMatthew Dillon  */
326b06ebda0SMatthew Dillon 
327b06ebda0SMatthew Dillon ng_l2cap_chan_p
ng_l2cap_new_chan(ng_l2cap_p l2cap,ng_l2cap_con_p con,u_int16_t psm)328b06ebda0SMatthew Dillon ng_l2cap_new_chan(ng_l2cap_p l2cap, ng_l2cap_con_p con, u_int16_t psm)
329b06ebda0SMatthew Dillon {
330b06ebda0SMatthew Dillon 	ng_l2cap_chan_p	ch = NULL;
331b06ebda0SMatthew Dillon 
332fc025606SSascha Wildner 	ch = kmalloc(sizeof(*ch), M_NETGRAPH_L2CAP,
3335a975a3dSMatthew Dillon 		     M_WAITOK | M_NULLOK | M_ZERO);
334b06ebda0SMatthew Dillon 	if (ch == NULL)
335b06ebda0SMatthew Dillon 		return (NULL);
336b06ebda0SMatthew Dillon 
337b06ebda0SMatthew Dillon 	ch->scid = ng_l2cap_get_cid(l2cap);
338b06ebda0SMatthew Dillon 
339b06ebda0SMatthew Dillon 	if (ch->scid != NG_L2CAP_NULL_CID) {
340b06ebda0SMatthew Dillon 		/* Initialize channel */
341b06ebda0SMatthew Dillon 		ch->psm = psm;
342b06ebda0SMatthew Dillon 		ch->con = con;
343b06ebda0SMatthew Dillon 		ch->state = NG_L2CAP_CLOSED;
344b06ebda0SMatthew Dillon 
345b06ebda0SMatthew Dillon 		/* Set MTU and flow control settings to defaults */
346b06ebda0SMatthew Dillon 		ch->imtu = NG_L2CAP_MTU_DEFAULT;
347b06ebda0SMatthew Dillon 		bcopy(ng_l2cap_default_flow(), &ch->iflow, sizeof(ch->iflow));
348b06ebda0SMatthew Dillon 
349b06ebda0SMatthew Dillon 		ch->omtu = NG_L2CAP_MTU_DEFAULT;
350b06ebda0SMatthew Dillon 		bcopy(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow));
351b06ebda0SMatthew Dillon 
352b06ebda0SMatthew Dillon 		ch->flush_timo = NG_L2CAP_FLUSH_TIMO_DEFAULT;
353b06ebda0SMatthew Dillon 		ch->link_timo = NG_L2CAP_LINK_TIMO_DEFAULT;
354b06ebda0SMatthew Dillon 
355b06ebda0SMatthew Dillon 		LIST_INSERT_HEAD(&l2cap->chan_list, ch, next);
356b06ebda0SMatthew Dillon 
357b06ebda0SMatthew Dillon 		ng_l2cap_con_ref(con);
358b06ebda0SMatthew Dillon 	} else {
359b06ebda0SMatthew Dillon 		bzero(ch, sizeof(*ch));
360fc025606SSascha Wildner 		kfree(ch, M_NETGRAPH_L2CAP);
361b06ebda0SMatthew Dillon 		ch = NULL;
362b06ebda0SMatthew Dillon 	}
363b06ebda0SMatthew Dillon 
364b06ebda0SMatthew Dillon 	return (ch);
365b06ebda0SMatthew Dillon } /* ng_l2cap_new_chan */
366b06ebda0SMatthew Dillon 
367b06ebda0SMatthew Dillon /*
368b06ebda0SMatthew Dillon  * Get channel by source (local) channel ID
369b06ebda0SMatthew Dillon  */
370b06ebda0SMatthew Dillon 
371b06ebda0SMatthew Dillon ng_l2cap_chan_p
ng_l2cap_chan_by_scid(ng_l2cap_p l2cap,u_int16_t scid)372b06ebda0SMatthew Dillon ng_l2cap_chan_by_scid(ng_l2cap_p l2cap, u_int16_t scid)
373b06ebda0SMatthew Dillon {
374b06ebda0SMatthew Dillon 	ng_l2cap_chan_p	ch = NULL;
375b06ebda0SMatthew Dillon 
376b06ebda0SMatthew Dillon 	LIST_FOREACH(ch, &l2cap->chan_list, next)
377b06ebda0SMatthew Dillon 		if (ch->scid == scid)
378b06ebda0SMatthew Dillon 			break;
379b06ebda0SMatthew Dillon 
380b06ebda0SMatthew Dillon 	return (ch);
381b06ebda0SMatthew Dillon } /* ng_l2cap_chan_by_scid */
382b06ebda0SMatthew Dillon 
383b06ebda0SMatthew Dillon /*
384b06ebda0SMatthew Dillon  * Free channel descriptor.
385b06ebda0SMatthew Dillon  */
386b06ebda0SMatthew Dillon 
387b06ebda0SMatthew Dillon void
ng_l2cap_free_chan(ng_l2cap_chan_p ch)388b06ebda0SMatthew Dillon ng_l2cap_free_chan(ng_l2cap_chan_p ch)
389b06ebda0SMatthew Dillon {
390b06ebda0SMatthew Dillon 	ng_l2cap_cmd_p	f = NULL, n = NULL;
391b06ebda0SMatthew Dillon 
392b06ebda0SMatthew Dillon 	f = TAILQ_FIRST(&ch->con->cmd_list);
393b06ebda0SMatthew Dillon 	while (f != NULL) {
394b06ebda0SMatthew Dillon 		n = TAILQ_NEXT(f, next);
395b06ebda0SMatthew Dillon 
396b06ebda0SMatthew Dillon 		if (f->ch == ch) {
397b06ebda0SMatthew Dillon 			ng_l2cap_unlink_cmd(f);
398b06ebda0SMatthew Dillon 			if (f->flags & NG_L2CAP_CMD_PENDING)
399b06ebda0SMatthew Dillon 				ng_l2cap_command_untimeout(f);
400b06ebda0SMatthew Dillon 			ng_l2cap_free_cmd(f);
401b06ebda0SMatthew Dillon 		}
402b06ebda0SMatthew Dillon 
403b06ebda0SMatthew Dillon 		f = n;
404b06ebda0SMatthew Dillon 	}
405b06ebda0SMatthew Dillon 
406b06ebda0SMatthew Dillon 	LIST_REMOVE(ch, next);
407b06ebda0SMatthew Dillon 
408b06ebda0SMatthew Dillon 	ng_l2cap_con_unref(ch->con);
409b06ebda0SMatthew Dillon 
410b06ebda0SMatthew Dillon 	bzero(ch, sizeof(*ch));
411fc025606SSascha Wildner 	kfree(ch, M_NETGRAPH_L2CAP);
412b06ebda0SMatthew Dillon } /* ng_l2cap_free_chan */
413b06ebda0SMatthew Dillon 
414b06ebda0SMatthew Dillon /*
415b06ebda0SMatthew Dillon  * Create new L2CAP command descriptor. WILL NOT add command to the queue.
416b06ebda0SMatthew Dillon  */
417b06ebda0SMatthew Dillon 
418b06ebda0SMatthew Dillon ng_l2cap_cmd_p
ng_l2cap_new_cmd(ng_l2cap_con_p con,ng_l2cap_chan_p ch,u_int8_t ident,u_int8_t code,u_int32_t token)419b06ebda0SMatthew Dillon ng_l2cap_new_cmd(ng_l2cap_con_p con, ng_l2cap_chan_p ch, u_int8_t ident,
420b06ebda0SMatthew Dillon 		u_int8_t code, u_int32_t token)
421b06ebda0SMatthew Dillon {
422b06ebda0SMatthew Dillon 	ng_l2cap_cmd_p	cmd = NULL;
423b06ebda0SMatthew Dillon 
424b06ebda0SMatthew Dillon 	KASSERT((ch == NULL || ch->con == con),
425b06ebda0SMatthew Dillon ("%s: %s - invalid channel pointer!\n",
426b06ebda0SMatthew Dillon 		__func__, NG_NODE_NAME(con->l2cap->node)));
427b06ebda0SMatthew Dillon 
428fc025606SSascha Wildner 	cmd = kmalloc(sizeof(*cmd), M_NETGRAPH_L2CAP,
4295a975a3dSMatthew Dillon 		      M_WAITOK | M_NULLOK | M_ZERO);
430b06ebda0SMatthew Dillon 	if (cmd == NULL)
431b06ebda0SMatthew Dillon 		return (NULL);
432b06ebda0SMatthew Dillon 
433b06ebda0SMatthew Dillon 	cmd->con = con;
434b06ebda0SMatthew Dillon 	cmd->ch = ch;
435b06ebda0SMatthew Dillon 	cmd->ident = ident;
436b06ebda0SMatthew Dillon 	cmd->code = code;
437b06ebda0SMatthew Dillon 	cmd->token = token;
438b06ebda0SMatthew Dillon 	ng_callout_init(&cmd->timo);
439b06ebda0SMatthew Dillon 
440b06ebda0SMatthew Dillon 	return (cmd);
441b06ebda0SMatthew Dillon } /* ng_l2cap_new_cmd */
442b06ebda0SMatthew Dillon 
443b06ebda0SMatthew Dillon /*
444b06ebda0SMatthew Dillon  * Get pending (i.e. initiated by local side) L2CAP command descriptor by ident
445b06ebda0SMatthew Dillon  */
446b06ebda0SMatthew Dillon 
447b06ebda0SMatthew Dillon ng_l2cap_cmd_p
ng_l2cap_cmd_by_ident(ng_l2cap_con_p con,u_int8_t ident)448b06ebda0SMatthew Dillon ng_l2cap_cmd_by_ident(ng_l2cap_con_p con, u_int8_t ident)
449b06ebda0SMatthew Dillon {
450b06ebda0SMatthew Dillon 	ng_l2cap_cmd_p	cmd = NULL;
451b06ebda0SMatthew Dillon 
452b06ebda0SMatthew Dillon 	TAILQ_FOREACH(cmd, &con->cmd_list, next) {
453b06ebda0SMatthew Dillon 		if ((cmd->flags & NG_L2CAP_CMD_PENDING) && cmd->ident == ident) {
454b06ebda0SMatthew Dillon 			KASSERT((cmd->con == con),
455b06ebda0SMatthew Dillon ("%s: %s - invalid connection pointer!\n",
456b06ebda0SMatthew Dillon 				__func__, NG_NODE_NAME(con->l2cap->node)));
457b06ebda0SMatthew Dillon 
458b06ebda0SMatthew Dillon 			break;
459b06ebda0SMatthew Dillon 		}
460b06ebda0SMatthew Dillon 	}
461b06ebda0SMatthew Dillon 
462b06ebda0SMatthew Dillon 	return (cmd);
463b06ebda0SMatthew Dillon } /* ng_l2cap_cmd_by_ident */
464b06ebda0SMatthew Dillon 
465b06ebda0SMatthew Dillon /*
466b06ebda0SMatthew Dillon  * Set LP timeout
467b06ebda0SMatthew Dillon  * XXX FIXME: check return code from ng_callout
468b06ebda0SMatthew Dillon  */
469b06ebda0SMatthew Dillon 
470b06ebda0SMatthew Dillon int
ng_l2cap_lp_timeout(ng_l2cap_con_p con)471b06ebda0SMatthew Dillon ng_l2cap_lp_timeout(ng_l2cap_con_p con)
472b06ebda0SMatthew Dillon {
473b06ebda0SMatthew Dillon 	if (con->flags & (NG_L2CAP_CON_LP_TIMO|NG_L2CAP_CON_AUTO_DISCON_TIMO))
474b06ebda0SMatthew Dillon 		panic(
475b06ebda0SMatthew Dillon "%s: %s - invalid timeout, state=%d, flags=%#x\n",
476b06ebda0SMatthew Dillon 			__func__, NG_NODE_NAME(con->l2cap->node),
477b06ebda0SMatthew Dillon 			con->state, con->flags);
478b06ebda0SMatthew Dillon 
479b06ebda0SMatthew Dillon 	con->flags |= NG_L2CAP_CON_LP_TIMO;
480b06ebda0SMatthew Dillon 	ng_callout(&con->con_timo, con->l2cap->node, NULL,
481b06ebda0SMatthew Dillon 				bluetooth_hci_connect_timeout(),
482b06ebda0SMatthew Dillon 				ng_l2cap_process_lp_timeout, NULL,
483b06ebda0SMatthew Dillon 				con->con_handle);
484b06ebda0SMatthew Dillon 
485b06ebda0SMatthew Dillon 	return (0);
486b06ebda0SMatthew Dillon } /* ng_l2cap_lp_timeout */
487b06ebda0SMatthew Dillon 
488b06ebda0SMatthew Dillon /*
489b06ebda0SMatthew Dillon  * Unset LP timeout
490b06ebda0SMatthew Dillon  */
491b06ebda0SMatthew Dillon 
492b06ebda0SMatthew Dillon int
ng_l2cap_lp_untimeout(ng_l2cap_con_p con)493b06ebda0SMatthew Dillon ng_l2cap_lp_untimeout(ng_l2cap_con_p con)
494b06ebda0SMatthew Dillon {
495b06ebda0SMatthew Dillon 	if (!(con->flags & NG_L2CAP_CON_LP_TIMO))
496b06ebda0SMatthew Dillon 		panic(
497b06ebda0SMatthew Dillon "%s: %s - no LP connection timeout, state=%d, flags=%#x\n",
498b06ebda0SMatthew Dillon 			__func__,  NG_NODE_NAME(con->l2cap->node),
499b06ebda0SMatthew Dillon 			con->state, con->flags);
500b06ebda0SMatthew Dillon 
501b06ebda0SMatthew Dillon 	if (ng_uncallout(&con->con_timo, con->l2cap->node) == 0)
502b06ebda0SMatthew Dillon 		return (ETIMEDOUT);
503b06ebda0SMatthew Dillon 
504b06ebda0SMatthew Dillon 	con->flags &= ~NG_L2CAP_CON_LP_TIMO;
505b06ebda0SMatthew Dillon 
506b06ebda0SMatthew Dillon 	return (0);
507b06ebda0SMatthew Dillon } /* ng_l2cap_lp_untimeout */
508b06ebda0SMatthew Dillon 
509b06ebda0SMatthew Dillon /*
510b06ebda0SMatthew Dillon  * Set L2CAP command timeout
511b06ebda0SMatthew Dillon  * XXX FIXME: check return code from ng_callout
512b06ebda0SMatthew Dillon  */
513b06ebda0SMatthew Dillon 
514b06ebda0SMatthew Dillon int
ng_l2cap_command_timeout(ng_l2cap_cmd_p cmd,int timo)515b06ebda0SMatthew Dillon ng_l2cap_command_timeout(ng_l2cap_cmd_p cmd, int timo)
516b06ebda0SMatthew Dillon {
517b06ebda0SMatthew Dillon 	int	arg;
518b06ebda0SMatthew Dillon 
519b06ebda0SMatthew Dillon 	if (cmd->flags & NG_L2CAP_CMD_PENDING)
520b06ebda0SMatthew Dillon 		panic(
521b06ebda0SMatthew Dillon "%s: %s - duplicated command timeout, code=%#x, flags=%#x\n",
522b06ebda0SMatthew Dillon 			__func__, NG_NODE_NAME(cmd->con->l2cap->node),
523b06ebda0SMatthew Dillon 			cmd->code, cmd->flags);
524b06ebda0SMatthew Dillon 
525b06ebda0SMatthew Dillon 	arg = ((cmd->ident << 16) | cmd->con->con_handle);
526b06ebda0SMatthew Dillon 	cmd->flags |= NG_L2CAP_CMD_PENDING;
527b06ebda0SMatthew Dillon 	ng_callout(&cmd->timo, cmd->con->l2cap->node, NULL, timo,
528b06ebda0SMatthew Dillon 				ng_l2cap_process_command_timeout, NULL, arg);
529b06ebda0SMatthew Dillon 
530b06ebda0SMatthew Dillon 	return (0);
531b06ebda0SMatthew Dillon } /* ng_l2cap_command_timeout */
532b06ebda0SMatthew Dillon 
533b06ebda0SMatthew Dillon /*
534b06ebda0SMatthew Dillon  * Unset L2CAP command timeout
535b06ebda0SMatthew Dillon  */
536b06ebda0SMatthew Dillon 
537b06ebda0SMatthew Dillon int
ng_l2cap_command_untimeout(ng_l2cap_cmd_p cmd)538b06ebda0SMatthew Dillon ng_l2cap_command_untimeout(ng_l2cap_cmd_p cmd)
539b06ebda0SMatthew Dillon {
540b06ebda0SMatthew Dillon 	if (!(cmd->flags & NG_L2CAP_CMD_PENDING))
541b06ebda0SMatthew Dillon 		panic(
542b06ebda0SMatthew Dillon "%s: %s - no command timeout, code=%#x, flags=%#x\n",
543b06ebda0SMatthew Dillon 			__func__, NG_NODE_NAME(cmd->con->l2cap->node),
544b06ebda0SMatthew Dillon 			cmd->code, cmd->flags);
545b06ebda0SMatthew Dillon 
546b06ebda0SMatthew Dillon 	if (ng_uncallout(&cmd->timo, cmd->con->l2cap->node) == 0)
547b06ebda0SMatthew Dillon 		return (ETIMEDOUT);
548b06ebda0SMatthew Dillon 
549b06ebda0SMatthew Dillon 	cmd->flags &= ~NG_L2CAP_CMD_PENDING;
550b06ebda0SMatthew Dillon 
551b06ebda0SMatthew Dillon 	return (0);
552b06ebda0SMatthew Dillon } /* ng_l2cap_command_untimeout */
553b06ebda0SMatthew Dillon 
554b06ebda0SMatthew Dillon /*
555b06ebda0SMatthew Dillon  * Prepend "m"buf with "size" bytes
556b06ebda0SMatthew Dillon  */
557b06ebda0SMatthew Dillon 
558b06ebda0SMatthew Dillon struct mbuf *
ng_l2cap_prepend(struct mbuf * m,int size)559b06ebda0SMatthew Dillon ng_l2cap_prepend(struct mbuf *m, int size)
560b06ebda0SMatthew Dillon {
561*b5523eacSSascha Wildner 	M_PREPEND(m, size, M_NOWAIT);
562b06ebda0SMatthew Dillon 	if (m == NULL || (m->m_len < size && (m = m_pullup(m, size)) == NULL))
563b06ebda0SMatthew Dillon 		return (NULL);
564b06ebda0SMatthew Dillon 
565b06ebda0SMatthew Dillon 	return (m);
566b06ebda0SMatthew Dillon } /* ng_l2cap_prepend */
567b06ebda0SMatthew Dillon 
568b06ebda0SMatthew Dillon /*
569b06ebda0SMatthew Dillon  * Default flow settings
570b06ebda0SMatthew Dillon  */
571b06ebda0SMatthew Dillon 
572b06ebda0SMatthew Dillon ng_l2cap_flow_p
ng_l2cap_default_flow(void)573b06ebda0SMatthew Dillon ng_l2cap_default_flow(void)
574b06ebda0SMatthew Dillon {
575b06ebda0SMatthew Dillon 	static ng_l2cap_flow_t	default_flow = {
576b06ebda0SMatthew Dillon 		/* flags */		0x0,
577b06ebda0SMatthew Dillon 		/* service_type */	NG_HCI_SERVICE_TYPE_BEST_EFFORT,
578b06ebda0SMatthew Dillon 		/* token_rate */	0xffffffff, /* maximum */
579b06ebda0SMatthew Dillon 		/* token_bucket_size */	0xffffffff, /* maximum */
580b06ebda0SMatthew Dillon 		/* peak_bandwidth */	0x00000000, /* maximum */
581b06ebda0SMatthew Dillon 		/* latency */		0xffffffff, /* don't care */
582b06ebda0SMatthew Dillon 		/* delay_variation */	0xffffffff  /* don't care */
583b06ebda0SMatthew Dillon 	};
584b06ebda0SMatthew Dillon 
585b06ebda0SMatthew Dillon 	return (&default_flow);
586b06ebda0SMatthew Dillon } /* ng_l2cap_default_flow */
587b06ebda0SMatthew Dillon 
588b06ebda0SMatthew Dillon /*
589b06ebda0SMatthew Dillon  * Get next available channel ID
590b06ebda0SMatthew Dillon  * XXX FIXME this is *UGLY* but will do for now
591b06ebda0SMatthew Dillon  */
592b06ebda0SMatthew Dillon 
593b06ebda0SMatthew Dillon static u_int16_t
ng_l2cap_get_cid(ng_l2cap_p l2cap)594b06ebda0SMatthew Dillon ng_l2cap_get_cid(ng_l2cap_p l2cap)
595b06ebda0SMatthew Dillon {
596b06ebda0SMatthew Dillon 	u_int16_t	cid = l2cap->cid + 1;
597b06ebda0SMatthew Dillon 
598b06ebda0SMatthew Dillon 	if (cid < NG_L2CAP_FIRST_CID)
599b06ebda0SMatthew Dillon 		cid = NG_L2CAP_FIRST_CID;
600b06ebda0SMatthew Dillon 
601b06ebda0SMatthew Dillon 	while (cid != l2cap->cid) {
602b06ebda0SMatthew Dillon 		if (ng_l2cap_chan_by_scid(l2cap, cid) == NULL) {
603b06ebda0SMatthew Dillon 			l2cap->cid = cid;
604b06ebda0SMatthew Dillon 
605b06ebda0SMatthew Dillon 			return (cid);
606b06ebda0SMatthew Dillon 		}
607b06ebda0SMatthew Dillon 
608b06ebda0SMatthew Dillon 		cid ++;
609b06ebda0SMatthew Dillon 		if (cid < NG_L2CAP_FIRST_CID)
610b06ebda0SMatthew Dillon 			cid = NG_L2CAP_FIRST_CID;
611b06ebda0SMatthew Dillon 	}
612b06ebda0SMatthew Dillon 
613b06ebda0SMatthew Dillon 	return (NG_L2CAP_NULL_CID);
614b06ebda0SMatthew Dillon } /* ng_l2cap_get_cid */
615b06ebda0SMatthew Dillon 
616b06ebda0SMatthew Dillon /*
617b06ebda0SMatthew Dillon  * Get next available command ident
618b06ebda0SMatthew Dillon  * XXX FIXME this is *UGLY* but will do for now
619b06ebda0SMatthew Dillon  */
620b06ebda0SMatthew Dillon 
621b06ebda0SMatthew Dillon u_int8_t
ng_l2cap_get_ident(ng_l2cap_con_p con)622b06ebda0SMatthew Dillon ng_l2cap_get_ident(ng_l2cap_con_p con)
623b06ebda0SMatthew Dillon {
624b06ebda0SMatthew Dillon 	u_int8_t	ident = con->ident + 1;
625b06ebda0SMatthew Dillon 
626b06ebda0SMatthew Dillon 	if (ident < NG_L2CAP_FIRST_IDENT)
627b06ebda0SMatthew Dillon 		ident = NG_L2CAP_FIRST_IDENT;
628b06ebda0SMatthew Dillon 
629b06ebda0SMatthew Dillon 	while (ident != con->ident) {
630b06ebda0SMatthew Dillon 		if (ng_l2cap_cmd_by_ident(con, ident) == NULL) {
631b06ebda0SMatthew Dillon 			con->ident = ident;
632b06ebda0SMatthew Dillon 
633b06ebda0SMatthew Dillon 			return (ident);
634b06ebda0SMatthew Dillon 		}
635b06ebda0SMatthew Dillon 
636b06ebda0SMatthew Dillon 		ident ++;
637b06ebda0SMatthew Dillon 		if (ident < NG_L2CAP_FIRST_IDENT)
638b06ebda0SMatthew Dillon 			ident = NG_L2CAP_FIRST_IDENT;
639b06ebda0SMatthew Dillon 	}
640b06ebda0SMatthew Dillon 
641b06ebda0SMatthew Dillon 	return (NG_L2CAP_NULL_IDENT);
642b06ebda0SMatthew Dillon } /* ng_l2cap_get_ident */
643b06ebda0SMatthew Dillon 
644