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