1 /* 2 * ng_hci_cmds.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_hci_cmds.c,v 1.4 2003/09/08 18:57:51 max Exp $ 31 * $FreeBSD: src/sys/netgraph/bluetooth/hci/ng_hci_cmds.c,v 1.7 2005/01/07 01:45:43 imp Exp $ 32 * $DragonFly: src/sys/netgraph7/bluetooth/hci/ng_hci_cmds.c,v 1.2 2008/06/26 23:05:40 dillon Exp $ 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/endian.h> 39 #include <sys/malloc.h> 40 #include <sys/mbuf.h> 41 #include <sys/queue.h> 42 #include "ng_message.h" 43 #include "netgraph.h" 44 #include "bluetooth/include/ng_bluetooth.h" 45 #include "bluetooth/include/ng_hci.h" 46 #include "bluetooth/hci/ng_hci_var.h" 47 #include "bluetooth/hci/ng_hci_cmds.h" 48 #include "bluetooth/hci/ng_hci_evnt.h" 49 #include "bluetooth/hci/ng_hci_ulpi.h" 50 #include "bluetooth/hci/ng_hci_misc.h" 51 52 /****************************************************************************** 53 ****************************************************************************** 54 ** HCI commands processing module 55 ****************************************************************************** 56 ******************************************************************************/ 57 58 #undef min 59 #define min(a, b) ((a) < (b))? (a) : (b) 60 61 static int complete_command (ng_hci_unit_p, int, struct mbuf **); 62 63 static int process_link_control_params 64 (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 65 static int process_link_policy_params 66 (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 67 static int process_hc_baseband_params 68 (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 69 static int process_info_params 70 (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 71 static int process_status_params 72 (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 73 static int process_testing_params 74 (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 75 76 static int process_link_control_status 77 (ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *); 78 static int process_link_policy_status 79 (ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *); 80 81 /* 82 * Send HCI command to the driver. 83 */ 84 85 int 86 ng_hci_send_command(ng_hci_unit_p unit) 87 { 88 struct mbuf *m0 = NULL, *m = NULL; 89 int free, error = 0; 90 91 /* Check if other command is pending */ 92 if (unit->state & NG_HCI_UNIT_COMMAND_PENDING) 93 return (0); 94 95 /* Check if unit can accept our command */ 96 NG_HCI_BUFF_CMD_GET(unit->buffer, free); 97 if (free == 0) 98 return (0); 99 100 /* Check if driver hook is still ok */ 101 if (unit->drv == NULL || NG_HOOK_NOT_VALID(unit->drv)) { 102 NG_HCI_WARN( 103 "%s: %s - hook \"%s\" is not connected or valid\n", 104 __func__, NG_NODE_NAME(unit->node), NG_HCI_HOOK_DRV); 105 106 NG_BT_MBUFQ_DRAIN(&unit->cmdq); 107 108 return (ENOTCONN); 109 } 110 111 /* 112 * Get first command from queue, give it to RAW hook then 113 * make copy of it and send it to the driver 114 */ 115 116 m0 = NG_BT_MBUFQ_FIRST(&unit->cmdq); 117 if (m0 == NULL) 118 return (0); 119 120 ng_hci_mtap(unit, m0); 121 122 m = m_dup(m0, MB_DONTWAIT); 123 if (m != NULL) 124 NG_SEND_DATA_ONLY(error, unit->drv, m); 125 else 126 error = ENOBUFS; 127 128 if (error != 0) 129 NG_HCI_ERR( 130 "%s: %s - could not send HCI command, error=%d\n", 131 __func__, NG_NODE_NAME(unit->node), error); 132 133 /* 134 * Even if we were not able to send command we still pretend 135 * that everything is OK and let timeout handle that. 136 */ 137 138 NG_HCI_BUFF_CMD_USE(unit->buffer, 1); 139 NG_HCI_STAT_CMD_SENT(unit->stat); 140 NG_HCI_STAT_BYTES_SENT(unit->stat, m0->m_pkthdr.len); 141 142 /* 143 * Note: ng_hci_command_timeout() will set 144 * NG_HCI_UNIT_COMMAND_PENDING flag 145 */ 146 147 ng_hci_command_timeout(unit); 148 149 return (0); 150 } /* ng_hci_send_command */ 151 152 /* 153 * Process HCI Command_Compete event. Complete HCI command, and do post 154 * processing on the command parameters (cp) and command return parameters 155 * (e) if required (for example adjust state). 156 */ 157 158 int 159 ng_hci_process_command_complete(ng_hci_unit_p unit, struct mbuf *e) 160 { 161 ng_hci_command_compl_ep *ep = NULL; 162 struct mbuf *cp = NULL; 163 int error = 0; 164 165 /* Get event packet and update command buffer info */ 166 NG_HCI_M_PULLUP(e, sizeof(*ep)); 167 if (e == NULL) 168 return (ENOBUFS); /* XXX this is bad */ 169 170 ep = mtod(e, ng_hci_command_compl_ep *); 171 NG_HCI_BUFF_CMD_SET(unit->buffer, ep->num_cmd_pkts); 172 173 /* Check for special NOOP command */ 174 if (ep->opcode == 0x0000) { 175 NG_FREE_M(e); 176 goto out; 177 } 178 179 /* Try to match first command item in the queue */ 180 error = complete_command(unit, ep->opcode, &cp); 181 if (error != 0) { 182 NG_FREE_M(e); 183 goto out; 184 } 185 186 /* 187 * Perform post processing on command parameters and return parameters 188 * do it only if status is OK (status == 0). Status is the first byte 189 * of any command return parameters. 190 */ 191 192 ep->opcode = le16toh(ep->opcode); 193 m_adj(e, sizeof(*ep)); 194 195 if (*mtod(e, u_int8_t *) == 0) { /* XXX m_pullup here? */ 196 switch (NG_HCI_OGF(ep->opcode)) { 197 case NG_HCI_OGF_LINK_CONTROL: 198 error = process_link_control_params(unit, 199 NG_HCI_OCF(ep->opcode), cp, e); 200 break; 201 202 case NG_HCI_OGF_LINK_POLICY: 203 error = process_link_policy_params(unit, 204 NG_HCI_OCF(ep->opcode), cp, e); 205 break; 206 207 case NG_HCI_OGF_HC_BASEBAND: 208 error = process_hc_baseband_params(unit, 209 NG_HCI_OCF(ep->opcode), cp, e); 210 break; 211 212 case NG_HCI_OGF_INFO: 213 error = process_info_params(unit, 214 NG_HCI_OCF(ep->opcode), cp, e); 215 break; 216 217 case NG_HCI_OGF_STATUS: 218 error = process_status_params(unit, 219 NG_HCI_OCF(ep->opcode), cp, e); 220 break; 221 222 case NG_HCI_OGF_TESTING: 223 error = process_testing_params(unit, 224 NG_HCI_OCF(ep->opcode), cp, e); 225 break; 226 227 case NG_HCI_OGF_BT_LOGO: 228 case NG_HCI_OGF_VENDOR: 229 NG_FREE_M(cp); 230 NG_FREE_M(e); 231 break; 232 233 default: 234 NG_FREE_M(cp); 235 NG_FREE_M(e); 236 error = EINVAL; 237 break; 238 } 239 } else { 240 NG_HCI_ERR( 241 "%s: %s - HCI command failed, OGF=%#x, OCF=%#x, status=%#x\n", 242 __func__, NG_NODE_NAME(unit->node), 243 NG_HCI_OGF(ep->opcode), NG_HCI_OCF(ep->opcode), 244 *mtod(e, u_int8_t *)); 245 246 NG_FREE_M(cp); 247 NG_FREE_M(e); 248 } 249 out: 250 ng_hci_send_command(unit); 251 252 return (error); 253 } /* ng_hci_process_command_complete */ 254 255 /* 256 * Process HCI Command_Status event. Check the status (mst) and do post 257 * processing (if required). 258 */ 259 260 int 261 ng_hci_process_command_status(ng_hci_unit_p unit, struct mbuf *e) 262 { 263 ng_hci_command_status_ep *ep = NULL; 264 struct mbuf *cp = NULL; 265 int error = 0; 266 267 /* Update command buffer info */ 268 NG_HCI_M_PULLUP(e, sizeof(*ep)); 269 if (e == NULL) 270 return (ENOBUFS); /* XXX this is bad */ 271 272 ep = mtod(e, ng_hci_command_status_ep *); 273 NG_HCI_BUFF_CMD_SET(unit->buffer, ep->num_cmd_pkts); 274 275 /* Check for special NOOP command */ 276 if (ep->opcode == 0x0000) 277 goto out; 278 279 /* Try to match first command item in the queue */ 280 error = complete_command(unit, ep->opcode, &cp); 281 if (error != 0) 282 goto out; 283 284 /* 285 * Perform post processing on HCI Command_Status event 286 */ 287 288 ep->opcode = le16toh(ep->opcode); 289 290 switch (NG_HCI_OGF(ep->opcode)) { 291 case NG_HCI_OGF_LINK_CONTROL: 292 error = process_link_control_status(unit, ep, cp); 293 break; 294 295 case NG_HCI_OGF_LINK_POLICY: 296 error = process_link_policy_status(unit, ep, cp); 297 break; 298 299 case NG_HCI_OGF_BT_LOGO: 300 case NG_HCI_OGF_VENDOR: 301 NG_FREE_M(cp); 302 break; 303 304 case NG_HCI_OGF_HC_BASEBAND: 305 case NG_HCI_OGF_INFO: 306 case NG_HCI_OGF_STATUS: 307 case NG_HCI_OGF_TESTING: 308 default: 309 NG_FREE_M(cp); 310 error = EINVAL; 311 break; 312 } 313 out: 314 NG_FREE_M(e); 315 ng_hci_send_command(unit); 316 317 return (error); 318 } /* ng_hci_process_command_status */ 319 320 /* 321 * Complete queued HCI command. 322 */ 323 324 static int 325 complete_command(ng_hci_unit_p unit, int opcode, struct mbuf **cp) 326 { 327 struct mbuf *m = NULL; 328 329 /* Check unit state */ 330 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) { 331 NG_HCI_ALERT( 332 "%s: %s - no pending command, state=%#x\n", 333 __func__, NG_NODE_NAME(unit->node), unit->state); 334 335 return (EINVAL); 336 } 337 338 /* Get first command in the queue */ 339 m = NG_BT_MBUFQ_FIRST(&unit->cmdq); 340 if (m == NULL) { 341 NG_HCI_ALERT( 342 "%s: %s - empty command queue?!\n", __func__, NG_NODE_NAME(unit->node)); 343 344 return (EINVAL); 345 } 346 347 /* 348 * Match command opcode, if does not match - do nothing and 349 * let timeout handle that. 350 */ 351 352 if (mtod(m, ng_hci_cmd_pkt_t *)->opcode != opcode) { 353 NG_HCI_ALERT( 354 "%s: %s - command queue is out of sync\n", __func__, NG_NODE_NAME(unit->node)); 355 356 return (EINVAL); 357 } 358 359 /* 360 * Now we can remove command timeout, dequeue completed command 361 * and return command parameters. ng_hci_command_untimeout will 362 * drop NG_HCI_UNIT_COMMAND_PENDING flag. 363 * Note: if ng_hci_command_untimeout() fails (returns non-zero) 364 * then timeout aready happened and timeout message went info node 365 * queue. In this case we ignore command completion and pretend 366 * there is a timeout. 367 */ 368 369 if (ng_hci_command_untimeout(unit) != 0) 370 return (ETIMEDOUT); 371 372 NG_BT_MBUFQ_DEQUEUE(&unit->cmdq, *cp); 373 m_adj(*cp, sizeof(ng_hci_cmd_pkt_t)); 374 375 return (0); 376 } /* complete_command */ 377 378 /* 379 * Process HCI command timeout 380 */ 381 382 void 383 ng_hci_process_command_timeout(node_p node, hook_p hook, void *arg1, int arg2) 384 { 385 ng_hci_unit_p unit = NULL; 386 struct mbuf *m = NULL; 387 u_int16_t opcode; 388 389 if (NG_NODE_NOT_VALID(node)) { 390 printf("%s: Netgraph node is not valid\n", __func__); 391 return; 392 } 393 394 unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node); 395 396 if (unit->state & NG_HCI_UNIT_COMMAND_PENDING) { 397 unit->state &= ~NG_HCI_UNIT_COMMAND_PENDING; 398 399 NG_BT_MBUFQ_DEQUEUE(&unit->cmdq, m); 400 if (m == NULL) { 401 NG_HCI_ALERT( 402 "%s: %s - command queue is out of sync!\n", __func__, NG_NODE_NAME(unit->node)); 403 404 return; 405 } 406 407 opcode = le16toh(mtod(m, ng_hci_cmd_pkt_t *)->opcode); 408 NG_FREE_M(m); 409 410 NG_HCI_ERR( 411 "%s: %s - unable to complete HCI command OGF=%#x, OCF=%#x. Timeout\n", 412 __func__, NG_NODE_NAME(unit->node), NG_HCI_OGF(opcode), 413 NG_HCI_OCF(opcode)); 414 415 /* Try to send more commands */ 416 NG_HCI_BUFF_CMD_SET(unit->buffer, 1); 417 ng_hci_send_command(unit); 418 } else 419 NG_HCI_ALERT( 420 "%s: %s - no pending command\n", __func__, NG_NODE_NAME(unit->node)); 421 } /* ng_hci_process_command_timeout */ 422 423 /* 424 * Process link command return parameters 425 */ 426 427 static int 428 process_link_control_params(ng_hci_unit_p unit, u_int16_t ocf, 429 struct mbuf *mcp, struct mbuf *mrp) 430 { 431 int error = 0; 432 433 switch (ocf) { 434 case NG_HCI_OCF_INQUIRY_CANCEL: 435 case NG_HCI_OCF_PERIODIC_INQUIRY: 436 case NG_HCI_OCF_EXIT_PERIODIC_INQUIRY: 437 case NG_HCI_OCF_LINK_KEY_REP: 438 case NG_HCI_OCF_LINK_KEY_NEG_REP: 439 case NG_HCI_OCF_PIN_CODE_REP: 440 case NG_HCI_OCF_PIN_CODE_NEG_REP: 441 /* These do not need post processing */ 442 break; 443 444 case NG_HCI_OCF_INQUIRY: 445 case NG_HCI_OCF_CREATE_CON: 446 case NG_HCI_OCF_DISCON: 447 case NG_HCI_OCF_ADD_SCO_CON: 448 case NG_HCI_OCF_ACCEPT_CON: 449 case NG_HCI_OCF_REJECT_CON: 450 case NG_HCI_OCF_CHANGE_CON_PKT_TYPE: 451 case NG_HCI_OCF_AUTH_REQ: 452 case NG_HCI_OCF_SET_CON_ENCRYPTION: 453 case NG_HCI_OCF_CHANGE_CON_LINK_KEY: 454 case NG_HCI_OCF_MASTER_LINK_KEY: 455 case NG_HCI_OCF_REMOTE_NAME_REQ: 456 case NG_HCI_OCF_READ_REMOTE_FEATURES: 457 case NG_HCI_OCF_READ_REMOTE_VER_INFO: 458 case NG_HCI_OCF_READ_CLOCK_OFFSET: 459 default: 460 461 /* 462 * None of these command was supposed to generate 463 * Command_Complete event. Instead Command_Status event 464 * should have been generated and then appropriate event 465 * should have been sent to indicate the final result. 466 */ 467 468 error = EINVAL; 469 break; 470 } 471 472 NG_FREE_M(mcp); 473 NG_FREE_M(mrp); 474 475 return (error); 476 } /* process_link_control_params */ 477 478 /* 479 * Process link policy command return parameters 480 */ 481 482 static int 483 process_link_policy_params(ng_hci_unit_p unit, u_int16_t ocf, 484 struct mbuf *mcp, struct mbuf *mrp) 485 { 486 int error = 0; 487 488 switch (ocf){ 489 case NG_HCI_OCF_ROLE_DISCOVERY: { 490 ng_hci_role_discovery_rp *rp = NULL; 491 ng_hci_unit_con_t *con = NULL; 492 u_int16_t h; 493 494 NG_HCI_M_PULLUP(mrp, sizeof(*rp)); 495 if (mrp != NULL) { 496 rp = mtod(mrp, ng_hci_role_discovery_rp *); 497 498 h = NG_HCI_CON_HANDLE(le16toh(rp->con_handle)); 499 con = ng_hci_con_by_handle(unit, h); 500 if (con == NULL) { 501 NG_HCI_ALERT( 502 "%s: %s - invalid connection handle=%d\n", 503 __func__, NG_NODE_NAME(unit->node), h); 504 error = ENOENT; 505 } else if (con->link_type != NG_HCI_LINK_ACL) { 506 NG_HCI_ALERT( 507 "%s: %s - invalid link type=%d\n", __func__, NG_NODE_NAME(unit->node), 508 con->link_type); 509 error = EINVAL; 510 } else 511 con->role = rp->role; 512 } else 513 error = ENOBUFS; 514 } break; 515 516 case NG_HCI_OCF_READ_LINK_POLICY_SETTINGS: 517 case NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS: 518 /* These do not need post processing */ 519 break; 520 521 case NG_HCI_OCF_HOLD_MODE: 522 case NG_HCI_OCF_SNIFF_MODE: 523 case NG_HCI_OCF_EXIT_SNIFF_MODE: 524 case NG_HCI_OCF_PARK_MODE: 525 case NG_HCI_OCF_EXIT_PARK_MODE: 526 case NG_HCI_OCF_QOS_SETUP: 527 case NG_HCI_OCF_SWITCH_ROLE: 528 default: 529 530 /* 531 * None of these command was supposed to generate 532 * Command_Complete event. Instead Command_Status event 533 * should have been generated and then appropriate event 534 * should have been sent to indicate the final result. 535 */ 536 537 error = EINVAL; 538 break; 539 } 540 541 NG_FREE_M(mcp); 542 NG_FREE_M(mrp); 543 544 return (error); 545 } /* process_link_policy_params */ 546 547 /* 548 * Process HC and baseband command return parameters 549 */ 550 551 int 552 process_hc_baseband_params(ng_hci_unit_p unit, u_int16_t ocf, 553 struct mbuf *mcp, struct mbuf *mrp) 554 { 555 int error = 0; 556 557 switch (ocf) { 558 case NG_HCI_OCF_SET_EVENT_MASK: 559 case NG_HCI_OCF_SET_EVENT_FILTER: 560 case NG_HCI_OCF_FLUSH: /* XXX Do we need to handle that? */ 561 case NG_HCI_OCF_READ_PIN_TYPE: 562 case NG_HCI_OCF_WRITE_PIN_TYPE: 563 case NG_HCI_OCF_CREATE_NEW_UNIT_KEY: 564 case NG_HCI_OCF_WRITE_STORED_LINK_KEY: 565 case NG_HCI_OCF_WRITE_CON_ACCEPT_TIMO: 566 case NG_HCI_OCF_WRITE_PAGE_TIMO: 567 case NG_HCI_OCF_READ_SCAN_ENABLE: 568 case NG_HCI_OCF_WRITE_SCAN_ENABLE: 569 case NG_HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY: 570 case NG_HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY: 571 case NG_HCI_OCF_READ_AUTH_ENABLE: 572 case NG_HCI_OCF_WRITE_AUTH_ENABLE: 573 case NG_HCI_OCF_READ_ENCRYPTION_MODE: 574 case NG_HCI_OCF_WRITE_ENCRYPTION_MODE: 575 case NG_HCI_OCF_WRITE_VOICE_SETTINGS: 576 case NG_HCI_OCF_READ_NUM_BROADCAST_RETRANS: 577 case NG_HCI_OCF_WRITE_NUM_BROADCAST_RETRANS: 578 case NG_HCI_OCF_READ_HOLD_MODE_ACTIVITY: 579 case NG_HCI_OCF_WRITE_HOLD_MODE_ACTIVITY: 580 case NG_HCI_OCF_READ_SCO_FLOW_CONTROL: 581 case NG_HCI_OCF_WRITE_SCO_FLOW_CONTROL: 582 case NG_HCI_OCF_H2HC_FLOW_CONTROL: /* XXX Not supported this time */ 583 case NG_HCI_OCF_HOST_BUFFER_SIZE: 584 case NG_HCI_OCF_READ_IAC_LAP: 585 case NG_HCI_OCF_WRITE_IAC_LAP: 586 case NG_HCI_OCF_READ_PAGE_SCAN_PERIOD: 587 case NG_HCI_OCF_WRITE_PAGE_SCAN_PERIOD: 588 case NG_HCI_OCF_READ_PAGE_SCAN: 589 case NG_HCI_OCF_WRITE_PAGE_SCAN: 590 case NG_HCI_OCF_READ_LINK_SUPERVISION_TIMO: 591 case NG_HCI_OCF_WRITE_LINK_SUPERVISION_TIMO: 592 case NG_HCI_OCF_READ_SUPPORTED_IAC_NUM: 593 case NG_HCI_OCF_READ_STORED_LINK_KEY: 594 case NG_HCI_OCF_DELETE_STORED_LINK_KEY: 595 case NG_HCI_OCF_READ_CON_ACCEPT_TIMO: 596 case NG_HCI_OCF_READ_PAGE_TIMO: 597 case NG_HCI_OCF_READ_PAGE_SCAN_ACTIVITY: 598 case NG_HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY: 599 case NG_HCI_OCF_READ_VOICE_SETTINGS: 600 case NG_HCI_OCF_READ_AUTO_FLUSH_TIMO: 601 case NG_HCI_OCF_WRITE_AUTO_FLUSH_TIMO: 602 case NG_HCI_OCF_READ_XMIT_LEVEL: 603 case NG_HCI_OCF_HOST_NUM_COMPL_PKTS: /* XXX Can get here? */ 604 case NG_HCI_OCF_CHANGE_LOCAL_NAME: 605 case NG_HCI_OCF_READ_LOCAL_NAME: 606 case NG_HCI_OCF_READ_UNIT_CLASS: 607 case NG_HCI_OCF_WRITE_UNIT_CLASS: 608 /* These do not need post processing */ 609 break; 610 611 case NG_HCI_OCF_RESET: { 612 ng_hci_unit_con_p con = NULL; 613 int size; 614 615 /* 616 * XXX 617 * 618 * After RESET command unit goes into standby mode 619 * and all operational state is lost. Host controller 620 * will revert to default values for all parameters. 621 * 622 * For now we shall terminate all connections and drop 623 * inited bit. After RESET unit must be re-initialized. 624 */ 625 626 while (!LIST_EMPTY(&unit->con_list)) { 627 con = LIST_FIRST(&unit->con_list); 628 629 /* Remove all timeouts (if any) */ 630 if (con->flags & NG_HCI_CON_TIMEOUT_PENDING) 631 ng_hci_con_untimeout(con); 632 633 /* Connection terminated by local host */ 634 ng_hci_lp_discon_ind(con, 0x16); 635 ng_hci_free_con(con); 636 } 637 638 NG_HCI_BUFF_ACL_TOTAL(unit->buffer, size); 639 NG_HCI_BUFF_ACL_FREE(unit->buffer, size); 640 641 NG_HCI_BUFF_SCO_TOTAL(unit->buffer, size); 642 NG_HCI_BUFF_SCO_FREE(unit->buffer, size); 643 644 unit->state &= ~NG_HCI_UNIT_INITED; 645 } break; 646 647 default: 648 error = EINVAL; 649 break; 650 } 651 652 NG_FREE_M(mcp); 653 NG_FREE_M(mrp); 654 655 return (error); 656 } /* process_hc_baseband_params */ 657 658 /* 659 * Process info command return parameters 660 */ 661 662 static int 663 process_info_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp, 664 struct mbuf *mrp) 665 { 666 int error = 0, len; 667 668 switch (ocf) { 669 case NG_HCI_OCF_READ_LOCAL_VER: 670 case NG_HCI_OCF_READ_COUNTRY_CODE: 671 break; 672 673 case NG_HCI_OCF_READ_LOCAL_FEATURES: 674 m_adj(mrp, sizeof(u_int8_t)); 675 len = min(mrp->m_pkthdr.len, sizeof(unit->features)); 676 m_copydata(mrp, 0, len, (caddr_t) unit->features); 677 break; 678 679 case NG_HCI_OCF_READ_BUFFER_SIZE: { 680 ng_hci_read_buffer_size_rp *rp = NULL; 681 682 /* Do not update buffer descriptor if node was initialized */ 683 if ((unit->state & NG_HCI_UNIT_READY) == NG_HCI_UNIT_READY) 684 break; 685 686 NG_HCI_M_PULLUP(mrp, sizeof(*rp)); 687 if (mrp != NULL) { 688 rp = mtod(mrp, ng_hci_read_buffer_size_rp *); 689 690 NG_HCI_BUFF_ACL_SET( 691 unit->buffer, 692 le16toh(rp->num_acl_pkt), /* number */ 693 le16toh(rp->max_acl_size), /* size */ 694 le16toh(rp->num_acl_pkt) /* free */ 695 ); 696 697 NG_HCI_BUFF_SCO_SET( 698 unit->buffer, 699 le16toh(rp->num_sco_pkt), /* number */ 700 rp->max_sco_size, /* size */ 701 le16toh(rp->num_sco_pkt) /* free */ 702 ); 703 704 /* Let upper layers know */ 705 ng_hci_node_is_up(unit->node, unit->acl, NULL, 0); 706 ng_hci_node_is_up(unit->node, unit->sco, NULL, 0); 707 } else 708 error = ENOBUFS; 709 } break; 710 711 case NG_HCI_OCF_READ_BDADDR: 712 /* Do not update BD_ADDR if node was initialized */ 713 if ((unit->state & NG_HCI_UNIT_READY) == NG_HCI_UNIT_READY) 714 break; 715 716 m_adj(mrp, sizeof(u_int8_t)); 717 len = min(mrp->m_pkthdr.len, sizeof(unit->bdaddr)); 718 m_copydata(mrp, 0, len, (caddr_t) &unit->bdaddr); 719 720 /* Let upper layers know */ 721 ng_hci_node_is_up(unit->node, unit->acl, NULL, 0); 722 ng_hci_node_is_up(unit->node, unit->sco, NULL, 0); 723 break; 724 725 default: 726 error = EINVAL; 727 break; 728 } 729 730 NG_FREE_M(mcp); 731 NG_FREE_M(mrp); 732 733 return (error); 734 } /* process_info_params */ 735 736 /* 737 * Process status command return parameters 738 */ 739 740 static int 741 process_status_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp, 742 struct mbuf *mrp) 743 { 744 int error = 0; 745 746 switch (ocf) { 747 case NG_HCI_OCF_READ_FAILED_CONTACT_CNTR: 748 case NG_HCI_OCF_RESET_FAILED_CONTACT_CNTR: 749 case NG_HCI_OCF_GET_LINK_QUALITY: 750 case NG_HCI_OCF_READ_RSSI: 751 /* These do not need post processing */ 752 break; 753 754 default: 755 error = EINVAL; 756 break; 757 } 758 759 NG_FREE_M(mcp); 760 NG_FREE_M(mrp); 761 762 return (error); 763 } /* process_status_params */ 764 765 /* 766 * Process testing command return parameters 767 */ 768 769 int 770 process_testing_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp, 771 struct mbuf *mrp) 772 { 773 int error = 0; 774 775 switch (ocf) { 776 777 /* 778 * XXX FIXME 779 * We do not support these features at this time. However, 780 * HCI node could support this and do something smart. At least 781 * node can change unit state. 782 */ 783 784 case NG_HCI_OCF_READ_LOOPBACK_MODE: 785 case NG_HCI_OCF_WRITE_LOOPBACK_MODE: 786 case NG_HCI_OCF_ENABLE_UNIT_UNDER_TEST: 787 break; 788 789 default: 790 error = EINVAL; 791 break; 792 } 793 794 NG_FREE_M(mcp); 795 NG_FREE_M(mrp); 796 797 return (error); 798 } /* process_testing_params */ 799 800 /* 801 * Process link control command status 802 */ 803 804 static int 805 process_link_control_status(ng_hci_unit_p unit, ng_hci_command_status_ep *ep, 806 struct mbuf *mcp) 807 { 808 int error = 0; 809 810 switch (NG_HCI_OCF(ep->opcode)) { 811 case NG_HCI_OCF_INQUIRY: 812 case NG_HCI_OCF_DISCON: /* XXX */ 813 case NG_HCI_OCF_REJECT_CON: /* XXX */ 814 case NG_HCI_OCF_CHANGE_CON_PKT_TYPE: 815 case NG_HCI_OCF_AUTH_REQ: 816 case NG_HCI_OCF_SET_CON_ENCRYPTION: 817 case NG_HCI_OCF_CHANGE_CON_LINK_KEY: 818 case NG_HCI_OCF_MASTER_LINK_KEY: 819 case NG_HCI_OCF_REMOTE_NAME_REQ: 820 case NG_HCI_OCF_READ_REMOTE_FEATURES: 821 case NG_HCI_OCF_READ_REMOTE_VER_INFO: 822 case NG_HCI_OCF_READ_CLOCK_OFFSET: 823 /* These do not need post processing */ 824 break; 825 826 case NG_HCI_OCF_CREATE_CON: 827 break; 828 829 case NG_HCI_OCF_ADD_SCO_CON: 830 break; 831 832 case NG_HCI_OCF_ACCEPT_CON: 833 break; 834 835 case NG_HCI_OCF_INQUIRY_CANCEL: 836 case NG_HCI_OCF_PERIODIC_INQUIRY: 837 case NG_HCI_OCF_EXIT_PERIODIC_INQUIRY: 838 case NG_HCI_OCF_LINK_KEY_REP: 839 case NG_HCI_OCF_LINK_KEY_NEG_REP: 840 case NG_HCI_OCF_PIN_CODE_REP: 841 case NG_HCI_OCF_PIN_CODE_NEG_REP: 842 default: 843 844 /* 845 * None of these command was supposed to generate 846 * Command_Status event. Instead Command_Complete event 847 * should have been sent. 848 */ 849 850 error = EINVAL; 851 break; 852 } 853 854 NG_FREE_M(mcp); 855 856 return (error); 857 } /* process_link_control_status */ 858 859 /* 860 * Process link policy command status 861 */ 862 863 static int 864 process_link_policy_status(ng_hci_unit_p unit, ng_hci_command_status_ep *ep, 865 struct mbuf *mcp) 866 { 867 int error = 0; 868 869 switch (NG_HCI_OCF(ep->opcode)) { 870 case NG_HCI_OCF_HOLD_MODE: 871 case NG_HCI_OCF_SNIFF_MODE: 872 case NG_HCI_OCF_EXIT_SNIFF_MODE: 873 case NG_HCI_OCF_PARK_MODE: 874 case NG_HCI_OCF_EXIT_PARK_MODE: 875 case NG_HCI_OCF_SWITCH_ROLE: 876 /* These do not need post processing */ 877 break; 878 879 case NG_HCI_OCF_QOS_SETUP: 880 break; 881 882 case NG_HCI_OCF_ROLE_DISCOVERY: 883 case NG_HCI_OCF_READ_LINK_POLICY_SETTINGS: 884 case NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS: 885 default: 886 887 /* 888 * None of these command was supposed to generate 889 * Command_Status event. Instead Command_Complete event 890 * should have been sent. 891 */ 892 893 error = EINVAL; 894 break; 895 } 896 897 NG_FREE_M(mcp); 898 899 return (error); 900 } /* process_link_policy_status */ 901 902