FreeBSD kernel netgraph code
ng_l2cap_evnt.c
Go to the documentation of this file.
1/*
2 * ng_l2cap_evnt.c
3 */
4
5/*-
6 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
7 *
8 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $Id: ng_l2cap_evnt.c,v 1.5 2003/09/08 19:11:45 max Exp $
33 * $FreeBSD$
34 */
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/kernel.h>
39#include <sys/endian.h>
40#include <sys/malloc.h>
41#include <sys/mbuf.h>
42#include <sys/queue.h>
43#include <netgraph/ng_message.h>
44#include <netgraph/netgraph.h>
54
55/******************************************************************************
56 ******************************************************************************
57 ** L2CAP events processing module
58 ******************************************************************************
59 ******************************************************************************/
60
63static int ng_l2cap_process_cmd_rej (ng_l2cap_con_p, u_int8_t);
66static int ng_l2cap_process_con_req (ng_l2cap_con_p, u_int8_t);
67static int ng_l2cap_process_con_rsp (ng_l2cap_con_p, u_int8_t);
68static int ng_l2cap_process_cfg_req (ng_l2cap_con_p, u_int8_t);
69static int ng_l2cap_process_cfg_rsp (ng_l2cap_con_p, u_int8_t);
70static int ng_l2cap_process_discon_req (ng_l2cap_con_p, u_int8_t);
71static int ng_l2cap_process_discon_rsp (ng_l2cap_con_p, u_int8_t);
72static int ng_l2cap_process_echo_req (ng_l2cap_con_p, u_int8_t);
73static int ng_l2cap_process_echo_rsp (ng_l2cap_con_p, u_int8_t);
74static int ng_l2cap_process_info_req (ng_l2cap_con_p, u_int8_t);
75static int ng_l2cap_process_info_rsp (ng_l2cap_con_p, u_int8_t);
76static int send_l2cap_reject
77 (ng_l2cap_con_p, u_int8_t, u_int16_t, u_int16_t, u_int16_t, u_int16_t);
78static int send_l2cap_con_rej
79 (ng_l2cap_con_p, u_int8_t, u_int16_t, u_int16_t, u_int16_t);
80static int send_l2cap_cfg_rsp
81 (ng_l2cap_con_p, u_int8_t, u_int16_t, u_int16_t, struct mbuf *);
82static int send_l2cap_param_urs
83 (ng_l2cap_con_p , u_int8_t , u_int16_t);
84
85static int get_next_l2cap_opt
86 (struct mbuf *, int *, ng_l2cap_cfg_opt_p, ng_l2cap_cfg_opt_val_p);
87
88/*
89 * Receive L2CAP packet. First get L2CAP header and verify packet. Than
90 * get destination channel and process packet.
91 */
92
93int
95{
96 ng_l2cap_p l2cap = con->l2cap;
97 ng_l2cap_hdr_t *hdr = NULL;
98 int error = 0;
99
100 /* Check packet */
101 if (con->rx_pkt->m_pkthdr.len < sizeof(*hdr)) {
103"%s: %s - invalid L2CAP packet. Packet too small, len=%d\n",
104 __func__, NG_NODE_NAME(l2cap->node),
105 con->rx_pkt->m_pkthdr.len);
106 error = EMSGSIZE;
107 goto drop;
108 }
109
110 /* Get L2CAP header */
111 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
112 if (con->rx_pkt == NULL)
113 return (ENOBUFS);
114
115 hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *);
116 hdr->length = le16toh(hdr->length);
117 hdr->dcid = le16toh(hdr->dcid);
118
119 /* Check payload size */
120 if (hdr->length != con->rx_pkt->m_pkthdr.len - sizeof(*hdr)) {
122"%s: %s - invalid L2CAP packet. Payload length mismatch, length=%d, len=%zd\n",
123 __func__, NG_NODE_NAME(l2cap->node), hdr->length,
124 con->rx_pkt->m_pkthdr.len - sizeof(*hdr));
125 error = EMSGSIZE;
126 goto drop;
127 }
128
129 /* Process packet */
130 switch (hdr->dcid) {
131 case NG_L2CAP_SIGNAL_CID: /* L2CAP command */
132 m_adj(con->rx_pkt, sizeof(*hdr));
133 error = ng_l2cap_process_signal_cmd(con);
134 break;
136 m_adj(con->rx_pkt, sizeof(*hdr));
138 break;
139 case NG_L2CAP_CLT_CID: /* Connectionless packet */
140 error = ng_l2cap_l2ca_clt_receive(con);
141 break;
142
143 default: /* Data packet */
144 error = ng_l2cap_l2ca_receive(con);
145 break;
146 }
147
148 return (error);
149drop:
150 NG_FREE_M(con->rx_pkt);
151
152 return (error);
153} /* ng_l2cap_receive */
154
155/*
156 * Process L2CAP signaling command. We already know that destination channel ID
157 * is 0x1 that means we have received signaling command from peer's L2CAP layer.
158 * So get command header, decode and process it.
159 *
160 * XXX do we need to check signaling MTU here?
161 */
162
163static int
165{
166 ng_l2cap_p l2cap = con->l2cap;
167 ng_l2cap_cmd_hdr_t *hdr = NULL;
168 struct mbuf *m = NULL;
169
170 while (con->rx_pkt != NULL) {
171 /* Verify packet length */
172 if (con->rx_pkt->m_pkthdr.len < sizeof(*hdr)) {
174"%s: %s - invalid L2CAP signaling command. Packet too small, len=%d\n",
175 __func__, NG_NODE_NAME(l2cap->node),
176 con->rx_pkt->m_pkthdr.len);
177 NG_FREE_M(con->rx_pkt);
178
179 return (EMSGSIZE);
180 }
181
182 /* Get signaling command */
183 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
184 if (con->rx_pkt == NULL)
185 return (ENOBUFS);
186
187 hdr = mtod(con->rx_pkt, ng_l2cap_cmd_hdr_t *);
188 hdr->length = le16toh(hdr->length);
189 m_adj(con->rx_pkt, sizeof(*hdr));
190
191 /* Verify command length */
192 if (con->rx_pkt->m_pkthdr.len < hdr->length) {
194"%s: %s - invalid L2CAP signaling command, code=%#x, ident=%d. " \
195"Invalid command length=%d, m_pkthdr.len=%d\n",
196 __func__, NG_NODE_NAME(l2cap->node),
197 hdr->code, hdr->ident, hdr->length,
198 con->rx_pkt->m_pkthdr.len);
199 NG_FREE_M(con->rx_pkt);
200
201 return (EMSGSIZE);
202 }
203
204 /* Get the command, save the rest (if any) */
205 if (con->rx_pkt->m_pkthdr.len > hdr->length)
206 m = m_split(con->rx_pkt, hdr->length, M_NOWAIT);
207 else
208 m = NULL;
209
210 /* Process command */
211 switch (hdr->code) {
212 case NG_L2CAP_CMD_REJ:
214 break;
215
216 case NG_L2CAP_CON_REQ:
218 break;
219
220 case NG_L2CAP_CON_RSP:
222 break;
223
224 case NG_L2CAP_CFG_REQ:
226 break;
227
228 case NG_L2CAP_CFG_RSP:
230 break;
231
234 break;
235
238 break;
239
242 break;
243
246 break;
247
250 break;
251
254 break;
255
256 default:
258"%s: %s - unknown L2CAP signaling command, code=%#x, ident=%d, length=%d\n",
259 __func__, NG_NODE_NAME(l2cap->node),
260 hdr->code, hdr->ident, hdr->length);
261
262 /*
263 * Send L2CAP_CommandRej. Do not really care
264 * about the result
265 */
266
267 send_l2cap_reject(con, hdr->ident,
269 NG_FREE_M(con->rx_pkt);
270 break;
271 }
272
273 con->rx_pkt = m;
274 }
275
276 return (0);
277} /* ng_l2cap_process_signal_cmd */
278static int
280{
281 ng_l2cap_p l2cap = con->l2cap;
282 ng_l2cap_cmd_hdr_t *hdr = NULL;
283 struct mbuf *m = NULL;
284
285 while (con->rx_pkt != NULL) {
286 /* Verify packet length */
287 if (con->rx_pkt->m_pkthdr.len < sizeof(*hdr)) {
289"%s: %s - invalid L2CAP signaling command. Packet too small, len=%d\n",
290 __func__, NG_NODE_NAME(l2cap->node),
291 con->rx_pkt->m_pkthdr.len);
292 NG_FREE_M(con->rx_pkt);
293
294 return (EMSGSIZE);
295 }
296
297 /* Get signaling command */
298 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
299 if (con->rx_pkt == NULL)
300 return (ENOBUFS);
301
302 hdr = mtod(con->rx_pkt, ng_l2cap_cmd_hdr_t *);
303 hdr->length = le16toh(hdr->length);
304 m_adj(con->rx_pkt, sizeof(*hdr));
305
306 /* Verify command length */
307 if (con->rx_pkt->m_pkthdr.len < hdr->length) {
309"%s: %s - invalid L2CAP signaling command, code=%#x, ident=%d. " \
310"Invalid command length=%d, m_pkthdr.len=%d\n",
311 __func__, NG_NODE_NAME(l2cap->node),
312 hdr->code, hdr->ident, hdr->length,
313 con->rx_pkt->m_pkthdr.len);
314 NG_FREE_M(con->rx_pkt);
315
316 return (EMSGSIZE);
317 }
318
319 /* Get the command, save the rest (if any) */
320 if (con->rx_pkt->m_pkthdr.len > hdr->length)
321 m = m_split(con->rx_pkt, hdr->length, M_NOWAIT);
322 else
323 m = NULL;
324
325 /* Process command */
326 switch (hdr->code) {
327 case NG_L2CAP_CMD_REJ:
329 break;
332 break;
335 break;
336
337
338 default:
340"%s: %s - unknown L2CAP signaling command, code=%#x, ident=%d, length=%d\n",
341 __func__, NG_NODE_NAME(l2cap->node),
342 hdr->code, hdr->ident, hdr->length);
343
344 /*
345 * Send L2CAP_CommandRej. Do not really care
346 * about the result
347 */
348
349 send_l2cap_reject(con, hdr->ident,
351 NG_FREE_M(con->rx_pkt);
352 break;
353 }
354
355 con->rx_pkt = m;
356 }
357
358 return (0);
359} /* ng_l2cap_process_signal_cmd */
360/*Update Paramater Request*/
361static int ng_l2cap_process_cmd_urq(ng_l2cap_con_p con, uint8_t ident)
362{
363 /* We do not implement parameter negotiation for now. */
365 NG_FREE_M(con->rx_pkt);
366 return 0;
367}
368
369static int ng_l2cap_process_cmd_urs(ng_l2cap_con_p con, uint8_t ident)
370{
371 /* We only support master side yet .*/
372 //send_l2cap_reject(con,ident ... );
373
374 NG_FREE_M(con->rx_pkt);
375 return 0;
376}
377
378/*
379 * Process L2CAP_CommandRej command
380 */
381
382static int
384{
385 ng_l2cap_p l2cap = con->l2cap;
386 ng_l2cap_cmd_rej_cp *cp = NULL;
387 ng_l2cap_cmd_p cmd = NULL;
388
389 /* Get command parameters */
390 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*cp));
391 if (con->rx_pkt == NULL)
392 return (ENOBUFS);
393
394 cp = mtod(con->rx_pkt, ng_l2cap_cmd_rej_cp *);
395 cp->reason = le16toh(cp->reason);
396
397 /* Check if we have pending command descriptor */
398 cmd = ng_l2cap_cmd_by_ident(con, ident);
399 if (cmd != NULL) {
400 /* If command timeout already happened then ignore reject */
402 NG_FREE_M(con->rx_pkt);
403 return (ETIMEDOUT);
404 }
405
407
408 switch (cmd->code) {
409 case NG_L2CAP_CON_REQ:
410 ng_l2cap_l2ca_con_rsp(cmd->ch,cmd->token,cp->reason,0);
412 break;
413
414 case NG_L2CAP_CFG_REQ:
415 ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token, cp->reason);
416 break;
417
419 ng_l2cap_l2ca_discon_rsp(cmd->ch,cmd->token,cp->reason);
420 ng_l2cap_free_chan(cmd->ch); /* XXX free channel */
421 break;
422
424 ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
425 cp->reason, NULL);
426 break;
427
430 cp->reason, NULL);
431 break;
432
433 default:
435"%s: %s - unexpected L2CAP_CommandRej. Unexpected L2CAP command opcode=%d\n",
436 __func__, NG_NODE_NAME(l2cap->node), cmd->code);
437 break;
438 }
439
441 } else
443"%s: %s - unexpected L2CAP_CommandRej command. " \
444"Requested ident does not exist, ident=%d\n",
445 __func__, NG_NODE_NAME(l2cap->node), ident);
446
447 NG_FREE_M(con->rx_pkt);
448
449 return (0);
450} /* ng_l2cap_process_cmd_rej */
451
452/*
453 * Process L2CAP_ConnectReq command
454 */
455
456static int
458{
459 ng_l2cap_p l2cap = con->l2cap;
460 struct mbuf *m = con->rx_pkt;
461 ng_l2cap_con_req_cp *cp = NULL;
462 ng_l2cap_chan_p ch = NULL;
463 int error = 0;
464 u_int16_t dcid, psm;
465 int idtype;
466
467 /* Get command parameters */
468 NG_L2CAP_M_PULLUP(m, sizeof(*cp));
469 if (m == NULL)
470 return (ENOBUFS);
471
472 cp = mtod(m, ng_l2cap_con_req_cp *);
473 psm = le16toh(cp->psm);
474 dcid = le16toh(cp->scid);
475
476 NG_FREE_M(m);
477 con->rx_pkt = NULL;
480 else if(dcid == NG_L2CAP_SMP_CID)
482 else if( con->linktype != NG_HCI_LINK_ACL)
484 else
486
487 /*
488 * Create new channel and send L2CA_ConnectInd notification
489 * to the upper layer protocol.
490 */
491
492 ch = ng_l2cap_new_chan(l2cap, con, psm, idtype);
493
494 if (ch == NULL)
495 return (send_l2cap_con_rej(con, ident, 0, dcid,
497
498 /* Update channel IDs */
499 ch->dcid = dcid;
500
501 /* Sent L2CA_ConnectInd notification to the upper layer */
502 ch->ident = ident;
504
505 error = ng_l2cap_l2ca_con_ind(ch);
506 if (error != 0) {
507 send_l2cap_con_rej(con, ident, ch->scid, dcid,
508 (error == ENOMEM)? NG_L2CAP_NO_RESOURCES :
511 }
512
513 return (error);
514} /* ng_l2cap_process_con_req */
515
516/*
517 * Process L2CAP_ConnectRsp command
518 */
519
520static int
522{
523 ng_l2cap_p l2cap = con->l2cap;
524 struct mbuf *m = con->rx_pkt;
525 ng_l2cap_con_rsp_cp *cp = NULL;
526 ng_l2cap_cmd_p cmd = NULL;
527 u_int16_t scid, dcid, result, status;
528 int error = 0;
529
530 /* Get command parameters */
531 NG_L2CAP_M_PULLUP(m, sizeof(*cp));
532 if (m == NULL)
533 return (ENOBUFS);
534
535 cp = mtod(m, ng_l2cap_con_rsp_cp *);
536 dcid = le16toh(cp->dcid);
537 scid = le16toh(cp->scid);
538 result = le16toh(cp->result);
539 status = le16toh(cp->status);
540
541 NG_FREE_M(m);
542 con->rx_pkt = NULL;
543
544 /* Check if we have pending command descriptor */
545 cmd = ng_l2cap_cmd_by_ident(con, ident);
546 if (cmd == NULL) {
548"%s: %s - unexpected L2CAP_ConnectRsp command. ident=%d, con_handle=%d\n",
549 __func__, NG_NODE_NAME(l2cap->node), ident,
550 con->con_handle);
551
552 return (ENOENT);
553 }
554
555 /* Verify channel state, if invalid - do nothing */
556 if (cmd->ch->state != NG_L2CAP_W4_L2CAP_CON_RSP) {
558"%s: %s - unexpected L2CAP_ConnectRsp. " \
559"Invalid channel state, cid=%d, state=%d\n",
560 __func__, NG_NODE_NAME(l2cap->node), scid,
561 cmd->ch->state);
562 goto reject;
563 }
564
565 /* Verify CIDs and send reject if does not match */
566 if (cmd->ch->scid != scid) {
568"%s: %s - unexpected L2CAP_ConnectRsp. Channel IDs do not match, scid=%d(%d)\n",
569 __func__, NG_NODE_NAME(l2cap->node), cmd->ch->scid,
570 scid);
571 goto reject;
572 }
573
574 /*
575 * Looks good. We got confirmation from our peer. Now process
576 * it. First disable RTX timer. Then check the result and send
577 * notification to the upper layer. If command timeout already
578 * happened then ignore response.
579 */
580
581 if ((error = ng_l2cap_command_untimeout(cmd)) != 0)
582 return (error);
583
584 if (result == NG_L2CAP_PENDING) {
585 /*
586 * Our peer wants more time to complete connection. We shall
587 * start ERTX timer and wait. Keep command in the list.
588 */
589
590 cmd->ch->dcid = dcid;
592
593 error = ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token,
594 result, status);
595 if (error != 0)
597 } else {
599
600 if (result == NG_L2CAP_SUCCESS) {
601 /*
602 * Channel is open. Complete command and move to CONFIG
603 * state. Since we have sent positive confirmation we
604 * expect to receive L2CA_Config request from the upper
605 * layer protocol.
606 */
607
608 cmd->ch->dcid = dcid;
609 cmd->ch->state = ((cmd->ch->scid == NG_L2CAP_ATT_CID)||
610 (cmd->ch->scid == NG_L2CAP_SMP_CID))
611 ?
613 } else
614 /* There was an error, so close the channel */
616"%s: %s - failed to open L2CAP channel, result=%d, status=%d\n",
617 __func__, NG_NODE_NAME(l2cap->node), result,
618 status);
619
620 error = ng_l2cap_l2ca_con_rsp(cmd->ch, cmd->token,
621 result, status);
622
623 /* XXX do we have to remove the channel on error? */
624 if (error != 0 || result != NG_L2CAP_SUCCESS)
626
628 }
629
630 return (error);
631
632reject:
633 /* Send reject. Do not really care about the result */
635
636 return (0);
637} /* ng_l2cap_process_con_rsp */
638
639/*
640 * Process L2CAP_ConfigReq command
641 */
642
643static int
645{
646 ng_l2cap_p l2cap = con->l2cap;
647 struct mbuf *m = con->rx_pkt;
648 ng_l2cap_cfg_req_cp *cp = NULL;
649 ng_l2cap_chan_p ch = NULL;
650 u_int16_t dcid, respond, result;
651 ng_l2cap_cfg_opt_t hdr;
653 int off, error = 0;
654
655 /* Get command parameters */
656 con->rx_pkt = NULL;
657 NG_L2CAP_M_PULLUP(m, sizeof(*cp));
658 if (m == NULL)
659 return (ENOBUFS);
660
661 cp = mtod(m, ng_l2cap_cfg_req_cp *);
662 dcid = le16toh(cp->dcid);
663 respond = NG_L2CAP_OPT_CFLAG(le16toh(cp->flags));
664 m_adj(m, sizeof(*cp));
665
666 /* Check if we have this channel and it is in valid state */
668 if (ch == NULL) {
670"%s: %s - unexpected L2CAP_ConfigReq command. " \
671"Channel does not exist, cid=%d\n",
672 __func__, NG_NODE_NAME(l2cap->node), dcid);
673 goto reject;
674 }
675
676 /* Verify channel state */
677 if (ch->state != NG_L2CAP_CONFIG && ch->state != NG_L2CAP_OPEN) {
679"%s: %s - unexpected L2CAP_ConfigReq. " \
680"Invalid channel state, cid=%d, state=%d\n",
681 __func__, NG_NODE_NAME(l2cap->node), dcid, ch->state);
682 goto reject;
683 }
684
685 if (ch->state == NG_L2CAP_OPEN) { /* Re-configuration */
686 ch->cfg_state = 0;
688 }
689
690 for (result = 0, off = 0; ; ) {
691 error = get_next_l2cap_opt(m, &off, &hdr, &val);
692 if (error == 0) { /* We done with this packet */
693 NG_FREE_M(m);
694 break;
695 } else if (error > 0) { /* Got option */
696 switch (hdr.type) {
697 case NG_L2CAP_OPT_MTU:
698 ch->omtu = val.mtu;
699 break;
700
702 ch->flush_timo = val.flush_timo;
703 break;
704
705 case NG_L2CAP_OPT_QOS:
706 bcopy(&val.flow, &ch->iflow, sizeof(ch->iflow));
707 break;
708
709 default: /* Ignore unknown hint option */
710 break;
711 }
712 } else { /* Oops, something is wrong */
713 respond = 1;
714
715 if (error == -3) {
716 /*
717 * Adjust mbuf so we can get to the start
718 * of the first option we did not like.
719 */
720
721 m_adj(m, off - sizeof(hdr));
722 m->m_pkthdr.len = sizeof(hdr) + hdr.length;
723
725 } else {
726 /* XXX FIXME Send other reject codes? */
727 NG_FREE_M(m);
728 result = NG_L2CAP_REJECT;
729 }
730
731 break;
732 }
733 }
734
735 /*
736 * Now check and see if we have to respond. If everything was OK then
737 * respond contain "C flag" and (if set) we will respond with empty
738 * packet and will wait for more options.
739 *
740 * Other case is that we did not like peer's options and will respond
741 * with L2CAP_Config response command with Reject error code.
742 *
743 * When "respond == 0" than we have received all options and we will
744 * sent L2CA_ConfigInd event to the upper layer protocol.
745 */
746
747 if (respond) {
748 error = send_l2cap_cfg_rsp(con, ident, ch->dcid, result, m);
749 if (error != 0) {
752 }
753 } else {
754 /* Send L2CA_ConfigInd event to the upper layer protocol */
755 ch->ident = ident;
756 error = ng_l2cap_l2ca_cfg_ind(ch);
757 if (error != 0)
759 }
760
761 return (error);
762
763reject:
764 /* Send reject. Do not really care about the result */
765 NG_FREE_M(m);
766
768
769 return (0);
770} /* ng_l2cap_process_cfg_req */
771
772/*
773 * Process L2CAP_ConfigRsp command
774 */
775
776static int
778{
779 ng_l2cap_p l2cap = con->l2cap;
780 struct mbuf *m = con->rx_pkt;
781 ng_l2cap_cfg_rsp_cp *cp = NULL;
782 ng_l2cap_cmd_p cmd = NULL;
783 u_int16_t scid, cflag, result;
784 ng_l2cap_cfg_opt_t hdr;
786 int off, error = 0;
787
788 /* Get command parameters */
789 con->rx_pkt = NULL;
790 NG_L2CAP_M_PULLUP(m, sizeof(*cp));
791 if (m == NULL)
792 return (ENOBUFS);
793
794 cp = mtod(m, ng_l2cap_cfg_rsp_cp *);
795 scid = le16toh(cp->scid);
796 cflag = NG_L2CAP_OPT_CFLAG(le16toh(cp->flags));
797 result = le16toh(cp->result);
798 m_adj(m, sizeof(*cp));
799
800 /* Check if we have this command */
801 cmd = ng_l2cap_cmd_by_ident(con, ident);
802 if (cmd == NULL) {
804"%s: %s - unexpected L2CAP_ConfigRsp command. ident=%d, con_handle=%d\n",
805 __func__, NG_NODE_NAME(l2cap->node), ident,
806 con->con_handle);
807 NG_FREE_M(m);
808
809 return (ENOENT);
810 }
811
812 /* Verify CIDs and send reject if does not match */
813 if (cmd->ch->scid != scid) {
815"%s: %s - unexpected L2CAP_ConfigRsp. " \
816"Channel ID does not match, scid=%d(%d)\n",
817 __func__, NG_NODE_NAME(l2cap->node), cmd->ch->scid,
818 scid);
819 goto reject;
820 }
821
822 /* Verify channel state and reject if invalid */
823 if (cmd->ch->state != NG_L2CAP_CONFIG) {
825"%s: %s - unexpected L2CAP_ConfigRsp. " \
826"Invalid channel state, scid=%d, state=%d\n",
827 __func__, NG_NODE_NAME(l2cap->node), cmd->ch->scid,
828 cmd->ch->state);
829 goto reject;
830 }
831
832 /*
833 * Looks like it is our response, so process it. First parse options,
834 * then verify C flag. If it is set then we shall expect more
835 * configuration options from the peer and we will wait. Otherwise we
836 * have received all options and we will send L2CA_ConfigRsp event to
837 * the upper layer protocol. If command timeout already happened then
838 * ignore response.
839 */
840
841 if ((error = ng_l2cap_command_untimeout(cmd)) != 0) {
842 NG_FREE_M(m);
843 return (error);
844 }
845
846 for (off = 0; ; ) {
847 error = get_next_l2cap_opt(m, &off, &hdr, &val);
848 if (error == 0) /* We done with this packet */
849 break;
850 else if (error > 0) { /* Got option */
851 switch (hdr.type) {
852 case NG_L2CAP_OPT_MTU:
853 cmd->ch->imtu = val.mtu;
854 break;
855
857 cmd->ch->flush_timo = val.flush_timo;
858 break;
859
860 case NG_L2CAP_OPT_QOS:
861 bcopy(&val.flow, &cmd->ch->oflow,
862 sizeof(cmd->ch->oflow));
863 break;
864
865 default: /* Ignore unknown hint option */
866 break;
867 }
868 } else {
869 /*
870 * XXX FIXME What to do here?
871 *
872 * This is really BAD :( options packet was broken, or
873 * peer sent us option that we did not understand. Let
874 * upper layer know and do not wait for more options.
875 */
876
878"%s: %s - failed to parse configuration options, error=%d\n",
879 __func__, NG_NODE_NAME(l2cap->node), error);
880
881 result = NG_L2CAP_UNKNOWN;
882 cflag = 0;
883
884 break;
885 }
886 }
887
888 NG_FREE_M(m);
889
890 if (cflag) /* Restart timer and wait for more options */
892 else {
894
895 /* Send L2CA_Config response to the upper layer protocol */
896 error = ng_l2cap_l2ca_cfg_rsp(cmd->ch, cmd->token, result);
897 if (error != 0) {
898 /*
899 * XXX FIXME what to do here? we were not able to send
900 * response to the upper layer protocol, so for now
901 * just close the channel. Send L2CAP_Disconnect to
902 * remote peer?
903 */
904
906"%s: %s - failed to send L2CA_Config response, error=%d\n",
907 __func__, NG_NODE_NAME(l2cap->node), error);
908
910 }
911
913 }
914
915 return (error);
916
917reject:
918 /* Send reject. Do not really care about the result */
919 NG_FREE_M(m);
920
922
923 return (0);
924} /* ng_l2cap_process_cfg_rsp */
925
926/*
927 * Process L2CAP_DisconnectReq command
928 */
929
930static int
932{
933 ng_l2cap_p l2cap = con->l2cap;
934 ng_l2cap_discon_req_cp *cp = NULL;
935 ng_l2cap_chan_p ch = NULL;
936 ng_l2cap_cmd_p cmd = NULL;
937 u_int16_t scid, dcid;
938
939 /* Get command parameters */
940 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*cp));
941 if (con->rx_pkt == NULL)
942 return (ENOBUFS);
943
944 cp = mtod(con->rx_pkt, ng_l2cap_discon_req_cp *);
945 dcid = le16toh(cp->dcid);
946 scid = le16toh(cp->scid);
947
948 NG_FREE_M(con->rx_pkt);
949
950 /* Check if we have this channel and it is in valid state */
952 if (ch == NULL) {
954"%s: %s - unexpected L2CAP_DisconnectReq message. " \
955"Channel does not exist, cid=%d\n",
956 __func__, NG_NODE_NAME(l2cap->node), dcid);
957 goto reject;
958 }
959
960 /* XXX Verify channel state and reject if invalid -- is that true? */
961 if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG &&
964"%s: %s - unexpected L2CAP_DisconnectReq. " \
965"Invalid channel state, cid=%d, state=%d\n",
966 __func__, NG_NODE_NAME(l2cap->node), dcid, ch->state);
967 goto reject;
968 }
969
970 /* Match destination channel ID */
971 if (ch->dcid != scid || ch->scid != dcid) {
973"%s: %s - unexpected L2CAP_DisconnectReq. " \
974"Channel IDs does not match, channel: scid=%d, dcid=%d, " \
975"request: scid=%d, dcid=%d\n",
976 __func__, NG_NODE_NAME(l2cap->node), ch->scid, ch->dcid,
977 scid, dcid);
978 goto reject;
979 }
980
981 /*
982 * Looks good, so notify upper layer protocol that channel is about
983 * to be disconnected and send L2CA_DisconnectInd message. Then respond
984 * with L2CAP_DisconnectRsp.
985 */
986
988 ng_l2cap_l2ca_discon_ind(ch); /* do not care about result */
990 }
991
992 /* Send L2CAP_DisconnectRsp */
993 cmd = ng_l2cap_new_cmd(con, NULL, ident, NG_L2CAP_DISCON_RSP, 0);
994 if (cmd == NULL)
995 return (ENOMEM);
996
997 _ng_l2cap_discon_rsp(cmd->aux, ident, dcid, scid);
998 if (cmd->aux == NULL) {
1000
1001 return (ENOBUFS);
1002 }
1003
1004 /* Link command to the queue */
1005 ng_l2cap_link_cmd(con, cmd);
1007
1008 return (0);
1009
1010reject:
1011 /* Send reject. Do not really care about the result */
1013
1014 return (0);
1015} /* ng_l2cap_process_discon_req */
1016
1017/*
1018 * Process L2CAP_DisconnectRsp command
1019 */
1020
1021static int
1023{
1024 ng_l2cap_p l2cap = con->l2cap;
1025 ng_l2cap_discon_rsp_cp *cp = NULL;
1026 ng_l2cap_cmd_p cmd = NULL;
1027 u_int16_t scid, dcid;
1028 int error = 0;
1029
1030 /* Get command parameters */
1031 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*cp));
1032 if (con->rx_pkt == NULL)
1033 return (ENOBUFS);
1034
1035 cp = mtod(con->rx_pkt, ng_l2cap_discon_rsp_cp *);
1036 dcid = le16toh(cp->dcid);
1037 scid = le16toh(cp->scid);
1038
1039 NG_FREE_M(con->rx_pkt);
1040
1041 /* Check if we have pending command descriptor */
1042 cmd = ng_l2cap_cmd_by_ident(con, ident);
1043 if (cmd == NULL) {
1045"%s: %s - unexpected L2CAP_DisconnectRsp command. ident=%d, con_handle=%d\n",
1046 __func__, NG_NODE_NAME(l2cap->node), ident,
1047 con->con_handle);
1048 goto out;
1049 }
1050
1051 /* Verify channel state, do nothing if invalid */
1052 if (cmd->ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) {
1054"%s: %s - unexpected L2CAP_DisconnectRsp. " \
1055"Invalid channel state, cid=%d, state=%d\n",
1056 __func__, NG_NODE_NAME(l2cap->node), scid,
1057 cmd->ch->state);
1058 goto out;
1059 }
1060
1061 /* Verify CIDs and send reject if does not match */
1062 if (cmd->ch->scid != scid || cmd->ch->dcid != dcid) {
1064"%s: %s - unexpected L2CAP_DisconnectRsp. " \
1065"Channel IDs do not match, scid=%d(%d), dcid=%d(%d)\n",
1066 __func__, NG_NODE_NAME(l2cap->node), cmd->ch->scid,
1067 scid, cmd->ch->dcid, dcid);
1068 goto out;
1069 }
1070
1071 /*
1072 * Looks like we have successfully disconnected channel, so notify
1073 * upper layer. If command timeout already happened then ignore
1074 * response.
1075 */
1076
1077 if ((error = ng_l2cap_command_untimeout(cmd)) != 0)
1078 goto out;
1079
1080 error = ng_l2cap_l2ca_discon_rsp(cmd->ch, cmd->token, NG_L2CAP_SUCCESS);
1081 ng_l2cap_free_chan(cmd->ch); /* this will free commands too */
1082out:
1083 return (error);
1084} /* ng_l2cap_process_discon_rsp */
1085
1086/*
1087 * Process L2CAP_EchoReq command
1088 */
1089
1090static int
1092{
1093 ng_l2cap_p l2cap = con->l2cap;
1094 ng_l2cap_cmd_hdr_t *hdr = NULL;
1095 ng_l2cap_cmd_p cmd = NULL;
1096
1097 con->rx_pkt = ng_l2cap_prepend(con->rx_pkt, sizeof(*hdr));
1098 if (con->rx_pkt == NULL) {
1100"%s: %s - ng_l2cap_prepend() failed, size=%zd\n",
1101 __func__, NG_NODE_NAME(l2cap->node), sizeof(*hdr));
1102
1103 return (ENOBUFS);
1104 }
1105
1106 hdr = mtod(con->rx_pkt, ng_l2cap_cmd_hdr_t *);
1107 hdr->code = NG_L2CAP_ECHO_RSP;
1108 hdr->ident = ident;
1109 hdr->length = htole16(con->rx_pkt->m_pkthdr.len - sizeof(*hdr));
1110
1111 cmd = ng_l2cap_new_cmd(con, NULL, ident, NG_L2CAP_ECHO_RSP, 0);
1112 if (cmd == NULL) {
1113 NG_FREE_M(con->rx_pkt);
1114
1115 return (ENOBUFS);
1116 }
1117
1118 /* Attach data and link command to the queue */
1119 cmd->aux = con->rx_pkt;
1120 con->rx_pkt = NULL;
1121 ng_l2cap_link_cmd(con, cmd);
1123
1124 return (0);
1125} /* ng_l2cap_process_echo_req */
1126
1127/*
1128 * Process L2CAP_EchoRsp command
1129 */
1130
1131static int
1133{
1134 ng_l2cap_p l2cap = con->l2cap;
1135 ng_l2cap_cmd_p cmd = NULL;
1136 int error = 0;
1137
1138 /* Check if we have this command */
1139 cmd = ng_l2cap_cmd_by_ident(con, ident);
1140 if (cmd != NULL) {
1141 /* If command timeout already happened then ignore response */
1142 if ((error = ng_l2cap_command_untimeout(cmd)) != 0) {
1143 NG_FREE_M(con->rx_pkt);
1144 return (error);
1145 }
1146
1148
1149 error = ng_l2cap_l2ca_ping_rsp(cmd->con, cmd->token,
1150 NG_L2CAP_SUCCESS, con->rx_pkt);
1151
1153 con->rx_pkt = NULL;
1154 } else {
1156"%s: %s - unexpected L2CAP_EchoRsp command. " \
1157"Requested ident does not exist, ident=%d\n",
1158 __func__, NG_NODE_NAME(l2cap->node), ident);
1159 NG_FREE_M(con->rx_pkt);
1160 }
1161
1162 return (error);
1163} /* ng_l2cap_process_echo_rsp */
1164
1165/*
1166 * Process L2CAP_InfoReq command
1167 */
1168
1169static int
1171{
1172 ng_l2cap_p l2cap = con->l2cap;
1173 ng_l2cap_cmd_p cmd = NULL;
1174 u_int16_t type;
1175
1176 /* Get command parameters */
1177 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(ng_l2cap_info_req_cp));
1178 if (con->rx_pkt == NULL)
1179 return (ENOBUFS);
1180
1181 type = le16toh(mtod(con->rx_pkt, ng_l2cap_info_req_cp *)->type);
1182 NG_FREE_M(con->rx_pkt);
1183
1184 cmd = ng_l2cap_new_cmd(con, NULL, ident, NG_L2CAP_INFO_RSP, 0);
1185 if (cmd == NULL)
1186 return (ENOMEM);
1187
1188 switch (type) {
1192 break;
1193
1194 default:
1195 _ng_l2cap_info_rsp(cmd->aux, ident, type,
1197 break;
1198 }
1199
1200 if (cmd->aux == NULL) {
1202
1203 return (ENOBUFS);
1204 }
1205
1206 /* Link command to the queue */
1207 ng_l2cap_link_cmd(con, cmd);
1209
1210 return (0);
1211} /* ng_l2cap_process_info_req */
1212
1213/*
1214 * Process L2CAP_InfoRsp command
1215 */
1216
1217static int
1219{
1220 ng_l2cap_p l2cap = con->l2cap;
1221 ng_l2cap_info_rsp_cp *cp = NULL;
1222 ng_l2cap_cmd_p cmd = NULL;
1223 int error = 0;
1224
1225 /* Get command parameters */
1226 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*cp));
1227 if (con->rx_pkt == NULL)
1228 return (ENOBUFS);
1229
1230 cp = mtod(con->rx_pkt, ng_l2cap_info_rsp_cp *);
1231 cp->type = le16toh(cp->type);
1232 cp->result = le16toh(cp->result);
1233 m_adj(con->rx_pkt, sizeof(*cp));
1234
1235 /* Check if we have pending command descriptor */
1236 cmd = ng_l2cap_cmd_by_ident(con, ident);
1237 if (cmd == NULL) {
1239"%s: %s - unexpected L2CAP_InfoRsp command. " \
1240"Requested ident does not exist, ident=%d\n",
1241 __func__, NG_NODE_NAME(l2cap->node), ident);
1242 NG_FREE_M(con->rx_pkt);
1243
1244 return (ENOENT);
1245 }
1246
1247 /* If command timeout already happened then ignore response */
1248 if ((error = ng_l2cap_command_untimeout(cmd)) != 0) {
1249 NG_FREE_M(con->rx_pkt);
1250 return (error);
1251 }
1252
1254
1255 if (cp->result == NG_L2CAP_SUCCESS) {
1256 switch (cp->type) {
1258 if (con->rx_pkt->m_pkthdr.len == sizeof(u_int16_t))
1259 *mtod(con->rx_pkt, u_int16_t *) =
1260 le16toh(*mtod(con->rx_pkt,u_int16_t *));
1261 else {
1262 cp->result = NG_L2CAP_UNKNOWN; /* XXX */
1263
1265"%s: %s - invalid L2CAP_InfoRsp command. " \
1266"Bad connectionless MTU parameter, len=%d\n",
1267 __func__, NG_NODE_NAME(l2cap->node),
1268 con->rx_pkt->m_pkthdr.len);
1269 }
1270 break;
1271
1272 default:
1274"%s: %s - invalid L2CAP_InfoRsp command. Unknown info type=%d\n",
1275 __func__, NG_NODE_NAME(l2cap->node), cp->type);
1276 break;
1277 }
1278 }
1279
1280 error = ng_l2cap_l2ca_get_info_rsp(cmd->con, cmd->token,
1281 cp->result, con->rx_pkt);
1282
1284 con->rx_pkt = NULL;
1285
1286 return (error);
1287} /* ng_l2cap_process_info_rsp */
1288
1289/*
1290 * Send L2CAP reject
1291 */
1292
1293static int
1294send_l2cap_reject(ng_l2cap_con_p con, u_int8_t ident, u_int16_t reason,
1295 u_int16_t mtu, u_int16_t scid, u_int16_t dcid)
1296{
1297 ng_l2cap_cmd_p cmd = NULL;
1298
1299 cmd = ng_l2cap_new_cmd(con, NULL, ident, NG_L2CAP_CMD_REJ, 0);
1300 if (cmd == NULL)
1301 return (ENOMEM);
1302
1303 _ng_l2cap_cmd_rej(cmd->aux, cmd->ident, reason, mtu, scid, dcid);
1304 if (cmd->aux == NULL) {
1306
1307 return (ENOBUFS);
1308 }
1309
1310 /* Link command to the queue */
1311 ng_l2cap_link_cmd(con, cmd);
1313
1314 return (0);
1315} /* send_l2cap_reject */
1316
1317/*
1318 * Send L2CAP connection reject
1319 */
1320
1321static int
1322send_l2cap_con_rej(ng_l2cap_con_p con, u_int8_t ident, u_int16_t scid,
1323 u_int16_t dcid, u_int16_t result)
1324{
1325 ng_l2cap_cmd_p cmd = NULL;
1326
1327 cmd = ng_l2cap_new_cmd(con, NULL, ident, NG_L2CAP_CON_RSP, 0);
1328 if (cmd == NULL)
1329 return (ENOMEM);
1330
1331 _ng_l2cap_con_rsp(cmd->aux, cmd->ident, scid, dcid, result, 0);
1332 if (cmd->aux == NULL) {
1334
1335 return (ENOBUFS);
1336 }
1337
1338 /* Link command to the queue */
1339 ng_l2cap_link_cmd(con, cmd);
1341
1342 return (0);
1343} /* send_l2cap_con_rej */
1344
1345/*
1346 * Send L2CAP config response
1347 */
1348
1349static int
1350send_l2cap_cfg_rsp(ng_l2cap_con_p con, u_int8_t ident, u_int16_t scid,
1351 u_int16_t result, struct mbuf *opt)
1352{
1353 ng_l2cap_cmd_p cmd = NULL;
1354
1355 cmd = ng_l2cap_new_cmd(con, NULL, ident, NG_L2CAP_CFG_RSP, 0);
1356 if (cmd == NULL) {
1357 NG_FREE_M(opt);
1358
1359 return (ENOMEM);
1360 }
1361
1362 _ng_l2cap_cfg_rsp(cmd->aux, cmd->ident, scid, 0, result, opt);
1363 if (cmd->aux == NULL) {
1365
1366 return (ENOBUFS);
1367 }
1368
1369 /* Link command to the queue */
1370 ng_l2cap_link_cmd(con, cmd);
1372
1373 return (0);
1374} /* send_l2cap_cfg_rsp */
1375
1376static int
1378 u_int16_t result)
1379{
1380 ng_l2cap_cmd_p cmd = NULL;
1381
1382 cmd = ng_l2cap_new_cmd(con, NULL, ident,
1384 0);
1385 if (cmd == NULL) {
1386 return (ENOMEM);
1387 }
1388
1389 _ng_l2cap_cmd_urs(cmd->aux, cmd->ident, result);
1390 if (cmd->aux == NULL) {
1392
1393 return (ENOBUFS);
1394 }
1395
1396 /* Link command to the queue */
1397 ng_l2cap_link_cmd(con, cmd);
1399
1400 return (0);
1401} /* send_l2cap_cfg_rsp */
1402
1403/*
1404 * Get next L2CAP configuration option
1405 *
1406 * Return codes:
1407 * 0 no option
1408 * 1 we have got option
1409 * -1 header too short
1410 * -2 bad option value or length
1411 * -3 unknown option
1412 */
1413
1414static int
1415get_next_l2cap_opt(struct mbuf *m, int *off, ng_l2cap_cfg_opt_p hdr,
1417{
1418 int hint, len = m->m_pkthdr.len - (*off);
1419
1420 if (len == 0)
1421 return (0);
1422 if (len < 0 || len < sizeof(*hdr))
1423 return (-1);
1424
1425 m_copydata(m, *off, sizeof(*hdr), (caddr_t) hdr);
1426 *off += sizeof(*hdr);
1427 len -= sizeof(*hdr);
1428
1429 hint = NG_L2CAP_OPT_HINT(hdr->type);
1430 hdr->type &= NG_L2CAP_OPT_HINT_MASK;
1431
1432 switch (hdr->type) {
1433 case NG_L2CAP_OPT_MTU:
1434 if (hdr->length != NG_L2CAP_OPT_MTU_SIZE || len < hdr->length)
1435 return (-2);
1436
1437 m_copydata(m, *off, NG_L2CAP_OPT_MTU_SIZE, (caddr_t) val);
1438 val->mtu = le16toh(val->mtu);
1439 *off += NG_L2CAP_OPT_MTU_SIZE;
1440 break;
1441
1443 if (hdr->length != NG_L2CAP_OPT_FLUSH_TIMO_SIZE ||
1444 len < hdr->length)
1445 return (-2);
1446
1447 m_copydata(m, *off, NG_L2CAP_OPT_FLUSH_TIMO_SIZE, (caddr_t)val);
1448 val->flush_timo = le16toh(val->flush_timo);
1450 break;
1451
1452 case NG_L2CAP_OPT_QOS:
1453 if (hdr->length != NG_L2CAP_OPT_QOS_SIZE || len < hdr->length)
1454 return (-2);
1455
1456 m_copydata(m, *off, NG_L2CAP_OPT_QOS_SIZE, (caddr_t) val);
1457 val->flow.token_rate = le32toh(val->flow.token_rate);
1458 val->flow.token_bucket_size =
1459 le32toh(val->flow.token_bucket_size);
1460 val->flow.peak_bandwidth = le32toh(val->flow.peak_bandwidth);
1461 val->flow.latency = le32toh(val->flow.latency);
1462 val->flow.delay_variation = le32toh(val->flow.delay_variation);
1463 *off += NG_L2CAP_OPT_QOS_SIZE;
1464 break;
1465
1466 default:
1467 if (hint)
1468 *off += hdr->length;
1469 else
1470 return (-3);
1471 break;
1472 }
1473
1474 return (1);
1475} /* get_next_l2cap_opt */
#define NG_FREE_M(m)
Definition: netgraph.h:946
#define NG_NODE_NAME(node)
Definition: netgraph.h:603
u_int32_t bluetooth_l2cap_ertx_timeout(void)
Definition: ng_bluetooth.c:209
u_int32_t bluetooth_l2cap_rtx_timeout(void)
Definition: ng_bluetooth.c:203
u_int8_t type
u_int16_t mtu
#define NG_HCI_LINK_ACL
Definition: ng_hci.h:121
#define NG_L2CAP_CONNLESS_MTU
Definition: ng_l2cap.h:147
#define NG_L2CAP_LESIGNAL_CID
Definition: ng_l2cap.h:80
#define NG_L2CAP_CON_RSP
Definition: ng_l2cap.h:222
#define NG_L2CAP_REJ_INVALID_CID
Definition: ng_l2cap.h:100
#define NG_L2CAP_SMP_CID
Definition: ng_l2cap.h:81
#define NG_L2CAP_OPT_MTU
Definition: ng_l2cap.h:138
#define NG_L2CAP_CLT_CID
Definition: ng_l2cap.h:77
#define NG_L2CAP_L2CA_IDTYPE_LE
Definition: ng_l2cap.h:361
#define NG_L2CAP_PSM_NOT_SUPPORTED
Definition: ng_l2cap.h:113
#define NG_L2CAP_SIGNAL_CID
Definition: ng_l2cap.h:76
#define NG_L2CAP_PENDING
Definition: ng_l2cap.h:112
#define NG_L2CAP_L2CA_IDTYPE_BREDR
Definition: ng_l2cap.h:359
#define NG_L2CAP_ECHO_REQ
Definition: ng_l2cap.h:276
#define NG_L2CAP_L2CA_IDTYPE_SMP
Definition: ng_l2cap.h:362
#define NG_L2CAP_NOT_SUPPORTED
Definition: ng_l2cap.h:151
#define NG_L2CAP_OPT_QOS_SIZE
Definition: ng_l2cap.h:143
#define NG_L2CAP_W4_L2CAP_CON_RSP
Definition: ng_l2cap.h:625
#define NG_L2CAP_OPT_FLUSH_TIMO
Definition: ng_l2cap.h:140
#define NG_L2CAP_OPT_HINT(type)
Definition: ng_l2cap.h:136
u_int16_t dcid
Definition: ng_l2cap.h:1
#define NG_L2CAP_ATT_CID
Definition: ng_l2cap.h:79
#define NG_L2CAP_OPEN
Definition: ng_l2cap.h:628
#define NG_L2CAP_CMD_REJ
Definition: ng_l2cap.h:194
#define NG_L2CAP_UNKNOWN
Definition: ng_l2cap.h:117
#define NG_L2CAP_OPT_FLUSH_TIMO_SIZE
Definition: ng_l2cap.h:141
#define NG_L2CAP_INFO_REQ
Definition: ng_l2cap.h:286
#define NG_L2CAP_CMD_PARAM_UPDATE_REQUEST
Definition: ng_l2cap.h:309
#define NG_L2CAP_CFG_REQ
Definition: ng_l2cap.h:231
#define NG_L2CAP_UPDATE_PARAM_ACCEPT
Definition: ng_l2cap.h:319
#define NG_L2CAP_MTU_DEFAULT
Definition: ng_l2cap.h:90
#define NG_L2CAP_OPT_MTU_SIZE
Definition: ng_l2cap.h:139
#define NG_L2CAP_CFG_RSP
Definition: ng_l2cap.h:239
#define NG_L2CAP_L2CA_IDTYPE_ATT
Definition: ng_l2cap.h:360
#define NG_L2CAP_SUCCESS
Definition: ng_l2cap.h:111
ng_l2cap_discon_req_cp ng_l2cap_discon_rsp_cp
Definition: ng_l2cap.h:273
#define NG_L2CAP_OPT_QOS
Definition: ng_l2cap.h:142
#define NG_L2CAP_ECHO_RSP
Definition: ng_l2cap.h:280
#define NG_L2CAP_OPT_CFLAG(flags)
Definition: ng_l2cap.h:134
#define NG_L2CAP_DISCON_REQ
Definition: ng_l2cap.h:265
#define NG_L2CAP_INFO_RSP
Definition: ng_l2cap.h:292
#define NG_L2CAP_W4_L2CAP_DISCON_RSP
Definition: ng_l2cap.h:629
#define NG_L2CAP_CONFIG
Definition: ng_l2cap.h:627
#define NG_L2CAP_DISCON_RSP
Definition: ng_l2cap.h:272
#define NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE
Definition: ng_l2cap.h:318
ng_l2cap_cfg_opt_t * ng_l2cap_cfg_opt_p
Definition: ng_l2cap.h:253
#define NG_L2CAP_REJ_NOT_UNDERSTOOD
Definition: ng_l2cap.h:98
u_int16_t scid
Definition: ng_l2cap.h:0
#define NG_L2CAP_NO_RESOURCES
Definition: ng_l2cap.h:115
#define NG_L2CAP_OPT_HINT_MASK
Definition: ng_l2cap.h:137
#define NG_L2CAP_REJECT
Definition: ng_l2cap.h:128
#define NG_L2CAP_UNKNOWN_OPTION
Definition: ng_l2cap.h:129
#define NG_L2CAP_CON_REQ
Definition: ng_l2cap.h:215
#define NG_L2CAP_W4_L2CA_CON_RSP
Definition: ng_l2cap.h:626
#define _ng_l2cap_info_rsp(_m, _ident, _type, _result, _mtu)
#define _ng_l2cap_discon_rsp(_m, _ident, _dcid, _scid)
#define _ng_l2cap_cmd_urs(_m, _ident, _result)
#define _ng_l2cap_cmd_rej(_m, _ident, _reason, _mtu, _scid, _dcid)
Definition: ng_l2cap_cmds.h:53
#define _ng_l2cap_con_rsp(_m, _ident, _dcid, _scid, _result, _status)
#define _ng_l2cap_cfg_rsp(_m, _ident, _scid, _flags, _result, _data)
static int ng_l2cap_process_discon_req(ng_l2cap_con_p, u_int8_t)
static int ng_l2cap_process_info_rsp(ng_l2cap_con_p, u_int8_t)
static int ng_l2cap_process_con_rsp(ng_l2cap_con_p, u_int8_t)
static int ng_l2cap_process_cmd_urq(ng_l2cap_con_p, u_int8_t)
static int send_l2cap_cfg_rsp(ng_l2cap_con_p, u_int8_t, u_int16_t, u_int16_t, struct mbuf *)
static int ng_l2cap_process_lesignal_cmd(ng_l2cap_con_p)
static int ng_l2cap_process_cmd_rej(ng_l2cap_con_p, u_int8_t)
static int ng_l2cap_process_cfg_req(ng_l2cap_con_p, u_int8_t)
static int ng_l2cap_process_echo_req(ng_l2cap_con_p, u_int8_t)
static int send_l2cap_con_rej(ng_l2cap_con_p, u_int8_t, u_int16_t, u_int16_t, u_int16_t)
static int ng_l2cap_process_con_req(ng_l2cap_con_p, u_int8_t)
static int ng_l2cap_process_discon_rsp(ng_l2cap_con_p, u_int8_t)
static int get_next_l2cap_opt(struct mbuf *, int *, ng_l2cap_cfg_opt_p, ng_l2cap_cfg_opt_val_p)
static int send_l2cap_param_urs(ng_l2cap_con_p, u_int8_t, u_int16_t)
int ng_l2cap_receive(ng_l2cap_con_p con)
Definition: ng_l2cap_evnt.c:94
static int ng_l2cap_process_info_req(ng_l2cap_con_p, u_int8_t)
static int ng_l2cap_process_cfg_rsp(ng_l2cap_con_p, u_int8_t)
static int ng_l2cap_process_cmd_urs(ng_l2cap_con_p, u_int8_t)
static int ng_l2cap_process_echo_rsp(ng_l2cap_con_p, u_int8_t)
static int ng_l2cap_process_signal_cmd(ng_l2cap_con_p)
static int send_l2cap_reject(ng_l2cap_con_p, u_int8_t, u_int16_t, u_int16_t, u_int16_t, u_int16_t)
void ng_l2cap_lp_deliver(ng_l2cap_con_p con)
ng_l2cap_cmd_p ng_l2cap_cmd_by_ident(ng_l2cap_con_p con, u_int8_t ident)
void ng_l2cap_free_chan(ng_l2cap_chan_p ch)
int ng_l2cap_command_untimeout(ng_l2cap_cmd_p cmd)
int ng_l2cap_command_timeout(ng_l2cap_cmd_p cmd, int timo)
struct mbuf * ng_l2cap_prepend(struct mbuf *m, int size)
ng_l2cap_cmd_p ng_l2cap_new_cmd(ng_l2cap_con_p con, ng_l2cap_chan_p ch, u_int8_t ident, u_int8_t code, u_int32_t token)
ng_l2cap_chan_p ng_l2cap_new_chan(ng_l2cap_p l2cap, ng_l2cap_con_p con, u_int16_t psm, int idtype)
ng_l2cap_chan_p ng_l2cap_chan_by_scid(ng_l2cap_p l2cap, u_int16_t scid, int idtype)
#define ng_l2cap_unlink_cmd(cmd)
Definition: ng_l2cap_misc.h:72
#define ng_l2cap_free_cmd(cmd)
Definition: ng_l2cap_misc.h:78
#define ng_l2cap_link_cmd(con, cmd)
Definition: ng_l2cap_misc.h:66
int ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result, u_int16_t status)
int ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch)
int ng_l2cap_l2ca_cfg_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
int ng_l2cap_l2ca_receive(ng_l2cap_con_p con)
int ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result, struct mbuf *data)
int ng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con)
int ng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch)
int ng_l2cap_l2ca_con_ind(ng_l2cap_chan_p ch)
int ng_l2cap_l2ca_discon_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
int ng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result, struct mbuf *data)
#define NG_L2CAP_ALERT
Definition: ng_l2cap_var.h:47
#define NG_L2CAP_ERR
Definition: ng_l2cap_var.h:48
#define NG_L2CAP_M_PULLUP(m, s)
Definition: ng_l2cap_var.h:53
#define NG_L2CAP_WARN
Definition: ng_l2cap_var.h:49
#define NG_L2CAP_INFO
Definition: ng_l2cap_var.h:50
cmd
Definition: ng_pppoe.h:74
uint8_t status
Definition: ng_ubt_intel.c:0
uint8_t length
Definition: ng_ubt_var.h:1
u_int16_t dcid
Definition: ng_l2cap_var.h:156
u_int16_t flush_timo
Definition: ng_l2cap_var.h:165
u_int8_t cfg_state
Definition: ng_l2cap_var.h:147
u_int16_t state
Definition: ng_l2cap_var.h:145
u_int16_t scid
Definition: ng_l2cap_var.h:155
ng_l2cap_flow_t iflow
Definition: ng_l2cap_var.h:160
u_int16_t omtu
Definition: ng_l2cap_var.h:162
u_int8_t ident
Definition: ng_l2cap_var.h:152
uint8_t linktype
Definition: ng_l2cap_var.h:123
struct mbuf * rx_pkt
Definition: ng_l2cap_var.h:131
u_int8_t ident
Definition: ng_l2cap_var.h:122
ng_l2cap_p l2cap
Definition: ng_l2cap_var.h:111
u_int16_t con_handle
Definition: ng_l2cap_var.h:119
node_p node
Definition: ng_l2cap_var.h:81
ng_l2cap_flow_t flow
Definition: ng_l2cap.h:259
u_int16_t flush_timo
Definition: ng_l2cap.h:258