6 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
30 * $Id: ng_l2cap_ulpi.c,v 1.1 2002/11/24 19:47:06 max Exp $
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>
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>
52 /******************************************************************************
53 ******************************************************************************
54 ** Upper Layer Protocol Interface module
55 ******************************************************************************
56 ******************************************************************************/
59 * Process L2CA_Connect request from the upper layer protocol.
63 ng_l2cap_l2ca_con_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
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;
72 if (msg->header.arglen != sizeof(*ip)) {
74 "%s: %s - invalid L2CA_Connect request message size, size=%d\n",
75 __func__, NG_NODE_NAME(l2cap->node),
81 ip = (ng_l2cap_l2ca_con_ip *)(msg->data);
83 /* Check if we have connection to the remote unit */
84 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
86 /* Submit LP_ConnectReq to the lower layer */
87 error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);
90 "%s: %s - unable to send LP_ConnectReq message, error=%d\n",
91 __func__, NG_NODE_NAME(l2cap->node), error);
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)));
102 * Create new empty channel descriptor. In case of any failure do
103 * not touch connection descriptor.
106 ch = ng_l2cap_new_chan(l2cap, con, ip->psm, ip->idtype);
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);
116 ng_l2cap_free_chan(ch);
121 if (cmd->ident == NG_L2CAP_NULL_IDENT) {
122 ng_l2cap_free_cmd(cmd);
123 ng_l2cap_free_chan(ch);
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;
134 _ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid);
136 if (cmd->aux == NULL) {
137 ng_l2cap_free_cmd(cmd);
138 ng_l2cap_free_chan(ch);
143 ch->state = NG_L2CAP_W4_L2CAP_CON_RSP;
145 /* Link command to the queue */
146 ng_l2cap_link_cmd(ch->con, cmd);
147 ng_l2cap_lp_deliver(ch->con);
150 } /* ng_l2cap_l2ca_con_req */
153 * Send L2CA_Connect response to the upper layer protocol.
157 ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
160 ng_l2cap_p l2cap = ch->con->l2cap;
161 struct ng_mesg *msg = NULL;
162 ng_l2cap_l2ca_con_op *op = NULL;
165 /* Check if upstream hook is connected and valid */
166 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
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);
175 /* Create and send L2CA_Connect response message */
176 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON,
177 sizeof(*op), M_NOWAIT);
181 msg->header.token = token;
182 msg->header.flags |= NGF_RESP;
184 op = (ng_l2cap_l2ca_con_op *)(msg->data);
187 * XXX Spec. says we should only populate LCID when result == 0
188 * What about PENDING? What the heck, for now always populate
191 if(ch->scid == NG_L2CAP_ATT_CID){
192 op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
193 op->lcid = ch->con->con_handle;
195 op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
196 NG_L2CAP_L2CA_IDTYPE_BREDR :
197 NG_L2CAP_L2CA_IDTYPE_LE;
204 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
208 } /* ng_l2cap_l2ca_con_rsp */
211 * Process L2CA_ConnectRsp request from the upper layer protocol.
215 ng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
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;
225 if (msg->header.arglen != sizeof(*ip)) {
227 "%s: %s - invalid L2CA_ConnectRsp request message size, size=%d\n",
228 __func__, NG_NODE_NAME(l2cap->node),
234 ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data);
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);
243 // For now not support on ATT device.
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);
255 /* Check channel state */
256 if (ch->state != NG_L2CAP_W4_L2CA_CON_RSP) {
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,
270 * Now we are pretty much sure it is our response. So create and send
271 * L2CAP_ConnectRsp message to our peer.
274 if (ch->ident != ip->ident)
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);
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;
289 case NG_L2CAP_PENDING:
293 ng_l2cap_free_chan(ch);
298 /* Create L2CAP command */
299 cmd = ng_l2cap_new_cmd(con, ch, ip->ident, NG_L2CAP_CON_RSP,
303 ng_l2cap_free_chan(ch);
309 _ng_l2cap_con_rsp(cmd->aux, cmd->ident, ip->lcid, dcid,
310 ip->result, ip->status);
311 if (cmd->aux == NULL) {
313 ng_l2cap_free_chan(ch);
315 ng_l2cap_free_cmd(cmd);
320 /* Link command to the queue */
321 ng_l2cap_link_cmd(con, cmd);
322 ng_l2cap_lp_deliver(con);
325 } /* ng_l2cap_l2ca_con_rsp_req */
328 * Send L2CAP_ConnectRsp response to the upper layer
332 ng_l2cap_l2ca_con_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
334 ng_l2cap_p l2cap = ch->con->l2cap;
335 struct ng_mesg *msg = NULL;
336 ng_l2cap_l2ca_con_rsp_op *op = NULL;
339 /* Check if upstream hook is connected and valid */
340 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
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);
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);
355 msg->header.token = token;
356 msg->header.flags |= NGF_RESP;
358 op = (ng_l2cap_l2ca_con_rsp_op *)(msg->data);
361 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
365 } /* ng_l2cap_l2ca_con_rsp_rsp */
368 * Send L2CA_ConnectInd message to the upper layer protocol.
372 ng_l2cap_l2ca_con_ind(ng_l2cap_chan_p ch)
374 ng_l2cap_p l2cap = ch->con->l2cap;
375 struct ng_mesg *msg = NULL;
376 ng_l2cap_l2ca_con_ind_ip *ip = NULL;
379 /* Check if upstream hook is connected and valid */
380 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
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);
389 /* Create and send L2CA_ConnectInd message */
390 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_IND,
391 sizeof(*ip), M_NOWAIT);
395 ip = (ng_l2cap_l2ca_con_ind_ip *)(msg->data);
397 bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr));
400 ip->ident = ch->ident;
402 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
406 } /* ng_l2cap_l2ca_con_ind */
409 * Process L2CA_Config request from the upper layer protocol
413 ng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
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;
424 if (msg->header.arglen != sizeof(*ip)) {
426 "%s: %s - Invalid L2CA_Config request message size, size=%d\n",
427 __func__, NG_NODE_NAME(l2cap->node),
433 ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data);
435 /* Check if we have this channel */
436 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, NG_L2CAP_L2CA_IDTYPE_BREDR);
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);
446 /* Check channel state */
447 if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG) {
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,
457 /* Set requested channel configuration options */
459 bcopy(&ip->oflow, &ch->oflow, sizeof(ch->oflow));
460 ch->flush_timo = ip->flush_timo;
461 ch->link_timo = ip->link_timo;
463 /* Compare channel settings with defaults */
464 if (ch->imtu != NG_L2CAP_MTU_DEFAULT)
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)
471 /* Create configuration options */
472 _ng_l2cap_build_cfg_options(opt, mtu, flush_timo, flow);
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);
487 if (cmd->ident == NG_L2CAP_NULL_IDENT) {
488 ng_l2cap_free_cmd(cmd);
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);
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;
509 /* Link command to the queue */
510 ng_l2cap_link_cmd(ch->con, cmd);
511 ng_l2cap_lp_deliver(ch->con);
514 } /* ng_l2cap_l2ca_cfg_req */
517 * Send L2CA_Config response to the upper layer protocol
521 ng_l2cap_l2ca_cfg_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
523 ng_l2cap_p l2cap = ch->con->l2cap;
524 struct ng_mesg *msg = NULL;
525 ng_l2cap_l2ca_cfg_op *op = NULL;
528 /* Check if upstream hook is connected and valid */
529 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
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);
538 /* Create and send L2CA_Config response message */
539 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG,
540 sizeof(*op), M_NOWAIT);
544 msg->header.token = token;
545 msg->header.flags |= NGF_RESP;
547 op = (ng_l2cap_l2ca_cfg_op *)(msg->data);
550 bcopy(&ch->oflow, &op->oflow, sizeof(op->oflow));
551 op->flush_timo = ch->flush_timo;
553 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
555 if (error == 0 && result == NG_L2CAP_SUCCESS) {
556 ch->cfg_state |= NG_L2CAP_CFG_IN;
558 if (ch->cfg_state == NG_L2CAP_CFG_BOTH)
559 ch->state = NG_L2CAP_OPEN;
564 } /* ng_l2cap_l2ca_cfg_rsp */
567 * Process L2CA_ConfigRsp request from the upper layer protocol
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.
584 ng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
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;
595 if (msg->header.arglen != sizeof(*ip)) {
597 "%s: %s - invalid L2CA_ConfigRsp request message size, size=%d\n",
598 __func__, NG_NODE_NAME(l2cap->node),
604 ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data);
606 /* Check if we have this channel */
607 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid,
608 NG_L2CAP_L2CA_IDTYPE_BREDR);
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);
618 /* Check channel state */
619 if (ch->state != NG_L2CAP_CONFIG) {
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,
629 /* Set channel settings */
630 if (ip->omtu != ch->omtu) {
635 if (bcmp(&ip->iflow, &ch->iflow, sizeof(ch->iflow)) != 0) {
636 bcopy(&ip->iflow, &ch->iflow, sizeof(ch->iflow));
640 if (mtu != NULL || flow != NULL) {
641 _ng_l2cap_build_cfg_options(opt, mtu, NULL, flow);
648 /* Create L2CAP command */
649 cmd = ng_l2cap_new_cmd(ch->con, ch, ch->ident, NG_L2CAP_CFG_RSP,
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);
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;
669 /* Link command to the queue */
670 ng_l2cap_link_cmd(ch->con, cmd);
671 ng_l2cap_lp_deliver(ch->con);
674 } /* ng_l2cap_l2ca_cfg_rsp_req */
677 * Send L2CA_ConfigRsp response to the upper layer protocol
681 ng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
683 ng_l2cap_p l2cap = ch->con->l2cap;
684 struct ng_mesg *msg = NULL;
685 ng_l2cap_l2ca_cfg_rsp_op *op = NULL;
688 /* Check if upstream hook is connected and valid */
689 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
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);
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);
704 msg->header.token = token;
705 msg->header.flags |= NGF_RESP;
707 op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data);
710 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
714 } /* ng_l2cap_l2ca_cfg_rsp_rsp */
717 * Send L2CA_ConfigInd message to the upper layer protocol
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.
734 ng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch)
736 ng_l2cap_p l2cap = ch->con->l2cap;
737 struct ng_mesg *msg = NULL;
738 ng_l2cap_l2ca_cfg_ind_ip *ip = NULL;
741 /* Check if upstream hook is connected and valid */
742 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
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);
751 /* Create and send L2CA_ConnectInd message */
752 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_IND,
753 sizeof(*ip), M_NOWAIT);
757 ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data);
760 bcopy(&ch->iflow, &ip->iflow, sizeof(ip->iflow));
761 ip->flush_timo = ch->flush_timo;
763 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
767 } /* ng_l2cap_l2ca_cfg_ind */
770 * Process L2CA_Write event
774 ng_l2cap_l2ca_write_req(ng_l2cap_p l2cap, struct mbuf *m)
776 ng_l2cap_l2ca_hdr_t *l2ca_hdr = NULL;
777 ng_l2cap_chan_p ch = NULL;
778 ng_l2cap_cmd_p cmd = NULL;
782 /* Make sure we can access L2CA data packet header */
783 if (m->m_pkthdr.len < sizeof(*l2ca_hdr)) {
785 "%s: %s - L2CA Data packet too small, len=%d\n",
786 __func__,NG_NODE_NAME(l2cap->node),m->m_pkthdr.len);
791 /* Get L2CA data packet header */
792 NG_L2CAP_M_PULLUP(m, sizeof(*l2ca_hdr));
796 l2ca_hdr = mtod(m, ng_l2cap_l2ca_hdr_t *);
797 token = l2ca_hdr->token;
798 m_adj(m, sizeof(*l2ca_hdr));
800 /* Verify payload size */
801 if (l2ca_hdr->length != m->m_pkthdr.len) {
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,
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,
816 if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) {
818 "%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n",
819 __func__, NG_NODE_NAME(l2cap->node),
825 /* Verify that we have the channel and make sure it is open */
826 ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid,
832 "%s: %s - invalid L2CA Data packet. Channel does not exist, cid=%d\n",
833 __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid);
838 if (ch->state != NG_L2CAP_OPEN) {
840 "%s: %s - invalid L2CA Data packet. Invalid channel state, scid=%d, state=%d\n",
841 __func__, NG_NODE_NAME(l2cap->node), ch->scid,
844 goto drop; /* XXX not always - re-configure */
847 /* Create L2CAP command descriptor */
848 cmd = ng_l2cap_new_cmd(ch->con, ch, 0, NGM_L2CAP_L2CA_WRITE, token);
854 /* Attach data packet and link command to the queue */
856 ng_l2cap_link_cmd(ch->con, cmd);
857 ng_l2cap_lp_deliver(ch->con);
864 } /* ng_l2cap_l2ca_write_req */
867 * Send L2CA_Write response
871 ng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
874 ng_l2cap_p l2cap = ch->con->l2cap;
875 struct ng_mesg *msg = NULL;
876 ng_l2cap_l2ca_write_op *op = NULL;
879 /* Check if upstream hook is connected and valid */
880 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
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);
889 /* Create and send L2CA_WriteRsp message */
890 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_WRITE,
891 sizeof(*op), M_NOWAIT);
895 msg->header.token = token;
896 msg->header.flags |= NGF_RESP;
898 op = (ng_l2cap_l2ca_write_op *)(msg->data);
901 if(ch->scid == NG_L2CAP_ATT_CID){
902 op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
903 op->lcid = ch->con->con_handle;
905 op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
906 NG_L2CAP_L2CA_IDTYPE_BREDR :
907 NG_L2CAP_L2CA_IDTYPE_LE;
911 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
915 } /* ng_l2cap_l2ca_write_rsp */
918 * Receive packet from the lower layer protocol and send it to the upper
919 * layer protocol (L2CAP_Read)
923 ng_l2cap_l2ca_receive(ng_l2cap_con_p con)
925 ng_l2cap_p l2cap = con->l2cap;
926 ng_l2cap_hdr_t *hdr = NULL;
927 ng_l2cap_chan_p ch = NULL;
932 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
933 if (con->rx_pkt == NULL)
936 hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *);
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,
945 * Here,ATT channel is distinguished by
948 hdr->dcid = con->con_handle;
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);
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);
963 /* Check channel state */
964 if (ch->state != NG_L2CAP_OPEN) {
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,
970 error = EHOSTDOWN; /* XXX not always - re-configuration */
974 /* Check payload size and channel's MTU */
975 if (hdr->length > ch->imtu) {
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,
986 * If we got here then everything looks good and we can sent packet
987 * to the upper layer protocol.
990 /* Check if upstream hook is connected and valid */
991 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
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);
999 M_PREPEND(con->rx_pkt, sizeof(uint16_t), M_NOWAIT);
1000 if(con->rx_pkt == NULL)
1002 idp = mtod(con->rx_pkt, uint16_t *);
1005 NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
1008 NG_FREE_M(con->rx_pkt); /* checks for != NULL */
1011 } /* ng_l2cap_receive */
1014 * Receive connectioless (multicast) packet from the lower layer protocol and
1015 * send it to the upper layer protocol
1019 ng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con)
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;
1028 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
1029 if (con->rx_pkt == NULL)
1032 hdr = mtod(con->rx_pkt, struct _clt_pkt *);
1035 length = con->rx_pkt->m_pkthdr.len - sizeof(*hdr);
1038 "%s: %s - invalid L2CAP CLT data packet. Packet too small, length=%d\n",
1039 __func__, NG_NODE_NAME(l2cap->node), length);
1044 /* Check payload size against CLT MTU */
1045 if (length > NG_L2CAP_MTU_DEFAULT) {
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);
1054 hdr->c_h.psm = le16toh(hdr->c_h.psm);
1057 * If we got here then everything looks good and we can sent packet
1058 * to the upper layer protocol.
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)
1068 case NG_L2CAP_PSM_RFCOMM:
1069 if (l2cap->flags & NG_L2CAP_CLT_RFCOMM_DISABLED)
1073 case NG_L2CAP_PSM_TCP:
1074 if (l2cap->flags & NG_L2CAP_CLT_TCP_DISABLED)
1079 /* Check if upstream hook is connected and valid */
1080 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
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);
1089 NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
1092 NG_FREE_M(con->rx_pkt); /* checks for != NULL */
1095 } /* ng_l2cap_l2ca_clt_receive */
1098 * Send L2CA_QoSViolationInd to the upper layer protocol
1102 ng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch)
1104 ng_l2cap_p l2cap = ch->con->l2cap;
1105 struct ng_mesg *msg = NULL;
1106 ng_l2cap_l2ca_qos_ind_ip *ip = NULL;
1109 /* Check if upstream hook is connected and valid */
1110 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
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);
1119 /* Create and send L2CA_QoSViolationInd message */
1120 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_QOS_IND,
1121 sizeof(*ip), M_NOWAIT);
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);
1131 } /* ng_l2cap_l2ca_qos_ind */
1134 * Process L2CA_Disconnect request from the upper layer protocol.
1138 ng_l2cap_l2ca_discon_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1140 ng_l2cap_l2ca_discon_ip *ip = NULL;
1141 ng_l2cap_chan_p ch = NULL;
1142 ng_l2cap_cmd_p cmd = NULL;
1146 if (msg->header.arglen != sizeof(*ip)) {
1148 "%s: %s - invalid L2CA_Disconnect request message size, size=%d\n",
1149 __func__, NG_NODE_NAME(l2cap->node),
1150 msg->header.arglen);
1155 ip = (ng_l2cap_l2ca_discon_ip *)(msg->data);
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,
1164 ng_l2cap_free_chan(ch);
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);
1174 /* Check if we have this channel */
1175 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, ip->idtype);
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);
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) {
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,
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);
1202 ng_l2cap_free_chan(ch);
1207 if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1208 ng_l2cap_free_chan(ch);
1209 ng_l2cap_free_cmd(cmd);
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);
1222 ch->state = NG_L2CAP_W4_L2CAP_DISCON_RSP;
1224 /* Link command to the queue */
1225 ng_l2cap_link_cmd(ch->con, cmd);
1226 ng_l2cap_lp_deliver(ch->con);
1229 } /* ng_l2cap_l2ca_discon_req */
1232 * Send L2CA_Disconnect response to the upper layer protocol
1236 ng_l2cap_l2ca_discon_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
1238 ng_l2cap_p l2cap = ch->con->l2cap;
1239 struct ng_mesg *msg = NULL;
1240 ng_l2cap_l2ca_discon_op *op = NULL;
1243 /* Check if upstream hook is connected and valid */
1244 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
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);
1253 /* Create and send L2CA_Disconnect response message */
1254 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON,
1255 sizeof(*op), M_NOWAIT);
1259 msg->header.token = token;
1260 msg->header.flags |= NGF_RESP;
1262 op = (ng_l2cap_l2ca_discon_op *)(msg->data);
1263 op->result = result;
1265 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1269 } /* ng_l2cap_l2ca_discon_rsp */
1272 * Send L2CA_DisconnectInd message to the upper layer protocol.
1276 ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch)
1278 ng_l2cap_p l2cap = ch->con->l2cap;
1279 struct ng_mesg *msg = NULL;
1280 ng_l2cap_l2ca_discon_ind_ip *ip = NULL;
1283 /* Check if upstream hook is connected and valid */
1284 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
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);
1293 /* Create and send L2CA_DisconnectInd message */
1294 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND,
1295 sizeof(*ip), M_NOWAIT);
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);
1305 } /* ng_l2cap_l2ca_discon_ind */
1308 * Process L2CA_GroupCreate request from the upper layer protocol.
1313 ng_l2cap_l2ca_grp_create(ng_l2cap_p l2cap, struct ng_mesg *msg)
1316 } /* ng_l2cap_l2ca_grp_create */
1319 * Process L2CA_GroupClose request from the upper layer protocol
1324 ng_l2cap_l2ca_grp_close(ng_l2cap_p l2cap, struct ng_mesg *msg)
1327 } /* ng_l2cap_l2ca_grp_close */
1330 * Process L2CA_GroupAddMember request from the upper layer protocol.
1335 ng_l2cap_l2ca_grp_add_member_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1338 } /* ng_l2cap_l2ca_grp_add_member_req */
1341 * Send L2CA_GroupAddMember response to the upper layer protocol.
1346 ng_l2cap_l2ca_grp_add_member_rsp(ng_l2cap_chan_p ch, u_int32_t token,
1350 } /* ng_l2cap_l2ca_grp_add_member_rsp */
1353 * Process L2CA_GroupDeleteMember request from the upper layer protocol
1358 ng_l2cap_l2ca_grp_rem_member(ng_l2cap_p l2cap, struct ng_mesg *msg)
1361 } /* ng_l2cap_l2ca_grp_rem_member */
1364 * Process L2CA_GroupGetMembers request from the upper layer protocol
1369 ng_l2cap_l2ca_grp_get_members(ng_l2cap_p l2cap, struct ng_mesg *msg)
1372 } /* ng_l2cap_l2ca_grp_get_members */
1375 * Process L2CA_Ping request from the upper layer protocol
1379 ng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1381 ng_l2cap_l2ca_ping_ip *ip = NULL;
1382 ng_l2cap_con_p con = NULL;
1383 ng_l2cap_cmd_p cmd = NULL;
1386 /* Verify message */
1387 if (msg->header.arglen < sizeof(*ip)) {
1389 "%s: %s - invalid L2CA_Ping request message size, size=%d\n",
1390 __func__, NG_NODE_NAME(l2cap->node),
1391 msg->header.arglen);
1396 ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);
1397 if (ip->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
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);
1405 /* Check if we have connection to the unit */
1406 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1408 /* Submit LP_ConnectReq to the lower layer */
1409 error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1412 "%s: %s - unable to send LP_ConnectReq message, error=%d\n",
1413 __func__, NG_NODE_NAME(l2cap->node), error);
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)));
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);
1431 if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1432 ng_l2cap_free_cmd(cmd);
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);
1446 /* Link command to the queue */
1447 ng_l2cap_link_cmd(con, cmd);
1448 ng_l2cap_lp_deliver(con);
1451 } /* ng_l2cap_l2ca_ping_req */
1454 * Send L2CA_Ping response to the upper layer protocol
1458 ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result,
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;
1466 /* Check if control hook is connected and valid */
1467 if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
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));
1476 size = (data == NULL)? 0 : data->m_pkthdr.len;
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);
1484 msg->header.token = token;
1485 msg->header.flags |= NGF_RESP;
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));
1495 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1501 } /* ng_l2cap_l2ca_ping_rsp */
1504 * Process L2CA_GetInfo request from the upper layer protocol
1508 ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1510 ng_l2cap_l2ca_get_info_ip *ip = NULL;
1511 ng_l2cap_con_p con = NULL;
1512 ng_l2cap_cmd_p cmd = NULL;
1515 /* Verify message */
1516 if (msg->header.arglen != sizeof(*ip)) {
1518 "%s: %s - invalid L2CA_GetInfo request message size, size=%d\n",
1519 __func__, NG_NODE_NAME(l2cap->node),
1520 msg->header.arglen);
1525 ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
1527 /* Check if we have connection to the unit */
1528 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr,ip->linktype);
1530 /* Submit LP_ConnectReq to the lower layer */
1531 error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);
1534 "%s: %s - unable to send LP_ConnectReq message, error=%d\n",
1535 __func__, NG_NODE_NAME(l2cap->node), error);
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)));
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);
1553 if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1554 ng_l2cap_free_cmd(cmd);
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);
1567 /* Link command to the queue */
1568 ng_l2cap_link_cmd(con, cmd);
1569 ng_l2cap_lp_deliver(con);
1572 } /* ng_l2cap_l2ca_get_info_req */
1575 * Send L2CA_GetInfo response to the upper layer protocol
1579 ng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con, u_int32_t token,
1580 u_int16_t result, struct mbuf *data)
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;
1587 /* Check if control hook is connected and valid */
1588 if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
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));
1597 size = (data == NULL)? 0 : data->m_pkthdr.len;
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);
1605 msg->header.token = token;
1606 msg->header.flags |= NGF_RESP;
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));
1615 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1621 } /* ng_l2cap_l2ca_get_info_rsp */
1624 * Process L2CA_EnableCLT message from the upper layer protocol
1625 * XXX convert to NGN_L2CAP_NODE_SET_FLAGS?
1629 ng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg)
1631 ng_l2cap_l2ca_enable_clt_ip *ip = NULL;
1634 * ng_l2cap_l2ca_enable_clt_op *op = NULL;
1640 if (msg->header.arglen != sizeof(*ip)) {
1642 "%s: %s - invalid L2CA_EnableCLT message size, size=%d\n",
1643 __func__, NG_NODE_NAME(l2cap->node),
1644 msg->header.arglen);
1649 /* Process request */
1650 ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data);
1652 * result = NG_L2CAP_SUCCESS;
1658 /* Special case: disable/enable all PSM */
1660 l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED |
1661 NG_L2CAP_CLT_RFCOMM_DISABLED |
1662 NG_L2CAP_CLT_TCP_DISABLED);
1664 l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED |
1665 NG_L2CAP_CLT_RFCOMM_DISABLED |
1666 NG_L2CAP_CLT_TCP_DISABLED);
1669 case NG_L2CAP_PSM_SDP:
1671 l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED;
1673 l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED;
1676 case NG_L2CAP_PSM_RFCOMM:
1678 l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED;
1680 l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED;
1683 case NG_L2CAP_PSM_TCP:
1685 l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED;
1687 l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED;
1692 "%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm);
1694 * result = NG_L2CAP_PSM_NOT_SUPPORTED;
1701 * /* Create and send response message */
1702 * token = msg->header.token;
1704 * NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT,
1705 * sizeof(*op), M_NOWAIT);
1709 * msg->header.token = token;
1710 * msg->header.flags |= NGF_RESP;
1712 * op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data);
1713 * op->result = result;
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);
1722 } /* ng_l2cap_l2ca_enable_clt */