1/*
2 * ng_l2cap_ulpi.c
3 */
4
5/*-
6 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $Id: ng_l2cap_ulpi.c,v 1.1 2002/11/24 19:47:06 max Exp $
31 * $FreeBSD$
32 */
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/endian.h>
38#include <sys/malloc.h>
39#include <sys/mbuf.h>
40#include <sys/queue.h>
41#include <netgraph/ng_message.h>
42#include <netgraph/netgraph.h>
43#include <netgraph/bluetooth/include/ng_hci.h>
44#include <netgraph/bluetooth/include/ng_l2cap.h>
45#include <netgraph/bluetooth/l2cap/ng_l2cap_var.h>
46#include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h>
47#include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h>
48#include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h>
49#include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>
50#include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>
51
52/******************************************************************************
53 ******************************************************************************
54 **                 Upper Layer Protocol Interface module
55 ******************************************************************************
56 ******************************************************************************/
57
58/*
59 * Process L2CA_Connect request from the upper layer protocol.
60 */
61
62int
63ng_l2cap_l2ca_con_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
64{
65	ng_l2cap_l2ca_con_ip	*ip = NULL;
66	ng_l2cap_con_p		 con = NULL;
67	ng_l2cap_chan_p		 ch = NULL;
68	ng_l2cap_cmd_p		 cmd = NULL;
69	int			 error = 0;
70
71	/* Check message */
72	if (msg->header.arglen != sizeof(*ip)) {
73		NG_L2CAP_ALERT(
74"%s: %s - invalid L2CA_Connect request message size, size=%d\n",
75			__func__, NG_NODE_NAME(l2cap->node),
76			msg->header.arglen);
77		error = EMSGSIZE;
78		goto out;
79	}
80
81	ip = (ng_l2cap_l2ca_con_ip *)(msg->data);
82
83	/* Check if we have connection to the remote unit */
84	con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
85	if (con == NULL) {
86		/* Submit LP_ConnectReq to the lower layer */
87		error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);
88		if (error != 0) {
89			NG_L2CAP_ERR(
90"%s: %s - unable to send LP_ConnectReq message, error=%d\n",
91				__func__, NG_NODE_NAME(l2cap->node), error);
92			goto out;
93		}
94
95		/* This should not fail */
96		con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
97		KASSERT((con != NULL),
98("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
99	}
100
101	/*
102	 * Create new empty channel descriptor. In case of any failure do
103	 * not touch connection descriptor.
104	 */
105
106	ch = ng_l2cap_new_chan(l2cap, con, ip->psm, ip->idtype);
107	if (ch == NULL) {
108		error = ENOMEM;
109		goto out;
110	}
111
112	/* Now create L2CAP_ConnectReq command */
113	cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(con),
114			NG_L2CAP_CON_REQ, msg->header.token);
115	if (cmd == NULL) {
116		ng_l2cap_free_chan(ch);
117		error = ENOMEM;
118		goto out;
119	}
120
121	if (cmd->ident == NG_L2CAP_NULL_IDENT) {
122		ng_l2cap_free_cmd(cmd);
123		ng_l2cap_free_chan(ch);
124		error = EIO;
125		goto out;
126	}
127
128	/* Create L2CAP command packet */
129	if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
130		_ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_ATT_CID,
131				  NG_L2CAP_ATT_CID, 0, 0);
132		cmd->aux->m_flags |= M_PROTO2;
133	}else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
134		_ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_SMP_CID,
135				  NG_L2CAP_SMP_CID, 0, 0);
136		cmd->aux->m_flags |= M_PROTO2;
137	}else{
138		_ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid);
139	}
140	if (cmd->aux == NULL) {
141		ng_l2cap_free_cmd(cmd);
142		ng_l2cap_free_chan(ch);
143		error = ENOBUFS;
144		goto out;
145	}
146
147	ch->state = NG_L2CAP_W4_L2CAP_CON_RSP;
148
149	/* Link command to the queue */
150	ng_l2cap_link_cmd(ch->con, cmd);
151	ng_l2cap_lp_deliver(ch->con);
152out:
153	return (error);
154} /* ng_l2cap_l2ca_con_req */
155
156/*
157 * Send L2CA_Connect response to the upper layer protocol.
158 */
159
160int
161ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
162		u_int16_t status)
163{
164	ng_l2cap_p		 l2cap = ch->con->l2cap;
165	struct ng_mesg		*msg = NULL;
166	ng_l2cap_l2ca_con_op	*op = NULL;
167	int			 error = 0;
168
169	/* Check if upstream hook is connected and valid */
170	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
171		NG_L2CAP_ERR(
172"%s: %s - unable to send L2CA_Connect response message. " \
173"Hook is not connected or valid, psm=%d\n",
174			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
175
176		return (ENOTCONN);
177	}
178
179	/* Create and send L2CA_Connect response message */
180	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON,
181		sizeof(*op), M_NOWAIT);
182	if (msg == NULL)
183		error = ENOMEM;
184	else {
185		msg->header.token = token;
186		msg->header.flags |= NGF_RESP;
187
188		op = (ng_l2cap_l2ca_con_op *)(msg->data);
189
190		/*
191		 * XXX Spec. says we should only populate LCID when result == 0
192		 * What about PENDING? What the heck, for now always populate
193		 * LCID :)
194		 */
195		if(ch->scid == NG_L2CAP_ATT_CID){
196			op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
197			op->lcid = ch->con->con_handle;
198		}else if(ch->scid == NG_L2CAP_SMP_CID){
199			op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
200			op->lcid = ch->con->con_handle;
201		}else{
202			op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
203				NG_L2CAP_L2CA_IDTYPE_BREDR :
204				NG_L2CAP_L2CA_IDTYPE_LE;
205			op->lcid = ch->scid;
206		}
207		op->encryption = ch->con->encryption;
208		op->result = result;
209		op->status = status;
210
211		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
212	}
213
214	return (error);
215} /* ng_l2cap_l2ca_con_rsp */
216
217/*
218 * Process L2CA_ConnectRsp request from the upper layer protocol.
219 */
220
221int
222ng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
223{
224	ng_l2cap_l2ca_con_rsp_ip	*ip = NULL;
225	ng_l2cap_con_p			 con = NULL;
226	ng_l2cap_chan_p			 ch = NULL;
227	ng_l2cap_cmd_p			 cmd = NULL;
228	u_int16_t			 dcid;
229	int				 error = 0;
230
231	/* Check message */
232	if (msg->header.arglen != sizeof(*ip)) {
233		NG_L2CAP_ALERT(
234"%s: %s - invalid L2CA_ConnectRsp request message size, size=%d\n",
235			__func__, NG_NODE_NAME(l2cap->node),
236			msg->header.arglen);
237		error = EMSGSIZE;
238		goto out;
239	}
240
241	ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data);
242
243	/* Check if we have this channel */
244	if((ip->lcid != NG_L2CAP_ATT_CID)&&
245	   (ip->lcid != NG_L2CAP_SMP_CID)){
246		ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid
247					   ,(ip->linktype == NG_HCI_LINK_ACL)?
248					   NG_L2CAP_L2CA_IDTYPE_BREDR:
249					   NG_L2CAP_L2CA_IDTYPE_LE);
250	}else{
251		// For now not support on ATT device.
252		ch = NULL;
253	}
254	if (ch == NULL) {
255		NG_L2CAP_ALERT(
256"%s: %s - unexpected L2CA_ConnectRsp request message. " \
257"Channel does not exist, lcid=%d\n",
258			__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
259		error = ENOENT;
260		goto out;
261	}
262
263	/* Check channel state */
264	if (ch->state != NG_L2CAP_W4_L2CA_CON_RSP) {
265		NG_L2CAP_ERR(
266"%s: %s - unexpected L2CA_ConnectRsp request message. " \
267"Invalid channel state, state=%d, lcid=%d\n",
268			__func__, NG_NODE_NAME(l2cap->node), ch->state,
269			ip->lcid);
270		error = EINVAL;
271		goto out;
272	}
273
274	dcid = ch->dcid;
275	con = ch->con;
276
277	/*
278	 * Now we are pretty much sure it is our response. So create and send
279	 * L2CAP_ConnectRsp message to our peer.
280	 */
281
282	if (ch->ident != ip->ident)
283		NG_L2CAP_WARN(
284"%s: %s - channel ident and response ident do not match, scid=%d, ident=%d. " \
285"Will use response ident=%d\n",
286			__func__, NG_NODE_NAME(l2cap->node), ch->scid,
287			ch->ident, ip->ident);
288
289	/* Check result */
290	switch (ip->result) {
291	case NG_L2CAP_SUCCESS:
292		ch->state = ((ch->scid == NG_L2CAP_ATT_CID)||
293			     (ch->scid == NG_L2CAP_SMP_CID))?
294			NG_L2CAP_OPEN : NG_L2CAP_CONFIG;
295		ch->cfg_state = 0;
296		break;
297
298	case NG_L2CAP_PENDING:
299		break;
300
301	default:
302		ng_l2cap_free_chan(ch);
303		ch = NULL;
304		break;
305	}
306
307	/* Create L2CAP command */
308	cmd = ng_l2cap_new_cmd(con, ch, ip->ident, NG_L2CAP_CON_RSP,
309			msg->header.token);
310	if (cmd == NULL) {
311		if (ch != NULL)
312			ng_l2cap_free_chan(ch);
313
314		error = ENOMEM;
315		goto out;
316	}
317
318	_ng_l2cap_con_rsp(cmd->aux, cmd->ident, ip->lcid, dcid,
319		ip->result, ip->status);
320	if (cmd->aux == NULL) {
321		if (ch != NULL)
322			ng_l2cap_free_chan(ch);
323
324		ng_l2cap_free_cmd(cmd);
325		error = ENOBUFS;
326		goto out;
327	}
328
329	/* Link command to the queue */
330	ng_l2cap_link_cmd(con, cmd);
331	ng_l2cap_lp_deliver(con);
332out:
333	return (error);
334} /* ng_l2cap_l2ca_con_rsp_req */
335
336int ng_l2cap_l2ca_encryption_change(ng_l2cap_chan_p ch, uint16_t result)
337{
338	ng_l2cap_p			 l2cap = ch->con->l2cap;
339	struct ng_mesg			*msg = NULL;
340	ng_l2cap_l2ca_enc_chg_op	*op = NULL;
341	int				 error = 0;
342
343	/* Check if upstream hook is connected and valid */
344	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
345		NG_L2CAP_ERR(
346"%s: %s - unable to send L2CA_ConnectRsp response message. " \
347"Hook is not connected or valid, psm=%d\n",
348			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
349
350		return (ENOTCONN);
351	}
352
353	/* Create and send L2CA_ConnectRsp response message */
354	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENC_CHANGE,
355		sizeof(*op), M_NOWAIT);
356	if (msg == NULL)
357		error = ENOMEM;
358	else {
359		msg->header.token = 0;
360		msg->header.flags |= NGF_RESP;
361
362		op = (ng_l2cap_l2ca_enc_chg_op *)(msg->data);
363		op->result = result;
364		if(ch->scid ==NG_L2CAP_ATT_CID||
365		   ch->scid ==NG_L2CAP_SMP_CID){
366			op->lcid = ch->con->con_handle;
367			op->idtype = (ch->scid==NG_L2CAP_ATT_CID)?
368				NG_L2CAP_L2CA_IDTYPE_ATT:
369				NG_L2CAP_L2CA_IDTYPE_SMP;
370		}else{
371			op->idtype =(ch->con->linktype ==NG_HCI_LINK_ACL)?
372				NG_L2CAP_L2CA_IDTYPE_BREDR:
373				NG_L2CAP_L2CA_IDTYPE_LE;
374		}
375
376
377		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
378	}
379
380	return (error);
381
382}
383/*
384 * Send L2CAP_ConnectRsp response to the upper layer
385 */
386
387int
388ng_l2cap_l2ca_con_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
389{
390	ng_l2cap_p			 l2cap = ch->con->l2cap;
391	struct ng_mesg			*msg = NULL;
392	ng_l2cap_l2ca_con_rsp_op	*op = NULL;
393	int				 error = 0;
394
395	/* Check if upstream hook is connected and valid */
396	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
397		NG_L2CAP_ERR(
398"%s: %s - unable to send L2CA_ConnectRsp response message. " \
399"Hook is not connected or valid, psm=%d\n",
400			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
401
402		return (ENOTCONN);
403	}
404
405	/* Create and send L2CA_ConnectRsp response message */
406	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_RSP,
407		sizeof(*op), M_NOWAIT);
408	if (msg == NULL)
409		error = ENOMEM;
410	else {
411		msg->header.token = token;
412		msg->header.flags |= NGF_RESP;
413
414		op = (ng_l2cap_l2ca_con_rsp_op *)(msg->data);
415		op->result = result;
416
417		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
418	}
419
420	return (error);
421} /* ng_l2cap_l2ca_con_rsp_rsp */
422
423/*
424 * Send L2CA_ConnectInd message to the upper layer protocol.
425 */
426
427int
428ng_l2cap_l2ca_con_ind(ng_l2cap_chan_p ch)
429{
430	ng_l2cap_p			 l2cap = ch->con->l2cap;
431	struct ng_mesg			*msg = NULL;
432	ng_l2cap_l2ca_con_ind_ip	*ip = NULL;
433	int				 error = 0;
434
435	/* Check if upstream hook is connected and valid */
436	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
437		NG_L2CAP_ERR(
438"%s: %s - unable to send L2CA_ConnectInd message. " \
439"Hook is not connected or valid, psm=%d\n",
440			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
441
442		return (ENOTCONN);
443	}
444
445	/* Create and send L2CA_ConnectInd message */
446	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_IND,
447		sizeof(*ip), M_NOWAIT);
448	if (msg == NULL)
449		error = ENOMEM;
450	else {
451		ip = (ng_l2cap_l2ca_con_ind_ip *)(msg->data);
452
453		bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr));
454		ip->lcid = ch->scid;
455		ip->psm = ch->psm;
456		ip->ident = ch->ident;
457		ip->linktype = ch->con->linktype;
458
459		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
460	}
461
462	return (error);
463} /* ng_l2cap_l2ca_con_ind */
464
465/*
466 * Process L2CA_Config request from the upper layer protocol
467 */
468
469int
470ng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
471{
472	ng_l2cap_l2ca_cfg_ip	*ip = NULL;
473	ng_l2cap_chan_p		 ch = NULL;
474	ng_l2cap_cmd_p		 cmd = NULL;
475	struct mbuf		*opt = NULL;
476        u_int16_t		*mtu = NULL, *flush_timo = NULL;
477        ng_l2cap_flow_p		 flow = NULL;
478	int			 error = 0;
479
480	/* Check message */
481	if (msg->header.arglen != sizeof(*ip)) {
482		NG_L2CAP_ALERT(
483"%s: %s - Invalid L2CA_Config request message size, size=%d\n",
484			__func__, NG_NODE_NAME(l2cap->node),
485			msg->header.arglen);
486		error = EMSGSIZE;
487		goto out;
488	}
489
490	ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data);
491
492	/* Check if we have this channel */
493	ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, NG_L2CAP_L2CA_IDTYPE_BREDR);
494	if (ch == NULL) {
495		NG_L2CAP_ERR(
496"%s: %s - unexpected L2CA_Config request message. " \
497"Channel does not exist, lcid=%d\n",
498			__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
499		error = ENOENT;
500		goto out;
501	}
502
503	/* Check channel state */
504	if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG) {
505		NG_L2CAP_ERR(
506"%s: %s - unexpected L2CA_Config request message. " \
507"Invalid channel state, state=%d, lcid=%d\n",
508			__func__, NG_NODE_NAME(l2cap->node), ch->state,
509			ch->scid);
510		error = EINVAL;
511		goto out;
512	}
513
514	/* Set requested channel configuration options */
515	ch->imtu = ip->imtu;
516	bcopy(&ip->oflow, &ch->oflow, sizeof(ch->oflow));
517	ch->flush_timo = ip->flush_timo;
518	ch->link_timo = ip->link_timo;
519
520	/* Compare channel settings with defaults */
521	if (ch->imtu != NG_L2CAP_MTU_DEFAULT)
522		mtu = &ch->imtu;
523	if (ch->flush_timo != NG_L2CAP_FLUSH_TIMO_DEFAULT)
524		flush_timo = &ch->flush_timo;
525	if (bcmp(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)) != 0)
526		flow = &ch->oflow;
527
528	/* Create configuration options */
529	_ng_l2cap_build_cfg_options(opt, mtu, flush_timo, flow);
530	if (opt == NULL) {
531                error = ENOBUFS;
532		goto out;
533	}
534
535	/* Create L2CAP command descriptor */
536	cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con),
537			NG_L2CAP_CFG_REQ, msg->header.token);
538	if (cmd == NULL) {
539		NG_FREE_M(opt);
540		error = ENOMEM;
541		goto out;
542	}
543
544	if (cmd->ident == NG_L2CAP_NULL_IDENT) {
545		ng_l2cap_free_cmd(cmd);
546		NG_FREE_M(opt);
547		error = EIO;
548		goto out;
549	}
550
551	/* Create L2CAP command packet */
552	_ng_l2cap_cfg_req(cmd->aux, cmd->ident, ch->dcid, 0, opt);
553	if (cmd->aux == NULL) {
554		ng_l2cap_free_cmd(cmd);
555		error =  ENOBUFS;
556		goto out;
557	}
558
559	/* Adjust channel state for re-configuration */
560	if (ch->state == NG_L2CAP_OPEN) {
561		ch->state = ((ch->scid == NG_L2CAP_ATT_CID)||
562			     (ch->scid == NG_L2CAP_SMP_CID))?
563			NG_L2CAP_OPEN : NG_L2CAP_CONFIG;
564		ch->cfg_state = 0;
565	}
566
567        /* Link command to the queue */
568	ng_l2cap_link_cmd(ch->con, cmd);
569	ng_l2cap_lp_deliver(ch->con);
570out:
571	return (error);
572} /* ng_l2cap_l2ca_cfg_req */
573
574/*
575 * Send L2CA_Config response to the upper layer protocol
576 */
577
578int
579ng_l2cap_l2ca_cfg_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
580{
581	ng_l2cap_p		 l2cap = ch->con->l2cap;
582	struct ng_mesg		*msg = NULL;
583	ng_l2cap_l2ca_cfg_op	*op = NULL;
584	int			 error = 0;
585
586	/* Check if upstream hook is connected and valid */
587	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
588		NG_L2CAP_ERR(
589"%s: %s - unable to send L2CA_Config response message. " \
590"Hook is not connected or valid, psm=%d\n",
591			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
592
593		return (ENOTCONN);
594	}
595
596	/* Create and send L2CA_Config response message */
597	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG,
598		sizeof(*op), M_NOWAIT);
599	if (msg == NULL)
600		error = ENOMEM;
601	else {
602		msg->header.token = token;
603		msg->header.flags |= NGF_RESP;
604
605		op = (ng_l2cap_l2ca_cfg_op *)(msg->data);
606		op->result = result;
607		op->imtu = ch->imtu;
608		bcopy(&ch->oflow, &op->oflow, sizeof(op->oflow));
609		op->flush_timo = ch->flush_timo;
610
611		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
612
613		if (error == 0 && result == NG_L2CAP_SUCCESS) {
614			ch->cfg_state |= NG_L2CAP_CFG_IN;
615
616			if (ch->cfg_state == NG_L2CAP_CFG_BOTH)
617				ch->state = NG_L2CAP_OPEN;
618		}
619	}
620
621	return (error);
622} /* ng_l2cap_l2ca_cfg_rsp */
623
624/*
625 * Process L2CA_ConfigRsp request from the upper layer protocol
626 *
627 * XXX XXX XXX
628 *
629 * NOTE: The Bluetooth specification says that Configuration_Response
630 * (L2CA_ConfigRsp) should be used to issue response to configuration request
631 * indication. The minor problem here is L2CAP command ident. We should use
632 * ident from original L2CAP request to make sure our peer can match request
633 * and response. For some reason Bluetooth specification does not include
634 * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems
635 * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident
636 * field. So we should store last known L2CAP request command ident in channel.
637 * Also it seems that upper layer can not reject configuration request, as
638 * Configuration_Response message does not have status/reason field.
639 */
640
641int
642ng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
643{
644	ng_l2cap_l2ca_cfg_rsp_ip	*ip = NULL;
645	ng_l2cap_chan_p			 ch = NULL;
646	ng_l2cap_cmd_p			 cmd = NULL;
647	struct mbuf			*opt = NULL;
648	u_int16_t			*mtu = NULL;
649	ng_l2cap_flow_p			 flow = NULL;
650	int				 error = 0;
651
652	/* Check message */
653	if (msg->header.arglen != sizeof(*ip)) {
654		NG_L2CAP_ALERT(
655"%s: %s - invalid L2CA_ConfigRsp request message size, size=%d\n",
656			__func__, NG_NODE_NAME(l2cap->node),
657			msg->header.arglen);
658		error = EMSGSIZE;
659		goto out;
660	}
661
662	ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data);
663
664	/* Check if we have this channel */
665	ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid,
666				   NG_L2CAP_L2CA_IDTYPE_BREDR);
667	if (ch == NULL) {
668		NG_L2CAP_ERR(
669"%s: %s - unexpected L2CA_ConfigRsp request message. " \
670"Channel does not exist, lcid=%d\n",
671			__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
672		error = ENOENT;
673		goto out;
674	}
675
676	/* Check channel state */
677	if (ch->state != NG_L2CAP_CONFIG) {
678		NG_L2CAP_ERR(
679"%s: %s - unexpected L2CA_ConfigRsp request message. " \
680"Invalid channel state, state=%d, lcid=%d\n",
681			__func__, NG_NODE_NAME(l2cap->node), ch->state,
682			ch->scid);
683		error = EINVAL;
684		goto out;
685	}
686
687	/* Set channel settings */
688	if (ip->omtu != ch->omtu) {
689		ch->omtu = ip->omtu;
690		mtu = &ch->omtu;
691	}
692
693	if (bcmp(&ip->iflow, &ch->iflow, sizeof(ch->iflow)) != 0) {
694		bcopy(&ip->iflow, &ch->iflow, sizeof(ch->iflow));
695		flow = &ch->iflow;
696	}
697
698	if (mtu != NULL || flow != NULL) {
699		_ng_l2cap_build_cfg_options(opt, mtu, NULL, flow);
700		if (opt == NULL) {
701			error = ENOBUFS;
702			goto out;
703		}
704	}
705
706	/* Create L2CAP command */
707	cmd = ng_l2cap_new_cmd(ch->con, ch, ch->ident, NG_L2CAP_CFG_RSP,
708			msg->header.token);
709	if (cmd == NULL) {
710		NG_FREE_M(opt);
711		error = ENOMEM;
712		goto out;
713	}
714
715	_ng_l2cap_cfg_rsp(cmd->aux,cmd->ident,ch->dcid,0,NG_L2CAP_SUCCESS,opt);
716	if (cmd->aux == NULL) {
717		ng_l2cap_free_cmd(cmd);
718		error = ENOBUFS;
719		goto out;
720	}
721
722	/* XXX FIXME - not here ??? */
723	ch->cfg_state |= NG_L2CAP_CFG_OUT;
724	if (ch->cfg_state == NG_L2CAP_CFG_BOTH)
725		ch->state = NG_L2CAP_OPEN;
726
727	/* Link command to the queue */
728	ng_l2cap_link_cmd(ch->con, cmd);
729	ng_l2cap_lp_deliver(ch->con);
730out:
731	return (error);
732} /* ng_l2cap_l2ca_cfg_rsp_req */
733
734/*
735 * Send L2CA_ConfigRsp response to the upper layer protocol
736 */
737
738int
739ng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
740{
741	ng_l2cap_p			 l2cap = ch->con->l2cap;
742	struct ng_mesg			*msg = NULL;
743	ng_l2cap_l2ca_cfg_rsp_op	*op = NULL;
744	int				 error = 0;
745
746	/* Check if upstream hook is connected and valid */
747	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
748		NG_L2CAP_ERR(
749"%s: %s - unable to send L2CA_ConfigRsp response message. " \
750"Hook is not connected or valid, psm=%d\n",
751			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
752
753		return (ENOTCONN);
754	}
755
756	/* Create and send L2CA_ConfigRsp response message */
757	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP,
758		sizeof(*op), M_NOWAIT);
759	if (msg == NULL)
760		error = ENOMEM;
761	else {
762		msg->header.token = token;
763		msg->header.flags |= NGF_RESP;
764
765		op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data);
766		op->result = result;
767
768		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
769	}
770
771	return (error);
772} /* ng_l2cap_l2ca_cfg_rsp_rsp */
773
774/*
775 * Send L2CA_ConfigInd message to the upper layer protocol
776 *
777 * XXX XXX XXX
778 *
779 * NOTE: The Bluetooth specification says that Configuration_Response
780 * (L2CA_ConfigRsp) should be used to issue response to configuration request
781 * indication. The minor problem here is L2CAP command ident. We should use
782 * ident from original L2CAP request to make sure our peer can match request
783 * and response. For some reason Bluetooth specification does not include
784 * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems
785 * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident
786 * field. So we should store last known L2CAP request command ident in channel.
787 * Also it seems that upper layer can not reject configuration request, as
788 * Configuration_Response message does not have status/reason field.
789 */
790
791int
792ng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch)
793{
794	ng_l2cap_p			 l2cap = ch->con->l2cap;
795	struct ng_mesg			*msg = NULL;
796	ng_l2cap_l2ca_cfg_ind_ip	*ip = NULL;
797	int				 error = 0;
798
799	/* Check if upstream hook is connected and valid */
800	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
801		NG_L2CAP_ERR(
802"%s: %s - Unable to send L2CA_ConfigInd message. " \
803"Hook is not connected or valid, psm=%d\n",
804			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
805
806		return (ENOTCONN);
807	}
808
809	/* Create and send L2CA_ConnectInd message */
810	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_IND,
811			sizeof(*ip), M_NOWAIT);
812	if (msg == NULL)
813		error = ENOMEM;
814	else {
815		ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data);
816		ip->lcid = ch->scid;
817		ip->omtu = ch->omtu;
818		bcopy(&ch->iflow, &ip->iflow, sizeof(ip->iflow));
819		ip->flush_timo = ch->flush_timo;
820
821		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
822	}
823
824	return (error);
825} /* ng_l2cap_l2ca_cfg_ind */
826
827/*
828 * Process L2CA_Write event
829 */
830
831int
832ng_l2cap_l2ca_write_req(ng_l2cap_p l2cap, struct mbuf *m)
833{
834	ng_l2cap_l2ca_hdr_t	*l2ca_hdr = NULL;
835	ng_l2cap_chan_p		 ch = NULL;
836	ng_l2cap_cmd_p		 cmd = NULL;
837	int			 error = 0;
838	u_int32_t		 token = 0;
839
840	/* Make sure we can access L2CA data packet header */
841	if (m->m_pkthdr.len < sizeof(*l2ca_hdr)) {
842		NG_L2CAP_ERR(
843"%s: %s - L2CA Data packet too small, len=%d\n",
844			__func__,NG_NODE_NAME(l2cap->node),m->m_pkthdr.len);
845		error = EMSGSIZE;
846		goto drop;
847	}
848
849	/* Get L2CA data packet header */
850	NG_L2CAP_M_PULLUP(m, sizeof(*l2ca_hdr));
851	if (m == NULL)
852		return (ENOBUFS);
853
854	l2ca_hdr = mtod(m, ng_l2cap_l2ca_hdr_t *);
855	token = l2ca_hdr->token;
856	m_adj(m, sizeof(*l2ca_hdr));
857
858	/* Verify payload size */
859	if (l2ca_hdr->length != m->m_pkthdr.len) {
860		NG_L2CAP_ERR(
861"%s: %s - invalid L2CA Data packet. " \
862"Payload length does not match, length=%d, len=%d\n",
863			__func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->length,
864			m->m_pkthdr.len);
865		error = EMSGSIZE;
866		goto drop;
867	}
868
869	/* Check channel ID */
870	if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
871		ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
872						l2ca_hdr->lcid);
873	} else if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
874		ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
875						l2ca_hdr->lcid);
876	}else{
877		if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) {
878			NG_L2CAP_ERR(
879				"%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n",
880				__func__, NG_NODE_NAME(l2cap->node),
881				l2ca_hdr->lcid);
882			error = EINVAL;
883			goto drop;
884		}
885
886		/* Verify that we have the channel and make sure it is open */
887		ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid,
888					   l2ca_hdr->idtype);
889	}
890
891	if (ch == NULL) {
892		NG_L2CAP_ERR(
893"%s: %s - invalid L2CA Data packet. Channel does not exist, cid=%d\n",
894			__func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid);
895		error = ENOENT;
896		goto drop;
897	}
898
899	if (ch->state != NG_L2CAP_OPEN) {
900		NG_L2CAP_ERR(
901"%s: %s - invalid L2CA Data packet. Invalid channel state, scid=%d, state=%d\n",
902			 __func__, NG_NODE_NAME(l2cap->node), ch->scid,
903			ch->state);
904		error = EHOSTDOWN;
905		goto drop; /* XXX not always - re-configure */
906	}
907
908	/* Create L2CAP command descriptor */
909	cmd = ng_l2cap_new_cmd(ch->con, ch, 0, NGM_L2CAP_L2CA_WRITE, token);
910	if (cmd == NULL) {
911		error = ENOMEM;
912		goto drop;
913	}
914
915	/* Attach data packet and link command to the queue */
916	cmd->aux = m;
917	ng_l2cap_link_cmd(ch->con, cmd);
918	ng_l2cap_lp_deliver(ch->con);
919
920	return (error);
921drop:
922	NG_FREE_M(m);
923
924	return (error);
925} /* ng_l2cap_l2ca_write_req */
926
927/*
928 * Send L2CA_Write response
929 */
930
931int
932ng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
933		u_int16_t length)
934{
935	ng_l2cap_p		 l2cap = ch->con->l2cap;
936	struct ng_mesg		*msg = NULL;
937	ng_l2cap_l2ca_write_op	*op = NULL;
938	int			 error = 0;
939
940	/* Check if upstream hook is connected and valid */
941	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
942		NG_L2CAP_ERR(
943"%s: %s - unable to send L2CA_WriteRsp message. " \
944"Hook is not connected or valid, psm=%d\n",
945			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
946
947		return (ENOTCONN);
948	}
949
950	/* Create and send L2CA_WriteRsp message */
951	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_WRITE,
952			sizeof(*op), M_NOWAIT);
953	if (msg == NULL)
954		error = ENOMEM;
955	else {
956		msg->header.token = token;
957		msg->header.flags |= NGF_RESP;
958
959		op = (ng_l2cap_l2ca_write_op *)(msg->data);
960		op->result = result;
961		op->length = length;
962		if(ch->scid == NG_L2CAP_ATT_CID){
963			op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
964			op->lcid = ch->con->con_handle;
965		}else if(ch->scid == NG_L2CAP_SMP_CID){
966			op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
967			op->lcid = ch->con->con_handle;
968		}else{
969			op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
970				NG_L2CAP_L2CA_IDTYPE_BREDR :
971				NG_L2CAP_L2CA_IDTYPE_LE;
972			op->lcid = ch->scid;
973
974		}
975		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
976	}
977
978	return (error);
979} /* ng_l2cap_l2ca_write_rsp */
980
981/*
982 * Receive packet from the lower layer protocol and send it to the upper
983 * layer protocol (L2CAP_Read)
984 */
985
986int
987ng_l2cap_l2ca_receive(ng_l2cap_con_p con)
988{
989	ng_l2cap_p	 l2cap = con->l2cap;
990	ng_l2cap_hdr_t	*hdr = NULL;
991	ng_l2cap_chan_p  ch = NULL;
992	int		 error = 0;
993	int idtype;
994	uint16_t *idp;
995	int silent = 0;
996
997	NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
998	if (con->rx_pkt == NULL)
999		return (ENOBUFS);
1000
1001	hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *);
1002
1003	/* Check channel */
1004
1005	if(hdr->dcid == NG_L2CAP_ATT_CID){
1006		idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
1007		ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
1008						con->con_handle);
1009		/*
1010		 * Here,ATT channel is distinguished by
1011		 * connection handle
1012		 */
1013		hdr->dcid = con->con_handle;
1014		silent = 1;
1015	}else if(hdr->dcid == NG_L2CAP_SMP_CID){
1016		idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
1017		ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
1018						con->con_handle);
1019		/*
1020		 * Here,SMP channel is distinguished by
1021		 * connection handle
1022		 */
1023		silent = 1;
1024		hdr->dcid = con->con_handle;
1025	}else{
1026		idtype = (con->linktype==NG_HCI_LINK_ACL)?
1027			NG_L2CAP_L2CA_IDTYPE_BREDR:
1028			NG_L2CAP_L2CA_IDTYPE_LE;
1029		ch = ng_l2cap_chan_by_scid(l2cap, hdr->dcid, idtype);
1030	}
1031	if (ch == NULL) {
1032		if(!silent)
1033			NG_L2CAP_ERR(
1034"%s: %s - unexpected L2CAP data packet. Channel does not exist, cid=%d, idtype=%d\n",
1035	__func__, NG_NODE_NAME(l2cap->node), hdr->dcid, idtype);
1036		error = ENOENT;
1037		goto drop;
1038	}
1039
1040	/* Check channel state */
1041	if (ch->state != NG_L2CAP_OPEN) {
1042		NG_L2CAP_WARN(
1043"%s: %s - unexpected L2CAP data packet. " \
1044"Invalid channel state, cid=%d, state=%d\n",
1045			__func__, NG_NODE_NAME(l2cap->node), ch->scid,
1046			ch->state);
1047		error = EHOSTDOWN; /* XXX not always - re-configuration */
1048		goto drop;
1049	}
1050
1051	/* Check payload size and channel's MTU */
1052	if (hdr->length > ch->imtu) {
1053		NG_L2CAP_ERR(
1054"%s: %s - invalid L2CAP data packet. " \
1055"Packet too big, length=%d, imtu=%d, cid=%d\n",
1056			__func__, NG_NODE_NAME(l2cap->node), hdr->length,
1057			ch->imtu, ch->scid);
1058		error = EMSGSIZE;
1059		goto drop;
1060	}
1061
1062	/*
1063	 * If we got here then everything looks good and we can sent packet
1064	 * to the upper layer protocol.
1065	 */
1066
1067	/* Check if upstream hook is connected and valid */
1068	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1069		NG_L2CAP_ERR(
1070"%s: %s - unable to send L2CAP data packet. " \
1071"Hook is not connected or valid, psm=%d\n",
1072			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
1073		error = ENOTCONN;
1074		goto drop;
1075	}
1076	M_PREPEND(con->rx_pkt, sizeof(uint16_t), M_NOWAIT);
1077	if(con->rx_pkt == NULL)
1078		goto drop;
1079	idp = mtod(con->rx_pkt, uint16_t *);
1080	*idp = idtype;
1081
1082	NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
1083	con->rx_pkt = NULL;
1084drop:
1085	NG_FREE_M(con->rx_pkt); /* checks for != NULL */
1086
1087	return (error);
1088} /* ng_l2cap_receive */
1089
1090/*
1091 * Receive connectioless (multicast) packet from the lower layer protocol and
1092 * send it to the upper layer protocol
1093 */
1094
1095int
1096ng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con)
1097{
1098	struct _clt_pkt {
1099		ng_l2cap_hdr_t		 h;
1100		ng_l2cap_clt_hdr_t	 c_h;
1101	} __attribute__ ((packed))	*hdr = NULL;
1102	ng_l2cap_p			 l2cap = con->l2cap;
1103	int				 length, error = 0;
1104
1105	NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
1106	if (con->rx_pkt == NULL)
1107		return (ENOBUFS);
1108
1109	hdr = mtod(con->rx_pkt, struct _clt_pkt *);
1110
1111	/* Check packet */
1112	length = con->rx_pkt->m_pkthdr.len - sizeof(*hdr);
1113	if (length < 0) {
1114		NG_L2CAP_ERR(
1115"%s: %s - invalid L2CAP CLT data packet. Packet too small, length=%d\n",
1116			__func__, NG_NODE_NAME(l2cap->node), length);
1117		error = EMSGSIZE;
1118		goto drop;
1119	}
1120
1121	/* Check payload size against CLT MTU */
1122	if (length > NG_L2CAP_MTU_DEFAULT) {
1123		NG_L2CAP_ERR(
1124"%s: %s - invalid L2CAP CLT data packet. Packet too big, length=%d, mtu=%d\n",
1125			__func__, NG_NODE_NAME(l2cap->node), length,
1126			NG_L2CAP_MTU_DEFAULT);
1127		error = EMSGSIZE;
1128		goto drop;
1129	}
1130
1131	hdr->c_h.psm = le16toh(hdr->c_h.psm);
1132
1133	/*
1134	 * If we got here then everything looks good and we can sent packet
1135	 * to the upper layer protocol.
1136	 */
1137
1138	/* Select upstream hook based on PSM */
1139	switch (hdr->c_h.psm) {
1140	case NG_L2CAP_PSM_SDP:
1141		if (l2cap->flags & NG_L2CAP_CLT_SDP_DISABLED)
1142			goto drop;
1143		break;
1144
1145	case NG_L2CAP_PSM_RFCOMM:
1146		if (l2cap->flags & NG_L2CAP_CLT_RFCOMM_DISABLED)
1147			goto drop;
1148		break;
1149
1150	case NG_L2CAP_PSM_TCP:
1151		if (l2cap->flags & NG_L2CAP_CLT_TCP_DISABLED)
1152			goto drop;
1153		break;
1154        }
1155
1156	/* Check if upstream hook is connected and valid */
1157	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1158		NG_L2CAP_ERR(
1159"%s: %s - unable to send L2CAP CLT data packet. " \
1160"Hook is not connected or valid, psm=%d\n",
1161			__func__, NG_NODE_NAME(l2cap->node), hdr->c_h.psm);
1162		error = ENOTCONN;
1163		goto drop;
1164	}
1165
1166	NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
1167	con->rx_pkt = NULL;
1168drop:
1169	NG_FREE_M(con->rx_pkt); /* checks for != NULL */
1170
1171	return (error);
1172} /* ng_l2cap_l2ca_clt_receive */
1173
1174/*
1175 * Send L2CA_QoSViolationInd to the upper layer protocol
1176 */
1177
1178int
1179ng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch)
1180{
1181	ng_l2cap_p			 l2cap = ch->con->l2cap;
1182	struct ng_mesg			*msg = NULL;
1183	ng_l2cap_l2ca_qos_ind_ip	*ip = NULL;
1184	int				 error = 0;
1185
1186	/* Check if upstream hook is connected and valid */
1187	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1188		NG_L2CAP_ERR(
1189"%s: %s - unable to send L2CA_QoSViolationInd message. " \
1190"Hook is not connected or valid, psm=%d\n",
1191			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
1192
1193		return (ENOTCONN);
1194	}
1195
1196	/* Create and send L2CA_QoSViolationInd message */
1197	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_QOS_IND,
1198		sizeof(*ip), M_NOWAIT);
1199	if (msg == NULL)
1200		error = ENOMEM;
1201	else {
1202		ip = (ng_l2cap_l2ca_qos_ind_ip *)(msg->data);
1203		bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr));
1204		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1205	}
1206
1207	return (error);
1208} /* ng_l2cap_l2ca_qos_ind */
1209
1210/*
1211 * Process L2CA_Disconnect request from the upper layer protocol.
1212 */
1213
1214int
1215ng_l2cap_l2ca_discon_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1216{
1217	ng_l2cap_l2ca_discon_ip	*ip = NULL;
1218	ng_l2cap_chan_p		 ch = NULL;
1219	ng_l2cap_cmd_p		 cmd = NULL;
1220	int			 error = 0;
1221
1222	/* Check message */
1223	if (msg->header.arglen != sizeof(*ip)) {
1224		NG_L2CAP_ALERT(
1225"%s: %s - invalid L2CA_Disconnect request message size, size=%d\n",
1226			__func__, NG_NODE_NAME(l2cap->node),
1227			msg->header.arglen);
1228		error = EMSGSIZE;
1229		goto out;
1230	}
1231
1232	ip = (ng_l2cap_l2ca_discon_ip *)(msg->data);
1233
1234
1235	if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
1236		/* Don't send Disconnect request on L2CAP Layer*/
1237		ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
1238			ip->lcid);
1239
1240		if(ch != NULL){
1241			ng_l2cap_free_chan(ch);
1242		}else{
1243		NG_L2CAP_ERR(
1244"%s: %s - unexpected L2CA_Disconnect request message. " \
1245"Channel does not exist, conhandle=%d\n",
1246			__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1247			error = EINVAL;
1248		}
1249		goto out;
1250	}else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
1251		/* Don't send Disconnect request on L2CAP Layer*/
1252		ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
1253			ip->lcid);
1254
1255		if(ch != NULL){
1256			ng_l2cap_free_chan(ch);
1257		}else{
1258		NG_L2CAP_ERR(
1259"%s: %s - unexpected L2CA_Disconnect request message. " \
1260"Channel does not exist, conhandle=%d\n",
1261			__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1262			error = EINVAL;
1263		}
1264		goto out;
1265	}else{
1266		/* Check if we have this channel */
1267		ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, ip->idtype);
1268	}
1269	if (ch == NULL) {
1270		NG_L2CAP_ERR(
1271"%s: %s - unexpected L2CA_Disconnect request message. " \
1272"Channel does not exist, lcid=%d\n",
1273			__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1274		error = ENOENT;
1275		goto out;
1276	}
1277
1278	/* Check channel state */
1279	if (ch->state != NG_L2CAP_CONFIG && ch->state != NG_L2CAP_OPEN &&
1280	    ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) {
1281		NG_L2CAP_ERR(
1282"%s: %s - unexpected L2CA_Disconnect request message. " \
1283"Invalid channel state, state=%d, lcid=%d\n",
1284			__func__, NG_NODE_NAME(l2cap->node), ch->state,
1285			ch->scid);
1286		error = EINVAL;
1287		goto out;
1288	}
1289
1290	/* Create and send L2CAP_DisconReq message */
1291	cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con),
1292			NG_L2CAP_DISCON_REQ, msg->header.token);
1293	if (cmd == NULL) {
1294		ng_l2cap_free_chan(ch);
1295		error = ENOMEM;
1296		goto out;
1297	}
1298
1299	if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1300		ng_l2cap_free_chan(ch);
1301		ng_l2cap_free_cmd(cmd);
1302		error = EIO;
1303		goto out;
1304	}
1305
1306	_ng_l2cap_discon_req(cmd->aux, cmd->ident, ch->dcid, ch->scid);
1307	if (cmd->aux == NULL) {
1308		ng_l2cap_free_chan(ch);
1309		ng_l2cap_free_cmd(cmd);
1310		error = ENOBUFS;
1311		goto out;
1312	}
1313
1314	ch->state = NG_L2CAP_W4_L2CAP_DISCON_RSP;
1315
1316	/* Link command to the queue */
1317	ng_l2cap_link_cmd(ch->con, cmd);
1318	ng_l2cap_lp_deliver(ch->con);
1319out:
1320	return (error);
1321} /* ng_l2cap_l2ca_discon_req */
1322
1323/*
1324 * Send L2CA_Disconnect response to the upper layer protocol
1325 */
1326
1327int
1328ng_l2cap_l2ca_discon_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
1329{
1330	ng_l2cap_p		 l2cap = ch->con->l2cap;
1331	struct ng_mesg		*msg = NULL;
1332	ng_l2cap_l2ca_discon_op	*op = NULL;
1333	int			 error = 0;
1334
1335	/* Check if upstream hook is connected and valid */
1336	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1337		NG_L2CAP_ERR(
1338"%s: %s - unable to send L2CA_Disconnect response message. " \
1339"Hook is not connected or valid, psm=%d\n",
1340			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
1341
1342		return (ENOTCONN);
1343	}
1344
1345	/* Create and send L2CA_Disconnect response message */
1346	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON,
1347		sizeof(*op), M_NOWAIT);
1348	if (msg == NULL)
1349		error = ENOMEM;
1350	else {
1351		msg->header.token = token;
1352		msg->header.flags |= NGF_RESP;
1353
1354		op = (ng_l2cap_l2ca_discon_op *)(msg->data);
1355		op->result = result;
1356
1357		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1358	}
1359
1360	return (error);
1361} /* ng_l2cap_l2ca_discon_rsp */
1362
1363/*
1364 * Send L2CA_DisconnectInd message to the upper layer protocol.
1365 */
1366
1367int
1368ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch)
1369{
1370	ng_l2cap_p			 l2cap = ch->con->l2cap;
1371	struct ng_mesg			*msg = NULL;
1372	ng_l2cap_l2ca_discon_ind_ip	*ip = NULL;
1373	int				 error = 0;
1374
1375	/* Check if upstream hook is connected and valid */
1376	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1377		NG_L2CAP_ERR(
1378"%s: %s - unable to send L2CA_DisconnectInd message. " \
1379"Hook is not connected or valid, psm=%d\n",
1380			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
1381
1382		return (ENOTCONN);
1383	}
1384
1385	/* Create and send L2CA_DisconnectInd message */
1386	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND,
1387		sizeof(*ip), M_NOWAIT);
1388	if (msg == NULL)
1389		error = ENOMEM;
1390	else {
1391		ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data);
1392		ip->idtype = ch->idtype;
1393		if(ch->idtype == NG_L2CAP_L2CA_IDTYPE_ATT||
1394		   ch->idtype == NG_L2CAP_L2CA_IDTYPE_SMP)
1395			ip->lcid = ch->con->con_handle;
1396		else
1397			ip->lcid = ch->scid;
1398
1399		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1400	}
1401
1402	return (error);
1403} /* ng_l2cap_l2ca_discon_ind */
1404
1405/*
1406 * Process L2CA_GroupCreate request from the upper layer protocol.
1407 * XXX FIXME
1408 */
1409
1410int
1411ng_l2cap_l2ca_grp_create(ng_l2cap_p l2cap, struct ng_mesg *msg)
1412{
1413	return (ENOTSUP);
1414} /* ng_l2cap_l2ca_grp_create */
1415
1416/*
1417 * Process L2CA_GroupClose request from the upper layer protocol
1418 * XXX FIXME
1419 */
1420
1421int
1422ng_l2cap_l2ca_grp_close(ng_l2cap_p l2cap, struct ng_mesg *msg)
1423{
1424	return (ENOTSUP);
1425} /* ng_l2cap_l2ca_grp_close */
1426
1427/*
1428 * Process L2CA_GroupAddMember request from the upper layer protocol.
1429 * XXX FIXME
1430 */
1431
1432int
1433ng_l2cap_l2ca_grp_add_member_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1434{
1435	return (ENOTSUP);
1436} /* ng_l2cap_l2ca_grp_add_member_req */
1437
1438/*
1439 * Send L2CA_GroupAddMember response to the upper layer protocol.
1440 * XXX FIXME
1441 */
1442
1443int
1444ng_l2cap_l2ca_grp_add_member_rsp(ng_l2cap_chan_p ch, u_int32_t token,
1445		u_int16_t result)
1446{
1447	return (0);
1448} /* ng_l2cap_l2ca_grp_add_member_rsp */
1449
1450/*
1451 * Process L2CA_GroupDeleteMember request from the upper layer protocol
1452 * XXX FIXME
1453 */
1454
1455int
1456ng_l2cap_l2ca_grp_rem_member(ng_l2cap_p l2cap, struct ng_mesg *msg)
1457{
1458	return (ENOTSUP);
1459} /* ng_l2cap_l2ca_grp_rem_member */
1460
1461/*
1462 * Process L2CA_GroupGetMembers request from the upper layer protocol
1463 * XXX FIXME
1464 */
1465
1466int
1467ng_l2cap_l2ca_grp_get_members(ng_l2cap_p l2cap, struct ng_mesg *msg)
1468{
1469	return (ENOTSUP);
1470} /* ng_l2cap_l2ca_grp_get_members */
1471
1472/*
1473 * Process L2CA_Ping request from the upper layer protocol
1474 */
1475
1476int
1477ng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1478{
1479	ng_l2cap_l2ca_ping_ip	*ip = NULL;
1480	ng_l2cap_con_p		 con = NULL;
1481	ng_l2cap_cmd_p		 cmd = NULL;
1482	int			 error = 0;
1483
1484	/* Verify message */
1485	if (msg->header.arglen < sizeof(*ip)) {
1486		NG_L2CAP_ALERT(
1487"%s: %s - invalid L2CA_Ping request message size, size=%d\n",
1488			__func__, NG_NODE_NAME(l2cap->node),
1489			msg->header.arglen);
1490		error = EMSGSIZE;
1491		goto out;
1492	}
1493
1494	ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);
1495	if (ip->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
1496		NG_L2CAP_WARN(
1497"%s: %s - invalid L2CA_Ping request. Echo size is too big, echo_size=%d\n",
1498			__func__, NG_NODE_NAME(l2cap->node), ip->echo_size);
1499		error = EMSGSIZE;
1500		goto out;
1501	}
1502
1503	/* Check if we have connection to the unit */
1504	con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1505	if (con == NULL) {
1506		/* Submit LP_ConnectReq to the lower layer */
1507	  error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1508		if (error != 0) {
1509			NG_L2CAP_ERR(
1510"%s: %s - unable to send LP_ConnectReq message, error=%d\n",
1511				__func__, NG_NODE_NAME(l2cap->node), error);
1512			goto out;
1513		}
1514
1515		/* This should not fail */
1516		con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1517		KASSERT((con != NULL),
1518("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
1519	}
1520
1521	/* Create L2CAP command descriptor */
1522	cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),
1523			NG_L2CAP_ECHO_REQ, msg->header.token);
1524	if (cmd == NULL) {
1525		error = ENOMEM;
1526		goto out;
1527	}
1528
1529	if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1530		ng_l2cap_free_cmd(cmd);
1531                error = EIO;
1532		goto out;
1533	}
1534
1535	/* Create L2CAP command packet */
1536	_ng_l2cap_echo_req(cmd->aux, cmd->ident,
1537			msg->data + sizeof(*ip), ip->echo_size);
1538	if (cmd->aux == NULL) {
1539		ng_l2cap_free_cmd(cmd);
1540                error = ENOBUFS;
1541		goto out;
1542	}
1543
1544        /* Link command to the queue */
1545        ng_l2cap_link_cmd(con, cmd);
1546	ng_l2cap_lp_deliver(con);
1547out:
1548	return (error);
1549} /* ng_l2cap_l2ca_ping_req */
1550
1551/*
1552 * Send L2CA_Ping response to the upper layer protocol
1553 */
1554
1555int
1556ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result,
1557		struct mbuf *data)
1558{
1559	ng_l2cap_p		 l2cap = con->l2cap;
1560	struct ng_mesg		*msg = NULL;
1561	ng_l2cap_l2ca_ping_op	*op = NULL;
1562	int			 error = 0, size = 0;
1563
1564	/* Check if control hook is connected and valid */
1565	if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
1566		NG_L2CAP_WARN(
1567"%s: %s - unable to send L2CA_Ping response message. " \
1568"Hook is not connected or valid\n",
1569			__func__, NG_NODE_NAME(l2cap->node));
1570		error = ENOTCONN;
1571		goto out;
1572	}
1573
1574	size = (data == NULL)? 0 : data->m_pkthdr.len;
1575
1576	/* Create and send L2CA_Ping response message */
1577	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_PING,
1578		sizeof(*op) + size, M_NOWAIT);
1579	if (msg == NULL)
1580		error = ENOMEM;
1581	else {
1582		msg->header.token = token;
1583		msg->header.flags |= NGF_RESP;
1584
1585		op = (ng_l2cap_l2ca_ping_op *)(msg->data);
1586		op->result = result;
1587		bcopy(&con->remote, &op->bdaddr, sizeof(op->bdaddr));
1588		if (data != NULL && size > 0) {
1589			op->echo_size = size;
1590			m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));
1591		}
1592
1593		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1594	}
1595out:
1596	NG_FREE_M(data);
1597
1598	return (error);
1599} /* ng_l2cap_l2ca_ping_rsp */
1600
1601/*
1602 * Process L2CA_GetInfo request from the upper layer protocol
1603 */
1604
1605int
1606ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1607{
1608	ng_l2cap_l2ca_get_info_ip	*ip = NULL;
1609	ng_l2cap_con_p			 con = NULL;
1610	ng_l2cap_cmd_p			 cmd = NULL;
1611	int				 error = 0;
1612
1613	/* Verify message */
1614	if (msg->header.arglen != sizeof(*ip)) {
1615		NG_L2CAP_ALERT(
1616"%s: %s - invalid L2CA_GetInfo request message size, size=%d\n",
1617			__func__, NG_NODE_NAME(l2cap->node),
1618			msg->header.arglen);
1619		error = EMSGSIZE;
1620		goto out;
1621	}
1622
1623	ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
1624
1625	/* Check if we have connection to the unit */
1626	con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr,ip->linktype);
1627	if (con == NULL) {
1628		/* Submit LP_ConnectReq to the lower layer */
1629		error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);
1630		if (error != 0) {
1631			NG_L2CAP_ERR(
1632"%s: %s - unable to send LP_ConnectReq message, error=%d\n",
1633				__func__, NG_NODE_NAME(l2cap->node), error);
1634			goto out;
1635		}
1636
1637		/* This should not fail */
1638		con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
1639		KASSERT((con != NULL),
1640("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
1641	}
1642
1643	/* Create L2CAP command descriptor */
1644	cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),
1645			NG_L2CAP_INFO_REQ, msg->header.token);
1646	if (cmd == NULL) {
1647		error = ENOMEM;
1648		goto out;
1649	}
1650
1651	if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1652		ng_l2cap_free_cmd(cmd);
1653		error = EIO;
1654		goto out;
1655	}
1656
1657	/* Create L2CAP command packet */
1658	_ng_l2cap_info_req(cmd->aux, cmd->ident, ip->info_type);
1659	if (cmd->aux == NULL) {
1660		ng_l2cap_free_cmd(cmd);
1661		error = ENOBUFS;
1662		goto out;
1663	}
1664
1665        /* Link command to the queue */
1666	ng_l2cap_link_cmd(con, cmd);
1667	ng_l2cap_lp_deliver(con);
1668out:
1669	return (error);
1670} /* ng_l2cap_l2ca_get_info_req */
1671
1672/*
1673 * Send L2CA_GetInfo response to the upper layer protocol
1674 */
1675
1676int
1677ng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con, u_int32_t token,
1678		u_int16_t result, struct mbuf *data)
1679{
1680	ng_l2cap_p			 l2cap = con->l2cap;
1681	struct ng_mesg			*msg = NULL;
1682	ng_l2cap_l2ca_get_info_op	*op = NULL;
1683	int				 error = 0, size;
1684
1685	/* Check if control hook is connected and valid */
1686	if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
1687		NG_L2CAP_WARN(
1688"%s: %s - unable to send L2CA_GetInfo response message. " \
1689"Hook is not connected or valid\n",
1690			__func__, NG_NODE_NAME(l2cap->node));
1691		error = ENOTCONN;
1692		goto out;
1693	}
1694
1695	size = (data == NULL)? 0 : data->m_pkthdr.len;
1696
1697	/* Create and send L2CA_GetInfo response message */
1698	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_GET_INFO,
1699		sizeof(*op) + size, M_NOWAIT);
1700	if (msg == NULL)
1701		error = ENOMEM;
1702	else {
1703		msg->header.token = token;
1704		msg->header.flags |= NGF_RESP;
1705
1706		op = (ng_l2cap_l2ca_get_info_op *)(msg->data);
1707		op->result = result;
1708		if (data != NULL && size > 0) {
1709			op->info_size = size;
1710			m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));
1711		}
1712
1713		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1714	}
1715out:
1716	NG_FREE_M(data);
1717
1718	return (error);
1719} /* ng_l2cap_l2ca_get_info_rsp */
1720
1721/*
1722 * Process L2CA_EnableCLT message from the upper layer protocol
1723 * XXX convert to NGN_L2CAP_NODE_SET_FLAGS?
1724 */
1725
1726int
1727ng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg)
1728{
1729	ng_l2cap_l2ca_enable_clt_ip	*ip = NULL;
1730	int				 error = 0;
1731#if 0
1732 *	ng_l2cap_l2ca_enable_clt_op	*op = NULL;
1733 *	u_int16_t			 result;
1734 * 	u_int32_t			 token;
1735#endif
1736
1737	/* Check message */
1738	if (msg->header.arglen != sizeof(*ip)) {
1739		NG_L2CAP_ALERT(
1740"%s: %s - invalid L2CA_EnableCLT message size, size=%d\n",
1741			__func__, NG_NODE_NAME(l2cap->node),
1742			msg->header.arglen);
1743
1744		return (EMSGSIZE);
1745	}
1746
1747	/* Process request */
1748	ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data);
1749#if 0
1750 *	result = NG_L2CAP_SUCCESS;
1751#endif
1752
1753	switch (ip->psm)
1754	{
1755	case 0:
1756		/* Special case: disable/enable all PSM */
1757		if (ip->enable)
1758			l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED    |
1759					  NG_L2CAP_CLT_RFCOMM_DISABLED |
1760					  NG_L2CAP_CLT_TCP_DISABLED);
1761		else
1762			l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED    |
1763					 NG_L2CAP_CLT_RFCOMM_DISABLED |
1764					 NG_L2CAP_CLT_TCP_DISABLED);
1765		break;
1766
1767	case NG_L2CAP_PSM_SDP:
1768		if (ip->enable)
1769			l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED;
1770		else
1771			l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED;
1772		break;
1773
1774	case NG_L2CAP_PSM_RFCOMM:
1775		if (ip->enable)
1776			l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED;
1777		else
1778			l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED;
1779		break;
1780
1781	case NG_L2CAP_PSM_TCP:
1782		if (ip->enable)
1783			l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED;
1784		else
1785			l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED;
1786		break;
1787
1788	default:
1789		NG_L2CAP_ERR(
1790"%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm);
1791#if 0
1792 *		result = NG_L2CAP_PSM_NOT_SUPPORTED;
1793#endif
1794		error = ENOTSUP;
1795		break;
1796	}
1797
1798#if 0
1799 *	/* Create and send response message */
1800 * 	token = msg->header.token;
1801 * 	NG_FREE_MSG(msg);
1802 * 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT,
1803 * 		sizeof(*op), M_NOWAIT);
1804 * 	if (msg == NULL)
1805 * 		error = ENOMEM;
1806 * 	else {
1807 * 		msg->header.token = token;
1808 * 		msg->header.flags |= NGF_RESP;
1809 *
1810 * 		op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data);
1811 * 		op->result = result;
1812 * 	}
1813 *
1814 * 	/* Send response to control hook */
1815 * 	if (l2cap->ctl != NULL && NG_HOOK_IS_VALID(l2cap->ctl))
1816 * 		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1817#endif
1818
1819	return (error);
1820} /* ng_l2cap_l2ca_enable_clt */
1821
1822