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