The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netbt/hci_socket.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: hci_socket.c,v 1.4 2006/10/01 10:13:54 plunky Exp $    */
    2 
    3 /*-
    4  * Copyright (c) 2005 Iain Hibbert.
    5  * Copyright (c) 2006 Itronix Inc.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. The name of Itronix Inc. may not be used to endorse
   17  *    or promote products derived from this software without specific
   18  *    prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
   24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   27  * ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: hci_socket.c,v 1.4 2006/10/01 10:13:54 plunky Exp $");
   35 
   36 #include "opt_bluetooth.h"
   37 #ifdef BLUETOOTH_DEBUG
   38 #define PRCOREQUESTS
   39 #endif
   40 
   41 #include <sys/param.h>
   42 #include <sys/domain.h>
   43 #include <sys/kauth.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         case HCI_CMD_REMOTE_NAME_REQ:
   98         case HCI_CMD_READ_REMOTE_FEATURES:
   99         case HCI_CMD_READ_REMOTE_EXTENDED_FEATURES:
  100         case HCI_CMD_READ_REMOTE_VER_INFO:
  101         case HCI_CMD_READ_CLOCK_OFFSET:
  102         case HCI_CMD_READ_LMP_HANDLE:
  103 
  104         /* Link policy */
  105         case HCI_CMD_ROLE_DISCOVERY:
  106         case HCI_CMD_READ_LINK_POLICY_SETTINGS:
  107         case HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS:
  108 
  109         /* Host controller and baseband */
  110         case HCI_CMD_READ_PIN_TYPE:
  111         case HCI_CMD_READ_LOCAL_NAME:
  112         case HCI_CMD_READ_CON_ACCEPT_TIMEOUT:
  113         case HCI_CMD_READ_PAGE_TIMEOUT:
  114         case HCI_CMD_READ_SCAN_ENABLE:
  115         case HCI_CMD_READ_PAGE_SCAN_ACTIVITY:
  116         case HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY:
  117         case HCI_CMD_READ_AUTH_ENABLE:
  118         case HCI_CMD_READ_ENCRYPTION_MODE:
  119         case HCI_CMD_READ_UNIT_CLASS:
  120         case HCI_CMD_READ_VOICE_SETTING:
  121         case HCI_CMD_READ_AUTO_FLUSH_TIMEOUT:
  122         case HCI_CMD_READ_NUM_BROADCAST_RETRANS:
  123         case HCI_CMD_READ_HOLD_MODE_ACTIVITY:
  124         case HCI_CMD_READ_XMIT_LEVEL:
  125         case HCI_CMD_READ_SCO_FLOW_CONTROL:
  126         case HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT:
  127         case HCI_CMD_READ_NUM_SUPPORTED_IAC:
  128         case HCI_CMD_READ_IAC_LAP:
  129         case HCI_CMD_READ_PAGE_SCAN_PERIOD:
  130         case HCI_CMD_READ_PAGE_SCAN:
  131         case HCI_CMD_READ_INQUIRY_SCAN_TYPE:
  132         case HCI_CMD_READ_INQUIRY_MODE:
  133         case HCI_CMD_READ_PAGE_SCAN_TYPE:
  134         case HCI_CMD_READ_AFH_ASSESSMENT:
  135 
  136         /* Informational */
  137         case HCI_CMD_READ_LOCAL_VER:
  138         case HCI_CMD_READ_LOCAL_COMMANDS:
  139         case HCI_CMD_READ_LOCAL_FEATURES:
  140         case HCI_CMD_READ_LOCAL_EXTENDED_FEATURES:
  141         case HCI_CMD_READ_BUFFER_SIZE:
  142         case HCI_CMD_READ_COUNTRY_CODE:
  143         case HCI_CMD_READ_BDADDR:
  144 
  145         /* Status */
  146         case HCI_CMD_READ_FAILED_CONTACT_CNTR:
  147         case HCI_CMD_READ_LINK_QUALITY:
  148         case HCI_CMD_READ_RSSI:
  149         case HCI_CMD_READ_AFH_CHANNEL_MAP:
  150         case HCI_CMD_READ_CLOCK:
  151 
  152         /* Testing */
  153         case HCI_CMD_READ_LOOPBACK_MODE:
  154                 return 1;
  155         }
  156 
  157         return 0;
  158 }
  159 
  160 static int
  161 hci_security_check_event(uint8_t event)
  162 {
  163 
  164         switch (event) {
  165         case HCI_EVENT_RETURN_LINK_KEYS:
  166         case HCI_EVENT_LINK_KEY_NOTIFICATION:
  167         case HCI_EVENT_VENDOR:
  168                 return 0;
  169         }
  170 
  171         return 1;
  172 }
  173 
  174 /*
  175  * When command packet reaches the device, we can drop
  176  * it from the socket buffer (called from hci_output_acl)
  177  */
  178 void
  179 hci_drop(void *arg)
  180 {
  181         struct socket *so = arg;
  182 
  183         sbdroprecord(&so->so_snd);
  184         sowwakeup(so);
  185 }
  186 
  187 /*
  188  * HCI socket is going away and has some pending packets. We let them
  189  * go by design, but remove the context pointer as it will be invalid
  190  * and we no longer need to be notified.
  191  */
  192 static void
  193 hci_cmdwait_flush(struct socket *so)
  194 {
  195         struct hci_unit *unit;
  196         struct socket *ctx;
  197         struct mbuf *m;
  198 
  199         DPRINTF("flushing %p\n", so);
  200 
  201         SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) {
  202                 m = MBUFQ_FIRST(&unit->hci_cmdwait);
  203                 while (m != NULL) {
  204                         ctx = M_GETCTX(m, struct socket *);
  205                         if (ctx == so)
  206                                 M_SETCTX(m, NULL);
  207 
  208                         m = MBUFQ_NEXT(m);
  209                 }
  210         }
  211 }
  212 
  213 /*
  214  * HCI send packet
  215  *     This came from userland, so check it out.
  216  */
  217 static int
  218 hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr)
  219 {
  220         struct hci_unit *unit;
  221         struct mbuf *m0;
  222         hci_cmd_hdr_t hdr;
  223         int err;
  224 
  225         KASSERT(m);
  226         KASSERT(addr);
  227 
  228         /* wants at least a header to start with */
  229         if (m->m_pkthdr.len < sizeof(hdr)) {
  230                 err = EMSGSIZE;
  231                 goto bad;
  232         }
  233         m_copydata(m, 0, sizeof(hdr), &hdr);
  234 
  235         /* only allows CMD packets to be sent */
  236         if (hdr.type != HCI_CMD_PKT) {
  237                 err = EINVAL;
  238                 goto bad;
  239         }
  240 
  241         /* validates packet length */
  242         if (m->m_pkthdr.len != sizeof(hdr) + hdr.length) {
  243                 err = EMSGSIZE;
  244                 goto bad;
  245         }
  246 
  247         /* security checks for unprivileged users */
  248         if ((pcb->hp_flags & HCI_PRIVILEGED) == 0
  249             && (hci_security_check_opcode(le16toh(hdr.opcode)) == 0)) {
  250                 err = EPERM;
  251                 goto bad;
  252         }
  253 
  254         /* finds destination */
  255         unit = hci_unit_lookup(addr);
  256         if (unit == NULL) {
  257                 err = ENETDOWN;
  258                 goto bad;
  259         }
  260 
  261         /* makess a copy for precious to keep */
  262         m0 = m_copypacket(m, M_DONTWAIT);
  263         if (m0 == NULL) {
  264                 err = ENOMEM;
  265                 goto bad;
  266         }
  267         sbappendrecord(&pcb->hp_socket->so_snd, m0);
  268         M_SETCTX(m, pcb->hp_socket);    /* enable drop callback */
  269 
  270         DPRINTFN(2, "(%s) opcode (%03x|%04x)\n", unit->hci_devname,
  271                 HCI_OGF(le16toh(hdr.opcode)), HCI_OCF(le16toh(hdr.opcode)));
  272 
  273         /* Sendss it */
  274         if (unit->hci_num_cmd_pkts == 0)
  275                 MBUFQ_ENQUEUE(&unit->hci_cmdwait, m);
  276         else
  277                 hci_output_cmd(unit, m);
  278 
  279         return 0;
  280 
  281 bad:
  282         DPRINTF("packet (%d bytes) not sent (error %d)\n",
  283                         m->m_pkthdr.len, err);
  284         if (m) m_freem(m);
  285         return err;
  286 }
  287 
  288 /*
  289  * User Request.
  290  * up is socket
  291  * m is either
  292  *      optional mbuf chain containing message
  293  *      ioctl command (PRU_CONTROL)
  294  * nam is either
  295  *      optional mbuf chain containing an address
  296  *      ioctl data (PRU_CONTROL)
  297  *      optionally, protocol number (PRU_ATTACH)
  298  * ctl is optional mbuf chain containing socket options
  299  * l is pointer to process requesting action (if any)
  300  *
  301  * we are responsible for disposing of m and ctl if
  302  * they are mbuf chains
  303  */
  304 int
  305 hci_usrreq(struct socket *up, int req, struct mbuf *m,
  306                 struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
  307 {
  308         struct hci_pcb *pcb = (struct hci_pcb *)up->so_pcb;
  309         struct sockaddr_bt *sa;
  310         int err = 0;
  311 
  312         DPRINTFN(2, "%s\n", prurequests[req]);
  313 
  314         switch(req) {
  315         case PRU_CONTROL:
  316                 return hci_ioctl((unsigned long)m, (void *)nam, l);
  317 
  318         case PRU_PURGEIF:
  319                 return EOPNOTSUPP;
  320 
  321         case PRU_ATTACH:
  322                 if (pcb)
  323                         return EINVAL;
  324 
  325                 err = soreserve(up, hci_sendspace, hci_recvspace);
  326                 if (err)
  327                         return err;
  328 
  329                 pcb = malloc(sizeof(struct hci_pcb), M_PCB, M_NOWAIT | M_ZERO);
  330                 if (pcb == NULL)
  331                         return ENOMEM;
  332 
  333                 up->so_pcb = pcb;
  334                 pcb->hp_socket = up;
  335 
  336                 if (l == NULL
  337                     || kauth_authorize_generic(l->l_cred,
  338                                                 KAUTH_GENERIC_ISSUSER,
  339                                                 &l->l_acflag) == 0)
  340                         pcb->hp_flags |= HCI_PRIVILEGED;
  341 
  342                 /*
  343                  * Set default user filter. By default, socket only passes
  344                  * Command_Complete and Command_Status Events.
  345                  */
  346                 hci_filter_set(HCI_EVENT_COMMAND_COMPL, &pcb->hp_efilter);
  347                 hci_filter_set(HCI_EVENT_COMMAND_STATUS, &pcb->hp_efilter);
  348                 hci_filter_set(HCI_EVENT_PKT, &pcb->hp_pfilter);
  349 
  350                 LIST_INSERT_HEAD(&hci_pcb, pcb, hp_next);
  351 
  352                 return 0;
  353         }
  354 
  355         /* anything after here *requires* a pcb */
  356         if (pcb == NULL) {
  357                 err = EINVAL;
  358                 goto release;
  359         }
  360 
  361         switch(req) {
  362         case PRU_DISCONNECT:
  363                 bdaddr_copy(&pcb->hp_raddr, BDADDR_ANY);
  364 
  365                 /* XXX we cannot call soisdisconnected() here, as it sets
  366                  * SS_CANTRCVMORE and SS_CANTSENDMORE. The problem being,
  367                  * that soisconnected() does not clear these and if you
  368                  * try to reconnect this socket (which is permitted) you
  369                  * get a broken pipe when you try to write any data.
  370                  */
  371                 up->so_state &= ~SS_ISCONNECTED;
  372                 break;
  373 
  374         case PRU_ABORT:
  375                 soisdisconnected(up);
  376                 /* fall through to */
  377         case PRU_DETACH:
  378                 if (up->so_snd.sb_mb != NULL)
  379                         hci_cmdwait_flush(up);
  380 
  381                 up->so_pcb = NULL;
  382                 LIST_REMOVE(pcb, hp_next);
  383                 free(pcb, M_PCB);
  384                 return 0;
  385 
  386         case PRU_BIND:
  387                 KASSERT(nam);
  388                 sa = mtod(nam, struct sockaddr_bt *);
  389 
  390                 if (sa->bt_len != sizeof(struct sockaddr_bt))
  391                         return EINVAL;
  392 
  393                 if (sa->bt_family != AF_BLUETOOTH)
  394                         return EAFNOSUPPORT;
  395 
  396                 bdaddr_copy(&pcb->hp_laddr, &sa->bt_bdaddr);
  397 
  398                 if (bdaddr_any(&sa->bt_bdaddr))
  399                         pcb->hp_flags |= HCI_PROMISCUOUS;
  400                 else
  401                         pcb->hp_flags &= ~HCI_PROMISCUOUS;
  402 
  403                 return 0;
  404 
  405         case PRU_CONNECT:
  406                 KASSERT(nam);
  407                 sa = mtod(nam, struct sockaddr_bt *);
  408 
  409                 if (sa->bt_len != sizeof(struct sockaddr_bt))
  410                         return EINVAL;
  411 
  412                 if (sa->bt_family != AF_BLUETOOTH)
  413                         return EAFNOSUPPORT;
  414 
  415                 if (hci_unit_lookup(&sa->bt_bdaddr) == NULL)
  416                         return EADDRNOTAVAIL;
  417 
  418                 bdaddr_copy(&pcb->hp_raddr, &sa->bt_bdaddr);
  419                 soisconnected(up);
  420                 return 0;
  421 
  422         case PRU_PEERADDR:
  423                 KASSERT(nam);
  424                 sa = mtod(nam, struct sockaddr_bt *);
  425 
  426                 memset(sa, 0, sizeof(struct sockaddr_bt));
  427                 nam->m_len =
  428                 sa->bt_len = sizeof(struct sockaddr_bt);
  429                 sa->bt_family = AF_BLUETOOTH;
  430                 bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_raddr);
  431                 return 0;
  432 
  433         case PRU_SOCKADDR:
  434                 KASSERT(nam);
  435                 sa = mtod(nam, struct sockaddr_bt *);
  436 
  437                 memset(sa, 0, sizeof(struct sockaddr_bt));
  438                 nam->m_len =
  439                 sa->bt_len = sizeof(struct sockaddr_bt);
  440                 sa->bt_family = AF_BLUETOOTH;
  441                 bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_laddr);
  442                 return 0;
  443 
  444         case PRU_SHUTDOWN:
  445                 socantsendmore(up);
  446                 break;
  447 
  448         case PRU_SEND:
  449                 sa = NULL;
  450                 if (nam) {
  451                         sa = mtod(nam, struct sockaddr_bt *);
  452 
  453                         if (sa->bt_len != sizeof(struct sockaddr_bt)) {
  454                                 err = EINVAL;
  455                                 goto release;
  456                         }
  457 
  458                         if (sa->bt_family != AF_BLUETOOTH) {
  459                                 err = EAFNOSUPPORT;
  460                                 goto release;
  461                         }
  462                 }
  463 
  464                 if (ctl) /* have no use for this */
  465                         m_freem(ctl);
  466 
  467                 return hci_send(pcb, m, (sa ? &sa->bt_bdaddr : &pcb->hp_raddr));
  468 
  469         case PRU_SENSE:
  470                 return 0;               /* (no sense - Doh!) */
  471 
  472         case PRU_RCVD:
  473         case PRU_RCVOOB:
  474                 return EOPNOTSUPP;      /* (no release) */
  475 
  476         case PRU_ACCEPT:
  477         case PRU_CONNECT2:
  478         case PRU_LISTEN:
  479         case PRU_SENDOOB:
  480         case PRU_FASTTIMO:
  481         case PRU_SLOWTIMO:
  482         case PRU_PROTORCV:
  483         case PRU_PROTOSEND:
  484                 err = EOPNOTSUPP;
  485                 break;
  486 
  487         default:
  488                 UNKNOWN(req);
  489                 err = EOPNOTSUPP;
  490                 break;
  491         }
  492 
  493 release:
  494         if (m)
  495                 m_freem(m);
  496         if (ctl)
  497                 m_freem(ctl);
  498         return err;
  499 }
  500 
  501 /*
  502  * get/set socket options
  503  */
  504 int
  505 hci_ctloutput(int req, struct socket *so, int level,
  506                 int optname, struct mbuf **opt)
  507 {
  508         struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
  509         struct mbuf *m;
  510         int err = 0;
  511 
  512         DPRINTFN(2, "req %s\n", prcorequests[req]);
  513 
  514         if (pcb == NULL)
  515                 return EINVAL;
  516 
  517         if (level != BTPROTO_HCI)
  518                 return 0;
  519 
  520         switch(req) {
  521         case PRCO_GETOPT:
  522                 m = m_get(M_WAIT, MT_SOOPTS);
  523                 switch (optname) {
  524                 case SO_HCI_EVT_FILTER:
  525                         m->m_len = sizeof(struct hci_filter);
  526                         memcpy(mtod(m, void *), &pcb->hp_efilter, m->m_len);
  527                         break;
  528 
  529                 case SO_HCI_PKT_FILTER:
  530                         m->m_len = sizeof(struct hci_filter);
  531                         memcpy(mtod(m, void *), &pcb->hp_pfilter, m->m_len);
  532                         break;
  533 
  534                 case SO_HCI_DIRECTION:
  535                         m->m_len = sizeof(int);
  536                         if (pcb->hp_flags & HCI_DIRECTION)
  537                                 *mtod(m, int *) = 1;
  538                         else
  539                                 *mtod(m, int *) = 0;
  540                         break;
  541 
  542                 default:
  543                         err = EINVAL;
  544                         m_freem(m);
  545                         m = NULL;
  546                         break;
  547                 }
  548                 *opt = m;
  549                 break;
  550 
  551         case PRCO_SETOPT:
  552                 m = *opt;
  553                 if (m) switch (optname) {
  554                 case SO_HCI_EVT_FILTER: /* set event filter */
  555                         m->m_len = min(m->m_len, sizeof(struct hci_filter));
  556                         memcpy(&pcb->hp_efilter, mtod(m, void *), m->m_len);
  557                         break;
  558 
  559                 case SO_HCI_PKT_FILTER: /* set packet filter */
  560                         m->m_len = min(m->m_len, sizeof(struct hci_filter));
  561                         memcpy(&pcb->hp_pfilter, mtod(m, void *), m->m_len);
  562                         break;
  563 
  564                 case SO_HCI_DIRECTION:  /* request direction ctl messages */
  565                         if (*mtod(m, int *))
  566                                 pcb->hp_flags |= HCI_DIRECTION;
  567                         else
  568                                 pcb->hp_flags &= ~HCI_DIRECTION;
  569                         break;
  570 
  571                 default:
  572                         err = EINVAL;
  573                         break;
  574                 }
  575                 m_freem(m);
  576                 break;
  577 
  578         default:
  579                 err = EINVAL;
  580                 break;
  581         }
  582 
  583         return err;
  584 }
  585 
  586 /*
  587  * HCI mbuf tap routine
  588  *
  589  * copy packets to any raw HCI sockets that wish (and are
  590  * permitted) to see them
  591  */
  592 void
  593 hci_mtap(struct mbuf *m, struct hci_unit *unit)
  594 {
  595         struct hci_pcb *pcb;
  596         struct mbuf *m0, *ctlmsg, **ctl;
  597         struct sockaddr_bt sa;
  598         uint8_t type;
  599         uint8_t event;
  600         uint16_t opcode;
  601 
  602         KASSERT(m->m_len >= sizeof(type));
  603 
  604         type = *mtod(m, uint8_t *);
  605 
  606         memset(&sa, 0, sizeof(sa));
  607         sa.bt_len = sizeof(struct sockaddr_bt);
  608         sa.bt_family = AF_BLUETOOTH;
  609         bdaddr_copy(&sa.bt_bdaddr, &unit->hci_bdaddr);
  610 
  611         LIST_FOREACH(pcb, &hci_pcb, hp_next) {
  612                 /*
  613                  * filter according to source address
  614                  */
  615                 if ((pcb->hp_flags & HCI_PROMISCUOUS) == 0
  616                     && bdaddr_same(&pcb->hp_laddr, &sa.bt_bdaddr) == 0)
  617                         continue;
  618 
  619                 /*
  620                  * filter according to packet type filter
  621                  */
  622                 if (hci_filter_test(type, &pcb->hp_pfilter) == 0)
  623                         continue;
  624 
  625                 /*
  626                  * filter according to event/security filters
  627                  */
  628                 switch(type) {
  629                 case HCI_EVENT_PKT:
  630                         KASSERT(m->m_len >= sizeof(hci_event_hdr_t));
  631 
  632                         event = mtod(m, hci_event_hdr_t *)->event;
  633 
  634                         if (hci_filter_test(event, &pcb->hp_efilter) == 0)
  635                                 continue;
  636 
  637                         if ((pcb->hp_flags & HCI_PRIVILEGED) == 0
  638                             && hci_security_check_event(event) == 0)
  639                                 continue;
  640                         break;
  641 
  642                 case HCI_CMD_PKT:
  643                         KASSERT(m->m_len >= sizeof(hci_cmd_hdr_t));
  644 
  645                         opcode = le16toh(mtod(m, hci_cmd_hdr_t *)->opcode);
  646 
  647                         if ((pcb->hp_flags & HCI_PRIVILEGED) == 0
  648                             && hci_security_check_opcode(opcode) == 0)
  649                                 continue;
  650                         break;
  651 
  652                 case HCI_ACL_DATA_PKT:
  653                 case HCI_SCO_DATA_PKT:
  654                 default:
  655                         if ((pcb->hp_flags & HCI_PRIVILEGED) == 0)
  656                                 continue;
  657 
  658                         break;
  659                 }
  660 
  661                 /*
  662                  * create control messages
  663                  */
  664                 ctlmsg = NULL;
  665                 ctl = &ctlmsg;
  666                 if (pcb->hp_flags & HCI_DIRECTION) {
  667                         int dir = m->m_flags & M_LINK0 ? 1 : 0;
  668 
  669                         *ctl = sbcreatecontrol((caddr_t)&dir, sizeof(dir),
  670                             SCM_HCI_DIRECTION, BTPROTO_HCI);
  671 
  672                         if (*ctl != NULL)
  673                                 ctl = &((*ctl)->m_next);
  674                 }
  675 
  676                 /*
  677                  * copy to socket
  678                  */
  679                 m0 = m_copypacket(m, M_DONTWAIT);
  680                 if (m0 && sbappendaddr(&pcb->hp_socket->so_rcv,
  681                                 (struct sockaddr *)&sa, m0, ctlmsg)) {
  682                         sorwakeup(pcb->hp_socket);
  683                 } else {
  684                         m_freem(ctlmsg);
  685                         m_freem(m0);
  686                 }
  687         }
  688 }

Cache object: bd6a8731343716180467c8b14d74ab8d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.