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