ng_hci_cmds.c revision 121054
1231990Smp/* 259243Sobrien * ng_hci_cmds.c 359243Sobrien * 459243Sobrien * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 559243Sobrien * All rights reserved. 659243Sobrien * 759243Sobrien * Redistribution and use in source and binary forms, with or without 859243Sobrien * modification, are permitted provided that the following conditions 959243Sobrien * are met: 1059243Sobrien * 1. Redistributions of source code must retain the above copyright 1159243Sobrien * notice, this list of conditions and the following disclaimer. 1259243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer in the 1459243Sobrien * documentation and/or other materials provided with the distribution. 1559243Sobrien * 1659243Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1759243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1859243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1959243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2059243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2159243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22167465Smp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23167465Smp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24167465Smp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2559243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26167465Smp * SUCH DAMAGE. 27167465Smp * 2859243Sobrien * $Id: ng_hci_cmds.c,v 1.4 2003/09/08 18:57:51 max Exp $ 2959243Sobrien * $FreeBSD: head/sys/netgraph/bluetooth/hci/ng_hci_cmds.c 121054 2003-10-12 22:04:24Z emax $ 3059243Sobrien */ 3159243Sobrien 3259243Sobrien#include <sys/param.h> 3359243Sobrien#include <sys/systm.h> 3459243Sobrien#include <sys/kernel.h> 3559243Sobrien#include <sys/endian.h> 3659243Sobrien#include <sys/malloc.h> 37167465Smp#include <sys/mbuf.h> 3859243Sobrien#include <sys/queue.h> 3959243Sobrien#include <netgraph/ng_message.h> 4059243Sobrien#include <netgraph/netgraph.h> 4159243Sobrien#include "ng_bluetooth.h" 4259243Sobrien#include "ng_hci.h" 4359243Sobrien#include "ng_hci_var.h" 4459243Sobrien#include "ng_hci_cmds.h" 4559243Sobrien#include "ng_hci_evnt.h" 4659243Sobrien#include "ng_hci_ulpi.h" 4759243Sobrien#include "ng_hci_misc.h" 4859243Sobrien 4959243Sobrien/****************************************************************************** 5059243Sobrien ****************************************************************************** 51167465Smp ** HCI commands processing module 5259243Sobrien ****************************************************************************** 5359243Sobrien ******************************************************************************/ 5459243Sobrien 5559243Sobrien#undef min 5659243Sobrien#define min(a, b) ((a) < (b))? (a) : (b) 5759243Sobrien 58167465Smpstatic int complete_command (ng_hci_unit_p, int, struct mbuf **); 5959243Sobrien 60167465Smpstatic int process_link_control_params 6159243Sobrien (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 6259243Sobrienstatic int process_link_policy_params 6359243Sobrien (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 6459243Sobrienstatic int process_hc_baseband_params 65167465Smp (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 6659243Sobrienstatic int process_info_params 6759243Sobrien (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 6859243Sobrienstatic int process_status_params 6959243Sobrien (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 7059243Sobrienstatic int process_testing_params 7159243Sobrien (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 7259243Sobrien 7359243Sobrienstatic int process_link_control_status 7459243Sobrien (ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *); 7559243Sobrienstatic int process_link_policy_status 7659243Sobrien (ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *); 7759243Sobrien 7859243Sobrien/* 7959243Sobrien * Send HCI command to the driver. 8059243Sobrien */ 8159243Sobrien 8259243Sobrienint 83167465Smpng_hci_send_command(ng_hci_unit_p unit) 8459243Sobrien{ 8559243Sobrien struct mbuf *m0 = NULL, *m = NULL; 8659243Sobrien int free, error = 0; 8759243Sobrien 88167465Smp /* Check if other command is pending */ 8959243Sobrien if (unit->state & NG_HCI_UNIT_COMMAND_PENDING) 90231990Smp return (0); 9159243Sobrien 92145479Smp /* Check if unit can accept our command */ 93145479Smp NG_HCI_BUFF_CMD_GET(unit->buffer, free); 94145479Smp if (free == 0) 95145479Smp return (0); 96131962Smp 97131962Smp /* Check if driver hook is still ok */ 9859243Sobrien if (unit->drv == NULL || NG_HOOK_NOT_VALID(unit->drv)) { 9959243Sobrien NG_HCI_WARN( 10059243Sobrien"%s: %s - hook \"%s\" is not connected or valid\n", 10159243Sobrien __func__, NG_NODE_NAME(unit->node), NG_HCI_HOOK_DRV); 10259243Sobrien 10359243Sobrien NG_BT_MBUFQ_DRAIN(&unit->cmdq); 10459243Sobrien 10559243Sobrien return (ENOTCONN); 10659243Sobrien } 107145479Smp 10859243Sobrien /* 10959243Sobrien * Get first command from queue, give it to RAW hook then 11059243Sobrien * make copy of it and send it to the driver 11159243Sobrien */ 11259243Sobrien 11359243Sobrien m0 = NG_BT_MBUFQ_FIRST(&unit->cmdq); 11459243Sobrien if (m0 == NULL) 11559243Sobrien return (0); 11659243Sobrien 11759243Sobrien ng_hci_mtap(unit, m0); 11859243Sobrien 11959243Sobrien m = m_dup(m0, M_DONTWAIT); 12059243Sobrien if (m != NULL) 12159243Sobrien NG_SEND_DATA_ONLY(error, unit->drv, m); 12259243Sobrien else 12359243Sobrien error = ENOBUFS; 12459243Sobrien 12559243Sobrien if (error != 0) 12659243Sobrien NG_HCI_ERR( 12759243Sobrien"%s: %s - could not send HCI command, error=%d\n", 12859243Sobrien __func__, NG_NODE_NAME(unit->node), error); 12959243Sobrien 13059243Sobrien /* 13159243Sobrien * Even if we were not able to send command we still pretend 13259243Sobrien * that everything is OK and let timeout handle that. 13359243Sobrien */ 13459243Sobrien 13559243Sobrien NG_HCI_BUFF_CMD_USE(unit->buffer, 1); 13659243Sobrien NG_HCI_STAT_CMD_SENT(unit->stat); 13759243Sobrien NG_HCI_STAT_BYTES_SENT(unit->stat, m0->m_pkthdr.len); 13859243Sobrien 13959243Sobrien /* 14059243Sobrien * Note: ng_hci_command_timeout() will set 14159243Sobrien * NG_HCI_UNIT_COMMAND_PENDING flag 14259243Sobrien */ 14359243Sobrien 14459243Sobrien ng_hci_command_timeout(unit); 14559243Sobrien 14659243Sobrien return (0); 14759243Sobrien} /* ng_hci_send_command */ 14859243Sobrien 14959243Sobrien/* 15059243Sobrien * Process HCI Command_Compete event. Complete HCI command, and do post 15159243Sobrien * processing on the command parameters (cp) and command return parameters 15259243Sobrien * (e) if required (for example adjust state). 15359243Sobrien */ 15459243Sobrien 15559243Sobrienint 15659243Sobrienng_hci_process_command_complete(ng_hci_unit_p unit, struct mbuf *e) 15759243Sobrien{ 15859243Sobrien ng_hci_command_compl_ep *ep = NULL; 15959243Sobrien struct mbuf *cp = NULL; 16059243Sobrien int error = 0; 16159243Sobrien 16259243Sobrien /* Get event packet and update command buffer info */ 16359243Sobrien NG_HCI_M_PULLUP(e, sizeof(*ep)); 16459243Sobrien if (e == NULL) 16559243Sobrien return (ENOBUFS); /* XXX this is bad */ 16659243Sobrien 16759243Sobrien ep = mtod(e, ng_hci_command_compl_ep *); 16859243Sobrien NG_HCI_BUFF_CMD_SET(unit->buffer, ep->num_cmd_pkts); 16959243Sobrien 17059243Sobrien /* Check for special NOOP command */ 17159243Sobrien if (ep->opcode == 0x0000) { 17259243Sobrien NG_FREE_M(e); 17359243Sobrien goto out; 17459243Sobrien } 17559243Sobrien 17659243Sobrien /* Try to match first command item in the queue */ 17759243Sobrien error = complete_command(unit, ep->opcode, &cp); 17859243Sobrien if (error != 0) { 17959243Sobrien NG_FREE_M(e); 18059243Sobrien goto out; 18159243Sobrien } 18259243Sobrien 18359243Sobrien /* 18459243Sobrien * Perform post processing on command parameters and return parameters 18559243Sobrien * do it only if status is OK (status == 0). Status is the first byte 18659243Sobrien * of any command return parameters. 18759243Sobrien */ 18859243Sobrien 18959243Sobrien ep->opcode = le16toh(ep->opcode); 19059243Sobrien m_adj(e, sizeof(*ep)); 19159243Sobrien 19259243Sobrien if (*mtod(e, u_int8_t *) == 0) { /* XXX m_pullup here? */ 19359243Sobrien switch (NG_HCI_OGF(ep->opcode)) { 19459243Sobrien case NG_HCI_OGF_LINK_CONTROL: 19559243Sobrien error = process_link_control_params(unit, 19659243Sobrien NG_HCI_OCF(ep->opcode), cp, e); 19759243Sobrien break; 19859243Sobrien 19959243Sobrien case NG_HCI_OGF_LINK_POLICY: 20059243Sobrien error = process_link_policy_params(unit, 20159243Sobrien NG_HCI_OCF(ep->opcode), cp, e); 20259243Sobrien break; 20359243Sobrien 20459243Sobrien case NG_HCI_OGF_HC_BASEBAND: 20559243Sobrien error = process_hc_baseband_params(unit, 20659243Sobrien NG_HCI_OCF(ep->opcode), cp, e); 20759243Sobrien break; 208 209 case NG_HCI_OGF_INFO: 210 error = process_info_params(unit, 211 NG_HCI_OCF(ep->opcode), cp, e); 212 break; 213 214 case NG_HCI_OGF_STATUS: 215 error = process_status_params(unit, 216 NG_HCI_OCF(ep->opcode), cp, e); 217 break; 218 219 case NG_HCI_OGF_TESTING: 220 error = process_testing_params(unit, 221 NG_HCI_OCF(ep->opcode), cp, e); 222 break; 223 224 case NG_HCI_OGF_BT_LOGO: 225 case NG_HCI_OGF_VENDOR: 226 NG_FREE_M(cp); 227 NG_FREE_M(e); 228 break; 229 230 default: 231 NG_FREE_M(cp); 232 NG_FREE_M(e); 233 error = EINVAL; 234 break; 235 } 236 } else { 237 NG_HCI_ERR( 238"%s: %s - HCI command failed, OGF=%#x, OCF=%#x, status=%#x\n", 239 __func__, NG_NODE_NAME(unit->node), 240 NG_HCI_OGF(ep->opcode), NG_HCI_OCF(ep->opcode), 241 *mtod(e, u_int8_t *)); 242 243 NG_FREE_M(cp); 244 NG_FREE_M(e); 245 } 246out: 247 ng_hci_send_command(unit); 248 249 return (error); 250} /* ng_hci_process_command_complete */ 251 252/* 253 * Process HCI Command_Status event. Check the status (mst) and do post 254 * processing (if required). 255 */ 256 257int 258ng_hci_process_command_status(ng_hci_unit_p unit, struct mbuf *e) 259{ 260 ng_hci_command_status_ep *ep = NULL; 261 struct mbuf *cp = NULL; 262 int error = 0; 263 264 /* Update command buffer info */ 265 NG_HCI_M_PULLUP(e, sizeof(*ep)); 266 if (e == NULL) 267 return (ENOBUFS); /* XXX this is bad */ 268 269 ep = mtod(e, ng_hci_command_status_ep *); 270 NG_HCI_BUFF_CMD_SET(unit->buffer, ep->num_cmd_pkts); 271 272 /* Check for special NOOP command */ 273 if (ep->opcode == 0x0000) 274 goto out; 275 276 /* Try to match first command item in the queue */ 277 error = complete_command(unit, ep->opcode, &cp); 278 if (error != 0) 279 goto out; 280 281 /* 282 * Perform post processing on HCI Command_Status event 283 */ 284 285 ep->opcode = le16toh(ep->opcode); 286 287 switch (NG_HCI_OGF(ep->opcode)) { 288 case NG_HCI_OGF_LINK_CONTROL: 289 error = process_link_control_status(unit, ep, cp); 290 break; 291 292 case NG_HCI_OGF_LINK_POLICY: 293 error = process_link_policy_status(unit, ep, cp); 294 break; 295 296 case NG_HCI_OGF_BT_LOGO: 297 case NG_HCI_OGF_VENDOR: 298 NG_FREE_M(cp); 299 break; 300 301 case NG_HCI_OGF_HC_BASEBAND: 302 case NG_HCI_OGF_INFO: 303 case NG_HCI_OGF_STATUS: 304 case NG_HCI_OGF_TESTING: 305 default: 306 NG_FREE_M(cp); 307 error = EINVAL; 308 break; 309 } 310out: 311 NG_FREE_M(e); 312 ng_hci_send_command(unit); 313 314 return (error); 315} /* ng_hci_process_command_status */ 316 317/* 318 * Complete queued HCI command. 319 */ 320 321static int 322complete_command(ng_hci_unit_p unit, int opcode, struct mbuf **cp) 323{ 324 struct mbuf *m = NULL; 325 326 /* Check unit state */ 327 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) { 328 NG_HCI_ALERT( 329"%s: %s - no pending command, state=%#x\n", 330 __func__, NG_NODE_NAME(unit->node), unit->state); 331 332 return (EINVAL); 333 } 334 335 /* Get first command in the queue */ 336 m = NG_BT_MBUFQ_FIRST(&unit->cmdq); 337 if (m == NULL) { 338 NG_HCI_ALERT( 339"%s: %s - empty command queue?!\n", __func__, NG_NODE_NAME(unit->node)); 340 341 return (EINVAL); 342 } 343 344 /* 345 * Match command opcode, if does not match - do nothing and 346 * let timeout handle that. 347 */ 348 349 if (mtod(m, ng_hci_cmd_pkt_t *)->opcode != opcode) { 350 NG_HCI_ALERT( 351"%s: %s - command queue is out of sync\n", __func__, NG_NODE_NAME(unit->node)); 352 353 return (EINVAL); 354 } 355 356 /* 357 * Now we can remove command timeout, dequeue completed command 358 * and return command parameters. ng_hci_command_untimeout will 359 * drop NG_HCI_UNIT_COMMAND_PENDING flag. 360 * Note: if ng_hci_command_untimeout() fails (returns non-zero) 361 * then timeout aready happened and timeout message went info node 362 * queue. In this case we ignore command completion and pretend 363 * there is a timeout. 364 */ 365 366 if (ng_hci_command_untimeout(unit) != 0) 367 return (ETIMEDOUT); 368 369 NG_BT_MBUFQ_DEQUEUE(&unit->cmdq, *cp); 370 m_adj(*cp, sizeof(ng_hci_cmd_pkt_t)); 371 372 return (0); 373} /* complete_command */ 374 375/* 376 * Process HCI command timeout 377 */ 378 379void 380ng_hci_process_command_timeout(node_p node, hook_p hook, void *arg1, int arg2) 381{ 382 ng_hci_unit_p unit = NULL; 383 struct mbuf *m = NULL; 384 u_int16_t opcode; 385 386 if (NG_NODE_NOT_VALID(node)) { 387 printf("%s: Netgraph node is not valid\n", __func__); 388 return; 389 } 390 391 unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node); 392 393 if (unit->state & NG_HCI_UNIT_COMMAND_PENDING) { 394 unit->state &= ~NG_HCI_UNIT_COMMAND_PENDING; 395 396 NG_BT_MBUFQ_DEQUEUE(&unit->cmdq, m); 397 if (m == NULL) { 398 NG_HCI_ALERT( 399"%s: %s - command queue is out of sync!\n", __func__, NG_NODE_NAME(unit->node)); 400 401 return; 402 } 403 404 opcode = le16toh(mtod(m, ng_hci_cmd_pkt_t *)->opcode); 405 NG_FREE_M(m); 406 407 NG_HCI_ERR( 408"%s: %s - unable to complete HCI command OGF=%#x, OCF=%#x. Timeout\n", 409 __func__, NG_NODE_NAME(unit->node), NG_HCI_OGF(opcode), 410 NG_HCI_OCF(opcode)); 411 412 /* Try to send more commands */ 413 NG_HCI_BUFF_CMD_SET(unit->buffer, 1); 414 ng_hci_send_command(unit); 415 } else 416 NG_HCI_ALERT( 417"%s: %s - no pending command\n", __func__, NG_NODE_NAME(unit->node)); 418} /* ng_hci_process_command_timeout */ 419 420/* 421 * Process link command return parameters 422 */ 423 424static int 425process_link_control_params(ng_hci_unit_p unit, u_int16_t ocf, 426 struct mbuf *mcp, struct mbuf *mrp) 427{ 428 int error = 0; 429 430 switch (ocf) { 431 case NG_HCI_OCF_INQUIRY_CANCEL: 432 case NG_HCI_OCF_PERIODIC_INQUIRY: 433 case NG_HCI_OCF_EXIT_PERIODIC_INQUIRY: 434 case NG_HCI_OCF_LINK_KEY_REP: 435 case NG_HCI_OCF_LINK_KEY_NEG_REP: 436 case NG_HCI_OCF_PIN_CODE_REP: 437 case NG_HCI_OCF_PIN_CODE_NEG_REP: 438 /* These do not need post processing */ 439 break; 440 441 case NG_HCI_OCF_INQUIRY: 442 case NG_HCI_OCF_CREATE_CON: 443 case NG_HCI_OCF_DISCON: 444 case NG_HCI_OCF_ADD_SCO_CON: 445 case NG_HCI_OCF_ACCEPT_CON: 446 case NG_HCI_OCF_REJECT_CON: 447 case NG_HCI_OCF_CHANGE_CON_PKT_TYPE: 448 case NG_HCI_OCF_AUTH_REQ: 449 case NG_HCI_OCF_SET_CON_ENCRYPTION: 450 case NG_HCI_OCF_CHANGE_CON_LINK_KEY: 451 case NG_HCI_OCF_MASTER_LINK_KEY: 452 case NG_HCI_OCF_REMOTE_NAME_REQ: 453 case NG_HCI_OCF_READ_REMOTE_FEATURES: 454 case NG_HCI_OCF_READ_REMOTE_VER_INFO: 455 case NG_HCI_OCF_READ_CLOCK_OFFSET: 456 default: 457 458 /* 459 * None of these command was supposed to generate 460 * Command_Complete event. Instead Command_Status event 461 * should have been generated and then appropriate event 462 * should have been sent to indicate the final result. 463 */ 464 465 error = EINVAL; 466 break; 467 } 468 469 NG_FREE_M(mcp); 470 NG_FREE_M(mrp); 471 472 return (error); 473} /* process_link_control_params */ 474 475/* 476 * Process link policy command return parameters 477 */ 478 479static int 480process_link_policy_params(ng_hci_unit_p unit, u_int16_t ocf, 481 struct mbuf *mcp, struct mbuf *mrp) 482{ 483 int error = 0; 484 485 switch (ocf){ 486 case NG_HCI_OCF_ROLE_DISCOVERY: { 487 ng_hci_role_discovery_rp *rp = NULL; 488 ng_hci_unit_con_t *con = NULL; 489 u_int16_t h; 490 491 NG_HCI_M_PULLUP(mrp, sizeof(*rp)); 492 if (mrp != NULL) { 493 rp = mtod(mrp, ng_hci_role_discovery_rp *); 494 495 h = NG_HCI_CON_HANDLE(le16toh(rp->con_handle)); 496 con = ng_hci_con_by_handle(unit, h); 497 if (con == NULL) { 498 NG_HCI_ALERT( 499"%s: %s - invalid connection handle=%d\n", 500 __func__, NG_NODE_NAME(unit->node), h); 501 error = ENOENT; 502 } else if (con->link_type != NG_HCI_LINK_ACL) { 503 NG_HCI_ALERT( 504"%s: %s - invalid link type=%d\n", __func__, NG_NODE_NAME(unit->node), 505 con->link_type); 506 error = EINVAL; 507 } else 508 con->role = rp->role; 509 } else 510 error = ENOBUFS; 511 } break; 512 513 case NG_HCI_OCF_READ_LINK_POLICY_SETTINGS: 514 case NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS: 515 /* These do not need post processing */ 516 break; 517 518 case NG_HCI_OCF_HOLD_MODE: 519 case NG_HCI_OCF_SNIFF_MODE: 520 case NG_HCI_OCF_EXIT_SNIFF_MODE: 521 case NG_HCI_OCF_PARK_MODE: 522 case NG_HCI_OCF_EXIT_PARK_MODE: 523 case NG_HCI_OCF_QOS_SETUP: 524 case NG_HCI_OCF_SWITCH_ROLE: 525 default: 526 527 /* 528 * None of these command was supposed to generate 529 * Command_Complete event. Instead Command_Status event 530 * should have been generated and then appropriate event 531 * should have been sent to indicate the final result. 532 */ 533 534 error = EINVAL; 535 break; 536 } 537 538 NG_FREE_M(mcp); 539 NG_FREE_M(mrp); 540 541 return (error); 542} /* process_link_policy_params */ 543 544/* 545 * Process HC and baseband command return parameters 546 */ 547 548int 549process_hc_baseband_params(ng_hci_unit_p unit, u_int16_t ocf, 550 struct mbuf *mcp, struct mbuf *mrp) 551{ 552 int error = 0; 553 554 switch (ocf) { 555 case NG_HCI_OCF_SET_EVENT_MASK: 556 case NG_HCI_OCF_SET_EVENT_FILTER: 557 case NG_HCI_OCF_FLUSH: /* XXX Do we need to handle that? */ 558 case NG_HCI_OCF_READ_PIN_TYPE: 559 case NG_HCI_OCF_WRITE_PIN_TYPE: 560 case NG_HCI_OCF_CREATE_NEW_UNIT_KEY: 561 case NG_HCI_OCF_WRITE_STORED_LINK_KEY: 562 case NG_HCI_OCF_WRITE_CON_ACCEPT_TIMO: 563 case NG_HCI_OCF_WRITE_PAGE_TIMO: 564 case NG_HCI_OCF_READ_SCAN_ENABLE: 565 case NG_HCI_OCF_WRITE_SCAN_ENABLE: 566 case NG_HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY: 567 case NG_HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY: 568 case NG_HCI_OCF_READ_AUTH_ENABLE: 569 case NG_HCI_OCF_WRITE_AUTH_ENABLE: 570 case NG_HCI_OCF_READ_ENCRYPTION_MODE: 571 case NG_HCI_OCF_WRITE_ENCRYPTION_MODE: 572 case NG_HCI_OCF_WRITE_VOICE_SETTINGS: 573 case NG_HCI_OCF_READ_NUM_BROADCAST_RETRANS: 574 case NG_HCI_OCF_WRITE_NUM_BROADCAST_RETRANS: 575 case NG_HCI_OCF_READ_HOLD_MODE_ACTIVITY: 576 case NG_HCI_OCF_WRITE_HOLD_MODE_ACTIVITY: 577 case NG_HCI_OCF_READ_SCO_FLOW_CONTROL: 578 case NG_HCI_OCF_WRITE_SCO_FLOW_CONTROL: 579 case NG_HCI_OCF_H2HC_FLOW_CONTROL: /* XXX Not supported this time */ 580 case NG_HCI_OCF_HOST_BUFFER_SIZE: 581 case NG_HCI_OCF_READ_IAC_LAP: 582 case NG_HCI_OCF_WRITE_IAC_LAP: 583 case NG_HCI_OCF_READ_PAGE_SCAN_PERIOD: 584 case NG_HCI_OCF_WRITE_PAGE_SCAN_PERIOD: 585 case NG_HCI_OCF_READ_PAGE_SCAN: 586 case NG_HCI_OCF_WRITE_PAGE_SCAN: 587 case NG_HCI_OCF_READ_LINK_SUPERVISION_TIMO: 588 case NG_HCI_OCF_WRITE_LINK_SUPERVISION_TIMO: 589 case NG_HCI_OCF_READ_SUPPORTED_IAC_NUM: 590 case NG_HCI_OCF_READ_STORED_LINK_KEY: 591 case NG_HCI_OCF_DELETE_STORED_LINK_KEY: 592 case NG_HCI_OCF_READ_CON_ACCEPT_TIMO: 593 case NG_HCI_OCF_READ_PAGE_TIMO: 594 case NG_HCI_OCF_READ_PAGE_SCAN_ACTIVITY: 595 case NG_HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY: 596 case NG_HCI_OCF_READ_VOICE_SETTINGS: 597 case NG_HCI_OCF_READ_AUTO_FLUSH_TIMO: 598 case NG_HCI_OCF_WRITE_AUTO_FLUSH_TIMO: 599 case NG_HCI_OCF_READ_XMIT_LEVEL: 600 case NG_HCI_OCF_HOST_NUM_COMPL_PKTS: /* XXX Can get here? */ 601 case NG_HCI_OCF_CHANGE_LOCAL_NAME: 602 case NG_HCI_OCF_READ_LOCAL_NAME: 603 case NG_HCI_OCF_READ_UNIT_CLASS: 604 case NG_HCI_OCF_WRITE_UNIT_CLASS: 605 /* These do not need post processing */ 606 break; 607 608 case NG_HCI_OCF_RESET: { 609 ng_hci_unit_con_p con = NULL; 610 int size; 611 612 /* 613 * XXX 614 * 615 * After RESET command unit goes into standby mode 616 * and all operational state is lost. Host controller 617 * will revert to default values for all parameters. 618 * 619 * For now we shall terminate all connections and drop 620 * inited bit. After RESET unit must be re-initialized. 621 */ 622 623 while (!LIST_EMPTY(&unit->con_list)) { 624 con = LIST_FIRST(&unit->con_list); 625 626 /* Remove all timeouts (if any) */ 627 if (con->flags & NG_HCI_CON_TIMEOUT_PENDING) 628 ng_hci_con_untimeout(con); 629 630 /* Connection terminated by local host */ 631 ng_hci_lp_discon_ind(con, 0x16); 632 ng_hci_free_con(con); 633 } 634 635 NG_HCI_BUFF_ACL_TOTAL(unit->buffer, size); 636 NG_HCI_BUFF_ACL_FREE(unit->buffer, size); 637 638 NG_HCI_BUFF_SCO_TOTAL(unit->buffer, size); 639 NG_HCI_BUFF_SCO_FREE(unit->buffer, size); 640 641 unit->state &= ~NG_HCI_UNIT_INITED; 642 } break; 643 644 default: 645 error = EINVAL; 646 break; 647 } 648 649 NG_FREE_M(mcp); 650 NG_FREE_M(mrp); 651 652 return (error); 653} /* process_hc_baseband_params */ 654 655/* 656 * Process info command return parameters 657 */ 658 659static int 660process_info_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp, 661 struct mbuf *mrp) 662{ 663 int error = 0, len; 664 665 switch (ocf) { 666 case NG_HCI_OCF_READ_LOCAL_VER: 667 case NG_HCI_OCF_READ_COUNTRY_CODE: 668 break; 669 670 case NG_HCI_OCF_READ_LOCAL_FEATURES: 671 m_adj(mrp, sizeof(u_int8_t)); 672 len = min(mrp->m_pkthdr.len, sizeof(unit->features)); 673 m_copydata(mrp, 0, len, (caddr_t) unit->features); 674 break; 675 676 case NG_HCI_OCF_READ_BUFFER_SIZE: { 677 ng_hci_read_buffer_size_rp *rp = NULL; 678 679 /* Do not update buffer descriptor if node was initialized */ 680 if ((unit->state & NG_HCI_UNIT_READY) == NG_HCI_UNIT_READY) 681 break; 682 683 NG_HCI_M_PULLUP(mrp, sizeof(*rp)); 684 if (mrp != NULL) { 685 rp = mtod(mrp, ng_hci_read_buffer_size_rp *); 686 687 NG_HCI_BUFF_ACL_SET( 688 unit->buffer, 689 le16toh(rp->num_acl_pkt), /* number */ 690 le16toh(rp->max_acl_size), /* size */ 691 le16toh(rp->num_acl_pkt) /* free */ 692 ); 693 694 NG_HCI_BUFF_SCO_SET( 695 unit->buffer, 696 le16toh(rp->num_sco_pkt), /* number */ 697 rp->max_sco_size, /* size */ 698 le16toh(rp->num_sco_pkt) /* free */ 699 ); 700 701 /* Let upper layers know */ 702 ng_hci_node_is_up(unit->node, unit->acl, NULL, 0); 703 ng_hci_node_is_up(unit->node, unit->sco, NULL, 0); 704 } else 705 error = ENOBUFS; 706 } break; 707 708 case NG_HCI_OCF_READ_BDADDR: 709 /* Do not update BD_ADDR if node was initialized */ 710 if ((unit->state & NG_HCI_UNIT_READY) == NG_HCI_UNIT_READY) 711 break; 712 713 m_adj(mrp, sizeof(u_int8_t)); 714 len = min(mrp->m_pkthdr.len, sizeof(unit->bdaddr)); 715 m_copydata(mrp, 0, len, (caddr_t) &unit->bdaddr); 716 717 /* Let upper layers know */ 718 ng_hci_node_is_up(unit->node, unit->acl, NULL, 0); 719 ng_hci_node_is_up(unit->node, unit->sco, NULL, 0); 720 break; 721 722 default: 723 error = EINVAL; 724 break; 725 } 726 727 NG_FREE_M(mcp); 728 NG_FREE_M(mrp); 729 730 return (error); 731} /* process_info_params */ 732 733/* 734 * Process status command return parameters 735 */ 736 737static int 738process_status_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp, 739 struct mbuf *mrp) 740{ 741 int error = 0; 742 743 switch (ocf) { 744 case NG_HCI_OCF_READ_FAILED_CONTACT_CNTR: 745 case NG_HCI_OCF_RESET_FAILED_CONTACT_CNTR: 746 case NG_HCI_OCF_GET_LINK_QUALITY: 747 case NG_HCI_OCF_READ_RSSI: 748 /* These do not need post processing */ 749 break; 750 751 default: 752 error = EINVAL; 753 break; 754 } 755 756 NG_FREE_M(mcp); 757 NG_FREE_M(mrp); 758 759 return (error); 760} /* process_status_params */ 761 762/* 763 * Process testing command return parameters 764 */ 765 766int 767process_testing_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp, 768 struct mbuf *mrp) 769{ 770 int error = 0; 771 772 switch (ocf) { 773 774 /* 775 * XXX FIXME 776 * We do not support these features at this time. However, 777 * HCI node could support this and do something smart. At least 778 * node can change unit state. 779 */ 780 781 case NG_HCI_OCF_READ_LOOPBACK_MODE: 782 case NG_HCI_OCF_WRITE_LOOPBACK_MODE: 783 case NG_HCI_OCF_ENABLE_UNIT_UNDER_TEST: 784 break; 785 786 default: 787 error = EINVAL; 788 break; 789 } 790 791 NG_FREE_M(mcp); 792 NG_FREE_M(mrp); 793 794 return (error); 795} /* process_testing_params */ 796 797/* 798 * Process link control command status 799 */ 800 801static int 802process_link_control_status(ng_hci_unit_p unit, ng_hci_command_status_ep *ep, 803 struct mbuf *mcp) 804{ 805 int error = 0; 806 807 switch (NG_HCI_OCF(ep->opcode)) { 808 case NG_HCI_OCF_INQUIRY: 809 case NG_HCI_OCF_DISCON: /* XXX */ 810 case NG_HCI_OCF_REJECT_CON: /* XXX */ 811 case NG_HCI_OCF_CHANGE_CON_PKT_TYPE: 812 case NG_HCI_OCF_AUTH_REQ: 813 case NG_HCI_OCF_SET_CON_ENCRYPTION: 814 case NG_HCI_OCF_CHANGE_CON_LINK_KEY: 815 case NG_HCI_OCF_MASTER_LINK_KEY: 816 case NG_HCI_OCF_REMOTE_NAME_REQ: 817 case NG_HCI_OCF_READ_REMOTE_FEATURES: 818 case NG_HCI_OCF_READ_REMOTE_VER_INFO: 819 case NG_HCI_OCF_READ_CLOCK_OFFSET: 820 /* These do not need post processing */ 821 break; 822 823 case NG_HCI_OCF_CREATE_CON: 824 break; 825 826 case NG_HCI_OCF_ADD_SCO_CON: 827 break; 828 829 case NG_HCI_OCF_ACCEPT_CON: 830 break; 831 832 case NG_HCI_OCF_INQUIRY_CANCEL: 833 case NG_HCI_OCF_PERIODIC_INQUIRY: 834 case NG_HCI_OCF_EXIT_PERIODIC_INQUIRY: 835 case NG_HCI_OCF_LINK_KEY_REP: 836 case NG_HCI_OCF_LINK_KEY_NEG_REP: 837 case NG_HCI_OCF_PIN_CODE_REP: 838 case NG_HCI_OCF_PIN_CODE_NEG_REP: 839 default: 840 841 /* 842 * None of these command was supposed to generate 843 * Command_Status event. Instead Command_Complete event 844 * should have been sent. 845 */ 846 847 error = EINVAL; 848 break; 849 } 850 851 NG_FREE_M(mcp); 852 853 return (error); 854} /* process_link_control_status */ 855 856/* 857 * Process link policy command status 858 */ 859 860static int 861process_link_policy_status(ng_hci_unit_p unit, ng_hci_command_status_ep *ep, 862 struct mbuf *mcp) 863{ 864 int error = 0; 865 866 switch (NG_HCI_OCF(ep->opcode)) { 867 case NG_HCI_OCF_HOLD_MODE: 868 case NG_HCI_OCF_SNIFF_MODE: 869 case NG_HCI_OCF_EXIT_SNIFF_MODE: 870 case NG_HCI_OCF_PARK_MODE: 871 case NG_HCI_OCF_EXIT_PARK_MODE: 872 case NG_HCI_OCF_SWITCH_ROLE: 873 /* These do not need post processing */ 874 break; 875 876 case NG_HCI_OCF_QOS_SETUP: 877 break; 878 879 case NG_HCI_OCF_ROLE_DISCOVERY: 880 case NG_HCI_OCF_READ_LINK_POLICY_SETTINGS: 881 case NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS: 882 default: 883 884 /* 885 * None of these command was supposed to generate 886 * Command_Status event. Instead Command_Complete event 887 * should have been sent. 888 */ 889 890 error = EINVAL; 891 break; 892 } 893 894 NG_FREE_M(mcp); 895 896 return (error); 897} /* process_link_policy_status */ 898 899