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 * $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 if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_ATT){ 1237 /* Don't send Disconnect request on L2CAP Layer*/ 1238 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_ATT_CID, 1239 ip->lcid); 1240 1241 if(ch != NULL){ 1242 ng_l2cap_free_chan(ch); 1243 }else{ 1244 NG_L2CAP_ERR( 1245 "%s: %s - unexpected L2CA_Disconnect request message. " \ 1246 "Channel does not exist, conhandle=%d\n", 1247 __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 1248 error = EINVAL; 1249 } 1250 goto out; 1251 }else if(ip->idtype == NG_L2CAP_L2CA_IDTYPE_SMP){ 1252 /* Don't send Disconnect request on L2CAP Layer*/ 1253 ch = ng_l2cap_chan_by_conhandle(l2cap, NG_L2CAP_SMP_CID, 1254 ip->lcid); 1255 1256 if(ch != NULL){ 1257 ng_l2cap_free_chan(ch); 1258 }else{ 1259 NG_L2CAP_ERR( 1260 "%s: %s - unexpected L2CA_Disconnect request message. " \ 1261 "Channel does not exist, conhandle=%d\n", 1262 __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 1263 error = EINVAL; 1264 } 1265 goto out; 1266 }else{ 1267 /* Check if we have this channel */ 1268 ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid, ip->idtype); 1269 } 1270 if (ch == NULL) { 1271 NG_L2CAP_ERR( 1272 "%s: %s - unexpected L2CA_Disconnect request message. " \ 1273 "Channel does not exist, lcid=%d\n", 1274 __func__, NG_NODE_NAME(l2cap->node), ip->lcid); 1275 error = ENOENT; 1276 goto out; 1277 } 1278 1279 /* Check channel state */ 1280 if (ch->state != NG_L2CAP_CONFIG && ch->state != NG_L2CAP_OPEN && 1281 ch->state != NG_L2CAP_W4_L2CAP_DISCON_RSP) { 1282 NG_L2CAP_ERR( 1283 "%s: %s - unexpected L2CA_Disconnect request message. " \ 1284 "Invalid channel state, state=%d, lcid=%d\n", 1285 __func__, NG_NODE_NAME(l2cap->node), ch->state, 1286 ch->scid); 1287 error = EINVAL; 1288 goto out; 1289 } 1290 1291 /* Create and send L2CAP_DisconReq message */ 1292 cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con), 1293 NG_L2CAP_DISCON_REQ, msg->header.token); 1294 if (cmd == NULL) { 1295 ng_l2cap_free_chan(ch); 1296 error = ENOMEM; 1297 goto out; 1298 } 1299 1300 if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1301 ng_l2cap_free_chan(ch); 1302 ng_l2cap_free_cmd(cmd); 1303 error = EIO; 1304 goto out; 1305 } 1306 1307 _ng_l2cap_discon_req(cmd->aux, cmd->ident, ch->dcid, ch->scid); 1308 if (cmd->aux == NULL) { 1309 ng_l2cap_free_chan(ch); 1310 ng_l2cap_free_cmd(cmd); 1311 error = ENOBUFS; 1312 goto out; 1313 } 1314 1315 ch->state = NG_L2CAP_W4_L2CAP_DISCON_RSP; 1316 1317 /* Link command to the queue */ 1318 ng_l2cap_link_cmd(ch->con, cmd); 1319 ng_l2cap_lp_deliver(ch->con); 1320 out: 1321 return (error); 1322 } /* ng_l2cap_l2ca_discon_req */ 1323 1324 /* 1325 * Send L2CA_Disconnect response to the upper layer protocol 1326 */ 1327 1328 int 1329 ng_l2cap_l2ca_discon_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) 1330 { 1331 ng_l2cap_p l2cap = ch->con->l2cap; 1332 struct ng_mesg *msg = NULL; 1333 ng_l2cap_l2ca_discon_op *op = NULL; 1334 int error = 0; 1335 1336 /* Check if upstream hook is connected and valid */ 1337 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1338 NG_L2CAP_ERR( 1339 "%s: %s - unable to send L2CA_Disconnect response message. " \ 1340 "Hook is not connected or valid, psm=%d\n", 1341 __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1342 1343 return (ENOTCONN); 1344 } 1345 1346 /* Create and send L2CA_Disconnect response message */ 1347 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON, 1348 sizeof(*op), M_NOWAIT); 1349 if (msg == NULL) 1350 error = ENOMEM; 1351 else { 1352 msg->header.token = token; 1353 msg->header.flags |= NGF_RESP; 1354 1355 op = (ng_l2cap_l2ca_discon_op *)(msg->data); 1356 op->result = result; 1357 1358 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1359 } 1360 1361 return (error); 1362 } /* ng_l2cap_l2ca_discon_rsp */ 1363 1364 /* 1365 * Send L2CA_DisconnectInd message to the upper layer protocol. 1366 */ 1367 1368 int 1369 ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch) 1370 { 1371 ng_l2cap_p l2cap = ch->con->l2cap; 1372 struct ng_mesg *msg = NULL; 1373 ng_l2cap_l2ca_discon_ind_ip *ip = NULL; 1374 int error = 0; 1375 1376 /* Check if upstream hook is connected and valid */ 1377 if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { 1378 NG_L2CAP_ERR( 1379 "%s: %s - unable to send L2CA_DisconnectInd message. " \ 1380 "Hook is not connected or valid, psm=%d\n", 1381 __func__, NG_NODE_NAME(l2cap->node), ch->psm); 1382 1383 return (ENOTCONN); 1384 } 1385 1386 /* Create and send L2CA_DisconnectInd message */ 1387 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND, 1388 sizeof(*ip), M_NOWAIT); 1389 if (msg == NULL) 1390 error = ENOMEM; 1391 else { 1392 ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data); 1393 ip->idtype = ch->idtype; 1394 if(ch->idtype == NG_L2CAP_L2CA_IDTYPE_ATT|| 1395 ch->idtype == NG_L2CAP_L2CA_IDTYPE_SMP) 1396 ip->lcid = ch->con->con_handle; 1397 else 1398 ip->lcid = ch->scid; 1399 1400 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); 1401 } 1402 1403 return (error); 1404 } /* ng_l2cap_l2ca_discon_ind */ 1405 1406 /* 1407 * Process L2CA_GroupCreate request from the upper layer protocol. 1408 * XXX FIXME 1409 */ 1410 1411 int 1412 ng_l2cap_l2ca_grp_create(ng_l2cap_p l2cap, struct ng_mesg *msg) 1413 { 1414 return (ENOTSUP); 1415 } /* ng_l2cap_l2ca_grp_create */ 1416 1417 /* 1418 * Process L2CA_GroupClose request from the upper layer protocol 1419 * XXX FIXME 1420 */ 1421 1422 int 1423 ng_l2cap_l2ca_grp_close(ng_l2cap_p l2cap, struct ng_mesg *msg) 1424 { 1425 return (ENOTSUP); 1426 } /* ng_l2cap_l2ca_grp_close */ 1427 1428 /* 1429 * Process L2CA_GroupAddMember request from the upper layer protocol. 1430 * XXX FIXME 1431 */ 1432 1433 int 1434 ng_l2cap_l2ca_grp_add_member_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1435 { 1436 return (ENOTSUP); 1437 } /* ng_l2cap_l2ca_grp_add_member_req */ 1438 1439 /* 1440 * Send L2CA_GroupAddMember response to the upper layer protocol. 1441 * XXX FIXME 1442 */ 1443 1444 int 1445 ng_l2cap_l2ca_grp_add_member_rsp(ng_l2cap_chan_p ch, u_int32_t token, 1446 u_int16_t result) 1447 { 1448 return (0); 1449 } /* ng_l2cap_l2ca_grp_add_member_rsp */ 1450 1451 /* 1452 * Process L2CA_GroupDeleteMember request from the upper layer protocol 1453 * XXX FIXME 1454 */ 1455 1456 int 1457 ng_l2cap_l2ca_grp_rem_member(ng_l2cap_p l2cap, struct ng_mesg *msg) 1458 { 1459 return (ENOTSUP); 1460 } /* ng_l2cap_l2ca_grp_rem_member */ 1461 1462 /* 1463 * Process L2CA_GroupGetMembers request from the upper layer protocol 1464 * XXX FIXME 1465 */ 1466 1467 int 1468 ng_l2cap_l2ca_grp_get_members(ng_l2cap_p l2cap, struct ng_mesg *msg) 1469 { 1470 return (ENOTSUP); 1471 } /* ng_l2cap_l2ca_grp_get_members */ 1472 1473 /* 1474 * Process L2CA_Ping request from the upper layer protocol 1475 */ 1476 1477 int 1478 ng_l2cap_l2ca_ping_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1479 { 1480 ng_l2cap_l2ca_ping_ip *ip = NULL; 1481 ng_l2cap_con_p con = NULL; 1482 ng_l2cap_cmd_p cmd = NULL; 1483 int error = 0; 1484 1485 /* Verify message */ 1486 if (msg->header.arglen < sizeof(*ip)) { 1487 NG_L2CAP_ALERT( 1488 "%s: %s - invalid L2CA_Ping request message size, size=%d\n", 1489 __func__, NG_NODE_NAME(l2cap->node), 1490 msg->header.arglen); 1491 error = EMSGSIZE; 1492 goto out; 1493 } 1494 1495 ip = (ng_l2cap_l2ca_ping_ip *)(msg->data); 1496 if (ip->echo_size > NG_L2CAP_MAX_ECHO_SIZE) { 1497 NG_L2CAP_WARN( 1498 "%s: %s - invalid L2CA_Ping request. Echo size is too big, echo_size=%d\n", 1499 __func__, NG_NODE_NAME(l2cap->node), ip->echo_size); 1500 error = EMSGSIZE; 1501 goto out; 1502 } 1503 1504 /* Check if we have connection to the unit */ 1505 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL); 1506 if (con == NULL) { 1507 /* Submit LP_ConnectReq to the lower layer */ 1508 error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL); 1509 if (error != 0) { 1510 NG_L2CAP_ERR( 1511 "%s: %s - unable to send LP_ConnectReq message, error=%d\n", 1512 __func__, NG_NODE_NAME(l2cap->node), error); 1513 goto out; 1514 } 1515 1516 /* This should not fail */ 1517 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, NG_HCI_LINK_ACL); 1518 KASSERT((con != NULL), 1519 ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node))); 1520 } 1521 1522 /* Create L2CAP command descriptor */ 1523 cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con), 1524 NG_L2CAP_ECHO_REQ, msg->header.token); 1525 if (cmd == NULL) { 1526 error = ENOMEM; 1527 goto out; 1528 } 1529 1530 if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1531 ng_l2cap_free_cmd(cmd); 1532 error = EIO; 1533 goto out; 1534 } 1535 1536 /* Create L2CAP command packet */ 1537 _ng_l2cap_echo_req(cmd->aux, cmd->ident, 1538 msg->data + sizeof(*ip), ip->echo_size); 1539 if (cmd->aux == NULL) { 1540 ng_l2cap_free_cmd(cmd); 1541 error = ENOBUFS; 1542 goto out; 1543 } 1544 1545 /* Link command to the queue */ 1546 ng_l2cap_link_cmd(con, cmd); 1547 ng_l2cap_lp_deliver(con); 1548 out: 1549 return (error); 1550 } /* ng_l2cap_l2ca_ping_req */ 1551 1552 /* 1553 * Send L2CA_Ping response to the upper layer protocol 1554 */ 1555 1556 int 1557 ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result, 1558 struct mbuf *data) 1559 { 1560 ng_l2cap_p l2cap = con->l2cap; 1561 struct ng_mesg *msg = NULL; 1562 ng_l2cap_l2ca_ping_op *op = NULL; 1563 int error = 0, size = 0; 1564 1565 /* Check if control hook is connected and valid */ 1566 if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) { 1567 NG_L2CAP_WARN( 1568 "%s: %s - unable to send L2CA_Ping response message. " \ 1569 "Hook is not connected or valid\n", 1570 __func__, NG_NODE_NAME(l2cap->node)); 1571 error = ENOTCONN; 1572 goto out; 1573 } 1574 1575 size = (data == NULL)? 0 : data->m_pkthdr.len; 1576 1577 /* Create and send L2CA_Ping response message */ 1578 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_PING, 1579 sizeof(*op) + size, M_NOWAIT); 1580 if (msg == NULL) 1581 error = ENOMEM; 1582 else { 1583 msg->header.token = token; 1584 msg->header.flags |= NGF_RESP; 1585 1586 op = (ng_l2cap_l2ca_ping_op *)(msg->data); 1587 op->result = result; 1588 bcopy(&con->remote, &op->bdaddr, sizeof(op->bdaddr)); 1589 if (data != NULL && size > 0) { 1590 op->echo_size = size; 1591 m_copydata(data, 0, size, (caddr_t) op + sizeof(*op)); 1592 } 1593 1594 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1595 } 1596 out: 1597 NG_FREE_M(data); 1598 1599 return (error); 1600 } /* ng_l2cap_l2ca_ping_rsp */ 1601 1602 /* 1603 * Process L2CA_GetInfo request from the upper layer protocol 1604 */ 1605 1606 int 1607 ng_l2cap_l2ca_get_info_req(ng_l2cap_p l2cap, struct ng_mesg *msg) 1608 { 1609 ng_l2cap_l2ca_get_info_ip *ip = NULL; 1610 ng_l2cap_con_p con = NULL; 1611 ng_l2cap_cmd_p cmd = NULL; 1612 int error = 0; 1613 1614 /* Verify message */ 1615 if (msg->header.arglen != sizeof(*ip)) { 1616 NG_L2CAP_ALERT( 1617 "%s: %s - invalid L2CA_GetInfo request message size, size=%d\n", 1618 __func__, NG_NODE_NAME(l2cap->node), 1619 msg->header.arglen); 1620 error = EMSGSIZE; 1621 goto out; 1622 } 1623 1624 ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data); 1625 1626 /* Check if we have connection to the unit */ 1627 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr,ip->linktype); 1628 if (con == NULL) { 1629 /* Submit LP_ConnectReq to the lower layer */ 1630 error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr,ip->linktype); 1631 if (error != 0) { 1632 NG_L2CAP_ERR( 1633 "%s: %s - unable to send LP_ConnectReq message, error=%d\n", 1634 __func__, NG_NODE_NAME(l2cap->node), error); 1635 goto out; 1636 } 1637 1638 /* This should not fail */ 1639 con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr, ip->linktype); 1640 KASSERT((con != NULL), 1641 ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node))); 1642 } 1643 1644 /* Create L2CAP command descriptor */ 1645 cmd = ng_l2cap_new_cmd(con, NULL, ng_l2cap_get_ident(con), 1646 NG_L2CAP_INFO_REQ, msg->header.token); 1647 if (cmd == NULL) { 1648 error = ENOMEM; 1649 goto out; 1650 } 1651 1652 if (cmd->ident == NG_L2CAP_NULL_IDENT) { 1653 ng_l2cap_free_cmd(cmd); 1654 error = EIO; 1655 goto out; 1656 } 1657 1658 /* Create L2CAP command packet */ 1659 _ng_l2cap_info_req(cmd->aux, cmd->ident, ip->info_type); 1660 if (cmd->aux == NULL) { 1661 ng_l2cap_free_cmd(cmd); 1662 error = ENOBUFS; 1663 goto out; 1664 } 1665 1666 /* Link command to the queue */ 1667 ng_l2cap_link_cmd(con, cmd); 1668 ng_l2cap_lp_deliver(con); 1669 out: 1670 return (error); 1671 } /* ng_l2cap_l2ca_get_info_req */ 1672 1673 /* 1674 * Send L2CA_GetInfo response to the upper layer protocol 1675 */ 1676 1677 int 1678 ng_l2cap_l2ca_get_info_rsp(ng_l2cap_con_p con, u_int32_t token, 1679 u_int16_t result, struct mbuf *data) 1680 { 1681 ng_l2cap_p l2cap = con->l2cap; 1682 struct ng_mesg *msg = NULL; 1683 ng_l2cap_l2ca_get_info_op *op = NULL; 1684 int error = 0, size; 1685 1686 /* Check if control hook is connected and valid */ 1687 if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) { 1688 NG_L2CAP_WARN( 1689 "%s: %s - unable to send L2CA_GetInfo response message. " \ 1690 "Hook is not connected or valid\n", 1691 __func__, NG_NODE_NAME(l2cap->node)); 1692 error = ENOTCONN; 1693 goto out; 1694 } 1695 1696 size = (data == NULL)? 0 : data->m_pkthdr.len; 1697 1698 /* Create and send L2CA_GetInfo response message */ 1699 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_GET_INFO, 1700 sizeof(*op) + size, M_NOWAIT); 1701 if (msg == NULL) 1702 error = ENOMEM; 1703 else { 1704 msg->header.token = token; 1705 msg->header.flags |= NGF_RESP; 1706 1707 op = (ng_l2cap_l2ca_get_info_op *)(msg->data); 1708 op->result = result; 1709 if (data != NULL && size > 0) { 1710 op->info_size = size; 1711 m_copydata(data, 0, size, (caddr_t) op + sizeof(*op)); 1712 } 1713 1714 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1715 } 1716 out: 1717 NG_FREE_M(data); 1718 1719 return (error); 1720 } /* ng_l2cap_l2ca_get_info_rsp */ 1721 1722 /* 1723 * Process L2CA_EnableCLT message from the upper layer protocol 1724 * XXX convert to NGN_L2CAP_NODE_SET_FLAGS? 1725 */ 1726 1727 int 1728 ng_l2cap_l2ca_enable_clt(ng_l2cap_p l2cap, struct ng_mesg *msg) 1729 { 1730 ng_l2cap_l2ca_enable_clt_ip *ip = NULL; 1731 int error = 0; 1732 #if 0 1733 * ng_l2cap_l2ca_enable_clt_op *op = NULL; 1734 * u_int16_t result; 1735 * u_int32_t token; 1736 #endif 1737 1738 /* Check message */ 1739 if (msg->header.arglen != sizeof(*ip)) { 1740 NG_L2CAP_ALERT( 1741 "%s: %s - invalid L2CA_EnableCLT message size, size=%d\n", 1742 __func__, NG_NODE_NAME(l2cap->node), 1743 msg->header.arglen); 1744 1745 return (EMSGSIZE); 1746 } 1747 1748 /* Process request */ 1749 ip = (ng_l2cap_l2ca_enable_clt_ip *) (msg->data); 1750 #if 0 1751 * result = NG_L2CAP_SUCCESS; 1752 #endif 1753 1754 switch (ip->psm) 1755 { 1756 case 0: 1757 /* Special case: disable/enable all PSM */ 1758 if (ip->enable) 1759 l2cap->flags &= ~(NG_L2CAP_CLT_SDP_DISABLED | 1760 NG_L2CAP_CLT_RFCOMM_DISABLED | 1761 NG_L2CAP_CLT_TCP_DISABLED); 1762 else 1763 l2cap->flags |= (NG_L2CAP_CLT_SDP_DISABLED | 1764 NG_L2CAP_CLT_RFCOMM_DISABLED | 1765 NG_L2CAP_CLT_TCP_DISABLED); 1766 break; 1767 1768 case NG_L2CAP_PSM_SDP: 1769 if (ip->enable) 1770 l2cap->flags &= ~NG_L2CAP_CLT_SDP_DISABLED; 1771 else 1772 l2cap->flags |= NG_L2CAP_CLT_SDP_DISABLED; 1773 break; 1774 1775 case NG_L2CAP_PSM_RFCOMM: 1776 if (ip->enable) 1777 l2cap->flags &= ~NG_L2CAP_CLT_RFCOMM_DISABLED; 1778 else 1779 l2cap->flags |= NG_L2CAP_CLT_RFCOMM_DISABLED; 1780 break; 1781 1782 case NG_L2CAP_PSM_TCP: 1783 if (ip->enable) 1784 l2cap->flags &= ~NG_L2CAP_CLT_TCP_DISABLED; 1785 else 1786 l2cap->flags |= NG_L2CAP_CLT_TCP_DISABLED; 1787 break; 1788 1789 default: 1790 NG_L2CAP_ERR( 1791 "%s: %s - unsupported PSM=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->psm); 1792 #if 0 1793 * result = NG_L2CAP_PSM_NOT_SUPPORTED; 1794 #endif 1795 error = ENOTSUP; 1796 break; 1797 } 1798 1799 #if 0 1800 * /* Create and send response message */ 1801 * token = msg->header.token; 1802 * NG_FREE_MSG(msg); 1803 * NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_ENABLE_CLT, 1804 * sizeof(*op), M_NOWAIT); 1805 * if (msg == NULL) 1806 * error = ENOMEM; 1807 * else { 1808 * msg->header.token = token; 1809 * msg->header.flags |= NGF_RESP; 1810 * 1811 * op = (ng_l2cap_l2ca_enable_clt_op *)(msg->data); 1812 * op->result = result; 1813 * } 1814 * 1815 * /* Send response to control hook */ 1816 * if (l2cap->ctl != NULL && NG_HOOK_IS_VALID(l2cap->ctl)) 1817 * NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); 1818 #endif 1819 1820 return (error); 1821 } /* ng_l2cap_l2ca_enable_clt */ 1822