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