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