Annotation of sys/netbt/hci_event.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: hci_event.c,v 1.5 2007/06/19 08:12:35 uwe Exp $ */
! 2: /* $NetBSD: hci_event.c,v 1.6 2007/04/21 06:15:23 plunky Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2005 Iain Hibbert.
! 6: * Copyright (c) 2006 Itronix Inc.
! 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: * 3. The name of Itronix Inc. may not be used to endorse
! 18: * or promote products derived from this software without specific
! 19: * prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 23: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 24: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
! 25: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 26: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
! 27: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
! 28: * ON ANY THEORY OF LIABILITY, WHETHER IN
! 29: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 30: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 31: * POSSIBILITY OF SUCH DAMAGE.
! 32: */
! 33:
! 34: #include <sys/cdefs.h>
! 35:
! 36: #include <sys/param.h>
! 37: #include <sys/kernel.h>
! 38: #include <sys/malloc.h>
! 39: #include <sys/mbuf.h>
! 40: #include <sys/proc.h>
! 41: #include <sys/systm.h>
! 42:
! 43: #include <netbt/bluetooth.h>
! 44: #include <netbt/hci.h>
! 45: #include <netbt/sco.h>
! 46:
! 47: static void hci_event_inquiry_result(struct hci_unit *, struct mbuf *);
! 48: static void hci_event_command_status(struct hci_unit *, struct mbuf *);
! 49: static void hci_event_command_compl(struct hci_unit *, struct mbuf *);
! 50: static void hci_event_con_compl(struct hci_unit *, struct mbuf *);
! 51: static void hci_event_discon_compl(struct hci_unit *, struct mbuf *);
! 52: static void hci_event_con_req(struct hci_unit *, struct mbuf *);
! 53: static void hci_event_num_compl_pkts(struct hci_unit *, struct mbuf *);
! 54: static void hci_event_auth_compl(struct hci_unit *, struct mbuf *);
! 55: static void hci_event_encryption_change(struct hci_unit *, struct mbuf *);
! 56: static void hci_event_change_con_link_key_compl(struct hci_unit *, struct mbuf *);
! 57: static void hci_cmd_read_bdaddr(struct hci_unit *, struct mbuf *);
! 58: static void hci_cmd_read_buffer_size(struct hci_unit *, struct mbuf *);
! 59: static void hci_cmd_read_local_features(struct hci_unit *, struct mbuf *);
! 60: static void hci_cmd_reset(struct hci_unit *, struct mbuf *);
! 61:
! 62: #ifdef BLUETOOTH_DEBUG
! 63: int bluetooth_debug = 0;
! 64:
! 65: static const char *hci_eventnames[] = {
! 66: /* 0x00 */ "NULL",
! 67: /* 0x01 */ "INQUIRY COMPLETE",
! 68: /* 0x02 */ "INQUIRY RESULT",
! 69: /* 0x03 */ "CONN COMPLETE",
! 70: /* 0x04 */ "CONN REQ",
! 71: /* 0x05 */ "DISCONN COMPLETE",
! 72: /* 0x06 */ "AUTH COMPLETE",
! 73: /* 0x07 */ "REMOTE NAME REQ COMPLETE",
! 74: /* 0x08 */ "ENCRYPTION CHANGE",
! 75: /* 0x09 */ "CHANGE CONN LINK KEY COMPLETE",
! 76: /* 0x0a */ "MASTER LINK KEY COMPLETE",
! 77: /* 0x0b */ "READ REMOTE FEATURES COMPLETE",
! 78: /* 0x0c */ "READ REMOTE VERSION INFO COMPLETE",
! 79: /* 0x0d */ "QoS SETUP COMPLETE",
! 80: /* 0x0e */ "COMMAND COMPLETE",
! 81: /* 0x0f */ "COMMAND STATUS",
! 82: /* 0x10 */ "HARDWARE ERROR",
! 83: /* 0x11 */ "FLUSH OCCUR",
! 84: /* 0x12 */ "ROLE CHANGE",
! 85: /* 0x13 */ "NUM COMPLETED PACKETS",
! 86: /* 0x14 */ "MODE CHANGE",
! 87: /* 0x15 */ "RETURN LINK KEYS",
! 88: /* 0x16 */ "PIN CODE REQ",
! 89: /* 0x17 */ "LINK KEY REQ",
! 90: /* 0x18 */ "LINK KEY NOTIFICATION",
! 91: /* 0x19 */ "LOOPBACK COMMAND",
! 92: /* 0x1a */ "DATA BUFFER OVERFLOW",
! 93: /* 0x1b */ "MAX SLOT CHANGE",
! 94: /* 0x1c */ "READ CLOCK OFFSET COMPLETE",
! 95: /* 0x1d */ "CONN PKT TYPE CHANGED",
! 96: /* 0x1e */ "QOS VIOLATION",
! 97: /* 0x1f */ "PAGE SCAN MODE CHANGE",
! 98: /* 0x20 */ "PAGE SCAN REP MODE CHANGE",
! 99: /* 0x21 */ "FLOW SPECIFICATION COMPLETE",
! 100: /* 0x22 */ "RSSI RESULT",
! 101: /* 0x23 */ "READ REMOTE EXT FEATURES"
! 102: };
! 103:
! 104: static const char *
! 105: hci_eventstr(unsigned int event)
! 106: {
! 107:
! 108: if (event < (sizeof(hci_eventnames) / sizeof(*hci_eventnames)))
! 109: return hci_eventnames[event];
! 110:
! 111: switch (event) {
! 112: case HCI_EVENT_SCO_CON_COMPL: /* 0x2c */
! 113: return "SCO CON COMPLETE";
! 114:
! 115: case HCI_EVENT_SCO_CON_CHANGED: /* 0x2d */
! 116: return "SCO CON CHANGED";
! 117:
! 118: case HCI_EVENT_BT_LOGO: /* 0xfe */
! 119: return "BT_LOGO";
! 120:
! 121: case HCI_EVENT_VENDOR: /* 0xff */
! 122: return "VENDOR";
! 123: }
! 124:
! 125: return "UNRECOGNISED";
! 126: }
! 127: #endif /* BLUETOOTH_DEBUG */
! 128:
! 129: /*
! 130: * process HCI Events
! 131: *
! 132: * We will free the mbuf at the end, no need for any sub
! 133: * functions to handle that. We kind of assume that the
! 134: * device sends us valid events.
! 135: * XXX "kind of"? This needs to be fixed.
! 136: */
! 137: void
! 138: hci_event(struct mbuf *m, struct hci_unit *unit)
! 139: {
! 140: hci_event_hdr_t hdr;
! 141:
! 142: KASSERT(m->m_flags & M_PKTHDR);
! 143:
! 144: KASSERT(m->m_pkthdr.len >= sizeof(hdr));
! 145: m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr);
! 146: m_adj(m, sizeof(hdr));
! 147:
! 148: KASSERT(hdr.type == HCI_EVENT_PKT);
! 149:
! 150: DPRINTFN(1, "(%s) event %s\n", unit->hci_devname, hci_eventstr(hdr.event));
! 151:
! 152: switch(hdr.event) {
! 153: case HCI_EVENT_COMMAND_STATUS:
! 154: hci_event_command_status(unit, m);
! 155: break;
! 156:
! 157: case HCI_EVENT_COMMAND_COMPL:
! 158: hci_event_command_compl(unit, m);
! 159: break;
! 160:
! 161: case HCI_EVENT_NUM_COMPL_PKTS:
! 162: hci_event_num_compl_pkts(unit, m);
! 163: break;
! 164:
! 165: case HCI_EVENT_INQUIRY_RESULT:
! 166: hci_event_inquiry_result(unit, m);
! 167: break;
! 168:
! 169: case HCI_EVENT_CON_COMPL:
! 170: hci_event_con_compl(unit, m);
! 171: break;
! 172:
! 173: case HCI_EVENT_DISCON_COMPL:
! 174: hci_event_discon_compl(unit, m);
! 175: break;
! 176:
! 177: case HCI_EVENT_CON_REQ:
! 178: hci_event_con_req(unit, m);
! 179: break;
! 180:
! 181: case HCI_EVENT_AUTH_COMPL:
! 182: hci_event_auth_compl(unit, m);
! 183: break;
! 184:
! 185: case HCI_EVENT_ENCRYPTION_CHANGE:
! 186: hci_event_encryption_change(unit, m);
! 187: break;
! 188:
! 189: case HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL:
! 190: hci_event_change_con_link_key_compl(unit, m);
! 191: break;
! 192:
! 193: case HCI_EVENT_SCO_CON_COMPL:
! 194: case HCI_EVENT_INQUIRY_COMPL:
! 195: case HCI_EVENT_REMOTE_NAME_REQ_COMPL:
! 196: case HCI_EVENT_MASTER_LINK_KEY_COMPL:
! 197: case HCI_EVENT_READ_REMOTE_FEATURES_COMPL:
! 198: case HCI_EVENT_READ_REMOTE_VER_INFO_COMPL:
! 199: case HCI_EVENT_QOS_SETUP_COMPL:
! 200: case HCI_EVENT_HARDWARE_ERROR:
! 201: case HCI_EVENT_FLUSH_OCCUR:
! 202: case HCI_EVENT_ROLE_CHANGE:
! 203: case HCI_EVENT_MODE_CHANGE:
! 204: case HCI_EVENT_RETURN_LINK_KEYS:
! 205: case HCI_EVENT_PIN_CODE_REQ:
! 206: case HCI_EVENT_LINK_KEY_REQ:
! 207: case HCI_EVENT_LINK_KEY_NOTIFICATION:
! 208: case HCI_EVENT_LOOPBACK_COMMAND:
! 209: case HCI_EVENT_DATA_BUFFER_OVERFLOW:
! 210: case HCI_EVENT_MAX_SLOT_CHANGE:
! 211: case HCI_EVENT_READ_CLOCK_OFFSET_COMPL:
! 212: case HCI_EVENT_CON_PKT_TYPE_CHANGED:
! 213: case HCI_EVENT_QOS_VIOLATION:
! 214: case HCI_EVENT_PAGE_SCAN_MODE_CHANGE:
! 215: case HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE:
! 216: case HCI_EVENT_FLOW_SPECIFICATION_COMPL:
! 217: case HCI_EVENT_RSSI_RESULT:
! 218: case HCI_EVENT_READ_REMOTE_EXTENDED_FEATURES:
! 219: case HCI_EVENT_SCO_CON_CHANGED:
! 220: case HCI_EVENT_BT_LOGO:
! 221: case HCI_EVENT_VENDOR:
! 222: break;
! 223:
! 224: default:
! 225: UNKNOWN(hdr.event);
! 226: break;
! 227: }
! 228:
! 229: m_freem(m);
! 230: }
! 231:
! 232: /*
! 233: * Command Status
! 234: *
! 235: * Update our record of num_cmd_pkts then post-process any pending commands
! 236: * and optionally restart cmd output on the unit.
! 237: */
! 238: static void
! 239: hci_event_command_status(struct hci_unit *unit, struct mbuf *m)
! 240: {
! 241: hci_command_status_ep ep;
! 242: struct hci_link *link;
! 243:
! 244: KASSERT(m->m_pkthdr.len >= sizeof(ep));
! 245: m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
! 246: m_adj(m, sizeof(ep));
! 247:
! 248: DPRINTFN(1, "(%s) opcode (%03x|%04x) status = 0x%x num_cmd_pkts = %d\n",
! 249: unit->hci_devname,
! 250: HCI_OGF(letoh16(ep.opcode)), HCI_OCF(letoh16(ep.opcode)),
! 251: ep.status,
! 252: ep.num_cmd_pkts);
! 253:
! 254: unit->hci_num_cmd_pkts = ep.num_cmd_pkts;
! 255:
! 256: /*
! 257: * post processing of pending commands
! 258: */
! 259: switch(letoh16(ep.opcode)) {
! 260: case HCI_CMD_CREATE_CON:
! 261: switch (ep.status) {
! 262: case 0x12: /* Invalid HCI command parameters */
! 263: DPRINTF("(%s) Invalid HCI command parameters\n",
! 264: unit->hci_devname);
! 265: while ((link = hci_link_lookup_state(unit,
! 266: HCI_LINK_ACL, HCI_LINK_WAIT_CONNECT)) != NULL)
! 267: hci_link_free(link, ECONNABORTED);
! 268: break;
! 269: }
! 270: break;
! 271: default:
! 272: break;
! 273: }
! 274:
! 275: while (unit->hci_num_cmd_pkts > 0 && !IF_IS_EMPTY(&unit->hci_cmdwait)) {
! 276: IF_DEQUEUE(&unit->hci_cmdwait, m);
! 277: hci_output_cmd(unit, m);
! 278: }
! 279: }
! 280:
! 281: /*
! 282: * Command Complete
! 283: *
! 284: * Update our record of num_cmd_pkts then handle the completed command,
! 285: * and optionally restart cmd output on the unit.
! 286: */
! 287: static void
! 288: hci_event_command_compl(struct hci_unit *unit, struct mbuf *m)
! 289: {
! 290: hci_command_compl_ep ep;
! 291:
! 292: KASSERT(m->m_pkthdr.len >= sizeof(ep));
! 293: m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
! 294: m_adj(m, sizeof(ep));
! 295:
! 296: DPRINTFN(1, "(%s) opcode (%03x|%04x) num_cmd_pkts = %d\n",
! 297: unit->hci_devname,
! 298: HCI_OGF(letoh16(ep.opcode)), HCI_OCF(letoh16(ep.opcode)),
! 299: ep.num_cmd_pkts);
! 300:
! 301: unit->hci_num_cmd_pkts = ep.num_cmd_pkts;
! 302:
! 303: /*
! 304: * post processing of completed commands
! 305: */
! 306: switch(letoh16(ep.opcode)) {
! 307: case HCI_CMD_READ_BDADDR:
! 308: hci_cmd_read_bdaddr(unit, m);
! 309: break;
! 310:
! 311: case HCI_CMD_READ_BUFFER_SIZE:
! 312: hci_cmd_read_buffer_size(unit, m);
! 313: break;
! 314:
! 315: case HCI_CMD_READ_LOCAL_FEATURES:
! 316: hci_cmd_read_local_features(unit, m);
! 317: break;
! 318:
! 319: case HCI_CMD_RESET:
! 320: hci_cmd_reset(unit, m);
! 321: break;
! 322:
! 323: default:
! 324: break;
! 325: }
! 326:
! 327: while (unit->hci_num_cmd_pkts > 0 && !IF_IS_EMPTY(&unit->hci_cmdwait)) {
! 328: IF_DEQUEUE(&unit->hci_cmdwait, m);
! 329: hci_output_cmd(unit, m);
! 330: }
! 331: }
! 332:
! 333: /*
! 334: * Number of Completed Packets
! 335: *
! 336: * This is sent periodically by the Controller telling us how many
! 337: * buffers are now freed up and which handle was using them. From
! 338: * this we determine which type of buffer it was and add the qty
! 339: * back into the relevant packet counter, then restart output on
! 340: * links that have halted.
! 341: */
! 342: static void
! 343: hci_event_num_compl_pkts(struct hci_unit *unit, struct mbuf *m)
! 344: {
! 345: hci_num_compl_pkts_ep ep;
! 346: struct hci_link *link, *next;
! 347: uint16_t handle, num;
! 348: int num_acl = 0, num_sco = 0;
! 349:
! 350: KASSERT(m->m_pkthdr.len >= sizeof(ep));
! 351: m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
! 352: m_adj(m, sizeof(ep));
! 353:
! 354: while (ep.num_con_handles--) {
! 355: m_copydata(m, 0, sizeof(handle), (caddr_t)&handle);
! 356: m_adj(m, sizeof(handle));
! 357: handle = letoh16(handle);
! 358:
! 359: m_copydata(m, 0, sizeof(num), (caddr_t)&num);
! 360: m_adj(m, sizeof(num));
! 361: num = letoh16(num);
! 362:
! 363: link = hci_link_lookup_handle(unit, handle);
! 364: if (link) {
! 365: if (link->hl_type == HCI_LINK_ACL) {
! 366: num_acl += num;
! 367: hci_acl_complete(link, num);
! 368: } else {
! 369: num_sco += num;
! 370: hci_sco_complete(link, num);
! 371: }
! 372: } else {
! 373: /* XXX need to issue Read_Buffer_Size or Reset? */
! 374: printf("%s: unknown handle %d! "
! 375: "(losing track of %d packet buffer%s)\n",
! 376: unit->hci_devname, handle,
! 377: num, (num == 1 ? "" : "s"));
! 378: }
! 379: }
! 380:
! 381: /*
! 382: * Move up any queued packets. When a link has sent data, it will move
! 383: * to the back of the queue - technically then if a link had something
! 384: * to send and there were still buffers available it could get started
! 385: * twice but it seemed more important to to handle higher loads fairly
! 386: * than worry about wasting cycles when we are not busy.
! 387: */
! 388:
! 389: unit->hci_num_acl_pkts += num_acl;
! 390: unit->hci_num_sco_pkts += num_sco;
! 391:
! 392: link = TAILQ_FIRST(&unit->hci_links);
! 393: while (link && (unit->hci_num_acl_pkts > 0 || unit->hci_num_sco_pkts > 0)) {
! 394: next = TAILQ_NEXT(link, hl_next);
! 395:
! 396: if (link->hl_type == HCI_LINK_ACL) {
! 397: if (unit->hci_num_acl_pkts > 0 && link->hl_txqlen > 0)
! 398: hci_acl_start(link);
! 399: } else {
! 400: if (unit->hci_num_sco_pkts > 0 && link->hl_txqlen > 0)
! 401: hci_sco_start(link);
! 402: }
! 403:
! 404: link = next;
! 405: }
! 406: }
! 407:
! 408: /*
! 409: * Inquiry Result
! 410: *
! 411: * keep a note of devices seen, so we know which unit to use
! 412: * on outgoing connections
! 413: */
! 414: static void
! 415: hci_event_inquiry_result(struct hci_unit *unit, struct mbuf *m)
! 416: {
! 417: hci_inquiry_result_ep ep;
! 418: struct hci_memo *memo;
! 419: bdaddr_t bdaddr;
! 420:
! 421: KASSERT(m->m_pkthdr.len >= sizeof(ep));
! 422: m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
! 423: m_adj(m, sizeof(ep));
! 424:
! 425: DPRINTFN(1, "%d response%s\n", ep.num_responses,
! 426: (ep.num_responses == 1 ? "" : "s"));
! 427:
! 428: while(ep.num_responses--) {
! 429: m_copydata(m, 0, sizeof(bdaddr_t), (caddr_t)&bdaddr);
! 430:
! 431: DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
! 432: bdaddr.b[5], bdaddr.b[4], bdaddr.b[3],
! 433: bdaddr.b[2], bdaddr.b[1], bdaddr.b[0]);
! 434:
! 435: memo = hci_memo_find(unit, &bdaddr);
! 436: if (memo == NULL) {
! 437: memo = malloc(sizeof(struct hci_memo),
! 438: M_BLUETOOTH, M_NOWAIT);
! 439: if (memo == NULL) {
! 440: DPRINTFN(0, "out of memo memory!\n");
! 441: break;
! 442: }
! 443: bzero(memo, sizeof *memo);
! 444:
! 445: LIST_INSERT_HEAD(&unit->hci_memos, memo, next);
! 446: }
! 447:
! 448: microtime(&memo->time);
! 449: m_copydata(m, 0, sizeof(hci_inquiry_response),
! 450: (caddr_t)&memo->response);
! 451: m_adj(m, sizeof(hci_inquiry_response));
! 452:
! 453: memo->response.clock_offset =
! 454: letoh16(memo->response.clock_offset);
! 455: }
! 456: }
! 457:
! 458: /*
! 459: * Connection Complete
! 460: *
! 461: * Sent to us when a connection is made. If there is no link
! 462: * structure already allocated for this, we must have changed
! 463: * our mind, so just disconnect.
! 464: */
! 465: static void
! 466: hci_event_con_compl(struct hci_unit *unit, struct mbuf *m)
! 467: {
! 468: hci_con_compl_ep ep;
! 469: hci_write_link_policy_settings_cp cp;
! 470: struct hci_link *link;
! 471: int err;
! 472:
! 473: KASSERT(m->m_pkthdr.len >= sizeof(ep));
! 474: m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
! 475: m_adj(m, sizeof(ep));
! 476:
! 477: DPRINTFN(1, "(%s) %s connection complete for "
! 478: "%02x:%02x:%02x:%02x:%02x:%02x status %#x\n",
! 479: unit->hci_devname,
! 480: (ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO"),
! 481: ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3],
! 482: ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0],
! 483: ep.status);
! 484:
! 485: link = hci_link_lookup_bdaddr(unit, &ep.bdaddr, ep.link_type);
! 486:
! 487: if (ep.status) {
! 488: if (link != NULL) {
! 489: switch (ep.status) {
! 490: case 0x04: /* "Page Timeout" */
! 491: err = EHOSTDOWN;
! 492: break;
! 493:
! 494: case 0x08: /* "Connection Timed Out" */
! 495: case 0x10: /* "Connection Accept Timeout Exceeded" */
! 496: err = ETIMEDOUT;
! 497: break;
! 498:
! 499: case 0x16: /* "Connection Terminated by Local Host" */
! 500: err = 0;
! 501: break;
! 502:
! 503: default:
! 504: err = ECONNREFUSED;
! 505: break;
! 506: }
! 507:
! 508: hci_link_free(link, err);
! 509: }
! 510:
! 511: return;
! 512: }
! 513:
! 514: if (link == NULL) {
! 515: hci_discon_cp dp;
! 516:
! 517: dp.con_handle = ep.con_handle;
! 518: dp.reason = 0x13; /* "Remote User Terminated Connection" */
! 519:
! 520: hci_send_cmd(unit, HCI_CMD_DISCONNECT, &dp, sizeof(dp));
! 521: return;
! 522: }
! 523:
! 524: /* XXX could check auth_enable here */
! 525:
! 526: if (ep.encryption_mode)
! 527: link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT);
! 528:
! 529: link->hl_state = HCI_LINK_OPEN;
! 530: link->hl_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
! 531:
! 532: if (ep.link_type == HCI_LINK_ACL) {
! 533: cp.con_handle = ep.con_handle;
! 534: cp.settings = htole16(unit->hci_link_policy);
! 535: err = hci_send_cmd(unit, HCI_CMD_WRITE_LINK_POLICY_SETTINGS,
! 536: &cp, sizeof(cp));
! 537: if (err)
! 538: printf("%s: Warning, could not write link policy\n",
! 539: unit->hci_devname);
! 540:
! 541: err = hci_acl_setmode(link);
! 542: if (err == EINPROGRESS)
! 543: return;
! 544:
! 545: hci_acl_linkmode(link);
! 546: } else {
! 547: (*link->hl_sco->sp_proto->connected)(link->hl_sco->sp_upper);
! 548: }
! 549: }
! 550:
! 551: /*
! 552: * Disconnection Complete
! 553: *
! 554: * This is sent in response to a disconnection request, but also if
! 555: * the remote device goes out of range.
! 556: */
! 557: static void
! 558: hci_event_discon_compl(struct hci_unit *unit, struct mbuf *m)
! 559: {
! 560: hci_discon_compl_ep ep;
! 561: struct hci_link *link;
! 562:
! 563: KASSERT(m->m_pkthdr.len >= sizeof(ep));
! 564: m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
! 565: m_adj(m, sizeof(ep));
! 566:
! 567: ep.con_handle = letoh16(ep.con_handle);
! 568:
! 569: DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status);
! 570:
! 571: link = hci_link_lookup_handle(unit, HCI_CON_HANDLE(ep.con_handle));
! 572: if (link)
! 573: hci_link_free(link, ENOENT); /* XXX NetBSD used ENOLINK here */
! 574: }
! 575:
! 576: /*
! 577: * Connect Request
! 578: *
! 579: * We check upstream for appropriate listeners and accept connections
! 580: * that are wanted.
! 581: */
! 582: static void
! 583: hci_event_con_req(struct hci_unit *unit, struct mbuf *m)
! 584: {
! 585: hci_con_req_ep ep;
! 586: hci_accept_con_cp ap;
! 587: hci_reject_con_cp rp;
! 588: struct hci_link *link;
! 589:
! 590: KASSERT(m->m_pkthdr.len >= sizeof(ep));
! 591: m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
! 592: m_adj(m, sizeof(ep));
! 593:
! 594: DPRINTFN(1, "bdaddr %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
! 595: "class %2.2x%2.2x%2.2x type %s\n",
! 596: ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3],
! 597: ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0],
! 598: ep.uclass[0], ep.uclass[1], ep.uclass[2],
! 599: ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO");
! 600:
! 601: if (ep.link_type == HCI_LINK_ACL)
! 602: link = hci_acl_newconn(unit, &ep.bdaddr);
! 603: else
! 604: link = hci_sco_newconn(unit, &ep.bdaddr);
! 605:
! 606: if (link == NULL) {
! 607: memset(&rp, 0, sizeof(rp));
! 608: bdaddr_copy(&rp.bdaddr, &ep.bdaddr);
! 609: rp.reason = 0x0f; /* Unacceptable BD_ADDR */
! 610:
! 611: hci_send_cmd(unit, HCI_CMD_REJECT_CON, &rp, sizeof(rp));
! 612: } else {
! 613: memset(&ap, 0, sizeof(ap));
! 614: bdaddr_copy(&ap.bdaddr, &ep.bdaddr);
! 615: if (unit->hci_link_policy & HCI_LINK_POLICY_ENABLE_ROLE_SWITCH)
! 616: ap.role = HCI_ROLE_MASTER;
! 617: else
! 618: ap.role = HCI_ROLE_SLAVE;
! 619:
! 620: hci_send_cmd(unit, HCI_CMD_ACCEPT_CON, &ap, sizeof(ap));
! 621: }
! 622: }
! 623:
! 624: /*
! 625: * Auth Complete
! 626: *
! 627: * Authentication has been completed on an ACL link. We can notify the
! 628: * upper layer protocols unless further mode changes are pending.
! 629: */
! 630: static void
! 631: hci_event_auth_compl(struct hci_unit *unit, struct mbuf *m)
! 632: {
! 633: hci_auth_compl_ep ep;
! 634: struct hci_link *link;
! 635: int err;
! 636:
! 637: KASSERT(m->m_pkthdr.len >= sizeof(ep));
! 638: m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
! 639: m_adj(m, sizeof(ep));
! 640:
! 641: ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
! 642:
! 643: DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status);
! 644:
! 645: link = hci_link_lookup_handle(unit, ep.con_handle);
! 646: if (link == NULL || link->hl_type != HCI_LINK_ACL)
! 647: return;
! 648:
! 649: if (ep.status == 0) {
! 650: link->hl_flags |= HCI_LINK_AUTH;
! 651:
! 652: if (link->hl_state == HCI_LINK_WAIT_AUTH)
! 653: link->hl_state = HCI_LINK_OPEN;
! 654:
! 655: err = hci_acl_setmode(link);
! 656: if (err == EINPROGRESS)
! 657: return;
! 658: }
! 659:
! 660: hci_acl_linkmode(link);
! 661: }
! 662:
! 663: /*
! 664: * Encryption Change
! 665: *
! 666: * The encryption status has changed. Basically, we note the change
! 667: * then notify the upper layer protocol unless further mode changes
! 668: * are pending.
! 669: * Note that if encryption gets disabled when it has been requested,
! 670: * we will attempt to enable it again.. (its a feature not a bug :)
! 671: */
! 672: static void
! 673: hci_event_encryption_change(struct hci_unit *unit, struct mbuf *m)
! 674: {
! 675: hci_encryption_change_ep ep;
! 676: struct hci_link *link;
! 677: int err;
! 678:
! 679: KASSERT(m->m_pkthdr.len >= sizeof(ep));
! 680: m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
! 681: m_adj(m, sizeof(ep));
! 682:
! 683: ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
! 684:
! 685: DPRINTFN(1, "handle #%d, status=0x%x, encryption_enable=0x%x\n",
! 686: ep.con_handle, ep.status, ep.encryption_enable);
! 687:
! 688: link = hci_link_lookup_handle(unit, ep.con_handle);
! 689: if (link == NULL || link->hl_type != HCI_LINK_ACL)
! 690: return;
! 691:
! 692: if (ep.status == 0) {
! 693: if (ep.encryption_enable == 0)
! 694: link->hl_flags &= ~HCI_LINK_ENCRYPT;
! 695: else
! 696: link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT);
! 697:
! 698: if (link->hl_state == HCI_LINK_WAIT_ENCRYPT)
! 699: link->hl_state = HCI_LINK_OPEN;
! 700:
! 701: err = hci_acl_setmode(link);
! 702: if (err == EINPROGRESS)
! 703: return;
! 704: }
! 705:
! 706: hci_acl_linkmode(link);
! 707: }
! 708:
! 709: /*
! 710: * Change Connection Link Key Complete
! 711: *
! 712: * Link keys are handled in userland but if we are waiting to secure
! 713: * this link, we should notify the upper protocols. A SECURE request
! 714: * only needs a single key change, so we can cancel the request.
! 715: */
! 716: static void
! 717: hci_event_change_con_link_key_compl(struct hci_unit *unit, struct mbuf *m)
! 718: {
! 719: hci_change_con_link_key_compl_ep ep;
! 720: struct hci_link *link;
! 721: int err;
! 722:
! 723: KASSERT(m->m_pkthdr.len >= sizeof(ep));
! 724: m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
! 725: m_adj(m, sizeof(ep));
! 726:
! 727: ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
! 728:
! 729: DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status);
! 730:
! 731: link = hci_link_lookup_handle(unit, ep.con_handle);
! 732: if (link == NULL || link->hl_type != HCI_LINK_ACL)
! 733: return;
! 734:
! 735: link->hl_flags &= ~HCI_LINK_SECURE_REQ;
! 736:
! 737: if (ep.status == 0) {
! 738: link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_SECURE);
! 739:
! 740: if (link->hl_state == HCI_LINK_WAIT_SECURE)
! 741: link->hl_state = HCI_LINK_OPEN;
! 742:
! 743: err = hci_acl_setmode(link);
! 744: if (err == EINPROGRESS)
! 745: return;
! 746: }
! 747:
! 748: hci_acl_linkmode(link);
! 749: }
! 750:
! 751: /*
! 752: * process results of read_bdaddr command_complete event
! 753: */
! 754: static void
! 755: hci_cmd_read_bdaddr(struct hci_unit *unit, struct mbuf *m)
! 756: {
! 757: hci_read_bdaddr_rp rp;
! 758: int s;
! 759:
! 760: KASSERT(m->m_pkthdr.len >= sizeof(rp));
! 761: m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
! 762: m_adj(m, sizeof(rp));
! 763:
! 764: if (rp.status > 0)
! 765: return;
! 766:
! 767: if ((unit->hci_flags & BTF_INIT_BDADDR) == 0)
! 768: return;
! 769:
! 770: bdaddr_copy(&unit->hci_bdaddr, &rp.bdaddr);
! 771:
! 772: s = splraiseipl(unit->hci_ipl);
! 773: unit->hci_flags &= ~BTF_INIT_BDADDR;
! 774: splx(s);
! 775:
! 776: wakeup(unit);
! 777: }
! 778:
! 779: /*
! 780: * process results of read_buffer_size command_complete event
! 781: */
! 782: static void
! 783: hci_cmd_read_buffer_size(struct hci_unit *unit, struct mbuf *m)
! 784: {
! 785: hci_read_buffer_size_rp rp;
! 786: int s;
! 787:
! 788: KASSERT(m->m_pkthdr.len >= sizeof(rp));
! 789: m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
! 790: m_adj(m, sizeof(rp));
! 791:
! 792: if (rp.status > 0)
! 793: return;
! 794:
! 795: if ((unit->hci_flags & BTF_INIT_BUFFER_SIZE) == 0)
! 796: return;
! 797:
! 798: unit->hci_max_acl_size = letoh16(rp.max_acl_size);
! 799: unit->hci_num_acl_pkts = letoh16(rp.num_acl_pkts);
! 800: unit->hci_max_sco_size = rp.max_sco_size;
! 801: unit->hci_num_sco_pkts = letoh16(rp.num_sco_pkts);
! 802:
! 803: s = splraiseipl(unit->hci_ipl);
! 804: unit->hci_flags &= ~BTF_INIT_BUFFER_SIZE;
! 805: splx(s);
! 806:
! 807: wakeup(unit);
! 808: }
! 809:
! 810: /*
! 811: * process results of read_local_features command_complete event
! 812: */
! 813: static void
! 814: hci_cmd_read_local_features(struct hci_unit *unit, struct mbuf *m)
! 815: {
! 816: hci_read_local_features_rp rp;
! 817: int s;
! 818:
! 819: KASSERT(m->m_pkthdr.len >= sizeof(rp));
! 820: m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
! 821: m_adj(m, sizeof(rp));
! 822:
! 823: if (rp.status > 0)
! 824: return;
! 825:
! 826: if ((unit->hci_flags & BTF_INIT_FEATURES) == 0)
! 827: return;
! 828:
! 829: unit->hci_lmp_mask = 0;
! 830:
! 831: if (rp.features[0] & HCI_LMP_ROLE_SWITCH)
! 832: unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_ROLE_SWITCH;
! 833:
! 834: if (rp.features[0] & HCI_LMP_HOLD_MODE)
! 835: unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_HOLD_MODE;
! 836:
! 837: if (rp.features[0] & HCI_LMP_SNIFF_MODE)
! 838: unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_SNIFF_MODE;
! 839:
! 840: if (rp.features[1] & HCI_LMP_PARK_MODE)
! 841: unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_PARK_MODE;
! 842:
! 843: /* ACL packet mask */
! 844: unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1;
! 845:
! 846: if (rp.features[0] & HCI_LMP_3SLOT)
! 847: unit->hci_acl_mask |= HCI_PKT_DM3 | HCI_PKT_DH3;
! 848:
! 849: if (rp.features[0] & HCI_LMP_5SLOT)
! 850: unit->hci_acl_mask |= HCI_PKT_DM5 | HCI_PKT_DH5;
! 851:
! 852: if ((rp.features[3] & HCI_LMP_EDR_ACL_2MBPS) == 0)
! 853: unit->hci_acl_mask |= HCI_PKT_2MBPS_DH1
! 854: | HCI_PKT_2MBPS_DH3
! 855: | HCI_PKT_2MBPS_DH5;
! 856:
! 857: if ((rp.features[3] & HCI_LMP_EDR_ACL_3MBPS) == 0)
! 858: unit->hci_acl_mask |= HCI_PKT_3MBPS_DH1
! 859: | HCI_PKT_3MBPS_DH3
! 860: | HCI_PKT_3MBPS_DH5;
! 861:
! 862: if ((rp.features[4] & HCI_LMP_3SLOT_EDR_ACL) == 0)
! 863: unit->hci_acl_mask |= HCI_PKT_2MBPS_DH3
! 864: | HCI_PKT_3MBPS_DH3;
! 865:
! 866: if ((rp.features[5] & HCI_LMP_5SLOT_EDR_ACL) == 0)
! 867: unit->hci_acl_mask |= HCI_PKT_2MBPS_DH5
! 868: | HCI_PKT_3MBPS_DH5;
! 869:
! 870: unit->hci_packet_type = unit->hci_acl_mask;
! 871:
! 872: /* SCO packet mask */
! 873: unit->hci_sco_mask = 0;
! 874: if (rp.features[1] & HCI_LMP_SCO_LINK)
! 875: unit->hci_sco_mask |= HCI_PKT_HV1;
! 876:
! 877: if (rp.features[1] & HCI_LMP_HV2_PKT)
! 878: unit->hci_sco_mask |= HCI_PKT_HV2;
! 879:
! 880: if (rp.features[1] & HCI_LMP_HV3_PKT)
! 881: unit->hci_sco_mask |= HCI_PKT_HV3;
! 882:
! 883: if (rp.features[3] & HCI_LMP_EV3_PKT)
! 884: unit->hci_sco_mask |= HCI_PKT_EV3;
! 885:
! 886: if (rp.features[4] & HCI_LMP_EV4_PKT)
! 887: unit->hci_sco_mask |= HCI_PKT_EV4;
! 888:
! 889: if (rp.features[4] & HCI_LMP_EV5_PKT)
! 890: unit->hci_sco_mask |= HCI_PKT_EV5;
! 891:
! 892: /* XXX what do 2MBPS/3MBPS/3SLOT eSCO mean? */
! 893:
! 894: s = splraiseipl(unit->hci_ipl);
! 895: unit->hci_flags &= ~BTF_INIT_FEATURES;
! 896: splx(s);
! 897:
! 898: wakeup(unit);
! 899:
! 900: DPRINTFN(1, "%s: lmp_mask %4.4x, acl_mask %4.4x, sco_mask %4.4x\n",
! 901: unit->hci_devname, unit->hci_lmp_mask,
! 902: unit->hci_acl_mask, unit->hci_sco_mask);
! 903: }
! 904:
! 905: /*
! 906: * process results of reset command_complete event
! 907: *
! 908: * This has killed all the connections, so close down anything we have left,
! 909: * and reinitialise the unit.
! 910: */
! 911: static void
! 912: hci_cmd_reset(struct hci_unit *unit, struct mbuf *m)
! 913: {
! 914: hci_reset_rp rp;
! 915: struct hci_link *link, *next;
! 916: int acl;
! 917:
! 918: KASSERT(m->m_pkthdr.len >= sizeof(rp));
! 919: m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
! 920: m_adj(m, sizeof(rp));
! 921:
! 922: if (rp.status != 0)
! 923: return;
! 924:
! 925: /*
! 926: * release SCO links first, since they may be holding
! 927: * an ACL link reference.
! 928: */
! 929: for (acl = 0 ; acl < 2 ; acl++) {
! 930: next = TAILQ_FIRST(&unit->hci_links);
! 931: while ((link = next) != NULL) {
! 932: next = TAILQ_NEXT(link, hl_next);
! 933: if (acl || link->hl_type != HCI_LINK_ACL)
! 934: hci_link_free(link, ECONNABORTED);
! 935: }
! 936: }
! 937:
! 938: unit->hci_num_acl_pkts = 0;
! 939: unit->hci_num_sco_pkts = 0;
! 940:
! 941: if (hci_send_cmd(unit, HCI_CMD_READ_BDADDR, NULL, 0))
! 942: return;
! 943:
! 944: if (hci_send_cmd(unit, HCI_CMD_READ_BUFFER_SIZE, NULL, 0))
! 945: return;
! 946:
! 947: if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_FEATURES, NULL, 0))
! 948: return;
! 949: }
CVSweb