xref: /freebsd/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.c (revision 878ed22696d5402cabd6f90932cc970ab912b7b0)
1878ed226SJulian Elischer /*
2878ed226SJulian Elischer  * ng_l2cap_misc.c
3878ed226SJulian Elischer  *
4878ed226SJulian Elischer  * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
5878ed226SJulian Elischer  * All rights reserved.
6878ed226SJulian Elischer  *
7878ed226SJulian Elischer  * Redistribution and use in source and binary forms, with or without
8878ed226SJulian Elischer  * modification, are permitted provided that the following conditions
9878ed226SJulian Elischer  * are met:
10878ed226SJulian Elischer  * 1. Redistributions of source code must retain the above copyright
11878ed226SJulian Elischer  *    notice, this list of conditions and the following disclaimer.
12878ed226SJulian Elischer  * 2. Redistributions in binary form must reproduce the above copyright
13878ed226SJulian Elischer  *    notice, this list of conditions and the following disclaimer in the
14878ed226SJulian Elischer  *    documentation and/or other materials provided with the distribution.
15878ed226SJulian Elischer  *
16878ed226SJulian Elischer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17878ed226SJulian Elischer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18878ed226SJulian Elischer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19878ed226SJulian Elischer  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20878ed226SJulian Elischer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21878ed226SJulian Elischer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22878ed226SJulian Elischer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23878ed226SJulian Elischer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24878ed226SJulian Elischer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25878ed226SJulian Elischer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26878ed226SJulian Elischer  * SUCH DAMAGE.
27878ed226SJulian Elischer  *
28878ed226SJulian Elischer  * $Id: ng_l2cap_misc.c,v 1.16 2002/09/04 21:38:38 max Exp $
29878ed226SJulian Elischer  * $FreeBSD$
30878ed226SJulian Elischer  */
31878ed226SJulian Elischer 
32878ed226SJulian Elischer #include <sys/param.h>
33878ed226SJulian Elischer #include <sys/systm.h>
34878ed226SJulian Elischer #include <sys/kernel.h>
35878ed226SJulian Elischer #include <sys/malloc.h>
36878ed226SJulian Elischer #include <sys/mbuf.h>
37878ed226SJulian Elischer #include <sys/queue.h>
38878ed226SJulian Elischer #include <netgraph/ng_message.h>
39878ed226SJulian Elischer #include <netgraph/netgraph.h>
40878ed226SJulian Elischer #include "ng_bluetooth.h"
41878ed226SJulian Elischer #include "ng_hci.h"
42878ed226SJulian Elischer #include "ng_l2cap.h"
43878ed226SJulian Elischer #include "ng_l2cap_var.h"
44878ed226SJulian Elischer #include "ng_l2cap_cmds.h"
45878ed226SJulian Elischer #include "ng_l2cap_evnt.h"
46878ed226SJulian Elischer #include "ng_l2cap_llpi.h"
47878ed226SJulian Elischer #include "ng_l2cap_ulpi.h"
48878ed226SJulian Elischer #include "ng_l2cap_misc.h"
49878ed226SJulian Elischer 
50878ed226SJulian Elischer static u_int16_t	ng_l2cap_get_cid		(ng_l2cap_p);
51878ed226SJulian Elischer static void		ng_l2cap_queue_lp_timeout	(void *);
52878ed226SJulian Elischer static void		ng_l2cap_queue_command_timeout	(void *);
53878ed226SJulian Elischer 
54878ed226SJulian Elischer /******************************************************************************
55878ed226SJulian Elischer  ******************************************************************************
56878ed226SJulian Elischer  **                              Utility routines
57878ed226SJulian Elischer  ******************************************************************************
58878ed226SJulian Elischer  ******************************************************************************/
59878ed226SJulian Elischer 
60878ed226SJulian Elischer /*
61878ed226SJulian Elischer  * Send hook information to the upper layer
62878ed226SJulian Elischer  */
63878ed226SJulian Elischer 
64878ed226SJulian Elischer void
65878ed226SJulian Elischer ng_l2cap_send_hook_info(node_p node, hook_p hook, void *arg1, int arg2)
66878ed226SJulian Elischer {
67878ed226SJulian Elischer 	ng_l2cap_p	 l2cap = NULL;
68878ed226SJulian Elischer 	struct ng_mesg	*msg = NULL;
69878ed226SJulian Elischer 	int		 error = 0;
70878ed226SJulian Elischer 
71878ed226SJulian Elischer 	if (node == NULL || NG_NODE_NOT_VALID(node) ||
72878ed226SJulian Elischer 	    hook == NULL || NG_HOOK_NOT_VALID(hook))
73878ed226SJulian Elischer 		return;
74878ed226SJulian Elischer 
75878ed226SJulian Elischer 	l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
76878ed226SJulian Elischer 	if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci) ||
77878ed226SJulian Elischer 	    bcmp(&l2cap->bdaddr, NG_HCI_BDADDR_ANY, sizeof(l2cap->bdaddr)) == 0)
78878ed226SJulian Elischer 		return;
79878ed226SJulian Elischer 
80878ed226SJulian Elischer 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_HOOK_INFO,
81878ed226SJulian Elischer 		sizeof(bdaddr_t), M_NOWAIT);
82878ed226SJulian Elischer 	if (msg != NULL) {
83878ed226SJulian Elischer 		bcopy(&l2cap->bdaddr, msg->data, sizeof(bdaddr_t));
84878ed226SJulian Elischer 		NG_SEND_MSG_HOOK(error, node, msg, hook, NULL);
85878ed226SJulian Elischer 	} else
86878ed226SJulian Elischer 		error = ENOMEM;
87878ed226SJulian Elischer 
88878ed226SJulian Elischer 	if (error != 0)
89878ed226SJulian Elischer 		NG_L2CAP_INFO(
90878ed226SJulian Elischer "%s: %s - failed to send HOOK_INFO message to hook \"%s\", error=%d\n",
91878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), NG_HOOK_NAME(hook),
92878ed226SJulian Elischer 			error);
93878ed226SJulian Elischer } /* ng_l2cap_send_hook_info */
94878ed226SJulian Elischer 
95878ed226SJulian Elischer /*
96878ed226SJulian Elischer  * Create new connection descriptor for the "remote" unit. Will create new
97878ed226SJulian Elischer  * connection descriptor and signal channel. Will link both connection and
98878ed226SJulian Elischer  * channel to the l2cap node.
99878ed226SJulian Elischer  */
100878ed226SJulian Elischer 
101878ed226SJulian Elischer ng_l2cap_con_p
102878ed226SJulian Elischer ng_l2cap_new_con(ng_l2cap_p l2cap, bdaddr_p bdaddr)
103878ed226SJulian Elischer {
104878ed226SJulian Elischer 	ng_l2cap_con_p	con = NULL;
105878ed226SJulian Elischer 
106878ed226SJulian Elischer 	/* Create new connection descriptor */
107878ed226SJulian Elischer 	MALLOC(con, ng_l2cap_con_p, sizeof(*con), M_NETGRAPH_L2CAP,
108878ed226SJulian Elischer 		M_NOWAIT|M_ZERO);
109878ed226SJulian Elischer 	if (con == NULL)
110878ed226SJulian Elischer 		return (NULL);
111878ed226SJulian Elischer 
112878ed226SJulian Elischer 	con->l2cap = l2cap;
113878ed226SJulian Elischer 	con->state = NG_L2CAP_CON_CLOSED;
114878ed226SJulian Elischer 
115878ed226SJulian Elischer 	bcopy(bdaddr, &con->remote, sizeof(con->remote));
116878ed226SJulian Elischer 	callout_handle_init(&con->con_timo);
117878ed226SJulian Elischer 
118878ed226SJulian Elischer 	con->ident = NG_L2CAP_FIRST_IDENT - 1;
119878ed226SJulian Elischer 	TAILQ_INIT(&con->cmd_list);
120878ed226SJulian Elischer 
121878ed226SJulian Elischer 	/* Link connection */
122878ed226SJulian Elischer 	LIST_INSERT_HEAD(&l2cap->con_list, con, next);
123878ed226SJulian Elischer 
124878ed226SJulian Elischer 	return (con);
125878ed226SJulian Elischer } /* ng_l2cap_new_con */
126878ed226SJulian Elischer 
127878ed226SJulian Elischer /*
128878ed226SJulian Elischer  * Free connection descriptor. Will unlink connection and free everything.
129878ed226SJulian Elischer  */
130878ed226SJulian Elischer 
131878ed226SJulian Elischer void
132878ed226SJulian Elischer ng_l2cap_free_con(ng_l2cap_con_p con)
133878ed226SJulian Elischer {
134878ed226SJulian Elischer 	ng_l2cap_chan_p f = NULL, n = NULL;
135878ed226SJulian Elischer 
136878ed226SJulian Elischer 	if (con->state == NG_L2CAP_W4_LP_CON_CFM)
137878ed226SJulian Elischer 		ng_l2cap_lp_untimeout(con);
138878ed226SJulian Elischer 
139878ed226SJulian Elischer 	if (con->tx_pkt != NULL) {
140878ed226SJulian Elischer 		while (con->tx_pkt != NULL) {
141878ed226SJulian Elischer 			struct mbuf	*m = con->tx_pkt->m_nextpkt;
142878ed226SJulian Elischer 
143878ed226SJulian Elischer 			m_freem(con->tx_pkt);
144878ed226SJulian Elischer 			con->tx_pkt = m;
145878ed226SJulian Elischer 		}
146878ed226SJulian Elischer 	}
147878ed226SJulian Elischer 
148878ed226SJulian Elischer 	NG_FREE_M(con->rx_pkt);
149878ed226SJulian Elischer 
150878ed226SJulian Elischer 	for (f = LIST_FIRST(&con->l2cap->chan_list); f != NULL; ) {
151878ed226SJulian Elischer 		n = LIST_NEXT(f, next);
152878ed226SJulian Elischer 
153878ed226SJulian Elischer 		if (f->con == con)
154878ed226SJulian Elischer 			ng_l2cap_free_chan(f);
155878ed226SJulian Elischer 
156878ed226SJulian Elischer 		f = n;
157878ed226SJulian Elischer 	}
158878ed226SJulian Elischer 
159878ed226SJulian Elischer 	while (!TAILQ_EMPTY(&con->cmd_list)) {
160878ed226SJulian Elischer 		ng_l2cap_cmd_p	cmd = TAILQ_FIRST(&con->cmd_list);
161878ed226SJulian Elischer 
162878ed226SJulian Elischer 		ng_l2cap_unlink_cmd(cmd);
163878ed226SJulian Elischer 		ng_l2cap_free_cmd(cmd);
164878ed226SJulian Elischer 	}
165878ed226SJulian Elischer 
166878ed226SJulian Elischer 	LIST_REMOVE(con, next);
167878ed226SJulian Elischer 	bzero(con, sizeof(*con));
168878ed226SJulian Elischer 	FREE(con, M_NETGRAPH_L2CAP);
169878ed226SJulian Elischer } /* ng_l2cap_free_con */
170878ed226SJulian Elischer 
171878ed226SJulian Elischer /*
172878ed226SJulian Elischer  * Get connection by "remote" address
173878ed226SJulian Elischer  */
174878ed226SJulian Elischer 
175878ed226SJulian Elischer ng_l2cap_con_p
176878ed226SJulian Elischer ng_l2cap_con_by_addr(ng_l2cap_p l2cap, bdaddr_p bdaddr)
177878ed226SJulian Elischer {
178878ed226SJulian Elischer 	ng_l2cap_con_p	con = NULL;
179878ed226SJulian Elischer 
180878ed226SJulian Elischer 	LIST_FOREACH(con, &l2cap->con_list, next)
181878ed226SJulian Elischer 		if (bcmp(bdaddr, &con->remote, sizeof(con->remote)) == 0)
182878ed226SJulian Elischer 			break;
183878ed226SJulian Elischer 
184878ed226SJulian Elischer 	return (con);
185878ed226SJulian Elischer } /* ng_l2cap_con_by_addr */
186878ed226SJulian Elischer 
187878ed226SJulian Elischer /*
188878ed226SJulian Elischer  * Get connection by "handle"
189878ed226SJulian Elischer  */
190878ed226SJulian Elischer 
191878ed226SJulian Elischer ng_l2cap_con_p
192878ed226SJulian Elischer ng_l2cap_con_by_handle(ng_l2cap_p l2cap, u_int16_t con_handle)
193878ed226SJulian Elischer {
194878ed226SJulian Elischer 	ng_l2cap_con_p	con = NULL;
195878ed226SJulian Elischer 
196878ed226SJulian Elischer 	LIST_FOREACH(con, &l2cap->con_list, next)
197878ed226SJulian Elischer 		if (con->con_handle == con_handle)
198878ed226SJulian Elischer 			break;
199878ed226SJulian Elischer 
200878ed226SJulian Elischer 	return (con);
201878ed226SJulian Elischer } /* ng_l2cap_con_by_handle */
202878ed226SJulian Elischer 
203878ed226SJulian Elischer /*
204878ed226SJulian Elischer  * Allocate new L2CAP channel descriptor on "con" conection with "psm".
205878ed226SJulian Elischer  * Will link the channel to the l2cap node
206878ed226SJulian Elischer  */
207878ed226SJulian Elischer 
208878ed226SJulian Elischer ng_l2cap_chan_p
209878ed226SJulian Elischer ng_l2cap_new_chan(ng_l2cap_p l2cap, ng_l2cap_con_p con, u_int16_t psm)
210878ed226SJulian Elischer {
211878ed226SJulian Elischer 	ng_l2cap_chan_p	ch = NULL;
212878ed226SJulian Elischer 
213878ed226SJulian Elischer 	MALLOC(ch, ng_l2cap_chan_p, sizeof(*ch), M_NETGRAPH_L2CAP,
214878ed226SJulian Elischer 		M_NOWAIT|M_ZERO);
215878ed226SJulian Elischer 	if (ch == NULL)
216878ed226SJulian Elischer 		return (NULL);
217878ed226SJulian Elischer 
218878ed226SJulian Elischer 	ch->scid = ng_l2cap_get_cid(l2cap);
219878ed226SJulian Elischer 
220878ed226SJulian Elischer 	if (ch->scid != NG_L2CAP_NULL_CID) {
221878ed226SJulian Elischer 		/* Initialize channel */
222878ed226SJulian Elischer 		ch->psm = psm;
223878ed226SJulian Elischer 		ch->con = con;
224878ed226SJulian Elischer 		ch->state = NG_L2CAP_CLOSED;
225878ed226SJulian Elischer 
226878ed226SJulian Elischer 		/* Set MTU and flow control settings to defaults */
227878ed226SJulian Elischer 		ch->imtu = NG_L2CAP_MTU_DEFAULT;
228878ed226SJulian Elischer 		bcopy(ng_l2cap_default_flow(), &ch->iflow, sizeof(ch->iflow));
229878ed226SJulian Elischer 
230878ed226SJulian Elischer 		ch->omtu = NG_L2CAP_MTU_DEFAULT;
231878ed226SJulian Elischer 		bcopy(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow));
232878ed226SJulian Elischer 
233878ed226SJulian Elischer 		ch->flush_timo = NG_L2CAP_FLUSH_TIMO_DEFAULT;
234878ed226SJulian Elischer 		ch->link_timo = NG_L2CAP_LINK_TIMO_DEFAULT;
235878ed226SJulian Elischer 
236878ed226SJulian Elischer 		LIST_INSERT_HEAD(&l2cap->chan_list, ch, next);
237878ed226SJulian Elischer 	} else {
238878ed226SJulian Elischer 		bzero(ch, sizeof(*ch));
239878ed226SJulian Elischer 		FREE(ch, M_NETGRAPH_L2CAP);
240878ed226SJulian Elischer 		ch = NULL;
241878ed226SJulian Elischer 	}
242878ed226SJulian Elischer 
243878ed226SJulian Elischer 	return (ch);
244878ed226SJulian Elischer } /* ng_l2cap_new_chan */
245878ed226SJulian Elischer 
246878ed226SJulian Elischer /*
247878ed226SJulian Elischer  * Get channel by source (local) channel ID
248878ed226SJulian Elischer  */
249878ed226SJulian Elischer 
250878ed226SJulian Elischer ng_l2cap_chan_p
251878ed226SJulian Elischer ng_l2cap_chan_by_scid(ng_l2cap_p l2cap, u_int16_t scid)
252878ed226SJulian Elischer {
253878ed226SJulian Elischer 	ng_l2cap_chan_p	ch = NULL;
254878ed226SJulian Elischer 
255878ed226SJulian Elischer 	LIST_FOREACH(ch, &l2cap->chan_list, next)
256878ed226SJulian Elischer 		if (ch->scid == scid)
257878ed226SJulian Elischer 			break;
258878ed226SJulian Elischer 
259878ed226SJulian Elischer 	return (ch);
260878ed226SJulian Elischer } /* ng_l2cap_chan_by_scid */
261878ed226SJulian Elischer 
262878ed226SJulian Elischer /*
263878ed226SJulian Elischer  * Free channel descriptor.
264878ed226SJulian Elischer  */
265878ed226SJulian Elischer 
266878ed226SJulian Elischer void
267878ed226SJulian Elischer ng_l2cap_free_chan(ng_l2cap_chan_p ch)
268878ed226SJulian Elischer {
269878ed226SJulian Elischer 	ng_l2cap_cmd_p	f = NULL, n = NULL;
270878ed226SJulian Elischer 
271878ed226SJulian Elischer 	f = TAILQ_FIRST(&ch->con->cmd_list);
272878ed226SJulian Elischer 	while (f != NULL) {
273878ed226SJulian Elischer 		n = TAILQ_NEXT(f, next);
274878ed226SJulian Elischer 
275878ed226SJulian Elischer 		if (f->ch == ch) {
276878ed226SJulian Elischer 			ng_l2cap_unlink_cmd(f);
277878ed226SJulian Elischer 			ng_l2cap_free_cmd(f);
278878ed226SJulian Elischer 		}
279878ed226SJulian Elischer 
280878ed226SJulian Elischer 		f = n;
281878ed226SJulian Elischer 	}
282878ed226SJulian Elischer 
283878ed226SJulian Elischer 	LIST_REMOVE(ch, next);
284878ed226SJulian Elischer 	bzero(ch, sizeof(*ch));
285878ed226SJulian Elischer 	FREE(ch, M_NETGRAPH_L2CAP);
286878ed226SJulian Elischer } /* ng_l2cap_free_chan */
287878ed226SJulian Elischer 
288878ed226SJulian Elischer /*
289878ed226SJulian Elischer  * Create new L2CAP command descriptor. WILL NOT add command to the queue.
290878ed226SJulian Elischer  */
291878ed226SJulian Elischer 
292878ed226SJulian Elischer ng_l2cap_cmd_p
293878ed226SJulian Elischer ng_l2cap_new_cmd(ng_l2cap_con_p con, ng_l2cap_chan_p ch, u_int8_t ident,
294878ed226SJulian Elischer 		u_int8_t code, u_int32_t token)
295878ed226SJulian Elischer {
296878ed226SJulian Elischer 	ng_l2cap_cmd_p	cmd = NULL;
297878ed226SJulian Elischer 
298878ed226SJulian Elischer 	KASSERT((ch == NULL || ch->con == con),
299878ed226SJulian Elischer ("%s: %s - invalid channel pointer!\n",
300878ed226SJulian Elischer 		__func__, NG_NODE_NAME(con->l2cap->node)));
301878ed226SJulian Elischer 
302878ed226SJulian Elischer 	MALLOC(cmd, ng_l2cap_cmd_p, sizeof(*cmd), M_NETGRAPH_L2CAP,
303878ed226SJulian Elischer 		M_NOWAIT|M_ZERO);
304878ed226SJulian Elischer 	if (cmd == NULL)
305878ed226SJulian Elischer 		return (NULL);
306878ed226SJulian Elischer 
307878ed226SJulian Elischer 	cmd->con = con;
308878ed226SJulian Elischer 	cmd->ch = ch;
309878ed226SJulian Elischer 	cmd->ident = ident;
310878ed226SJulian Elischer 	cmd->code = code;
311878ed226SJulian Elischer 	cmd->token = token;
312878ed226SJulian Elischer 	callout_handle_init(&cmd->timo);
313878ed226SJulian Elischer 
314878ed226SJulian Elischer 	return (cmd);
315878ed226SJulian Elischer } /* ng_l2cap_new_cmd */
316878ed226SJulian Elischer 
317878ed226SJulian Elischer /*
318878ed226SJulian Elischer  * Get L2CAP command descriptor by ident
319878ed226SJulian Elischer  */
320878ed226SJulian Elischer 
321878ed226SJulian Elischer ng_l2cap_cmd_p
322878ed226SJulian Elischer ng_l2cap_cmd_by_ident(ng_l2cap_con_p con, u_int8_t ident)
323878ed226SJulian Elischer {
324878ed226SJulian Elischer 	ng_l2cap_cmd_p	cmd = NULL;
325878ed226SJulian Elischer 
326878ed226SJulian Elischer 	TAILQ_FOREACH(cmd, &con->cmd_list, next)
327878ed226SJulian Elischer 		if (cmd->ident == ident)
328878ed226SJulian Elischer 			break;
329878ed226SJulian Elischer 
330878ed226SJulian Elischer 	return (cmd);
331878ed226SJulian Elischer } /* ng_l2cap_cmd_by_ident */
332878ed226SJulian Elischer 
333878ed226SJulian Elischer /*
334878ed226SJulian Elischer  * Set LP timeout
335878ed226SJulian Elischer  */
336878ed226SJulian Elischer 
337878ed226SJulian Elischer void
338878ed226SJulian Elischer ng_l2cap_lp_timeout(ng_l2cap_con_p con)
339878ed226SJulian Elischer {
340878ed226SJulian Elischer 	NG_NODE_REF(con->l2cap->node);
341878ed226SJulian Elischer 	con->con_timo = timeout(ng_l2cap_queue_lp_timeout, con,
342878ed226SJulian Elischer 				bluetooth_hci_connect_timeout());
343878ed226SJulian Elischer } /* ng_l2cap_lp_timeout */
344878ed226SJulian Elischer 
345878ed226SJulian Elischer /*
346878ed226SJulian Elischer  * Unset LP timeout
347878ed226SJulian Elischer  */
348878ed226SJulian Elischer 
349878ed226SJulian Elischer void
350878ed226SJulian Elischer ng_l2cap_lp_untimeout(ng_l2cap_con_p con)
351878ed226SJulian Elischer {
352878ed226SJulian Elischer 	untimeout(ng_l2cap_queue_lp_timeout, con, con->con_timo);
353878ed226SJulian Elischer 	NG_NODE_UNREF(con->l2cap->node);
354878ed226SJulian Elischer } /* ng_l2cap_lp_untimeout */
355878ed226SJulian Elischer 
356878ed226SJulian Elischer /*
357878ed226SJulian Elischer  * OK, timeout has happend so queue LP timeout processing function
358878ed226SJulian Elischer  */
359878ed226SJulian Elischer 
360878ed226SJulian Elischer static void
361878ed226SJulian Elischer ng_l2cap_queue_lp_timeout(void *context)
362878ed226SJulian Elischer {
363878ed226SJulian Elischer 	ng_l2cap_con_p	con = (ng_l2cap_con_p) context;
364878ed226SJulian Elischer 	node_p		node = con->l2cap->node;
365878ed226SJulian Elischer 
366878ed226SJulian Elischer 	/*
367878ed226SJulian Elischer 	 * We need to save node pointer here, because ng_send_fn()
368878ed226SJulian Elischer 	 * can execute ng_l2cap_process_lp_timeout() without putting
369878ed226SJulian Elischer 	 * item into node's queue (if node can be locked). Once
370878ed226SJulian Elischer 	 * ng_l2cap_process_lp_timeout() executed the con pointer
371878ed226SJulian Elischer 	 * is no longer valid.
372878ed226SJulian Elischer 	 */
373878ed226SJulian Elischer 
374878ed226SJulian Elischer 	if (NG_NODE_IS_VALID(node))
375878ed226SJulian Elischer 		ng_send_fn(node, NULL, &ng_l2cap_process_lp_timeout, con, 0);
376878ed226SJulian Elischer 
377878ed226SJulian Elischer 	NG_NODE_UNREF(node);
378878ed226SJulian Elischer } /* ng_l2cap_queue_lp_timeout */
379878ed226SJulian Elischer 
380878ed226SJulian Elischer /*
381878ed226SJulian Elischer  * Set L2CAP command timeout
382878ed226SJulian Elischer  */
383878ed226SJulian Elischer 
384878ed226SJulian Elischer void
385878ed226SJulian Elischer ng_l2cap_command_timeout(ng_l2cap_cmd_p cmd, int timo)
386878ed226SJulian Elischer {
387878ed226SJulian Elischer 	NG_NODE_REF(cmd->con->l2cap->node);
388878ed226SJulian Elischer 	cmd->flags |= NG_L2CAP_CMD_PENDING;
389878ed226SJulian Elischer 	cmd->timo = timeout(ng_l2cap_queue_command_timeout, cmd, timo);
390878ed226SJulian Elischer } /* ng_l2cap_command_timeout */
391878ed226SJulian Elischer 
392878ed226SJulian Elischer /*
393878ed226SJulian Elischer  * Unset L2CAP command timeout
394878ed226SJulian Elischer  */
395878ed226SJulian Elischer 
396878ed226SJulian Elischer void
397878ed226SJulian Elischer ng_l2cap_command_untimeout(ng_l2cap_cmd_p cmd)
398878ed226SJulian Elischer {
399878ed226SJulian Elischer 	cmd->flags &= ~NG_L2CAP_CMD_PENDING;
400878ed226SJulian Elischer 	untimeout(ng_l2cap_queue_command_timeout, cmd, cmd->timo);
401878ed226SJulian Elischer 	NG_NODE_UNREF(cmd->con->l2cap->node);
402878ed226SJulian Elischer } /* ng_l2cap_command_untimeout */
403878ed226SJulian Elischer 
404878ed226SJulian Elischer /*
405878ed226SJulian Elischer  * OK, timeout has happend so queue L2CAP command timeout processing function
406878ed226SJulian Elischer  */
407878ed226SJulian Elischer 
408878ed226SJulian Elischer static void
409878ed226SJulian Elischer ng_l2cap_queue_command_timeout(void *context)
410878ed226SJulian Elischer {
411878ed226SJulian Elischer 	ng_l2cap_cmd_p	cmd = (ng_l2cap_cmd_p) context;
412878ed226SJulian Elischer 	node_p		node = cmd->con->l2cap->node;
413878ed226SJulian Elischer 
414878ed226SJulian Elischer 	/*
415878ed226SJulian Elischer 	 * We need to save node pointer here, because ng_send_fn()
416878ed226SJulian Elischer 	 * can execute ng_l2cap_process_command_timeout() without
417878ed226SJulian Elischer 	 * putting item into node's queue (if node can be locked).
418878ed226SJulian Elischer 	 * Once ng_l2cap_process_command_timeout() executed the
419878ed226SJulian Elischer 	 * cmd pointer is no longer valid.
420878ed226SJulian Elischer 	 */
421878ed226SJulian Elischer 
422878ed226SJulian Elischer 	if (NG_NODE_IS_VALID(node))
423878ed226SJulian Elischer 		ng_send_fn(node,NULL,&ng_l2cap_process_command_timeout,cmd,0);
424878ed226SJulian Elischer 
425878ed226SJulian Elischer 	NG_NODE_UNREF(node);
426878ed226SJulian Elischer } /* ng_l2cap_queue_command_timeout */
427878ed226SJulian Elischer 
428878ed226SJulian Elischer /*
429878ed226SJulian Elischer  * Prepend "m"buf with "size" bytes
430878ed226SJulian Elischer  */
431878ed226SJulian Elischer 
432878ed226SJulian Elischer struct mbuf *
433878ed226SJulian Elischer ng_l2cap_prepend(struct mbuf *m, int size)
434878ed226SJulian Elischer {
435878ed226SJulian Elischer 	M_PREPEND(m, size, M_DONTWAIT);
436878ed226SJulian Elischer 	if (m == NULL || (m->m_len < size && (m = m_pullup(m, size)) == NULL))
437878ed226SJulian Elischer 		return (NULL);
438878ed226SJulian Elischer 
439878ed226SJulian Elischer 	return (m);
440878ed226SJulian Elischer } /* ng_l2cap_prepend */
441878ed226SJulian Elischer 
442878ed226SJulian Elischer /*
443878ed226SJulian Elischer  * Default flow settings
444878ed226SJulian Elischer  */
445878ed226SJulian Elischer 
446878ed226SJulian Elischer ng_l2cap_flow_p
447878ed226SJulian Elischer ng_l2cap_default_flow(void)
448878ed226SJulian Elischer {
449878ed226SJulian Elischer 	static ng_l2cap_flow_t	default_flow = {
450878ed226SJulian Elischer 		/* flags */		0x0,
451878ed226SJulian Elischer 		/* service_type */	NG_HCI_SERVICE_TYPE_BEST_EFFORT,
452878ed226SJulian Elischer 		/* token_rate */	0xffffffff, /* maximum */
453878ed226SJulian Elischer 		/* token_bucket_size */	0xffffffff, /* maximum */
454878ed226SJulian Elischer 		/* peak_bandwidth */	0x00000000, /* maximum */
455878ed226SJulian Elischer 		/* latency */		0xffffffff, /* don't care */
456878ed226SJulian Elischer 		/* delay_variation */	0xffffffff  /* don't care */
457878ed226SJulian Elischer 	};
458878ed226SJulian Elischer 
459878ed226SJulian Elischer 	return (&default_flow);
460878ed226SJulian Elischer } /* ng_l2cap_default_flow */
461878ed226SJulian Elischer 
462878ed226SJulian Elischer /*
463878ed226SJulian Elischer  * Get next available channel ID
464878ed226SJulian Elischer  * XXX FIXME this is *UGLY* but will do for now
465878ed226SJulian Elischer  */
466878ed226SJulian Elischer 
467878ed226SJulian Elischer static u_int16_t
468878ed226SJulian Elischer ng_l2cap_get_cid(ng_l2cap_p l2cap)
469878ed226SJulian Elischer {
470878ed226SJulian Elischer 	u_int16_t	cid = l2cap->cid + 1;
471878ed226SJulian Elischer 
472878ed226SJulian Elischer 	if (cid < NG_L2CAP_FIRST_CID)
473878ed226SJulian Elischer 		cid = NG_L2CAP_FIRST_CID;
474878ed226SJulian Elischer 
475878ed226SJulian Elischer 	while (cid != l2cap->cid) {
476878ed226SJulian Elischer 		if (ng_l2cap_chan_by_scid(l2cap, cid) == NULL) {
477878ed226SJulian Elischer 			l2cap->cid = cid;
478878ed226SJulian Elischer 
479878ed226SJulian Elischer 			return (cid);
480878ed226SJulian Elischer 		}
481878ed226SJulian Elischer 
482878ed226SJulian Elischer 		cid ++;
483878ed226SJulian Elischer 		if (cid < NG_L2CAP_FIRST_CID)
484878ed226SJulian Elischer 			cid = NG_L2CAP_FIRST_CID;
485878ed226SJulian Elischer 	}
486878ed226SJulian Elischer 
487878ed226SJulian Elischer 	return (NG_L2CAP_NULL_CID);
488878ed226SJulian Elischer } /* ng_l2cap_get_cid */
489878ed226SJulian Elischer 
490878ed226SJulian Elischer /*
491878ed226SJulian Elischer  * Get next available command ident
492878ed226SJulian Elischer  * XXX FIXME this is *UGLY* but will do for now
493878ed226SJulian Elischer  */
494878ed226SJulian Elischer 
495878ed226SJulian Elischer u_int8_t
496878ed226SJulian Elischer ng_l2cap_get_ident(ng_l2cap_con_p con)
497878ed226SJulian Elischer {
498878ed226SJulian Elischer 	u_int8_t	ident = con->ident + 1;
499878ed226SJulian Elischer 
500878ed226SJulian Elischer 	if (ident < NG_L2CAP_FIRST_IDENT)
501878ed226SJulian Elischer 		ident = NG_L2CAP_FIRST_IDENT;
502878ed226SJulian Elischer 
503878ed226SJulian Elischer 	while (ident != con->ident) {
504878ed226SJulian Elischer 		if (ng_l2cap_cmd_by_ident(con, ident) == NULL) {
505878ed226SJulian Elischer 			con->ident = ident;
506878ed226SJulian Elischer 
507878ed226SJulian Elischer 			return (ident);
508878ed226SJulian Elischer 		}
509878ed226SJulian Elischer 
510878ed226SJulian Elischer 		ident ++;
511878ed226SJulian Elischer 		if (ident < NG_L2CAP_FIRST_IDENT)
512878ed226SJulian Elischer 			ident = NG_L2CAP_FIRST_IDENT;
513878ed226SJulian Elischer 	}
514878ed226SJulian Elischer 
515878ed226SJulian Elischer 	return (NG_L2CAP_NULL_IDENT);
516878ed226SJulian Elischer } /* ng_l2cap_get_ident */
517878ed226SJulian Elischer 
518