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;
133 }else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
134 _ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_SMP_CID,
135 NG_L2CAP_SMP_CID, 0, 0);
136 cmd->aux->m_flags |= M_PROTO2;
138 _ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid);
140 if (cmd->aux == NULL) {
141 ng_l2cap_free_cmd(cmd);
142 ng_l2cap_free_chan(ch);
147 ch->state = NG_L2CAP_W4_L2CAP_CON_RSP;
149 /* Link command to the queue */
150 ng_l2cap_link_cmd(ch->con, cmd);
151 ng_l2cap_lp_deliver(ch->con);
154 } /* ng_l2cap_l2ca_con_req */
157 * Send L2CA_Connect response to the upper layer protocol.
161 ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
164 ng_l2cap_p l2cap = ch->con->l2cap;
165 struct ng_mesg *msg = NULL;
166 ng_l2cap_l2ca_con_op *op = NULL;
169 /* Check if upstream hook is connected and valid */
170 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
172 "%s: %s - unable to send L2CA_Connect response message. " \
173 "Hook is not connected or valid, psm=%d\n",
174 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
179 /* Create and send L2CA_Connect response message */
180 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON,
181 sizeof(*op), M_NOWAIT);
185 msg->header.token = token;
186 msg->header.flags |= NGF_RESP;
188 op = (ng_l2cap_l2ca_con_op *)(msg->data);
191 * XXX Spec. says we should only populate LCID when result == 0
192 * What about PENDING? What the heck, for now always populate
195 if(ch->scid == NG_L2CAP_ATT_CID){
196 op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
197 op->lcid = ch->con->con_handle;
198 }else if(ch->scid == NG_L2CAP_SMP_CID){
199 op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
200 op->lcid = ch->con->con_handle;
202 op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
203 NG_L2CAP_L2CA_IDTYPE_BREDR :
204 NG_L2CAP_L2CA_IDTYPE_LE;
207 op->encryption = ch->con->encryption;
211 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
215 } /* ng_l2cap_l2ca_con_rsp */
218 * Process L2CA_ConnectRsp request from the upper layer protocol.
222 ng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
224 ng_l2cap_l2ca_con_rsp_ip *ip = NULL;
225 ng_l2cap_con_p con = NULL;
226 ng_l2cap_chan_p ch = NULL;
227 ng_l2cap_cmd_p cmd = NULL;
232 if (msg->header.arglen != sizeof(*ip)) {
234 "%s: %s - invalid L2CA_ConnectRsp request message size, size=%d\n",
235 __func__, NG_NODE_NAME(l2cap->node),
241 ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data);
243 /* Check if we have this channel */
244 if((ip->lcid != NG_L2CAP_ATT_CID)&&
245 (ip->lcid != NG_L2CAP_SMP_CID)){
246 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid
247 ,(ip->linktype == NG_HCI_LINK_ACL)?
248 NG_L2CAP_L2CA_IDTYPE_BREDR:
249 NG_L2CAP_L2CA_IDTYPE_LE);
251 // For now not support on ATT device.
256 "%s: %s - unexpected L2CA_ConnectRsp request message. " \
257 "Channel does not exist, lcid=%d\n",
258 __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
263 /* Check channel state */
264 if (ch->state != NG_L2CAP_W4_L2CA_CON_RSP) {
266 "%s: %s - unexpected L2CA_ConnectRsp request message. " \
267 "Invalid channel state, state=%d, lcid=%d\n",
268 __func__, NG_NODE_NAME(l2cap->node), ch->state,
278 * Now we are pretty much sure it is our response. So create and send
279 * L2CAP_ConnectRsp message to our peer.
282 if (ch->ident != ip->ident)
284 "%s: %s - channel ident and response ident do not match, scid=%d, ident=%d. " \
285 "Will use response ident=%d\n",
286 __func__, NG_NODE_NAME(l2cap->node), ch->scid,
287 ch->ident, ip->ident);
290 switch (ip->result) {
291 case NG_L2CAP_SUCCESS:
292 ch->state = ((ch->scid == NG_L2CAP_ATT_CID)||
293 (ch->scid == NG_L2CAP_SMP_CID))?
294 NG_L2CAP_OPEN : NG_L2CAP_CONFIG;
298 case NG_L2CAP_PENDING:
302 ng_l2cap_free_chan(ch);
307 /* Create L2CAP command */
308 cmd = ng_l2cap_new_cmd(con, ch, ip->ident, NG_L2CAP_CON_RSP,
312 ng_l2cap_free_chan(ch);
318 _ng_l2cap_con_rsp(cmd->aux, cmd->ident, ip->lcid, dcid,
319 ip->result, ip->status);
320 if (cmd->aux == NULL) {
322 ng_l2cap_free_chan(ch);
324 ng_l2cap_free_cmd(cmd);
329 /* Link command to the queue */
330 ng_l2cap_link_cmd(con, cmd);
331 ng_l2cap_lp_deliver(con);
334 } /* ng_l2cap_l2ca_con_rsp_req */
336 int ng_l2cap_l2ca_encryption_change(ng_l2cap_chan_p ch, uint16_t result)
338 ng_l2cap_p l2cap = ch->con->l2cap;
339 struct ng_mesg *msg = NULL;
340 ng_l2cap_l2ca_enc_chg_op *op = NULL;
343 /* Check if upstream hook is connected and valid */
344 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
346 "%s: %s - unable to send L2CA_ConnectRsp response message. " \
347 "Hook is not connected or valid, psm=%d\n",
348 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
353 /* Create and send L2CA_ConnectRsp response message */
354 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENC_CHANGE,
355 sizeof(*op), M_NOWAIT);
359 msg->header.token = 0;
360 msg->header.flags |= NGF_RESP;
362 op = (ng_l2cap_l2ca_enc_chg_op *)(msg->data);
364 if(ch->scid ==NG_L2CAP_ATT_CID||
365 ch->scid ==NG_L2CAP_SMP_CID){
366 op->lcid = ch->con->con_handle;
367 op->idtype = (ch->scid==NG_L2CAP_ATT_CID)?
368 NG_L2CAP_L2CA_IDTYPE_ATT:
369 NG_L2CAP_L2CA_IDTYPE_SMP;
371 op->idtype =(ch->con->linktype ==NG_HCI_LINK_ACL)?
372 NG_L2CAP_L2CA_IDTYPE_BREDR:
373 NG_L2CAP_L2CA_IDTYPE_LE;
377 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
384 * Send L2CAP_ConnectRsp response to the upper layer
388 ng_l2cap_l2ca_con_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
390 ng_l2cap_p l2cap = ch->con->l2cap;
391 struct ng_mesg *msg = NULL;
392 ng_l2cap_l2ca_con_rsp_op *op = NULL;
395 /* Check if upstream hook is connected and valid */
396 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
398 "%s: %s - unable to send L2CA_ConnectRsp response message. " \
399 "Hook is not connected or valid, psm=%d\n",
400 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
405 /* Create and send L2CA_ConnectRsp response message */
406 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_RSP,
407 sizeof(*op), M_NOWAIT);
411 msg->header.token = token;
412 msg->header.flags |= NGF_RESP;
414 op = (ng_l2cap_l2ca_con_rsp_op *)(msg->data);
417 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
421 } /* ng_l2cap_l2ca_con_rsp_rsp */
424 * Send L2CA_ConnectInd message to the upper layer protocol.
428 ng_l2cap_l2ca_con_ind(ng_l2cap_chan_p ch)
430 ng_l2cap_p l2cap = ch->con->l2cap;
431 struct ng_mesg *msg = NULL;
432 ng_l2cap_l2ca_con_ind_ip *ip = NULL;
435 /* Check if upstream hook is connected and valid */
436 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
438 "%s: %s - unable to send L2CA_ConnectInd message. " \
439 "Hook is not connected or valid, psm=%d\n",
440 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
445 /* Create and send L2CA_ConnectInd message */
446 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_IND,
447 sizeof(*ip), M_NOWAIT);
451 ip = (ng_l2cap_l2ca_con_ind_ip *)(msg->data);
453 bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr));
456 ip->ident = ch->ident;
457 ip->linktype = ch->con->linktype;
459 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
463 } /* ng_l2cap_l2ca_con_ind */
466 * Process L2CA_Config request from the upper layer protocol
470 ng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
472 ng_l2cap_l2ca_cfg_ip *ip = NULL;
473 ng_l2cap_chan_p ch = NULL;
474 ng_l2cap_cmd_p cmd = NULL;
475 struct mbuf *opt = NULL;
476 u_int16_t *mtu = NULL, *flush_timo = NULL;
477 ng_l2cap_flow_p flow = NULL;
481 if (msg->header.arglen != sizeof(*ip)) {
483 "%s: %s - Invalid L2CA_Config request message size, size=%d\n",
484 __func__, NG_NODE_NAME(l2cap->node),
490 ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data);
492 /* Check if we have this channel */
493 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, NG_L2CAP_L2CA_IDTYPE_BREDR);
496 "%s: %s - unexpected L2CA_Config request message. " \
497 "Channel does not exist, lcid=%d\n",
498 __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
503 /* Check channel state */
504 if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG) {
506 "%s: %s - unexpected L2CA_Config request message. " \
507 "Invalid channel state, state=%d, lcid=%d\n",
508 __func__, NG_NODE_NAME(l2cap->node), ch->state,
514 /* Set requested channel configuration options */
516 bcopy(&ip->oflow, &ch->oflow, sizeof(ch->oflow));
517 ch->flush_timo = ip->flush_timo;
518 ch->link_timo = ip->link_timo;
520 /* Compare channel settings with defaults */
521 if (ch->imtu != NG_L2CAP_MTU_DEFAULT)
523 if (ch->flush_timo != NG_L2CAP_FLUSH_TIMO_DEFAULT)
524 flush_timo = &ch->flush_timo;
525 if (bcmp(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)) != 0)
528 /* Create configuration options */
529 _ng_l2cap_build_cfg_options(opt, mtu, flush_timo, flow);
535 /* Create L2CAP command descriptor */
536 cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con),
537 NG_L2CAP_CFG_REQ, msg->header.token);
544 if (cmd->ident == NG_L2CAP_NULL_IDENT) {
545 ng_l2cap_free_cmd(cmd);
551 /* Create L2CAP command packet */
552 _ng_l2cap_cfg_req(cmd->aux, cmd->ident, ch->dcid, 0, opt);
553 if (cmd->aux == NULL) {
554 ng_l2cap_free_cmd(cmd);
559 /* Adjust channel state for re-configuration */
560 if (ch->state == NG_L2CAP_OPEN) {
561 ch->state = ((ch->scid == NG_L2CAP_ATT_CID)||
562 (ch->scid == NG_L2CAP_SMP_CID))?
563 NG_L2CAP_OPEN : NG_L2CAP_CONFIG;
567 /* Link command to the queue */
568 ng_l2cap_link_cmd(ch->con, cmd);
569 ng_l2cap_lp_deliver(ch->con);
572 } /* ng_l2cap_l2ca_cfg_req */
575 * Send L2CA_Config response to the upper layer protocol
579 ng_l2cap_l2ca_cfg_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
581 ng_l2cap_p l2cap = ch->con->l2cap;
582 struct ng_mesg *msg = NULL;
583 ng_l2cap_l2ca_cfg_op *op = NULL;
586 /* Check if upstream hook is connected and valid */
587 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
589 "%s: %s - unable to send L2CA_Config response message. " \
590 "Hook is not connected or valid, psm=%d\n",
591 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
596 /* Create and send L2CA_Config response message */
597 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG,
598 sizeof(*op), M_NOWAIT);
602 msg->header.token = token;
603 msg->header.flags |= NGF_RESP;
605 op = (ng_l2cap_l2ca_cfg_op *)(msg->data);
608 bcopy(&ch->oflow, &op->oflow, sizeof(op->oflow));
609 op->flush_timo = ch->flush_timo;
611 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
613 if (error == 0 && result == NG_L2CAP_SUCCESS) {
614 ch->cfg_state |= NG_L2CAP_CFG_IN;
616 if (ch->cfg_state == NG_L2CAP_CFG_BOTH)
617 ch->state = NG_L2CAP_OPEN;
622 } /* ng_l2cap_l2ca_cfg_rsp */
625 * Process L2CA_ConfigRsp request from the upper layer protocol
629 * NOTE: The Bluetooth specification says that Configuration_Response
630 * (L2CA_ConfigRsp) should be used to issue response to configuration request
631 * indication. The minor problem here is L2CAP command ident. We should use
632 * ident from original L2CAP request to make sure our peer can match request
633 * and response. For some reason Bluetooth specification does not include
634 * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems
635 * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident
636 * field. So we should store last known L2CAP request command ident in channel.
637 * Also it seems that upper layer can not reject configuration request, as
638 * Configuration_Response message does not have status/reason field.
642 ng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
644 ng_l2cap_l2ca_cfg_rsp_ip *ip = NULL;
645 ng_l2cap_chan_p ch = NULL;
646 ng_l2cap_cmd_p cmd = NULL;
647 struct mbuf *opt = NULL;
648 u_int16_t *mtu = NULL;
649 ng_l2cap_flow_p flow = NULL;
653 if (msg->header.arglen != sizeof(*ip)) {
655 "%s: %s - invalid L2CA_ConfigRsp request message size, size=%d\n",
656 __func__, NG_NODE_NAME(l2cap->node),
662 ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data);
664 /* Check if we have this channel */
665 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid,
666 NG_L2CAP_L2CA_IDTYPE_BREDR);
669 "%s: %s - unexpected L2CA_ConfigRsp request message. " \
670 "Channel does not exist, lcid=%d\n",
671 __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
676 /* Check channel state */
677 if (ch->state != NG_L2CAP_CONFIG) {
679 "%s: %s - unexpected L2CA_ConfigRsp request message. " \
680 "Invalid channel state, state=%d, lcid=%d\n",
681 __func__, NG_NODE_NAME(l2cap->node), ch->state,
687 /* Set channel settings */
688 if (ip->omtu != ch->omtu) {
693 if (bcmp(&ip->iflow, &ch->iflow, sizeof(ch->iflow)) != 0) {
694 bcopy(&ip->iflow, &ch->iflow, sizeof(ch->iflow));
698 if (mtu != NULL || flow != NULL) {
699 _ng_l2cap_build_cfg_options(opt, mtu, NULL, flow);
706 /* Create L2CAP command */
707 cmd = ng_l2cap_new_cmd(ch->con, ch, ch->ident, NG_L2CAP_CFG_RSP,
715 _ng_l2cap_cfg_rsp(cmd->aux,cmd->ident,ch->dcid,0,NG_L2CAP_SUCCESS,opt);
716 if (cmd->aux == NULL) {
717 ng_l2cap_free_cmd(cmd);
722 /* XXX FIXME - not here ??? */
723 ch->cfg_state |= NG_L2CAP_CFG_OUT;
724 if (ch->cfg_state == NG_L2CAP_CFG_BOTH)
725 ch->state = NG_L2CAP_OPEN;
727 /* Link command to the queue */
728 ng_l2cap_link_cmd(ch->con, cmd);
729 ng_l2cap_lp_deliver(ch->con);
732 } /* ng_l2cap_l2ca_cfg_rsp_req */
735 * Send L2CA_ConfigRsp response to the upper layer protocol
739 ng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
741 ng_l2cap_p l2cap = ch->con->l2cap;
742 struct ng_mesg *msg = NULL;
743 ng_l2cap_l2ca_cfg_rsp_op *op = NULL;
746 /* Check if upstream hook is connected and valid */
747 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
749 "%s: %s - unable to send L2CA_ConfigRsp response message. " \
750 "Hook is not connected or valid, psm=%d\n",
751 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
756 /* Create and send L2CA_ConfigRsp response message */
757 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP,
758 sizeof(*op), M_NOWAIT);
762 msg->header.token = token;
763 msg->header.flags |= NGF_RESP;
765 op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data);
768 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
772 } /* ng_l2cap_l2ca_cfg_rsp_rsp */
775 * Send L2CA_ConfigInd message to the upper layer protocol
779 * NOTE: The Bluetooth specification says that Configuration_Response
780 * (L2CA_ConfigRsp) should be used to issue response to configuration request
781 * indication. The minor problem here is L2CAP command ident. We should use
782 * ident from original L2CAP request to make sure our peer can match request
783 * and response. For some reason Bluetooth specification does not include
784 * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems
785 * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident
786 * field. So we should store last known L2CAP request command ident in channel.
787 * Also it seems that upper layer can not reject configuration request, as
788 * Configuration_Response message does not have status/reason field.
792 ng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch)
794 ng_l2cap_p l2cap = ch->con->l2cap;
795 struct ng_mesg *msg = NULL;
796 ng_l2cap_l2ca_cfg_ind_ip *ip = NULL;
799 /* Check if upstream hook is connected and valid */
800 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
802 "%s: %s - Unable to send L2CA_ConfigInd message. " \
803 "Hook is not connected or valid, psm=%d\n",
804 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
809 /* Create and send L2CA_ConnectInd message */
810 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_IND,
811 sizeof(*ip), M_NOWAIT);
815 ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data);
818 bcopy(&ch->iflow, &ip->iflow, sizeof(ip->iflow));
819 ip->flush_timo = ch->flush_timo;
821 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
825 } /* ng_l2cap_l2ca_cfg_ind */
828 * Process L2CA_Write event
832 ng_l2cap_l2ca_write_req(ng_l2cap_p l2cap, struct mbuf *m)
834 ng_l2cap_l2ca_hdr_t *l2ca_hdr = NULL;
835 ng_l2cap_chan_p ch = NULL;
836 ng_l2cap_cmd_p cmd = NULL;
840 /* Make sure we can access L2CA data packet header */
841 if (m->m_pkthdr.len < sizeof(*l2ca_hdr)) {
843 "%s: %s - L2CA Data packet too small, len=%d\n",
844 __func__,NG_NODE_NAME(l2cap->node),m->m_pkthdr.len);
849 /* Get L2CA data packet header */
850 NG_L2CAP_M_PULLUP(m, sizeof(*l2ca_hdr));
854 l2ca_hdr = mtod(m, ng_l2cap_l2ca_hdr_t *);
855 token = l2ca_hdr->token;
856 m_adj(m, sizeof(*l2ca_hdr));
858 /* Verify payload size */
859 if (l2ca_hdr->length != m->m_pkthdr.len) {
861 "%s: %s - invalid L2CA Data packet. " \
862 "Payload length does not match, length=%d, len=%d\n",
863 __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->length,
869 /* Check channel ID */
870 if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
871 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
873 } else if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
874 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
877 if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) {
879 "%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n",
880 __func__, NG_NODE_NAME(l2cap->node),
886 /* Verify that we have the channel and make sure it is open */
887 ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid,
893 "%s: %s - invalid L2CA Data packet. Channel does not exist, cid=%d\n",
894 __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid);
899 if (ch->state != NG_L2CAP_OPEN) {
901 "%s: %s - invalid L2CA Data packet. Invalid channel state, scid=%d, state=%d\n",
902 __func__, NG_NODE_NAME(l2cap->node), ch->scid,
905 goto drop; /* XXX not always - re-configure */
908 /* Create L2CAP command descriptor */
909 cmd = ng_l2cap_new_cmd(ch->con, ch, 0, NGM_L2CAP_L2CA_WRITE, token);
915 /* Attach data packet and link command to the queue */
917 ng_l2cap_link_cmd(ch->con, cmd);
918 ng_l2cap_lp_deliver(ch->con);
925 } /* ng_l2cap_l2ca_write_req */
928 * Send L2CA_Write response
932 ng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result,
935 ng_l2cap_p l2cap = ch->con->l2cap;
936 struct ng_mesg *msg = NULL;
937 ng_l2cap_l2ca_write_op *op = NULL;
940 /* Check if upstream hook is connected and valid */
941 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
943 "%s: %s - unable to send L2CA_WriteRsp message. " \
944 "Hook is not connected or valid, psm=%d\n",
945 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
950 /* Create and send L2CA_WriteRsp message */
951 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_WRITE,
952 sizeof(*op), M_NOWAIT);
956 msg->header.token = token;
957 msg->header.flags |= NGF_RESP;
959 op = (ng_l2cap_l2ca_write_op *)(msg->data);
962 if(ch->scid == NG_L2CAP_ATT_CID){
963 op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
964 op->lcid = ch->con->con_handle;
965 }else if(ch->scid == NG_L2CAP_SMP_CID){
966 op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
967 op->lcid = ch->con->con_handle;
969 op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)?
970 NG_L2CAP_L2CA_IDTYPE_BREDR :
971 NG_L2CAP_L2CA_IDTYPE_LE;
975 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
979 } /* ng_l2cap_l2ca_write_rsp */
982 * Receive packet from the lower layer protocol and send it to the upper
983 * layer protocol (L2CAP_Read)
987 ng_l2cap_l2ca_receive(ng_l2cap_con_p con)
989 ng_l2cap_p l2cap = con->l2cap;
990 ng_l2cap_hdr_t *hdr = NULL;
991 ng_l2cap_chan_p ch = NULL;
997 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
998 if (con->rx_pkt == NULL)
1001 hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *);
1005 if(hdr->dcid == NG_L2CAP_ATT_CID){
1006 idtype = NG_L2CAP_L2CA_IDTYPE_ATT;
1007 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
1010 * Here,ATT channel is distinguished by
1013 hdr->dcid = con->con_handle;
1015 }else if(hdr->dcid == NG_L2CAP_SMP_CID){
1016 idtype = NG_L2CAP_L2CA_IDTYPE_SMP;
1017 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
1020 * Here,SMP channel is distinguished by
1024 hdr->dcid = con->con_handle;
1026 idtype = (con->linktype==NG_HCI_LINK_ACL)?
1027 NG_L2CAP_L2CA_IDTYPE_BREDR:
1028 NG_L2CAP_L2CA_IDTYPE_LE;
1029 ch = ng_l2cap_chan_by_scid(l2cap, hdr->dcid, idtype);
1034 "%s: %s - unexpected L2CAP data packet. Channel does not exist, cid=%d, idtype=%d\n",
1035 __func__, NG_NODE_NAME(l2cap->node), hdr->dcid, idtype);
1040 /* Check channel state */
1041 if (ch->state != NG_L2CAP_OPEN) {
1043 "%s: %s - unexpected L2CAP data packet. " \
1044 "Invalid channel state, cid=%d, state=%d\n",
1045 __func__, NG_NODE_NAME(l2cap->node), ch->scid,
1047 error = EHOSTDOWN; /* XXX not always - re-configuration */
1051 /* Check payload size and channel's MTU */
1052 if (hdr->length > ch->imtu) {
1054 "%s: %s - invalid L2CAP data packet. " \
1055 "Packet too big, length=%d, imtu=%d, cid=%d\n",
1056 __func__, NG_NODE_NAME(l2cap->node), hdr->length,
1057 ch->imtu, ch->scid);
1063 * If we got here then everything looks good and we can sent packet
1064 * to the upper layer protocol.
1067 /* Check if upstream hook is connected and valid */
1068 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1070 "%s: %s - unable to send L2CAP data packet. " \
1071 "Hook is not connected or valid, psm=%d\n",
1072 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
1076 M_PREPEND(con->rx_pkt, sizeof(uint16_t), M_NOWAIT);
1077 if(con->rx_pkt == NULL)
1079 idp = mtod(con->rx_pkt, uint16_t *);
1082 NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
1085 NG_FREE_M(con->rx_pkt); /* checks for != NULL */
1088 } /* ng_l2cap_receive */
1091 * Receive connectioless (multicast) packet from the lower layer protocol and
1092 * send it to the upper layer protocol
1096 ng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con)
1100 ng_l2cap_clt_hdr_t c_h;
1101 } __attribute__ ((packed)) *hdr = NULL;
1102 ng_l2cap_p l2cap = con->l2cap;
1103 int length, error = 0;
1105 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr));
1106 if (con->rx_pkt == NULL)
1109 hdr = mtod(con->rx_pkt, struct _clt_pkt *);
1112 length = con->rx_pkt->m_pkthdr.len - sizeof(*hdr);
1115 "%s: %s - invalid L2CAP CLT data packet. Packet too small, length=%d\n",
1116 __func__, NG_NODE_NAME(l2cap->node), length);
1121 /* Check payload size against CLT MTU */
1122 if (length > NG_L2CAP_MTU_DEFAULT) {
1124 "%s: %s - invalid L2CAP CLT data packet. Packet too big, length=%d, mtu=%d\n",
1125 __func__, NG_NODE_NAME(l2cap->node), length,
1126 NG_L2CAP_MTU_DEFAULT);
1131 hdr->c_h.psm = le16toh(hdr->c_h.psm);
1134 * If we got here then everything looks good and we can sent packet
1135 * to the upper layer protocol.
1138 /* Select upstream hook based on PSM */
1139 switch (hdr->c_h.psm) {
1140 case NG_L2CAP_PSM_SDP:
1141 if (l2cap->flags & NG_L2CAP_CLT_SDP_DISABLED)
1145 case NG_L2CAP_PSM_RFCOMM:
1146 if (l2cap->flags & NG_L2CAP_CLT_RFCOMM_DISABLED)
1150 case NG_L2CAP_PSM_TCP:
1151 if (l2cap->flags & NG_L2CAP_CLT_TCP_DISABLED)
1156 /* Check if upstream hook is connected and valid */
1157 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1159 "%s: %s - unable to send L2CAP CLT data packet. " \
1160 "Hook is not connected or valid, psm=%d\n",
1161 __func__, NG_NODE_NAME(l2cap->node), hdr->c_h.psm);
1166 NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt);
1169 NG_FREE_M(con->rx_pkt); /* checks for != NULL */
1172 } /* ng_l2cap_l2ca_clt_receive */
1175 * Send L2CA_QoSViolationInd to the upper layer protocol
1179 ng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch)
1181 ng_l2cap_p l2cap = ch->con->l2cap;
1182 struct ng_mesg *msg = NULL;
1183 ng_l2cap_l2ca_qos_ind_ip *ip = NULL;
1186 /* Check if upstream hook is connected and valid */
1187 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1189 "%s: %s - unable to send L2CA_QoSViolationInd message. " \
1190 "Hook is not connected or valid, psm=%d\n",
1191 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
1196 /* Create and send L2CA_QoSViolationInd message */
1197 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_QOS_IND,
1198 sizeof(*ip), M_NOWAIT);
1202 ip = (ng_l2cap_l2ca_qos_ind_ip *)(msg->data);
1203 bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr));
1204 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1208 } /* ng_l2cap_l2ca_qos_ind */
1211 * Process L2CA_Disconnect request from the upper layer protocol.
1215 ng_l2cap_l2ca_discon_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1217 ng_l2cap_l2ca_discon_ip *ip = NULL;
1218 ng_l2cap_chan_p ch = NULL;
1219 ng_l2cap_cmd_p cmd = NULL;
1223 if (msg->header.arglen != sizeof(*ip)) {
1225 "%s: %s - invalid L2CA_Disconnect request message size, size=%d\n",
1226 __func__, NG_NODE_NAME(l2cap->node),
1227 msg->header.arglen);
1232 ip = (ng_l2cap_l2ca_discon_ip *)(msg->data);
1235 if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){
1236 /* Don't send Disconnect request on L2CAP Layer*/
1237 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID,
1241 ng_l2cap_free_chan(ch);
1244 "%s: %s - unexpected L2CA_Disconnect request message. " \
1245 "Channel does not exist, conhandle=%d\n",
1246 __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1250 }else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){
1251 /* Don't send Disconnect request on L2CAP Layer*/
1252 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID,
1256 ng_l2cap_free_chan(ch);
1259 "%s: %s - unexpected L2CA_Disconnect request message. " \
1260 "Channel does not exist, conhandle=%d\n",
1261 __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1266 /* Check if we have this channel */
1267 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, ip->idtype);
1271 "%s: %s - unexpected L2CA_Disconnect request message. " \
1272 "Channel does not exist, lcid=%d\n",
1273 __func__, NG_NODE_NAME(l2cap->node), ip->lcid);
1278 /* Check channel state */
1279 if (ch->state != NG_L2CAP_CONFIG && ch->state != NG_L2CAP_OPEN &&
1280 ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) {
1282 "%s: %s - unexpected L2CA_Disconnect request message. " \
1283 "Invalid channel state, state=%d, lcid=%d\n",
1284 __func__, NG_NODE_NAME(l2cap->node), ch->state,
1290 /* Create and send L2CAP_DisconReq message */
1291 cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con),
1292 NG_L2CAP_DISCON_REQ, msg->header.token);
1294 ng_l2cap_free_chan(ch);
1299 if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1300 ng_l2cap_free_chan(ch);
1301 ng_l2cap_free_cmd(cmd);
1306 _ng_l2cap_discon_req(cmd->aux, cmd->ident, ch->dcid, ch->scid);
1307 if (cmd->aux == NULL) {
1308 ng_l2cap_free_chan(ch);
1309 ng_l2cap_free_cmd(cmd);
1314 ch->state = NG_L2CAP_W4_L2CAP_DISCON_RSP;
1316 /* Link command to the queue */
1317 ng_l2cap_link_cmd(ch->con, cmd);
1318 ng_l2cap_lp_deliver(ch->con);
1321 } /* ng_l2cap_l2ca_discon_req */
1324 * Send L2CA_Disconnect response to the upper layer protocol
1328 ng_l2cap_l2ca_discon_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result)
1330 ng_l2cap_p l2cap = ch->con->l2cap;
1331 struct ng_mesg *msg = NULL;
1332 ng_l2cap_l2ca_discon_op *op = NULL;
1335 /* Check if upstream hook is connected and valid */
1336 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1338 "%s: %s - unable to send L2CA_Disconnect response message. " \
1339 "Hook is not connected or valid, psm=%d\n",
1340 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
1345 /* Create and send L2CA_Disconnect response message */
1346 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON,
1347 sizeof(*op), M_NOWAIT);
1351 msg->header.token = token;
1352 msg->header.flags |= NGF_RESP;
1354 op = (ng_l2cap_l2ca_discon_op *)(msg->data);
1355 op->result = result;
1357 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1361 } /* ng_l2cap_l2ca_discon_rsp */
1364 * Send L2CA_DisconnectInd message to the upper layer protocol.
1368 ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch)
1370 ng_l2cap_p l2cap = ch->con->l2cap;
1371 struct ng_mesg *msg = NULL;
1372 ng_l2cap_l2ca_discon_ind_ip *ip = NULL;
1375 /* Check if upstream hook is connected and valid */
1376 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) {
1378 "%s: %s - unable to send L2CA_DisconnectInd message. " \
1379 "Hook is not connected or valid, psm=%d\n",
1380 __func__, NG_NODE_NAME(l2cap->node), ch->psm);
1385 /* Create and send L2CA_DisconnectInd message */
1386 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND,
1387 sizeof(*ip), M_NOWAIT);
1391 ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data);
1392 ip->idtype = ch->idtype;
1393 if(ch->idtype == NG_L2CAP_L2CA_IDTYPE_ATT||
1394 ch->idtype == NG_L2CAP_L2CA_IDTYPE_SMP)
1395 ip->lcid = ch->con->con_handle;
1397 ip->lcid = ch->scid;
1399 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0);
1403 } /* ng_l2cap_l2ca_discon_ind */
1406 * Process L2CA_GroupCreate request from the upper layer protocol.
1411 ng_l2cap_l2ca_grp_create(ng_l2cap_p l2cap, struct ng_mesg *msg)
1414 } /* ng_l2cap_l2ca_grp_create */
1417 * Process L2CA_GroupClose request from the upper layer protocol
1422 ng_l2cap_l2ca_grp_close(ng_l2cap_p l2cap, struct ng_mesg *msg)
1425 } /* ng_l2cap_l2ca_grp_close */
1428 * Process L2CA_GroupAddMember request from the upper layer protocol.
1433 ng_l2cap_l2ca_grp_add_member_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1436 } /* ng_l2cap_l2ca_grp_add_member_req */
1439 * Send L2CA_GroupAddMember response to the upper layer protocol.
1444 ng_l2cap_l2ca_grp_add_member_rsp(ng_l2cap_chan_p ch, u_int32_t token,
1448 } /* ng_l2cap_l2ca_grp_add_member_rsp */
1451 * Process L2CA_GroupDeleteMember request from the upper layer protocol
1456 ng_l2cap_l2ca_grp_rem_member(ng_l2cap_p l2cap, struct ng_mesg *msg)
1459 } /* ng_l2cap_l2ca_grp_rem_member */
1462 * Process L2CA_GroupGetMembers request from the upper layer protocol
1467 ng_l2cap_l2ca_grp_get_members(ng_l2cap_p l2cap, struct ng_mesg *msg)
1470 } /* ng_l2cap_l2ca_grp_get_members */
1473 * Process L2CA_Ping request from the upper layer protocol
1477 ng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1479 ng_l2cap_l2ca_ping_ip *ip = NULL;
1480 ng_l2cap_con_p con = NULL;
1481 ng_l2cap_cmd_p cmd = NULL;
1484 /* Verify message */
1485 if (msg->header.arglen < sizeof(*ip)) {
1487 "%s: %s - invalid L2CA_Ping request message size, size=%d\n",
1488 __func__, NG_NODE_NAME(l2cap->node),
1489 msg->header.arglen);
1494 ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);
1495 if (ip->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
1497 "%s: %s - invalid L2CA_Ping request. Echo size is too big, echo_size=%d\n",
1498 __func__, NG_NODE_NAME(l2cap->node), ip->echo_size);
1503 /* Check if we have connection to the unit */
1504 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1506 /* Submit LP_ConnectReq to the lower layer */
1507 error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1510 "%s: %s - unable to send LP_ConnectReq message, error=%d\n",
1511 __func__, NG_NODE_NAME(l2cap->node), error);
1515 /* This should not fail */
1516 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL);
1517 KASSERT((con != NULL),
1518 ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
1521 /* Create L2CAP command descriptor */
1522 cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),
1523 NG_L2CAP_ECHO_REQ, msg->header.token);
1529 if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1530 ng_l2cap_free_cmd(cmd);
1535 /* Create L2CAP command packet */
1536 _ng_l2cap_echo_req(cmd->aux, cmd->ident,
1537 msg->data + sizeof(*ip), ip->echo_size);
1538 if (cmd->aux == NULL) {
1539 ng_l2cap_free_cmd(cmd);
1544 /* Link command to the queue */
1545 ng_l2cap_link_cmd(con, cmd);
1546 ng_l2cap_lp_deliver(con);
1549 } /* ng_l2cap_l2ca_ping_req */
1552 * Send L2CA_Ping response to the upper layer protocol
1556 ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result,
1559 ng_l2cap_p l2cap = con->l2cap;
1560 struct ng_mesg *msg = NULL;
1561 ng_l2cap_l2ca_ping_op *op = NULL;
1562 int error = 0, size = 0;
1564 /* Check if control hook is connected and valid */
1565 if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
1567 "%s: %s - unable to send L2CA_Ping response message. " \
1568 "Hook is not connected or valid\n",
1569 __func__, NG_NODE_NAME(l2cap->node));
1574 size = (data == NULL)? 0 : data->m_pkthdr.len;
1576 /* Create and send L2CA_Ping response message */
1577 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_PING,
1578 sizeof(*op) + size, M_NOWAIT);
1582 msg->header.token = token;
1583 msg->header.flags |= NGF_RESP;
1585 op = (ng_l2cap_l2ca_ping_op *)(msg->data);
1586 op->result = result;
1587 bcopy(&con->remote, &op->bdaddr, sizeof(op->bdaddr));
1588 if (data != NULL && size > 0) {
1589 op->echo_size = size;
1590 m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));
1593 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1599 } /* ng_l2cap_l2ca_ping_rsp */
1602 * Process L2CA_GetInfo request from the upper layer protocol
1606 ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg)
1608 ng_l2cap_l2ca_get_info_ip *ip = NULL;
1609 ng_l2cap_con_p con = NULL;
1610 ng_l2cap_cmd_p cmd = NULL;
1613 /* Verify message */
1614 if (msg->header.arglen != sizeof(*ip)) {
1616 "%s: %s - invalid L2CA_GetInfo request message size, size=%d\n",
1617 __func__, NG_NODE_NAME(l2cap->node),
1618 msg->header.arglen);
1623 ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
1625 /* Check if we have connection to the unit */
1626 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr,ip->linktype);
1628 /* Submit LP_ConnectReq to the lower layer */
1629 error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype);
1632 "%s: %s - unable to send LP_ConnectReq message, error=%d\n",
1633 __func__, NG_NODE_NAME(l2cap->node), error);
1637 /* This should not fail */
1638 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype);
1639 KASSERT((con != NULL),
1640 ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node)));
1643 /* Create L2CAP command descriptor */
1644 cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con),
1645 NG_L2CAP_INFO_REQ, msg->header.token);
1651 if (cmd->ident == NG_L2CAP_NULL_IDENT) {
1652 ng_l2cap_free_cmd(cmd);
1657 /* Create L2CAP command packet */
1658 _ng_l2cap_info_req(cmd->aux, cmd->ident, ip->info_type);
1659 if (cmd->aux == NULL) {
1660 ng_l2cap_free_cmd(cmd);
1665 /* Link command to the queue */
1666 ng_l2cap_link_cmd(con, cmd);
1667 ng_l2cap_lp_deliver(con);
1670 } /* ng_l2cap_l2ca_get_info_req */
1673 * Send L2CA_GetInfo response to the upper layer protocol
1677 ng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con, u_int32_t token,
1678 u_int16_t result, struct mbuf *data)
1680 ng_l2cap_p l2cap = con->l2cap;
1681 struct ng_mesg *msg = NULL;
1682 ng_l2cap_l2ca_get_info_op *op = NULL;
1683 int error = 0, size;
1685 /* Check if control hook is connected and valid */
1686 if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) {
1688 "%s: %s - unable to send L2CA_GetInfo response message. " \
1689 "Hook is not connected or valid\n",
1690 __func__, NG_NODE_NAME(l2cap->node));
1695 size = (data == NULL)? 0 : data->m_pkthdr.len;
1697 /* Create and send L2CA_GetInfo response message */
1698 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_GET_INFO,
1699 sizeof(*op) + size, M_NOWAIT);
1703 msg->header.token = token;
1704 msg->header.flags |= NGF_RESP;
1706 op = (ng_l2cap_l2ca_get_info_op *)(msg->data);
1707 op->result = result;
1708 if (data != NULL && size > 0) {
1709 op->info_size = size;
1710 m_copydata(data, 0, size, (caddr_t) op + sizeof(*op));
1713 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1719 } /* ng_l2cap_l2ca_get_info_rsp */
1722 * Process L2CA_EnableCLT message from the upper layer protocol
1723 * XXX convert to NGN_L2CAP_NODE_SET_FLAGS?
1727 ng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg)
1729 ng_l2cap_l2ca_enable_clt_ip *ip = NULL;
1732 * ng_l2cap_l2ca_enable_clt_op *op = NULL;
1738 if (msg->header.arglen != sizeof(*ip)) {
1740 "%s: %s - invalid L2CA_EnableCLT message size, size=%d\n",
1741 __func__, NG_NODE_NAME(l2cap->node),
1742 msg->header.arglen);
1747 /* Process request */
1748 ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data);
1750 * result = NG_L2CAP_SUCCESS;
1756 /* Special case: disable/enable all PSM */
1758 l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED |
1759 NG_L2CAP_CLT_RFCOMM_DISABLED |
1760 NG_L2CAP_CLT_TCP_DISABLED);
1762 l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED |
1763 NG_L2CAP_CLT_RFCOMM_DISABLED |
1764 NG_L2CAP_CLT_TCP_DISABLED);
1767 case NG_L2CAP_PSM_SDP:
1769 l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED;
1771 l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED;
1774 case NG_L2CAP_PSM_RFCOMM:
1776 l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED;
1778 l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED;
1781 case NG_L2CAP_PSM_TCP:
1783 l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED;
1785 l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED;
1790 "%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm);
1792 * result = NG_L2CAP_PSM_NOT_SUPPORTED;
1799 * /* Create and send response message */
1800 * token = msg->header.token;
1802 * NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT,
1803 * sizeof(*op), M_NOWAIT);
1807 * msg->header.token = token;
1808 * msg->header.flags |= NGF_RESP;
1810 * op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data);
1811 * op->result = result;
1814 * /* Send response to control hook */
1815 * if (l2cap->ctl != NULL && NG_HOOK_IS_VALID(l2cap->ctl))
1816 * NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0);
1820 } /* ng_l2cap_l2ca_enable_clt */