]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netgraph/bluetooth/l2cap/ng_l2cap_ulpi.c
net: clean up empty lines in .c and .h files
[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         if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
1237                 /* Don't send Disconnect request on L2CAP Layer*/
1238                 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
1239                         ip->lcid);
1240                 
1241                 if(ch != NULL){
1242                         ng_l2cap_free_chan(ch);
1243                 }else{
1244                 NG_L2CAP_ERR(
1245 "%s: %s - unexpected L2CA_Disconnect request message. " \
1246 "Channel does not exist, conhandle=%d\n",
1247                         __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1248                         error = EINVAL;
1249                 }
1250                 goto out;
1251         }else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
1252                 /* Don't send Disconnect request on L2CAP Layer*/
1253                 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
1254                         ip->lcid);
1255                 
1256                 if(ch != NULL){
1257                         ng_l2cap_free_chan(ch);
1258                 }else{
1259                 NG_L2CAP_ERR(
1260 "%s: %s - unexpected L2CA_Disconnect request message. " \
1261 "Channel does not exist, conhandle=%d\n",
1262                         __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1263                         error = EINVAL;
1264                 }
1265                 goto out;
1266         }else{
1267                 /* Check if we have this channel */
1268                 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, ip->idtype);
1269         }
1270         if (ch == NULL) {
1271                 NG_L2CAP_ERR(
1272 "%s: %s - unexpected L2CA_Disconnect request message. " \
1273 "Channel does not exist, lcid=%d\n",
1274                         __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1275                 error = ENOENT;
1276                 goto out;
1277         }
1278
1279         /* Check channel state */
1280         if (ch->state != NG_L2CAP_CONFIG && ch->state != NG_L2CAP_OPEN && 
1281             ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) {
1282                 NG_L2CAP_ERR(
1283 "%s: %s - unexpected L2CA_Disconnect request message. " \
1284 "Invalid channel state, state=%d, lcid=%d\n", 
1285                         __func__, NG_NODE_NAME(l2cap->node), ch->state,
1286                         ch->scid);
1287                 error = EINVAL;
1288                 goto out;
1289         }
1290
1291         /* Create and send L2CAP_DisconReq message */
1292         cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con),
1293                         NG_L2CAP_DISCON_REQ, msg->header.token);
1294         if (cmd == NULL) {
1295                 ng_l2cap_free_chan(ch);
1296                 error = ENOMEM;
1297                 goto out;
1298         }
1299
1300         if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1301                 ng_l2cap_free_chan(ch);
1302                 ng_l2cap_free_cmd(cmd);
1303                 error = EIO;
1304                 goto out;
1305         }
1306
1307         _ng_l2cap_discon_req(cmd->aux, cmd->ident, ch->dcid, ch->scid);
1308         if (cmd->aux == NULL) {
1309                 ng_l2cap_free_chan(ch);
1310                 ng_l2cap_free_cmd(cmd);
1311                 error = ENOBUFS;
1312                 goto out;
1313         }
1314
1315         ch->state = NG_L2CAP_W4_L2CAP_DISCON_RSP;
1316
1317         /* Link command to the queue */
1318         ng_l2cap_link_cmd(ch->con, cmd);
1319         ng_l2cap_lp_deliver(ch->con);
1320 out:
1321         return (error);
1322 } /* ng_l2cap_l2ca_discon_req */
1323
1324 /*
1325  * Send L2CA_Disconnect response to the upper layer protocol
1326  */
1327
1328 int
1329 ng_l2cap_l2ca_discon_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
1330 {
1331         ng_l2cap_p               l2cap = ch->con->l2cap;
1332         struct ng_mesg          *msg = NULL;
1333         ng_l2cap_l2ca_discon_op *op = NULL;
1334         int                      error = 0;
1335
1336         /* Check if upstream hook is connected and valid */
1337         if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1338                 NG_L2CAP_ERR(
1339 "%s: %s - unable to send L2CA_Disconnect response message. " \
1340 "Hook is not connected or valid, psm=%d\n",
1341                         __func__, NG_NODE_NAME(l2cap->node), ch->psm);
1342
1343                 return (ENOTCONN);
1344         }
1345
1346         /* Create and send L2CA_Disconnect response message */
1347         NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON,
1348                 sizeof(*op), M_NOWAIT);
1349         if (msg == NULL)
1350                 error = ENOMEM;
1351         else {
1352                 msg->header.token = token;
1353                 msg->header.flags |= NGF_RESP;
1354
1355                 op = (ng_l2cap_l2ca_discon_op *)(msg->data);
1356                 op->result = result;
1357
1358                 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1359         }
1360
1361         return (error);
1362 } /* ng_l2cap_l2ca_discon_rsp */
1363
1364 /*
1365  * Send L2CA_DisconnectInd message to the upper layer protocol.
1366  */
1367
1368 int
1369 ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch)
1370 {
1371         ng_l2cap_p                       l2cap = ch->con->l2cap;
1372         struct ng_mesg                  *msg = NULL;
1373         ng_l2cap_l2ca_discon_ind_ip     *ip = NULL;
1374         int                              error = 0;
1375
1376         /* Check if upstream hook is connected and valid */
1377         if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1378                 NG_L2CAP_ERR(
1379 "%s: %s - unable to send L2CA_DisconnectInd message. " \
1380 "Hook is not connected or valid, psm=%d\n",
1381                         __func__, NG_NODE_NAME(l2cap->node), ch->psm);
1382
1383                 return (ENOTCONN);
1384         }
1385
1386         /* Create and send L2CA_DisconnectInd message */
1387         NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND,
1388                 sizeof(*ip), M_NOWAIT);
1389         if (msg == NULL)
1390                 error = ENOMEM;
1391         else {
1392                 ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data);
1393                 ip->idtype = ch->idtype;
1394                 if(ch->idtype == NG_L2CAP_L2CA_IDTYPE_ATT||
1395                    ch->idtype == NG_L2CAP_L2CA_IDTYPE_SMP)
1396                         ip->lcid = ch->con->con_handle;
1397                 else
1398                         ip->lcid = ch->scid;
1399                 
1400                 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1401         } 
1402
1403         return (error);
1404 } /* ng_l2cap_l2ca_discon_ind */
1405
1406 /*
1407  * Process L2CA_GroupCreate request from the upper layer protocol.
1408  * XXX FIXME
1409  */
1410
1411 int
1412 ng_l2cap_l2ca_grp_create(ng_l2cap_p l2cap, struct ng_mesg *msg)
1413 {
1414         return (ENOTSUP);
1415 } /* ng_l2cap_l2ca_grp_create */
1416
1417 /*
1418  * Process L2CA_GroupClose request from the upper layer protocol
1419  * XXX FIXME
1420  */
1421
1422 int
1423 ng_l2cap_l2ca_grp_close(ng_l2cap_p l2cap, struct ng_mesg *msg)
1424 {
1425         return (ENOTSUP);
1426 } /* ng_l2cap_l2ca_grp_close */
1427
1428 /*
1429  * Process L2CA_GroupAddMember request from the upper layer protocol.
1430  * XXX FIXME
1431  */
1432
1433 int
1434 ng_l2cap_l2ca_grp_add_member_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1435 {
1436         return (ENOTSUP);
1437 } /* ng_l2cap_l2ca_grp_add_member_req */
1438
1439 /*
1440  * Send L2CA_GroupAddMember response to the upper layer protocol.
1441  * XXX FIXME
1442  */
1443
1444 int
1445 ng_l2cap_l2ca_grp_add_member_rsp(ng_l2cap_chan_p ch, u_int32_t token,
1446                 u_int16_t result)
1447 {
1448         return (0);
1449 } /* ng_l2cap_l2ca_grp_add_member_rsp */
1450
1451 /*
1452  * Process L2CA_GroupDeleteMember request from the upper layer protocol
1453  * XXX FIXME
1454  */
1455
1456 int
1457 ng_l2cap_l2ca_grp_rem_member(ng_l2cap_p l2cap, struct ng_mesg *msg)
1458 {
1459         return (ENOTSUP);
1460 } /* ng_l2cap_l2ca_grp_rem_member */
1461
1462 /*
1463  * Process L2CA_GroupGetMembers request from the upper layer protocol
1464  * XXX FIXME
1465  */
1466
1467 int
1468 ng_l2cap_l2ca_grp_get_members(ng_l2cap_p l2cap, struct ng_mesg *msg)
1469 {
1470         return (ENOTSUP);
1471 } /* ng_l2cap_l2ca_grp_get_members */
1472
1473 /*
1474  * Process L2CA_Ping request from the upper layer protocol
1475  */
1476
1477 int
1478 ng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1479 {
1480         ng_l2cap_l2ca_ping_ip   *ip = NULL;
1481         ng_l2cap_con_p           con = NULL;
1482         ng_l2cap_cmd_p           cmd = NULL;
1483         int                      error = 0;
1484
1485         /* Verify message */
1486         if (msg->header.arglen < sizeof(*ip)) {
1487                 NG_L2CAP_ALERT(
1488 "%s: %s - invalid L2CA_Ping request message size, size=%d\n",
1489                         __func__, NG_NODE_NAME(l2cap->node),
1490                         msg->header.arglen);
1491                 error = EMSGSIZE;
1492                 goto out;
1493         }
1494
1495         ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);
1496         if (ip->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
1497                 NG_L2CAP_WARN(
1498 "%s: %s - invalid L2CA_Ping request. Echo size is too big, echo_size=%d\n",
1499                         __func__, NG_NODE_NAME(l2cap->node), ip->echo_size);
1500                 error = EMSGSIZE;
1501                 goto out;
1502         }
1503
1504         /* Check if we have connection to the unit */
1505         con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1506         if (con == NULL) {
1507                 /* Submit LP_ConnectReq to the lower layer */
1508           error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1509                 if (error != 0) {
1510                         NG_L2CAP_ERR(
1511 "%s: %s - unable to send LP_ConnectReq message, error=%d\n",
1512                                 __func__, NG_NODE_NAME(l2cap->node), error);
1513                         goto out;
1514                 }
1515
1516                 /* This should not fail */
1517                 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1518                 KASSERT((con != NULL),
1519 ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
1520         }
1521
1522         /* Create L2CAP command descriptor */
1523         cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),
1524                         NG_L2CAP_ECHO_REQ, msg->header.token);
1525         if (cmd == NULL) {
1526                 error = ENOMEM;
1527                 goto out;
1528         }
1529
1530         if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1531                 ng_l2cap_free_cmd(cmd);
1532                 error = EIO;
1533                 goto out;
1534         }
1535
1536         /* Create L2CAP command packet */
1537         _ng_l2cap_echo_req(cmd->aux, cmd->ident, 
1538                         msg->data + sizeof(*ip), ip->echo_size);
1539         if (cmd->aux == NULL) {
1540                 ng_l2cap_free_cmd(cmd);
1541                 error = ENOBUFS;
1542                 goto out;
1543         }
1544
1545         /* Link command to the queue */
1546         ng_l2cap_link_cmd(con, cmd);
1547         ng_l2cap_lp_deliver(con);
1548 out:
1549         return (error);
1550 } /* ng_l2cap_l2ca_ping_req */
1551
1552 /*
1553  * Send L2CA_Ping response to the upper layer protocol
1554  */
1555
1556 int
1557 ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result,
1558                 struct mbuf *data)
1559 {
1560         ng_l2cap_p               l2cap = con->l2cap;
1561         struct ng_mesg          *msg = NULL;
1562         ng_l2cap_l2ca_ping_op   *op = NULL;
1563         int                      error = 0, size = 0;
1564
1565         /* Check if control hook is connected and valid */
1566         if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
1567                 NG_L2CAP_WARN(
1568 "%s: %s - unable to send L2CA_Ping response message. " \
1569 "Hook is not connected or valid\n",
1570                         __func__, NG_NODE_NAME(l2cap->node));
1571                 error = ENOTCONN;
1572                 goto out;
1573         }
1574
1575         size = (data == NULL)? 0 : data->m_pkthdr.len;
1576
1577         /* Create and send L2CA_Ping response message */
1578         NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_PING,
1579                 sizeof(*op) + size, M_NOWAIT);
1580         if (msg == NULL)
1581                 error = ENOMEM;
1582         else {
1583                 msg->header.token = token;
1584                 msg->header.flags |= NGF_RESP;
1585
1586                 op = (ng_l2cap_l2ca_ping_op *)(msg->data);
1587                 op->result = result;
1588                 bcopy(&con->remote, &op->bdaddr, sizeof(op->bdaddr));
1589                 if (data != NULL && size > 0) {
1590                         op->echo_size = size;
1591                         m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));
1592                 }
1593
1594                 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1595         }
1596 out:
1597         NG_FREE_M(data);
1598
1599         return (error);
1600 } /* ng_l2cap_l2ca_ping_rsp */
1601
1602 /*
1603  * Process L2CA_GetInfo request from the upper layer protocol
1604  */
1605
1606 int
1607 ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1608 {
1609         ng_l2cap_l2ca_get_info_ip       *ip = NULL;
1610         ng_l2cap_con_p                   con = NULL;
1611         ng_l2cap_cmd_p                   cmd = NULL;
1612         int                              error = 0;
1613
1614         /* Verify message */
1615         if (msg->header.arglen != sizeof(*ip)) {
1616                 NG_L2CAP_ALERT(
1617 "%s: %s - invalid L2CA_GetInfo request message size, size=%d\n",
1618                         __func__, NG_NODE_NAME(l2cap->node),
1619                         msg->header.arglen);
1620                 error = EMSGSIZE;
1621                 goto out;
1622         }
1623
1624         ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
1625
1626         /* Check if we have connection to the unit */
1627         con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr,ip->linktype);
1628         if (con == NULL) {
1629                 /* Submit LP_ConnectReq to the lower layer */
1630                 error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);
1631                 if (error != 0) {
1632                         NG_L2CAP_ERR(
1633 "%s: %s - unable to send LP_ConnectReq message, error=%d\n",
1634                                 __func__, NG_NODE_NAME(l2cap->node), error);
1635                         goto out;
1636                 }
1637
1638                 /* This should not fail */
1639                 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
1640                 KASSERT((con != NULL),
1641 ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
1642         }
1643
1644         /* Create L2CAP command descriptor */
1645         cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),
1646                         NG_L2CAP_INFO_REQ, msg->header.token);
1647         if (cmd == NULL) {
1648                 error = ENOMEM;
1649                 goto out;
1650         }
1651
1652         if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1653                 ng_l2cap_free_cmd(cmd);
1654                 error = EIO;
1655                 goto out;
1656         }
1657
1658         /* Create L2CAP command packet */
1659         _ng_l2cap_info_req(cmd->aux, cmd->ident, ip->info_type);
1660         if (cmd->aux == NULL) {
1661                 ng_l2cap_free_cmd(cmd);
1662                 error = ENOBUFS;
1663                 goto out;
1664         }
1665
1666         /* Link command to the queue */
1667         ng_l2cap_link_cmd(con, cmd);
1668         ng_l2cap_lp_deliver(con);
1669 out:
1670         return (error);
1671 } /* ng_l2cap_l2ca_get_info_req */
1672
1673 /*
1674  * Send L2CA_GetInfo response to the upper layer protocol
1675  */
1676
1677 int
1678 ng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con, u_int32_t token, 
1679                 u_int16_t result, struct mbuf *data)
1680 {
1681         ng_l2cap_p                       l2cap = con->l2cap;
1682         struct ng_mesg                  *msg = NULL;
1683         ng_l2cap_l2ca_get_info_op       *op = NULL;
1684         int                              error = 0, size;
1685
1686         /* Check if control hook is connected and valid */
1687         if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
1688                 NG_L2CAP_WARN(
1689 "%s: %s - unable to send L2CA_GetInfo response message. " \
1690 "Hook is not connected or valid\n",
1691                         __func__, NG_NODE_NAME(l2cap->node));
1692                 error = ENOTCONN;
1693                 goto out;
1694         }
1695
1696         size = (data == NULL)? 0 : data->m_pkthdr.len;
1697
1698         /* Create and send L2CA_GetInfo response message */
1699         NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_GET_INFO,
1700                 sizeof(*op) + size, M_NOWAIT);
1701         if (msg == NULL)
1702                 error = ENOMEM;
1703         else {
1704                 msg->header.token = token;
1705                 msg->header.flags |= NGF_RESP;
1706
1707                 op = (ng_l2cap_l2ca_get_info_op *)(msg->data);
1708                 op->result = result;
1709                 if (data != NULL && size > 0) {
1710                         op->info_size = size;
1711                         m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));
1712                 }
1713
1714                 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1715         }
1716 out:
1717         NG_FREE_M(data);
1718
1719         return (error);
1720 } /* ng_l2cap_l2ca_get_info_rsp */
1721
1722 /*
1723  * Process L2CA_EnableCLT message from the upper layer protocol
1724  * XXX convert to NGN_L2CAP_NODE_SET_FLAGS?
1725  */
1726
1727 int
1728 ng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg)
1729 {
1730         ng_l2cap_l2ca_enable_clt_ip     *ip = NULL;
1731         int                              error = 0;
1732 #if 0
1733  *      ng_l2cap_l2ca_enable_clt_op     *op = NULL;
1734  *      u_int16_t                        result; 
1735  *      u_int32_t                        token;
1736 #endif
1737
1738         /* Check message */
1739         if (msg->header.arglen != sizeof(*ip)) {
1740                 NG_L2CAP_ALERT(
1741 "%s: %s - invalid L2CA_EnableCLT message size, size=%d\n",
1742                         __func__, NG_NODE_NAME(l2cap->node),
1743                         msg->header.arglen);
1744
1745                 return (EMSGSIZE);
1746         }
1747
1748         /* Process request */
1749         ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data);
1750 #if 0
1751  *      result = NG_L2CAP_SUCCESS;
1752 #endif
1753
1754         switch (ip->psm) 
1755         {
1756         case 0:
1757                 /* Special case: disable/enable all PSM */
1758                 if (ip->enable)
1759                         l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED    |
1760                                           NG_L2CAP_CLT_RFCOMM_DISABLED |
1761                                           NG_L2CAP_CLT_TCP_DISABLED);
1762                 else
1763                         l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED    |
1764                                          NG_L2CAP_CLT_RFCOMM_DISABLED |
1765                                          NG_L2CAP_CLT_TCP_DISABLED);
1766                 break;
1767
1768         case NG_L2CAP_PSM_SDP:
1769                 if (ip->enable)
1770                         l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED;
1771                 else
1772                         l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED;
1773                 break;
1774
1775         case NG_L2CAP_PSM_RFCOMM:
1776                 if (ip->enable)
1777                         l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED;
1778                 else
1779                         l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED;
1780                 break;
1781
1782         case NG_L2CAP_PSM_TCP:
1783                 if (ip->enable)
1784                         l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED;
1785                 else
1786                         l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED;
1787                 break;
1788
1789         default:
1790                 NG_L2CAP_ERR(
1791 "%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm);
1792 #if 0
1793  *              result = NG_L2CAP_PSM_NOT_SUPPORTED;
1794 #endif
1795                 error = ENOTSUP;
1796                 break;
1797         }
1798
1799 #if 0
1800  *      /* Create and send response message */
1801  *      token = msg->header.token;
1802  *      NG_FREE_MSG(msg);
1803  *      NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT,
1804  *              sizeof(*op), M_NOWAIT);
1805  *      if (msg == NULL)
1806  *              error = ENOMEM;
1807  *      else {
1808  *              msg->header.token = token;
1809  *              msg->header.flags |= NGF_RESP;
1810  * 
1811  *              op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data);
1812  *              op->result = result;
1813  *      }
1814  * 
1815  *      /* Send response to control hook */
1816  *      if (l2cap->ctl != NULL && NG_HOOK_IS_VALID(l2cap->ctl))
1817  *              NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1818 #endif
1819
1820         return (error);
1821 } /* ng_l2cap_l2ca_enable_clt */