ng_l2cap_misc.c revision 107120
1107120Sjulian/*
2107120Sjulian * ng_l2cap_misc.c
3107120Sjulian *
4107120Sjulian * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
5107120Sjulian * All rights reserved.
6107120Sjulian *
7107120Sjulian * Redistribution and use in source and binary forms, with or without
8107120Sjulian * modification, are permitted provided that the following conditions
9107120Sjulian * are met:
10107120Sjulian * 1. Redistributions of source code must retain the above copyright
11107120Sjulian *    notice, this list of conditions and the following disclaimer.
12107120Sjulian * 2. Redistributions in binary form must reproduce the above copyright
13107120Sjulian *    notice, this list of conditions and the following disclaimer in the
14107120Sjulian *    documentation and/or other materials provided with the distribution.
15107120Sjulian *
16107120Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17107120Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18107120Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19107120Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20107120Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21107120Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22107120Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23107120Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24107120Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25107120Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26107120Sjulian * SUCH DAMAGE.
27107120Sjulian *
28107120Sjulian * $Id: ng_l2cap_misc.c,v 1.16 2002/09/04 21:38:38 max Exp $
29107120Sjulian * $FreeBSD: head/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.c 107120 2002-11-20 23:01:59Z julian $
30107120Sjulian */
31107120Sjulian
32107120Sjulian#include <sys/param.h>
33107120Sjulian#include <sys/systm.h>
34107120Sjulian#include <sys/kernel.h>
35107120Sjulian#include <sys/malloc.h>
36107120Sjulian#include <sys/mbuf.h>
37107120Sjulian#include <sys/queue.h>
38107120Sjulian#include <netgraph/ng_message.h>
39107120Sjulian#include <netgraph/netgraph.h>
40107120Sjulian#include "ng_bluetooth.h"
41107120Sjulian#include "ng_hci.h"
42107120Sjulian#include "ng_l2cap.h"
43107120Sjulian#include "ng_l2cap_var.h"
44107120Sjulian#include "ng_l2cap_cmds.h"
45107120Sjulian#include "ng_l2cap_evnt.h"
46107120Sjulian#include "ng_l2cap_llpi.h"
47107120Sjulian#include "ng_l2cap_ulpi.h"
48107120Sjulian#include "ng_l2cap_misc.h"
49107120Sjulian
50107120Sjulianstatic u_int16_t	ng_l2cap_get_cid		(ng_l2cap_p);
51107120Sjulianstatic void		ng_l2cap_queue_lp_timeout	(void *);
52107120Sjulianstatic void		ng_l2cap_queue_command_timeout	(void *);
53107120Sjulian
54107120Sjulian/******************************************************************************
55107120Sjulian ******************************************************************************
56107120Sjulian **                              Utility routines
57107120Sjulian ******************************************************************************
58107120Sjulian ******************************************************************************/
59107120Sjulian
60107120Sjulian/*
61107120Sjulian * Send hook information to the upper layer
62107120Sjulian */
63107120Sjulian
64107120Sjulianvoid
65107120Sjulianng_l2cap_send_hook_info(node_p node, hook_p hook, void *arg1, int arg2)
66107120Sjulian{
67107120Sjulian	ng_l2cap_p	 l2cap = NULL;
68107120Sjulian	struct ng_mesg	*msg = NULL;
69107120Sjulian	int		 error = 0;
70107120Sjulian
71107120Sjulian	if (node == NULL || NG_NODE_NOT_VALID(node) ||
72107120Sjulian	    hook == NULL || NG_HOOK_NOT_VALID(hook))
73107120Sjulian		return;
74107120Sjulian
75107120Sjulian	l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
76107120Sjulian	if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci) ||
77107120Sjulian	    bcmp(&l2cap->bdaddr, NG_HCI_BDADDR_ANY, sizeof(l2cap->bdaddr)) == 0)
78107120Sjulian		return;
79107120Sjulian
80107120Sjulian	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_HOOK_INFO,
81107120Sjulian		sizeof(bdaddr_t), M_NOWAIT);
82107120Sjulian	if (msg != NULL) {
83107120Sjulian		bcopy(&l2cap->bdaddr, msg->data, sizeof(bdaddr_t));
84107120Sjulian		NG_SEND_MSG_HOOK(error, node, msg, hook, NULL);
85107120Sjulian	} else
86107120Sjulian		error = ENOMEM;
87107120Sjulian
88107120Sjulian	if (error != 0)
89107120Sjulian		NG_L2CAP_INFO(
90107120Sjulian"%s: %s - failed to send HOOK_INFO message to hook \"%s\", error=%d\n",
91107120Sjulian			__func__, NG_NODE_NAME(l2cap->node), NG_HOOK_NAME(hook),
92107120Sjulian			error);
93107120Sjulian} /* ng_l2cap_send_hook_info */
94107120Sjulian
95107120Sjulian/*
96107120Sjulian * Create new connection descriptor for the "remote" unit. Will create new
97107120Sjulian * connection descriptor and signal channel. Will link both connection and
98107120Sjulian * channel to the l2cap node.
99107120Sjulian */
100107120Sjulian
101107120Sjulianng_l2cap_con_p
102107120Sjulianng_l2cap_new_con(ng_l2cap_p l2cap, bdaddr_p bdaddr)
103107120Sjulian{
104107120Sjulian	ng_l2cap_con_p	con = NULL;
105107120Sjulian
106107120Sjulian	/* Create new connection descriptor */
107107120Sjulian	MALLOC(con, ng_l2cap_con_p, sizeof(*con), M_NETGRAPH_L2CAP,
108107120Sjulian		M_NOWAIT|M_ZERO);
109107120Sjulian	if (con == NULL)
110107120Sjulian		return (NULL);
111107120Sjulian
112107120Sjulian	con->l2cap = l2cap;
113107120Sjulian	con->state = NG_L2CAP_CON_CLOSED;
114107120Sjulian
115107120Sjulian	bcopy(bdaddr, &con->remote, sizeof(con->remote));
116107120Sjulian	callout_handle_init(&con->con_timo);
117107120Sjulian
118107120Sjulian	con->ident = NG_L2CAP_FIRST_IDENT - 1;
119107120Sjulian	TAILQ_INIT(&con->cmd_list);
120107120Sjulian
121107120Sjulian	/* Link connection */
122107120Sjulian	LIST_INSERT_HEAD(&l2cap->con_list, con, next);
123107120Sjulian
124107120Sjulian	return (con);
125107120Sjulian} /* ng_l2cap_new_con */
126107120Sjulian
127107120Sjulian/*
128107120Sjulian * Free connection descriptor. Will unlink connection and free everything.
129107120Sjulian */
130107120Sjulian
131107120Sjulianvoid
132107120Sjulianng_l2cap_free_con(ng_l2cap_con_p con)
133107120Sjulian{
134107120Sjulian	ng_l2cap_chan_p f = NULL, n = NULL;
135107120Sjulian
136107120Sjulian	if (con->state == NG_L2CAP_W4_LP_CON_CFM)
137107120Sjulian		ng_l2cap_lp_untimeout(con);
138107120Sjulian
139107120Sjulian	if (con->tx_pkt != NULL) {
140107120Sjulian		while (con->tx_pkt != NULL) {
141107120Sjulian			struct mbuf	*m = con->tx_pkt->m_nextpkt;
142107120Sjulian
143107120Sjulian			m_freem(con->tx_pkt);
144107120Sjulian			con->tx_pkt = m;
145107120Sjulian		}
146107120Sjulian	}
147107120Sjulian
148107120Sjulian	NG_FREE_M(con->rx_pkt);
149107120Sjulian
150107120Sjulian	for (f = LIST_FIRST(&con->l2cap->chan_list); f != NULL; ) {
151107120Sjulian		n = LIST_NEXT(f, next);
152107120Sjulian
153107120Sjulian		if (f->con == con)
154107120Sjulian			ng_l2cap_free_chan(f);
155107120Sjulian
156107120Sjulian		f = n;
157107120Sjulian	}
158107120Sjulian
159107120Sjulian	while (!TAILQ_EMPTY(&con->cmd_list)) {
160107120Sjulian		ng_l2cap_cmd_p	cmd = TAILQ_FIRST(&con->cmd_list);
161107120Sjulian
162107120Sjulian		ng_l2cap_unlink_cmd(cmd);
163107120Sjulian		ng_l2cap_free_cmd(cmd);
164107120Sjulian	}
165107120Sjulian
166107120Sjulian	LIST_REMOVE(con, next);
167107120Sjulian	bzero(con, sizeof(*con));
168107120Sjulian	FREE(con, M_NETGRAPH_L2CAP);
169107120Sjulian} /* ng_l2cap_free_con */
170107120Sjulian
171107120Sjulian/*
172107120Sjulian * Get connection by "remote" address
173107120Sjulian */
174107120Sjulian
175107120Sjulianng_l2cap_con_p
176107120Sjulianng_l2cap_con_by_addr(ng_l2cap_p l2cap, bdaddr_p bdaddr)
177107120Sjulian{
178107120Sjulian	ng_l2cap_con_p	con = NULL;
179107120Sjulian
180107120Sjulian	LIST_FOREACH(con, &l2cap->con_list, next)
181107120Sjulian		if (bcmp(bdaddr, &con->remote, sizeof(con->remote)) == 0)
182107120Sjulian			break;
183107120Sjulian
184107120Sjulian	return (con);
185107120Sjulian} /* ng_l2cap_con_by_addr */
186107120Sjulian
187107120Sjulian/*
188107120Sjulian * Get connection by "handle"
189107120Sjulian */
190107120Sjulian
191107120Sjulianng_l2cap_con_p
192107120Sjulianng_l2cap_con_by_handle(ng_l2cap_p l2cap, u_int16_t con_handle)
193107120Sjulian{
194107120Sjulian	ng_l2cap_con_p	con = NULL;
195107120Sjulian
196107120Sjulian	LIST_FOREACH(con, &l2cap->con_list, next)
197107120Sjulian		if (con->con_handle == con_handle)
198107120Sjulian			break;
199107120Sjulian
200107120Sjulian	return (con);
201107120Sjulian} /* ng_l2cap_con_by_handle */
202107120Sjulian
203107120Sjulian/*
204107120Sjulian * Allocate new L2CAP channel descriptor on "con" conection with "psm".
205107120Sjulian * Will link the channel to the l2cap node
206107120Sjulian */
207107120Sjulian
208107120Sjulianng_l2cap_chan_p
209107120Sjulianng_l2cap_new_chan(ng_l2cap_p l2cap, ng_l2cap_con_p con, u_int16_t psm)
210107120Sjulian{
211107120Sjulian	ng_l2cap_chan_p	ch = NULL;
212107120Sjulian
213107120Sjulian	MALLOC(ch, ng_l2cap_chan_p, sizeof(*ch), M_NETGRAPH_L2CAP,
214107120Sjulian		M_NOWAIT|M_ZERO);
215107120Sjulian	if (ch == NULL)
216107120Sjulian		return (NULL);
217107120Sjulian
218107120Sjulian	ch->scid = ng_l2cap_get_cid(l2cap);
219107120Sjulian
220107120Sjulian	if (ch->scid != NG_L2CAP_NULL_CID) {
221107120Sjulian		/* Initialize channel */
222107120Sjulian		ch->psm = psm;
223107120Sjulian		ch->con = con;
224107120Sjulian		ch->state = NG_L2CAP_CLOSED;
225107120Sjulian
226107120Sjulian		/* Set MTU and flow control settings to defaults */
227107120Sjulian		ch->imtu = NG_L2CAP_MTU_DEFAULT;
228107120Sjulian		bcopy(ng_l2cap_default_flow(), &ch->iflow, sizeof(ch->iflow));
229107120Sjulian
230107120Sjulian		ch->omtu = NG_L2CAP_MTU_DEFAULT;
231107120Sjulian		bcopy(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow));
232107120Sjulian
233107120Sjulian		ch->flush_timo = NG_L2CAP_FLUSH_TIMO_DEFAULT;
234107120Sjulian		ch->link_timo = NG_L2CAP_LINK_TIMO_DEFAULT;
235107120Sjulian
236107120Sjulian		LIST_INSERT_HEAD(&l2cap->chan_list, ch, next);
237107120Sjulian	} else {
238107120Sjulian		bzero(ch, sizeof(*ch));
239107120Sjulian		FREE(ch, M_NETGRAPH_L2CAP);
240107120Sjulian		ch = NULL;
241107120Sjulian	}
242107120Sjulian
243107120Sjulian	return (ch);
244107120Sjulian} /* ng_l2cap_new_chan */
245107120Sjulian
246107120Sjulian/*
247107120Sjulian * Get channel by source (local) channel ID
248107120Sjulian */
249107120Sjulian
250107120Sjulianng_l2cap_chan_p
251107120Sjulianng_l2cap_chan_by_scid(ng_l2cap_p l2cap, u_int16_t scid)
252107120Sjulian{
253107120Sjulian	ng_l2cap_chan_p	ch = NULL;
254107120Sjulian
255107120Sjulian	LIST_FOREACH(ch, &l2cap->chan_list, next)
256107120Sjulian		if (ch->scid == scid)
257107120Sjulian			break;
258107120Sjulian
259107120Sjulian	return (ch);
260107120Sjulian} /* ng_l2cap_chan_by_scid */
261107120Sjulian
262107120Sjulian/*
263107120Sjulian * Free channel descriptor.
264107120Sjulian */
265107120Sjulian
266107120Sjulianvoid
267107120Sjulianng_l2cap_free_chan(ng_l2cap_chan_p ch)
268107120Sjulian{
269107120Sjulian	ng_l2cap_cmd_p	f = NULL, n = NULL;
270107120Sjulian
271107120Sjulian	f = TAILQ_FIRST(&ch->con->cmd_list);
272107120Sjulian	while (f != NULL) {
273107120Sjulian		n = TAILQ_NEXT(f, next);
274107120Sjulian
275107120Sjulian		if (f->ch == ch) {
276107120Sjulian			ng_l2cap_unlink_cmd(f);
277107120Sjulian			ng_l2cap_free_cmd(f);
278107120Sjulian		}
279107120Sjulian
280107120Sjulian		f = n;
281107120Sjulian	}
282107120Sjulian
283107120Sjulian	LIST_REMOVE(ch, next);
284107120Sjulian	bzero(ch, sizeof(*ch));
285107120Sjulian	FREE(ch, M_NETGRAPH_L2CAP);
286107120Sjulian} /* ng_l2cap_free_chan */
287107120Sjulian
288107120Sjulian/*
289107120Sjulian * Create new L2CAP command descriptor. WILL NOT add command to the queue.
290107120Sjulian */
291107120Sjulian
292107120Sjulianng_l2cap_cmd_p
293107120Sjulianng_l2cap_new_cmd(ng_l2cap_con_p con, ng_l2cap_chan_p ch, u_int8_t ident,
294107120Sjulian		u_int8_t code, u_int32_t token)
295107120Sjulian{
296107120Sjulian	ng_l2cap_cmd_p	cmd = NULL;
297107120Sjulian
298107120Sjulian	KASSERT((ch == NULL || ch->con == con),
299107120Sjulian("%s: %s - invalid channel pointer!\n",
300107120Sjulian		__func__, NG_NODE_NAME(con->l2cap->node)));
301107120Sjulian
302107120Sjulian	MALLOC(cmd, ng_l2cap_cmd_p, sizeof(*cmd), M_NETGRAPH_L2CAP,
303107120Sjulian		M_NOWAIT|M_ZERO);
304107120Sjulian	if (cmd == NULL)
305107120Sjulian		return (NULL);
306107120Sjulian
307107120Sjulian	cmd->con = con;
308107120Sjulian	cmd->ch = ch;
309107120Sjulian	cmd->ident = ident;
310107120Sjulian	cmd->code = code;
311107120Sjulian	cmd->token = token;
312107120Sjulian	callout_handle_init(&cmd->timo);
313107120Sjulian
314107120Sjulian	return (cmd);
315107120Sjulian} /* ng_l2cap_new_cmd */
316107120Sjulian
317107120Sjulian/*
318107120Sjulian * Get L2CAP command descriptor by ident
319107120Sjulian */
320107120Sjulian
321107120Sjulianng_l2cap_cmd_p
322107120Sjulianng_l2cap_cmd_by_ident(ng_l2cap_con_p con, u_int8_t ident)
323107120Sjulian{
324107120Sjulian	ng_l2cap_cmd_p	cmd = NULL;
325107120Sjulian
326107120Sjulian	TAILQ_FOREACH(cmd, &con->cmd_list, next)
327107120Sjulian		if (cmd->ident == ident)
328107120Sjulian			break;
329107120Sjulian
330107120Sjulian	return (cmd);
331107120Sjulian} /* ng_l2cap_cmd_by_ident */
332107120Sjulian
333107120Sjulian/*
334107120Sjulian * Set LP timeout
335107120Sjulian */
336107120Sjulian
337107120Sjulianvoid
338107120Sjulianng_l2cap_lp_timeout(ng_l2cap_con_p con)
339107120Sjulian{
340107120Sjulian	NG_NODE_REF(con->l2cap->node);
341107120Sjulian	con->con_timo = timeout(ng_l2cap_queue_lp_timeout, con,
342107120Sjulian				bluetooth_hci_connect_timeout());
343107120Sjulian} /* ng_l2cap_lp_timeout */
344107120Sjulian
345107120Sjulian/*
346107120Sjulian * Unset LP timeout
347107120Sjulian */
348107120Sjulian
349107120Sjulianvoid
350107120Sjulianng_l2cap_lp_untimeout(ng_l2cap_con_p con)
351107120Sjulian{
352107120Sjulian	untimeout(ng_l2cap_queue_lp_timeout, con, con->con_timo);
353107120Sjulian	NG_NODE_UNREF(con->l2cap->node);
354107120Sjulian} /* ng_l2cap_lp_untimeout */
355107120Sjulian
356107120Sjulian/*
357107120Sjulian * OK, timeout has happend so queue LP timeout processing function
358107120Sjulian */
359107120Sjulian
360107120Sjulianstatic void
361107120Sjulianng_l2cap_queue_lp_timeout(void *context)
362107120Sjulian{
363107120Sjulian	ng_l2cap_con_p	con = (ng_l2cap_con_p) context;
364107120Sjulian	node_p		node = con->l2cap->node;
365107120Sjulian
366107120Sjulian	/*
367107120Sjulian	 * We need to save node pointer here, because ng_send_fn()
368107120Sjulian	 * can execute ng_l2cap_process_lp_timeout() without putting
369107120Sjulian	 * item into node's queue (if node can be locked). Once
370107120Sjulian	 * ng_l2cap_process_lp_timeout() executed the con pointer
371107120Sjulian	 * is no longer valid.
372107120Sjulian	 */
373107120Sjulian
374107120Sjulian	if (NG_NODE_IS_VALID(node))
375107120Sjulian		ng_send_fn(node, NULL, &ng_l2cap_process_lp_timeout, con, 0);
376107120Sjulian
377107120Sjulian	NG_NODE_UNREF(node);
378107120Sjulian} /* ng_l2cap_queue_lp_timeout */
379107120Sjulian
380107120Sjulian/*
381107120Sjulian * Set L2CAP command timeout
382107120Sjulian */
383107120Sjulian
384107120Sjulianvoid
385107120Sjulianng_l2cap_command_timeout(ng_l2cap_cmd_p cmd, int timo)
386107120Sjulian{
387107120Sjulian	NG_NODE_REF(cmd->con->l2cap->node);
388107120Sjulian	cmd->flags |= NG_L2CAP_CMD_PENDING;
389107120Sjulian	cmd->timo = timeout(ng_l2cap_queue_command_timeout, cmd, timo);
390107120Sjulian} /* ng_l2cap_command_timeout */
391107120Sjulian
392107120Sjulian/*
393107120Sjulian * Unset L2CAP command timeout
394107120Sjulian */
395107120Sjulian
396107120Sjulianvoid
397107120Sjulianng_l2cap_command_untimeout(ng_l2cap_cmd_p cmd)
398107120Sjulian{
399107120Sjulian	cmd->flags &= ~NG_L2CAP_CMD_PENDING;
400107120Sjulian	untimeout(ng_l2cap_queue_command_timeout, cmd, cmd->timo);
401107120Sjulian	NG_NODE_UNREF(cmd->con->l2cap->node);
402107120Sjulian} /* ng_l2cap_command_untimeout */
403107120Sjulian
404107120Sjulian/*
405107120Sjulian * OK, timeout has happend so queue L2CAP command timeout processing function
406107120Sjulian */
407107120Sjulian
408107120Sjulianstatic void
409107120Sjulianng_l2cap_queue_command_timeout(void *context)
410107120Sjulian{
411107120Sjulian	ng_l2cap_cmd_p	cmd = (ng_l2cap_cmd_p) context;
412107120Sjulian	node_p		node = cmd->con->l2cap->node;
413107120Sjulian
414107120Sjulian	/*
415107120Sjulian	 * We need to save node pointer here, because ng_send_fn()
416107120Sjulian	 * can execute ng_l2cap_process_command_timeout() without
417107120Sjulian	 * putting item into node's queue (if node can be locked).
418107120Sjulian	 * Once ng_l2cap_process_command_timeout() executed the
419107120Sjulian	 * cmd pointer is no longer valid.
420107120Sjulian	 */
421107120Sjulian
422107120Sjulian	if (NG_NODE_IS_VALID(node))
423107120Sjulian		ng_send_fn(node,NULL,&ng_l2cap_process_command_timeout,cmd,0);
424107120Sjulian
425107120Sjulian	NG_NODE_UNREF(node);
426107120Sjulian} /* ng_l2cap_queue_command_timeout */
427107120Sjulian
428107120Sjulian/*
429107120Sjulian * Prepend "m"buf with "size" bytes
430107120Sjulian */
431107120Sjulian
432107120Sjulianstruct mbuf *
433107120Sjulianng_l2cap_prepend(struct mbuf *m, int size)
434107120Sjulian{
435107120Sjulian	M_PREPEND(m, size, M_DONTWAIT);
436107120Sjulian	if (m == NULL || (m->m_len < size && (m = m_pullup(m, size)) == NULL))
437107120Sjulian		return (NULL);
438107120Sjulian
439107120Sjulian	return (m);
440107120Sjulian} /* ng_l2cap_prepend */
441107120Sjulian
442107120Sjulian/*
443107120Sjulian * Default flow settings
444107120Sjulian */
445107120Sjulian
446107120Sjulianng_l2cap_flow_p
447107120Sjulianng_l2cap_default_flow(void)
448107120Sjulian{
449107120Sjulian	static ng_l2cap_flow_t	default_flow = {
450107120Sjulian		/* flags */		0x0,
451107120Sjulian		/* service_type */	NG_HCI_SERVICE_TYPE_BEST_EFFORT,
452107120Sjulian		/* token_rate */	0xffffffff, /* maximum */
453107120Sjulian		/* token_bucket_size */	0xffffffff, /* maximum */
454107120Sjulian		/* peak_bandwidth */	0x00000000, /* maximum */
455107120Sjulian		/* latency */		0xffffffff, /* don't care */
456107120Sjulian		/* delay_variation */	0xffffffff  /* don't care */
457107120Sjulian	};
458107120Sjulian
459107120Sjulian	return (&default_flow);
460107120Sjulian} /* ng_l2cap_default_flow */
461107120Sjulian
462107120Sjulian/*
463107120Sjulian * Get next available channel ID
464107120Sjulian * XXX FIXME this is *UGLY* but will do for now
465107120Sjulian */
466107120Sjulian
467107120Sjulianstatic u_int16_t
468107120Sjulianng_l2cap_get_cid(ng_l2cap_p l2cap)
469107120Sjulian{
470107120Sjulian	u_int16_t	cid = l2cap->cid + 1;
471107120Sjulian
472107120Sjulian	if (cid < NG_L2CAP_FIRST_CID)
473107120Sjulian		cid = NG_L2CAP_FIRST_CID;
474107120Sjulian
475107120Sjulian	while (cid != l2cap->cid) {
476107120Sjulian		if (ng_l2cap_chan_by_scid(l2cap, cid) == NULL) {
477107120Sjulian			l2cap->cid = cid;
478107120Sjulian
479107120Sjulian			return (cid);
480107120Sjulian		}
481107120Sjulian
482107120Sjulian		cid ++;
483107120Sjulian		if (cid < NG_L2CAP_FIRST_CID)
484107120Sjulian			cid = NG_L2CAP_FIRST_CID;
485107120Sjulian	}
486107120Sjulian
487107120Sjulian	return (NG_L2CAP_NULL_CID);
488107120Sjulian} /* ng_l2cap_get_cid */
489107120Sjulian
490107120Sjulian/*
491107120Sjulian * Get next available command ident
492107120Sjulian * XXX FIXME this is *UGLY* but will do for now
493107120Sjulian */
494107120Sjulian
495107120Sjulianu_int8_t
496107120Sjulianng_l2cap_get_ident(ng_l2cap_con_p con)
497107120Sjulian{
498107120Sjulian	u_int8_t	ident = con->ident + 1;
499107120Sjulian
500107120Sjulian	if (ident < NG_L2CAP_FIRST_IDENT)
501107120Sjulian		ident = NG_L2CAP_FIRST_IDENT;
502107120Sjulian
503107120Sjulian	while (ident != con->ident) {
504107120Sjulian		if (ng_l2cap_cmd_by_ident(con, ident) == NULL) {
505107120Sjulian			con->ident = ident;
506107120Sjulian
507107120Sjulian			return (ident);
508107120Sjulian		}
509107120Sjulian
510107120Sjulian		ident ++;
511107120Sjulian		if (ident < NG_L2CAP_FIRST_IDENT)
512107120Sjulian			ident = NG_L2CAP_FIRST_IDENT;
513107120Sjulian	}
514107120Sjulian
515107120Sjulian	return (NG_L2CAP_NULL_IDENT);
516107120Sjulian} /* ng_l2cap_get_ident */
517107120Sjulian
518