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