6 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
8 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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
32 * $Id: ng_l2cap_ulpi.c,v 1.1 2002/11/24 19:47:06 max Exp $
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>
42 #include <sys/queue.h>
43 #include <netgraph/ng_message.h>
44 #include <netgraph/netgraph.h>
45 #include <netgraph/bluetooth/include/ng_hci.h>
46 #include <netgraph/bluetooth/include/ng_l2cap.h>
47 #include <netgraph/bluetooth/l2cap/ng_l2cap_var.h>
48 #include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h>
49 #include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h>
50 #include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h>
51 #include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>
52 #include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>
54 /******************************************************************************
55 ******************************************************************************
56 ** Upper Layer Protocol Interface module
57 ******************************************************************************
58 ******************************************************************************/
61 * Process L2CA_Connect request from the upper layer protocol.
65 ng_l2cap_l2ca_con_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
67 ng_l2cap_l2ca_con_ip *ip = NULL;
68 ng_l2cap_con_p con = NULL;
69 ng_l2cap_chan_p ch = NULL;
70 ng_l2cap_cmd_p cmd = NULL;
74 if (msg->header.arglen != sizeof(*ip)) {
76 "%s: %s - invalid L2CA_Connect request message size, size=%d\n",
77 __func__, NG_NODE_NAME(l2cap->node),
83 ip = (ng_l2cap_l2ca_con_ip *)(msg->data);
85 /* Check if we have connection to the remote unit */
86 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
88 /* Submit LP_ConnectReq to the lower layer */
89 error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);
92 "%s: %s - unable to send LP_ConnectReq message, error=%d\n",
93 __func__, NG_NODE_NAME(l2cap->node), error);
97 /* This should not fail */
98 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
99 KASSERT((con != NULL),
100 ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
104 * Create new empty channel descriptor. In case of any failure do
105 * not touch connection descriptor.
108 ch = ng_l2cap_new_chan(l2cap, con, ip->psm, ip->idtype);
114 /* Now create L2CAP_ConnectReq command */
115 cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(con),
116 NG_L2CAP_CON_REQ, msg->header.token);
118 ng_l2cap_free_chan(ch);
123 if (cmd->ident == NG_L2CAP_NULL_IDENT) {
124 ng_l2cap_free_cmd(cmd);
125 ng_l2cap_free_chan(ch);
130 /* Create L2CAP command packet */
131 if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
132 _ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_ATT_CID,
133 NG_L2CAP_ATT_CID, 0, 0);
134 cmd->aux->m_flags |= M_PROTO2;
135 }else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
136 _ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_SMP_CID,
137 NG_L2CAP_SMP_CID, 0, 0);
138 cmd->aux->m_flags |= M_PROTO2;
140 _ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid);
142 if (cmd->aux == NULL) {
143 ng_l2cap_free_cmd(cmd);
144 ng_l2cap_free_chan(ch);
149 ch->state = NG_L2CAP_W4_L2CAP_CON_RSP;
151 /* Link command to the queue */
152 ng_l2cap_link_cmd(ch->con, cmd);
153 ng_l2cap_lp_deliver(ch->con);
156 } /* ng_l2cap_l2ca_con_req */
159 * Send L2CA_Connect response to the upper layer protocol.
163 ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
166 ng_l2cap_p l2cap = ch->con->l2cap;
167 struct ng_mesg *msg = NULL;
168 ng_l2cap_l2ca_con_op *op = NULL;
171 /* Check if upstream hook is connected and valid */
172 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
174 "%s: %s - unable to send L2CA_Connect response message. " \
175 "Hook is not connected or valid, psm=%d\n",
176 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
181 /* Create and send L2CA_Connect response message */
182 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON,
183 sizeof(*op), M_NOWAIT);
187 msg->header.token = token;
188 msg->header.flags |= NGF_RESP;
190 op = (ng_l2cap_l2ca_con_op *)(msg->data);
193 * XXX Spec. says we should only populate LCID when result == 0
194 * What about PENDING? What the heck, for now always populate
197 if(ch->scid == NG_L2CAP_ATT_CID){
198 op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
199 op->lcid = ch->con->con_handle;
200 }else if(ch->scid == NG_L2CAP_SMP_CID){
201 op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
202 op->lcid = ch->con->con_handle;
204 op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
205 NG_L2CAP_L2CA_IDTYPE_BREDR :
206 NG_L2CAP_L2CA_IDTYPE_LE;
209 op->encryption = ch->con->encryption;
213 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
217 } /* ng_l2cap_l2ca_con_rsp */
220 * Process L2CA_ConnectRsp request from the upper layer protocol.
224 ng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
226 ng_l2cap_l2ca_con_rsp_ip *ip = NULL;
227 ng_l2cap_con_p con = NULL;
228 ng_l2cap_chan_p ch = NULL;
229 ng_l2cap_cmd_p cmd = NULL;
234 if (msg->header.arglen != sizeof(*ip)) {
236 "%s: %s - invalid L2CA_ConnectRsp request message size, size=%d\n",
237 __func__, NG_NODE_NAME(l2cap->node),
243 ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data);
245 /* Check if we have this channel */
246 if((ip->lcid != NG_L2CAP_ATT_CID)&&
247 (ip->lcid != NG_L2CAP_SMP_CID)){
248 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid
249 ,(ip->linktype == NG_HCI_LINK_ACL)?
250 NG_L2CAP_L2CA_IDTYPE_BREDR:
251 NG_L2CAP_L2CA_IDTYPE_LE);
253 // For now not support on ATT device.
258 "%s: %s - unexpected L2CA_ConnectRsp request message. " \
259 "Channel does not exist, lcid=%d\n",
260 __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
265 /* Check channel state */
266 if (ch->state != NG_L2CAP_W4_L2CA_CON_RSP) {
268 "%s: %s - unexpected L2CA_ConnectRsp request message. " \
269 "Invalid channel state, state=%d, lcid=%d\n",
270 __func__, NG_NODE_NAME(l2cap->node), ch->state,
280 * Now we are pretty much sure it is our response. So create and send
281 * L2CAP_ConnectRsp message to our peer.
284 if (ch->ident != ip->ident)
286 "%s: %s - channel ident and response ident do not match, scid=%d, ident=%d. " \
287 "Will use response ident=%d\n",
288 __func__, NG_NODE_NAME(l2cap->node), ch->scid,
289 ch->ident, ip->ident);
292 switch (ip->result) {
293 case NG_L2CAP_SUCCESS:
294 ch->state = ((ch->scid == NG_L2CAP_ATT_CID)||
295 (ch->scid == NG_L2CAP_SMP_CID))?
296 NG_L2CAP_OPEN : NG_L2CAP_CONFIG;
300 case NG_L2CAP_PENDING:
304 ng_l2cap_free_chan(ch);
309 /* Create L2CAP command */
310 cmd = ng_l2cap_new_cmd(con, ch, ip->ident, NG_L2CAP_CON_RSP,
314 ng_l2cap_free_chan(ch);
320 _ng_l2cap_con_rsp(cmd->aux, cmd->ident, ip->lcid, dcid,
321 ip->result, ip->status);
322 if (cmd->aux == NULL) {
324 ng_l2cap_free_chan(ch);
326 ng_l2cap_free_cmd(cmd);
331 /* Link command to the queue */
332 ng_l2cap_link_cmd(con, cmd);
333 ng_l2cap_lp_deliver(con);
336 } /* ng_l2cap_l2ca_con_rsp_req */
338 int ng_l2cap_l2ca_encryption_change(ng_l2cap_chan_p ch, uint16_t result)
340 ng_l2cap_p l2cap = ch->con->l2cap;
341 struct ng_mesg *msg = NULL;
342 ng_l2cap_l2ca_enc_chg_op *op = NULL;
345 /* Check if upstream hook is connected and valid */
346 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
348 "%s: %s - unable to send L2CA_ConnectRsp response message. " \
349 "Hook is not connected or valid, psm=%d\n",
350 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
355 /* Create and send L2CA_ConnectRsp response message */
356 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENC_CHANGE,
357 sizeof(*op), M_NOWAIT);
361 msg->header.token = 0;
362 msg->header.flags |= NGF_RESP;
364 op = (ng_l2cap_l2ca_enc_chg_op *)(msg->data);
366 if(ch->scid ==NG_L2CAP_ATT_CID||
367 ch->scid ==NG_L2CAP_SMP_CID){
368 op->lcid = ch->con->con_handle;
369 op->idtype = (ch->scid==NG_L2CAP_ATT_CID)?
370 NG_L2CAP_L2CA_IDTYPE_ATT:
371 NG_L2CAP_L2CA_IDTYPE_SMP;
373 op->idtype =(ch->con->linktype ==NG_HCI_LINK_ACL)?
374 NG_L2CAP_L2CA_IDTYPE_BREDR:
375 NG_L2CAP_L2CA_IDTYPE_LE;
379 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
386 * Send L2CAP_ConnectRsp response to the upper layer
390 ng_l2cap_l2ca_con_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
392 ng_l2cap_p l2cap = ch->con->l2cap;
393 struct ng_mesg *msg = NULL;
394 ng_l2cap_l2ca_con_rsp_op *op = NULL;
397 /* Check if upstream hook is connected and valid */
398 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
400 "%s: %s - unable to send L2CA_ConnectRsp response message. " \
401 "Hook is not connected or valid, psm=%d\n",
402 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
407 /* Create and send L2CA_ConnectRsp response message */
408 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_RSP,
409 sizeof(*op), M_NOWAIT);
413 msg->header.token = token;
414 msg->header.flags |= NGF_RESP;
416 op = (ng_l2cap_l2ca_con_rsp_op *)(msg->data);
419 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
423 } /* ng_l2cap_l2ca_con_rsp_rsp */
426 * Send L2CA_ConnectInd message to the upper layer protocol.
430 ng_l2cap_l2ca_con_ind(ng_l2cap_chan_p ch)
432 ng_l2cap_p l2cap = ch->con->l2cap;
433 struct ng_mesg *msg = NULL;
434 ng_l2cap_l2ca_con_ind_ip *ip = NULL;
437 /* Check if upstream hook is connected and valid */
438 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
440 "%s: %s - unable to send L2CA_ConnectInd message. " \
441 "Hook is not connected or valid, psm=%d\n",
442 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
447 /* Create and send L2CA_ConnectInd message */
448 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_IND,
449 sizeof(*ip), M_NOWAIT);
453 ip = (ng_l2cap_l2ca_con_ind_ip *)(msg->data);
455 bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr));
458 ip->ident = ch->ident;
459 ip->linktype = ch->con->linktype;
461 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
465 } /* ng_l2cap_l2ca_con_ind */
468 * Process L2CA_Config request from the upper layer protocol
472 ng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
474 ng_l2cap_l2ca_cfg_ip *ip = NULL;
475 ng_l2cap_chan_p ch = NULL;
476 ng_l2cap_cmd_p cmd = NULL;
477 struct mbuf *opt = NULL;
478 u_int16_t *mtu = NULL, *flush_timo = NULL;
479 ng_l2cap_flow_p flow = NULL;
483 if (msg->header.arglen != sizeof(*ip)) {
485 "%s: %s - Invalid L2CA_Config request message size, size=%d\n",
486 __func__, NG_NODE_NAME(l2cap->node),
492 ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data);
494 /* Check if we have this channel */
495 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, NG_L2CAP_L2CA_IDTYPE_BREDR);
498 "%s: %s - unexpected L2CA_Config request message. " \
499 "Channel does not exist, lcid=%d\n",
500 __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
505 /* Check channel state */
506 if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG) {
508 "%s: %s - unexpected L2CA_Config request message. " \
509 "Invalid channel state, state=%d, lcid=%d\n",
510 __func__, NG_NODE_NAME(l2cap->node), ch->state,
516 /* Set requested channel configuration options */
518 bcopy(&ip->oflow, &ch->oflow, sizeof(ch->oflow));
519 ch->flush_timo = ip->flush_timo;
520 ch->link_timo = ip->link_timo;
522 /* Compare channel settings with defaults */
523 if (ch->imtu != NG_L2CAP_MTU_DEFAULT)
525 if (ch->flush_timo != NG_L2CAP_FLUSH_TIMO_DEFAULT)
526 flush_timo = &ch->flush_timo;
527 if (bcmp(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)) != 0)
530 /* Create configuration options */
531 _ng_l2cap_build_cfg_options(opt, mtu, flush_timo, flow);
537 /* Create L2CAP command descriptor */
538 cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con),
539 NG_L2CAP_CFG_REQ, msg->header.token);
546 if (cmd->ident == NG_L2CAP_NULL_IDENT) {
547 ng_l2cap_free_cmd(cmd);
553 /* Create L2CAP command packet */
554 _ng_l2cap_cfg_req(cmd->aux, cmd->ident, ch->dcid, 0, opt);
555 if (cmd->aux == NULL) {
556 ng_l2cap_free_cmd(cmd);
561 /* Adjust channel state for re-configuration */
562 if (ch->state == NG_L2CAP_OPEN) {
563 ch->state = ((ch->scid == NG_L2CAP_ATT_CID)||
564 (ch->scid == NG_L2CAP_SMP_CID))?
565 NG_L2CAP_OPEN : NG_L2CAP_CONFIG;
569 /* Link command to the queue */
570 ng_l2cap_link_cmd(ch->con, cmd);
571 ng_l2cap_lp_deliver(ch->con);
574 } /* ng_l2cap_l2ca_cfg_req */
577 * Send L2CA_Config response to the upper layer protocol
581 ng_l2cap_l2ca_cfg_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
583 ng_l2cap_p l2cap = ch->con->l2cap;
584 struct ng_mesg *msg = NULL;
585 ng_l2cap_l2ca_cfg_op *op = NULL;
588 /* Check if upstream hook is connected and valid */
589 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
591 "%s: %s - unable to send L2CA_Config response message. " \
592 "Hook is not connected or valid, psm=%d\n",
593 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
598 /* Create and send L2CA_Config response message */
599 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG,
600 sizeof(*op), M_NOWAIT);
604 msg->header.token = token;
605 msg->header.flags |= NGF_RESP;
607 op = (ng_l2cap_l2ca_cfg_op *)(msg->data);
610 bcopy(&ch->oflow, &op->oflow, sizeof(op->oflow));
611 op->flush_timo = ch->flush_timo;
613 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
615 if (error == 0 && result == NG_L2CAP_SUCCESS) {
616 ch->cfg_state |= NG_L2CAP_CFG_IN;
618 if (ch->cfg_state == NG_L2CAP_CFG_BOTH)
619 ch->state = NG_L2CAP_OPEN;
624 } /* ng_l2cap_l2ca_cfg_rsp */
627 * Process L2CA_ConfigRsp request from the upper layer protocol
631 * NOTE: The Bluetooth specification says that Configuration_Response
632 * (L2CA_ConfigRsp) should be used to issue response to configuration request
633 * indication. The minor problem here is L2CAP command ident. We should use
634 * ident from original L2CAP request to make sure our peer can match request
635 * and response. For some reason Bluetooth specification does not include
636 * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems
637 * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident
638 * field. So we should store last known L2CAP request command ident in channel.
639 * Also it seems that upper layer can not reject configuration request, as
640 * Configuration_Response message does not have status/reason field.
644 ng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
646 ng_l2cap_l2ca_cfg_rsp_ip *ip = NULL;
647 ng_l2cap_chan_p ch = NULL;
648 ng_l2cap_cmd_p cmd = NULL;
649 struct mbuf *opt = NULL;
650 u_int16_t *mtu = NULL;
651 ng_l2cap_flow_p flow = NULL;
655 if (msg->header.arglen != sizeof(*ip)) {
657 "%s: %s - invalid L2CA_ConfigRsp request message size, size=%d\n",
658 __func__, NG_NODE_NAME(l2cap->node),
664 ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data);
666 /* Check if we have this channel */
667 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid,
668 NG_L2CAP_L2CA_IDTYPE_BREDR);
671 "%s: %s - unexpected L2CA_ConfigRsp request message. " \
672 "Channel does not exist, lcid=%d\n",
673 __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
678 /* Check channel state */
679 if (ch->state != NG_L2CAP_CONFIG) {
681 "%s: %s - unexpected L2CA_ConfigRsp request message. " \
682 "Invalid channel state, state=%d, lcid=%d\n",
683 __func__, NG_NODE_NAME(l2cap->node), ch->state,
689 /* Set channel settings */
690 if (ip->omtu != ch->omtu) {
695 if (bcmp(&ip->iflow, &ch->iflow, sizeof(ch->iflow)) != 0) {
696 bcopy(&ip->iflow, &ch->iflow, sizeof(ch->iflow));
700 if (mtu != NULL || flow != NULL) {
701 _ng_l2cap_build_cfg_options(opt, mtu, NULL, flow);
708 /* Create L2CAP command */
709 cmd = ng_l2cap_new_cmd(ch->con, ch, ch->ident, NG_L2CAP_CFG_RSP,
717 _ng_l2cap_cfg_rsp(cmd->aux,cmd->ident,ch->dcid,0,NG_L2CAP_SUCCESS,opt);
718 if (cmd->aux == NULL) {
719 ng_l2cap_free_cmd(cmd);
724 /* XXX FIXME - not here ??? */
725 ch->cfg_state |= NG_L2CAP_CFG_OUT;
726 if (ch->cfg_state == NG_L2CAP_CFG_BOTH)
727 ch->state = NG_L2CAP_OPEN;
729 /* Link command to the queue */
730 ng_l2cap_link_cmd(ch->con, cmd);
731 ng_l2cap_lp_deliver(ch->con);
734 } /* ng_l2cap_l2ca_cfg_rsp_req */
737 * Send L2CA_ConfigRsp response to the upper layer protocol
741 ng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
743 ng_l2cap_p l2cap = ch->con->l2cap;
744 struct ng_mesg *msg = NULL;
745 ng_l2cap_l2ca_cfg_rsp_op *op = NULL;
748 /* Check if upstream hook is connected and valid */
749 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
751 "%s: %s - unable to send L2CA_ConfigRsp response message. " \
752 "Hook is not connected or valid, psm=%d\n",
753 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
758 /* Create and send L2CA_ConfigRsp response message */
759 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP,
760 sizeof(*op), M_NOWAIT);
764 msg->header.token = token;
765 msg->header.flags |= NGF_RESP;
767 op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data);
770 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
774 } /* ng_l2cap_l2ca_cfg_rsp_rsp */
777 * Send L2CA_ConfigInd message to the upper layer protocol
781 * NOTE: The Bluetooth specification says that Configuration_Response
782 * (L2CA_ConfigRsp) should be used to issue response to configuration request
783 * indication. The minor problem here is L2CAP command ident. We should use
784 * ident from original L2CAP request to make sure our peer can match request
785 * and response. For some reason Bluetooth specification does not include
786 * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems
787 * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident
788 * field. So we should store last known L2CAP request command ident in channel.
789 * Also it seems that upper layer can not reject configuration request, as
790 * Configuration_Response message does not have status/reason field.
794 ng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch)
796 ng_l2cap_p l2cap = ch->con->l2cap;
797 struct ng_mesg *msg = NULL;
798 ng_l2cap_l2ca_cfg_ind_ip *ip = NULL;
801 /* Check if upstream hook is connected and valid */
802 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
804 "%s: %s - Unable to send L2CA_ConfigInd message. " \
805 "Hook is not connected or valid, psm=%d\n",
806 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
811 /* Create and send L2CA_ConnectInd message */
812 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_IND,
813 sizeof(*ip), M_NOWAIT);
817 ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data);
820 bcopy(&ch->iflow, &ip->iflow, sizeof(ip->iflow));
821 ip->flush_timo = ch->flush_timo;
823 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
827 } /* ng_l2cap_l2ca_cfg_ind */
830 * Process L2CA_Write event
834 ng_l2cap_l2ca_write_req(ng_l2cap_p l2cap, struct mbuf *m)
836 ng_l2cap_l2ca_hdr_t *l2ca_hdr = NULL;
837 ng_l2cap_chan_p ch = NULL;
838 ng_l2cap_cmd_p cmd = NULL;
842 /* Make sure we can access L2CA data packet header */
843 if (m->m_pkthdr.len < sizeof(*l2ca_hdr)) {
845 "%s: %s - L2CA Data packet too small, len=%d\n",
846 __func__,NG_NODE_NAME(l2cap->node),m->m_pkthdr.len);
851 /* Get L2CA data packet header */
852 NG_L2CAP_M_PULLUP(m, sizeof(*l2ca_hdr));
856 l2ca_hdr = mtod(m, ng_l2cap_l2ca_hdr_t *);
857 token = l2ca_hdr->token;
858 m_adj(m, sizeof(*l2ca_hdr));
860 /* Verify payload size */
861 if (l2ca_hdr->length != m->m_pkthdr.len) {
863 "%s: %s - invalid L2CA Data packet. " \
864 "Payload length does not match, length=%d, len=%d\n",
865 __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->length,
871 /* Check channel ID */
872 if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
873 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
875 } else if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
876 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
879 if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) {
881 "%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n",
882 __func__, NG_NODE_NAME(l2cap->node),
888 /* Verify that we have the channel and make sure it is open */
889 ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid,
895 "%s: %s - invalid L2CA Data packet. Channel does not exist, cid=%d\n",
896 __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid);
901 if (ch->state != NG_L2CAP_OPEN) {
903 "%s: %s - invalid L2CA Data packet. Invalid channel state, scid=%d, state=%d\n",
904 __func__, NG_NODE_NAME(l2cap->node), ch->scid,
907 goto drop; /* XXX not always - re-configure */
910 /* Create L2CAP command descriptor */
911 cmd = ng_l2cap_new_cmd(ch->con, ch, 0, NGM_L2CAP_L2CA_WRITE, token);
917 /* Attach data packet and link command to the queue */
919 ng_l2cap_link_cmd(ch->con, cmd);
920 ng_l2cap_lp_deliver(ch->con);
927 } /* ng_l2cap_l2ca_write_req */
930 * Send L2CA_Write response
934 ng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
937 ng_l2cap_p l2cap = ch->con->l2cap;
938 struct ng_mesg *msg = NULL;
939 ng_l2cap_l2ca_write_op *op = NULL;
942 /* Check if upstream hook is connected and valid */
943 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
945 "%s: %s - unable to send L2CA_WriteRsp message. " \
946 "Hook is not connected or valid, psm=%d\n",
947 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
952 /* Create and send L2CA_WriteRsp message */
953 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_WRITE,
954 sizeof(*op), M_NOWAIT);
958 msg->header.token = token;
959 msg->header.flags |= NGF_RESP;
961 op = (ng_l2cap_l2ca_write_op *)(msg->data);
964 if(ch->scid == NG_L2CAP_ATT_CID){
965 op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
966 op->lcid = ch->con->con_handle;
967 }else if(ch->scid == NG_L2CAP_SMP_CID){
968 op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
969 op->lcid = ch->con->con_handle;
971 op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
972 NG_L2CAP_L2CA_IDTYPE_BREDR :
973 NG_L2CAP_L2CA_IDTYPE_LE;
977 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
981 } /* ng_l2cap_l2ca_write_rsp */
984 * Receive packet from the lower layer protocol and send it to the upper
985 * layer protocol (L2CAP_Read)
989 ng_l2cap_l2ca_receive(ng_l2cap_con_p con)
991 ng_l2cap_p l2cap = con->l2cap;
992 ng_l2cap_hdr_t *hdr = NULL;
993 ng_l2cap_chan_p ch = NULL;
999 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
1000 if (con->rx_pkt == NULL)
1003 hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *);
1007 if(hdr->dcid == NG_L2CAP_ATT_CID){
1008 idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
1009 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
1012 * Here,ATT channel is distinguished by
1015 hdr->dcid = con->con_handle;
1017 }else if(hdr->dcid == NG_L2CAP_SMP_CID){
1018 idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
1019 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
1022 * Here,SMP channel is distinguished by
1026 hdr->dcid = con->con_handle;
1028 idtype = (con->linktype==NG_HCI_LINK_ACL)?
1029 NG_L2CAP_L2CA_IDTYPE_BREDR:
1030 NG_L2CAP_L2CA_IDTYPE_LE;
1031 ch = ng_l2cap_chan_by_scid(l2cap, hdr->dcid, idtype);
1036 "%s: %s - unexpected L2CAP data packet. Channel does not exist, cid=%d, idtype=%d\n",
1037 __func__, NG_NODE_NAME(l2cap->node), hdr->dcid, idtype);
1042 /* Check channel state */
1043 if (ch->state != NG_L2CAP_OPEN) {
1045 "%s: %s - unexpected L2CAP data packet. " \
1046 "Invalid channel state, cid=%d, state=%d\n",
1047 __func__, NG_NODE_NAME(l2cap->node), ch->scid,
1049 error = EHOSTDOWN; /* XXX not always - re-configuration */
1053 /* Check payload size and channel's MTU */
1054 if (hdr->length > ch->imtu) {
1056 "%s: %s - invalid L2CAP data packet. " \
1057 "Packet too big, length=%d, imtu=%d, cid=%d\n",
1058 __func__, NG_NODE_NAME(l2cap->node), hdr->length,
1059 ch->imtu, ch->scid);
1065 * If we got here then everything looks good and we can sent packet
1066 * to the upper layer protocol.
1069 /* Check if upstream hook is connected and valid */
1070 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1072 "%s: %s - unable to send L2CAP data packet. " \
1073 "Hook is not connected or valid, psm=%d\n",
1074 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
1078 M_PREPEND(con->rx_pkt, sizeof(uint16_t), M_NOWAIT);
1079 if(con->rx_pkt == NULL)
1081 idp = mtod(con->rx_pkt, uint16_t *);
1084 NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
1087 NG_FREE_M(con->rx_pkt); /* checks for != NULL */
1090 } /* ng_l2cap_receive */
1093 * Receive connectioless (multicast) packet from the lower layer protocol and
1094 * send it to the upper layer protocol
1098 ng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con)
1102 ng_l2cap_clt_hdr_t c_h;
1103 } __attribute__ ((packed)) *hdr = NULL;
1104 ng_l2cap_p l2cap = con->l2cap;
1105 int length, error = 0;
1107 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
1108 if (con->rx_pkt == NULL)
1111 hdr = mtod(con->rx_pkt, struct _clt_pkt *);
1114 length = con->rx_pkt->m_pkthdr.len - sizeof(*hdr);
1117 "%s: %s - invalid L2CAP CLT data packet. Packet too small, length=%d\n",
1118 __func__, NG_NODE_NAME(l2cap->node), length);
1123 /* Check payload size against CLT MTU */
1124 if (length > NG_L2CAP_MTU_DEFAULT) {
1126 "%s: %s - invalid L2CAP CLT data packet. Packet too big, length=%d, mtu=%d\n",
1127 __func__, NG_NODE_NAME(l2cap->node), length,
1128 NG_L2CAP_MTU_DEFAULT);
1133 hdr->c_h.psm = le16toh(hdr->c_h.psm);
1136 * If we got here then everything looks good and we can sent packet
1137 * to the upper layer protocol.
1140 /* Select upstream hook based on PSM */
1141 switch (hdr->c_h.psm) {
1142 case NG_L2CAP_PSM_SDP:
1143 if (l2cap->flags & NG_L2CAP_CLT_SDP_DISABLED)
1147 case NG_L2CAP_PSM_RFCOMM:
1148 if (l2cap->flags & NG_L2CAP_CLT_RFCOMM_DISABLED)
1152 case NG_L2CAP_PSM_TCP:
1153 if (l2cap->flags & NG_L2CAP_CLT_TCP_DISABLED)
1158 /* Check if upstream hook is connected and valid */
1159 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1161 "%s: %s - unable to send L2CAP CLT data packet. " \
1162 "Hook is not connected or valid, psm=%d\n",
1163 __func__, NG_NODE_NAME(l2cap->node), hdr->c_h.psm);
1168 NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
1171 NG_FREE_M(con->rx_pkt); /* checks for != NULL */
1174 } /* ng_l2cap_l2ca_clt_receive */
1177 * Send L2CA_QoSViolationInd to the upper layer protocol
1181 ng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch)
1183 ng_l2cap_p l2cap = ch->con->l2cap;
1184 struct ng_mesg *msg = NULL;
1185 ng_l2cap_l2ca_qos_ind_ip *ip = NULL;
1188 /* Check if upstream hook is connected and valid */
1189 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1191 "%s: %s - unable to send L2CA_QoSViolationInd message. " \
1192 "Hook is not connected or valid, psm=%d\n",
1193 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
1198 /* Create and send L2CA_QoSViolationInd message */
1199 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_QOS_IND,
1200 sizeof(*ip), M_NOWAIT);
1204 ip = (ng_l2cap_l2ca_qos_ind_ip *)(msg->data);
1205 bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr));
1206 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1210 } /* ng_l2cap_l2ca_qos_ind */
1213 * Process L2CA_Disconnect request from the upper layer protocol.
1217 ng_l2cap_l2ca_discon_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1219 ng_l2cap_l2ca_discon_ip *ip = NULL;
1220 ng_l2cap_chan_p ch = NULL;
1221 ng_l2cap_cmd_p cmd = NULL;
1225 if (msg->header.arglen != sizeof(*ip)) {
1227 "%s: %s - invalid L2CA_Disconnect request message size, size=%d\n",
1228 __func__, NG_NODE_NAME(l2cap->node),
1229 msg->header.arglen);
1234 ip = (ng_l2cap_l2ca_discon_ip *)(msg->data);
1236 if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
1237 /* Don't send Disconnect request on L2CAP Layer*/
1238 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
1242 ng_l2cap_free_chan(ch);
1245 "%s: %s - unexpected L2CA_Disconnect request message. " \
1246 "Channel does not exist, conhandle=%d\n",
1247 __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1251 }else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
1252 /* Don't send Disconnect request on L2CAP Layer*/
1253 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
1257 ng_l2cap_free_chan(ch);
1260 "%s: %s - unexpected L2CA_Disconnect request message. " \
1261 "Channel does not exist, conhandle=%d\n",
1262 __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1267 /* Check if we have this channel */
1268 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, ip->idtype);
1272 "%s: %s - unexpected L2CA_Disconnect request message. " \
1273 "Channel does not exist, lcid=%d\n",
1274 __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1279 /* Check channel state */
1280 if (ch->state != NG_L2CAP_CONFIG && ch->state != NG_L2CAP_OPEN &&
1281 ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) {
1283 "%s: %s - unexpected L2CA_Disconnect request message. " \
1284 "Invalid channel state, state=%d, lcid=%d\n",
1285 __func__, NG_NODE_NAME(l2cap->node), ch->state,
1291 /* Create and send L2CAP_DisconReq message */
1292 cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con),
1293 NG_L2CAP_DISCON_REQ, msg->header.token);
1295 ng_l2cap_free_chan(ch);
1300 if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1301 ng_l2cap_free_chan(ch);
1302 ng_l2cap_free_cmd(cmd);
1307 _ng_l2cap_discon_req(cmd->aux, cmd->ident, ch->dcid, ch->scid);
1308 if (cmd->aux == NULL) {
1309 ng_l2cap_free_chan(ch);
1310 ng_l2cap_free_cmd(cmd);
1315 ch->state = NG_L2CAP_W4_L2CAP_DISCON_RSP;
1317 /* Link command to the queue */
1318 ng_l2cap_link_cmd(ch->con, cmd);
1319 ng_l2cap_lp_deliver(ch->con);
1322 } /* ng_l2cap_l2ca_discon_req */
1325 * Send L2CA_Disconnect response to the upper layer protocol
1329 ng_l2cap_l2ca_discon_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
1331 ng_l2cap_p l2cap = ch->con->l2cap;
1332 struct ng_mesg *msg = NULL;
1333 ng_l2cap_l2ca_discon_op *op = NULL;
1336 /* Check if upstream hook is connected and valid */
1337 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1339 "%s: %s - unable to send L2CA_Disconnect response message. " \
1340 "Hook is not connected or valid, psm=%d\n",
1341 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
1346 /* Create and send L2CA_Disconnect response message */
1347 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON,
1348 sizeof(*op), M_NOWAIT);
1352 msg->header.token = token;
1353 msg->header.flags |= NGF_RESP;
1355 op = (ng_l2cap_l2ca_discon_op *)(msg->data);
1356 op->result = result;
1358 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1362 } /* ng_l2cap_l2ca_discon_rsp */
1365 * Send L2CA_DisconnectInd message to the upper layer protocol.
1369 ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch)
1371 ng_l2cap_p l2cap = ch->con->l2cap;
1372 struct ng_mesg *msg = NULL;
1373 ng_l2cap_l2ca_discon_ind_ip *ip = NULL;
1376 /* Check if upstream hook is connected and valid */
1377 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1379 "%s: %s - unable to send L2CA_DisconnectInd message. " \
1380 "Hook is not connected or valid, psm=%d\n",
1381 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
1386 /* Create and send L2CA_DisconnectInd message */
1387 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND,
1388 sizeof(*ip), M_NOWAIT);
1392 ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data);
1393 ip->idtype = ch->idtype;
1394 if(ch->idtype == NG_L2CAP_L2CA_IDTYPE_ATT||
1395 ch->idtype == NG_L2CAP_L2CA_IDTYPE_SMP)
1396 ip->lcid = ch->con->con_handle;
1398 ip->lcid = ch->scid;
1400 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1404 } /* ng_l2cap_l2ca_discon_ind */
1407 * Process L2CA_GroupCreate request from the upper layer protocol.
1412 ng_l2cap_l2ca_grp_create(ng_l2cap_p l2cap, struct ng_mesg *msg)
1415 } /* ng_l2cap_l2ca_grp_create */
1418 * Process L2CA_GroupClose request from the upper layer protocol
1423 ng_l2cap_l2ca_grp_close(ng_l2cap_p l2cap, struct ng_mesg *msg)
1426 } /* ng_l2cap_l2ca_grp_close */
1429 * Process L2CA_GroupAddMember request from the upper layer protocol.
1434 ng_l2cap_l2ca_grp_add_member_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1437 } /* ng_l2cap_l2ca_grp_add_member_req */
1440 * Send L2CA_GroupAddMember response to the upper layer protocol.
1445 ng_l2cap_l2ca_grp_add_member_rsp(ng_l2cap_chan_p ch, u_int32_t token,
1449 } /* ng_l2cap_l2ca_grp_add_member_rsp */
1452 * Process L2CA_GroupDeleteMember request from the upper layer protocol
1457 ng_l2cap_l2ca_grp_rem_member(ng_l2cap_p l2cap, struct ng_mesg *msg)
1460 } /* ng_l2cap_l2ca_grp_rem_member */
1463 * Process L2CA_GroupGetMembers request from the upper layer protocol
1468 ng_l2cap_l2ca_grp_get_members(ng_l2cap_p l2cap, struct ng_mesg *msg)
1471 } /* ng_l2cap_l2ca_grp_get_members */
1474 * Process L2CA_Ping request from the upper layer protocol
1478 ng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1480 ng_l2cap_l2ca_ping_ip *ip = NULL;
1481 ng_l2cap_con_p con = NULL;
1482 ng_l2cap_cmd_p cmd = NULL;
1485 /* Verify message */
1486 if (msg->header.arglen < sizeof(*ip)) {
1488 "%s: %s - invalid L2CA_Ping request message size, size=%d\n",
1489 __func__, NG_NODE_NAME(l2cap->node),
1490 msg->header.arglen);
1495 ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);
1496 if (ip->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
1498 "%s: %s - invalid L2CA_Ping request. Echo size is too big, echo_size=%d\n",
1499 __func__, NG_NODE_NAME(l2cap->node), ip->echo_size);
1504 /* Check if we have connection to the unit */
1505 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1507 /* Submit LP_ConnectReq to the lower layer */
1508 error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1511 "%s: %s - unable to send LP_ConnectReq message, error=%d\n",
1512 __func__, NG_NODE_NAME(l2cap->node), error);
1516 /* This should not fail */
1517 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1518 KASSERT((con != NULL),
1519 ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
1522 /* Create L2CAP command descriptor */
1523 cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),
1524 NG_L2CAP_ECHO_REQ, msg->header.token);
1530 if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1531 ng_l2cap_free_cmd(cmd);
1536 /* Create L2CAP command packet */
1537 _ng_l2cap_echo_req(cmd->aux, cmd->ident,
1538 msg->data + sizeof(*ip), ip->echo_size);
1539 if (cmd->aux == NULL) {
1540 ng_l2cap_free_cmd(cmd);
1545 /* Link command to the queue */
1546 ng_l2cap_link_cmd(con, cmd);
1547 ng_l2cap_lp_deliver(con);
1550 } /* ng_l2cap_l2ca_ping_req */
1553 * Send L2CA_Ping response to the upper layer protocol
1557 ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result,
1560 ng_l2cap_p l2cap = con->l2cap;
1561 struct ng_mesg *msg = NULL;
1562 ng_l2cap_l2ca_ping_op *op = NULL;
1563 int error = 0, size = 0;
1565 /* Check if control hook is connected and valid */
1566 if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
1568 "%s: %s - unable to send L2CA_Ping response message. " \
1569 "Hook is not connected or valid\n",
1570 __func__, NG_NODE_NAME(l2cap->node));
1575 size = (data == NULL)? 0 : data->m_pkthdr.len;
1577 /* Create and send L2CA_Ping response message */
1578 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_PING,
1579 sizeof(*op) + size, M_NOWAIT);
1583 msg->header.token = token;
1584 msg->header.flags |= NGF_RESP;
1586 op = (ng_l2cap_l2ca_ping_op *)(msg->data);
1587 op->result = result;
1588 bcopy(&con->remote, &op->bdaddr, sizeof(op->bdaddr));
1589 if (data != NULL && size > 0) {
1590 op->echo_size = size;
1591 m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));
1594 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1600 } /* ng_l2cap_l2ca_ping_rsp */
1603 * Process L2CA_GetInfo request from the upper layer protocol
1607 ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1609 ng_l2cap_l2ca_get_info_ip *ip = NULL;
1610 ng_l2cap_con_p con = NULL;
1611 ng_l2cap_cmd_p cmd = NULL;
1614 /* Verify message */
1615 if (msg->header.arglen != sizeof(*ip)) {
1617 "%s: %s - invalid L2CA_GetInfo request message size, size=%d\n",
1618 __func__, NG_NODE_NAME(l2cap->node),
1619 msg->header.arglen);
1624 ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
1626 /* Check if we have connection to the unit */
1627 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr,ip->linktype);
1629 /* Submit LP_ConnectReq to the lower layer */
1630 error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);
1633 "%s: %s - unable to send LP_ConnectReq message, error=%d\n",
1634 __func__, NG_NODE_NAME(l2cap->node), error);
1638 /* This should not fail */
1639 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
1640 KASSERT((con != NULL),
1641 ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
1644 /* Create L2CAP command descriptor */
1645 cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),
1646 NG_L2CAP_INFO_REQ, msg->header.token);
1652 if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1653 ng_l2cap_free_cmd(cmd);
1658 /* Create L2CAP command packet */
1659 _ng_l2cap_info_req(cmd->aux, cmd->ident, ip->info_type);
1660 if (cmd->aux == NULL) {
1661 ng_l2cap_free_cmd(cmd);
1666 /* Link command to the queue */
1667 ng_l2cap_link_cmd(con, cmd);
1668 ng_l2cap_lp_deliver(con);
1671 } /* ng_l2cap_l2ca_get_info_req */
1674 * Send L2CA_GetInfo response to the upper layer protocol
1678 ng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con, u_int32_t token,
1679 u_int16_t result, struct mbuf *data)
1681 ng_l2cap_p l2cap = con->l2cap;
1682 struct ng_mesg *msg = NULL;
1683 ng_l2cap_l2ca_get_info_op *op = NULL;
1684 int error = 0, size;
1686 /* Check if control hook is connected and valid */
1687 if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
1689 "%s: %s - unable to send L2CA_GetInfo response message. " \
1690 "Hook is not connected or valid\n",
1691 __func__, NG_NODE_NAME(l2cap->node));
1696 size = (data == NULL)? 0 : data->m_pkthdr.len;
1698 /* Create and send L2CA_GetInfo response message */
1699 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_GET_INFO,
1700 sizeof(*op) + size, M_NOWAIT);
1704 msg->header.token = token;
1705 msg->header.flags |= NGF_RESP;
1707 op = (ng_l2cap_l2ca_get_info_op *)(msg->data);
1708 op->result = result;
1709 if (data != NULL && size > 0) {
1710 op->info_size = size;
1711 m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));
1714 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1720 } /* ng_l2cap_l2ca_get_info_rsp */
1723 * Process L2CA_EnableCLT message from the upper layer protocol
1724 * XXX convert to NGN_L2CAP_NODE_SET_FLAGS?
1728 ng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg)
1730 ng_l2cap_l2ca_enable_clt_ip *ip = NULL;
1733 * ng_l2cap_l2ca_enable_clt_op *op = NULL;
1739 if (msg->header.arglen != sizeof(*ip)) {
1741 "%s: %s - invalid L2CA_EnableCLT message size, size=%d\n",
1742 __func__, NG_NODE_NAME(l2cap->node),
1743 msg->header.arglen);
1748 /* Process request */
1749 ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data);
1751 * result = NG_L2CAP_SUCCESS;
1757 /* Special case: disable/enable all PSM */
1759 l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED |
1760 NG_L2CAP_CLT_RFCOMM_DISABLED |
1761 NG_L2CAP_CLT_TCP_DISABLED);
1763 l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED |
1764 NG_L2CAP_CLT_RFCOMM_DISABLED |
1765 NG_L2CAP_CLT_TCP_DISABLED);
1768 case NG_L2CAP_PSM_SDP:
1770 l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED;
1772 l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED;
1775 case NG_L2CAP_PSM_RFCOMM:
1777 l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED;
1779 l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED;
1782 case NG_L2CAP_PSM_TCP:
1784 l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED;
1786 l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED;
1791 "%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm);
1793 * result = NG_L2CAP_PSM_NOT_SUPPORTED;
1800 * /* Create and send response message */
1801 * token = msg->header.token;
1803 * NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT,
1804 * sizeof(*op), M_NOWAIT);
1808 * msg->header.token = token;
1809 * msg->header.flags |= NGF_RESP;
1811 * op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data);
1812 * op->result = result;
1815 * /* Send response to control hook */
1816 * if (l2cap->ctl != NULL && NG_HOOK_IS_VALID(l2cap->ctl))
1817 * NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1821 } /* ng_l2cap_l2ca_enable_clt */