xref: /freebsd/sys/netgraph/bluetooth/l2cap/ng_l2cap_ulpi.c (revision 3a601a238175704dbee47b29290dbe804d71f08b)
1878ed226SJulian Elischer /*
2878ed226SJulian Elischer  * ng_l2cap_ulpi.c
3c398230bSWarner Losh  */
4c398230bSWarner Losh 
5c398230bSWarner Losh /*-
6878ed226SJulian Elischer  * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
7878ed226SJulian Elischer  * All rights reserved.
8878ed226SJulian Elischer  *
9878ed226SJulian Elischer  * Redistribution and use in source and binary forms, with or without
10878ed226SJulian Elischer  * modification, are permitted provided that the following conditions
11878ed226SJulian Elischer  * are met:
12878ed226SJulian Elischer  * 1. Redistributions of source code must retain the above copyright
13878ed226SJulian Elischer  *    notice, this list of conditions and the following disclaimer.
14878ed226SJulian Elischer  * 2. Redistributions in binary form must reproduce the above copyright
15878ed226SJulian Elischer  *    notice, this list of conditions and the following disclaimer in the
16878ed226SJulian Elischer  *    documentation and/or other materials provided with the distribution.
17878ed226SJulian Elischer  *
18878ed226SJulian Elischer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19878ed226SJulian Elischer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20878ed226SJulian Elischer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21878ed226SJulian Elischer  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22878ed226SJulian Elischer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23878ed226SJulian Elischer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24878ed226SJulian Elischer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25878ed226SJulian Elischer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26878ed226SJulian Elischer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27878ed226SJulian Elischer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28878ed226SJulian Elischer  * SUCH DAMAGE.
29878ed226SJulian Elischer  *
30f2bb1caeSJulian Elischer  * $Id: ng_l2cap_ulpi.c,v 1.1 2002/11/24 19:47:06 max Exp $
31878ed226SJulian Elischer  * $FreeBSD$
32878ed226SJulian Elischer  */
33878ed226SJulian Elischer 
34878ed226SJulian Elischer #include <sys/param.h>
35878ed226SJulian Elischer #include <sys/systm.h>
36878ed226SJulian Elischer #include <sys/kernel.h>
37878ed226SJulian Elischer #include <sys/endian.h>
38878ed226SJulian Elischer #include <sys/malloc.h>
39878ed226SJulian Elischer #include <sys/mbuf.h>
40878ed226SJulian Elischer #include <sys/queue.h>
41878ed226SJulian Elischer #include <netgraph/ng_message.h>
42878ed226SJulian Elischer #include <netgraph/netgraph.h>
43b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_hci.h>
44b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_l2cap.h>
45b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_var.h>
46b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h>
47b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h>
48b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h>
49b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>
50b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>
51878ed226SJulian Elischer 
52878ed226SJulian Elischer /******************************************************************************
53878ed226SJulian Elischer  ******************************************************************************
54878ed226SJulian Elischer  **                 Upper Layer Protocol Interface module
55878ed226SJulian Elischer  ******************************************************************************
56878ed226SJulian Elischer  ******************************************************************************/
57878ed226SJulian Elischer 
58878ed226SJulian Elischer /*
59878ed226SJulian Elischer  * Process L2CA_Connect request from the upper layer protocol.
60878ed226SJulian Elischer  */
61878ed226SJulian Elischer 
62878ed226SJulian Elischer int
63878ed226SJulian Elischer ng_l2cap_l2ca_con_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
64878ed226SJulian Elischer {
65878ed226SJulian Elischer 	ng_l2cap_l2ca_con_ip	*ip = NULL;
66878ed226SJulian Elischer 	ng_l2cap_con_p		 con = NULL;
67878ed226SJulian Elischer 	ng_l2cap_chan_p		 ch = NULL;
68878ed226SJulian Elischer 	ng_l2cap_cmd_p		 cmd = NULL;
69878ed226SJulian Elischer 	int			 error = 0;
70878ed226SJulian Elischer 
71878ed226SJulian Elischer 	/* Check message */
72878ed226SJulian Elischer 	if (msg->header.arglen != sizeof(*ip)) {
73878ed226SJulian Elischer 		NG_L2CAP_ALERT(
74878ed226SJulian Elischer "%s: %s - invalid L2CA_Connect request message size, size=%d\n",
75878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node),
76878ed226SJulian Elischer 			msg->header.arglen);
77878ed226SJulian Elischer 		error = EMSGSIZE;
78878ed226SJulian Elischer 		goto out;
79878ed226SJulian Elischer 	}
80878ed226SJulian Elischer 
81878ed226SJulian Elischer 	ip = (ng_l2cap_l2ca_con_ip *)(msg->data);
82878ed226SJulian Elischer 
83878ed226SJulian Elischer 	/* Check if we have connection to the remote unit */
84fbc48c2bSTakanori Watanabe 	con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
85878ed226SJulian Elischer 	if (con == NULL) {
86878ed226SJulian Elischer 		/* Submit LP_ConnectReq to the lower layer */
87fbc48c2bSTakanori Watanabe 		error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);
88878ed226SJulian Elischer 		if (error != 0) {
89878ed226SJulian Elischer 			NG_L2CAP_ERR(
90878ed226SJulian Elischer "%s: %s - unable to send LP_ConnectReq message, error=%d\n",
91878ed226SJulian Elischer 				__func__, NG_NODE_NAME(l2cap->node), error);
92878ed226SJulian Elischer 			goto out;
93878ed226SJulian Elischer 		}
94878ed226SJulian Elischer 
95878ed226SJulian Elischer 		/* This should not fail */
96fbc48c2bSTakanori Watanabe 		con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
97878ed226SJulian Elischer 		KASSERT((con != NULL),
98878ed226SJulian Elischer ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
99878ed226SJulian Elischer 	}
100878ed226SJulian Elischer 
101878ed226SJulian Elischer 	/*
102878ed226SJulian Elischer 	 * Create new empty channel descriptor. In case of any failure do
103878ed226SJulian Elischer 	 * not touch connection descriptor.
104878ed226SJulian Elischer 	 */
105878ed226SJulian Elischer 
106fbc48c2bSTakanori Watanabe 	ch = ng_l2cap_new_chan(l2cap, con, ip->psm, ip->idtype);
107878ed226SJulian Elischer 	if (ch == NULL) {
108878ed226SJulian Elischer 		error = ENOMEM;
109878ed226SJulian Elischer 		goto out;
110878ed226SJulian Elischer 	}
111878ed226SJulian Elischer 
112878ed226SJulian Elischer 	/* Now create L2CAP_ConnectReq command */
113878ed226SJulian Elischer 	cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(con),
114878ed226SJulian Elischer 			NG_L2CAP_CON_REQ, msg->header.token);
115878ed226SJulian Elischer 	if (cmd == NULL) {
116878ed226SJulian Elischer 		ng_l2cap_free_chan(ch);
117878ed226SJulian Elischer 		error = ENOMEM;
118878ed226SJulian Elischer 		goto out;
119878ed226SJulian Elischer 	}
120878ed226SJulian Elischer 
121878ed226SJulian Elischer 	if (cmd->ident == NG_L2CAP_NULL_IDENT) {
122878ed226SJulian Elischer 		ng_l2cap_free_cmd(cmd);
123878ed226SJulian Elischer 		ng_l2cap_free_chan(ch);
124878ed226SJulian Elischer 		error = EIO;
125878ed226SJulian Elischer 		goto out;
126878ed226SJulian Elischer 	}
127878ed226SJulian Elischer 
128878ed226SJulian Elischer 	/* Create L2CAP command packet */
129fbc48c2bSTakanori Watanabe 	if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
130fbc48c2bSTakanori Watanabe 		_ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_ATT_CID,
131fbc48c2bSTakanori Watanabe 				  NG_L2CAP_ATT_CID, 0, 0);
132fbc48c2bSTakanori Watanabe 		cmd->aux->m_flags |= M_PROTO2;
133*3a601a23STakanori Watanabe 	}else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
134*3a601a23STakanori Watanabe 		_ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_SMP_CID,
135*3a601a23STakanori Watanabe 				  NG_L2CAP_SMP_CID, 0, 0);
136*3a601a23STakanori Watanabe 		cmd->aux->m_flags |= M_PROTO2;
137fbc48c2bSTakanori Watanabe 	}else{
138878ed226SJulian Elischer 		_ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid);
139fbc48c2bSTakanori Watanabe 	}
140878ed226SJulian Elischer 	if (cmd->aux == NULL) {
141878ed226SJulian Elischer 		ng_l2cap_free_cmd(cmd);
142878ed226SJulian Elischer 		ng_l2cap_free_chan(ch);
143878ed226SJulian Elischer 		error = ENOBUFS;
144878ed226SJulian Elischer 		goto out;
145878ed226SJulian Elischer 	}
146878ed226SJulian Elischer 
147878ed226SJulian Elischer 	ch->state = NG_L2CAP_W4_L2CAP_CON_RSP;
148878ed226SJulian Elischer 
149878ed226SJulian Elischer 	/* Link command to the queue */
150878ed226SJulian Elischer 	ng_l2cap_link_cmd(ch->con, cmd);
151878ed226SJulian Elischer 	ng_l2cap_lp_deliver(ch->con);
152878ed226SJulian Elischer out:
153878ed226SJulian Elischer 	return (error);
154878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_req */
155878ed226SJulian Elischer 
156878ed226SJulian Elischer /*
157878ed226SJulian Elischer  * Send L2CA_Connect response to the upper layer protocol.
158878ed226SJulian Elischer  */
159878ed226SJulian Elischer 
160878ed226SJulian Elischer int
161878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
162878ed226SJulian Elischer 		u_int16_t status)
163878ed226SJulian Elischer {
164878ed226SJulian Elischer 	ng_l2cap_p		 l2cap = ch->con->l2cap;
165878ed226SJulian Elischer 	struct ng_mesg		*msg = NULL;
166878ed226SJulian Elischer 	ng_l2cap_l2ca_con_op	*op = NULL;
167878ed226SJulian Elischer 	int			 error = 0;
168878ed226SJulian Elischer 
169878ed226SJulian Elischer 	/* Check if upstream hook is connected and valid */
170878ed226SJulian Elischer 	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
171878ed226SJulian Elischer 		NG_L2CAP_ERR(
172878ed226SJulian Elischer "%s: %s - unable to send L2CA_Connect response message. " \
173878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
174878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
175878ed226SJulian Elischer 
176878ed226SJulian Elischer 		return (ENOTCONN);
177878ed226SJulian Elischer 	}
178878ed226SJulian Elischer 
179878ed226SJulian Elischer 	/* Create and send L2CA_Connect response message */
180878ed226SJulian Elischer 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON,
181878ed226SJulian Elischer 		sizeof(*op), M_NOWAIT);
182878ed226SJulian Elischer 	if (msg == NULL)
183878ed226SJulian Elischer 		error = ENOMEM;
184878ed226SJulian Elischer 	else {
185878ed226SJulian Elischer 		msg->header.token = token;
186878ed226SJulian Elischer 		msg->header.flags |= NGF_RESP;
187878ed226SJulian Elischer 
188878ed226SJulian Elischer 		op = (ng_l2cap_l2ca_con_op *)(msg->data);
189878ed226SJulian Elischer 
190878ed226SJulian Elischer 		/*
191878ed226SJulian Elischer 		 * XXX Spec. says we should only populate LCID when result == 0
192878ed226SJulian Elischer 		 * What about PENDING? What the heck, for now always populate
193878ed226SJulian Elischer 		 * LCID :)
194878ed226SJulian Elischer 		 */
195fbc48c2bSTakanori Watanabe 		if(ch->scid == NG_L2CAP_ATT_CID){
196fbc48c2bSTakanori Watanabe 			op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
197fbc48c2bSTakanori Watanabe 			op->lcid = ch->con->con_handle;
198*3a601a23STakanori Watanabe 		}else if(ch->scid == NG_L2CAP_SMP_CID){
199*3a601a23STakanori Watanabe 			op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
200*3a601a23STakanori Watanabe 			op->lcid = ch->con->con_handle;
201fbc48c2bSTakanori Watanabe 		}else{
202fbc48c2bSTakanori Watanabe 			op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
203fbc48c2bSTakanori Watanabe 				NG_L2CAP_L2CA_IDTYPE_BREDR :
204fbc48c2bSTakanori Watanabe 				NG_L2CAP_L2CA_IDTYPE_LE;
205878ed226SJulian Elischer 			op->lcid = ch->scid;
206fbc48c2bSTakanori Watanabe 		}
207*3a601a23STakanori Watanabe 		op->encryption = ch->con->encryption;
208878ed226SJulian Elischer 		op->result = result;
209878ed226SJulian Elischer 		op->status = status;
210878ed226SJulian Elischer 
2114ae439a3SMaksim Yevmenkin 		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
212878ed226SJulian Elischer 	}
213878ed226SJulian Elischer 
214878ed226SJulian Elischer 	return (error);
215878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_rsp */
216878ed226SJulian Elischer 
217878ed226SJulian Elischer /*
218878ed226SJulian Elischer  * Process L2CA_ConnectRsp request from the upper layer protocol.
219878ed226SJulian Elischer  */
220878ed226SJulian Elischer 
221878ed226SJulian Elischer int
222878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
223878ed226SJulian Elischer {
224878ed226SJulian Elischer 	ng_l2cap_l2ca_con_rsp_ip	*ip = NULL;
225878ed226SJulian Elischer 	ng_l2cap_con_p			 con = NULL;
226878ed226SJulian Elischer 	ng_l2cap_chan_p			 ch = NULL;
227878ed226SJulian Elischer 	ng_l2cap_cmd_p			 cmd = NULL;
228878ed226SJulian Elischer 	u_int16_t			 dcid;
229878ed226SJulian Elischer 	int				 error = 0;
230878ed226SJulian Elischer 
231878ed226SJulian Elischer 	/* Check message */
232878ed226SJulian Elischer 	if (msg->header.arglen != sizeof(*ip)) {
233878ed226SJulian Elischer 		NG_L2CAP_ALERT(
234878ed226SJulian Elischer "%s: %s - invalid L2CA_ConnectRsp request message size, size=%d\n",
235878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node),
236878ed226SJulian Elischer 			msg->header.arglen);
237878ed226SJulian Elischer 		error = EMSGSIZE;
238878ed226SJulian Elischer 		goto out;
239878ed226SJulian Elischer 	}
240878ed226SJulian Elischer 
241878ed226SJulian Elischer 	ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data);
242878ed226SJulian Elischer 
243878ed226SJulian Elischer 	/* Check if we have this channel */
244*3a601a23STakanori Watanabe 	if((ip->lcid != NG_L2CAP_ATT_CID)&&
245*3a601a23STakanori Watanabe 	   (ip->lcid != NG_L2CAP_SMP_CID)){
246fbc48c2bSTakanori Watanabe 		ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid
247fbc48c2bSTakanori Watanabe 					   ,(ip->linktype == NG_HCI_LINK_ACL)?
248fbc48c2bSTakanori Watanabe 					   NG_L2CAP_L2CA_IDTYPE_BREDR:
249fbc48c2bSTakanori Watanabe 					   NG_L2CAP_L2CA_IDTYPE_LE);
250fbc48c2bSTakanori Watanabe 	}else{
251fbc48c2bSTakanori Watanabe 		// For now not support on ATT device.
252fbc48c2bSTakanori Watanabe 		ch = NULL;
253fbc48c2bSTakanori Watanabe 	}
254878ed226SJulian Elischer 	if (ch == NULL) {
255878ed226SJulian Elischer 		NG_L2CAP_ALERT(
256878ed226SJulian Elischer "%s: %s - unexpected L2CA_ConnectRsp request message. " \
257878ed226SJulian Elischer "Channel does not exist, lcid=%d\n",
258878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
259878ed226SJulian Elischer 		error = ENOENT;
260878ed226SJulian Elischer 		goto out;
261878ed226SJulian Elischer 	}
262878ed226SJulian Elischer 
263878ed226SJulian Elischer 	/* Check channel state */
264878ed226SJulian Elischer 	if (ch->state != NG_L2CAP_W4_L2CA_CON_RSP) {
265878ed226SJulian Elischer 		NG_L2CAP_ERR(
266878ed226SJulian Elischer "%s: %s - unexpected L2CA_ConnectRsp request message. " \
267878ed226SJulian Elischer "Invalid channel state, state=%d, lcid=%d\n",
268878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->state,
269878ed226SJulian Elischer 			ip->lcid);
270878ed226SJulian Elischer 		error = EINVAL;
271878ed226SJulian Elischer 		goto out;
272878ed226SJulian Elischer 	}
273878ed226SJulian Elischer 
274878ed226SJulian Elischer 	dcid = ch->dcid;
275878ed226SJulian Elischer 	con = ch->con;
276878ed226SJulian Elischer 
277878ed226SJulian Elischer 	/*
278878ed226SJulian Elischer 	 * Now we are pretty much sure it is our response. So create and send
279878ed226SJulian Elischer 	 * L2CAP_ConnectRsp message to our peer.
280878ed226SJulian Elischer 	 */
281878ed226SJulian Elischer 
282878ed226SJulian Elischer 	if (ch->ident != ip->ident)
283878ed226SJulian Elischer 		NG_L2CAP_WARN(
284878ed226SJulian Elischer "%s: %s - channel ident and response ident do not match, scid=%d, ident=%d. " \
285878ed226SJulian Elischer "Will use response ident=%d\n",
286878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->scid,
287878ed226SJulian Elischer 			ch->ident, ip->ident);
288878ed226SJulian Elischer 
289878ed226SJulian Elischer 	/* Check result */
290878ed226SJulian Elischer 	switch (ip->result) {
291878ed226SJulian Elischer 	case NG_L2CAP_SUCCESS:
292*3a601a23STakanori Watanabe 		ch->state = ((ch->scid == NG_L2CAP_ATT_CID)||
293*3a601a23STakanori Watanabe 			     (ch->scid == NG_L2CAP_SMP_CID))?
294fbc48c2bSTakanori Watanabe 			NG_L2CAP_OPEN : NG_L2CAP_CONFIG;
295878ed226SJulian Elischer 		ch->cfg_state = 0;
296878ed226SJulian Elischer 		break;
297878ed226SJulian Elischer 
298878ed226SJulian Elischer 	case NG_L2CAP_PENDING:
299878ed226SJulian Elischer 		break;
300878ed226SJulian Elischer 
301878ed226SJulian Elischer 	default:
302878ed226SJulian Elischer 		ng_l2cap_free_chan(ch);
303878ed226SJulian Elischer 		ch = NULL;
304878ed226SJulian Elischer 		break;
305878ed226SJulian Elischer 	}
306878ed226SJulian Elischer 
307878ed226SJulian Elischer 	/* Create L2CAP command */
308878ed226SJulian Elischer 	cmd = ng_l2cap_new_cmd(con, ch, ip->ident, NG_L2CAP_CON_RSP,
309878ed226SJulian Elischer 			msg->header.token);
310878ed226SJulian Elischer 	if (cmd == NULL) {
311878ed226SJulian Elischer 		if (ch != NULL)
312878ed226SJulian Elischer 			ng_l2cap_free_chan(ch);
313878ed226SJulian Elischer 
314878ed226SJulian Elischer 		error = ENOMEM;
315878ed226SJulian Elischer 		goto out;
316878ed226SJulian Elischer 	}
317878ed226SJulian Elischer 
318878ed226SJulian Elischer 	_ng_l2cap_con_rsp(cmd->aux, cmd->ident, ip->lcid, dcid,
319878ed226SJulian Elischer 		ip->result, ip->status);
320878ed226SJulian Elischer 	if (cmd->aux == NULL) {
321878ed226SJulian Elischer 		if (ch != NULL)
322878ed226SJulian Elischer 			ng_l2cap_free_chan(ch);
323878ed226SJulian Elischer 
324878ed226SJulian Elischer 		ng_l2cap_free_cmd(cmd);
325878ed226SJulian Elischer 		error = ENOBUFS;
326878ed226SJulian Elischer 		goto out;
327878ed226SJulian Elischer 	}
328878ed226SJulian Elischer 
329878ed226SJulian Elischer 	/* Link command to the queue */
330878ed226SJulian Elischer 	ng_l2cap_link_cmd(con, cmd);
331878ed226SJulian Elischer 	ng_l2cap_lp_deliver(con);
332878ed226SJulian Elischer out:
333878ed226SJulian Elischer 	return (error);
334878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_rsp_req */
335878ed226SJulian Elischer 
336*3a601a23STakanori Watanabe int ng_l2cap_l2ca_encryption_change(ng_l2cap_chan_p ch, uint16_t result)
337*3a601a23STakanori Watanabe {
338*3a601a23STakanori Watanabe 	ng_l2cap_p			 l2cap = ch->con->l2cap;
339*3a601a23STakanori Watanabe 	struct ng_mesg			*msg = NULL;
340*3a601a23STakanori Watanabe 	ng_l2cap_l2ca_enc_chg_op	*op = NULL;
341*3a601a23STakanori Watanabe 	int				 error = 0;
342*3a601a23STakanori Watanabe 
343*3a601a23STakanori Watanabe 	/* Check if upstream hook is connected and valid */
344*3a601a23STakanori Watanabe 	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
345*3a601a23STakanori Watanabe 		NG_L2CAP_ERR(
346*3a601a23STakanori Watanabe "%s: %s - unable to send L2CA_ConnectRsp response message. " \
347*3a601a23STakanori Watanabe "Hook is not connected or valid, psm=%d\n",
348*3a601a23STakanori Watanabe 			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
349*3a601a23STakanori Watanabe 
350*3a601a23STakanori Watanabe 		return (ENOTCONN);
351*3a601a23STakanori Watanabe 	}
352*3a601a23STakanori Watanabe 
353*3a601a23STakanori Watanabe 	/* Create and send L2CA_ConnectRsp response message */
354*3a601a23STakanori Watanabe 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENC_CHANGE,
355*3a601a23STakanori Watanabe 		sizeof(*op), M_NOWAIT);
356*3a601a23STakanori Watanabe 	if (msg == NULL)
357*3a601a23STakanori Watanabe 		error = ENOMEM;
358*3a601a23STakanori Watanabe 	else {
359*3a601a23STakanori Watanabe 		msg->header.token = 0;
360*3a601a23STakanori Watanabe 		msg->header.flags |= NGF_RESP;
361*3a601a23STakanori Watanabe 
362*3a601a23STakanori Watanabe 		op = (ng_l2cap_l2ca_enc_chg_op *)(msg->data);
363*3a601a23STakanori Watanabe 		op->result = result;
364*3a601a23STakanori Watanabe 		if(ch->scid ==NG_L2CAP_ATT_CID||
365*3a601a23STakanori Watanabe 		   ch->scid ==NG_L2CAP_SMP_CID){
366*3a601a23STakanori Watanabe 			op->lcid = ch->con->con_handle;
367*3a601a23STakanori Watanabe 			op->idtype = (ch->scid==NG_L2CAP_ATT_CID)?
368*3a601a23STakanori Watanabe 				NG_L2CAP_L2CA_IDTYPE_ATT:
369*3a601a23STakanori Watanabe 				NG_L2CAP_L2CA_IDTYPE_SMP;
370*3a601a23STakanori Watanabe 		}else{
371*3a601a23STakanori Watanabe 			op->idtype =(ch->con->linktype ==NG_HCI_LINK_ACL)?
372*3a601a23STakanori Watanabe 				NG_L2CAP_L2CA_IDTYPE_BREDR:
373*3a601a23STakanori Watanabe 				NG_L2CAP_L2CA_IDTYPE_LE;
374*3a601a23STakanori Watanabe 		}
375*3a601a23STakanori Watanabe 
376*3a601a23STakanori Watanabe 
377*3a601a23STakanori Watanabe 		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
378*3a601a23STakanori Watanabe 	}
379*3a601a23STakanori Watanabe 
380*3a601a23STakanori Watanabe 	return (error);
381*3a601a23STakanori Watanabe 
382*3a601a23STakanori Watanabe }
383878ed226SJulian Elischer /*
384878ed226SJulian Elischer  * Send L2CAP_ConnectRsp response to the upper layer
385878ed226SJulian Elischer  */
386878ed226SJulian Elischer 
387878ed226SJulian Elischer int
388878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
389878ed226SJulian Elischer {
390878ed226SJulian Elischer 	ng_l2cap_p			 l2cap = ch->con->l2cap;
391878ed226SJulian Elischer 	struct ng_mesg			*msg = NULL;
392878ed226SJulian Elischer 	ng_l2cap_l2ca_con_rsp_op	*op = NULL;
393878ed226SJulian Elischer 	int				 error = 0;
394878ed226SJulian Elischer 
395878ed226SJulian Elischer 	/* Check if upstream hook is connected and valid */
396878ed226SJulian Elischer 	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
397878ed226SJulian Elischer 		NG_L2CAP_ERR(
398878ed226SJulian Elischer "%s: %s - unable to send L2CA_ConnectRsp response message. " \
399878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
400878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
401878ed226SJulian Elischer 
402878ed226SJulian Elischer 		return (ENOTCONN);
403878ed226SJulian Elischer 	}
404878ed226SJulian Elischer 
405878ed226SJulian Elischer 	/* Create and send L2CA_ConnectRsp response message */
406878ed226SJulian Elischer 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_RSP,
407878ed226SJulian Elischer 		sizeof(*op), M_NOWAIT);
408878ed226SJulian Elischer 	if (msg == NULL)
409878ed226SJulian Elischer 		error = ENOMEM;
410878ed226SJulian Elischer 	else {
411878ed226SJulian Elischer 		msg->header.token = token;
412878ed226SJulian Elischer 		msg->header.flags |= NGF_RESP;
413878ed226SJulian Elischer 
414878ed226SJulian Elischer 		op = (ng_l2cap_l2ca_con_rsp_op *)(msg->data);
415878ed226SJulian Elischer 		op->result = result;
416878ed226SJulian Elischer 
4174ae439a3SMaksim Yevmenkin 		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
418878ed226SJulian Elischer 	}
419878ed226SJulian Elischer 
420878ed226SJulian Elischer 	return (error);
421878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_rsp_rsp */
422878ed226SJulian Elischer 
423878ed226SJulian Elischer /*
424878ed226SJulian Elischer  * Send L2CA_ConnectInd message to the upper layer protocol.
425878ed226SJulian Elischer  */
426878ed226SJulian Elischer 
427878ed226SJulian Elischer int
428878ed226SJulian Elischer ng_l2cap_l2ca_con_ind(ng_l2cap_chan_p ch)
429878ed226SJulian Elischer {
430878ed226SJulian Elischer 	ng_l2cap_p			 l2cap = ch->con->l2cap;
431878ed226SJulian Elischer 	struct ng_mesg			*msg = NULL;
432878ed226SJulian Elischer 	ng_l2cap_l2ca_con_ind_ip	*ip = NULL;
433878ed226SJulian Elischer 	int				 error = 0;
434878ed226SJulian Elischer 
435878ed226SJulian Elischer 	/* Check if upstream hook is connected and valid */
436878ed226SJulian Elischer 	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
437878ed226SJulian Elischer 		NG_L2CAP_ERR(
438878ed226SJulian Elischer "%s: %s - unable to send L2CA_ConnectInd message. " \
439878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
440878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
441878ed226SJulian Elischer 
442878ed226SJulian Elischer 		return (ENOTCONN);
443878ed226SJulian Elischer 	}
444878ed226SJulian Elischer 
445878ed226SJulian Elischer 	/* Create and send L2CA_ConnectInd message */
446878ed226SJulian Elischer 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_IND,
447878ed226SJulian Elischer 		sizeof(*ip), M_NOWAIT);
448878ed226SJulian Elischer 	if (msg == NULL)
449878ed226SJulian Elischer 		error = ENOMEM;
450878ed226SJulian Elischer 	else {
451878ed226SJulian Elischer 		ip = (ng_l2cap_l2ca_con_ind_ip *)(msg->data);
452878ed226SJulian Elischer 
453878ed226SJulian Elischer 		bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr));
454878ed226SJulian Elischer 		ip->lcid = ch->scid;
455878ed226SJulian Elischer 		ip->psm = ch->psm;
456878ed226SJulian Elischer 		ip->ident = ch->ident;
45799043514STakanori Watanabe 		ip->linktype = ch->con->linktype;
458*3a601a23STakanori Watanabe 
4594ae439a3SMaksim Yevmenkin 		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
460878ed226SJulian Elischer 	}
461878ed226SJulian Elischer 
462878ed226SJulian Elischer 	return (error);
463878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_ind */
464878ed226SJulian Elischer 
465878ed226SJulian Elischer /*
466878ed226SJulian Elischer  * Process L2CA_Config request from the upper layer protocol
467878ed226SJulian Elischer  */
468878ed226SJulian Elischer 
469878ed226SJulian Elischer int
470878ed226SJulian Elischer ng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
471878ed226SJulian Elischer {
472878ed226SJulian Elischer 	ng_l2cap_l2ca_cfg_ip	*ip = NULL;
473878ed226SJulian Elischer 	ng_l2cap_chan_p		 ch = NULL;
474878ed226SJulian Elischer 	ng_l2cap_cmd_p		 cmd = NULL;
475878ed226SJulian Elischer 	struct mbuf		*opt = NULL;
476878ed226SJulian Elischer         u_int16_t		*mtu = NULL, *flush_timo = NULL;
477878ed226SJulian Elischer         ng_l2cap_flow_p		 flow = NULL;
478878ed226SJulian Elischer 	int			 error = 0;
479878ed226SJulian Elischer 
480878ed226SJulian Elischer 	/* Check message */
481878ed226SJulian Elischer 	if (msg->header.arglen != sizeof(*ip)) {
482878ed226SJulian Elischer 		NG_L2CAP_ALERT(
483878ed226SJulian Elischer "%s: %s - Invalid L2CA_Config request message size, size=%d\n",
484878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node),
485878ed226SJulian Elischer 			msg->header.arglen);
486878ed226SJulian Elischer 		error = EMSGSIZE;
487878ed226SJulian Elischer 		goto out;
488878ed226SJulian Elischer 	}
489878ed226SJulian Elischer 
490878ed226SJulian Elischer 	ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data);
491878ed226SJulian Elischer 
492878ed226SJulian Elischer 	/* Check if we have this channel */
493fbc48c2bSTakanori Watanabe 	ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, NG_L2CAP_L2CA_IDTYPE_BREDR);
494878ed226SJulian Elischer 	if (ch == NULL) {
495878ed226SJulian Elischer 		NG_L2CAP_ERR(
496878ed226SJulian Elischer "%s: %s - unexpected L2CA_Config request message. " \
497878ed226SJulian Elischer "Channel does not exist, lcid=%d\n",
498878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
499878ed226SJulian Elischer 		error = ENOENT;
500878ed226SJulian Elischer 		goto out;
501878ed226SJulian Elischer 	}
502878ed226SJulian Elischer 
503878ed226SJulian Elischer 	/* Check channel state */
504878ed226SJulian Elischer 	if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG) {
505878ed226SJulian Elischer 		NG_L2CAP_ERR(
506878ed226SJulian Elischer "%s: %s - unexpected L2CA_Config request message. " \
507878ed226SJulian Elischer "Invalid channel state, state=%d, lcid=%d\n",
508878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->state,
509878ed226SJulian Elischer 			ch->scid);
510878ed226SJulian Elischer 		error = EINVAL;
511878ed226SJulian Elischer 		goto out;
512878ed226SJulian Elischer 	}
513878ed226SJulian Elischer 
514878ed226SJulian Elischer 	/* Set requested channel configuration options */
515878ed226SJulian Elischer 	ch->imtu = ip->imtu;
516878ed226SJulian Elischer 	bcopy(&ip->oflow, &ch->oflow, sizeof(ch->oflow));
517878ed226SJulian Elischer 	ch->flush_timo = ip->flush_timo;
518878ed226SJulian Elischer 	ch->link_timo = ip->link_timo;
519878ed226SJulian Elischer 
520878ed226SJulian Elischer 	/* Compare channel settings with defaults */
521878ed226SJulian Elischer 	if (ch->imtu != NG_L2CAP_MTU_DEFAULT)
522878ed226SJulian Elischer 		mtu = &ch->imtu;
523878ed226SJulian Elischer 	if (ch->flush_timo != NG_L2CAP_FLUSH_TIMO_DEFAULT)
524878ed226SJulian Elischer 		flush_timo = &ch->flush_timo;
525878ed226SJulian Elischer 	if (bcmp(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)) != 0)
526878ed226SJulian Elischer 		flow = &ch->oflow;
527878ed226SJulian Elischer 
528878ed226SJulian Elischer 	/* Create configuration options */
529878ed226SJulian Elischer 	_ng_l2cap_build_cfg_options(opt, mtu, flush_timo, flow);
530878ed226SJulian Elischer 	if (opt == NULL) {
531878ed226SJulian Elischer                 error = ENOBUFS;
532878ed226SJulian Elischer 		goto out;
533878ed226SJulian Elischer 	}
534878ed226SJulian Elischer 
535878ed226SJulian Elischer 	/* Create L2CAP command descriptor */
536878ed226SJulian Elischer 	cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con),
537878ed226SJulian Elischer 			NG_L2CAP_CFG_REQ, msg->header.token);
538878ed226SJulian Elischer 	if (cmd == NULL) {
539878ed226SJulian Elischer 		NG_FREE_M(opt);
540878ed226SJulian Elischer 		error = ENOMEM;
541878ed226SJulian Elischer 		goto out;
542878ed226SJulian Elischer 	}
543878ed226SJulian Elischer 
544878ed226SJulian Elischer 	if (cmd->ident == NG_L2CAP_NULL_IDENT) {
545878ed226SJulian Elischer 		ng_l2cap_free_cmd(cmd);
546878ed226SJulian Elischer 		NG_FREE_M(opt);
547878ed226SJulian Elischer 		error = EIO;
548878ed226SJulian Elischer 		goto out;
549878ed226SJulian Elischer 	}
550878ed226SJulian Elischer 
551878ed226SJulian Elischer 	/* Create L2CAP command packet */
552878ed226SJulian Elischer 	_ng_l2cap_cfg_req(cmd->aux, cmd->ident, ch->dcid, 0, opt);
553878ed226SJulian Elischer 	if (cmd->aux == NULL) {
554878ed226SJulian Elischer 		ng_l2cap_free_cmd(cmd);
555878ed226SJulian Elischer 		error =  ENOBUFS;
556878ed226SJulian Elischer 		goto out;
557878ed226SJulian Elischer 	}
558878ed226SJulian Elischer 
559878ed226SJulian Elischer 	/* Adjust channel state for re-configuration */
560878ed226SJulian Elischer 	if (ch->state == NG_L2CAP_OPEN) {
561*3a601a23STakanori Watanabe 		ch->state = ((ch->scid == NG_L2CAP_ATT_CID)||
562*3a601a23STakanori Watanabe 			     (ch->scid == NG_L2CAP_SMP_CID))?
563fbc48c2bSTakanori Watanabe 			NG_L2CAP_OPEN : NG_L2CAP_CONFIG;
564878ed226SJulian Elischer 		ch->cfg_state = 0;
565878ed226SJulian Elischer 	}
566878ed226SJulian Elischer 
567878ed226SJulian Elischer         /* Link command to the queue */
568878ed226SJulian Elischer 	ng_l2cap_link_cmd(ch->con, cmd);
569878ed226SJulian Elischer 	ng_l2cap_lp_deliver(ch->con);
570878ed226SJulian Elischer out:
571878ed226SJulian Elischer 	return (error);
572878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_req */
573878ed226SJulian Elischer 
574878ed226SJulian Elischer /*
575878ed226SJulian Elischer  * Send L2CA_Config response to the upper layer protocol
576878ed226SJulian Elischer  */
577878ed226SJulian Elischer 
578878ed226SJulian Elischer int
579878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
580878ed226SJulian Elischer {
581878ed226SJulian Elischer 	ng_l2cap_p		 l2cap = ch->con->l2cap;
582878ed226SJulian Elischer 	struct ng_mesg		*msg = NULL;
583878ed226SJulian Elischer 	ng_l2cap_l2ca_cfg_op	*op = NULL;
584878ed226SJulian Elischer 	int			 error = 0;
585878ed226SJulian Elischer 
586878ed226SJulian Elischer 	/* Check if upstream hook is connected and valid */
587878ed226SJulian Elischer 	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
588878ed226SJulian Elischer 		NG_L2CAP_ERR(
589878ed226SJulian Elischer "%s: %s - unable to send L2CA_Config response message. " \
590878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
591878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
592878ed226SJulian Elischer 
593878ed226SJulian Elischer 		return (ENOTCONN);
594878ed226SJulian Elischer 	}
595878ed226SJulian Elischer 
596878ed226SJulian Elischer 	/* Create and send L2CA_Config response message */
597878ed226SJulian Elischer 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG,
598878ed226SJulian Elischer 		sizeof(*op), M_NOWAIT);
599878ed226SJulian Elischer 	if (msg == NULL)
600878ed226SJulian Elischer 		error = ENOMEM;
601878ed226SJulian Elischer 	else {
602878ed226SJulian Elischer 		msg->header.token = token;
603878ed226SJulian Elischer 		msg->header.flags |= NGF_RESP;
604878ed226SJulian Elischer 
605878ed226SJulian Elischer 		op = (ng_l2cap_l2ca_cfg_op *)(msg->data);
606878ed226SJulian Elischer 		op->result = result;
607878ed226SJulian Elischer 		op->imtu = ch->imtu;
608878ed226SJulian Elischer 		bcopy(&ch->oflow, &op->oflow, sizeof(op->oflow));
609878ed226SJulian Elischer 		op->flush_timo = ch->flush_timo;
610878ed226SJulian Elischer 
6114ae439a3SMaksim Yevmenkin 		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
612878ed226SJulian Elischer 
613878ed226SJulian Elischer 		if (error == 0 && result == NG_L2CAP_SUCCESS) {
614878ed226SJulian Elischer 			ch->cfg_state |= NG_L2CAP_CFG_IN;
615878ed226SJulian Elischer 
616878ed226SJulian Elischer 			if (ch->cfg_state == NG_L2CAP_CFG_BOTH)
617878ed226SJulian Elischer 				ch->state = NG_L2CAP_OPEN;
618878ed226SJulian Elischer 		}
619878ed226SJulian Elischer 	}
620878ed226SJulian Elischer 
621878ed226SJulian Elischer 	return (error);
622878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_rsp */
623878ed226SJulian Elischer 
624878ed226SJulian Elischer /*
625878ed226SJulian Elischer  * Process L2CA_ConfigRsp request from the upper layer protocol
626878ed226SJulian Elischer  *
627878ed226SJulian Elischer  * XXX XXX XXX
628878ed226SJulian Elischer  *
629878ed226SJulian Elischer  * NOTE: The Bluetooth specification says that Configuration_Response
630878ed226SJulian Elischer  * (L2CA_ConfigRsp) should be used to issue response to configuration request
631878ed226SJulian Elischer  * indication. The minor problem here is L2CAP command ident. We should use
632878ed226SJulian Elischer  * ident from original L2CAP request to make sure our peer can match request
633878ed226SJulian Elischer  * and response. For some reason Bluetooth specification does not include
634878ed226SJulian Elischer  * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems
635878ed226SJulian Elischer  * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident
636878ed226SJulian Elischer  * field. So we should store last known L2CAP request command ident in channel.
637878ed226SJulian Elischer  * Also it seems that upper layer can not reject configuration request, as
638878ed226SJulian Elischer  * Configuration_Response message does not have status/reason field.
639878ed226SJulian Elischer  */
640878ed226SJulian Elischer 
641878ed226SJulian Elischer int
642878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
643878ed226SJulian Elischer {
644878ed226SJulian Elischer 	ng_l2cap_l2ca_cfg_rsp_ip	*ip = NULL;
645878ed226SJulian Elischer 	ng_l2cap_chan_p			 ch = NULL;
646878ed226SJulian Elischer 	ng_l2cap_cmd_p			 cmd = NULL;
647878ed226SJulian Elischer 	struct mbuf			*opt = NULL;
648878ed226SJulian Elischer 	u_int16_t			*mtu = NULL;
649878ed226SJulian Elischer 	ng_l2cap_flow_p			 flow = NULL;
650878ed226SJulian Elischer 	int				 error = 0;
651878ed226SJulian Elischer 
652878ed226SJulian Elischer 	/* Check message */
653878ed226SJulian Elischer 	if (msg->header.arglen != sizeof(*ip)) {
654878ed226SJulian Elischer 		NG_L2CAP_ALERT(
655878ed226SJulian Elischer "%s: %s - invalid L2CA_ConfigRsp request message size, size=%d\n",
656878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node),
657878ed226SJulian Elischer 			msg->header.arglen);
658878ed226SJulian Elischer 		error = EMSGSIZE;
659878ed226SJulian Elischer 		goto out;
660878ed226SJulian Elischer 	}
661878ed226SJulian Elischer 
662878ed226SJulian Elischer 	ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data);
663878ed226SJulian Elischer 
664878ed226SJulian Elischer 	/* Check if we have this channel */
665fbc48c2bSTakanori Watanabe 	ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid,
666fbc48c2bSTakanori Watanabe 				   NG_L2CAP_L2CA_IDTYPE_BREDR);
667878ed226SJulian Elischer 	if (ch == NULL) {
668878ed226SJulian Elischer 		NG_L2CAP_ERR(
669878ed226SJulian Elischer "%s: %s - unexpected L2CA_ConfigRsp request message. " \
670878ed226SJulian Elischer "Channel does not exist, lcid=%d\n",
671878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
672878ed226SJulian Elischer 		error = ENOENT;
673878ed226SJulian Elischer 		goto out;
674878ed226SJulian Elischer 	}
675878ed226SJulian Elischer 
676878ed226SJulian Elischer 	/* Check channel state */
677878ed226SJulian Elischer 	if (ch->state != NG_L2CAP_CONFIG) {
678878ed226SJulian Elischer 		NG_L2CAP_ERR(
679878ed226SJulian Elischer "%s: %s - unexpected L2CA_ConfigRsp request message. " \
680878ed226SJulian Elischer "Invalid channel state, state=%d, lcid=%d\n",
681878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->state,
682878ed226SJulian Elischer 			ch->scid);
683878ed226SJulian Elischer 		error = EINVAL;
684878ed226SJulian Elischer 		goto out;
685878ed226SJulian Elischer 	}
686878ed226SJulian Elischer 
687878ed226SJulian Elischer 	/* Set channel settings */
688878ed226SJulian Elischer 	if (ip->omtu != ch->omtu) {
689878ed226SJulian Elischer 		ch->omtu = ip->omtu;
690878ed226SJulian Elischer 		mtu = &ch->omtu;
691878ed226SJulian Elischer 	}
692878ed226SJulian Elischer 
693878ed226SJulian Elischer 	if (bcmp(&ip->iflow, &ch->iflow, sizeof(ch->iflow)) != 0) {
694878ed226SJulian Elischer 		bcopy(&ip->iflow, &ch->iflow, sizeof(ch->iflow));
695878ed226SJulian Elischer 		flow = &ch->iflow;
696878ed226SJulian Elischer 	}
697878ed226SJulian Elischer 
698878ed226SJulian Elischer 	if (mtu != NULL || flow != NULL) {
699878ed226SJulian Elischer 		_ng_l2cap_build_cfg_options(opt, mtu, NULL, flow);
700878ed226SJulian Elischer 		if (opt == NULL) {
701878ed226SJulian Elischer 			error = ENOBUFS;
702878ed226SJulian Elischer 			goto out;
703878ed226SJulian Elischer 		}
704878ed226SJulian Elischer 	}
705878ed226SJulian Elischer 
706878ed226SJulian Elischer 	/* Create L2CAP command */
707878ed226SJulian Elischer 	cmd = ng_l2cap_new_cmd(ch->con, ch, ch->ident, NG_L2CAP_CFG_RSP,
708878ed226SJulian Elischer 			msg->header.token);
709878ed226SJulian Elischer 	if (cmd == NULL) {
710878ed226SJulian Elischer 		NG_FREE_M(opt);
711878ed226SJulian Elischer 		error = ENOMEM;
712878ed226SJulian Elischer 		goto out;
713878ed226SJulian Elischer 	}
714878ed226SJulian Elischer 
715878ed226SJulian Elischer 	_ng_l2cap_cfg_rsp(cmd->aux,cmd->ident,ch->dcid,0,NG_L2CAP_SUCCESS,opt);
716878ed226SJulian Elischer 	if (cmd->aux == NULL) {
717878ed226SJulian Elischer 		ng_l2cap_free_cmd(cmd);
718878ed226SJulian Elischer 		error = ENOBUFS;
719878ed226SJulian Elischer 		goto out;
720878ed226SJulian Elischer 	}
721878ed226SJulian Elischer 
722878ed226SJulian Elischer 	/* XXX FIXME - not here ??? */
723878ed226SJulian Elischer 	ch->cfg_state |= NG_L2CAP_CFG_OUT;
724878ed226SJulian Elischer 	if (ch->cfg_state == NG_L2CAP_CFG_BOTH)
725878ed226SJulian Elischer 		ch->state = NG_L2CAP_OPEN;
726878ed226SJulian Elischer 
727878ed226SJulian Elischer 	/* Link command to the queue */
728878ed226SJulian Elischer 	ng_l2cap_link_cmd(ch->con, cmd);
729878ed226SJulian Elischer 	ng_l2cap_lp_deliver(ch->con);
730878ed226SJulian Elischer out:
731878ed226SJulian Elischer 	return (error);
732878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_rsp_req */
733878ed226SJulian Elischer 
734878ed226SJulian Elischer /*
735878ed226SJulian Elischer  * Send L2CA_ConfigRsp response to the upper layer protocol
736878ed226SJulian Elischer  */
737878ed226SJulian Elischer 
738878ed226SJulian Elischer int
739878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
740878ed226SJulian Elischer {
741878ed226SJulian Elischer 	ng_l2cap_p			 l2cap = ch->con->l2cap;
742878ed226SJulian Elischer 	struct ng_mesg			*msg = NULL;
743878ed226SJulian Elischer 	ng_l2cap_l2ca_cfg_rsp_op	*op = NULL;
744878ed226SJulian Elischer 	int				 error = 0;
745878ed226SJulian Elischer 
746878ed226SJulian Elischer 	/* Check if upstream hook is connected and valid */
747878ed226SJulian Elischer 	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
748878ed226SJulian Elischer 		NG_L2CAP_ERR(
749878ed226SJulian Elischer "%s: %s - unable to send L2CA_ConfigRsp response message. " \
750878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
751878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
752878ed226SJulian Elischer 
753878ed226SJulian Elischer 		return (ENOTCONN);
754878ed226SJulian Elischer 	}
755878ed226SJulian Elischer 
756878ed226SJulian Elischer 	/* Create and send L2CA_ConfigRsp response message */
757878ed226SJulian Elischer 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP,
758878ed226SJulian Elischer 		sizeof(*op), M_NOWAIT);
759878ed226SJulian Elischer 	if (msg == NULL)
760878ed226SJulian Elischer 		error = ENOMEM;
761878ed226SJulian Elischer 	else {
762878ed226SJulian Elischer 		msg->header.token = token;
763878ed226SJulian Elischer 		msg->header.flags |= NGF_RESP;
764878ed226SJulian Elischer 
765878ed226SJulian Elischer 		op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data);
766878ed226SJulian Elischer 		op->result = result;
767878ed226SJulian Elischer 
7684ae439a3SMaksim Yevmenkin 		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
769878ed226SJulian Elischer 	}
770878ed226SJulian Elischer 
771878ed226SJulian Elischer 	return (error);
772878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_rsp_rsp */
773878ed226SJulian Elischer 
774878ed226SJulian Elischer /*
775878ed226SJulian Elischer  * Send L2CA_ConfigInd message to the upper layer protocol
776878ed226SJulian Elischer  *
777878ed226SJulian Elischer  * XXX XXX XXX
778878ed226SJulian Elischer  *
779878ed226SJulian Elischer  * NOTE: The Bluetooth specification says that Configuration_Response
780878ed226SJulian Elischer  * (L2CA_ConfigRsp) should be used to issue response to configuration request
781878ed226SJulian Elischer  * indication. The minor problem here is L2CAP command ident. We should use
782878ed226SJulian Elischer  * ident from original L2CAP request to make sure our peer can match request
783878ed226SJulian Elischer  * and response. For some reason Bluetooth specification does not include
784878ed226SJulian Elischer  * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems
785878ed226SJulian Elischer  * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident
786878ed226SJulian Elischer  * field. So we should store last known L2CAP request command ident in channel.
787878ed226SJulian Elischer  * Also it seems that upper layer can not reject configuration request, as
788878ed226SJulian Elischer  * Configuration_Response message does not have status/reason field.
789878ed226SJulian Elischer  */
790878ed226SJulian Elischer 
791878ed226SJulian Elischer int
792878ed226SJulian Elischer ng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch)
793878ed226SJulian Elischer {
794878ed226SJulian Elischer 	ng_l2cap_p			 l2cap = ch->con->l2cap;
795878ed226SJulian Elischer 	struct ng_mesg			*msg = NULL;
796878ed226SJulian Elischer 	ng_l2cap_l2ca_cfg_ind_ip	*ip = NULL;
797878ed226SJulian Elischer 	int				 error = 0;
798878ed226SJulian Elischer 
799878ed226SJulian Elischer 	/* Check if upstream hook is connected and valid */
800878ed226SJulian Elischer 	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
801878ed226SJulian Elischer 		NG_L2CAP_ERR(
802878ed226SJulian Elischer "%s: %s - Unable to send L2CA_ConfigInd message. " \
803878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
804878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
805878ed226SJulian Elischer 
806878ed226SJulian Elischer 		return (ENOTCONN);
807878ed226SJulian Elischer 	}
808878ed226SJulian Elischer 
809878ed226SJulian Elischer 	/* Create and send L2CA_ConnectInd message */
810878ed226SJulian Elischer 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_IND,
811878ed226SJulian Elischer 			sizeof(*ip), M_NOWAIT);
812878ed226SJulian Elischer 	if (msg == NULL)
813878ed226SJulian Elischer 		error = ENOMEM;
814878ed226SJulian Elischer 	else {
815878ed226SJulian Elischer 		ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data);
816878ed226SJulian Elischer 		ip->lcid = ch->scid;
817878ed226SJulian Elischer 		ip->omtu = ch->omtu;
818878ed226SJulian Elischer 		bcopy(&ch->iflow, &ip->iflow, sizeof(ip->iflow));
819878ed226SJulian Elischer 		ip->flush_timo = ch->flush_timo;
820878ed226SJulian Elischer 
8214ae439a3SMaksim Yevmenkin 		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
822878ed226SJulian Elischer 	}
823878ed226SJulian Elischer 
824878ed226SJulian Elischer 	return (error);
825878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_ind */
826878ed226SJulian Elischer 
827878ed226SJulian Elischer /*
828878ed226SJulian Elischer  * Process L2CA_Write event
829878ed226SJulian Elischer  */
830878ed226SJulian Elischer 
831878ed226SJulian Elischer int
832878ed226SJulian Elischer ng_l2cap_l2ca_write_req(ng_l2cap_p l2cap, struct mbuf *m)
833878ed226SJulian Elischer {
834878ed226SJulian Elischer 	ng_l2cap_l2ca_hdr_t	*l2ca_hdr = NULL;
835878ed226SJulian Elischer 	ng_l2cap_chan_p		 ch = NULL;
836878ed226SJulian Elischer 	ng_l2cap_cmd_p		 cmd = NULL;
837878ed226SJulian Elischer 	int			 error = 0;
838878ed226SJulian Elischer 	u_int32_t		 token = 0;
839878ed226SJulian Elischer 
840878ed226SJulian Elischer 	/* Make sure we can access L2CA data packet header */
841878ed226SJulian Elischer 	if (m->m_pkthdr.len < sizeof(*l2ca_hdr)) {
842878ed226SJulian Elischer 		NG_L2CAP_ERR(
843878ed226SJulian Elischer "%s: %s - L2CA Data packet too small, len=%d\n",
844878ed226SJulian Elischer 			__func__,NG_NODE_NAME(l2cap->node),m->m_pkthdr.len);
845878ed226SJulian Elischer 		error = EMSGSIZE;
846878ed226SJulian Elischer 		goto drop;
847878ed226SJulian Elischer 	}
848878ed226SJulian Elischer 
849878ed226SJulian Elischer 	/* Get L2CA data packet header */
850878ed226SJulian Elischer 	NG_L2CAP_M_PULLUP(m, sizeof(*l2ca_hdr));
851878ed226SJulian Elischer 	if (m == NULL)
852878ed226SJulian Elischer 		return (ENOBUFS);
853878ed226SJulian Elischer 
854878ed226SJulian Elischer 	l2ca_hdr = mtod(m, ng_l2cap_l2ca_hdr_t *);
855878ed226SJulian Elischer 	token = l2ca_hdr->token;
856878ed226SJulian Elischer 	m_adj(m, sizeof(*l2ca_hdr));
857878ed226SJulian Elischer 
858878ed226SJulian Elischer 	/* Verify payload size */
859878ed226SJulian Elischer 	if (l2ca_hdr->length != m->m_pkthdr.len) {
860878ed226SJulian Elischer 		NG_L2CAP_ERR(
861878ed226SJulian Elischer "%s: %s - invalid L2CA Data packet. " \
862878ed226SJulian Elischer "Payload length does not match, length=%d, len=%d\n",
863878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->length,
864878ed226SJulian Elischer 			m->m_pkthdr.len);
865878ed226SJulian Elischer 		error = EMSGSIZE;
866878ed226SJulian Elischer 		goto drop;
867878ed226SJulian Elischer 	}
868878ed226SJulian Elischer 
869878ed226SJulian Elischer 	/* Check channel ID */
870fbc48c2bSTakanori Watanabe 	if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
871fbc48c2bSTakanori Watanabe 		ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
872fbc48c2bSTakanori Watanabe 						l2ca_hdr->lcid);
873*3a601a23STakanori Watanabe 	} else if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
874*3a601a23STakanori Watanabe 		ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
875*3a601a23STakanori Watanabe 						l2ca_hdr->lcid);
876fbc48c2bSTakanori Watanabe 	}else{
877878ed226SJulian Elischer 		if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) {
878878ed226SJulian Elischer 			NG_L2CAP_ERR(
879878ed226SJulian Elischer 				"%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n",
880fbc48c2bSTakanori Watanabe 				__func__, NG_NODE_NAME(l2cap->node),
881fbc48c2bSTakanori Watanabe 				l2ca_hdr->lcid);
882878ed226SJulian Elischer 			error = EINVAL;
883878ed226SJulian Elischer 			goto drop;
884878ed226SJulian Elischer 		}
885878ed226SJulian Elischer 
886878ed226SJulian Elischer 		/* Verify that we have the channel and make sure it is open */
887fbc48c2bSTakanori Watanabe 		ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid,
888fbc48c2bSTakanori Watanabe 					   l2ca_hdr->idtype);
889fbc48c2bSTakanori Watanabe 	}
890fbc48c2bSTakanori Watanabe 
891878ed226SJulian Elischer 	if (ch == NULL) {
892878ed226SJulian Elischer 		NG_L2CAP_ERR(
893878ed226SJulian Elischer "%s: %s - invalid L2CA Data packet. Channel does not exist, cid=%d\n",
894878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid);
895878ed226SJulian Elischer 		error = ENOENT;
896878ed226SJulian Elischer 		goto drop;
897878ed226SJulian Elischer 	}
898878ed226SJulian Elischer 
899878ed226SJulian Elischer 	if (ch->state != NG_L2CAP_OPEN) {
900878ed226SJulian Elischer 		NG_L2CAP_ERR(
901878ed226SJulian Elischer "%s: %s - invalid L2CA Data packet. Invalid channel state, scid=%d, state=%d\n",
902878ed226SJulian Elischer 			 __func__, NG_NODE_NAME(l2cap->node), ch->scid,
903878ed226SJulian Elischer 			ch->state);
904878ed226SJulian Elischer 		error = EHOSTDOWN;
905878ed226SJulian Elischer 		goto drop; /* XXX not always - re-configure */
906878ed226SJulian Elischer 	}
907878ed226SJulian Elischer 
908878ed226SJulian Elischer 	/* Create L2CAP command descriptor */
909878ed226SJulian Elischer 	cmd = ng_l2cap_new_cmd(ch->con, ch, 0, NGM_L2CAP_L2CA_WRITE, token);
910878ed226SJulian Elischer 	if (cmd == NULL) {
911878ed226SJulian Elischer 		error = ENOMEM;
912878ed226SJulian Elischer 		goto drop;
913878ed226SJulian Elischer 	}
914878ed226SJulian Elischer 
915878ed226SJulian Elischer 	/* Attach data packet and link command to the queue */
916878ed226SJulian Elischer 	cmd->aux = m;
917878ed226SJulian Elischer 	ng_l2cap_link_cmd(ch->con, cmd);
918878ed226SJulian Elischer 	ng_l2cap_lp_deliver(ch->con);
919878ed226SJulian Elischer 
920878ed226SJulian Elischer 	return (error);
921878ed226SJulian Elischer drop:
922878ed226SJulian Elischer 	NG_FREE_M(m);
923878ed226SJulian Elischer 
924878ed226SJulian Elischer 	return (error);
925878ed226SJulian Elischer } /* ng_l2cap_l2ca_write_req */
926878ed226SJulian Elischer 
927878ed226SJulian Elischer /*
928878ed226SJulian Elischer  * Send L2CA_Write response
929878ed226SJulian Elischer  */
930878ed226SJulian Elischer 
931878ed226SJulian Elischer int
932878ed226SJulian Elischer ng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
933878ed226SJulian Elischer 		u_int16_t length)
934878ed226SJulian Elischer {
935878ed226SJulian Elischer 	ng_l2cap_p		 l2cap = ch->con->l2cap;
936878ed226SJulian Elischer 	struct ng_mesg		*msg = NULL;
937878ed226SJulian Elischer 	ng_l2cap_l2ca_write_op	*op = NULL;
938878ed226SJulian Elischer 	int			 error = 0;
939878ed226SJulian Elischer 
940878ed226SJulian Elischer 	/* Check if upstream hook is connected and valid */
941878ed226SJulian Elischer 	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
942878ed226SJulian Elischer 		NG_L2CAP_ERR(
943878ed226SJulian Elischer "%s: %s - unable to send L2CA_WriteRsp message. " \
944878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
945878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
946878ed226SJulian Elischer 
947878ed226SJulian Elischer 		return (ENOTCONN);
948878ed226SJulian Elischer 	}
949878ed226SJulian Elischer 
950878ed226SJulian Elischer 	/* Create and send L2CA_WriteRsp message */
951878ed226SJulian Elischer 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_WRITE,
952878ed226SJulian Elischer 			sizeof(*op), M_NOWAIT);
953878ed226SJulian Elischer 	if (msg == NULL)
954878ed226SJulian Elischer 		error = ENOMEM;
955878ed226SJulian Elischer 	else {
956878ed226SJulian Elischer 		msg->header.token = token;
957878ed226SJulian Elischer 		msg->header.flags |= NGF_RESP;
958878ed226SJulian Elischer 
959878ed226SJulian Elischer 		op = (ng_l2cap_l2ca_write_op *)(msg->data);
960878ed226SJulian Elischer 		op->result = result;
961878ed226SJulian Elischer 		op->length = length;
962fbc48c2bSTakanori Watanabe 		if(ch->scid == NG_L2CAP_ATT_CID){
963fbc48c2bSTakanori Watanabe 			op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
964fbc48c2bSTakanori Watanabe 			op->lcid = ch->con->con_handle;
965*3a601a23STakanori Watanabe 		}else if(ch->scid == NG_L2CAP_SMP_CID){
966*3a601a23STakanori Watanabe 			op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
967*3a601a23STakanori Watanabe 			op->lcid = ch->con->con_handle;
968fbc48c2bSTakanori Watanabe 		}else{
969fbc48c2bSTakanori Watanabe 			op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
970fbc48c2bSTakanori Watanabe 				NG_L2CAP_L2CA_IDTYPE_BREDR :
971fbc48c2bSTakanori Watanabe 				NG_L2CAP_L2CA_IDTYPE_LE;
972878ed226SJulian Elischer 			op->lcid = ch->scid;
973878ed226SJulian Elischer 
974fbc48c2bSTakanori Watanabe 		}
9754ae439a3SMaksim Yevmenkin 		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
976878ed226SJulian Elischer 	}
977878ed226SJulian Elischer 
978878ed226SJulian Elischer 	return (error);
979878ed226SJulian Elischer } /* ng_l2cap_l2ca_write_rsp */
980878ed226SJulian Elischer 
981878ed226SJulian Elischer /*
982878ed226SJulian Elischer  * Receive packet from the lower layer protocol and send it to the upper
983878ed226SJulian Elischer  * layer protocol (L2CAP_Read)
984878ed226SJulian Elischer  */
985878ed226SJulian Elischer 
986878ed226SJulian Elischer int
987878ed226SJulian Elischer ng_l2cap_l2ca_receive(ng_l2cap_con_p con)
988878ed226SJulian Elischer {
989878ed226SJulian Elischer 	ng_l2cap_p	 l2cap = con->l2cap;
990878ed226SJulian Elischer 	ng_l2cap_hdr_t	*hdr = NULL;
991878ed226SJulian Elischer 	ng_l2cap_chan_p  ch = NULL;
992878ed226SJulian Elischer 	int		 error = 0;
993fbc48c2bSTakanori Watanabe 	int idtype;
994fbc48c2bSTakanori Watanabe 	uint16_t *idp;
995*3a601a23STakanori Watanabe 	int silent = 0;
996878ed226SJulian Elischer 
997878ed226SJulian Elischer 	NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
998878ed226SJulian Elischer 	if (con->rx_pkt == NULL)
999878ed226SJulian Elischer 		return (ENOBUFS);
1000878ed226SJulian Elischer 
1001878ed226SJulian Elischer 	hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *);
1002878ed226SJulian Elischer 
1003878ed226SJulian Elischer 	/* Check channel */
1004fbc48c2bSTakanori Watanabe 
1005fbc48c2bSTakanori Watanabe 	if(hdr->dcid == NG_L2CAP_ATT_CID){
1006fbc48c2bSTakanori Watanabe 		idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
1007fbc48c2bSTakanori Watanabe 		ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
1008fbc48c2bSTakanori Watanabe 						con->con_handle);
1009fbc48c2bSTakanori Watanabe 		/*
1010fbc48c2bSTakanori Watanabe 		 * Here,ATT channel is distinguished by
1011fbc48c2bSTakanori Watanabe 		 * connection handle
1012fbc48c2bSTakanori Watanabe 		 */
1013fbc48c2bSTakanori Watanabe 		hdr->dcid = con->con_handle;
1014*3a601a23STakanori Watanabe 		silent = 1;
1015*3a601a23STakanori Watanabe 	}else if(hdr->dcid == NG_L2CAP_SMP_CID){
1016*3a601a23STakanori Watanabe 		idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
1017*3a601a23STakanori Watanabe 		ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
1018*3a601a23STakanori Watanabe 						con->con_handle);
1019*3a601a23STakanori Watanabe 		/*
1020*3a601a23STakanori Watanabe 		 * Here,SMP channel is distinguished by
1021*3a601a23STakanori Watanabe 		 * connection handle
1022*3a601a23STakanori Watanabe 		 */
1023*3a601a23STakanori Watanabe 		silent = 1;
1024*3a601a23STakanori Watanabe 		hdr->dcid = con->con_handle;
1025fbc48c2bSTakanori Watanabe 	}else{
1026fbc48c2bSTakanori Watanabe 		idtype = (con->linktype==NG_HCI_LINK_ACL)?
1027fbc48c2bSTakanori Watanabe 			NG_L2CAP_L2CA_IDTYPE_BREDR:
1028fbc48c2bSTakanori Watanabe 			NG_L2CAP_L2CA_IDTYPE_LE;
1029fbc48c2bSTakanori Watanabe 		ch = ng_l2cap_chan_by_scid(l2cap, hdr->dcid, idtype);
1030fbc48c2bSTakanori Watanabe 	}
1031878ed226SJulian Elischer 	if (ch == NULL) {
1032*3a601a23STakanori Watanabe 		if(!silent)
1033878ed226SJulian Elischer 			NG_L2CAP_ERR(
1034fbc48c2bSTakanori Watanabe "%s: %s - unexpected L2CAP data packet. Channel does not exist, cid=%d, idtype=%d\n",
1035fbc48c2bSTakanori Watanabe 	__func__, NG_NODE_NAME(l2cap->node), hdr->dcid, idtype);
1036878ed226SJulian Elischer 		error = ENOENT;
1037878ed226SJulian Elischer 		goto drop;
1038878ed226SJulian Elischer 	}
1039878ed226SJulian Elischer 
1040878ed226SJulian Elischer 	/* Check channel state */
1041878ed226SJulian Elischer 	if (ch->state != NG_L2CAP_OPEN) {
1042878ed226SJulian Elischer 		NG_L2CAP_WARN(
1043878ed226SJulian Elischer "%s: %s - unexpected L2CAP data packet. " \
1044878ed226SJulian Elischer "Invalid channel state, cid=%d, state=%d\n",
1045878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->scid,
1046878ed226SJulian Elischer 			ch->state);
1047878ed226SJulian Elischer 		error = EHOSTDOWN; /* XXX not always - re-configuration */
1048878ed226SJulian Elischer 		goto drop;
1049878ed226SJulian Elischer 	}
1050878ed226SJulian Elischer 
1051878ed226SJulian Elischer 	/* Check payload size and channel's MTU */
1052878ed226SJulian Elischer 	if (hdr->length > ch->imtu) {
1053878ed226SJulian Elischer 		NG_L2CAP_ERR(
1054878ed226SJulian Elischer "%s: %s - invalid L2CAP data packet. " \
1055878ed226SJulian Elischer "Packet too big, length=%d, imtu=%d, cid=%d\n",
1056878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), hdr->length,
1057878ed226SJulian Elischer 			ch->imtu, ch->scid);
1058878ed226SJulian Elischer 		error = EMSGSIZE;
1059878ed226SJulian Elischer 		goto drop;
1060878ed226SJulian Elischer 	}
1061878ed226SJulian Elischer 
1062878ed226SJulian Elischer 	/*
1063878ed226SJulian Elischer 	 * If we got here then everything looks good and we can sent packet
1064878ed226SJulian Elischer 	 * to the upper layer protocol.
1065878ed226SJulian Elischer 	 */
1066878ed226SJulian Elischer 
1067878ed226SJulian Elischer 	/* Check if upstream hook is connected and valid */
1068878ed226SJulian Elischer 	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1069878ed226SJulian Elischer 		NG_L2CAP_ERR(
1070878ed226SJulian Elischer "%s: %s - unable to send L2CAP data packet. " \
1071878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
1072878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
1073878ed226SJulian Elischer 		error = ENOTCONN;
1074878ed226SJulian Elischer 		goto drop;
1075878ed226SJulian Elischer 	}
1076fbc48c2bSTakanori Watanabe 	M_PREPEND(con->rx_pkt, sizeof(uint16_t), M_NOWAIT);
1077fbc48c2bSTakanori Watanabe 	if(con->rx_pkt == NULL)
1078fbc48c2bSTakanori Watanabe 		goto drop;
1079fbc48c2bSTakanori Watanabe 	idp = mtod(con->rx_pkt, uint16_t *);
1080fbc48c2bSTakanori Watanabe 	*idp = idtype;
1081878ed226SJulian Elischer 
1082878ed226SJulian Elischer 	NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
1083878ed226SJulian Elischer 	con->rx_pkt = NULL;
1084878ed226SJulian Elischer drop:
1085878ed226SJulian Elischer 	NG_FREE_M(con->rx_pkt); /* checks for != NULL */
1086878ed226SJulian Elischer 
1087878ed226SJulian Elischer 	return (error);
1088878ed226SJulian Elischer } /* ng_l2cap_receive */
1089878ed226SJulian Elischer 
1090878ed226SJulian Elischer /*
1091878ed226SJulian Elischer  * Receive connectioless (multicast) packet from the lower layer protocol and
1092878ed226SJulian Elischer  * send it to the upper layer protocol
1093878ed226SJulian Elischer  */
1094878ed226SJulian Elischer 
1095878ed226SJulian Elischer int
1096878ed226SJulian Elischer ng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con)
1097878ed226SJulian Elischer {
1098878ed226SJulian Elischer 	struct _clt_pkt {
1099878ed226SJulian Elischer 		ng_l2cap_hdr_t		 h;
1100878ed226SJulian Elischer 		ng_l2cap_clt_hdr_t	 c_h;
1101878ed226SJulian Elischer 	} __attribute__ ((packed))	*hdr = NULL;
1102878ed226SJulian Elischer 	ng_l2cap_p			 l2cap = con->l2cap;
1103878ed226SJulian Elischer 	int				 length, error = 0;
1104878ed226SJulian Elischer 
1105878ed226SJulian Elischer 	NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
1106878ed226SJulian Elischer 	if (con->rx_pkt == NULL)
1107878ed226SJulian Elischer 		return (ENOBUFS);
1108878ed226SJulian Elischer 
1109878ed226SJulian Elischer 	hdr = mtod(con->rx_pkt, struct _clt_pkt *);
1110878ed226SJulian Elischer 
1111878ed226SJulian Elischer 	/* Check packet */
1112878ed226SJulian Elischer 	length = con->rx_pkt->m_pkthdr.len - sizeof(*hdr);
1113878ed226SJulian Elischer 	if (length < 0) {
1114878ed226SJulian Elischer 		NG_L2CAP_ERR(
1115878ed226SJulian Elischer "%s: %s - invalid L2CAP CLT data packet. Packet too small, length=%d\n",
1116878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), length);
1117878ed226SJulian Elischer 		error = EMSGSIZE;
1118878ed226SJulian Elischer 		goto drop;
1119878ed226SJulian Elischer 	}
1120878ed226SJulian Elischer 
1121878ed226SJulian Elischer 	/* Check payload size against CLT MTU */
1122878ed226SJulian Elischer 	if (length > NG_L2CAP_MTU_DEFAULT) {
1123878ed226SJulian Elischer 		NG_L2CAP_ERR(
1124878ed226SJulian Elischer "%s: %s - invalid L2CAP CLT data packet. Packet too big, length=%d, mtu=%d\n",
1125878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), length,
1126878ed226SJulian Elischer 			NG_L2CAP_MTU_DEFAULT);
1127878ed226SJulian Elischer 		error = EMSGSIZE;
1128878ed226SJulian Elischer 		goto drop;
1129878ed226SJulian Elischer 	}
1130878ed226SJulian Elischer 
1131878ed226SJulian Elischer 	hdr->c_h.psm = le16toh(hdr->c_h.psm);
1132878ed226SJulian Elischer 
1133878ed226SJulian Elischer 	/*
1134878ed226SJulian Elischer 	 * If we got here then everything looks good and we can sent packet
1135878ed226SJulian Elischer 	 * to the upper layer protocol.
1136878ed226SJulian Elischer 	 */
1137878ed226SJulian Elischer 
1138878ed226SJulian Elischer 	/* Select upstream hook based on PSM */
1139878ed226SJulian Elischer 	switch (hdr->c_h.psm) {
1140878ed226SJulian Elischer 	case NG_L2CAP_PSM_SDP:
1141878ed226SJulian Elischer 		if (l2cap->flags & NG_L2CAP_CLT_SDP_DISABLED)
1142878ed226SJulian Elischer 			goto drop;
1143878ed226SJulian Elischer 		break;
1144878ed226SJulian Elischer 
1145878ed226SJulian Elischer 	case NG_L2CAP_PSM_RFCOMM:
1146878ed226SJulian Elischer 		if (l2cap->flags & NG_L2CAP_CLT_RFCOMM_DISABLED)
1147878ed226SJulian Elischer 			goto drop;
1148878ed226SJulian Elischer 		break;
1149878ed226SJulian Elischer 
1150878ed226SJulian Elischer 	case NG_L2CAP_PSM_TCP:
1151878ed226SJulian Elischer 		if (l2cap->flags & NG_L2CAP_CLT_TCP_DISABLED)
1152878ed226SJulian Elischer 			goto drop;
1153878ed226SJulian Elischer 		break;
1154878ed226SJulian Elischer         }
1155878ed226SJulian Elischer 
1156878ed226SJulian Elischer 	/* Check if upstream hook is connected and valid */
1157878ed226SJulian Elischer 	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1158878ed226SJulian Elischer 		NG_L2CAP_ERR(
1159878ed226SJulian Elischer "%s: %s - unable to send L2CAP CLT data packet. " \
1160878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
1161878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), hdr->c_h.psm);
1162878ed226SJulian Elischer 		error = ENOTCONN;
1163878ed226SJulian Elischer 		goto drop;
1164878ed226SJulian Elischer 	}
1165878ed226SJulian Elischer 
1166878ed226SJulian Elischer 	NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
1167878ed226SJulian Elischer 	con->rx_pkt = NULL;
1168878ed226SJulian Elischer drop:
1169878ed226SJulian Elischer 	NG_FREE_M(con->rx_pkt); /* checks for != NULL */
1170878ed226SJulian Elischer 
1171878ed226SJulian Elischer 	return (error);
1172878ed226SJulian Elischer } /* ng_l2cap_l2ca_clt_receive */
1173878ed226SJulian Elischer 
1174878ed226SJulian Elischer /*
1175878ed226SJulian Elischer  * Send L2CA_QoSViolationInd to the upper layer protocol
1176878ed226SJulian Elischer  */
1177878ed226SJulian Elischer 
1178878ed226SJulian Elischer int
1179878ed226SJulian Elischer ng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch)
1180878ed226SJulian Elischer {
1181878ed226SJulian Elischer 	ng_l2cap_p			 l2cap = ch->con->l2cap;
1182878ed226SJulian Elischer 	struct ng_mesg			*msg = NULL;
1183878ed226SJulian Elischer 	ng_l2cap_l2ca_qos_ind_ip	*ip = NULL;
1184878ed226SJulian Elischer 	int				 error = 0;
1185878ed226SJulian Elischer 
1186878ed226SJulian Elischer 	/* Check if upstream hook is connected and valid */
1187878ed226SJulian Elischer 	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1188878ed226SJulian Elischer 		NG_L2CAP_ERR(
1189878ed226SJulian Elischer "%s: %s - unable to send L2CA_QoSViolationInd message. " \
1190878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
1191878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
1192878ed226SJulian Elischer 
1193878ed226SJulian Elischer 		return (ENOTCONN);
1194878ed226SJulian Elischer 	}
1195878ed226SJulian Elischer 
1196878ed226SJulian Elischer 	/* Create and send L2CA_QoSViolationInd message */
1197878ed226SJulian Elischer 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_QOS_IND,
1198878ed226SJulian Elischer 		sizeof(*ip), M_NOWAIT);
1199878ed226SJulian Elischer 	if (msg == NULL)
1200878ed226SJulian Elischer 		error = ENOMEM;
1201878ed226SJulian Elischer 	else {
1202878ed226SJulian Elischer 		ip = (ng_l2cap_l2ca_qos_ind_ip *)(msg->data);
1203878ed226SJulian Elischer 		bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr));
12044ae439a3SMaksim Yevmenkin 		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1205878ed226SJulian Elischer 	}
1206878ed226SJulian Elischer 
1207878ed226SJulian Elischer 	return (error);
1208878ed226SJulian Elischer } /* ng_l2cap_l2ca_qos_ind */
1209878ed226SJulian Elischer 
1210878ed226SJulian Elischer /*
1211878ed226SJulian Elischer  * Process L2CA_Disconnect request from the upper layer protocol.
1212878ed226SJulian Elischer  */
1213878ed226SJulian Elischer 
1214878ed226SJulian Elischer int
1215878ed226SJulian Elischer ng_l2cap_l2ca_discon_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1216878ed226SJulian Elischer {
1217878ed226SJulian Elischer 	ng_l2cap_l2ca_discon_ip	*ip = NULL;
1218878ed226SJulian Elischer 	ng_l2cap_chan_p		 ch = NULL;
1219878ed226SJulian Elischer 	ng_l2cap_cmd_p		 cmd = NULL;
1220878ed226SJulian Elischer 	int			 error = 0;
1221878ed226SJulian Elischer 
1222878ed226SJulian Elischer 	/* Check message */
1223878ed226SJulian Elischer 	if (msg->header.arglen != sizeof(*ip)) {
1224878ed226SJulian Elischer 		NG_L2CAP_ALERT(
1225878ed226SJulian Elischer "%s: %s - invalid L2CA_Disconnect request message size, size=%d\n",
1226878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node),
1227878ed226SJulian Elischer 			msg->header.arglen);
1228878ed226SJulian Elischer 		error = EMSGSIZE;
1229878ed226SJulian Elischer 		goto out;
1230878ed226SJulian Elischer 	}
1231878ed226SJulian Elischer 
1232878ed226SJulian Elischer 	ip = (ng_l2cap_l2ca_discon_ip *)(msg->data);
1233878ed226SJulian Elischer 
1234fbc48c2bSTakanori Watanabe 
1235fbc48c2bSTakanori Watanabe 	if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
1236fbc48c2bSTakanori Watanabe 		/* Don't send Disconnect request on L2CAP Layer*/
1237fbc48c2bSTakanori Watanabe 		ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
1238fbc48c2bSTakanori Watanabe 			ip->lcid);
1239fbc48c2bSTakanori Watanabe 
1240fbc48c2bSTakanori Watanabe 		if(ch != NULL){
1241fbc48c2bSTakanori Watanabe 			ng_l2cap_free_chan(ch);
1242fbc48c2bSTakanori Watanabe 		}else{
1243fbc48c2bSTakanori Watanabe 		NG_L2CAP_ERR(
1244fbc48c2bSTakanori Watanabe "%s: %s - unexpected L2CA_Disconnect request message. " \
1245fbc48c2bSTakanori Watanabe "Channel does not exist, conhandle=%d\n",
1246fbc48c2bSTakanori Watanabe 			__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1247fbc48c2bSTakanori Watanabe 			error = EINVAL;
1248fbc48c2bSTakanori Watanabe 		}
1249fbc48c2bSTakanori Watanabe 		goto out;
1250*3a601a23STakanori Watanabe 	}else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
1251*3a601a23STakanori Watanabe 		/* Don't send Disconnect request on L2CAP Layer*/
1252*3a601a23STakanori Watanabe 		ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
1253*3a601a23STakanori Watanabe 			ip->lcid);
1254*3a601a23STakanori Watanabe 
1255*3a601a23STakanori Watanabe 		if(ch != NULL){
1256*3a601a23STakanori Watanabe 			ng_l2cap_free_chan(ch);
1257*3a601a23STakanori Watanabe 		}else{
1258*3a601a23STakanori Watanabe 		NG_L2CAP_ERR(
1259*3a601a23STakanori Watanabe "%s: %s - unexpected L2CA_Disconnect request message. " \
1260*3a601a23STakanori Watanabe "Channel does not exist, conhandle=%d\n",
1261*3a601a23STakanori Watanabe 			__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1262*3a601a23STakanori Watanabe 			error = EINVAL;
1263*3a601a23STakanori Watanabe 		}
1264*3a601a23STakanori Watanabe 		goto out;
1265fbc48c2bSTakanori Watanabe 	}else{
1266878ed226SJulian Elischer 		/* Check if we have this channel */
1267fbc48c2bSTakanori Watanabe 		ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, ip->idtype);
1268fbc48c2bSTakanori Watanabe 	}
1269878ed226SJulian Elischer 	if (ch == NULL) {
1270878ed226SJulian Elischer 		NG_L2CAP_ERR(
1271878ed226SJulian Elischer "%s: %s - unexpected L2CA_Disconnect request message. " \
1272878ed226SJulian Elischer "Channel does not exist, lcid=%d\n",
1273878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1274878ed226SJulian Elischer 		error = ENOENT;
1275878ed226SJulian Elischer 		goto out;
1276878ed226SJulian Elischer 	}
1277878ed226SJulian Elischer 
1278878ed226SJulian Elischer 	/* Check channel state */
1279878ed226SJulian Elischer 	if (ch->state != NG_L2CAP_CONFIG && ch->state != NG_L2CAP_OPEN &&
1280878ed226SJulian Elischer 	    ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) {
1281878ed226SJulian Elischer 		NG_L2CAP_ERR(
1282878ed226SJulian Elischer "%s: %s - unexpected L2CA_Disconnect request message. " \
1283878ed226SJulian Elischer "Invalid channel state, state=%d, lcid=%d\n",
1284878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->state,
1285878ed226SJulian Elischer 			ch->scid);
1286878ed226SJulian Elischer 		error = EINVAL;
1287878ed226SJulian Elischer 		goto out;
1288878ed226SJulian Elischer 	}
1289878ed226SJulian Elischer 
1290878ed226SJulian Elischer 	/* Create and send L2CAP_DisconReq message */
1291878ed226SJulian Elischer 	cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con),
1292878ed226SJulian Elischer 			NG_L2CAP_DISCON_REQ, msg->header.token);
1293878ed226SJulian Elischer 	if (cmd == NULL) {
1294878ed226SJulian Elischer 		ng_l2cap_free_chan(ch);
1295878ed226SJulian Elischer 		error = ENOMEM;
1296878ed226SJulian Elischer 		goto out;
1297878ed226SJulian Elischer 	}
1298878ed226SJulian Elischer 
1299878ed226SJulian Elischer 	if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1300878ed226SJulian Elischer 		ng_l2cap_free_chan(ch);
1301878ed226SJulian Elischer 		ng_l2cap_free_cmd(cmd);
1302878ed226SJulian Elischer 		error = EIO;
1303878ed226SJulian Elischer 		goto out;
1304878ed226SJulian Elischer 	}
1305878ed226SJulian Elischer 
1306878ed226SJulian Elischer 	_ng_l2cap_discon_req(cmd->aux, cmd->ident, ch->dcid, ch->scid);
1307878ed226SJulian Elischer 	if (cmd->aux == NULL) {
1308878ed226SJulian Elischer 		ng_l2cap_free_chan(ch);
1309878ed226SJulian Elischer 		ng_l2cap_free_cmd(cmd);
1310878ed226SJulian Elischer 		error = ENOBUFS;
1311878ed226SJulian Elischer 		goto out;
1312878ed226SJulian Elischer 	}
1313878ed226SJulian Elischer 
1314878ed226SJulian Elischer 	ch->state = NG_L2CAP_W4_L2CAP_DISCON_RSP;
1315878ed226SJulian Elischer 
1316878ed226SJulian Elischer 	/* Link command to the queue */
1317878ed226SJulian Elischer 	ng_l2cap_link_cmd(ch->con, cmd);
1318878ed226SJulian Elischer 	ng_l2cap_lp_deliver(ch->con);
1319878ed226SJulian Elischer out:
1320878ed226SJulian Elischer 	return (error);
1321878ed226SJulian Elischer } /* ng_l2cap_l2ca_discon_req */
1322878ed226SJulian Elischer 
1323878ed226SJulian Elischer /*
1324878ed226SJulian Elischer  * Send L2CA_Disconnect response to the upper layer protocol
1325878ed226SJulian Elischer  */
1326878ed226SJulian Elischer 
1327878ed226SJulian Elischer int
1328878ed226SJulian Elischer ng_l2cap_l2ca_discon_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
1329878ed226SJulian Elischer {
1330878ed226SJulian Elischer 	ng_l2cap_p		 l2cap = ch->con->l2cap;
1331878ed226SJulian Elischer 	struct ng_mesg		*msg = NULL;
1332878ed226SJulian Elischer 	ng_l2cap_l2ca_discon_op	*op = NULL;
1333878ed226SJulian Elischer 	int			 error = 0;
1334878ed226SJulian Elischer 
1335878ed226SJulian Elischer 	/* Check if upstream hook is connected and valid */
1336878ed226SJulian Elischer 	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1337878ed226SJulian Elischer 		NG_L2CAP_ERR(
1338878ed226SJulian Elischer "%s: %s - unable to send L2CA_Disconnect response message. " \
1339878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
1340878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
1341878ed226SJulian Elischer 
1342878ed226SJulian Elischer 		return (ENOTCONN);
1343878ed226SJulian Elischer 	}
1344878ed226SJulian Elischer 
1345878ed226SJulian Elischer 	/* Create and send L2CA_Disconnect response message */
1346878ed226SJulian Elischer 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON,
1347878ed226SJulian Elischer 		sizeof(*op), M_NOWAIT);
1348878ed226SJulian Elischer 	if (msg == NULL)
1349878ed226SJulian Elischer 		error = ENOMEM;
1350878ed226SJulian Elischer 	else {
1351878ed226SJulian Elischer 		msg->header.token = token;
1352878ed226SJulian Elischer 		msg->header.flags |= NGF_RESP;
1353878ed226SJulian Elischer 
1354878ed226SJulian Elischer 		op = (ng_l2cap_l2ca_discon_op *)(msg->data);
1355878ed226SJulian Elischer 		op->result = result;
1356878ed226SJulian Elischer 
13574ae439a3SMaksim Yevmenkin 		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1358878ed226SJulian Elischer 	}
1359878ed226SJulian Elischer 
1360878ed226SJulian Elischer 	return (error);
1361878ed226SJulian Elischer } /* ng_l2cap_l2ca_discon_rsp */
1362878ed226SJulian Elischer 
1363878ed226SJulian Elischer /*
1364878ed226SJulian Elischer  * Send L2CA_DisconnectInd message to the upper layer protocol.
1365878ed226SJulian Elischer  */
1366878ed226SJulian Elischer 
1367878ed226SJulian Elischer int
1368878ed226SJulian Elischer ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch)
1369878ed226SJulian Elischer {
1370878ed226SJulian Elischer 	ng_l2cap_p			 l2cap = ch->con->l2cap;
1371878ed226SJulian Elischer 	struct ng_mesg			*msg = NULL;
1372878ed226SJulian Elischer 	ng_l2cap_l2ca_discon_ind_ip	*ip = NULL;
1373878ed226SJulian Elischer 	int				 error = 0;
1374878ed226SJulian Elischer 
1375878ed226SJulian Elischer 	/* Check if upstream hook is connected and valid */
1376878ed226SJulian Elischer 	if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1377878ed226SJulian Elischer 		NG_L2CAP_ERR(
1378878ed226SJulian Elischer "%s: %s - unable to send L2CA_DisconnectInd message. " \
1379878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
1380878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ch->psm);
1381878ed226SJulian Elischer 
1382878ed226SJulian Elischer 		return (ENOTCONN);
1383878ed226SJulian Elischer 	}
1384878ed226SJulian Elischer 
1385878ed226SJulian Elischer 	/* Create and send L2CA_DisconnectInd message */
1386878ed226SJulian Elischer 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND,
1387878ed226SJulian Elischer 		sizeof(*ip), M_NOWAIT);
1388878ed226SJulian Elischer 	if (msg == NULL)
1389878ed226SJulian Elischer 		error = ENOMEM;
1390878ed226SJulian Elischer 	else {
1391878ed226SJulian Elischer 		ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data);
1392878ed226SJulian Elischer 		ip->lcid = ch->scid;
13934ae439a3SMaksim Yevmenkin 		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1394878ed226SJulian Elischer 	}
1395878ed226SJulian Elischer 
1396878ed226SJulian Elischer 	return (error);
1397878ed226SJulian Elischer } /* ng_l2cap_l2ca_discon_ind */
1398878ed226SJulian Elischer 
1399878ed226SJulian Elischer /*
1400878ed226SJulian Elischer  * Process L2CA_GroupCreate request from the upper layer protocol.
1401878ed226SJulian Elischer  * XXX FIXME
1402878ed226SJulian Elischer  */
1403878ed226SJulian Elischer 
1404878ed226SJulian Elischer int
1405878ed226SJulian Elischer ng_l2cap_l2ca_grp_create(ng_l2cap_p l2cap, struct ng_mesg *msg)
1406878ed226SJulian Elischer {
1407878ed226SJulian Elischer 	return (ENOTSUP);
1408878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_create */
1409878ed226SJulian Elischer 
1410878ed226SJulian Elischer /*
1411878ed226SJulian Elischer  * Process L2CA_GroupClose request from the upper layer protocol
1412878ed226SJulian Elischer  * XXX FIXME
1413878ed226SJulian Elischer  */
1414878ed226SJulian Elischer 
1415878ed226SJulian Elischer int
1416878ed226SJulian Elischer ng_l2cap_l2ca_grp_close(ng_l2cap_p l2cap, struct ng_mesg *msg)
1417878ed226SJulian Elischer {
1418878ed226SJulian Elischer 	return (ENOTSUP);
1419878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_close */
1420878ed226SJulian Elischer 
1421878ed226SJulian Elischer /*
1422878ed226SJulian Elischer  * Process L2CA_GroupAddMember request from the upper layer protocol.
1423878ed226SJulian Elischer  * XXX FIXME
1424878ed226SJulian Elischer  */
1425878ed226SJulian Elischer 
1426878ed226SJulian Elischer int
1427878ed226SJulian Elischer ng_l2cap_l2ca_grp_add_member_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1428878ed226SJulian Elischer {
1429878ed226SJulian Elischer 	return (ENOTSUP);
1430878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_add_member_req */
1431878ed226SJulian Elischer 
1432878ed226SJulian Elischer /*
1433878ed226SJulian Elischer  * Send L2CA_GroupAddMember response to the upper layer protocol.
1434878ed226SJulian Elischer  * XXX FIXME
1435878ed226SJulian Elischer  */
1436878ed226SJulian Elischer 
1437878ed226SJulian Elischer int
1438878ed226SJulian Elischer ng_l2cap_l2ca_grp_add_member_rsp(ng_l2cap_chan_p ch, u_int32_t token,
1439878ed226SJulian Elischer 		u_int16_t result)
1440878ed226SJulian Elischer {
1441878ed226SJulian Elischer 	return (0);
1442878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_add_member_rsp */
1443878ed226SJulian Elischer 
1444878ed226SJulian Elischer /*
1445878ed226SJulian Elischer  * Process L2CA_GroupDeleteMember request from the upper layer protocol
1446878ed226SJulian Elischer  * XXX FIXME
1447878ed226SJulian Elischer  */
1448878ed226SJulian Elischer 
1449878ed226SJulian Elischer int
1450878ed226SJulian Elischer ng_l2cap_l2ca_grp_rem_member(ng_l2cap_p l2cap, struct ng_mesg *msg)
1451878ed226SJulian Elischer {
1452878ed226SJulian Elischer 	return (ENOTSUP);
1453878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_rem_member */
1454878ed226SJulian Elischer 
1455878ed226SJulian Elischer /*
1456878ed226SJulian Elischer  * Process L2CA_GroupGetMembers request from the upper layer protocol
1457878ed226SJulian Elischer  * XXX FIXME
1458878ed226SJulian Elischer  */
1459878ed226SJulian Elischer 
1460878ed226SJulian Elischer int
1461878ed226SJulian Elischer ng_l2cap_l2ca_grp_get_members(ng_l2cap_p l2cap, struct ng_mesg *msg)
1462878ed226SJulian Elischer {
1463878ed226SJulian Elischer 	return (ENOTSUP);
1464878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_get_members */
1465878ed226SJulian Elischer 
1466878ed226SJulian Elischer /*
1467878ed226SJulian Elischer  * Process L2CA_Ping request from the upper layer protocol
1468878ed226SJulian Elischer  */
1469878ed226SJulian Elischer 
1470878ed226SJulian Elischer int
1471878ed226SJulian Elischer ng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1472878ed226SJulian Elischer {
1473878ed226SJulian Elischer 	ng_l2cap_l2ca_ping_ip	*ip = NULL;
1474878ed226SJulian Elischer 	ng_l2cap_con_p		 con = NULL;
1475878ed226SJulian Elischer 	ng_l2cap_cmd_p		 cmd = NULL;
1476878ed226SJulian Elischer 	int			 error = 0;
1477878ed226SJulian Elischer 
1478878ed226SJulian Elischer 	/* Verify message */
1479878ed226SJulian Elischer 	if (msg->header.arglen < sizeof(*ip)) {
1480878ed226SJulian Elischer 		NG_L2CAP_ALERT(
1481878ed226SJulian Elischer "%s: %s - invalid L2CA_Ping request message size, size=%d\n",
1482878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node),
1483878ed226SJulian Elischer 			msg->header.arglen);
1484878ed226SJulian Elischer 		error = EMSGSIZE;
1485878ed226SJulian Elischer 		goto out;
1486878ed226SJulian Elischer 	}
1487878ed226SJulian Elischer 
1488878ed226SJulian Elischer 	ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);
1489878ed226SJulian Elischer 	if (ip->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
1490878ed226SJulian Elischer 		NG_L2CAP_WARN(
1491878ed226SJulian Elischer "%s: %s - invalid L2CA_Ping request. Echo size is too big, echo_size=%d\n",
1492878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node), ip->echo_size);
1493878ed226SJulian Elischer 		error = EMSGSIZE;
1494878ed226SJulian Elischer 		goto out;
1495878ed226SJulian Elischer 	}
1496878ed226SJulian Elischer 
1497878ed226SJulian Elischer 	/* Check if we have connection to the unit */
1498fbc48c2bSTakanori Watanabe 	con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1499878ed226SJulian Elischer 	if (con == NULL) {
1500878ed226SJulian Elischer 		/* Submit LP_ConnectReq to the lower layer */
1501fbc48c2bSTakanori Watanabe 	  error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1502878ed226SJulian Elischer 		if (error != 0) {
1503878ed226SJulian Elischer 			NG_L2CAP_ERR(
1504878ed226SJulian Elischer "%s: %s - unable to send LP_ConnectReq message, error=%d\n",
1505878ed226SJulian Elischer 				__func__, NG_NODE_NAME(l2cap->node), error);
1506878ed226SJulian Elischer 			goto out;
1507878ed226SJulian Elischer 		}
1508878ed226SJulian Elischer 
1509878ed226SJulian Elischer 		/* This should not fail */
1510fbc48c2bSTakanori Watanabe 		con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1511878ed226SJulian Elischer 		KASSERT((con != NULL),
1512878ed226SJulian Elischer ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
1513878ed226SJulian Elischer 	}
1514878ed226SJulian Elischer 
1515878ed226SJulian Elischer 	/* Create L2CAP command descriptor */
1516878ed226SJulian Elischer 	cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),
1517878ed226SJulian Elischer 			NG_L2CAP_ECHO_REQ, msg->header.token);
1518878ed226SJulian Elischer 	if (cmd == NULL) {
1519878ed226SJulian Elischer 		error = ENOMEM;
1520878ed226SJulian Elischer 		goto out;
1521878ed226SJulian Elischer 	}
1522878ed226SJulian Elischer 
1523878ed226SJulian Elischer 	if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1524878ed226SJulian Elischer 		ng_l2cap_free_cmd(cmd);
1525878ed226SJulian Elischer                 error = EIO;
1526878ed226SJulian Elischer 		goto out;
1527878ed226SJulian Elischer 	}
1528878ed226SJulian Elischer 
1529878ed226SJulian Elischer 	/* Create L2CAP command packet */
1530878ed226SJulian Elischer 	_ng_l2cap_echo_req(cmd->aux, cmd->ident,
1531878ed226SJulian Elischer 			msg->data + sizeof(*ip), ip->echo_size);
1532878ed226SJulian Elischer 	if (cmd->aux == NULL) {
1533878ed226SJulian Elischer 		ng_l2cap_free_cmd(cmd);
1534878ed226SJulian Elischer                 error = ENOBUFS;
1535878ed226SJulian Elischer 		goto out;
1536878ed226SJulian Elischer 	}
1537878ed226SJulian Elischer 
1538878ed226SJulian Elischer         /* Link command to the queue */
1539878ed226SJulian Elischer         ng_l2cap_link_cmd(con, cmd);
1540878ed226SJulian Elischer 	ng_l2cap_lp_deliver(con);
1541878ed226SJulian Elischer out:
1542878ed226SJulian Elischer 	return (error);
1543878ed226SJulian Elischer } /* ng_l2cap_l2ca_ping_req */
1544878ed226SJulian Elischer 
1545878ed226SJulian Elischer /*
1546878ed226SJulian Elischer  * Send L2CA_Ping response to the upper layer protocol
1547878ed226SJulian Elischer  */
1548878ed226SJulian Elischer 
1549878ed226SJulian Elischer int
1550878ed226SJulian Elischer ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result,
1551878ed226SJulian Elischer 		struct mbuf *data)
1552878ed226SJulian Elischer {
1553878ed226SJulian Elischer 	ng_l2cap_p		 l2cap = con->l2cap;
1554878ed226SJulian Elischer 	struct ng_mesg		*msg = NULL;
1555878ed226SJulian Elischer 	ng_l2cap_l2ca_ping_op	*op = NULL;
1556878ed226SJulian Elischer 	int			 error = 0, size = 0;
1557878ed226SJulian Elischer 
1558878ed226SJulian Elischer 	/* Check if control hook is connected and valid */
1559878ed226SJulian Elischer 	if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
1560878ed226SJulian Elischer 		NG_L2CAP_WARN(
1561878ed226SJulian Elischer "%s: %s - unable to send L2CA_Ping response message. " \
1562878ed226SJulian Elischer "Hook is not connected or valid\n",
1563878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node));
1564878ed226SJulian Elischer 		error = ENOTCONN;
1565878ed226SJulian Elischer 		goto out;
1566878ed226SJulian Elischer 	}
1567878ed226SJulian Elischer 
1568878ed226SJulian Elischer 	size = (data == NULL)? 0 : data->m_pkthdr.len;
1569878ed226SJulian Elischer 
1570878ed226SJulian Elischer 	/* Create and send L2CA_Ping response message */
1571878ed226SJulian Elischer 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_PING,
1572878ed226SJulian Elischer 		sizeof(*op) + size, M_NOWAIT);
1573878ed226SJulian Elischer 	if (msg == NULL)
1574878ed226SJulian Elischer 		error = ENOMEM;
1575878ed226SJulian Elischer 	else {
1576878ed226SJulian Elischer 		msg->header.token = token;
1577878ed226SJulian Elischer 		msg->header.flags |= NGF_RESP;
1578878ed226SJulian Elischer 
1579878ed226SJulian Elischer 		op = (ng_l2cap_l2ca_ping_op *)(msg->data);
1580878ed226SJulian Elischer 		op->result = result;
1581878ed226SJulian Elischer 		bcopy(&con->remote, &op->bdaddr, sizeof(op->bdaddr));
1582878ed226SJulian Elischer 		if (data != NULL && size > 0) {
1583878ed226SJulian Elischer 			op->echo_size = size;
1584878ed226SJulian Elischer 			m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));
1585878ed226SJulian Elischer 		}
1586878ed226SJulian Elischer 
15874ae439a3SMaksim Yevmenkin 		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1588878ed226SJulian Elischer 	}
1589878ed226SJulian Elischer out:
1590878ed226SJulian Elischer 	NG_FREE_M(data);
1591878ed226SJulian Elischer 
1592878ed226SJulian Elischer 	return (error);
1593878ed226SJulian Elischer } /* ng_l2cap_l2ca_ping_rsp */
1594878ed226SJulian Elischer 
1595878ed226SJulian Elischer /*
1596878ed226SJulian Elischer  * Process L2CA_GetInfo request from the upper layer protocol
1597878ed226SJulian Elischer  */
1598878ed226SJulian Elischer 
1599878ed226SJulian Elischer int
1600878ed226SJulian Elischer ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1601878ed226SJulian Elischer {
1602878ed226SJulian Elischer 	ng_l2cap_l2ca_get_info_ip	*ip = NULL;
1603878ed226SJulian Elischer 	ng_l2cap_con_p			 con = NULL;
1604878ed226SJulian Elischer 	ng_l2cap_cmd_p			 cmd = NULL;
1605878ed226SJulian Elischer 	int				 error = 0;
1606878ed226SJulian Elischer 
1607878ed226SJulian Elischer 	/* Verify message */
1608878ed226SJulian Elischer 	if (msg->header.arglen != sizeof(*ip)) {
1609878ed226SJulian Elischer 		NG_L2CAP_ALERT(
1610878ed226SJulian Elischer "%s: %s - invalid L2CA_GetInfo request message size, size=%d\n",
1611878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node),
1612878ed226SJulian Elischer 			msg->header.arglen);
1613878ed226SJulian Elischer 		error = EMSGSIZE;
1614878ed226SJulian Elischer 		goto out;
1615878ed226SJulian Elischer 	}
1616878ed226SJulian Elischer 
1617878ed226SJulian Elischer 	ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
1618878ed226SJulian Elischer 
1619878ed226SJulian Elischer 	/* Check if we have connection to the unit */
1620fbc48c2bSTakanori Watanabe 	con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr,ip->linktype);
1621878ed226SJulian Elischer 	if (con == NULL) {
1622878ed226SJulian Elischer 		/* Submit LP_ConnectReq to the lower layer */
1623fbc48c2bSTakanori Watanabe 		error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);
1624878ed226SJulian Elischer 		if (error != 0) {
1625878ed226SJulian Elischer 			NG_L2CAP_ERR(
1626878ed226SJulian Elischer "%s: %s - unable to send LP_ConnectReq message, error=%d\n",
1627878ed226SJulian Elischer 				__func__, NG_NODE_NAME(l2cap->node), error);
1628878ed226SJulian Elischer 			goto out;
1629878ed226SJulian Elischer 		}
1630878ed226SJulian Elischer 
1631878ed226SJulian Elischer 		/* This should not fail */
1632fbc48c2bSTakanori Watanabe 		con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
1633878ed226SJulian Elischer 		KASSERT((con != NULL),
1634878ed226SJulian Elischer ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
1635878ed226SJulian Elischer 	}
1636878ed226SJulian Elischer 
1637878ed226SJulian Elischer 	/* Create L2CAP command descriptor */
1638878ed226SJulian Elischer 	cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),
1639878ed226SJulian Elischer 			NG_L2CAP_INFO_REQ, msg->header.token);
1640878ed226SJulian Elischer 	if (cmd == NULL) {
1641878ed226SJulian Elischer 		error = ENOMEM;
1642878ed226SJulian Elischer 		goto out;
1643878ed226SJulian Elischer 	}
1644878ed226SJulian Elischer 
1645878ed226SJulian Elischer 	if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1646878ed226SJulian Elischer 		ng_l2cap_free_cmd(cmd);
1647878ed226SJulian Elischer 		error = EIO;
1648878ed226SJulian Elischer 		goto out;
1649878ed226SJulian Elischer 	}
1650878ed226SJulian Elischer 
1651878ed226SJulian Elischer 	/* Create L2CAP command packet */
1652878ed226SJulian Elischer 	_ng_l2cap_info_req(cmd->aux, cmd->ident, ip->info_type);
1653878ed226SJulian Elischer 	if (cmd->aux == NULL) {
1654878ed226SJulian Elischer 		ng_l2cap_free_cmd(cmd);
1655878ed226SJulian Elischer 		error = ENOBUFS;
1656878ed226SJulian Elischer 		goto out;
1657878ed226SJulian Elischer 	}
1658878ed226SJulian Elischer 
1659878ed226SJulian Elischer         /* Link command to the queue */
1660878ed226SJulian Elischer 	ng_l2cap_link_cmd(con, cmd);
1661878ed226SJulian Elischer 	ng_l2cap_lp_deliver(con);
1662878ed226SJulian Elischer out:
1663878ed226SJulian Elischer 	return (error);
1664878ed226SJulian Elischer } /* ng_l2cap_l2ca_get_info_req */
1665878ed226SJulian Elischer 
1666878ed226SJulian Elischer /*
1667878ed226SJulian Elischer  * Send L2CA_GetInfo response to the upper layer protocol
1668878ed226SJulian Elischer  */
1669878ed226SJulian Elischer 
1670878ed226SJulian Elischer int
1671878ed226SJulian Elischer ng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con, u_int32_t token,
1672878ed226SJulian Elischer 		u_int16_t result, struct mbuf *data)
1673878ed226SJulian Elischer {
1674878ed226SJulian Elischer 	ng_l2cap_p			 l2cap = con->l2cap;
1675878ed226SJulian Elischer 	struct ng_mesg			*msg = NULL;
1676878ed226SJulian Elischer 	ng_l2cap_l2ca_get_info_op	*op = NULL;
1677878ed226SJulian Elischer 	int				 error = 0, size;
1678878ed226SJulian Elischer 
1679878ed226SJulian Elischer 	/* Check if control hook is connected and valid */
1680878ed226SJulian Elischer 	if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
1681878ed226SJulian Elischer 		NG_L2CAP_WARN(
1682878ed226SJulian Elischer "%s: %s - unable to send L2CA_GetInfo response message. " \
1683878ed226SJulian Elischer "Hook is not connected or valid\n",
1684878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node));
1685878ed226SJulian Elischer 		error = ENOTCONN;
1686878ed226SJulian Elischer 		goto out;
1687878ed226SJulian Elischer 	}
1688878ed226SJulian Elischer 
1689878ed226SJulian Elischer 	size = (data == NULL)? 0 : data->m_pkthdr.len;
1690878ed226SJulian Elischer 
1691878ed226SJulian Elischer 	/* Create and send L2CA_GetInfo response message */
1692878ed226SJulian Elischer 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_GET_INFO,
1693878ed226SJulian Elischer 		sizeof(*op) + size, M_NOWAIT);
1694878ed226SJulian Elischer 	if (msg == NULL)
1695878ed226SJulian Elischer 		error = ENOMEM;
1696878ed226SJulian Elischer 	else {
1697878ed226SJulian Elischer 		msg->header.token = token;
1698878ed226SJulian Elischer 		msg->header.flags |= NGF_RESP;
1699878ed226SJulian Elischer 
1700878ed226SJulian Elischer 		op = (ng_l2cap_l2ca_get_info_op *)(msg->data);
1701878ed226SJulian Elischer 		op->result = result;
1702878ed226SJulian Elischer 		if (data != NULL && size > 0) {
1703878ed226SJulian Elischer 			op->info_size = size;
1704878ed226SJulian Elischer 			m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));
1705878ed226SJulian Elischer 		}
1706878ed226SJulian Elischer 
17074ae439a3SMaksim Yevmenkin 		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1708878ed226SJulian Elischer 	}
1709878ed226SJulian Elischer out:
1710878ed226SJulian Elischer 	NG_FREE_M(data);
1711878ed226SJulian Elischer 
1712878ed226SJulian Elischer 	return (error);
1713878ed226SJulian Elischer } /* ng_l2cap_l2ca_get_info_rsp */
1714878ed226SJulian Elischer 
1715878ed226SJulian Elischer /*
1716878ed226SJulian Elischer  * Process L2CA_EnableCLT message from the upper layer protocol
1717878ed226SJulian Elischer  * XXX convert to NGN_L2CAP_NODE_SET_FLAGS?
1718878ed226SJulian Elischer  */
1719878ed226SJulian Elischer 
1720878ed226SJulian Elischer int
1721878ed226SJulian Elischer ng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg)
1722878ed226SJulian Elischer {
1723878ed226SJulian Elischer 	ng_l2cap_l2ca_enable_clt_ip	*ip = NULL;
1724878ed226SJulian Elischer 	int				 error = 0;
1725878ed226SJulian Elischer #if 0
1726878ed226SJulian Elischer  *	ng_l2cap_l2ca_enable_clt_op	*op = NULL;
1727878ed226SJulian Elischer  *	u_int16_t			 result;
1728878ed226SJulian Elischer  * 	u_int32_t			 token;
1729878ed226SJulian Elischer #endif
1730878ed226SJulian Elischer 
1731878ed226SJulian Elischer 	/* Check message */
1732878ed226SJulian Elischer 	if (msg->header.arglen != sizeof(*ip)) {
1733878ed226SJulian Elischer 		NG_L2CAP_ALERT(
1734878ed226SJulian Elischer "%s: %s - invalid L2CA_EnableCLT message size, size=%d\n",
1735878ed226SJulian Elischer 			__func__, NG_NODE_NAME(l2cap->node),
1736878ed226SJulian Elischer 			msg->header.arglen);
1737878ed226SJulian Elischer 
1738878ed226SJulian Elischer 		return (EMSGSIZE);
1739878ed226SJulian Elischer 	}
1740878ed226SJulian Elischer 
1741878ed226SJulian Elischer 	/* Process request */
1742878ed226SJulian Elischer 	ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data);
1743878ed226SJulian Elischer #if 0
1744878ed226SJulian Elischer  *	result = NG_L2CAP_SUCCESS;
1745878ed226SJulian Elischer #endif
1746878ed226SJulian Elischer 
1747878ed226SJulian Elischer 	switch (ip->psm)
1748878ed226SJulian Elischer 	{
1749878ed226SJulian Elischer 	case 0:
1750878ed226SJulian Elischer 		/* Special case: disable/enable all PSM */
1751878ed226SJulian Elischer 		if (ip->enable)
1752878ed226SJulian Elischer 			l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED    |
1753878ed226SJulian Elischer 					  NG_L2CAP_CLT_RFCOMM_DISABLED |
1754878ed226SJulian Elischer 					  NG_L2CAP_CLT_TCP_DISABLED);
1755878ed226SJulian Elischer 		else
1756878ed226SJulian Elischer 			l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED    |
1757878ed226SJulian Elischer 					 NG_L2CAP_CLT_RFCOMM_DISABLED |
1758878ed226SJulian Elischer 					 NG_L2CAP_CLT_TCP_DISABLED);
1759878ed226SJulian Elischer 		break;
1760878ed226SJulian Elischer 
1761878ed226SJulian Elischer 	case NG_L2CAP_PSM_SDP:
1762878ed226SJulian Elischer 		if (ip->enable)
1763878ed226SJulian Elischer 			l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED;
1764878ed226SJulian Elischer 		else
1765878ed226SJulian Elischer 			l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED;
1766878ed226SJulian Elischer 		break;
1767878ed226SJulian Elischer 
1768878ed226SJulian Elischer 	case NG_L2CAP_PSM_RFCOMM:
1769878ed226SJulian Elischer 		if (ip->enable)
1770878ed226SJulian Elischer 			l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED;
1771878ed226SJulian Elischer 		else
1772878ed226SJulian Elischer 			l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED;
1773878ed226SJulian Elischer 		break;
1774878ed226SJulian Elischer 
1775878ed226SJulian Elischer 	case NG_L2CAP_PSM_TCP:
1776878ed226SJulian Elischer 		if (ip->enable)
1777878ed226SJulian Elischer 			l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED;
1778878ed226SJulian Elischer 		else
1779878ed226SJulian Elischer 			l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED;
1780878ed226SJulian Elischer 		break;
1781878ed226SJulian Elischer 
1782878ed226SJulian Elischer 	default:
1783878ed226SJulian Elischer 		NG_L2CAP_ERR(
1784878ed226SJulian Elischer "%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm);
1785878ed226SJulian Elischer #if 0
1786878ed226SJulian Elischer  *		result = NG_L2CAP_PSM_NOT_SUPPORTED;
1787878ed226SJulian Elischer #endif
1788878ed226SJulian Elischer 		error = ENOTSUP;
1789878ed226SJulian Elischer 		break;
1790878ed226SJulian Elischer 	}
1791878ed226SJulian Elischer 
1792878ed226SJulian Elischer #if 0
1793878ed226SJulian Elischer  *	/* Create and send response message */
1794878ed226SJulian Elischer  * 	token = msg->header.token;
1795878ed226SJulian Elischer  * 	NG_FREE_MSG(msg);
1796878ed226SJulian Elischer  * 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT,
1797878ed226SJulian Elischer  * 		sizeof(*op), M_NOWAIT);
1798878ed226SJulian Elischer  * 	if (msg == NULL)
1799878ed226SJulian Elischer  * 		error = ENOMEM;
1800878ed226SJulian Elischer  * 	else {
1801878ed226SJulian Elischer  * 		msg->header.token = token;
1802878ed226SJulian Elischer  * 		msg->header.flags |= NGF_RESP;
1803878ed226SJulian Elischer  *
1804878ed226SJulian Elischer  * 		op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data);
1805878ed226SJulian Elischer  * 		op->result = result;
1806878ed226SJulian Elischer  * 	}
1807878ed226SJulian Elischer  *
1808878ed226SJulian Elischer  * 	/* Send response to control hook */
1809878ed226SJulian Elischer  * 	if (l2cap->ctl != NULL && NG_HOOK_IS_VALID(l2cap->ctl))
18104ae439a3SMaksim Yevmenkin  * 		NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1811878ed226SJulian Elischer #endif
1812878ed226SJulian Elischer 
1813878ed226SJulian Elischer 	return (error);
1814878ed226SJulian Elischer } /* ng_l2cap_l2ca_enable_clt */
1815878ed226SJulian Elischer 
1816