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