1 /* 2 * ng_l2cap_ulpi.c 3 */ 4 5 /*- 6 * SPDX-License-Identifier: BSD-2-Clause 7 * 8 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: ng_l2cap_ulpi.c,v 1.1 2002/11/24 19:47:06 max Exp $ 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/endian.h> 39 #include <sys/malloc.h> 40 #include <sys/mbuf.h> 41 #include <sys/queue.h> 42 #include <netgraph/ng_message.h> 43 #include <netgraph/netgraph.h> 44 #include <netgraph/bluetooth/include/ng_hci.h> 45 #include <netgraph/bluetooth/include/ng_l2cap.h> 46 #include <netgraph/bluetooth/l2cap/ng_l2cap_var.h> 47 #include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h> 48 #include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h> 49 #include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h> 50 #include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h> 51 #include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h> 52 53 /****************************************************************************** 54 ****************************************************************************** 55 ** Upper Layer Protocol Interface module 56 ****************************************************************************** 57 ******************************************************************************/ 58 59 /* 60 * Process L2CA_Connect request from the upper layer protocol. 61 */ 62 63 int 64 ng_l2cap_l2ca_con_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 65 { 66 ng_l2cap_l2ca_con_ip *ip = NULL; 67 ng_l2cap_con_p con = NULL; 68 ng_l2cap_chan_p ch = NULL; 69 ng_l2cap_cmd_p cmd = NULL; 70 int error = 0; 71 72 /* Check message */ 73 if (msg->header.arglen != sizeof(*ip)) { 74 NG_L2CAP_ALERT( 75 "%s: %s - invalid L2CA_Connect request message size, size=%d\n", 76 __func__, NG_NODE_NAME(l2cap->node), 77 msg->header.arglen); 78 error = EMSGSIZE; 79 goto out; 80 } 81 82 ip = (ng_l2cap_l2ca_con_ip *)(msg->data); 83 84 /* Check if we have connection to the remote unit */ 85 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype); 86 if (con == NULL) { 87 /* Submit LP_ConnectReq to the lower layer */ 88 error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype); 89 if (error != 0) { 90 NG_L2CAP_ERR( 91 "%s: %s - unable to send LP_ConnectReq message, error=%d\n", 92 __func__, NG_NODE_NAME(l2cap->node), error); 93 goto out; 94 } 95 96 /* This should not fail */ 97 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype); 98 KASSERT((con != NULL), 99 ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node))); 100 } 101 102 /* 103 * Create new empty channel descriptor. In case of any failure do 104 * not touch connection descriptor. 105 */ 106 107 ch = ng_l2cap_new_chan(l2cap, con, ip->psm, ip->idtype); 108 if (ch == NULL) { 109 error = ENOMEM; 110 goto out; 111 } 112 113 /* Now create L2CAP_ConnectReq command */ 114 cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(con), 115 NG_L2CAP_CON_REQ, msg->header.token); 116 if (cmd == NULL) { 117 ng_l2cap_free_chan(ch); 118 error = ENOMEM; 119 goto out; 120 } 121 122 if (cmd->ident == NG_L2CAP_NULL_IDENT) { 123 ng_l2cap_free_cmd(cmd); 124 ng_l2cap_free_chan(ch); 125 error = EIO; 126 goto out; 127 } 128 129 /* Create L2CAP command packet */ 130 if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){ 131 _ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_ATT_CID, 132 NG_L2CAP_ATT_CID, 0, 0); 133 cmd->aux->m_flags |= M_PROTO2; 134 }else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){ 135 _ng_l2cap_con_rsp(cmd->aux, cmd->ident, NG_L2CAP_SMP_CID, 136 NG_L2CAP_SMP_CID, 0, 0); 137 cmd->aux->m_flags |= M_PROTO2; 138 }else{ 139 _ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid); 140 } 141 if (cmd->aux == NULL) { 142 ng_l2cap_free_cmd(cmd); 143 ng_l2cap_free_chan(ch); 144 error = ENOBUFS; 145 goto out; 146 } 147 148 ch->state = NG_L2CAP_W4_L2CAP_CON_RSP; 149 150 /* Link command to the queue */ 151 ng_l2cap_link_cmd(ch->con, cmd); 152 ng_l2cap_lp_deliver(ch->con); 153 out: 154 return (error); 155 } /* ng_l2cap_l2ca_con_req */ 156 157 /* 158 * Send L2CA_Connect response to the upper layer protocol. 159 */ 160 161 int 162 ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result, 163 u_int16_t status) 164 { 165 ng_l2cap_p l2cap = ch->con->l2cap; 166 struct ng_mesg *msg = NULL; 167 ng_l2cap_l2ca_con_op *op = NULL; 168 int error = 0; 169 170 /* Check if upstream hook is connected and valid */ 171 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 172 NG_L2CAP_ERR( 173 "%s: %s - unable to send L2CA_Connect response message. " \ 174 "Hook is not connected or valid, psm=%d\n", 175 __func__, NG_NODE_NAME(l2cap->node), ch->psm); 176 177 return (ENOTCONN); 178 } 179 180 /* Create and send L2CA_Connect response message */ 181 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON, 182 sizeof(*op), M_NOWAIT); 183 if (msg == NULL) 184 error = ENOMEM; 185 else { 186 msg->header.token = token; 187 msg->header.flags |= NGF_RESP; 188 189 op = (ng_l2cap_l2ca_con_op *)(msg->data); 190 191 /* 192 * XXX Spec. says we should only populate LCID when result == 0 193 * What about PENDING? What the heck, for now always populate 194 * LCID :) 195 */ 196 if(ch->scid == NG_L2CAP_ATT_CID){ 197 op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT; 198 op->lcid = ch->con->con_handle; 199 }else if(ch->scid == NG_L2CAP_SMP_CID){ 200 op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP; 201 op->lcid = ch->con->con_handle; 202 }else{ 203 op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)? 204 NG_L2CAP_L2CA_IDTYPE_BREDR : 205 NG_L2CAP_L2CA_IDTYPE_LE; 206 op->lcid = ch->scid; 207 } 208 op->encryption = ch->con->encryption; 209 op->result = result; 210 op->status = status; 211 212 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 213 } 214 215 return (error); 216 } /* ng_l2cap_l2ca_con_rsp */ 217 218 /* 219 * Process L2CA_ConnectRsp request from the upper layer protocol. 220 */ 221 222 int 223 ng_l2cap_l2ca_con_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 224 { 225 ng_l2cap_l2ca_con_rsp_ip *ip = NULL; 226 ng_l2cap_con_p con = NULL; 227 ng_l2cap_chan_p ch = NULL; 228 ng_l2cap_cmd_p cmd = NULL; 229 u_int16_t dcid; 230 int error = 0; 231 232 /* Check message */ 233 if (msg->header.arglen != sizeof(*ip)) { 234 NG_L2CAP_ALERT( 235 "%s: %s - invalid L2CA_ConnectRsp request message size, size=%d\n", 236 __func__, NG_NODE_NAME(l2cap->node), 237 msg->header.arglen); 238 error = EMSGSIZE; 239 goto out; 240 } 241 242 ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data); 243 244 /* Check if we have this channel */ 245 if((ip->lcid != NG_L2CAP_ATT_CID)&& 246 (ip->lcid != NG_L2CAP_SMP_CID)){ 247 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid 248 ,(ip->linktype == NG_HCI_LINK_ACL)? 249 NG_L2CAP_L2CA_IDTYPE_BREDR: 250 NG_L2CAP_L2CA_IDTYPE_LE); 251 }else{ 252 // For now not support on ATT device. 253 ch = NULL; 254 } 255 if (ch == NULL) { 256 NG_L2CAP_ALERT( 257 "%s: %s - unexpected L2CA_ConnectRsp request message. " \ 258 "Channel does not exist, lcid=%d\n", 259 __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 260 error = ENOENT; 261 goto out; 262 } 263 264 /* Check channel state */ 265 if (ch->state != NG_L2CAP_W4_L2CA_CON_RSP) { 266 NG_L2CAP_ERR( 267 "%s: %s - unexpected L2CA_ConnectRsp request message. " \ 268 "Invalid channel state, state=%d, lcid=%d\n", 269 __func__, NG_NODE_NAME(l2cap->node), ch->state, 270 ip->lcid); 271 error = EINVAL; 272 goto out; 273 } 274 275 dcid = ch->dcid; 276 con = ch->con; 277 278 /* 279 * Now we are pretty much sure it is our response. So create and send 280 * L2CAP_ConnectRsp message to our peer. 281 */ 282 283 if (ch->ident != ip->ident) 284 NG_L2CAP_WARN( 285 "%s: %s - channel ident and response ident do not match, scid=%d, ident=%d. " \ 286 "Will use response ident=%d\n", 287 __func__, NG_NODE_NAME(l2cap->node), ch->scid, 288 ch->ident, ip->ident); 289 290 /* Check result */ 291 switch (ip->result) { 292 case NG_L2CAP_SUCCESS: 293 ch->state = ((ch->scid == NG_L2CAP_ATT_CID)|| 294 (ch->scid == NG_L2CAP_SMP_CID))? 295 NG_L2CAP_OPEN : NG_L2CAP_CONFIG; 296 ch->cfg_state = 0; 297 break; 298 299 case NG_L2CAP_PENDING: 300 break; 301 302 default: 303 ng_l2cap_free_chan(ch); 304 ch = NULL; 305 break; 306 } 307 308 /* Create L2CAP command */ 309 cmd = ng_l2cap_new_cmd(con, ch, ip->ident, NG_L2CAP_CON_RSP, 310 msg->header.token); 311 if (cmd == NULL) { 312 if (ch != NULL) 313 ng_l2cap_free_chan(ch); 314 315 error = ENOMEM; 316 goto out; 317 } 318 319 _ng_l2cap_con_rsp(cmd->aux, cmd->ident, ip->lcid, dcid, 320 ip->result, ip->status); 321 if (cmd->aux == NULL) { 322 if (ch != NULL) 323 ng_l2cap_free_chan(ch); 324 325 ng_l2cap_free_cmd(cmd); 326 error = ENOBUFS; 327 goto out; 328 } 329 330 /* Link command to the queue */ 331 ng_l2cap_link_cmd(con, cmd); 332 ng_l2cap_lp_deliver(con); 333 out: 334 return (error); 335 } /* ng_l2cap_l2ca_con_rsp_req */ 336 337 int ng_l2cap_l2ca_encryption_change(ng_l2cap_chan_p ch, uint16_t result) 338 { 339 ng_l2cap_p l2cap = ch->con->l2cap; 340 struct ng_mesg *msg = NULL; 341 ng_l2cap_l2ca_enc_chg_op *op = NULL; 342 int error = 0; 343 344 /* Check if upstream hook is connected and valid */ 345 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 346 NG_L2CAP_ERR( 347 "%s: %s - unable to send L2CA_ConnectRsp response message. " \ 348 "Hook is not connected or valid, psm=%d\n", 349 __func__, NG_NODE_NAME(l2cap->node), ch->psm); 350 351 return (ENOTCONN); 352 } 353 354 /* Create and send L2CA_ConnectRsp response message */ 355 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENC_CHANGE, 356 sizeof(*op), M_NOWAIT); 357 if (msg == NULL) 358 error = ENOMEM; 359 else { 360 msg->header.token = 0; 361 msg->header.flags |= NGF_RESP; 362 363 op = (ng_l2cap_l2ca_enc_chg_op *)(msg->data); 364 op->result = result; 365 if(ch->scid ==NG_L2CAP_ATT_CID|| 366 ch->scid ==NG_L2CAP_SMP_CID){ 367 op->lcid = ch->con->con_handle; 368 op->idtype = (ch->scid==NG_L2CAP_ATT_CID)? 369 NG_L2CAP_L2CA_IDTYPE_ATT: 370 NG_L2CAP_L2CA_IDTYPE_SMP; 371 }else{ 372 op->idtype =(ch->con->linktype ==NG_HCI_LINK_ACL)? 373 NG_L2CAP_L2CA_IDTYPE_BREDR: 374 NG_L2CAP_L2CA_IDTYPE_LE; 375 } 376 377 378 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 379 } 380 381 return (error); 382 383 } 384 /* 385 * Send L2CAP_ConnectRsp response to the upper layer 386 */ 387 388 int 389 ng_l2cap_l2ca_con_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 390 { 391 ng_l2cap_p l2cap = ch->con->l2cap; 392 struct ng_mesg *msg = NULL; 393 ng_l2cap_l2ca_con_rsp_op *op = NULL; 394 int error = 0; 395 396 /* Check if upstream hook is connected and valid */ 397 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 398 NG_L2CAP_ERR( 399 "%s: %s - unable to send L2CA_ConnectRsp response message. " \ 400 "Hook is not connected or valid, psm=%d\n", 401 __func__, NG_NODE_NAME(l2cap->node), ch->psm); 402 403 return (ENOTCONN); 404 } 405 406 /* Create and send L2CA_ConnectRsp response message */ 407 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_RSP, 408 sizeof(*op), M_NOWAIT); 409 if (msg == NULL) 410 error = ENOMEM; 411 else { 412 msg->header.token = token; 413 msg->header.flags |= NGF_RESP; 414 415 op = (ng_l2cap_l2ca_con_rsp_op *)(msg->data); 416 op->result = result; 417 418 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 419 } 420 421 return (error); 422 } /* ng_l2cap_l2ca_con_rsp_rsp */ 423 424 /* 425 * Send L2CA_ConnectInd message to the upper layer protocol. 426 */ 427 428 int 429 ng_l2cap_l2ca_con_ind(ng_l2cap_chan_p ch) 430 { 431 ng_l2cap_p l2cap = ch->con->l2cap; 432 struct ng_mesg *msg = NULL; 433 ng_l2cap_l2ca_con_ind_ip *ip = NULL; 434 int error = 0; 435 436 /* Check if upstream hook is connected and valid */ 437 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 438 NG_L2CAP_ERR( 439 "%s: %s - unable to send L2CA_ConnectInd message. " \ 440 "Hook is not connected or valid, psm=%d\n", 441 __func__, NG_NODE_NAME(l2cap->node), ch->psm); 442 443 return (ENOTCONN); 444 } 445 446 /* Create and send L2CA_ConnectInd message */ 447 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_IND, 448 sizeof(*ip), M_NOWAIT); 449 if (msg == NULL) 450 error = ENOMEM; 451 else { 452 ip = (ng_l2cap_l2ca_con_ind_ip *)(msg->data); 453 454 bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr)); 455 ip->lcid = ch->scid; 456 ip->psm = ch->psm; 457 ip->ident = ch->ident; 458 ip->linktype = ch->con->linktype; 459 460 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 461 } 462 463 return (error); 464 } /* ng_l2cap_l2ca_con_ind */ 465 466 /* 467 * Process L2CA_Config request from the upper layer protocol 468 */ 469 470 int 471 ng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 472 { 473 ng_l2cap_l2ca_cfg_ip *ip = NULL; 474 ng_l2cap_chan_p ch = NULL; 475 ng_l2cap_cmd_p cmd = NULL; 476 struct mbuf *opt = NULL; 477 u_int16_t *mtu = NULL, *flush_timo = NULL; 478 ng_l2cap_flow_p flow = NULL; 479 int error = 0; 480 481 /* Check message */ 482 if (msg->header.arglen != sizeof(*ip)) { 483 NG_L2CAP_ALERT( 484 "%s: %s - Invalid L2CA_Config request message size, size=%d\n", 485 __func__, NG_NODE_NAME(l2cap->node), 486 msg->header.arglen); 487 error = EMSGSIZE; 488 goto out; 489 } 490 491 ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data); 492 493 /* Check if we have this channel */ 494 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, NG_L2CAP_L2CA_IDTYPE_BREDR); 495 if (ch == NULL) { 496 NG_L2CAP_ERR( 497 "%s: %s - unexpected L2CA_Config request message. " \ 498 "Channel does not exist, lcid=%d\n", 499 __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 500 error = ENOENT; 501 goto out; 502 } 503 504 /* Check channel state */ 505 if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG) { 506 NG_L2CAP_ERR( 507 "%s: %s - unexpected L2CA_Config request message. " \ 508 "Invalid channel state, state=%d, lcid=%d\n", 509 __func__, NG_NODE_NAME(l2cap->node), ch->state, 510 ch->scid); 511 error = EINVAL; 512 goto out; 513 } 514 515 /* Set requested channel configuration options */ 516 ch->imtu = ip->imtu; 517 bcopy(&ip->oflow, &ch->oflow, sizeof(ch->oflow)); 518 ch->flush_timo = ip->flush_timo; 519 ch->link_timo = ip->link_timo; 520 521 /* Compare channel settings with defaults */ 522 if (ch->imtu != NG_L2CAP_MTU_DEFAULT) 523 mtu = &ch->imtu; 524 if (ch->flush_timo != NG_L2CAP_FLUSH_TIMO_DEFAULT) 525 flush_timo = &ch->flush_timo; 526 if (bcmp(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)) != 0) 527 flow = &ch->oflow; 528 529 /* Create configuration options */ 530 _ng_l2cap_build_cfg_options(opt, mtu, flush_timo, flow); 531 if (opt == NULL) { 532 error = ENOBUFS; 533 goto out; 534 } 535 536 /* Create L2CAP command descriptor */ 537 cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con), 538 NG_L2CAP_CFG_REQ, msg->header.token); 539 if (cmd == NULL) { 540 NG_FREE_M(opt); 541 error = ENOMEM; 542 goto out; 543 } 544 545 if (cmd->ident == NG_L2CAP_NULL_IDENT) { 546 ng_l2cap_free_cmd(cmd); 547 NG_FREE_M(opt); 548 error = EIO; 549 goto out; 550 } 551 552 /* Create L2CAP command packet */ 553 _ng_l2cap_cfg_req(cmd->aux, cmd->ident, ch->dcid, 0, opt); 554 if (cmd->aux == NULL) { 555 ng_l2cap_free_cmd(cmd); 556 error = ENOBUFS; 557 goto out; 558 } 559 560 /* Adjust channel state for re-configuration */ 561 if (ch->state == NG_L2CAP_OPEN) { 562 ch->state = ((ch->scid == NG_L2CAP_ATT_CID)|| 563 (ch->scid == NG_L2CAP_SMP_CID))? 564 NG_L2CAP_OPEN : NG_L2CAP_CONFIG; 565 ch->cfg_state = 0; 566 } 567 568 /* Link command to the queue */ 569 ng_l2cap_link_cmd(ch->con, cmd); 570 ng_l2cap_lp_deliver(ch->con); 571 out: 572 return (error); 573 } /* ng_l2cap_l2ca_cfg_req */ 574 575 /* 576 * Send L2CA_Config response to the upper layer protocol 577 */ 578 579 int 580 ng_l2cap_l2ca_cfg_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 581 { 582 ng_l2cap_p l2cap = ch->con->l2cap; 583 struct ng_mesg *msg = NULL; 584 ng_l2cap_l2ca_cfg_op *op = NULL; 585 int error = 0; 586 587 /* Check if upstream hook is connected and valid */ 588 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 589 NG_L2CAP_ERR( 590 "%s: %s - unable to send L2CA_Config response message. " \ 591 "Hook is not connected or valid, psm=%d\n", 592 __func__, NG_NODE_NAME(l2cap->node), ch->psm); 593 594 return (ENOTCONN); 595 } 596 597 /* Create and send L2CA_Config response message */ 598 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG, 599 sizeof(*op), M_NOWAIT); 600 if (msg == NULL) 601 error = ENOMEM; 602 else { 603 msg->header.token = token; 604 msg->header.flags |= NGF_RESP; 605 606 op = (ng_l2cap_l2ca_cfg_op *)(msg->data); 607 op->result = result; 608 op->imtu = ch->imtu; 609 bcopy(&ch->oflow, &op->oflow, sizeof(op->oflow)); 610 op->flush_timo = ch->flush_timo; 611 612 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 613 614 if (error == 0 && result == NG_L2CAP_SUCCESS) { 615 ch->cfg_state |= NG_L2CAP_CFG_IN; 616 617 if (ch->cfg_state == NG_L2CAP_CFG_BOTH) 618 ch->state = NG_L2CAP_OPEN; 619 } 620 } 621 622 return (error); 623 } /* ng_l2cap_l2ca_cfg_rsp */ 624 625 /* 626 * Process L2CA_ConfigRsp request from the upper layer protocol 627 * 628 * XXX XXX XXX 629 * 630 * NOTE: The Bluetooth specification says that Configuration_Response 631 * (L2CA_ConfigRsp) should be used to issue response to configuration request 632 * indication. The minor problem here is L2CAP command ident. We should use 633 * ident from original L2CAP request to make sure our peer can match request 634 * and response. For some reason Bluetooth specification does not include 635 * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems 636 * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident 637 * field. So we should store last known L2CAP request command ident in channel. 638 * Also it seems that upper layer can not reject configuration request, as 639 * Configuration_Response message does not have status/reason field. 640 */ 641 642 int 643 ng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 644 { 645 ng_l2cap_l2ca_cfg_rsp_ip *ip = NULL; 646 ng_l2cap_chan_p ch = NULL; 647 ng_l2cap_cmd_p cmd = NULL; 648 struct mbuf *opt = NULL; 649 u_int16_t *mtu = NULL; 650 ng_l2cap_flow_p flow = NULL; 651 int error = 0; 652 653 /* Check message */ 654 if (msg->header.arglen != sizeof(*ip)) { 655 NG_L2CAP_ALERT( 656 "%s: %s - invalid L2CA_ConfigRsp request message size, size=%d\n", 657 __func__, NG_NODE_NAME(l2cap->node), 658 msg->header.arglen); 659 error = EMSGSIZE; 660 goto out; 661 } 662 663 ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data); 664 665 /* Check if we have this channel */ 666 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, 667 NG_L2CAP_L2CA_IDTYPE_BREDR); 668 if (ch == NULL) { 669 NG_L2CAP_ERR( 670 "%s: %s - unexpected L2CA_ConfigRsp request message. " \ 671 "Channel does not exist, lcid=%d\n", 672 __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 673 error = ENOENT; 674 goto out; 675 } 676 677 /* Check channel state */ 678 if (ch->state != NG_L2CAP_CONFIG) { 679 NG_L2CAP_ERR( 680 "%s: %s - unexpected L2CA_ConfigRsp request message. " \ 681 "Invalid channel state, state=%d, lcid=%d\n", 682 __func__, NG_NODE_NAME(l2cap->node), ch->state, 683 ch->scid); 684 error = EINVAL; 685 goto out; 686 } 687 688 /* Set channel settings */ 689 if (ip->omtu != ch->omtu) { 690 ch->omtu = ip->omtu; 691 mtu = &ch->omtu; 692 } 693 694 if (bcmp(&ip->iflow, &ch->iflow, sizeof(ch->iflow)) != 0) { 695 bcopy(&ip->iflow, &ch->iflow, sizeof(ch->iflow)); 696 flow = &ch->iflow; 697 } 698 699 if (mtu != NULL || flow != NULL) { 700 _ng_l2cap_build_cfg_options(opt, mtu, NULL, flow); 701 if (opt == NULL) { 702 error = ENOBUFS; 703 goto out; 704 } 705 } 706 707 /* Create L2CAP command */ 708 cmd = ng_l2cap_new_cmd(ch->con, ch, ch->ident, NG_L2CAP_CFG_RSP, 709 msg->header.token); 710 if (cmd == NULL) { 711 NG_FREE_M(opt); 712 error = ENOMEM; 713 goto out; 714 } 715 716 _ng_l2cap_cfg_rsp(cmd->aux,cmd->ident,ch->dcid,0,NG_L2CAP_SUCCESS,opt); 717 if (cmd->aux == NULL) { 718 ng_l2cap_free_cmd(cmd); 719 error = ENOBUFS; 720 goto out; 721 } 722 723 /* XXX FIXME - not here ??? */ 724 ch->cfg_state |= NG_L2CAP_CFG_OUT; 725 if (ch->cfg_state == NG_L2CAP_CFG_BOTH) 726 ch->state = NG_L2CAP_OPEN; 727 728 /* Link command to the queue */ 729 ng_l2cap_link_cmd(ch->con, cmd); 730 ng_l2cap_lp_deliver(ch->con); 731 out: 732 return (error); 733 } /* ng_l2cap_l2ca_cfg_rsp_req */ 734 735 /* 736 * Send L2CA_ConfigRsp response to the upper layer protocol 737 */ 738 739 int 740 ng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 741 { 742 ng_l2cap_p l2cap = ch->con->l2cap; 743 struct ng_mesg *msg = NULL; 744 ng_l2cap_l2ca_cfg_rsp_op *op = NULL; 745 int error = 0; 746 747 /* Check if upstream hook is connected and valid */ 748 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 749 NG_L2CAP_ERR( 750 "%s: %s - unable to send L2CA_ConfigRsp response message. " \ 751 "Hook is not connected or valid, psm=%d\n", 752 __func__, NG_NODE_NAME(l2cap->node), ch->psm); 753 754 return (ENOTCONN); 755 } 756 757 /* Create and send L2CA_ConfigRsp response message */ 758 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP, 759 sizeof(*op), M_NOWAIT); 760 if (msg == NULL) 761 error = ENOMEM; 762 else { 763 msg->header.token = token; 764 msg->header.flags |= NGF_RESP; 765 766 op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data); 767 op->result = result; 768 769 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 770 } 771 772 return (error); 773 } /* ng_l2cap_l2ca_cfg_rsp_rsp */ 774 775 /* 776 * Send L2CA_ConfigInd message to the upper layer protocol 777 * 778 * XXX XXX XXX 779 * 780 * NOTE: The Bluetooth specification says that Configuration_Response 781 * (L2CA_ConfigRsp) should be used to issue response to configuration request 782 * indication. The minor problem here is L2CAP command ident. We should use 783 * ident from original L2CAP request to make sure our peer can match request 784 * and response. For some reason Bluetooth specification does not include 785 * ident field into L2CA_ConfigInd and L2CA_ConfigRsp messages. This seems 786 * strange to me, because L2CA_ConnectInd and L2CA_ConnectRsp do have ident 787 * field. So we should store last known L2CAP request command ident in channel. 788 * Also it seems that upper layer can not reject configuration request, as 789 * Configuration_Response message does not have status/reason field. 790 */ 791 792 int 793 ng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch) 794 { 795 ng_l2cap_p l2cap = ch->con->l2cap; 796 struct ng_mesg *msg = NULL; 797 ng_l2cap_l2ca_cfg_ind_ip *ip = NULL; 798 int error = 0; 799 800 /* Check if upstream hook is connected and valid */ 801 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 802 NG_L2CAP_ERR( 803 "%s: %s - Unable to send L2CA_ConfigInd message. " \ 804 "Hook is not connected or valid, psm=%d\n", 805 __func__, NG_NODE_NAME(l2cap->node), ch->psm); 806 807 return (ENOTCONN); 808 } 809 810 /* Create and send L2CA_ConnectInd message */ 811 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_IND, 812 sizeof(*ip), M_NOWAIT); 813 if (msg == NULL) 814 error = ENOMEM; 815 else { 816 ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data); 817 ip->lcid = ch->scid; 818 ip->omtu = ch->omtu; 819 bcopy(&ch->iflow, &ip->iflow, sizeof(ip->iflow)); 820 ip->flush_timo = ch->flush_timo; 821 822 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 823 } 824 825 return (error); 826 } /* ng_l2cap_l2ca_cfg_ind */ 827 828 /* 829 * Process L2CA_Write event 830 */ 831 832 int 833 ng_l2cap_l2ca_write_req(ng_l2cap_p l2cap, struct mbuf *m) 834 { 835 ng_l2cap_l2ca_hdr_t *l2ca_hdr = NULL; 836 ng_l2cap_chan_p ch = NULL; 837 ng_l2cap_cmd_p cmd = NULL; 838 int error = 0; 839 u_int32_t token = 0; 840 841 /* Make sure we can access L2CA data packet header */ 842 if (m->m_pkthdr.len < sizeof(*l2ca_hdr)) { 843 NG_L2CAP_ERR( 844 "%s: %s - L2CA Data packet too small, len=%d\n", 845 __func__,NG_NODE_NAME(l2cap->node),m->m_pkthdr.len); 846 error = EMSGSIZE; 847 goto drop; 848 } 849 850 /* Get L2CA data packet header */ 851 NG_L2CAP_M_PULLUP(m, sizeof(*l2ca_hdr)); 852 if (m == NULL) 853 return (ENOBUFS); 854 855 l2ca_hdr = mtod(m, ng_l2cap_l2ca_hdr_t *); 856 token = l2ca_hdr->token; 857 m_adj(m, sizeof(*l2ca_hdr)); 858 859 /* Verify payload size */ 860 if (l2ca_hdr->length != m->m_pkthdr.len) { 861 NG_L2CAP_ERR( 862 "%s: %s - invalid L2CA Data packet. " \ 863 "Payload length does not match, length=%d, len=%d\n", 864 __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->length, 865 m->m_pkthdr.len); 866 error = EMSGSIZE; 867 goto drop; 868 } 869 870 /* Check channel ID */ 871 if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){ 872 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID, 873 l2ca_hdr->lcid); 874 } else if (l2ca_hdr->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){ 875 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID, 876 l2ca_hdr->lcid); 877 }else{ 878 if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) { 879 NG_L2CAP_ERR( 880 "%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n", 881 __func__, NG_NODE_NAME(l2cap->node), 882 l2ca_hdr->lcid); 883 error = EINVAL; 884 goto drop; 885 } 886 887 /* Verify that we have the channel and make sure it is open */ 888 ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid, 889 l2ca_hdr->idtype); 890 } 891 892 if (ch == NULL) { 893 NG_L2CAP_ERR( 894 "%s: %s - invalid L2CA Data packet. Channel does not exist, cid=%d\n", 895 __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid); 896 error = ENOENT; 897 goto drop; 898 } 899 900 if (ch->state != NG_L2CAP_OPEN) { 901 NG_L2CAP_ERR( 902 "%s: %s - invalid L2CA Data packet. Invalid channel state, scid=%d, state=%d\n", 903 __func__, NG_NODE_NAME(l2cap->node), ch->scid, 904 ch->state); 905 error = EHOSTDOWN; 906 goto drop; /* XXX not always - re-configure */ 907 } 908 909 /* Create L2CAP command descriptor */ 910 cmd = ng_l2cap_new_cmd(ch->con, ch, 0, NGM_L2CAP_L2CA_WRITE, token); 911 if (cmd == NULL) { 912 error = ENOMEM; 913 goto drop; 914 } 915 916 /* Attach data packet and link command to the queue */ 917 cmd->aux = m; 918 ng_l2cap_link_cmd(ch->con, cmd); 919 ng_l2cap_lp_deliver(ch->con); 920 921 return (error); 922 drop: 923 NG_FREE_M(m); 924 925 return (error); 926 } /* ng_l2cap_l2ca_write_req */ 927 928 /* 929 * Send L2CA_Write response 930 */ 931 932 int 933 ng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result, 934 u_int16_t length) 935 { 936 ng_l2cap_p l2cap = ch->con->l2cap; 937 struct ng_mesg *msg = NULL; 938 ng_l2cap_l2ca_write_op *op = NULL; 939 int error = 0; 940 941 /* Check if upstream hook is connected and valid */ 942 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 943 NG_L2CAP_ERR( 944 "%s: %s - unable to send L2CA_WriteRsp message. " \ 945 "Hook is not connected or valid, psm=%d\n", 946 __func__, NG_NODE_NAME(l2cap->node), ch->psm); 947 948 return (ENOTCONN); 949 } 950 951 /* Create and send L2CA_WriteRsp message */ 952 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_WRITE, 953 sizeof(*op), M_NOWAIT); 954 if (msg == NULL) 955 error = ENOMEM; 956 else { 957 msg->header.token = token; 958 msg->header.flags |= NGF_RESP; 959 960 op = (ng_l2cap_l2ca_write_op *)(msg->data); 961 op->result = result; 962 op->length = length; 963 if(ch->scid == NG_L2CAP_ATT_CID){ 964 op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT; 965 op->lcid = ch->con->con_handle; 966 }else if(ch->scid == NG_L2CAP_SMP_CID){ 967 op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP; 968 op->lcid = ch->con->con_handle; 969 }else{ 970 op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)? 971 NG_L2CAP_L2CA_IDTYPE_BREDR : 972 NG_L2CAP_L2CA_IDTYPE_LE; 973 op->lcid = ch->scid; 974 975 } 976 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 977 } 978 979 return (error); 980 } /* ng_l2cap_l2ca_write_rsp */ 981 982 /* 983 * Receive packet from the lower layer protocol and send it to the upper 984 * layer protocol (L2CAP_Read) 985 */ 986 987 int 988 ng_l2cap_l2ca_receive(ng_l2cap_con_p con) 989 { 990 ng_l2cap_p l2cap = con->l2cap; 991 ng_l2cap_hdr_t *hdr = NULL; 992 ng_l2cap_chan_p ch = NULL; 993 int error = 0; 994 int idtype; 995 uint16_t *idp; 996 int silent = 0; 997 998 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr)); 999 if (con->rx_pkt == NULL) 1000 return (ENOBUFS); 1001 1002 hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *); 1003 1004 /* Check channel */ 1005 1006 if(hdr->dcid == NG_L2CAP_ATT_CID){ 1007 idtype = NG_L2CAP_L2CA_IDTYPE_ATT; 1008 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID, 1009 con->con_handle); 1010 /* 1011 * Here,ATT channel is distinguished by 1012 * connection handle 1013 */ 1014 hdr->dcid = con->con_handle; 1015 silent = 1; 1016 }else if(hdr->dcid == NG_L2CAP_SMP_CID){ 1017 idtype = NG_L2CAP_L2CA_IDTYPE_SMP; 1018 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID, 1019 con->con_handle); 1020 /* 1021 * Here,SMP channel is distinguished by 1022 * connection handle 1023 */ 1024 silent = 1; 1025 hdr->dcid = con->con_handle; 1026 }else{ 1027 idtype = (con->linktype==NG_HCI_LINK_ACL)? 1028 NG_L2CAP_L2CA_IDTYPE_BREDR: 1029 NG_L2CAP_L2CA_IDTYPE_LE; 1030 ch = ng_l2cap_chan_by_scid(l2cap, hdr->dcid, idtype); 1031 } 1032 if (ch == NULL) { 1033 if(!silent) 1034 NG_L2CAP_ERR( 1035 "%s: %s - unexpected L2CAP data packet. Channel does not exist, cid=%d, idtype=%d\n", 1036 __func__, NG_NODE_NAME(l2cap->node), hdr->dcid, idtype); 1037 error = ENOENT; 1038 goto drop; 1039 } 1040 1041 /* Check channel state */ 1042 if (ch->state != NG_L2CAP_OPEN) { 1043 NG_L2CAP_WARN( 1044 "%s: %s - unexpected L2CAP data packet. " \ 1045 "Invalid channel state, cid=%d, state=%d\n", 1046 __func__, NG_NODE_NAME(l2cap->node), ch->scid, 1047 ch->state); 1048 error = EHOSTDOWN; /* XXX not always - re-configuration */ 1049 goto drop; 1050 } 1051 1052 /* Check payload size and channel's MTU */ 1053 if (hdr->length > ch->imtu) { 1054 NG_L2CAP_ERR( 1055 "%s: %s - invalid L2CAP data packet. " \ 1056 "Packet too big, length=%d, imtu=%d, cid=%d\n", 1057 __func__, NG_NODE_NAME(l2cap->node), hdr->length, 1058 ch->imtu, ch->scid); 1059 error = EMSGSIZE; 1060 goto drop; 1061 } 1062 1063 /* 1064 * If we got here then everything looks good and we can sent packet 1065 * to the upper layer protocol. 1066 */ 1067 1068 /* Check if upstream hook is connected and valid */ 1069 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1070 NG_L2CAP_ERR( 1071 "%s: %s - unable to send L2CAP data packet. " \ 1072 "Hook is not connected or valid, psm=%d\n", 1073 __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1074 error = ENOTCONN; 1075 goto drop; 1076 } 1077 M_PREPEND(con->rx_pkt, sizeof(uint16_t), M_NOWAIT); 1078 if(con->rx_pkt == NULL) 1079 goto drop; 1080 idp = mtod(con->rx_pkt, uint16_t *); 1081 *idp = idtype; 1082 1083 NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt); 1084 con->rx_pkt = NULL; 1085 drop: 1086 NG_FREE_M(con->rx_pkt); /* checks for != NULL */ 1087 1088 return (error); 1089 } /* ng_l2cap_receive */ 1090 1091 /* 1092 * Receive connectioless (multicast) packet from the lower layer protocol and 1093 * send it to the upper layer protocol 1094 */ 1095 1096 int 1097 ng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con) 1098 { 1099 struct _clt_pkt { 1100 ng_l2cap_hdr_t h; 1101 ng_l2cap_clt_hdr_t c_h; 1102 } __attribute__ ((packed)) *hdr = NULL; 1103 ng_l2cap_p l2cap = con->l2cap; 1104 int length, error = 0; 1105 1106 NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr)); 1107 if (con->rx_pkt == NULL) 1108 return (ENOBUFS); 1109 1110 hdr = mtod(con->rx_pkt, struct _clt_pkt *); 1111 1112 /* Check packet */ 1113 length = con->rx_pkt->m_pkthdr.len - sizeof(*hdr); 1114 if (length < 0) { 1115 NG_L2CAP_ERR( 1116 "%s: %s - invalid L2CAP CLT data packet. Packet too small, length=%d\n", 1117 __func__, NG_NODE_NAME(l2cap->node), length); 1118 error = EMSGSIZE; 1119 goto drop; 1120 } 1121 1122 /* Check payload size against CLT MTU */ 1123 if (length > NG_L2CAP_MTU_DEFAULT) { 1124 NG_L2CAP_ERR( 1125 "%s: %s - invalid L2CAP CLT data packet. Packet too big, length=%d, mtu=%d\n", 1126 __func__, NG_NODE_NAME(l2cap->node), length, 1127 NG_L2CAP_MTU_DEFAULT); 1128 error = EMSGSIZE; 1129 goto drop; 1130 } 1131 1132 hdr->c_h.psm = le16toh(hdr->c_h.psm); 1133 1134 /* 1135 * If we got here then everything looks good and we can sent packet 1136 * to the upper layer protocol. 1137 */ 1138 1139 /* Select upstream hook based on PSM */ 1140 switch (hdr->c_h.psm) { 1141 case NG_L2CAP_PSM_SDP: 1142 if (l2cap->flags & NG_L2CAP_CLT_SDP_DISABLED) 1143 goto drop; 1144 break; 1145 1146 case NG_L2CAP_PSM_RFCOMM: 1147 if (l2cap->flags & NG_L2CAP_CLT_RFCOMM_DISABLED) 1148 goto drop; 1149 break; 1150 1151 case NG_L2CAP_PSM_TCP: 1152 if (l2cap->flags & NG_L2CAP_CLT_TCP_DISABLED) 1153 goto drop; 1154 break; 1155 } 1156 1157 /* Check if upstream hook is connected and valid */ 1158 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1159 NG_L2CAP_ERR( 1160 "%s: %s - unable to send L2CAP CLT data packet. " \ 1161 "Hook is not connected or valid, psm=%d\n", 1162 __func__, NG_NODE_NAME(l2cap->node), hdr->c_h.psm); 1163 error = ENOTCONN; 1164 goto drop; 1165 } 1166 1167 NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt); 1168 con->rx_pkt = NULL; 1169 drop: 1170 NG_FREE_M(con->rx_pkt); /* checks for != NULL */ 1171 1172 return (error); 1173 } /* ng_l2cap_l2ca_clt_receive */ 1174 1175 /* 1176 * Send L2CA_QoSViolationInd to the upper layer protocol 1177 */ 1178 1179 int 1180 ng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch) 1181 { 1182 ng_l2cap_p l2cap = ch->con->l2cap; 1183 struct ng_mesg *msg = NULL; 1184 ng_l2cap_l2ca_qos_ind_ip *ip = NULL; 1185 int error = 0; 1186 1187 /* Check if upstream hook is connected and valid */ 1188 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1189 NG_L2CAP_ERR( 1190 "%s: %s - unable to send L2CA_QoSViolationInd message. " \ 1191 "Hook is not connected or valid, psm=%d\n", 1192 __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1193 1194 return (ENOTCONN); 1195 } 1196 1197 /* Create and send L2CA_QoSViolationInd message */ 1198 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_QOS_IND, 1199 sizeof(*ip), M_NOWAIT); 1200 if (msg == NULL) 1201 error = ENOMEM; 1202 else { 1203 ip = (ng_l2cap_l2ca_qos_ind_ip *)(msg->data); 1204 bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr)); 1205 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1206 } 1207 1208 return (error); 1209 } /* ng_l2cap_l2ca_qos_ind */ 1210 1211 /* 1212 * Process L2CA_Disconnect request from the upper layer protocol. 1213 */ 1214 1215 int 1216 ng_l2cap_l2ca_discon_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1217 { 1218 ng_l2cap_l2ca_discon_ip *ip = NULL; 1219 ng_l2cap_chan_p ch = NULL; 1220 ng_l2cap_cmd_p cmd = NULL; 1221 int error = 0; 1222 1223 /* Check message */ 1224 if (msg->header.arglen != sizeof(*ip)) { 1225 NG_L2CAP_ALERT( 1226 "%s: %s - invalid L2CA_Disconnect request message size, size=%d\n", 1227 __func__, NG_NODE_NAME(l2cap->node), 1228 msg->header.arglen); 1229 error = EMSGSIZE; 1230 goto out; 1231 } 1232 1233 ip = (ng_l2cap_l2ca_discon_ip *)(msg->data); 1234 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, 1238 ip->lcid); 1239 1240 if(ch != NULL){ 1241 ng_l2cap_free_chan(ch); 1242 }else{ 1243 NG_L2CAP_ERR( 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); 1247 error = EINVAL; 1248 } 1249 goto out; 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, 1253 ip->lcid); 1254 1255 if(ch != NULL){ 1256 ng_l2cap_free_chan(ch); 1257 }else{ 1258 NG_L2CAP_ERR( 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); 1262 error = EINVAL; 1263 } 1264 goto out; 1265 }else{ 1266 /* Check if we have this channel */ 1267 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, ip->idtype); 1268 } 1269 if (ch == NULL) { 1270 NG_L2CAP_ERR( 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); 1274 error = ENOENT; 1275 goto out; 1276 } 1277 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) { 1281 NG_L2CAP_ERR( 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, 1285 ch->scid); 1286 error = EINVAL; 1287 goto out; 1288 } 1289 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); 1293 if (cmd == NULL) { 1294 ng_l2cap_free_chan(ch); 1295 error = ENOMEM; 1296 goto out; 1297 } 1298 1299 if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1300 ng_l2cap_free_chan(ch); 1301 ng_l2cap_free_cmd(cmd); 1302 error = EIO; 1303 goto out; 1304 } 1305 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); 1310 error = ENOBUFS; 1311 goto out; 1312 } 1313 1314 ch->state = NG_L2CAP_W4_L2CAP_DISCON_RSP; 1315 1316 /* Link command to the queue */ 1317 ng_l2cap_link_cmd(ch->con, cmd); 1318 ng_l2cap_lp_deliver(ch->con); 1319 out: 1320 return (error); 1321 } /* ng_l2cap_l2ca_discon_req */ 1322 1323 /* 1324 * Send L2CA_Disconnect response to the upper layer protocol 1325 */ 1326 1327 int 1328 ng_l2cap_l2ca_discon_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 1329 { 1330 ng_l2cap_p l2cap = ch->con->l2cap; 1331 struct ng_mesg *msg = NULL; 1332 ng_l2cap_l2ca_discon_op *op = NULL; 1333 int error = 0; 1334 1335 /* Check if upstream hook is connected and valid */ 1336 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1337 NG_L2CAP_ERR( 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); 1341 1342 return (ENOTCONN); 1343 } 1344 1345 /* Create and send L2CA_Disconnect response message */ 1346 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON, 1347 sizeof(*op), M_NOWAIT); 1348 if (msg == NULL) 1349 error = ENOMEM; 1350 else { 1351 msg->header.token = token; 1352 msg->header.flags |= NGF_RESP; 1353 1354 op = (ng_l2cap_l2ca_discon_op *)(msg->data); 1355 op->result = result; 1356 1357 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1358 } 1359 1360 return (error); 1361 } /* ng_l2cap_l2ca_discon_rsp */ 1362 1363 /* 1364 * Send L2CA_DisconnectInd message to the upper layer protocol. 1365 */ 1366 1367 int 1368 ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch) 1369 { 1370 ng_l2cap_p l2cap = ch->con->l2cap; 1371 struct ng_mesg *msg = NULL; 1372 ng_l2cap_l2ca_discon_ind_ip *ip = NULL; 1373 int error = 0; 1374 1375 /* Check if upstream hook is connected and valid */ 1376 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1377 NG_L2CAP_ERR( 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); 1381 1382 return (ENOTCONN); 1383 } 1384 1385 /* Create and send L2CA_DisconnectInd message */ 1386 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND, 1387 sizeof(*ip), M_NOWAIT); 1388 if (msg == NULL) 1389 error = ENOMEM; 1390 else { 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; 1396 else 1397 ip->lcid = ch->scid; 1398 1399 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1400 } 1401 1402 return (error); 1403 } /* ng_l2cap_l2ca_discon_ind */ 1404 1405 /* 1406 * Process L2CA_GroupCreate request from the upper layer protocol. 1407 * XXX FIXME 1408 */ 1409 1410 int 1411 ng_l2cap_l2ca_grp_create(ng_l2cap_p l2cap, struct ng_mesg *msg) 1412 { 1413 return (ENOTSUP); 1414 } /* ng_l2cap_l2ca_grp_create */ 1415 1416 /* 1417 * Process L2CA_GroupClose request from the upper layer protocol 1418 * XXX FIXME 1419 */ 1420 1421 int 1422 ng_l2cap_l2ca_grp_close(ng_l2cap_p l2cap, struct ng_mesg *msg) 1423 { 1424 return (ENOTSUP); 1425 } /* ng_l2cap_l2ca_grp_close */ 1426 1427 /* 1428 * Process L2CA_GroupAddMember request from the upper layer protocol. 1429 * XXX FIXME 1430 */ 1431 1432 int 1433 ng_l2cap_l2ca_grp_add_member_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1434 { 1435 return (ENOTSUP); 1436 } /* ng_l2cap_l2ca_grp_add_member_req */ 1437 1438 /* 1439 * Send L2CA_GroupAddMember response to the upper layer protocol. 1440 * XXX FIXME 1441 */ 1442 1443 int 1444 ng_l2cap_l2ca_grp_add_member_rsp(ng_l2cap_chan_p ch, u_int32_t token, 1445 u_int16_t result) 1446 { 1447 return (0); 1448 } /* ng_l2cap_l2ca_grp_add_member_rsp */ 1449 1450 /* 1451 * Process L2CA_GroupDeleteMember request from the upper layer protocol 1452 * XXX FIXME 1453 */ 1454 1455 int 1456 ng_l2cap_l2ca_grp_rem_member(ng_l2cap_p l2cap, struct ng_mesg *msg) 1457 { 1458 return (ENOTSUP); 1459 } /* ng_l2cap_l2ca_grp_rem_member */ 1460 1461 /* 1462 * Process L2CA_GroupGetMembers request from the upper layer protocol 1463 * XXX FIXME 1464 */ 1465 1466 int 1467 ng_l2cap_l2ca_grp_get_members(ng_l2cap_p l2cap, struct ng_mesg *msg) 1468 { 1469 return (ENOTSUP); 1470 } /* ng_l2cap_l2ca_grp_get_members */ 1471 1472 /* 1473 * Process L2CA_Ping request from the upper layer protocol 1474 */ 1475 1476 int 1477 ng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1478 { 1479 ng_l2cap_l2ca_ping_ip *ip = NULL; 1480 ng_l2cap_con_p con = NULL; 1481 ng_l2cap_cmd_p cmd = NULL; 1482 int error = 0; 1483 1484 /* Verify message */ 1485 if (msg->header.arglen < sizeof(*ip)) { 1486 NG_L2CAP_ALERT( 1487 "%s: %s - invalid L2CA_Ping request message size, size=%d\n", 1488 __func__, NG_NODE_NAME(l2cap->node), 1489 msg->header.arglen); 1490 error = EMSGSIZE; 1491 goto out; 1492 } 1493 1494 ip = (ng_l2cap_l2ca_ping_ip *)(msg->data); 1495 if (ip->echo_size > NG_L2CAP_MAX_ECHO_SIZE) { 1496 NG_L2CAP_WARN( 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); 1499 error = EMSGSIZE; 1500 goto out; 1501 } 1502 1503 /* Check if we have connection to the unit */ 1504 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL); 1505 if (con == NULL) { 1506 /* Submit LP_ConnectReq to the lower layer */ 1507 error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL); 1508 if (error != 0) { 1509 NG_L2CAP_ERR( 1510 "%s: %s - unable to send LP_ConnectReq message, error=%d\n", 1511 __func__, NG_NODE_NAME(l2cap->node), error); 1512 goto out; 1513 } 1514 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))); 1519 } 1520 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); 1524 if (cmd == NULL) { 1525 error = ENOMEM; 1526 goto out; 1527 } 1528 1529 if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1530 ng_l2cap_free_cmd(cmd); 1531 error = EIO; 1532 goto out; 1533 } 1534 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); 1540 error = ENOBUFS; 1541 goto out; 1542 } 1543 1544 /* Link command to the queue */ 1545 ng_l2cap_link_cmd(con, cmd); 1546 ng_l2cap_lp_deliver(con); 1547 out: 1548 return (error); 1549 } /* ng_l2cap_l2ca_ping_req */ 1550 1551 /* 1552 * Send L2CA_Ping response to the upper layer protocol 1553 */ 1554 1555 int 1556 ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result, 1557 struct mbuf *data) 1558 { 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; 1563 1564 /* Check if control hook is connected and valid */ 1565 if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) { 1566 NG_L2CAP_WARN( 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)); 1570 error = ENOTCONN; 1571 goto out; 1572 } 1573 1574 size = (data == NULL)? 0 : data->m_pkthdr.len; 1575 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); 1579 if (msg == NULL) 1580 error = ENOMEM; 1581 else { 1582 msg->header.token = token; 1583 msg->header.flags |= NGF_RESP; 1584 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)); 1591 } 1592 1593 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1594 } 1595 out: 1596 NG_FREE_M(data); 1597 1598 return (error); 1599 } /* ng_l2cap_l2ca_ping_rsp */ 1600 1601 /* 1602 * Process L2CA_GetInfo request from the upper layer protocol 1603 */ 1604 1605 int 1606 ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1607 { 1608 ng_l2cap_l2ca_get_info_ip *ip = NULL; 1609 ng_l2cap_con_p con = NULL; 1610 ng_l2cap_cmd_p cmd = NULL; 1611 int error = 0; 1612 1613 /* Verify message */ 1614 if (msg->header.arglen != sizeof(*ip)) { 1615 NG_L2CAP_ALERT( 1616 "%s: %s - invalid L2CA_GetInfo request message size, size=%d\n", 1617 __func__, NG_NODE_NAME(l2cap->node), 1618 msg->header.arglen); 1619 error = EMSGSIZE; 1620 goto out; 1621 } 1622 1623 ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data); 1624 1625 /* Check if we have connection to the unit */ 1626 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr,ip->linktype); 1627 if (con == NULL) { 1628 /* Submit LP_ConnectReq to the lower layer */ 1629 error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype); 1630 if (error != 0) { 1631 NG_L2CAP_ERR( 1632 "%s: %s - unable to send LP_ConnectReq message, error=%d\n", 1633 __func__, NG_NODE_NAME(l2cap->node), error); 1634 goto out; 1635 } 1636 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))); 1641 } 1642 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); 1646 if (cmd == NULL) { 1647 error = ENOMEM; 1648 goto out; 1649 } 1650 1651 if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1652 ng_l2cap_free_cmd(cmd); 1653 error = EIO; 1654 goto out; 1655 } 1656 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); 1661 error = ENOBUFS; 1662 goto out; 1663 } 1664 1665 /* Link command to the queue */ 1666 ng_l2cap_link_cmd(con, cmd); 1667 ng_l2cap_lp_deliver(con); 1668 out: 1669 return (error); 1670 } /* ng_l2cap_l2ca_get_info_req */ 1671 1672 /* 1673 * Send L2CA_GetInfo response to the upper layer protocol 1674 */ 1675 1676 int 1677 ng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con, u_int32_t token, 1678 u_int16_t result, struct mbuf *data) 1679 { 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; 1684 1685 /* Check if control hook is connected and valid */ 1686 if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) { 1687 NG_L2CAP_WARN( 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)); 1691 error = ENOTCONN; 1692 goto out; 1693 } 1694 1695 size = (data == NULL)? 0 : data->m_pkthdr.len; 1696 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); 1700 if (msg == NULL) 1701 error = ENOMEM; 1702 else { 1703 msg->header.token = token; 1704 msg->header.flags |= NGF_RESP; 1705 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)); 1711 } 1712 1713 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1714 } 1715 out: 1716 NG_FREE_M(data); 1717 1718 return (error); 1719 } /* ng_l2cap_l2ca_get_info_rsp */ 1720 1721 /* 1722 * Process L2CA_EnableCLT message from the upper layer protocol 1723 * XXX convert to NGN_L2CAP_NODE_SET_FLAGS? 1724 */ 1725 1726 int 1727 ng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg) 1728 { 1729 ng_l2cap_l2ca_enable_clt_ip *ip = NULL; 1730 int error = 0; 1731 #if 0 1732 * ng_l2cap_l2ca_enable_clt_op *op = NULL; 1733 * u_int16_t result; 1734 * u_int32_t token; 1735 #endif 1736 1737 /* Check message */ 1738 if (msg->header.arglen != sizeof(*ip)) { 1739 NG_L2CAP_ALERT( 1740 "%s: %s - invalid L2CA_EnableCLT message size, size=%d\n", 1741 __func__, NG_NODE_NAME(l2cap->node), 1742 msg->header.arglen); 1743 1744 return (EMSGSIZE); 1745 } 1746 1747 /* Process request */ 1748 ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data); 1749 #if 0 1750 * result = NG_L2CAP_SUCCESS; 1751 #endif 1752 1753 switch (ip->psm) 1754 { 1755 case 0: 1756 /* Special case: disable/enable all PSM */ 1757 if (ip->enable) 1758 l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED | 1759 NG_L2CAP_CLT_RFCOMM_DISABLED | 1760 NG_L2CAP_CLT_TCP_DISABLED); 1761 else 1762 l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED | 1763 NG_L2CAP_CLT_RFCOMM_DISABLED | 1764 NG_L2CAP_CLT_TCP_DISABLED); 1765 break; 1766 1767 case NG_L2CAP_PSM_SDP: 1768 if (ip->enable) 1769 l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED; 1770 else 1771 l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED; 1772 break; 1773 1774 case NG_L2CAP_PSM_RFCOMM: 1775 if (ip->enable) 1776 l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED; 1777 else 1778 l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED; 1779 break; 1780 1781 case NG_L2CAP_PSM_TCP: 1782 if (ip->enable) 1783 l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED; 1784 else 1785 l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED; 1786 break; 1787 1788 default: 1789 NG_L2CAP_ERR( 1790 "%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm); 1791 #if 0 1792 * result = NG_L2CAP_PSM_NOT_SUPPORTED; 1793 #endif 1794 error = ENOTSUP; 1795 break; 1796 } 1797 1798 #if 0 1799 * /* Create and send response message */ 1800 * token = msg->header.token; 1801 * NG_FREE_MSG(msg); 1802 * NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT, 1803 * sizeof(*op), M_NOWAIT); 1804 * if (msg == NULL) 1805 * error = ENOMEM; 1806 * else { 1807 * msg->header.token = token; 1808 * msg->header.flags |= NGF_RESP; 1809 * 1810 * op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data); 1811 * op->result = result; 1812 * } 1813 * 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); 1817 #endif 1818 1819 return (error); 1820 } /* ng_l2cap_l2ca_enable_clt */ 1821