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