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