1878ed226SJulian Elischer /*
2878ed226SJulian Elischer * ng_l2cap_ulpi.c
3c398230bSWarner Losh */
4c398230bSWarner Losh
5c398230bSWarner Losh /*-
6*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
7fe267a55SPedro F. Giffuni *
8878ed226SJulian Elischer * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
9878ed226SJulian Elischer * All rights reserved.
10878ed226SJulian Elischer *
11878ed226SJulian Elischer * Redistribution and use in source and binary forms, with or without
12878ed226SJulian Elischer * modification, are permitted provided that the following conditions
13878ed226SJulian Elischer * are met:
14878ed226SJulian Elischer * 1. Redistributions of source code must retain the above copyright
15878ed226SJulian Elischer * notice, this list of conditions and the following disclaimer.
16878ed226SJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright
17878ed226SJulian Elischer * notice, this list of conditions and the following disclaimer in the
18878ed226SJulian Elischer * documentation and/or other materials provided with the distribution.
19878ed226SJulian Elischer *
20878ed226SJulian Elischer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21878ed226SJulian Elischer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22878ed226SJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23878ed226SJulian Elischer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24878ed226SJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25878ed226SJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26878ed226SJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27878ed226SJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28878ed226SJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29878ed226SJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30878ed226SJulian Elischer * SUCH DAMAGE.
31878ed226SJulian Elischer *
32f2bb1caeSJulian Elischer * $Id: ng_l2cap_ulpi.c,v 1.1 2002/11/24 19:47:06 max Exp $
33878ed226SJulian Elischer */
34878ed226SJulian Elischer
35878ed226SJulian Elischer #include <sys/param.h>
36878ed226SJulian Elischer #include <sys/systm.h>
37878ed226SJulian Elischer #include <sys/kernel.h>
38878ed226SJulian Elischer #include <sys/endian.h>
39878ed226SJulian Elischer #include <sys/malloc.h>
40878ed226SJulian Elischer #include <sys/mbuf.h>
41878ed226SJulian Elischer #include <sys/queue.h>
42878ed226SJulian Elischer #include <netgraph/ng_message.h>
43878ed226SJulian Elischer #include <netgraph/netgraph.h>
44b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_hci.h>
45b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_l2cap.h>
46b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_var.h>
47b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h>
48b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h>
49b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h>
50b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>
51b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>
52878ed226SJulian Elischer
53878ed226SJulian Elischer /******************************************************************************
54878ed226SJulian Elischer ******************************************************************************
55878ed226SJulian Elischer ** Upper Layer Protocol Interface module
56878ed226SJulian Elischer ******************************************************************************
57878ed226SJulian Elischer ******************************************************************************/
58878ed226SJulian Elischer
59878ed226SJulian Elischer /*
60878ed226SJulian Elischer * Process L2CA_Connect request from the upper layer protocol.
61878ed226SJulian Elischer */
62878ed226SJulian Elischer
63878ed226SJulian Elischer int
ng_l2cap_l2ca_con_req(ng_l2cap_p l2cap,struct ng_mesg * msg)64878ed226SJulian Elischer ng_l2cap_l2ca_con_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
65878ed226SJulian Elischer {
66878ed226SJulian Elischer ng_l2cap_l2ca_con_ip *ip = NULL;
67878ed226SJulian Elischer ng_l2cap_con_p con = NULL;
68878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL;
69878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL;
70878ed226SJulian Elischer int error = 0;
71878ed226SJulian Elischer
72878ed226SJulian Elischer /* Check message */
73878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) {
74878ed226SJulian Elischer NG_L2CAP_ALERT(
75878ed226SJulian Elischer "%s: %s - invalid L2CA_Connect request message size, size=%d\n",
76878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node),
77878ed226SJulian Elischer msg->header.arglen);
78878ed226SJulian Elischer error = EMSGSIZE;
79878ed226SJulian Elischer goto out;
80878ed226SJulian Elischer }
81878ed226SJulian Elischer
82878ed226SJulian Elischer ip = (ng_l2cap_l2ca_con_ip *)(msg->data);
83878ed226SJulian Elischer
84878ed226SJulian Elischer /* Check if we have connection to the remote unit */
85fbc48c2bSTakanori Watanabe con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
86878ed226SJulian Elischer if (con == NULL) {
87878ed226SJulian Elischer /* Submit LP_ConnectReq to the lower layer */
88fbc48c2bSTakanori Watanabe error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);
89878ed226SJulian Elischer if (error != 0) {
90878ed226SJulian Elischer NG_L2CAP_ERR(
91878ed226SJulian Elischer "%s: %s - unable to send LP_ConnectReq message, error=%d\n",
92878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), error);
93878ed226SJulian Elischer goto out;
94878ed226SJulian Elischer }
95878ed226SJulian Elischer
96878ed226SJulian Elischer /* This should not fail */
97fbc48c2bSTakanori Watanabe con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
98878ed226SJulian Elischer KASSERT((con != NULL),
99878ed226SJulian Elischer ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
100878ed226SJulian Elischer }
101878ed226SJulian Elischer
102878ed226SJulian Elischer /*
103878ed226SJulian Elischer * Create new empty channel descriptor. In case of any failure do
104878ed226SJulian Elischer * not touch connection descriptor.
105878ed226SJulian Elischer */
106878ed226SJulian Elischer
107fbc48c2bSTakanori Watanabe ch = ng_l2cap_new_chan(l2cap, con, ip->psm, ip->idtype);
108878ed226SJulian Elischer if (ch == NULL) {
109878ed226SJulian Elischer error = ENOMEM;
110878ed226SJulian Elischer goto out;
111878ed226SJulian Elischer }
112878ed226SJulian Elischer
113878ed226SJulian Elischer /* Now create L2CAP_ConnectReq command */
114878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(con),
115878ed226SJulian Elischer NG_L2CAP_CON_REQ, msg->header.token);
116878ed226SJulian Elischer if (cmd == NULL) {
117878ed226SJulian Elischer ng_l2cap_free_chan(ch);
118878ed226SJulian Elischer error = ENOMEM;
119878ed226SJulian Elischer goto out;
120878ed226SJulian Elischer }
121878ed226SJulian Elischer
122878ed226SJulian Elischer if (cmd->ident == NG_L2CAP_NULL_IDENT) {
123878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
124878ed226SJulian Elischer ng_l2cap_free_chan(ch);
125878ed226SJulian Elischer error = EIO;
126878ed226SJulian Elischer goto out;
127878ed226SJulian Elischer }
128878ed226SJulian Elischer
129878ed226SJulian Elischer /* Create L2CAP command packet */
130fbc48c2bSTakanori Watanabe if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
131fbc48c2bSTakanori Watanabe _ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_ATT_CID,
132fbc48c2bSTakanori Watanabe NG_L2CAP_ATT_CID, 0, 0);
133fbc48c2bSTakanori Watanabe cmd->aux->m_flags |= M_PROTO2;
1343a601a23STakanori Watanabe }else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
1353a601a23STakanori Watanabe _ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_SMP_CID,
1363a601a23STakanori Watanabe NG_L2CAP_SMP_CID, 0, 0);
1373a601a23STakanori Watanabe cmd->aux->m_flags |= M_PROTO2;
138fbc48c2bSTakanori Watanabe }else{
139878ed226SJulian Elischer _ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid);
140fbc48c2bSTakanori Watanabe }
141878ed226SJulian Elischer if (cmd->aux == NULL) {
142878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
143878ed226SJulian Elischer ng_l2cap_free_chan(ch);
144878ed226SJulian Elischer error = ENOBUFS;
145878ed226SJulian Elischer goto out;
146878ed226SJulian Elischer }
147878ed226SJulian Elischer
148878ed226SJulian Elischer ch->state = NG_L2CAP_W4_L2CAP_CON_RSP;
149878ed226SJulian Elischer
150878ed226SJulian Elischer /* Link command to the queue */
151878ed226SJulian Elischer ng_l2cap_link_cmd(ch->con, cmd);
152878ed226SJulian Elischer ng_l2cap_lp_deliver(ch->con);
153878ed226SJulian Elischer out:
154878ed226SJulian Elischer return (error);
155878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_req */
156878ed226SJulian Elischer
157878ed226SJulian Elischer /*
158878ed226SJulian Elischer * Send L2CA_Connect response to the upper layer protocol.
159878ed226SJulian Elischer */
160878ed226SJulian Elischer
161878ed226SJulian Elischer int
ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch,u_int32_t token,u_int16_t result,u_int16_t status)162878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
163878ed226SJulian Elischer u_int16_t status)
164878ed226SJulian Elischer {
165878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap;
166878ed226SJulian Elischer struct ng_mesg *msg = NULL;
167878ed226SJulian Elischer ng_l2cap_l2ca_con_op *op = NULL;
168878ed226SJulian Elischer int error = 0;
169878ed226SJulian Elischer
170878ed226SJulian Elischer /* Check if upstream hook is connected and valid */
171878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
172878ed226SJulian Elischer NG_L2CAP_ERR(
173878ed226SJulian Elischer "%s: %s - unable to send L2CA_Connect response message. " \
174878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
175878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm);
176878ed226SJulian Elischer
177878ed226SJulian Elischer return (ENOTCONN);
178878ed226SJulian Elischer }
179878ed226SJulian Elischer
180878ed226SJulian Elischer /* Create and send L2CA_Connect response message */
181878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON,
182878ed226SJulian Elischer sizeof(*op), M_NOWAIT);
183878ed226SJulian Elischer if (msg == NULL)
184878ed226SJulian Elischer error = ENOMEM;
185878ed226SJulian Elischer else {
186878ed226SJulian Elischer msg->header.token = token;
187878ed226SJulian Elischer msg->header.flags |= NGF_RESP;
188878ed226SJulian Elischer
189878ed226SJulian Elischer op = (ng_l2cap_l2ca_con_op *)(msg->data);
190878ed226SJulian Elischer
191878ed226SJulian Elischer /*
192878ed226SJulian Elischer * XXX Spec. says we should only populate LCID when result == 0
193878ed226SJulian Elischer * What about PENDING? What the heck, for now always populate
194878ed226SJulian Elischer * LCID :)
195878ed226SJulian Elischer */
196fbc48c2bSTakanori Watanabe if(ch->scid == NG_L2CAP_ATT_CID){
197fbc48c2bSTakanori Watanabe op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
198fbc48c2bSTakanori Watanabe op->lcid = ch->con->con_handle;
1993a601a23STakanori Watanabe }else if(ch->scid == NG_L2CAP_SMP_CID){
2003a601a23STakanori Watanabe op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
2013a601a23STakanori Watanabe op->lcid = ch->con->con_handle;
202fbc48c2bSTakanori Watanabe }else{
203fbc48c2bSTakanori Watanabe op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
204fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR :
205fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_LE;
206878ed226SJulian Elischer op->lcid = ch->scid;
207fbc48c2bSTakanori Watanabe }
2083a601a23STakanori Watanabe op->encryption = ch->con->encryption;
209878ed226SJulian Elischer op->result = result;
210878ed226SJulian Elischer op->status = status;
211878ed226SJulian Elischer
2124ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
213878ed226SJulian Elischer }
214878ed226SJulian Elischer
215878ed226SJulian Elischer return (error);
216878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_rsp */
217878ed226SJulian Elischer
218878ed226SJulian Elischer /*
219878ed226SJulian Elischer * Process L2CA_ConnectRsp request from the upper layer protocol.
220878ed226SJulian Elischer */
221878ed226SJulian Elischer
222878ed226SJulian Elischer int
ng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap,struct ng_mesg * msg)223878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
224878ed226SJulian Elischer {
225878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_ip *ip = NULL;
226878ed226SJulian Elischer ng_l2cap_con_p con = NULL;
227878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL;
228878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL;
229878ed226SJulian Elischer u_int16_t dcid;
230878ed226SJulian Elischer int error = 0;
231878ed226SJulian Elischer
232878ed226SJulian Elischer /* Check message */
233878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) {
234878ed226SJulian Elischer NG_L2CAP_ALERT(
235878ed226SJulian Elischer "%s: %s - invalid L2CA_ConnectRsp request message size, size=%d\n",
236878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node),
237878ed226SJulian Elischer msg->header.arglen);
238878ed226SJulian Elischer error = EMSGSIZE;
239878ed226SJulian Elischer goto out;
240878ed226SJulian Elischer }
241878ed226SJulian Elischer
242878ed226SJulian Elischer ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data);
243878ed226SJulian Elischer
244878ed226SJulian Elischer /* Check if we have this channel */
2453a601a23STakanori Watanabe if((ip->lcid != NG_L2CAP_ATT_CID)&&
2463a601a23STakanori Watanabe (ip->lcid != NG_L2CAP_SMP_CID)){
247fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid
248fbc48c2bSTakanori Watanabe ,(ip->linktype == NG_HCI_LINK_ACL)?
249fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR:
250fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_LE);
251fbc48c2bSTakanori Watanabe }else{
252fbc48c2bSTakanori Watanabe // For now not support on ATT device.
253fbc48c2bSTakanori Watanabe ch = NULL;
254fbc48c2bSTakanori Watanabe }
255878ed226SJulian Elischer if (ch == NULL) {
256878ed226SJulian Elischer NG_L2CAP_ALERT(
257878ed226SJulian Elischer "%s: %s - unexpected L2CA_ConnectRsp request message. " \
258878ed226SJulian Elischer "Channel does not exist, lcid=%d\n",
259878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
260878ed226SJulian Elischer error = ENOENT;
261878ed226SJulian Elischer goto out;
262878ed226SJulian Elischer }
263878ed226SJulian Elischer
264878ed226SJulian Elischer /* Check channel state */
265878ed226SJulian Elischer if (ch->state != NG_L2CAP_W4_L2CA_CON_RSP) {
266878ed226SJulian Elischer NG_L2CAP_ERR(
267878ed226SJulian Elischer "%s: %s - unexpected L2CA_ConnectRsp request message. " \
268878ed226SJulian Elischer "Invalid channel state, state=%d, lcid=%d\n",
269878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->state,
270878ed226SJulian Elischer ip->lcid);
271878ed226SJulian Elischer error = EINVAL;
272878ed226SJulian Elischer goto out;
273878ed226SJulian Elischer }
274878ed226SJulian Elischer
275878ed226SJulian Elischer dcid = ch->dcid;
276878ed226SJulian Elischer con = ch->con;
277878ed226SJulian Elischer
278878ed226SJulian Elischer /*
279878ed226SJulian Elischer * Now we are pretty much sure it is our response. So create and send
280878ed226SJulian Elischer * L2CAP_ConnectRsp message to our peer.
281878ed226SJulian Elischer */
282878ed226SJulian Elischer
283878ed226SJulian Elischer if (ch->ident != ip->ident)
284878ed226SJulian Elischer NG_L2CAP_WARN(
285878ed226SJulian Elischer "%s: %s - channel ident and response ident do not match, scid=%d, ident=%d. " \
286878ed226SJulian Elischer "Will use response ident=%d\n",
287878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->scid,
288878ed226SJulian Elischer ch->ident, ip->ident);
289878ed226SJulian Elischer
290878ed226SJulian Elischer /* Check result */
291878ed226SJulian Elischer switch (ip->result) {
292878ed226SJulian Elischer case NG_L2CAP_SUCCESS:
2933a601a23STakanori Watanabe ch->state = ((ch->scid == NG_L2CAP_ATT_CID)||
2943a601a23STakanori Watanabe (ch->scid == NG_L2CAP_SMP_CID))?
295fbc48c2bSTakanori Watanabe NG_L2CAP_OPEN : NG_L2CAP_CONFIG;
296878ed226SJulian Elischer ch->cfg_state = 0;
297878ed226SJulian Elischer break;
298878ed226SJulian Elischer
299878ed226SJulian Elischer case NG_L2CAP_PENDING:
300878ed226SJulian Elischer break;
301878ed226SJulian Elischer
302878ed226SJulian Elischer default:
303878ed226SJulian Elischer ng_l2cap_free_chan(ch);
304878ed226SJulian Elischer ch = NULL;
305878ed226SJulian Elischer break;
306878ed226SJulian Elischer }
307878ed226SJulian Elischer
308878ed226SJulian Elischer /* Create L2CAP command */
309878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(con, ch, ip->ident, NG_L2CAP_CON_RSP,
310878ed226SJulian Elischer msg->header.token);
311878ed226SJulian Elischer if (cmd == NULL) {
312878ed226SJulian Elischer if (ch != NULL)
313878ed226SJulian Elischer ng_l2cap_free_chan(ch);
314878ed226SJulian Elischer
315878ed226SJulian Elischer error = ENOMEM;
316878ed226SJulian Elischer goto out;
317878ed226SJulian Elischer }
318878ed226SJulian Elischer
319878ed226SJulian Elischer _ng_l2cap_con_rsp(cmd->aux, cmd->ident, ip->lcid, dcid,
320878ed226SJulian Elischer ip->result, ip->status);
321878ed226SJulian Elischer if (cmd->aux == NULL) {
322878ed226SJulian Elischer if (ch != NULL)
323878ed226SJulian Elischer ng_l2cap_free_chan(ch);
324878ed226SJulian Elischer
325878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
326878ed226SJulian Elischer error = ENOBUFS;
327878ed226SJulian Elischer goto out;
328878ed226SJulian Elischer }
329878ed226SJulian Elischer
330878ed226SJulian Elischer /* Link command to the queue */
331878ed226SJulian Elischer ng_l2cap_link_cmd(con, cmd);
332878ed226SJulian Elischer ng_l2cap_lp_deliver(con);
333878ed226SJulian Elischer out:
334878ed226SJulian Elischer return (error);
335878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_rsp_req */
336878ed226SJulian Elischer
ng_l2cap_l2ca_encryption_change(ng_l2cap_chan_p ch,uint16_t result)3373a601a23STakanori Watanabe int ng_l2cap_l2ca_encryption_change(ng_l2cap_chan_p ch, uint16_t result)
3383a601a23STakanori Watanabe {
3393a601a23STakanori Watanabe ng_l2cap_p l2cap = ch->con->l2cap;
3403a601a23STakanori Watanabe struct ng_mesg *msg = NULL;
3413a601a23STakanori Watanabe ng_l2cap_l2ca_enc_chg_op *op = NULL;
3423a601a23STakanori Watanabe int error = 0;
3433a601a23STakanori Watanabe
3443a601a23STakanori Watanabe /* Check if upstream hook is connected and valid */
3453a601a23STakanori Watanabe if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
3463a601a23STakanori Watanabe NG_L2CAP_ERR(
3473a601a23STakanori Watanabe "%s: %s - unable to send L2CA_ConnectRsp response message. " \
3483a601a23STakanori Watanabe "Hook is not connected or valid, psm=%d\n",
3493a601a23STakanori Watanabe __func__, NG_NODE_NAME(l2cap->node), ch->psm);
3503a601a23STakanori Watanabe
3513a601a23STakanori Watanabe return (ENOTCONN);
3523a601a23STakanori Watanabe }
3533a601a23STakanori Watanabe
3543a601a23STakanori Watanabe /* Create and send L2CA_ConnectRsp response message */
3553a601a23STakanori Watanabe NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENC_CHANGE,
3563a601a23STakanori Watanabe sizeof(*op), M_NOWAIT);
3573a601a23STakanori Watanabe if (msg == NULL)
3583a601a23STakanori Watanabe error = ENOMEM;
3593a601a23STakanori Watanabe else {
3603a601a23STakanori Watanabe msg->header.token = 0;
3613a601a23STakanori Watanabe msg->header.flags |= NGF_RESP;
3623a601a23STakanori Watanabe
3633a601a23STakanori Watanabe op = (ng_l2cap_l2ca_enc_chg_op *)(msg->data);
3643a601a23STakanori Watanabe op->result = result;
3653a601a23STakanori Watanabe if(ch->scid ==NG_L2CAP_ATT_CID||
3663a601a23STakanori Watanabe ch->scid ==NG_L2CAP_SMP_CID){
3673a601a23STakanori Watanabe op->lcid = ch->con->con_handle;
3683a601a23STakanori Watanabe op->idtype = (ch->scid==NG_L2CAP_ATT_CID)?
3693a601a23STakanori Watanabe NG_L2CAP_L2CA_IDTYPE_ATT:
3703a601a23STakanori Watanabe NG_L2CAP_L2CA_IDTYPE_SMP;
3713a601a23STakanori Watanabe }else{
3723a601a23STakanori Watanabe op->idtype =(ch->con->linktype ==NG_HCI_LINK_ACL)?
3733a601a23STakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR:
3743a601a23STakanori Watanabe NG_L2CAP_L2CA_IDTYPE_LE;
3753a601a23STakanori Watanabe }
3763a601a23STakanori Watanabe
3773a601a23STakanori Watanabe
3783a601a23STakanori Watanabe NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
3793a601a23STakanori Watanabe }
3803a601a23STakanori Watanabe
3813a601a23STakanori Watanabe return (error);
3823a601a23STakanori Watanabe
3833a601a23STakanori Watanabe }
384878ed226SJulian Elischer /*
385878ed226SJulian Elischer * Send L2CAP_ConnectRsp response to the upper layer
386878ed226SJulian Elischer */
387878ed226SJulian Elischer
388878ed226SJulian Elischer int
ng_l2cap_l2ca_con_rsp_rsp(ng_l2cap_chan_p ch,u_int32_t token,u_int16_t result)389878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
390878ed226SJulian Elischer {
391878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap;
392878ed226SJulian Elischer struct ng_mesg *msg = NULL;
393878ed226SJulian Elischer ng_l2cap_l2ca_con_rsp_op *op = NULL;
394878ed226SJulian Elischer int error = 0;
395878ed226SJulian Elischer
396878ed226SJulian Elischer /* Check if upstream hook is connected and valid */
397878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
398878ed226SJulian Elischer NG_L2CAP_ERR(
399878ed226SJulian Elischer "%s: %s - unable to send L2CA_ConnectRsp response message. " \
400878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
401878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm);
402878ed226SJulian Elischer
403878ed226SJulian Elischer return (ENOTCONN);
404878ed226SJulian Elischer }
405878ed226SJulian Elischer
406878ed226SJulian Elischer /* Create and send L2CA_ConnectRsp response message */
407878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_RSP,
408878ed226SJulian Elischer sizeof(*op), M_NOWAIT);
409878ed226SJulian Elischer if (msg == NULL)
410878ed226SJulian Elischer error = ENOMEM;
411878ed226SJulian Elischer else {
412878ed226SJulian Elischer msg->header.token = token;
413878ed226SJulian Elischer msg->header.flags |= NGF_RESP;
414878ed226SJulian Elischer
415878ed226SJulian Elischer op = (ng_l2cap_l2ca_con_rsp_op *)(msg->data);
416878ed226SJulian Elischer op->result = result;
417878ed226SJulian Elischer
4184ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
419878ed226SJulian Elischer }
420878ed226SJulian Elischer
421878ed226SJulian Elischer return (error);
422878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_rsp_rsp */
423878ed226SJulian Elischer
424878ed226SJulian Elischer /*
425878ed226SJulian Elischer * Send L2CA_ConnectInd message to the upper layer protocol.
426878ed226SJulian Elischer */
427878ed226SJulian Elischer
428878ed226SJulian Elischer int
ng_l2cap_l2ca_con_ind(ng_l2cap_chan_p ch)429878ed226SJulian Elischer ng_l2cap_l2ca_con_ind(ng_l2cap_chan_p ch)
430878ed226SJulian Elischer {
431878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap;
432878ed226SJulian Elischer struct ng_mesg *msg = NULL;
433878ed226SJulian Elischer ng_l2cap_l2ca_con_ind_ip *ip = NULL;
434878ed226SJulian Elischer int error = 0;
435878ed226SJulian Elischer
436878ed226SJulian Elischer /* Check if upstream hook is connected and valid */
437878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
438878ed226SJulian Elischer NG_L2CAP_ERR(
439878ed226SJulian Elischer "%s: %s - unable to send L2CA_ConnectInd message. " \
440878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
441878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm);
442878ed226SJulian Elischer
443878ed226SJulian Elischer return (ENOTCONN);
444878ed226SJulian Elischer }
445878ed226SJulian Elischer
446878ed226SJulian Elischer /* Create and send L2CA_ConnectInd message */
447878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_IND,
448878ed226SJulian Elischer sizeof(*ip), M_NOWAIT);
449878ed226SJulian Elischer if (msg == NULL)
450878ed226SJulian Elischer error = ENOMEM;
451878ed226SJulian Elischer else {
452878ed226SJulian Elischer ip = (ng_l2cap_l2ca_con_ind_ip *)(msg->data);
453878ed226SJulian Elischer
454878ed226SJulian Elischer bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr));
455878ed226SJulian Elischer ip->lcid = ch->scid;
456878ed226SJulian Elischer ip->psm = ch->psm;
457878ed226SJulian Elischer ip->ident = ch->ident;
45899043514STakanori Watanabe ip->linktype = ch->con->linktype;
4593a601a23STakanori Watanabe
4604ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
461878ed226SJulian Elischer }
462878ed226SJulian Elischer
463878ed226SJulian Elischer return (error);
464878ed226SJulian Elischer } /* ng_l2cap_l2ca_con_ind */
465878ed226SJulian Elischer
466878ed226SJulian Elischer /*
467878ed226SJulian Elischer * Process L2CA_Config request from the upper layer protocol
468878ed226SJulian Elischer */
469878ed226SJulian Elischer
470878ed226SJulian Elischer int
ng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap,struct ng_mesg * msg)471878ed226SJulian Elischer ng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
472878ed226SJulian Elischer {
473878ed226SJulian Elischer ng_l2cap_l2ca_cfg_ip *ip = NULL;
474878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL;
475878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL;
476878ed226SJulian Elischer struct mbuf *opt = NULL;
477878ed226SJulian Elischer u_int16_t *mtu = NULL, *flush_timo = NULL;
478878ed226SJulian Elischer ng_l2cap_flow_p flow = NULL;
479878ed226SJulian Elischer int error = 0;
480878ed226SJulian Elischer
481878ed226SJulian Elischer /* Check message */
482878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) {
483878ed226SJulian Elischer NG_L2CAP_ALERT(
484878ed226SJulian Elischer "%s: %s - Invalid L2CA_Config request message size, size=%d\n",
485878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node),
486878ed226SJulian Elischer msg->header.arglen);
487878ed226SJulian Elischer error = EMSGSIZE;
488878ed226SJulian Elischer goto out;
489878ed226SJulian Elischer }
490878ed226SJulian Elischer
491878ed226SJulian Elischer ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data);
492878ed226SJulian Elischer
493878ed226SJulian Elischer /* Check if we have this channel */
494fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, NG_L2CAP_L2CA_IDTYPE_BREDR);
495878ed226SJulian Elischer if (ch == NULL) {
496878ed226SJulian Elischer NG_L2CAP_ERR(
497878ed226SJulian Elischer "%s: %s - unexpected L2CA_Config request message. " \
498878ed226SJulian Elischer "Channel does not exist, lcid=%d\n",
499878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
500878ed226SJulian Elischer error = ENOENT;
501878ed226SJulian Elischer goto out;
502878ed226SJulian Elischer }
503878ed226SJulian Elischer
504878ed226SJulian Elischer /* Check channel state */
505878ed226SJulian Elischer if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG) {
506878ed226SJulian Elischer NG_L2CAP_ERR(
507878ed226SJulian Elischer "%s: %s - unexpected L2CA_Config request message. " \
508878ed226SJulian Elischer "Invalid channel state, state=%d, lcid=%d\n",
509878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->state,
510878ed226SJulian Elischer ch->scid);
511878ed226SJulian Elischer error = EINVAL;
512878ed226SJulian Elischer goto out;
513878ed226SJulian Elischer }
514878ed226SJulian Elischer
515878ed226SJulian Elischer /* Set requested channel configuration options */
516878ed226SJulian Elischer ch->imtu = ip->imtu;
517878ed226SJulian Elischer bcopy(&ip->oflow, &ch->oflow, sizeof(ch->oflow));
518878ed226SJulian Elischer ch->flush_timo = ip->flush_timo;
519878ed226SJulian Elischer ch->link_timo = ip->link_timo;
520878ed226SJulian Elischer
521878ed226SJulian Elischer /* Compare channel settings with defaults */
522878ed226SJulian Elischer if (ch->imtu != NG_L2CAP_MTU_DEFAULT)
523878ed226SJulian Elischer mtu = &ch->imtu;
524878ed226SJulian Elischer if (ch->flush_timo != NG_L2CAP_FLUSH_TIMO_DEFAULT)
525878ed226SJulian Elischer flush_timo = &ch->flush_timo;
526878ed226SJulian Elischer if (bcmp(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)) != 0)
527878ed226SJulian Elischer flow = &ch->oflow;
528878ed226SJulian Elischer
529878ed226SJulian Elischer /* Create configuration options */
530878ed226SJulian Elischer _ng_l2cap_build_cfg_options(opt, mtu, flush_timo, flow);
531878ed226SJulian Elischer if (opt == NULL) {
532878ed226SJulian Elischer error = ENOBUFS;
533878ed226SJulian Elischer goto out;
534878ed226SJulian Elischer }
535878ed226SJulian Elischer
536878ed226SJulian Elischer /* Create L2CAP command descriptor */
537878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con),
538878ed226SJulian Elischer NG_L2CAP_CFG_REQ, msg->header.token);
539878ed226SJulian Elischer if (cmd == NULL) {
540878ed226SJulian Elischer NG_FREE_M(opt);
541878ed226SJulian Elischer error = ENOMEM;
542878ed226SJulian Elischer goto out;
543878ed226SJulian Elischer }
544878ed226SJulian Elischer
545878ed226SJulian Elischer if (cmd->ident == NG_L2CAP_NULL_IDENT) {
546878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
547878ed226SJulian Elischer NG_FREE_M(opt);
548878ed226SJulian Elischer error = EIO;
549878ed226SJulian Elischer goto out;
550878ed226SJulian Elischer }
551878ed226SJulian Elischer
552878ed226SJulian Elischer /* Create L2CAP command packet */
553878ed226SJulian Elischer _ng_l2cap_cfg_req(cmd->aux, cmd->ident, ch->dcid, 0, opt);
554878ed226SJulian Elischer if (cmd->aux == NULL) {
555878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
556878ed226SJulian Elischer error = ENOBUFS;
557878ed226SJulian Elischer goto out;
558878ed226SJulian Elischer }
559878ed226SJulian Elischer
560878ed226SJulian Elischer /* Adjust channel state for re-configuration */
561878ed226SJulian Elischer if (ch->state == NG_L2CAP_OPEN) {
5623a601a23STakanori Watanabe ch->state = ((ch->scid == NG_L2CAP_ATT_CID)||
5633a601a23STakanori Watanabe (ch->scid == NG_L2CAP_SMP_CID))?
564fbc48c2bSTakanori Watanabe NG_L2CAP_OPEN : NG_L2CAP_CONFIG;
565878ed226SJulian Elischer ch->cfg_state = 0;
566878ed226SJulian Elischer }
567878ed226SJulian Elischer
568878ed226SJulian Elischer /* Link command to the queue */
569878ed226SJulian Elischer ng_l2cap_link_cmd(ch->con, cmd);
570878ed226SJulian Elischer ng_l2cap_lp_deliver(ch->con);
571878ed226SJulian Elischer out:
572878ed226SJulian Elischer return (error);
573878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_req */
574878ed226SJulian Elischer
575878ed226SJulian Elischer /*
576878ed226SJulian Elischer * Send L2CA_Config response to the upper layer protocol
577878ed226SJulian Elischer */
578878ed226SJulian Elischer
579878ed226SJulian Elischer int
ng_l2cap_l2ca_cfg_rsp(ng_l2cap_chan_p ch,u_int32_t token,u_int16_t result)580878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
581878ed226SJulian Elischer {
582878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap;
583878ed226SJulian Elischer struct ng_mesg *msg = NULL;
584878ed226SJulian Elischer ng_l2cap_l2ca_cfg_op *op = NULL;
585878ed226SJulian Elischer int error = 0;
586878ed226SJulian Elischer
587878ed226SJulian Elischer /* Check if upstream hook is connected and valid */
588878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
589878ed226SJulian Elischer NG_L2CAP_ERR(
590878ed226SJulian Elischer "%s: %s - unable to send L2CA_Config response message. " \
591878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
592878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm);
593878ed226SJulian Elischer
594878ed226SJulian Elischer return (ENOTCONN);
595878ed226SJulian Elischer }
596878ed226SJulian Elischer
597878ed226SJulian Elischer /* Create and send L2CA_Config response message */
598878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG,
599878ed226SJulian Elischer sizeof(*op), M_NOWAIT);
600878ed226SJulian Elischer if (msg == NULL)
601878ed226SJulian Elischer error = ENOMEM;
602878ed226SJulian Elischer else {
603878ed226SJulian Elischer msg->header.token = token;
604878ed226SJulian Elischer msg->header.flags |= NGF_RESP;
605878ed226SJulian Elischer
606878ed226SJulian Elischer op = (ng_l2cap_l2ca_cfg_op *)(msg->data);
607878ed226SJulian Elischer op->result = result;
608878ed226SJulian Elischer op->imtu = ch->imtu;
609878ed226SJulian Elischer bcopy(&ch->oflow, &op->oflow, sizeof(op->oflow));
610878ed226SJulian Elischer op->flush_timo = ch->flush_timo;
611878ed226SJulian Elischer
6124ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
613878ed226SJulian Elischer
614878ed226SJulian Elischer if (error == 0 && result == NG_L2CAP_SUCCESS) {
615878ed226SJulian Elischer ch->cfg_state |= NG_L2CAP_CFG_IN;
616878ed226SJulian Elischer
617878ed226SJulian Elischer if (ch->cfg_state == NG_L2CAP_CFG_BOTH)
618878ed226SJulian Elischer ch->state = NG_L2CAP_OPEN;
619878ed226SJulian Elischer }
620878ed226SJulian Elischer }
621878ed226SJulian Elischer
622878ed226SJulian Elischer return (error);
623878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_rsp */
624878ed226SJulian Elischer
625878ed226SJulian Elischer /*
626878ed226SJulian Elischer * Process L2CA_ConfigRsp request from the upper layer protocol
627878ed226SJulian Elischer *
628878ed226SJulian Elischer * XXX XXX XXX
629878ed226SJulian Elischer *
630878ed226SJulian Elischer * NOTE: The Bluetooth specification says that Configuration_Response
631878ed226SJulian Elischer * (L2CA_ConfigRsp) should be used to issue response to configuration request
632878ed226SJulian Elischer * indication. The minor problem here is L2CAP command ident. We should use
633878ed226SJulian Elischer * ident from original L2CAP request to make sure our peer can match request
634878ed226SJulian Elischer * and response. For some reason Bluetooth specification does not include
635878ed226SJulian Elischer * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems
636878ed226SJulian Elischer * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident
637878ed226SJulian Elischer * field. So we should store last known L2CAP request command ident in channel.
638878ed226SJulian Elischer * Also it seems that upper layer can not reject configuration request, as
639878ed226SJulian Elischer * Configuration_Response message does not have status/reason field.
640878ed226SJulian Elischer */
641878ed226SJulian Elischer
642878ed226SJulian Elischer int
ng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap,struct ng_mesg * msg)643878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
644878ed226SJulian Elischer {
645878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp_ip *ip = NULL;
646878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL;
647878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL;
648878ed226SJulian Elischer struct mbuf *opt = NULL;
649878ed226SJulian Elischer u_int16_t *mtu = NULL;
650878ed226SJulian Elischer ng_l2cap_flow_p flow = NULL;
651878ed226SJulian Elischer int error = 0;
652878ed226SJulian Elischer
653878ed226SJulian Elischer /* Check message */
654878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) {
655878ed226SJulian Elischer NG_L2CAP_ALERT(
656878ed226SJulian Elischer "%s: %s - invalid L2CA_ConfigRsp request message size, size=%d\n",
657878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node),
658878ed226SJulian Elischer msg->header.arglen);
659878ed226SJulian Elischer error = EMSGSIZE;
660878ed226SJulian Elischer goto out;
661878ed226SJulian Elischer }
662878ed226SJulian Elischer
663878ed226SJulian Elischer ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data);
664878ed226SJulian Elischer
665878ed226SJulian Elischer /* Check if we have this channel */
666fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid,
667fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR);
668878ed226SJulian Elischer if (ch == NULL) {
669878ed226SJulian Elischer NG_L2CAP_ERR(
670878ed226SJulian Elischer "%s: %s - unexpected L2CA_ConfigRsp request message. " \
671878ed226SJulian Elischer "Channel does not exist, lcid=%d\n",
672878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
673878ed226SJulian Elischer error = ENOENT;
674878ed226SJulian Elischer goto out;
675878ed226SJulian Elischer }
676878ed226SJulian Elischer
677878ed226SJulian Elischer /* Check channel state */
678878ed226SJulian Elischer if (ch->state != NG_L2CAP_CONFIG) {
679878ed226SJulian Elischer NG_L2CAP_ERR(
680878ed226SJulian Elischer "%s: %s - unexpected L2CA_ConfigRsp request message. " \
681878ed226SJulian Elischer "Invalid channel state, state=%d, lcid=%d\n",
682878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->state,
683878ed226SJulian Elischer ch->scid);
684878ed226SJulian Elischer error = EINVAL;
685878ed226SJulian Elischer goto out;
686878ed226SJulian Elischer }
687878ed226SJulian Elischer
688878ed226SJulian Elischer /* Set channel settings */
689878ed226SJulian Elischer if (ip->omtu != ch->omtu) {
690878ed226SJulian Elischer ch->omtu = ip->omtu;
691878ed226SJulian Elischer mtu = &ch->omtu;
692878ed226SJulian Elischer }
693878ed226SJulian Elischer
694878ed226SJulian Elischer if (bcmp(&ip->iflow, &ch->iflow, sizeof(ch->iflow)) != 0) {
695878ed226SJulian Elischer bcopy(&ip->iflow, &ch->iflow, sizeof(ch->iflow));
696878ed226SJulian Elischer flow = &ch->iflow;
697878ed226SJulian Elischer }
698878ed226SJulian Elischer
699878ed226SJulian Elischer if (mtu != NULL || flow != NULL) {
700878ed226SJulian Elischer _ng_l2cap_build_cfg_options(opt, mtu, NULL, flow);
701878ed226SJulian Elischer if (opt == NULL) {
702878ed226SJulian Elischer error = ENOBUFS;
703878ed226SJulian Elischer goto out;
704878ed226SJulian Elischer }
705878ed226SJulian Elischer }
706878ed226SJulian Elischer
707878ed226SJulian Elischer /* Create L2CAP command */
708878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(ch->con, ch, ch->ident, NG_L2CAP_CFG_RSP,
709878ed226SJulian Elischer msg->header.token);
710878ed226SJulian Elischer if (cmd == NULL) {
711878ed226SJulian Elischer NG_FREE_M(opt);
712878ed226SJulian Elischer error = ENOMEM;
713878ed226SJulian Elischer goto out;
714878ed226SJulian Elischer }
715878ed226SJulian Elischer
716878ed226SJulian Elischer _ng_l2cap_cfg_rsp(cmd->aux,cmd->ident,ch->dcid,0,NG_L2CAP_SUCCESS,opt);
717878ed226SJulian Elischer if (cmd->aux == NULL) {
718878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
719878ed226SJulian Elischer error = ENOBUFS;
720878ed226SJulian Elischer goto out;
721878ed226SJulian Elischer }
722878ed226SJulian Elischer
723878ed226SJulian Elischer /* XXX FIXME - not here ??? */
724878ed226SJulian Elischer ch->cfg_state |= NG_L2CAP_CFG_OUT;
725878ed226SJulian Elischer if (ch->cfg_state == NG_L2CAP_CFG_BOTH)
726878ed226SJulian Elischer ch->state = NG_L2CAP_OPEN;
727878ed226SJulian Elischer
728878ed226SJulian Elischer /* Link command to the queue */
729878ed226SJulian Elischer ng_l2cap_link_cmd(ch->con, cmd);
730878ed226SJulian Elischer ng_l2cap_lp_deliver(ch->con);
731878ed226SJulian Elischer out:
732878ed226SJulian Elischer return (error);
733878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_rsp_req */
734878ed226SJulian Elischer
735878ed226SJulian Elischer /*
736878ed226SJulian Elischer * Send L2CA_ConfigRsp response to the upper layer protocol
737878ed226SJulian Elischer */
738878ed226SJulian Elischer
739878ed226SJulian Elischer int
ng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch,u_int32_t token,u_int16_t result)740878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
741878ed226SJulian Elischer {
742878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap;
743878ed226SJulian Elischer struct ng_mesg *msg = NULL;
744878ed226SJulian Elischer ng_l2cap_l2ca_cfg_rsp_op *op = NULL;
745878ed226SJulian Elischer int error = 0;
746878ed226SJulian Elischer
747878ed226SJulian Elischer /* Check if upstream hook is connected and valid */
748878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
749878ed226SJulian Elischer NG_L2CAP_ERR(
750878ed226SJulian Elischer "%s: %s - unable to send L2CA_ConfigRsp response message. " \
751878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
752878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm);
753878ed226SJulian Elischer
754878ed226SJulian Elischer return (ENOTCONN);
755878ed226SJulian Elischer }
756878ed226SJulian Elischer
757878ed226SJulian Elischer /* Create and send L2CA_ConfigRsp response message */
758878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP,
759878ed226SJulian Elischer sizeof(*op), M_NOWAIT);
760878ed226SJulian Elischer if (msg == NULL)
761878ed226SJulian Elischer error = ENOMEM;
762878ed226SJulian Elischer else {
763878ed226SJulian Elischer msg->header.token = token;
764878ed226SJulian Elischer msg->header.flags |= NGF_RESP;
765878ed226SJulian Elischer
766878ed226SJulian Elischer op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data);
767878ed226SJulian Elischer op->result = result;
768878ed226SJulian Elischer
7694ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
770878ed226SJulian Elischer }
771878ed226SJulian Elischer
772878ed226SJulian Elischer return (error);
773878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_rsp_rsp */
774878ed226SJulian Elischer
775878ed226SJulian Elischer /*
776878ed226SJulian Elischer * Send L2CA_ConfigInd message to the upper layer protocol
777878ed226SJulian Elischer *
778878ed226SJulian Elischer * XXX XXX XXX
779878ed226SJulian Elischer *
780878ed226SJulian Elischer * NOTE: The Bluetooth specification says that Configuration_Response
781878ed226SJulian Elischer * (L2CA_ConfigRsp) should be used to issue response to configuration request
782878ed226SJulian Elischer * indication. The minor problem here is L2CAP command ident. We should use
783878ed226SJulian Elischer * ident from original L2CAP request to make sure our peer can match request
784878ed226SJulian Elischer * and response. For some reason Bluetooth specification does not include
785878ed226SJulian Elischer * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems
786878ed226SJulian Elischer * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident
787878ed226SJulian Elischer * field. So we should store last known L2CAP request command ident in channel.
788878ed226SJulian Elischer * Also it seems that upper layer can not reject configuration request, as
789878ed226SJulian Elischer * Configuration_Response message does not have status/reason field.
790878ed226SJulian Elischer */
791878ed226SJulian Elischer
792878ed226SJulian Elischer int
ng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch)793878ed226SJulian Elischer ng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch)
794878ed226SJulian Elischer {
795878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap;
796878ed226SJulian Elischer struct ng_mesg *msg = NULL;
797878ed226SJulian Elischer ng_l2cap_l2ca_cfg_ind_ip *ip = NULL;
798878ed226SJulian Elischer int error = 0;
799878ed226SJulian Elischer
800878ed226SJulian Elischer /* Check if upstream hook is connected and valid */
801878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
802878ed226SJulian Elischer NG_L2CAP_ERR(
803878ed226SJulian Elischer "%s: %s - Unable to send L2CA_ConfigInd message. " \
804878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
805878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm);
806878ed226SJulian Elischer
807878ed226SJulian Elischer return (ENOTCONN);
808878ed226SJulian Elischer }
809878ed226SJulian Elischer
810878ed226SJulian Elischer /* Create and send L2CA_ConnectInd message */
811878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_IND,
812878ed226SJulian Elischer sizeof(*ip), M_NOWAIT);
813878ed226SJulian Elischer if (msg == NULL)
814878ed226SJulian Elischer error = ENOMEM;
815878ed226SJulian Elischer else {
816878ed226SJulian Elischer ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data);
817878ed226SJulian Elischer ip->lcid = ch->scid;
818878ed226SJulian Elischer ip->omtu = ch->omtu;
819878ed226SJulian Elischer bcopy(&ch->iflow, &ip->iflow, sizeof(ip->iflow));
820878ed226SJulian Elischer ip->flush_timo = ch->flush_timo;
821878ed226SJulian Elischer
8224ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
823878ed226SJulian Elischer }
824878ed226SJulian Elischer
825878ed226SJulian Elischer return (error);
826878ed226SJulian Elischer } /* ng_l2cap_l2ca_cfg_ind */
827878ed226SJulian Elischer
828878ed226SJulian Elischer /*
829878ed226SJulian Elischer * Process L2CA_Write event
830878ed226SJulian Elischer */
831878ed226SJulian Elischer
832878ed226SJulian Elischer int
ng_l2cap_l2ca_write_req(ng_l2cap_p l2cap,struct mbuf * m)833878ed226SJulian Elischer ng_l2cap_l2ca_write_req(ng_l2cap_p l2cap, struct mbuf *m)
834878ed226SJulian Elischer {
835878ed226SJulian Elischer ng_l2cap_l2ca_hdr_t *l2ca_hdr = NULL;
836878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL;
837878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL;
838878ed226SJulian Elischer int error = 0;
839878ed226SJulian Elischer u_int32_t token = 0;
840878ed226SJulian Elischer
841878ed226SJulian Elischer /* Make sure we can access L2CA data packet header */
842878ed226SJulian Elischer if (m->m_pkthdr.len < sizeof(*l2ca_hdr)) {
843878ed226SJulian Elischer NG_L2CAP_ERR(
844878ed226SJulian Elischer "%s: %s - L2CA Data packet too small, len=%d\n",
845878ed226SJulian Elischer __func__,NG_NODE_NAME(l2cap->node),m->m_pkthdr.len);
846878ed226SJulian Elischer error = EMSGSIZE;
847878ed226SJulian Elischer goto drop;
848878ed226SJulian Elischer }
849878ed226SJulian Elischer
850878ed226SJulian Elischer /* Get L2CA data packet header */
851878ed226SJulian Elischer NG_L2CAP_M_PULLUP(m, sizeof(*l2ca_hdr));
852878ed226SJulian Elischer if (m == NULL)
853878ed226SJulian Elischer return (ENOBUFS);
854878ed226SJulian Elischer
855878ed226SJulian Elischer l2ca_hdr = mtod(m, ng_l2cap_l2ca_hdr_t *);
856878ed226SJulian Elischer token = l2ca_hdr->token;
857878ed226SJulian Elischer m_adj(m, sizeof(*l2ca_hdr));
858878ed226SJulian Elischer
859878ed226SJulian Elischer /* Verify payload size */
860878ed226SJulian Elischer if (l2ca_hdr->length != m->m_pkthdr.len) {
861878ed226SJulian Elischer NG_L2CAP_ERR(
862878ed226SJulian Elischer "%s: %s - invalid L2CA Data packet. " \
863878ed226SJulian Elischer "Payload length does not match, length=%d, len=%d\n",
864878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->length,
865878ed226SJulian Elischer m->m_pkthdr.len);
866878ed226SJulian Elischer error = EMSGSIZE;
867878ed226SJulian Elischer goto drop;
868878ed226SJulian Elischer }
869878ed226SJulian Elischer
870878ed226SJulian Elischer /* Check channel ID */
871fbc48c2bSTakanori Watanabe if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
872fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
873fbc48c2bSTakanori Watanabe l2ca_hdr->lcid);
8743a601a23STakanori Watanabe } else if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
8753a601a23STakanori Watanabe ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
8763a601a23STakanori Watanabe l2ca_hdr->lcid);
877fbc48c2bSTakanori Watanabe }else{
878878ed226SJulian Elischer if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) {
879878ed226SJulian Elischer NG_L2CAP_ERR(
880878ed226SJulian Elischer "%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n",
881fbc48c2bSTakanori Watanabe __func__, NG_NODE_NAME(l2cap->node),
882fbc48c2bSTakanori Watanabe l2ca_hdr->lcid);
883878ed226SJulian Elischer error = EINVAL;
884878ed226SJulian Elischer goto drop;
885878ed226SJulian Elischer }
886878ed226SJulian Elischer
887878ed226SJulian Elischer /* Verify that we have the channel and make sure it is open */
888fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid,
889fbc48c2bSTakanori Watanabe l2ca_hdr->idtype);
890fbc48c2bSTakanori Watanabe }
891fbc48c2bSTakanori Watanabe
892878ed226SJulian Elischer if (ch == NULL) {
893878ed226SJulian Elischer NG_L2CAP_ERR(
894878ed226SJulian Elischer "%s: %s - invalid L2CA Data packet. Channel does not exist, cid=%d\n",
895878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid);
896878ed226SJulian Elischer error = ENOENT;
897878ed226SJulian Elischer goto drop;
898878ed226SJulian Elischer }
899878ed226SJulian Elischer
900878ed226SJulian Elischer if (ch->state != NG_L2CAP_OPEN) {
901878ed226SJulian Elischer NG_L2CAP_ERR(
902878ed226SJulian Elischer "%s: %s - invalid L2CA Data packet. Invalid channel state, scid=%d, state=%d\n",
903878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->scid,
904878ed226SJulian Elischer ch->state);
905878ed226SJulian Elischer error = EHOSTDOWN;
906878ed226SJulian Elischer goto drop; /* XXX not always - re-configure */
907878ed226SJulian Elischer }
908878ed226SJulian Elischer
909878ed226SJulian Elischer /* Create L2CAP command descriptor */
910878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(ch->con, ch, 0, NGM_L2CAP_L2CA_WRITE, token);
911878ed226SJulian Elischer if (cmd == NULL) {
912878ed226SJulian Elischer error = ENOMEM;
913878ed226SJulian Elischer goto drop;
914878ed226SJulian Elischer }
915878ed226SJulian Elischer
916878ed226SJulian Elischer /* Attach data packet and link command to the queue */
917878ed226SJulian Elischer cmd->aux = m;
918878ed226SJulian Elischer ng_l2cap_link_cmd(ch->con, cmd);
919878ed226SJulian Elischer ng_l2cap_lp_deliver(ch->con);
920878ed226SJulian Elischer
921878ed226SJulian Elischer return (error);
922878ed226SJulian Elischer drop:
923878ed226SJulian Elischer NG_FREE_M(m);
924878ed226SJulian Elischer
925878ed226SJulian Elischer return (error);
926878ed226SJulian Elischer } /* ng_l2cap_l2ca_write_req */
927878ed226SJulian Elischer
928878ed226SJulian Elischer /*
929878ed226SJulian Elischer * Send L2CA_Write response
930878ed226SJulian Elischer */
931878ed226SJulian Elischer
932878ed226SJulian Elischer int
ng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch,u_int32_t token,u_int16_t result,u_int16_t length)933878ed226SJulian Elischer ng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
934878ed226SJulian Elischer u_int16_t length)
935878ed226SJulian Elischer {
936878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap;
937878ed226SJulian Elischer struct ng_mesg *msg = NULL;
938878ed226SJulian Elischer ng_l2cap_l2ca_write_op *op = NULL;
939878ed226SJulian Elischer int error = 0;
940878ed226SJulian Elischer
941878ed226SJulian Elischer /* Check if upstream hook is connected and valid */
942878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
943878ed226SJulian Elischer NG_L2CAP_ERR(
944878ed226SJulian Elischer "%s: %s - unable to send L2CA_WriteRsp message. " \
945878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
946878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm);
947878ed226SJulian Elischer
948878ed226SJulian Elischer return (ENOTCONN);
949878ed226SJulian Elischer }
950878ed226SJulian Elischer
951878ed226SJulian Elischer /* Create and send L2CA_WriteRsp message */
952878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_WRITE,
953878ed226SJulian Elischer sizeof(*op), M_NOWAIT);
954878ed226SJulian Elischer if (msg == NULL)
955878ed226SJulian Elischer error = ENOMEM;
956878ed226SJulian Elischer else {
957878ed226SJulian Elischer msg->header.token = token;
958878ed226SJulian Elischer msg->header.flags |= NGF_RESP;
959878ed226SJulian Elischer
960878ed226SJulian Elischer op = (ng_l2cap_l2ca_write_op *)(msg->data);
961878ed226SJulian Elischer op->result = result;
962878ed226SJulian Elischer op->length = length;
963fbc48c2bSTakanori Watanabe if(ch->scid == NG_L2CAP_ATT_CID){
964fbc48c2bSTakanori Watanabe op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
965fbc48c2bSTakanori Watanabe op->lcid = ch->con->con_handle;
9663a601a23STakanori Watanabe }else if(ch->scid == NG_L2CAP_SMP_CID){
9673a601a23STakanori Watanabe op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
9683a601a23STakanori Watanabe op->lcid = ch->con->con_handle;
969fbc48c2bSTakanori Watanabe }else{
970fbc48c2bSTakanori Watanabe op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
971fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR :
972fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_LE;
973878ed226SJulian Elischer op->lcid = ch->scid;
974878ed226SJulian Elischer
975fbc48c2bSTakanori Watanabe }
9764ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
977878ed226SJulian Elischer }
978878ed226SJulian Elischer
979878ed226SJulian Elischer return (error);
980878ed226SJulian Elischer } /* ng_l2cap_l2ca_write_rsp */
981878ed226SJulian Elischer
982878ed226SJulian Elischer /*
983878ed226SJulian Elischer * Receive packet from the lower layer protocol and send it to the upper
984878ed226SJulian Elischer * layer protocol (L2CAP_Read)
985878ed226SJulian Elischer */
986878ed226SJulian Elischer
987878ed226SJulian Elischer int
ng_l2cap_l2ca_receive(ng_l2cap_con_p con)988878ed226SJulian Elischer ng_l2cap_l2ca_receive(ng_l2cap_con_p con)
989878ed226SJulian Elischer {
990878ed226SJulian Elischer ng_l2cap_p l2cap = con->l2cap;
991878ed226SJulian Elischer ng_l2cap_hdr_t *hdr = NULL;
992878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL;
993878ed226SJulian Elischer int error = 0;
994fbc48c2bSTakanori Watanabe int idtype;
995fbc48c2bSTakanori Watanabe uint16_t *idp;
9963a601a23STakanori Watanabe int silent = 0;
997878ed226SJulian Elischer
998878ed226SJulian Elischer NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
999878ed226SJulian Elischer if (con->rx_pkt == NULL)
1000878ed226SJulian Elischer return (ENOBUFS);
1001878ed226SJulian Elischer
1002878ed226SJulian Elischer hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *);
1003878ed226SJulian Elischer
1004878ed226SJulian Elischer /* Check channel */
1005fbc48c2bSTakanori Watanabe
1006fbc48c2bSTakanori Watanabe if(hdr->dcid == NG_L2CAP_ATT_CID){
1007fbc48c2bSTakanori Watanabe idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
1008fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
1009fbc48c2bSTakanori Watanabe con->con_handle);
1010fbc48c2bSTakanori Watanabe /*
1011fbc48c2bSTakanori Watanabe * Here,ATT channel is distinguished by
1012fbc48c2bSTakanori Watanabe * connection handle
1013fbc48c2bSTakanori Watanabe */
1014fbc48c2bSTakanori Watanabe hdr->dcid = con->con_handle;
10153a601a23STakanori Watanabe silent = 1;
10163a601a23STakanori Watanabe }else if(hdr->dcid == NG_L2CAP_SMP_CID){
10173a601a23STakanori Watanabe idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
10183a601a23STakanori Watanabe ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
10193a601a23STakanori Watanabe con->con_handle);
10203a601a23STakanori Watanabe /*
10213a601a23STakanori Watanabe * Here,SMP channel is distinguished by
10223a601a23STakanori Watanabe * connection handle
10233a601a23STakanori Watanabe */
10243a601a23STakanori Watanabe silent = 1;
10253a601a23STakanori Watanabe hdr->dcid = con->con_handle;
1026fbc48c2bSTakanori Watanabe }else{
1027fbc48c2bSTakanori Watanabe idtype = (con->linktype==NG_HCI_LINK_ACL)?
1028fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_BREDR:
1029fbc48c2bSTakanori Watanabe NG_L2CAP_L2CA_IDTYPE_LE;
1030fbc48c2bSTakanori Watanabe ch = ng_l2cap_chan_by_scid(l2cap, hdr->dcid, idtype);
1031fbc48c2bSTakanori Watanabe }
1032878ed226SJulian Elischer if (ch == NULL) {
10333a601a23STakanori Watanabe if(!silent)
1034878ed226SJulian Elischer NG_L2CAP_ERR(
1035fbc48c2bSTakanori Watanabe "%s: %s - unexpected L2CAP data packet. Channel does not exist, cid=%d, idtype=%d\n",
1036fbc48c2bSTakanori Watanabe __func__, NG_NODE_NAME(l2cap->node), hdr->dcid, idtype);
1037878ed226SJulian Elischer error = ENOENT;
1038878ed226SJulian Elischer goto drop;
1039878ed226SJulian Elischer }
1040878ed226SJulian Elischer
1041878ed226SJulian Elischer /* Check channel state */
1042878ed226SJulian Elischer if (ch->state != NG_L2CAP_OPEN) {
1043878ed226SJulian Elischer NG_L2CAP_WARN(
1044878ed226SJulian Elischer "%s: %s - unexpected L2CAP data packet. " \
1045878ed226SJulian Elischer "Invalid channel state, cid=%d, state=%d\n",
1046878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->scid,
1047878ed226SJulian Elischer ch->state);
1048878ed226SJulian Elischer error = EHOSTDOWN; /* XXX not always - re-configuration */
1049878ed226SJulian Elischer goto drop;
1050878ed226SJulian Elischer }
1051878ed226SJulian Elischer
1052878ed226SJulian Elischer /* Check payload size and channel's MTU */
1053878ed226SJulian Elischer if (hdr->length > ch->imtu) {
1054878ed226SJulian Elischer NG_L2CAP_ERR(
1055878ed226SJulian Elischer "%s: %s - invalid L2CAP data packet. " \
1056878ed226SJulian Elischer "Packet too big, length=%d, imtu=%d, cid=%d\n",
1057878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), hdr->length,
1058878ed226SJulian Elischer ch->imtu, ch->scid);
1059878ed226SJulian Elischer error = EMSGSIZE;
1060878ed226SJulian Elischer goto drop;
1061878ed226SJulian Elischer }
1062878ed226SJulian Elischer
1063878ed226SJulian Elischer /*
1064878ed226SJulian Elischer * If we got here then everything looks good and we can sent packet
1065878ed226SJulian Elischer * to the upper layer protocol.
1066878ed226SJulian Elischer */
1067878ed226SJulian Elischer
1068878ed226SJulian Elischer /* Check if upstream hook is connected and valid */
1069878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1070878ed226SJulian Elischer NG_L2CAP_ERR(
1071878ed226SJulian Elischer "%s: %s - unable to send L2CAP data packet. " \
1072878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
1073878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm);
1074878ed226SJulian Elischer error = ENOTCONN;
1075878ed226SJulian Elischer goto drop;
1076878ed226SJulian Elischer }
1077fbc48c2bSTakanori Watanabe M_PREPEND(con->rx_pkt, sizeof(uint16_t), M_NOWAIT);
1078fbc48c2bSTakanori Watanabe if(con->rx_pkt == NULL)
1079fbc48c2bSTakanori Watanabe goto drop;
1080fbc48c2bSTakanori Watanabe idp = mtod(con->rx_pkt, uint16_t *);
1081fbc48c2bSTakanori Watanabe *idp = idtype;
1082878ed226SJulian Elischer
1083878ed226SJulian Elischer NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
1084878ed226SJulian Elischer con->rx_pkt = NULL;
1085878ed226SJulian Elischer drop:
1086878ed226SJulian Elischer NG_FREE_M(con->rx_pkt); /* checks for != NULL */
1087878ed226SJulian Elischer
1088878ed226SJulian Elischer return (error);
1089878ed226SJulian Elischer } /* ng_l2cap_receive */
1090878ed226SJulian Elischer
1091878ed226SJulian Elischer /*
1092878ed226SJulian Elischer * Receive connectioless (multicast) packet from the lower layer protocol and
1093878ed226SJulian Elischer * send it to the upper layer protocol
1094878ed226SJulian Elischer */
1095878ed226SJulian Elischer
1096878ed226SJulian Elischer int
ng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con)1097878ed226SJulian Elischer ng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con)
1098878ed226SJulian Elischer {
1099878ed226SJulian Elischer struct _clt_pkt {
1100878ed226SJulian Elischer ng_l2cap_hdr_t h;
1101878ed226SJulian Elischer ng_l2cap_clt_hdr_t c_h;
1102878ed226SJulian Elischer } __attribute__ ((packed)) *hdr = NULL;
1103878ed226SJulian Elischer ng_l2cap_p l2cap = con->l2cap;
1104878ed226SJulian Elischer int length, error = 0;
1105878ed226SJulian Elischer
1106878ed226SJulian Elischer NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
1107878ed226SJulian Elischer if (con->rx_pkt == NULL)
1108878ed226SJulian Elischer return (ENOBUFS);
1109878ed226SJulian Elischer
1110878ed226SJulian Elischer hdr = mtod(con->rx_pkt, struct _clt_pkt *);
1111878ed226SJulian Elischer
1112878ed226SJulian Elischer /* Check packet */
1113878ed226SJulian Elischer length = con->rx_pkt->m_pkthdr.len - sizeof(*hdr);
1114878ed226SJulian Elischer if (length < 0) {
1115878ed226SJulian Elischer NG_L2CAP_ERR(
1116878ed226SJulian Elischer "%s: %s - invalid L2CAP CLT data packet. Packet too small, length=%d\n",
1117878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), length);
1118878ed226SJulian Elischer error = EMSGSIZE;
1119878ed226SJulian Elischer goto drop;
1120878ed226SJulian Elischer }
1121878ed226SJulian Elischer
1122878ed226SJulian Elischer /* Check payload size against CLT MTU */
1123878ed226SJulian Elischer if (length > NG_L2CAP_MTU_DEFAULT) {
1124878ed226SJulian Elischer NG_L2CAP_ERR(
1125878ed226SJulian Elischer "%s: %s - invalid L2CAP CLT data packet. Packet too big, length=%d, mtu=%d\n",
1126878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), length,
1127878ed226SJulian Elischer NG_L2CAP_MTU_DEFAULT);
1128878ed226SJulian Elischer error = EMSGSIZE;
1129878ed226SJulian Elischer goto drop;
1130878ed226SJulian Elischer }
1131878ed226SJulian Elischer
1132878ed226SJulian Elischer hdr->c_h.psm = le16toh(hdr->c_h.psm);
1133878ed226SJulian Elischer
1134878ed226SJulian Elischer /*
1135878ed226SJulian Elischer * If we got here then everything looks good and we can sent packet
1136878ed226SJulian Elischer * to the upper layer protocol.
1137878ed226SJulian Elischer */
1138878ed226SJulian Elischer
1139878ed226SJulian Elischer /* Select upstream hook based on PSM */
1140878ed226SJulian Elischer switch (hdr->c_h.psm) {
1141878ed226SJulian Elischer case NG_L2CAP_PSM_SDP:
1142878ed226SJulian Elischer if (l2cap->flags & NG_L2CAP_CLT_SDP_DISABLED)
1143878ed226SJulian Elischer goto drop;
1144878ed226SJulian Elischer break;
1145878ed226SJulian Elischer
1146878ed226SJulian Elischer case NG_L2CAP_PSM_RFCOMM:
1147878ed226SJulian Elischer if (l2cap->flags & NG_L2CAP_CLT_RFCOMM_DISABLED)
1148878ed226SJulian Elischer goto drop;
1149878ed226SJulian Elischer break;
1150878ed226SJulian Elischer
1151878ed226SJulian Elischer case NG_L2CAP_PSM_TCP:
1152878ed226SJulian Elischer if (l2cap->flags & NG_L2CAP_CLT_TCP_DISABLED)
1153878ed226SJulian Elischer goto drop;
1154878ed226SJulian Elischer break;
1155878ed226SJulian Elischer }
1156878ed226SJulian Elischer
1157878ed226SJulian Elischer /* Check if upstream hook is connected and valid */
1158878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1159878ed226SJulian Elischer NG_L2CAP_ERR(
1160878ed226SJulian Elischer "%s: %s - unable to send L2CAP CLT data packet. " \
1161878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
1162878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), hdr->c_h.psm);
1163878ed226SJulian Elischer error = ENOTCONN;
1164878ed226SJulian Elischer goto drop;
1165878ed226SJulian Elischer }
1166878ed226SJulian Elischer
1167878ed226SJulian Elischer NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
1168878ed226SJulian Elischer con->rx_pkt = NULL;
1169878ed226SJulian Elischer drop:
1170878ed226SJulian Elischer NG_FREE_M(con->rx_pkt); /* checks for != NULL */
1171878ed226SJulian Elischer
1172878ed226SJulian Elischer return (error);
1173878ed226SJulian Elischer } /* ng_l2cap_l2ca_clt_receive */
1174878ed226SJulian Elischer
1175878ed226SJulian Elischer /*
1176878ed226SJulian Elischer * Send L2CA_QoSViolationInd to the upper layer protocol
1177878ed226SJulian Elischer */
1178878ed226SJulian Elischer
1179878ed226SJulian Elischer int
ng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch)1180878ed226SJulian Elischer ng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch)
1181878ed226SJulian Elischer {
1182878ed226SJulian Elischer ng_l2cap_p l2cap = ch->con->l2cap;
1183878ed226SJulian Elischer struct ng_mesg *msg = NULL;
1184878ed226SJulian Elischer ng_l2cap_l2ca_qos_ind_ip *ip = NULL;
1185878ed226SJulian Elischer int error = 0;
1186878ed226SJulian Elischer
1187878ed226SJulian Elischer /* Check if upstream hook is connected and valid */
1188878ed226SJulian Elischer if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1189878ed226SJulian Elischer NG_L2CAP_ERR(
1190878ed226SJulian Elischer "%s: %s - unable to send L2CA_QoSViolationInd message. " \
1191878ed226SJulian Elischer "Hook is not connected or valid, psm=%d\n",
1192878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ch->psm);
1193878ed226SJulian Elischer
1194878ed226SJulian Elischer return (ENOTCONN);
1195878ed226SJulian Elischer }
1196878ed226SJulian Elischer
1197878ed226SJulian Elischer /* Create and send L2CA_QoSViolationInd message */
1198878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_QOS_IND,
1199878ed226SJulian Elischer sizeof(*ip), M_NOWAIT);
1200878ed226SJulian Elischer if (msg == NULL)
1201878ed226SJulian Elischer error = ENOMEM;
1202878ed226SJulian Elischer else {
1203878ed226SJulian Elischer ip = (ng_l2cap_l2ca_qos_ind_ip *)(msg->data);
1204878ed226SJulian Elischer bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr));
12054ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1206878ed226SJulian Elischer }
1207878ed226SJulian Elischer
1208878ed226SJulian Elischer return (error);
1209878ed226SJulian Elischer } /* ng_l2cap_l2ca_qos_ind */
1210878ed226SJulian Elischer
1211878ed226SJulian Elischer /*
1212878ed226SJulian Elischer * Process L2CA_Disconnect request from the upper layer protocol.
1213878ed226SJulian Elischer */
1214878ed226SJulian Elischer
1215878ed226SJulian Elischer int
ng_l2cap_l2ca_discon_req(ng_l2cap_p l2cap,struct ng_mesg * msg)1216878ed226SJulian Elischer ng_l2cap_l2ca_discon_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1217878ed226SJulian Elischer {
1218878ed226SJulian Elischer ng_l2cap_l2ca_discon_ip *ip = NULL;
1219878ed226SJulian Elischer ng_l2cap_chan_p ch = NULL;
1220878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL;
1221878ed226SJulian Elischer int error = 0;
1222878ed226SJulian Elischer
1223878ed226SJulian Elischer /* Check message */
1224878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) {
1225878ed226SJulian Elischer NG_L2CAP_ALERT(
1226878ed226SJulian Elischer "%s: %s - invalid L2CA_Disconnect request message size, size=%d\n",
1227878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node),
1228878ed226SJulian Elischer msg->header.arglen);
1229878ed226SJulian Elischer error = EMSGSIZE;
1230878ed226SJulian Elischer goto out;
1231878ed226SJulian Elischer }
1232878ed226SJulian Elischer
1233878ed226SJulian Elischer ip = (ng_l2cap_l2ca_discon_ip *)(msg->data);
1234878ed226SJulian Elischer
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;
12503a601a23STakanori Watanabe }else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
12513a601a23STakanori Watanabe /* Don't send Disconnect request on L2CAP Layer*/
12523a601a23STakanori Watanabe ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
12533a601a23STakanori Watanabe ip->lcid);
12543a601a23STakanori Watanabe
12553a601a23STakanori Watanabe if(ch != NULL){
12563a601a23STakanori Watanabe ng_l2cap_free_chan(ch);
12573a601a23STakanori Watanabe }else{
12583a601a23STakanori Watanabe NG_L2CAP_ERR(
12593a601a23STakanori Watanabe "%s: %s - unexpected L2CA_Disconnect request message. " \
12603a601a23STakanori Watanabe "Channel does not exist, conhandle=%d\n",
12613a601a23STakanori Watanabe __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
12623a601a23STakanori Watanabe error = EINVAL;
12633a601a23STakanori Watanabe }
12643a601a23STakanori 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
ng_l2cap_l2ca_discon_rsp(ng_l2cap_chan_p ch,u_int32_t token,u_int16_t result)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
ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch)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);
1392b32073c4STakanori Watanabe ip->idtype = ch->idtype;
1393b32073c4STakanori Watanabe if(ch->idtype == NG_L2CAP_L2CA_IDTYPE_ATT||
1394b32073c4STakanori Watanabe ch->idtype == NG_L2CAP_L2CA_IDTYPE_SMP)
1395b32073c4STakanori Watanabe ip->lcid = ch->con->con_handle;
1396b32073c4STakanori Watanabe else
1397878ed226SJulian Elischer ip->lcid = ch->scid;
1398b32073c4STakanori Watanabe
13994ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1400878ed226SJulian Elischer }
1401878ed226SJulian Elischer
1402878ed226SJulian Elischer return (error);
1403878ed226SJulian Elischer } /* ng_l2cap_l2ca_discon_ind */
1404878ed226SJulian Elischer
1405878ed226SJulian Elischer /*
1406878ed226SJulian Elischer * Process L2CA_GroupCreate request from the upper layer protocol.
1407878ed226SJulian Elischer * XXX FIXME
1408878ed226SJulian Elischer */
1409878ed226SJulian Elischer
1410878ed226SJulian Elischer int
ng_l2cap_l2ca_grp_create(ng_l2cap_p l2cap,struct ng_mesg * msg)1411878ed226SJulian Elischer ng_l2cap_l2ca_grp_create(ng_l2cap_p l2cap, struct ng_mesg *msg)
1412878ed226SJulian Elischer {
1413878ed226SJulian Elischer return (ENOTSUP);
1414878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_create */
1415878ed226SJulian Elischer
1416878ed226SJulian Elischer /*
1417878ed226SJulian Elischer * Process L2CA_GroupClose request from the upper layer protocol
1418878ed226SJulian Elischer * XXX FIXME
1419878ed226SJulian Elischer */
1420878ed226SJulian Elischer
1421878ed226SJulian Elischer int
ng_l2cap_l2ca_grp_close(ng_l2cap_p l2cap,struct ng_mesg * msg)1422878ed226SJulian Elischer ng_l2cap_l2ca_grp_close(ng_l2cap_p l2cap, struct ng_mesg *msg)
1423878ed226SJulian Elischer {
1424878ed226SJulian Elischer return (ENOTSUP);
1425878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_close */
1426878ed226SJulian Elischer
1427878ed226SJulian Elischer /*
1428878ed226SJulian Elischer * Process L2CA_GroupAddMember request from the upper layer protocol.
1429878ed226SJulian Elischer * XXX FIXME
1430878ed226SJulian Elischer */
1431878ed226SJulian Elischer
1432878ed226SJulian Elischer int
ng_l2cap_l2ca_grp_add_member_req(ng_l2cap_p l2cap,struct ng_mesg * msg)1433878ed226SJulian Elischer ng_l2cap_l2ca_grp_add_member_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1434878ed226SJulian Elischer {
1435878ed226SJulian Elischer return (ENOTSUP);
1436878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_add_member_req */
1437878ed226SJulian Elischer
1438878ed226SJulian Elischer /*
1439878ed226SJulian Elischer * Send L2CA_GroupAddMember response to the upper layer protocol.
1440878ed226SJulian Elischer * XXX FIXME
1441878ed226SJulian Elischer */
1442878ed226SJulian Elischer
1443878ed226SJulian Elischer int
ng_l2cap_l2ca_grp_add_member_rsp(ng_l2cap_chan_p ch,u_int32_t token,u_int16_t result)1444878ed226SJulian Elischer ng_l2cap_l2ca_grp_add_member_rsp(ng_l2cap_chan_p ch, u_int32_t token,
1445878ed226SJulian Elischer u_int16_t result)
1446878ed226SJulian Elischer {
1447878ed226SJulian Elischer return (0);
1448878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_add_member_rsp */
1449878ed226SJulian Elischer
1450878ed226SJulian Elischer /*
1451878ed226SJulian Elischer * Process L2CA_GroupDeleteMember request from the upper layer protocol
1452878ed226SJulian Elischer * XXX FIXME
1453878ed226SJulian Elischer */
1454878ed226SJulian Elischer
1455878ed226SJulian Elischer int
ng_l2cap_l2ca_grp_rem_member(ng_l2cap_p l2cap,struct ng_mesg * msg)1456878ed226SJulian Elischer ng_l2cap_l2ca_grp_rem_member(ng_l2cap_p l2cap, struct ng_mesg *msg)
1457878ed226SJulian Elischer {
1458878ed226SJulian Elischer return (ENOTSUP);
1459878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_rem_member */
1460878ed226SJulian Elischer
1461878ed226SJulian Elischer /*
1462878ed226SJulian Elischer * Process L2CA_GroupGetMembers request from the upper layer protocol
1463878ed226SJulian Elischer * XXX FIXME
1464878ed226SJulian Elischer */
1465878ed226SJulian Elischer
1466878ed226SJulian Elischer int
ng_l2cap_l2ca_grp_get_members(ng_l2cap_p l2cap,struct ng_mesg * msg)1467878ed226SJulian Elischer ng_l2cap_l2ca_grp_get_members(ng_l2cap_p l2cap, struct ng_mesg *msg)
1468878ed226SJulian Elischer {
1469878ed226SJulian Elischer return (ENOTSUP);
1470878ed226SJulian Elischer } /* ng_l2cap_l2ca_grp_get_members */
1471878ed226SJulian Elischer
1472878ed226SJulian Elischer /*
1473878ed226SJulian Elischer * Process L2CA_Ping request from the upper layer protocol
1474878ed226SJulian Elischer */
1475878ed226SJulian Elischer
1476878ed226SJulian Elischer int
ng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap,struct ng_mesg * msg)1477878ed226SJulian Elischer ng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1478878ed226SJulian Elischer {
1479878ed226SJulian Elischer ng_l2cap_l2ca_ping_ip *ip = NULL;
1480878ed226SJulian Elischer ng_l2cap_con_p con = NULL;
1481878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL;
1482878ed226SJulian Elischer int error = 0;
1483878ed226SJulian Elischer
1484878ed226SJulian Elischer /* Verify message */
1485878ed226SJulian Elischer if (msg->header.arglen < sizeof(*ip)) {
1486878ed226SJulian Elischer NG_L2CAP_ALERT(
1487878ed226SJulian Elischer "%s: %s - invalid L2CA_Ping request message size, size=%d\n",
1488878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node),
1489878ed226SJulian Elischer msg->header.arglen);
1490878ed226SJulian Elischer error = EMSGSIZE;
1491878ed226SJulian Elischer goto out;
1492878ed226SJulian Elischer }
1493878ed226SJulian Elischer
1494878ed226SJulian Elischer ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);
1495878ed226SJulian Elischer if (ip->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
1496878ed226SJulian Elischer NG_L2CAP_WARN(
1497878ed226SJulian Elischer "%s: %s - invalid L2CA_Ping request. Echo size is too big, echo_size=%d\n",
1498878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), ip->echo_size);
1499878ed226SJulian Elischer error = EMSGSIZE;
1500878ed226SJulian Elischer goto out;
1501878ed226SJulian Elischer }
1502878ed226SJulian Elischer
1503878ed226SJulian Elischer /* Check if we have connection to the unit */
1504fbc48c2bSTakanori Watanabe con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1505878ed226SJulian Elischer if (con == NULL) {
1506878ed226SJulian Elischer /* Submit LP_ConnectReq to the lower layer */
1507fbc48c2bSTakanori Watanabe error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1508878ed226SJulian Elischer if (error != 0) {
1509878ed226SJulian Elischer NG_L2CAP_ERR(
1510878ed226SJulian Elischer "%s: %s - unable to send LP_ConnectReq message, error=%d\n",
1511878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), error);
1512878ed226SJulian Elischer goto out;
1513878ed226SJulian Elischer }
1514878ed226SJulian Elischer
1515878ed226SJulian Elischer /* This should not fail */
1516fbc48c2bSTakanori Watanabe con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1517878ed226SJulian Elischer KASSERT((con != NULL),
1518878ed226SJulian Elischer ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
1519878ed226SJulian Elischer }
1520878ed226SJulian Elischer
1521878ed226SJulian Elischer /* Create L2CAP command descriptor */
1522878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),
1523878ed226SJulian Elischer NG_L2CAP_ECHO_REQ, msg->header.token);
1524878ed226SJulian Elischer if (cmd == NULL) {
1525878ed226SJulian Elischer error = ENOMEM;
1526878ed226SJulian Elischer goto out;
1527878ed226SJulian Elischer }
1528878ed226SJulian Elischer
1529878ed226SJulian Elischer if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1530878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
1531878ed226SJulian Elischer error = EIO;
1532878ed226SJulian Elischer goto out;
1533878ed226SJulian Elischer }
1534878ed226SJulian Elischer
1535878ed226SJulian Elischer /* Create L2CAP command packet */
1536878ed226SJulian Elischer _ng_l2cap_echo_req(cmd->aux, cmd->ident,
1537878ed226SJulian Elischer msg->data + sizeof(*ip), ip->echo_size);
1538878ed226SJulian Elischer if (cmd->aux == NULL) {
1539878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
1540878ed226SJulian Elischer error = ENOBUFS;
1541878ed226SJulian Elischer goto out;
1542878ed226SJulian Elischer }
1543878ed226SJulian Elischer
1544878ed226SJulian Elischer /* Link command to the queue */
1545878ed226SJulian Elischer ng_l2cap_link_cmd(con, cmd);
1546878ed226SJulian Elischer ng_l2cap_lp_deliver(con);
1547878ed226SJulian Elischer out:
1548878ed226SJulian Elischer return (error);
1549878ed226SJulian Elischer } /* ng_l2cap_l2ca_ping_req */
1550878ed226SJulian Elischer
1551878ed226SJulian Elischer /*
1552878ed226SJulian Elischer * Send L2CA_Ping response to the upper layer protocol
1553878ed226SJulian Elischer */
1554878ed226SJulian Elischer
1555878ed226SJulian Elischer int
ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con,u_int32_t token,u_int16_t result,struct mbuf * data)1556878ed226SJulian Elischer ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result,
1557878ed226SJulian Elischer struct mbuf *data)
1558878ed226SJulian Elischer {
1559878ed226SJulian Elischer ng_l2cap_p l2cap = con->l2cap;
1560878ed226SJulian Elischer struct ng_mesg *msg = NULL;
1561878ed226SJulian Elischer ng_l2cap_l2ca_ping_op *op = NULL;
1562878ed226SJulian Elischer int error = 0, size = 0;
1563878ed226SJulian Elischer
1564878ed226SJulian Elischer /* Check if control hook is connected and valid */
1565878ed226SJulian Elischer if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
1566878ed226SJulian Elischer NG_L2CAP_WARN(
1567878ed226SJulian Elischer "%s: %s - unable to send L2CA_Ping response message. " \
1568878ed226SJulian Elischer "Hook is not connected or valid\n",
1569878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node));
1570878ed226SJulian Elischer error = ENOTCONN;
1571878ed226SJulian Elischer goto out;
1572878ed226SJulian Elischer }
1573878ed226SJulian Elischer
1574878ed226SJulian Elischer size = (data == NULL)? 0 : data->m_pkthdr.len;
1575878ed226SJulian Elischer
1576878ed226SJulian Elischer /* Create and send L2CA_Ping response message */
1577878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_PING,
1578878ed226SJulian Elischer sizeof(*op) + size, M_NOWAIT);
1579878ed226SJulian Elischer if (msg == NULL)
1580878ed226SJulian Elischer error = ENOMEM;
1581878ed226SJulian Elischer else {
1582878ed226SJulian Elischer msg->header.token = token;
1583878ed226SJulian Elischer msg->header.flags |= NGF_RESP;
1584878ed226SJulian Elischer
1585878ed226SJulian Elischer op = (ng_l2cap_l2ca_ping_op *)(msg->data);
1586878ed226SJulian Elischer op->result = result;
1587878ed226SJulian Elischer bcopy(&con->remote, &op->bdaddr, sizeof(op->bdaddr));
1588878ed226SJulian Elischer if (data != NULL && size > 0) {
1589878ed226SJulian Elischer op->echo_size = size;
1590878ed226SJulian Elischer m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));
1591878ed226SJulian Elischer }
1592878ed226SJulian Elischer
15934ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1594878ed226SJulian Elischer }
1595878ed226SJulian Elischer out:
1596878ed226SJulian Elischer NG_FREE_M(data);
1597878ed226SJulian Elischer
1598878ed226SJulian Elischer return (error);
1599878ed226SJulian Elischer } /* ng_l2cap_l2ca_ping_rsp */
1600878ed226SJulian Elischer
1601878ed226SJulian Elischer /*
1602878ed226SJulian Elischer * Process L2CA_GetInfo request from the upper layer protocol
1603878ed226SJulian Elischer */
1604878ed226SJulian Elischer
1605878ed226SJulian Elischer int
ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap,struct ng_mesg * msg)1606878ed226SJulian Elischer ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1607878ed226SJulian Elischer {
1608878ed226SJulian Elischer ng_l2cap_l2ca_get_info_ip *ip = NULL;
1609878ed226SJulian Elischer ng_l2cap_con_p con = NULL;
1610878ed226SJulian Elischer ng_l2cap_cmd_p cmd = NULL;
1611878ed226SJulian Elischer int error = 0;
1612878ed226SJulian Elischer
1613878ed226SJulian Elischer /* Verify message */
1614878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) {
1615878ed226SJulian Elischer NG_L2CAP_ALERT(
1616878ed226SJulian Elischer "%s: %s - invalid L2CA_GetInfo request message size, size=%d\n",
1617878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node),
1618878ed226SJulian Elischer msg->header.arglen);
1619878ed226SJulian Elischer error = EMSGSIZE;
1620878ed226SJulian Elischer goto out;
1621878ed226SJulian Elischer }
1622878ed226SJulian Elischer
1623878ed226SJulian Elischer ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
1624878ed226SJulian Elischer
1625878ed226SJulian Elischer /* Check if we have connection to the unit */
1626fbc48c2bSTakanori Watanabe con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr,ip->linktype);
1627878ed226SJulian Elischer if (con == NULL) {
1628878ed226SJulian Elischer /* Submit LP_ConnectReq to the lower layer */
1629fbc48c2bSTakanori Watanabe error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);
1630878ed226SJulian Elischer if (error != 0) {
1631878ed226SJulian Elischer NG_L2CAP_ERR(
1632878ed226SJulian Elischer "%s: %s - unable to send LP_ConnectReq message, error=%d\n",
1633878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node), error);
1634878ed226SJulian Elischer goto out;
1635878ed226SJulian Elischer }
1636878ed226SJulian Elischer
1637878ed226SJulian Elischer /* This should not fail */
1638fbc48c2bSTakanori Watanabe con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
1639878ed226SJulian Elischer KASSERT((con != NULL),
1640878ed226SJulian Elischer ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
1641878ed226SJulian Elischer }
1642878ed226SJulian Elischer
1643878ed226SJulian Elischer /* Create L2CAP command descriptor */
1644878ed226SJulian Elischer cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),
1645878ed226SJulian Elischer NG_L2CAP_INFO_REQ, msg->header.token);
1646878ed226SJulian Elischer if (cmd == NULL) {
1647878ed226SJulian Elischer error = ENOMEM;
1648878ed226SJulian Elischer goto out;
1649878ed226SJulian Elischer }
1650878ed226SJulian Elischer
1651878ed226SJulian Elischer if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1652878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
1653878ed226SJulian Elischer error = EIO;
1654878ed226SJulian Elischer goto out;
1655878ed226SJulian Elischer }
1656878ed226SJulian Elischer
1657878ed226SJulian Elischer /* Create L2CAP command packet */
1658878ed226SJulian Elischer _ng_l2cap_info_req(cmd->aux, cmd->ident, ip->info_type);
1659878ed226SJulian Elischer if (cmd->aux == NULL) {
1660878ed226SJulian Elischer ng_l2cap_free_cmd(cmd);
1661878ed226SJulian Elischer error = ENOBUFS;
1662878ed226SJulian Elischer goto out;
1663878ed226SJulian Elischer }
1664878ed226SJulian Elischer
1665878ed226SJulian Elischer /* Link command to the queue */
1666878ed226SJulian Elischer ng_l2cap_link_cmd(con, cmd);
1667878ed226SJulian Elischer ng_l2cap_lp_deliver(con);
1668878ed226SJulian Elischer out:
1669878ed226SJulian Elischer return (error);
1670878ed226SJulian Elischer } /* ng_l2cap_l2ca_get_info_req */
1671878ed226SJulian Elischer
1672878ed226SJulian Elischer /*
1673878ed226SJulian Elischer * Send L2CA_GetInfo response to the upper layer protocol
1674878ed226SJulian Elischer */
1675878ed226SJulian Elischer
1676878ed226SJulian Elischer int
ng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con,u_int32_t token,u_int16_t result,struct mbuf * data)1677878ed226SJulian Elischer ng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con, u_int32_t token,
1678878ed226SJulian Elischer u_int16_t result, struct mbuf *data)
1679878ed226SJulian Elischer {
1680878ed226SJulian Elischer ng_l2cap_p l2cap = con->l2cap;
1681878ed226SJulian Elischer struct ng_mesg *msg = NULL;
1682878ed226SJulian Elischer ng_l2cap_l2ca_get_info_op *op = NULL;
1683878ed226SJulian Elischer int error = 0, size;
1684878ed226SJulian Elischer
1685878ed226SJulian Elischer /* Check if control hook is connected and valid */
1686878ed226SJulian Elischer if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
1687878ed226SJulian Elischer NG_L2CAP_WARN(
1688878ed226SJulian Elischer "%s: %s - unable to send L2CA_GetInfo response message. " \
1689878ed226SJulian Elischer "Hook is not connected or valid\n",
1690878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node));
1691878ed226SJulian Elischer error = ENOTCONN;
1692878ed226SJulian Elischer goto out;
1693878ed226SJulian Elischer }
1694878ed226SJulian Elischer
1695878ed226SJulian Elischer size = (data == NULL)? 0 : data->m_pkthdr.len;
1696878ed226SJulian Elischer
1697878ed226SJulian Elischer /* Create and send L2CA_GetInfo response message */
1698878ed226SJulian Elischer NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_GET_INFO,
1699878ed226SJulian Elischer sizeof(*op) + size, M_NOWAIT);
1700878ed226SJulian Elischer if (msg == NULL)
1701878ed226SJulian Elischer error = ENOMEM;
1702878ed226SJulian Elischer else {
1703878ed226SJulian Elischer msg->header.token = token;
1704878ed226SJulian Elischer msg->header.flags |= NGF_RESP;
1705878ed226SJulian Elischer
1706878ed226SJulian Elischer op = (ng_l2cap_l2ca_get_info_op *)(msg->data);
1707878ed226SJulian Elischer op->result = result;
1708878ed226SJulian Elischer if (data != NULL && size > 0) {
1709878ed226SJulian Elischer op->info_size = size;
1710878ed226SJulian Elischer m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));
1711878ed226SJulian Elischer }
1712878ed226SJulian Elischer
17134ae439a3SMaksim Yevmenkin NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1714878ed226SJulian Elischer }
1715878ed226SJulian Elischer out:
1716878ed226SJulian Elischer NG_FREE_M(data);
1717878ed226SJulian Elischer
1718878ed226SJulian Elischer return (error);
1719878ed226SJulian Elischer } /* ng_l2cap_l2ca_get_info_rsp */
1720878ed226SJulian Elischer
1721878ed226SJulian Elischer /*
1722878ed226SJulian Elischer * Process L2CA_EnableCLT message from the upper layer protocol
1723878ed226SJulian Elischer * XXX convert to NGN_L2CAP_NODE_SET_FLAGS?
1724878ed226SJulian Elischer */
1725878ed226SJulian Elischer
1726878ed226SJulian Elischer int
ng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap,struct ng_mesg * msg)1727878ed226SJulian Elischer ng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg)
1728878ed226SJulian Elischer {
1729878ed226SJulian Elischer ng_l2cap_l2ca_enable_clt_ip *ip = NULL;
1730878ed226SJulian Elischer int error = 0;
1731878ed226SJulian Elischer #if 0
1732878ed226SJulian Elischer * ng_l2cap_l2ca_enable_clt_op *op = NULL;
1733878ed226SJulian Elischer * u_int16_t result;
1734878ed226SJulian Elischer * u_int32_t token;
1735878ed226SJulian Elischer #endif
1736878ed226SJulian Elischer
1737878ed226SJulian Elischer /* Check message */
1738878ed226SJulian Elischer if (msg->header.arglen != sizeof(*ip)) {
1739878ed226SJulian Elischer NG_L2CAP_ALERT(
1740878ed226SJulian Elischer "%s: %s - invalid L2CA_EnableCLT message size, size=%d\n",
1741878ed226SJulian Elischer __func__, NG_NODE_NAME(l2cap->node),
1742878ed226SJulian Elischer msg->header.arglen);
1743878ed226SJulian Elischer
1744878ed226SJulian Elischer return (EMSGSIZE);
1745878ed226SJulian Elischer }
1746878ed226SJulian Elischer
1747878ed226SJulian Elischer /* Process request */
1748878ed226SJulian Elischer ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data);
1749878ed226SJulian Elischer #if 0
1750878ed226SJulian Elischer * result = NG_L2CAP_SUCCESS;
1751878ed226SJulian Elischer #endif
1752878ed226SJulian Elischer
1753878ed226SJulian Elischer switch (ip->psm)
1754878ed226SJulian Elischer {
1755878ed226SJulian Elischer case 0:
1756878ed226SJulian Elischer /* Special case: disable/enable all PSM */
1757878ed226SJulian Elischer if (ip->enable)
1758878ed226SJulian Elischer l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED |
1759878ed226SJulian Elischer NG_L2CAP_CLT_RFCOMM_DISABLED |
1760878ed226SJulian Elischer NG_L2CAP_CLT_TCP_DISABLED);
1761878ed226SJulian Elischer else
1762878ed226SJulian Elischer l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED |
1763878ed226SJulian Elischer NG_L2CAP_CLT_RFCOMM_DISABLED |
1764878ed226SJulian Elischer NG_L2CAP_CLT_TCP_DISABLED);
1765878ed226SJulian Elischer break;
1766878ed226SJulian Elischer
1767878ed226SJulian Elischer case NG_L2CAP_PSM_SDP:
1768878ed226SJulian Elischer if (ip->enable)
1769878ed226SJulian Elischer l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED;
1770878ed226SJulian Elischer else
1771878ed226SJulian Elischer l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED;
1772878ed226SJulian Elischer break;
1773878ed226SJulian Elischer
1774878ed226SJulian Elischer case NG_L2CAP_PSM_RFCOMM:
1775878ed226SJulian Elischer if (ip->enable)
1776878ed226SJulian Elischer l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED;
1777878ed226SJulian Elischer else
1778878ed226SJulian Elischer l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED;
1779878ed226SJulian Elischer break;
1780878ed226SJulian Elischer
1781878ed226SJulian Elischer case NG_L2CAP_PSM_TCP:
1782878ed226SJulian Elischer if (ip->enable)
1783878ed226SJulian Elischer l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED;
1784878ed226SJulian Elischer else
1785878ed226SJulian Elischer l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED;
1786878ed226SJulian Elischer break;
1787878ed226SJulian Elischer
1788878ed226SJulian Elischer default:
1789878ed226SJulian Elischer NG_L2CAP_ERR(
1790878ed226SJulian Elischer "%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm);
1791878ed226SJulian Elischer #if 0
1792878ed226SJulian Elischer * result = NG_L2CAP_PSM_NOT_SUPPORTED;
1793878ed226SJulian Elischer #endif
1794878ed226SJulian Elischer error = ENOTSUP;
1795878ed226SJulian Elischer break;
1796878ed226SJulian Elischer }
1797878ed226SJulian Elischer
1798878ed226SJulian Elischer #if 0
1799878ed226SJulian Elischer * /* Create and send response message */
1800878ed226SJulian Elischer * token = msg->header.token;
1801878ed226SJulian Elischer * NG_FREE_MSG(msg);
1802878ed226SJulian Elischer * NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT,
1803878ed226SJulian Elischer * sizeof(*op), M_NOWAIT);
1804878ed226SJulian Elischer * if (msg == NULL)
1805878ed226SJulian Elischer * error = ENOMEM;
1806878ed226SJulian Elischer * else {
1807878ed226SJulian Elischer * msg->header.token = token;
1808878ed226SJulian Elischer * msg->header.flags |= NGF_RESP;
1809878ed226SJulian Elischer *
1810878ed226SJulian Elischer * op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data);
1811878ed226SJulian Elischer * op->result = result;
1812878ed226SJulian Elischer * }
1813878ed226SJulian Elischer *
1814878ed226SJulian Elischer * /* Send response to control hook */
1815878ed226SJulian Elischer * if (l2cap->ctl != NULL && NG_HOOK_IS_VALID(l2cap->ctl))
18164ae439a3SMaksim Yevmenkin * NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1817878ed226SJulian Elischer #endif
1818878ed226SJulian Elischer
1819878ed226SJulian Elischer return (error);
1820878ed226SJulian Elischer } /* ng_l2cap_l2ca_enable_clt */
1821