Annotation of sys/netbt/hci_socket.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: hci_socket.c,v 1.3 2007/06/02 01:46:01 uwe Exp $ */
! 2: /* $NetBSD: hci_socket.c,v 1.10 2007/03/31 18:17:13 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: /* load symbolic names */
! 37: #ifdef BLUETOOTH_DEBUG
! 38: #define PRUREQUESTS
! 39: #define PRCOREQUESTS
! 40: #endif
! 41:
! 42: #include <sys/param.h>
! 43: #include <sys/domain.h>
! 44: #include <sys/kernel.h>
! 45: #include <sys/mbuf.h>
! 46: #include <sys/proc.h>
! 47: #include <sys/protosw.h>
! 48: #include <sys/socket.h>
! 49: #include <sys/socketvar.h>
! 50: #include <sys/systm.h>
! 51:
! 52: #include <netbt/bluetooth.h>
! 53: #include <netbt/hci.h>
! 54:
! 55: /*******************************************************************************
! 56: *
! 57: * HCI SOCK_RAW Sockets - for control of Bluetooth Devices
! 58: *
! 59: */
! 60:
! 61: /*
! 62: * the raw HCI protocol control block
! 63: */
! 64: struct hci_pcb {
! 65: struct socket *hp_socket; /* socket */
! 66: unsigned int hp_flags; /* flags */
! 67: bdaddr_t hp_laddr; /* local address */
! 68: bdaddr_t hp_raddr; /* remote address */
! 69: struct hci_filter hp_efilter; /* user event filter */
! 70: struct hci_filter hp_pfilter; /* user packet filter */
! 71: LIST_ENTRY(hci_pcb) hp_next; /* next HCI pcb */
! 72: };
! 73:
! 74: /* hp_flags */
! 75: #define HCI_PRIVILEGED (1<<0) /* no security filter for root */
! 76: #define HCI_DIRECTION (1<<1) /* direction control messages */
! 77: #define HCI_PROMISCUOUS (1<<2) /* listen to all units */
! 78:
! 79: LIST_HEAD(hci_pcb_list, hci_pcb) hci_pcb = LIST_HEAD_INITIALIZER(hci_pcb);
! 80:
! 81: /* sysctl defaults */
! 82: int hci_sendspace = HCI_CMD_PKT_SIZE;
! 83: int hci_recvspace = 4096;
! 84:
! 85: /*
! 86: * Security filter routines for unprivileged users.
! 87: * Allow all but a few critical events, and only permit read commands.
! 88: */
! 89:
! 90: static int
! 91: hci_security_check_opcode(uint16_t opcode)
! 92: {
! 93:
! 94: switch (opcode) {
! 95: /* Link control */
! 96: case HCI_CMD_INQUIRY:
! 97: return sizeof(hci_inquiry_cp);
! 98: case HCI_CMD_REMOTE_NAME_REQ:
! 99: return sizeof(hci_remote_name_req_cp);
! 100: case HCI_CMD_READ_REMOTE_FEATURES:
! 101: return sizeof(hci_read_remote_features_cp);
! 102: case HCI_CMD_READ_REMOTE_EXTENDED_FEATURES:
! 103: return sizeof(hci_read_remote_extended_features_cp);
! 104: case HCI_CMD_READ_REMOTE_VER_INFO:
! 105: return sizeof(hci_read_remote_ver_info_cp);
! 106: case HCI_CMD_READ_CLOCK_OFFSET:
! 107: return sizeof(hci_read_clock_offset_cp);
! 108: case HCI_CMD_READ_LMP_HANDLE:
! 109: return sizeof(hci_read_lmp_handle_cp);
! 110:
! 111: /* Link policy */
! 112: case HCI_CMD_ROLE_DISCOVERY:
! 113: return sizeof(hci_role_discovery_cp);
! 114: case HCI_CMD_READ_LINK_POLICY_SETTINGS:
! 115: return sizeof(hci_read_link_policy_settings_cp);
! 116: case HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS:
! 117: return 0; /* No command parameters */
! 118:
! 119: /* Host controller and baseband */
! 120: case HCI_CMD_READ_PIN_TYPE:
! 121: case HCI_CMD_READ_LOCAL_NAME:
! 122: case HCI_CMD_READ_CON_ACCEPT_TIMEOUT:
! 123: case HCI_CMD_READ_PAGE_TIMEOUT:
! 124: case HCI_CMD_READ_SCAN_ENABLE:
! 125: case HCI_CMD_READ_PAGE_SCAN_ACTIVITY:
! 126: case HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY:
! 127: case HCI_CMD_READ_AUTH_ENABLE:
! 128: case HCI_CMD_READ_ENCRYPTION_MODE:
! 129: case HCI_CMD_READ_UNIT_CLASS:
! 130: case HCI_CMD_READ_VOICE_SETTING:
! 131: return 0; /* No command parameters */
! 132: case HCI_CMD_READ_AUTO_FLUSH_TIMEOUT:
! 133: return sizeof(hci_read_auto_flush_timeout_cp);
! 134: case HCI_CMD_READ_NUM_BROADCAST_RETRANS:
! 135: case HCI_CMD_READ_HOLD_MODE_ACTIVITY:
! 136: return 0; /* No command parameters */
! 137: case HCI_CMD_READ_XMIT_LEVEL:
! 138: return sizeof(hci_read_xmit_level_cp);
! 139: case HCI_CMD_READ_SCO_FLOW_CONTROL:
! 140: return 0; /* No command parameters */
! 141: case HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT:
! 142: return sizeof(hci_read_link_supervision_timeout_cp);
! 143: case HCI_CMD_READ_NUM_SUPPORTED_IAC:
! 144: case HCI_CMD_READ_IAC_LAP:
! 145: case HCI_CMD_READ_PAGE_SCAN_PERIOD:
! 146: case HCI_CMD_READ_PAGE_SCAN:
! 147: case HCI_CMD_READ_INQUIRY_SCAN_TYPE:
! 148: case HCI_CMD_READ_INQUIRY_MODE:
! 149: case HCI_CMD_READ_PAGE_SCAN_TYPE:
! 150: case HCI_CMD_READ_AFH_ASSESSMENT:
! 151: return 0; /* No command parameters */
! 152:
! 153: /* Informational */
! 154: case HCI_CMD_READ_LOCAL_VER:
! 155: case HCI_CMD_READ_LOCAL_COMMANDS:
! 156: case HCI_CMD_READ_LOCAL_FEATURES:
! 157: return 0; /* No command parameters */
! 158: case HCI_CMD_READ_LOCAL_EXTENDED_FEATURES:
! 159: return sizeof(hci_read_local_extended_features_cp);
! 160: case HCI_CMD_READ_BUFFER_SIZE:
! 161: case HCI_CMD_READ_COUNTRY_CODE:
! 162: case HCI_CMD_READ_BDADDR:
! 163: return 0; /* No command parameters */
! 164:
! 165: /* Status */
! 166: case HCI_CMD_READ_FAILED_CONTACT_CNTR:
! 167: return sizeof(hci_read_failed_contact_cntr_cp);
! 168: case HCI_CMD_READ_LINK_QUALITY:
! 169: return sizeof(hci_read_link_quality_cp);
! 170: case HCI_CMD_READ_RSSI:
! 171: return sizeof(hci_read_rssi_cp);
! 172: case HCI_CMD_READ_AFH_CHANNEL_MAP:
! 173: return sizeof(hci_read_afh_channel_map_cp);
! 174: case HCI_CMD_READ_CLOCK:
! 175: return sizeof(hci_read_clock_cp);
! 176:
! 177: /* Testing */
! 178: case HCI_CMD_READ_LOOPBACK_MODE:
! 179: return 0; /* No command parameters */
! 180: }
! 181:
! 182: return -1; /* disallowed */
! 183: }
! 184:
! 185: static int
! 186: hci_security_check_event(uint8_t event)
! 187: {
! 188:
! 189: switch (event) {
! 190: case HCI_EVENT_RETURN_LINK_KEYS:
! 191: case HCI_EVENT_LINK_KEY_NOTIFICATION:
! 192: case HCI_EVENT_VENDOR:
! 193: return -1; /* disallowed */
! 194: }
! 195:
! 196: return 0; /* ok */
! 197: }
! 198:
! 199: /*
! 200: * When command packet reaches the device, we can drop
! 201: * it from the socket buffer (called from hci_output_acl)
! 202: */
! 203: void
! 204: hci_drop(void *arg)
! 205: {
! 206: struct socket *so = arg;
! 207:
! 208: sbdroprecord(&so->so_snd);
! 209: sowwakeup(so);
! 210: }
! 211:
! 212: /*
! 213: * HCI socket is going away and has some pending packets. We let them
! 214: * go by design, but remove the context pointer as it will be invalid
! 215: * and we no longer need to be notified.
! 216: */
! 217: static void
! 218: hci_cmdwait_flush(struct socket *so)
! 219: {
! 220: struct hci_unit *unit;
! 221: struct socket *ctx;
! 222: struct mbuf *m;
! 223:
! 224: DPRINTF("flushing %p\n", so);
! 225:
! 226: TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
! 227: IF_POLL(&unit->hci_cmdwait, m);
! 228: while (m != NULL) {
! 229: ctx = M_GETCTX(m, struct socket *);
! 230: if (ctx == so)
! 231: M_SETCTX(m, NULL);
! 232:
! 233: m = m->m_nextpkt;
! 234: }
! 235: }
! 236: }
! 237:
! 238: /*
! 239: * HCI send packet
! 240: * This came from userland, so check it out.
! 241: */
! 242: static int
! 243: hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr)
! 244: {
! 245: struct hci_unit *unit;
! 246: struct mbuf *m0;
! 247: hci_cmd_hdr_t hdr;
! 248: int err;
! 249:
! 250: KASSERT(m != NULL);
! 251: KASSERT(addr != NULL);
! 252:
! 253: /* wants at least a header to start with */
! 254: if (m->m_pkthdr.len < sizeof(hdr)) {
! 255: err = EMSGSIZE;
! 256: goto bad;
! 257: }
! 258: m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr);
! 259:
! 260: /* only allows CMD packets to be sent */
! 261: if (hdr.type != HCI_CMD_PKT) {
! 262: err = EINVAL;
! 263: goto bad;
! 264: }
! 265:
! 266: /* validates packet length */
! 267: if (m->m_pkthdr.len != sizeof(hdr) + hdr.length) {
! 268: err = EMSGSIZE;
! 269: goto bad;
! 270: }
! 271:
! 272: /* security checks for unprivileged users */
! 273: if ((pcb->hp_flags & HCI_PRIVILEGED) == 0
! 274: && hci_security_check_opcode(letoh16(hdr.opcode)) != hdr.length) {
! 275: err = EPERM;
! 276: goto bad;
! 277: }
! 278:
! 279: /* finds destination */
! 280: unit = hci_unit_lookup(addr);
! 281: if (unit == NULL) {
! 282: err = ENETDOWN;
! 283: goto bad;
! 284: }
! 285:
! 286: /* makes a copy for precious to keep */
! 287: m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
! 288: if (m0 == NULL) {
! 289: err = ENOMEM;
! 290: goto bad;
! 291: }
! 292: sbappendrecord(&pcb->hp_socket->so_snd, m0);
! 293: M_SETCTX(m, pcb->hp_socket); /* enable drop callback */
! 294:
! 295: DPRINTFN(2, "(%s) opcode (%03x|%04x)\n", unit->hci_devname,
! 296: HCI_OGF(letoh16(hdr.opcode)), HCI_OCF(letoh16(hdr.opcode)));
! 297:
! 298: /* Sendss it */
! 299: if (unit->hci_num_cmd_pkts == 0)
! 300: IF_ENQUEUE(&unit->hci_cmdwait, m);
! 301: else
! 302: hci_output_cmd(unit, m);
! 303:
! 304: return 0;
! 305:
! 306: bad:
! 307: DPRINTF("packet (%d bytes) not sent (error %d)\n",
! 308: m->m_pkthdr.len, err);
! 309: if (m) m_freem(m);
! 310: return err;
! 311: }
! 312:
! 313: /*
! 314: * User Request.
! 315: * up is socket
! 316: * m is either
! 317: * optional mbuf chain containing message
! 318: * ioctl command (PRU_CONTROL)
! 319: * nam is either
! 320: * optional mbuf chain containing an address
! 321: * ioctl data (PRU_CONTROL)
! 322: * optionally, protocol number (PRU_ATTACH)
! 323: * ctl is optional mbuf chain containing socket options
! 324: * l is pointer to process requesting action (if any)
! 325: *
! 326: * we are responsible for disposing of m and ctl if
! 327: * they are mbuf chains
! 328: */
! 329: int
! 330: hci_usrreq(struct socket *up, int req, struct mbuf *m,
! 331: struct mbuf *nam, struct mbuf *ctl)
! 332: {
! 333: struct hci_pcb *pcb = (struct hci_pcb *)up->so_pcb;
! 334: struct sockaddr_bt *sa;
! 335: int err = 0;
! 336:
! 337: #ifdef notyet /* XXX */
! 338: DPRINTFN(2, "%s\n", prurequests[req]);
! 339: #endif
! 340:
! 341: switch(req) {
! 342: case PRU_CONTROL:
! 343: return hci_ioctl((unsigned long)m, (void *)nam, curproc);
! 344:
! 345: case PRU_ATTACH:
! 346: if (pcb)
! 347: return EINVAL;
! 348:
! 349: err = soreserve(up, hci_sendspace, hci_recvspace);
! 350: if (err)
! 351: return err;
! 352:
! 353: pcb = malloc(sizeof *pcb, M_PCB, M_NOWAIT);
! 354: if (pcb == NULL)
! 355: return ENOMEM;
! 356: bzero(pcb, sizeof *pcb);
! 357:
! 358: up->so_pcb = pcb;
! 359: pcb->hp_socket = up;
! 360:
! 361: if (curproc == NULL || suser(curproc, 0) == 0)
! 362: pcb->hp_flags |= HCI_PRIVILEGED;
! 363:
! 364: /*
! 365: * Set default user filter. By default, socket only passes
! 366: * Command_Complete and Command_Status Events.
! 367: */
! 368: hci_filter_set(HCI_EVENT_COMMAND_COMPL, &pcb->hp_efilter);
! 369: hci_filter_set(HCI_EVENT_COMMAND_STATUS, &pcb->hp_efilter);
! 370: hci_filter_set(HCI_EVENT_PKT, &pcb->hp_pfilter);
! 371:
! 372: LIST_INSERT_HEAD(&hci_pcb, pcb, hp_next);
! 373:
! 374: return 0;
! 375: }
! 376:
! 377: /* anything after here *requires* a pcb */
! 378: if (pcb == NULL) {
! 379: err = EINVAL;
! 380: goto release;
! 381: }
! 382:
! 383: switch(req) {
! 384: case PRU_DISCONNECT:
! 385: bdaddr_copy(&pcb->hp_raddr, BDADDR_ANY);
! 386:
! 387: /* XXX we cannot call soisdisconnected() here, as it sets
! 388: * SS_CANTRCVMORE and SS_CANTSENDMORE. The problem being,
! 389: * that soisconnected() does not clear these and if you
! 390: * try to reconnect this socket (which is permitted) you
! 391: * get a broken pipe when you try to write any data.
! 392: */
! 393: up->so_state &= ~SS_ISCONNECTED;
! 394: break;
! 395:
! 396: case PRU_ABORT:
! 397: soisdisconnected(up);
! 398: /* fall through to */
! 399: case PRU_DETACH:
! 400: if (up->so_snd.sb_mb != NULL)
! 401: hci_cmdwait_flush(up);
! 402:
! 403: up->so_pcb = NULL;
! 404: LIST_REMOVE(pcb, hp_next);
! 405: free(pcb, M_PCB);
! 406: return 0;
! 407:
! 408: case PRU_BIND:
! 409: KASSERT(nam != NULL);
! 410: sa = mtod(nam, struct sockaddr_bt *);
! 411:
! 412: if (sa->bt_len != sizeof(struct sockaddr_bt))
! 413: return EINVAL;
! 414:
! 415: if (sa->bt_family != AF_BLUETOOTH)
! 416: return EAFNOSUPPORT;
! 417:
! 418: bdaddr_copy(&pcb->hp_laddr, &sa->bt_bdaddr);
! 419:
! 420: if (bdaddr_any(&sa->bt_bdaddr))
! 421: pcb->hp_flags |= HCI_PROMISCUOUS;
! 422: else
! 423: pcb->hp_flags &= ~HCI_PROMISCUOUS;
! 424:
! 425: return 0;
! 426:
! 427: case PRU_CONNECT:
! 428: KASSERT(nam != NULL);
! 429: sa = mtod(nam, struct sockaddr_bt *);
! 430:
! 431: if (sa->bt_len != sizeof(struct sockaddr_bt))
! 432: return EINVAL;
! 433:
! 434: if (sa->bt_family != AF_BLUETOOTH)
! 435: return EAFNOSUPPORT;
! 436:
! 437: if (hci_unit_lookup(&sa->bt_bdaddr) == NULL)
! 438: return EADDRNOTAVAIL;
! 439:
! 440: bdaddr_copy(&pcb->hp_raddr, &sa->bt_bdaddr);
! 441: soisconnected(up);
! 442: return 0;
! 443:
! 444: case PRU_PEERADDR:
! 445: KASSERT(nam != NULL);
! 446: sa = mtod(nam, struct sockaddr_bt *);
! 447:
! 448: memset(sa, 0, sizeof(struct sockaddr_bt));
! 449: nam->m_len =
! 450: sa->bt_len = sizeof(struct sockaddr_bt);
! 451: sa->bt_family = AF_BLUETOOTH;
! 452: bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_raddr);
! 453: return 0;
! 454:
! 455: case PRU_SOCKADDR:
! 456: KASSERT(nam != NULL);
! 457: sa = mtod(nam, struct sockaddr_bt *);
! 458:
! 459: memset(sa, 0, sizeof(struct sockaddr_bt));
! 460: nam->m_len =
! 461: sa->bt_len = sizeof(struct sockaddr_bt);
! 462: sa->bt_family = AF_BLUETOOTH;
! 463: bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_laddr);
! 464: return 0;
! 465:
! 466: case PRU_SHUTDOWN:
! 467: socantsendmore(up);
! 468: break;
! 469:
! 470: case PRU_SEND:
! 471: sa = NULL;
! 472: if (nam) {
! 473: sa = mtod(nam, struct sockaddr_bt *);
! 474:
! 475: if (sa->bt_len != sizeof(struct sockaddr_bt)) {
! 476: err = EINVAL;
! 477: goto release;
! 478: }
! 479:
! 480: if (sa->bt_family != AF_BLUETOOTH) {
! 481: err = EAFNOSUPPORT;
! 482: goto release;
! 483: }
! 484: }
! 485:
! 486: if (ctl) /* have no use for this */
! 487: m_freem(ctl);
! 488:
! 489: return hci_send(pcb, m, (sa ? &sa->bt_bdaddr : &pcb->hp_raddr));
! 490:
! 491: case PRU_SENSE:
! 492: return 0; /* (no sense - Doh!) */
! 493:
! 494: case PRU_RCVD:
! 495: case PRU_RCVOOB:
! 496: return EOPNOTSUPP; /* (no release) */
! 497:
! 498: case PRU_ACCEPT:
! 499: case PRU_CONNECT2:
! 500: case PRU_LISTEN:
! 501: case PRU_SENDOOB:
! 502: case PRU_FASTTIMO:
! 503: case PRU_SLOWTIMO:
! 504: case PRU_PROTORCV:
! 505: case PRU_PROTOSEND:
! 506: err = EOPNOTSUPP;
! 507: break;
! 508:
! 509: default:
! 510: UNKNOWN(req);
! 511: err = EOPNOTSUPP;
! 512: break;
! 513: }
! 514:
! 515: release:
! 516: if (m)
! 517: m_freem(m);
! 518: if (ctl)
! 519: m_freem(ctl);
! 520: return err;
! 521: }
! 522:
! 523: /*
! 524: * get/set socket options
! 525: */
! 526: int
! 527: hci_ctloutput(int req, struct socket *so, int level,
! 528: int optname, struct mbuf **opt)
! 529: {
! 530: struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
! 531: struct mbuf *m;
! 532: int err = 0;
! 533:
! 534: #ifdef notyet /* XXX */
! 535: DPRINTFN(2, "req %s\n", prcorequests[req]);
! 536: #endif
! 537:
! 538: if (pcb == NULL)
! 539: return EINVAL;
! 540:
! 541: if (level != BTPROTO_HCI)
! 542: return ENOPROTOOPT;
! 543:
! 544: switch(req) {
! 545: case PRCO_GETOPT:
! 546: m = m_get(M_WAIT, MT_SOOPTS);
! 547: switch (optname) {
! 548: case SO_HCI_EVT_FILTER:
! 549: m->m_len = sizeof(struct hci_filter);
! 550: memcpy(mtod(m, void *), &pcb->hp_efilter, m->m_len);
! 551: break;
! 552:
! 553: case SO_HCI_PKT_FILTER:
! 554: m->m_len = sizeof(struct hci_filter);
! 555: memcpy(mtod(m, void *), &pcb->hp_pfilter, m->m_len);
! 556: break;
! 557:
! 558: case SO_HCI_DIRECTION:
! 559: m->m_len = sizeof(int);
! 560: if (pcb->hp_flags & HCI_DIRECTION)
! 561: *mtod(m, int *) = 1;
! 562: else
! 563: *mtod(m, int *) = 0;
! 564: break;
! 565:
! 566: default:
! 567: err = ENOPROTOOPT;
! 568: m_freem(m);
! 569: m = NULL;
! 570: break;
! 571: }
! 572: *opt = m;
! 573: break;
! 574:
! 575: case PRCO_SETOPT:
! 576: m = *opt;
! 577: if (m) switch (optname) {
! 578: case SO_HCI_EVT_FILTER: /* set event filter */
! 579: m->m_len = min(m->m_len, sizeof(struct hci_filter));
! 580: memcpy(&pcb->hp_efilter, mtod(m, void *), m->m_len);
! 581: break;
! 582:
! 583: case SO_HCI_PKT_FILTER: /* set packet filter */
! 584: m->m_len = min(m->m_len, sizeof(struct hci_filter));
! 585: memcpy(&pcb->hp_pfilter, mtod(m, void *), m->m_len);
! 586: break;
! 587:
! 588: case SO_HCI_DIRECTION: /* request direction ctl messages */
! 589: if (*mtod(m, int *))
! 590: pcb->hp_flags |= HCI_DIRECTION;
! 591: else
! 592: pcb->hp_flags &= ~HCI_DIRECTION;
! 593: break;
! 594:
! 595: default:
! 596: err = ENOPROTOOPT;
! 597: break;
! 598: }
! 599: m_freem(m);
! 600: break;
! 601:
! 602: default:
! 603: err = ENOPROTOOPT;
! 604: break;
! 605: }
! 606:
! 607: return err;
! 608: }
! 609:
! 610: /*
! 611: * HCI mbuf tap routine
! 612: *
! 613: * copy packets to any raw HCI sockets that wish (and are
! 614: * permitted) to see them
! 615: */
! 616: void
! 617: hci_mtap(struct mbuf *m, struct hci_unit *unit)
! 618: {
! 619: struct hci_pcb *pcb;
! 620: struct mbuf *m0, *ctlmsg, **ctl;
! 621: struct sockaddr_bt sa;
! 622: uint8_t type;
! 623: uint8_t event;
! 624: uint16_t opcode;
! 625:
! 626: KASSERT(m->m_len >= sizeof(type));
! 627:
! 628: type = *mtod(m, uint8_t *);
! 629:
! 630: memset(&sa, 0, sizeof(sa));
! 631: sa.bt_len = sizeof(struct sockaddr_bt);
! 632: sa.bt_family = AF_BLUETOOTH;
! 633: bdaddr_copy(&sa.bt_bdaddr, &unit->hci_bdaddr);
! 634:
! 635: LIST_FOREACH(pcb, &hci_pcb, hp_next) {
! 636: /*
! 637: * filter according to source address
! 638: */
! 639: if ((pcb->hp_flags & HCI_PROMISCUOUS) == 0
! 640: && bdaddr_same(&pcb->hp_laddr, &sa.bt_bdaddr) == 0)
! 641: continue;
! 642:
! 643: /*
! 644: * filter according to packet type filter
! 645: */
! 646: if (hci_filter_test(type, &pcb->hp_pfilter) == 0)
! 647: continue;
! 648:
! 649: /*
! 650: * filter according to event/security filters
! 651: */
! 652: switch(type) {
! 653: case HCI_EVENT_PKT:
! 654: KASSERT(m->m_len >= sizeof(hci_event_hdr_t));
! 655:
! 656: event = mtod(m, hci_event_hdr_t *)->event;
! 657:
! 658: if (hci_filter_test(event, &pcb->hp_efilter) == 0)
! 659: continue;
! 660:
! 661: if ((pcb->hp_flags & HCI_PRIVILEGED) == 0
! 662: && hci_security_check_event(event) == -1)
! 663: continue;
! 664: break;
! 665:
! 666: case HCI_CMD_PKT:
! 667: KASSERT(m->m_len >= sizeof(hci_cmd_hdr_t));
! 668:
! 669: opcode = letoh16(mtod(m, hci_cmd_hdr_t *)->opcode);
! 670:
! 671: if ((pcb->hp_flags & HCI_PRIVILEGED) == 0
! 672: && hci_security_check_opcode(opcode) == -1)
! 673: continue;
! 674: break;
! 675:
! 676: case HCI_ACL_DATA_PKT:
! 677: case HCI_SCO_DATA_PKT:
! 678: default:
! 679: if ((pcb->hp_flags & HCI_PRIVILEGED) == 0)
! 680: continue;
! 681:
! 682: break;
! 683: }
! 684:
! 685: /*
! 686: * create control messages
! 687: */
! 688: ctlmsg = NULL;
! 689: ctl = &ctlmsg;
! 690: if (pcb->hp_flags & HCI_DIRECTION) {
! 691: int dir = m->m_flags & M_LINK0 ? 1 : 0;
! 692:
! 693: *ctl = sbcreatecontrol((void *)&dir, sizeof(dir),
! 694: SCM_HCI_DIRECTION, BTPROTO_HCI);
! 695:
! 696: if (*ctl != NULL)
! 697: ctl = &((*ctl)->m_next);
! 698: }
! 699:
! 700: /*
! 701: * copy to socket
! 702: */
! 703: m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
! 704: if (m0 && sbappendaddr(&pcb->hp_socket->so_rcv,
! 705: (struct sockaddr *)&sa, m0, ctlmsg)) {
! 706: sorwakeup(pcb->hp_socket);
! 707: } else {
! 708: m_freem(ctlmsg);
! 709: m_freem(m0);
! 710: }
! 711: }
! 712: }
CVSweb