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