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.17 2008/08/06 15:01:24 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.17 2008/08/06 15:01:24 plunky Exp $");
   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/kauth.h>
   45 #include <sys/kernel.h>
   46 #include <sys/mbuf.h>
   47 #include <sys/proc.h>
   48 #include <sys/protosw.h>
   49 #include <sys/socket.h>
   50 #include <sys/socketvar.h>
   51 #include <sys/systm.h>
   52 
   53 #include <netbt/bluetooth.h>
   54 #include <netbt/hci.h>
   55 
   56 /*******************************************************************************
   57  *
   58  * HCI SOCK_RAW Sockets - for control of Bluetooth Devices
   59  *
   60  */
   61 
   62 /*
   63  * the raw HCI protocol control block
   64  */
   65 struct hci_pcb {
   66         struct socket           *hp_socket;     /* socket */
   67         unsigned int            hp_flags;       /* flags */
   68         bdaddr_t                hp_laddr;       /* local address */
   69         bdaddr_t                hp_raddr;       /* remote address */
   70         struct hci_filter       hp_efilter;     /* user event filter */
   71         struct hci_filter       hp_pfilter;     /* user packet filter */
   72         LIST_ENTRY(hci_pcb)     hp_next;        /* next HCI pcb */
   73 };
   74 
   75 /* hp_flags */
   76 #define HCI_PRIVILEGED          (1<<0)  /* no security filter for root */
   77 #define HCI_DIRECTION           (1<<1)  /* direction control messages */
   78 #define HCI_PROMISCUOUS         (1<<2)  /* listen to all units */
   79 
   80 LIST_HEAD(hci_pcb_list, hci_pcb) hci_pcb = LIST_HEAD_INITIALIZER(hci_pcb);
   81 
   82 /* sysctl defaults */
   83 int hci_sendspace = HCI_CMD_PKT_SIZE;
   84 int hci_recvspace = 4096;
   85 
   86 /* supported commands opcode table */
   87 static const struct {
   88         uint16_t        opcode;
   89         uint8_t         offs;   /* 0 - 63 */
   90         uint8_t         mask;   /* bit 0 - 7 */
   91         int16_t         length; /* -1 if privileged */
   92 } hci_cmds[] = {
   93         { HCI_CMD_INQUIRY,
   94           0,  0x01, sizeof(hci_inquiry_cp) },
   95         { HCI_CMD_INQUIRY_CANCEL,
   96           0,  0x02, -1 },
   97         { HCI_CMD_PERIODIC_INQUIRY,
   98           0,  0x04, -1 },
   99         { HCI_CMD_EXIT_PERIODIC_INQUIRY,
  100           0,  0x08, -1 },
  101         { HCI_CMD_CREATE_CON,
  102           0,  0x10, -1 },
  103         { HCI_CMD_DISCONNECT,
  104           0,  0x20, -1 },
  105         { HCI_CMD_ADD_SCO_CON,
  106           0,  0x40, -1 },
  107         { HCI_CMD_CREATE_CON_CANCEL,
  108           0,  0x80, -1 },
  109         { HCI_CMD_ACCEPT_CON,
  110           1,  0x01, -1 },
  111         { HCI_CMD_REJECT_CON,
  112           1,  0x02, -1 },
  113         { HCI_CMD_LINK_KEY_REP,
  114           1,  0x04, -1 },
  115         { HCI_CMD_LINK_KEY_NEG_REP,
  116           1,  0x08, -1 },
  117         { HCI_CMD_PIN_CODE_REP,
  118           1,  0x10, -1 },
  119         { HCI_CMD_PIN_CODE_NEG_REP,
  120           1,  0x20, -1 },
  121         { HCI_CMD_CHANGE_CON_PACKET_TYPE,
  122           1,  0x40, -1 },
  123         { HCI_CMD_AUTH_REQ,
  124           1,  0x80, -1 },
  125         { HCI_CMD_SET_CON_ENCRYPTION,
  126           2,  0x01, -1 },
  127         { HCI_CMD_CHANGE_CON_LINK_KEY,
  128           2,  0x02, -1 },
  129         { HCI_CMD_MASTER_LINK_KEY,
  130           2,  0x04, -1 },
  131         { HCI_CMD_REMOTE_NAME_REQ,
  132           2,  0x08, sizeof(hci_remote_name_req_cp) },
  133         { HCI_CMD_REMOTE_NAME_REQ_CANCEL,
  134           2,  0x10, -1 },
  135         { HCI_CMD_READ_REMOTE_FEATURES,
  136           2,  0x20, sizeof(hci_read_remote_features_cp) },
  137         { HCI_CMD_READ_REMOTE_EXTENDED_FEATURES,
  138           2,  0x40, sizeof(hci_read_remote_extended_features_cp) },
  139         { HCI_CMD_READ_REMOTE_VER_INFO,
  140           2,  0x80, sizeof(hci_read_remote_ver_info_cp) },
  141         { HCI_CMD_READ_CLOCK_OFFSET,
  142           3,  0x01, sizeof(hci_read_clock_offset_cp) },
  143         { HCI_CMD_READ_LMP_HANDLE,
  144           3,  0x02, sizeof(hci_read_lmp_handle_cp) },
  145         { HCI_CMD_HOLD_MODE,
  146           4,  0x02, -1 },
  147         { HCI_CMD_SNIFF_MODE,
  148           4,  0x04, -1 },
  149         { HCI_CMD_EXIT_SNIFF_MODE,
  150           4,  0x08, -1 },
  151         { HCI_CMD_PARK_MODE,
  152           4,  0x10, -1 },
  153         { HCI_CMD_EXIT_PARK_MODE,
  154           4,  0x20, -1 },
  155         { HCI_CMD_QOS_SETUP,
  156           4,  0x40, -1 },
  157         { HCI_CMD_ROLE_DISCOVERY,
  158           4,  0x80, sizeof(hci_role_discovery_cp) },
  159         { HCI_CMD_SWITCH_ROLE,
  160           5,  0x01, -1 },
  161         { HCI_CMD_READ_LINK_POLICY_SETTINGS,
  162           5,  0x02, sizeof(hci_read_link_policy_settings_cp) },
  163         { HCI_CMD_WRITE_LINK_POLICY_SETTINGS,
  164           5,  0x04, -1 },
  165         { HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS,
  166           5,  0x08, 0 },
  167         { HCI_CMD_WRITE_DEFAULT_LINK_POLICY_SETTINGS,
  168           5,  0x10, -1 },
  169         { HCI_CMD_FLOW_SPECIFICATION,
  170           5,  0x20, -1 },
  171         { HCI_CMD_SET_EVENT_MASK,
  172           5,  0x40, -1 },
  173         { HCI_CMD_RESET,
  174           5,  0x80, -1 },
  175         { HCI_CMD_SET_EVENT_FILTER,
  176           6,  0x01, -1 },
  177         { HCI_CMD_FLUSH,
  178           6,  0x02, -1 },
  179         { HCI_CMD_READ_PIN_TYPE,
  180           6,  0x04, 0 },
  181         { HCI_CMD_WRITE_PIN_TYPE,
  182           6,  0x08, -1 },
  183         { HCI_CMD_CREATE_NEW_UNIT_KEY,
  184           6,  0x10, -1 },
  185         { HCI_CMD_READ_STORED_LINK_KEY,
  186           6,  0x20, -1 },
  187         { HCI_CMD_WRITE_STORED_LINK_KEY,
  188           6,  0x40, -1 },
  189         { HCI_CMD_DELETE_STORED_LINK_KEY,
  190           6,  0x80, -1 },
  191         { HCI_CMD_WRITE_LOCAL_NAME,
  192           7,  0x01, -1 },
  193         { HCI_CMD_READ_LOCAL_NAME,
  194           7,  0x02, 0 },
  195         { HCI_CMD_READ_CON_ACCEPT_TIMEOUT,
  196           7,  0x04, 0 },
  197         { HCI_CMD_WRITE_CON_ACCEPT_TIMEOUT,
  198           7,  0x08, -1 },
  199         { HCI_CMD_READ_PAGE_TIMEOUT,
  200           7,  0x10, 0 },
  201         { HCI_CMD_WRITE_PAGE_TIMEOUT,
  202           7,  0x20, -1 },
  203         { HCI_CMD_READ_SCAN_ENABLE,
  204           7,  0x40, 0 },
  205         { HCI_CMD_WRITE_SCAN_ENABLE,
  206           7,  0x80, -1 },
  207         { HCI_CMD_READ_PAGE_SCAN_ACTIVITY,
  208           8,  0x01, 0 },
  209         { HCI_CMD_WRITE_PAGE_SCAN_ACTIVITY,
  210           8,  0x02, -1 },
  211         { HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY,
  212           8,  0x04, 0 },
  213         { HCI_CMD_WRITE_INQUIRY_SCAN_ACTIVITY,
  214           8,  0x08, -1 },
  215         { HCI_CMD_READ_AUTH_ENABLE,
  216           8,  0x10, 0 },
  217         { HCI_CMD_WRITE_AUTH_ENABLE,
  218           8,  0x20, -1 },
  219         { HCI_CMD_READ_ENCRYPTION_MODE,
  220           8,  0x40, 0 },
  221         { HCI_CMD_WRITE_ENCRYPTION_MODE,
  222           8,  0x80, -1 },
  223         { HCI_CMD_READ_UNIT_CLASS,
  224           9,  0x01, 0 },
  225         { HCI_CMD_WRITE_UNIT_CLASS,
  226           9,  0x02, -1 },
  227         { HCI_CMD_READ_VOICE_SETTING,
  228           9,  0x04, 0 },
  229         { HCI_CMD_WRITE_VOICE_SETTING,
  230           9,  0x08, -1 },
  231         { HCI_CMD_READ_AUTO_FLUSH_TIMEOUT,
  232           9,  0x10, sizeof(hci_read_auto_flush_timeout_cp) },
  233         { HCI_CMD_WRITE_AUTO_FLUSH_TIMEOUT,
  234           9,  0x20, -1 },
  235         { HCI_CMD_READ_NUM_BROADCAST_RETRANS,
  236           9,  0x40, 0 },
  237         { HCI_CMD_WRITE_NUM_BROADCAST_RETRANS,
  238           9,  0x80, -1 },
  239         { HCI_CMD_READ_HOLD_MODE_ACTIVITY,
  240           10, 0x01, 0 },
  241         { HCI_CMD_WRITE_HOLD_MODE_ACTIVITY,
  242           10, 0x02, -1 },
  243         { HCI_CMD_READ_XMIT_LEVEL,
  244           10, 0x04, sizeof(hci_read_xmit_level_cp) },
  245         { HCI_CMD_READ_SCO_FLOW_CONTROL,
  246           10, 0x08, 0 },
  247         { HCI_CMD_WRITE_SCO_FLOW_CONTROL,
  248           10, 0x10, -1 },
  249         { HCI_CMD_HC2H_FLOW_CONTROL,
  250           10, 0x20, -1 },
  251         { HCI_CMD_HOST_BUFFER_SIZE,
  252           10, 0x40, -1 },
  253         { HCI_CMD_HOST_NUM_COMPL_PKTS,
  254           10, 0x80, -1 },
  255         { HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT,
  256           11, 0x01, sizeof(hci_read_link_supervision_timeout_cp) },
  257         { HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT,
  258           11, 0x02, -1 },
  259         { HCI_CMD_READ_NUM_SUPPORTED_IAC,
  260           11, 0x04, 0 },
  261         { HCI_CMD_READ_IAC_LAP,
  262           11, 0x08, 0 },
  263         { HCI_CMD_WRITE_IAC_LAP,
  264           11, 0x10, -1 },
  265         { HCI_CMD_READ_PAGE_SCAN_PERIOD,
  266           11, 0x20, 0 },
  267         { HCI_CMD_WRITE_PAGE_SCAN_PERIOD,
  268           11, 0x40, -1 },
  269         { HCI_CMD_READ_PAGE_SCAN,
  270           11, 0x80, 0 },
  271         { HCI_CMD_WRITE_PAGE_SCAN,
  272           12, 0x01, -1 },
  273         { HCI_CMD_SET_AFH_CLASSIFICATION,
  274           12, 0x02, -1 },
  275         { HCI_CMD_READ_INQUIRY_SCAN_TYPE,
  276           12, 0x10, 0 },
  277         { HCI_CMD_WRITE_INQUIRY_SCAN_TYPE,
  278           12, 0x20, -1 },
  279         { HCI_CMD_READ_INQUIRY_MODE,
  280           12, 0x40, 0 },
  281         { HCI_CMD_WRITE_INQUIRY_MODE,
  282           12, 0x80, -1 },
  283         { HCI_CMD_READ_PAGE_SCAN_TYPE,
  284           13, 0x01, 0 },
  285         { HCI_CMD_WRITE_PAGE_SCAN_TYPE,
  286           13, 0x02, -1 },
  287         { HCI_CMD_READ_AFH_ASSESSMENT,
  288           13, 0x04, 0 },
  289         { HCI_CMD_WRITE_AFH_ASSESSMENT,
  290           13, 0x08, -1 },
  291         { HCI_CMD_READ_LOCAL_VER,
  292           14, 0x08, 0 },
  293         { HCI_CMD_READ_LOCAL_COMMANDS,
  294           14, 0x10, 0 },
  295         { HCI_CMD_READ_LOCAL_FEATURES,
  296           14, 0x20, 0 },
  297         { HCI_CMD_READ_LOCAL_EXTENDED_FEATURES,
  298           14, 0x40, sizeof(hci_read_local_extended_features_cp) },
  299         { HCI_CMD_READ_BUFFER_SIZE,
  300           14, 0x80, 0 },
  301         { HCI_CMD_READ_COUNTRY_CODE,
  302           15, 0x01, 0 },
  303         { HCI_CMD_READ_BDADDR,
  304           15, 0x02, 0 },
  305         { HCI_CMD_READ_FAILED_CONTACT_CNTR,
  306           15, 0x04, sizeof(hci_read_failed_contact_cntr_cp) },
  307         { HCI_CMD_RESET_FAILED_CONTACT_CNTR,
  308           15, 0x08, -1 },
  309         { HCI_CMD_READ_LINK_QUALITY,
  310           15, 0x10, sizeof(hci_read_link_quality_cp) },
  311         { HCI_CMD_READ_RSSI,
  312           15, 0x20, sizeof(hci_read_rssi_cp) },
  313         { HCI_CMD_READ_AFH_CHANNEL_MAP,
  314           15, 0x40, sizeof(hci_read_afh_channel_map_cp) },
  315         { HCI_CMD_READ_CLOCK,
  316           15, 0x80, sizeof(hci_read_clock_cp) },
  317         { HCI_CMD_READ_LOOPBACK_MODE,
  318           16, 0x01, 0 },
  319         { HCI_CMD_WRITE_LOOPBACK_MODE,
  320           16, 0x02, -1 },
  321         { HCI_CMD_ENABLE_UNIT_UNDER_TEST,
  322           16, 0x04, -1 },
  323         { HCI_CMD_SETUP_SCO_CON,
  324           16, 0x08, -1 },
  325         { HCI_CMD_ACCEPT_SCO_CON_REQ,
  326           16, 0x10, -1 },
  327         { HCI_CMD_REJECT_SCO_CON_REQ,
  328           16, 0x20, -1 },
  329         { HCI_CMD_READ_EXTENDED_INQUIRY_RSP,
  330           17, 0x01, 0 },
  331         { HCI_CMD_WRITE_EXTENDED_INQUIRY_RSP,
  332           17, 0x02, -1 },
  333         { HCI_CMD_REFRESH_ENCRYPTION_KEY,
  334           17, 0x04, -1 },
  335         { HCI_CMD_SNIFF_SUBRATING,
  336           17, 0x10, -1 },
  337         { HCI_CMD_READ_SIMPLE_PAIRING_MODE,
  338           17, 0x20, 0 },
  339         { HCI_CMD_WRITE_SIMPLE_PAIRING_MODE,
  340           17, 0x40, -1 },
  341         { HCI_CMD_READ_LOCAL_OOB_DATA,
  342           17, 0x80, -1 },
  343         { HCI_CMD_READ_INQUIRY_RSP_XMIT_POWER,
  344           18, 0x01, 0 },
  345         { HCI_CMD_WRITE_INQUIRY_RSP_XMIT_POWER,
  346           18, 0x02, -1 },
  347         { HCI_CMD_READ_DEFAULT_ERRDATA_REPORTING,
  348           18, 0x04, 0 },
  349         { HCI_CMD_WRITE_DEFAULT_ERRDATA_REPORTING,
  350           18, 0x08, -1 },
  351         { HCI_CMD_IO_CAPABILITY_REP,
  352           18, 0x80, -1 },
  353         { HCI_CMD_USER_CONFIRM_REP,
  354           19, 0x01, -1 },
  355         { HCI_CMD_USER_CONFIRM_NEG_REP,
  356           19, 0x02, -1 },
  357         { HCI_CMD_USER_PASSKEY_REP,
  358           19, 0x04, -1 },
  359         { HCI_CMD_USER_PASSKEY_NEG_REP,
  360           19, 0x08, -1 },
  361         { HCI_CMD_OOB_DATA_REP,
  362           19, 0x10, -1 },
  363         { HCI_CMD_WRITE_SIMPLE_PAIRING_DEBUG_MODE,
  364           19, 0x20, -1 },
  365         { HCI_CMD_ENHANCED_FLUSH,
  366           19, 0x40, -1 },
  367         { HCI_CMD_OOB_DATA_NEG_REP,
  368           19, 0x80, -1 },
  369         { HCI_CMD_SEND_KEYPRESS_NOTIFICATION,
  370           20, 0x40, -1 },
  371         { HCI_CMD_IO_CAPABILITY_NEG_REP,
  372           20, 0x80, -1 },
  373 };
  374 
  375 /*
  376  * Security filter routines for unprivileged users.
  377  *      Allow all but a few critical events, and only permit read commands.
  378  *      If a unit is given, verify the command is supported.
  379  */
  380 
  381 static int
  382 hci_security_check_opcode(struct hci_unit *unit, uint16_t opcode)
  383 {
  384         int i;
  385 
  386         for (i = 0 ; i < __arraycount(hci_cmds) ; i++) {
  387                 if (opcode != hci_cmds[i].opcode)
  388                         continue;
  389 
  390                 if (unit == NULL
  391                     || (unit->hci_cmds[hci_cmds[i].offs] & hci_cmds[i].mask))
  392                         return hci_cmds[i].length;
  393 
  394                 break;
  395         }
  396 
  397         return -1;
  398 }
  399 
  400 static int
  401 hci_security_check_event(uint8_t event)
  402 {
  403 
  404         switch (event) {
  405         case HCI_EVENT_RETURN_LINK_KEYS:
  406         case HCI_EVENT_LINK_KEY_NOTIFICATION:
  407         case HCI_EVENT_USER_CONFIRM_REQ:
  408         case HCI_EVENT_USER_PASSKEY_NOTIFICATION:
  409         case HCI_EVENT_VENDOR:
  410                 return -1;      /* disallowed */
  411         }
  412 
  413         return 0;       /* ok */
  414 }
  415 
  416 /*
  417  * When command packet reaches the device, we can drop
  418  * it from the socket buffer (called from hci_output_acl)
  419  */
  420 void
  421 hci_drop(void *arg)
  422 {
  423         struct socket *so = arg;
  424 
  425         sbdroprecord(&so->so_snd);
  426         sowwakeup(so);
  427 }
  428 
  429 /*
  430  * HCI socket is going away and has some pending packets. We let them
  431  * go by design, but remove the context pointer as it will be invalid
  432  * and we no longer need to be notified.
  433  */
  434 static void
  435 hci_cmdwait_flush(struct socket *so)
  436 {
  437         struct hci_unit *unit;
  438         struct socket *ctx;
  439         struct mbuf *m;
  440 
  441         DPRINTF("flushing %p\n", so);
  442 
  443         SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) {
  444                 m = MBUFQ_FIRST(&unit->hci_cmdwait);
  445                 while (m != NULL) {
  446                         ctx = M_GETCTX(m, struct socket *);
  447                         if (ctx == so)
  448                                 M_SETCTX(m, NULL);
  449 
  450                         m = MBUFQ_NEXT(m);
  451                 }
  452         }
  453 }
  454 
  455 /*
  456  * HCI send packet
  457  *     This came from userland, so check it out.
  458  */
  459 static int
  460 hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr)
  461 {
  462         struct hci_unit *unit;
  463         struct mbuf *m0;
  464         hci_cmd_hdr_t hdr;
  465         int err;
  466 
  467         KASSERT(m != NULL);
  468         KASSERT(addr != NULL);
  469 
  470         /* wants at least a header to start with */
  471         if (m->m_pkthdr.len < sizeof(hdr)) {
  472                 err = EMSGSIZE;
  473                 goto bad;
  474         }
  475         m_copydata(m, 0, sizeof(hdr), &hdr);
  476         hdr.opcode = le16toh(hdr.opcode);
  477 
  478         /* only allows CMD packets to be sent */
  479         if (hdr.type != HCI_CMD_PKT) {
  480                 err = EINVAL;
  481                 goto bad;
  482         }
  483 
  484         /* validates packet length */
  485         if (m->m_pkthdr.len != sizeof(hdr) + hdr.length) {
  486                 err = EMSGSIZE;
  487                 goto bad;
  488         }
  489 
  490         /* finds destination */
  491         unit = hci_unit_lookup(addr);
  492         if (unit == NULL) {
  493                 err = ENETDOWN;
  494                 goto bad;
  495         }
  496 
  497         /* security checks for unprivileged users */
  498         if ((pcb->hp_flags & HCI_PRIVILEGED) == 0
  499             && hci_security_check_opcode(unit, hdr.opcode) != hdr.length) {
  500                 err = EPERM;
  501                 goto bad;
  502         }
  503 
  504         /* makess a copy for precious to keep */
  505         m0 = m_copypacket(m, M_DONTWAIT);
  506         if (m0 == NULL) {
  507                 err = ENOMEM;
  508                 goto bad;
  509         }
  510         sbappendrecord(&pcb->hp_socket->so_snd, m0);
  511         M_SETCTX(m, pcb->hp_socket);    /* enable drop callback */
  512 
  513         DPRINTFN(2, "(%s) opcode (%03x|%04x)\n", device_xname(unit->hci_dev),
  514                 HCI_OGF(hdr.opcode), HCI_OCF(hdr.opcode));
  515 
  516         /* Sendss it */
  517         if (unit->hci_num_cmd_pkts == 0)
  518                 MBUFQ_ENQUEUE(&unit->hci_cmdwait, m);
  519         else
  520                 hci_output_cmd(unit, m);
  521 
  522         return 0;
  523 
  524 bad:
  525         DPRINTF("packet (%d bytes) not sent (error %d)\n",
  526                         m->m_pkthdr.len, err);
  527         if (m) m_freem(m);
  528         return err;
  529 }
  530 
  531 /*
  532  * User Request.
  533  * up is socket
  534  * m is either
  535  *      optional mbuf chain containing message
  536  *      ioctl command (PRU_CONTROL)
  537  * nam is either
  538  *      optional mbuf chain containing an address
  539  *      ioctl data (PRU_CONTROL)
  540  *      optionally, protocol number (PRU_ATTACH)
  541  * ctl is optional mbuf chain containing socket options
  542  * l is pointer to process requesting action (if any)
  543  *
  544  * we are responsible for disposing of m and ctl if
  545  * they are mbuf chains
  546  */
  547 int
  548 hci_usrreq(struct socket *up, int req, struct mbuf *m,
  549                 struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
  550 {
  551         struct hci_pcb *pcb = (struct hci_pcb *)up->so_pcb;
  552         struct sockaddr_bt *sa;
  553         int err = 0;
  554 
  555         DPRINTFN(2, "%s\n", prurequests[req]);
  556 
  557         switch(req) {
  558         case PRU_CONTROL:
  559                 mutex_enter(bt_lock);
  560                 err = hci_ioctl((unsigned long)m, (void *)nam, l);
  561                 mutex_exit(bt_lock);
  562                 return err;
  563 
  564         case PRU_PURGEIF:
  565                 return EOPNOTSUPP;
  566 
  567         case PRU_ATTACH:
  568                 if (up->so_lock == NULL) {
  569                         mutex_obj_hold(bt_lock);
  570                         up->so_lock = bt_lock;
  571                         solock(up);
  572                 }
  573                 KASSERT(solocked(up));
  574                 if (pcb)
  575                         return EINVAL;
  576                 err = soreserve(up, hci_sendspace, hci_recvspace);
  577                 if (err)
  578                         return err;
  579 
  580                 pcb = malloc(sizeof(struct hci_pcb), M_PCB, M_NOWAIT | M_ZERO);
  581                 if (pcb == NULL)
  582                         return ENOMEM;
  583 
  584                 up->so_pcb = pcb;
  585                 pcb->hp_socket = up;
  586 
  587                 if (l == NULL || kauth_authorize_generic(l->l_cred,
  588                     KAUTH_GENERIC_ISSUSER, NULL) == 0)
  589                         pcb->hp_flags |= HCI_PRIVILEGED;
  590 
  591                 /*
  592                  * Set default user filter. By default, socket only passes
  593                  * Command_Complete and Command_Status Events.
  594                  */
  595                 hci_filter_set(HCI_EVENT_COMMAND_COMPL, &pcb->hp_efilter);
  596                 hci_filter_set(HCI_EVENT_COMMAND_STATUS, &pcb->hp_efilter);
  597                 hci_filter_set(HCI_EVENT_PKT, &pcb->hp_pfilter);
  598 
  599                 LIST_INSERT_HEAD(&hci_pcb, pcb, hp_next);
  600 
  601                 return 0;
  602         }
  603 
  604         /* anything after here *requires* a pcb */
  605         if (pcb == NULL) {
  606                 err = EINVAL;
  607                 goto release;
  608         }
  609 
  610         switch(req) {
  611         case PRU_DISCONNECT:
  612                 bdaddr_copy(&pcb->hp_raddr, BDADDR_ANY);
  613 
  614                 /* XXX we cannot call soisdisconnected() here, as it sets
  615                  * SS_CANTRCVMORE and SS_CANTSENDMORE. The problem being,
  616                  * that soisconnected() does not clear these and if you
  617                  * try to reconnect this socket (which is permitted) you
  618                  * get a broken pipe when you try to write any data.
  619                  */
  620                 up->so_state &= ~SS_ISCONNECTED;
  621                 break;
  622 
  623         case PRU_ABORT:
  624                 soisdisconnected(up);
  625                 /* fall through to */
  626         case PRU_DETACH:
  627                 if (up->so_snd.sb_mb != NULL)
  628                         hci_cmdwait_flush(up);
  629 
  630                 up->so_pcb = NULL;
  631                 LIST_REMOVE(pcb, hp_next);
  632                 free(pcb, M_PCB);
  633                 return 0;
  634 
  635         case PRU_BIND:
  636                 KASSERT(nam != NULL);
  637                 sa = mtod(nam, struct sockaddr_bt *);
  638 
  639                 if (sa->bt_len != sizeof(struct sockaddr_bt))
  640                         return EINVAL;
  641 
  642                 if (sa->bt_family != AF_BLUETOOTH)
  643                         return EAFNOSUPPORT;
  644 
  645                 bdaddr_copy(&pcb->hp_laddr, &sa->bt_bdaddr);
  646 
  647                 if (bdaddr_any(&sa->bt_bdaddr))
  648                         pcb->hp_flags |= HCI_PROMISCUOUS;
  649                 else
  650                         pcb->hp_flags &= ~HCI_PROMISCUOUS;
  651 
  652                 return 0;
  653 
  654         case PRU_CONNECT:
  655                 KASSERT(nam != NULL);
  656                 sa = mtod(nam, struct sockaddr_bt *);
  657 
  658                 if (sa->bt_len != sizeof(struct sockaddr_bt))
  659                         return EINVAL;
  660 
  661                 if (sa->bt_family != AF_BLUETOOTH)
  662                         return EAFNOSUPPORT;
  663 
  664                 if (hci_unit_lookup(&sa->bt_bdaddr) == NULL)
  665                         return EADDRNOTAVAIL;
  666 
  667                 bdaddr_copy(&pcb->hp_raddr, &sa->bt_bdaddr);
  668                 soisconnected(up);
  669                 return 0;
  670 
  671         case PRU_PEERADDR:
  672                 KASSERT(nam != NULL);
  673                 sa = mtod(nam, struct sockaddr_bt *);
  674 
  675                 memset(sa, 0, sizeof(struct sockaddr_bt));
  676                 nam->m_len =
  677                 sa->bt_len = sizeof(struct sockaddr_bt);
  678                 sa->bt_family = AF_BLUETOOTH;
  679                 bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_raddr);
  680                 return 0;
  681 
  682         case PRU_SOCKADDR:
  683                 KASSERT(nam != NULL);
  684                 sa = mtod(nam, struct sockaddr_bt *);
  685 
  686                 memset(sa, 0, sizeof(struct sockaddr_bt));
  687                 nam->m_len =
  688                 sa->bt_len = sizeof(struct sockaddr_bt);
  689                 sa->bt_family = AF_BLUETOOTH;
  690                 bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_laddr);
  691                 return 0;
  692 
  693         case PRU_SHUTDOWN:
  694                 socantsendmore(up);
  695                 break;
  696 
  697         case PRU_SEND:
  698                 sa = NULL;
  699                 if (nam) {
  700                         sa = mtod(nam, struct sockaddr_bt *);
  701 
  702                         if (sa->bt_len != sizeof(struct sockaddr_bt)) {
  703                                 err = EINVAL;
  704                                 goto release;
  705                         }
  706 
  707                         if (sa->bt_family != AF_BLUETOOTH) {
  708                                 err = EAFNOSUPPORT;
  709                                 goto release;
  710                         }
  711                 }
  712 
  713                 if (ctl) /* have no use for this */
  714                         m_freem(ctl);
  715 
  716                 return hci_send(pcb, m, (sa ? &sa->bt_bdaddr : &pcb->hp_raddr));
  717 
  718         case PRU_SENSE:
  719                 return 0;               /* (no sense - Doh!) */
  720 
  721         case PRU_RCVD:
  722         case PRU_RCVOOB:
  723                 return EOPNOTSUPP;      /* (no release) */
  724 
  725         case PRU_ACCEPT:
  726         case PRU_CONNECT2:
  727         case PRU_LISTEN:
  728         case PRU_SENDOOB:
  729         case PRU_FASTTIMO:
  730         case PRU_SLOWTIMO:
  731         case PRU_PROTORCV:
  732         case PRU_PROTOSEND:
  733                 err = EOPNOTSUPP;
  734                 break;
  735 
  736         default:
  737                 UNKNOWN(req);
  738                 err = EOPNOTSUPP;
  739                 break;
  740         }
  741 
  742 release:
  743         if (m)
  744                 m_freem(m);
  745         if (ctl)
  746                 m_freem(ctl);
  747         return err;
  748 }
  749 
  750 /*
  751  * get/set socket options
  752  */
  753 int
  754 hci_ctloutput(int req, struct socket *so, struct sockopt *sopt)
  755 {
  756         struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
  757         int optval, err = 0;
  758 
  759         DPRINTFN(2, "req %s\n", prcorequests[req]);
  760 
  761         if (pcb == NULL)
  762                 return EINVAL;
  763 
  764         if (sopt->sopt_level != BTPROTO_HCI)
  765                 return ENOPROTOOPT;
  766 
  767         switch(req) {
  768         case PRCO_GETOPT:
  769                 switch (sopt->sopt_name) {
  770                 case SO_HCI_EVT_FILTER:
  771                         err = sockopt_set(sopt, &pcb->hp_efilter,
  772                             sizeof(struct hci_filter));
  773 
  774                         break;
  775 
  776                 case SO_HCI_PKT_FILTER:
  777                         err = sockopt_set(sopt, &pcb->hp_pfilter,
  778                             sizeof(struct hci_filter));
  779 
  780                         break;
  781 
  782                 case SO_HCI_DIRECTION:
  783                         err = sockopt_setint(sopt,
  784                             (pcb->hp_flags & HCI_DIRECTION ? 1 : 0));
  785 
  786                         break;
  787 
  788                 default:
  789                         err = ENOPROTOOPT;
  790                         break;
  791                 }
  792                 break;
  793 
  794         case PRCO_SETOPT:
  795                 switch (sopt->sopt_name) {
  796                 case SO_HCI_EVT_FILTER: /* set event filter */
  797                         err = sockopt_get(sopt, &pcb->hp_efilter,
  798                             sizeof(pcb->hp_efilter));
  799 
  800                         break;
  801 
  802                 case SO_HCI_PKT_FILTER: /* set packet filter */
  803                         err = sockopt_get(sopt, &pcb->hp_pfilter,
  804                             sizeof(pcb->hp_pfilter));
  805 
  806                         break;
  807 
  808                 case SO_HCI_DIRECTION:  /* request direction ctl messages */
  809                         err = sockopt_getint(sopt, &optval);
  810                         if (err)
  811                                 break;
  812 
  813                         if (optval)
  814                                 pcb->hp_flags |= HCI_DIRECTION;
  815                         else
  816                                 pcb->hp_flags &= ~HCI_DIRECTION;
  817                         break;
  818 
  819                 default:
  820                         err = ENOPROTOOPT;
  821                         break;
  822                 }
  823                 break;
  824 
  825         default:
  826                 err = ENOPROTOOPT;
  827                 break;
  828         }
  829 
  830         return err;
  831 }
  832 
  833 /*
  834  * HCI mbuf tap routine
  835  *
  836  * copy packets to any raw HCI sockets that wish (and are
  837  * permitted) to see them
  838  */
  839 void
  840 hci_mtap(struct mbuf *m, struct hci_unit *unit)
  841 {
  842         struct hci_pcb *pcb;
  843         struct mbuf *m0, *ctlmsg, **ctl;
  844         struct sockaddr_bt sa;
  845         uint8_t type;
  846         uint8_t event;
  847         uint16_t opcode;
  848 
  849         KASSERT(m->m_len >= sizeof(type));
  850 
  851         type = *mtod(m, uint8_t *);
  852 
  853         memset(&sa, 0, sizeof(sa));
  854         sa.bt_len = sizeof(struct sockaddr_bt);
  855         sa.bt_family = AF_BLUETOOTH;
  856         bdaddr_copy(&sa.bt_bdaddr, &unit->hci_bdaddr);
  857 
  858         LIST_FOREACH(pcb, &hci_pcb, hp_next) {
  859                 /*
  860                  * filter according to source address
  861                  */
  862                 if ((pcb->hp_flags & HCI_PROMISCUOUS) == 0
  863                     && bdaddr_same(&pcb->hp_laddr, &sa.bt_bdaddr) == 0)
  864                         continue;
  865 
  866                 /*
  867                  * filter according to packet type filter
  868                  */
  869                 if (hci_filter_test(type, &pcb->hp_pfilter) == 0)
  870                         continue;
  871 
  872                 /*
  873                  * filter according to event/security filters
  874                  */
  875                 switch(type) {
  876                 case HCI_EVENT_PKT:
  877                         KASSERT(m->m_len >= sizeof(hci_event_hdr_t));
  878 
  879                         event = mtod(m, hci_event_hdr_t *)->event;
  880 
  881                         if (hci_filter_test(event, &pcb->hp_efilter) == 0)
  882                                 continue;
  883 
  884                         if ((pcb->hp_flags & HCI_PRIVILEGED) == 0
  885                             && hci_security_check_event(event) == -1)
  886                                 continue;
  887                         break;
  888 
  889                 case HCI_CMD_PKT:
  890                         KASSERT(m->m_len >= sizeof(hci_cmd_hdr_t));
  891 
  892                         opcode = le16toh(mtod(m, hci_cmd_hdr_t *)->opcode);
  893 
  894                         if ((pcb->hp_flags & HCI_PRIVILEGED) == 0
  895                             && hci_security_check_opcode(NULL, opcode) == -1)
  896                                 continue;
  897                         break;
  898 
  899                 case HCI_ACL_DATA_PKT:
  900                 case HCI_SCO_DATA_PKT:
  901                 default:
  902                         if ((pcb->hp_flags & HCI_PRIVILEGED) == 0)
  903                                 continue;
  904 
  905                         break;
  906                 }
  907 
  908                 /*
  909                  * create control messages
  910                  */
  911                 ctlmsg = NULL;
  912                 ctl = &ctlmsg;
  913                 if (pcb->hp_flags & HCI_DIRECTION) {
  914                         int dir = m->m_flags & M_LINK0 ? 1 : 0;
  915 
  916                         *ctl = sbcreatecontrol(&dir, sizeof(dir),
  917                             SCM_HCI_DIRECTION, BTPROTO_HCI);
  918 
  919                         if (*ctl != NULL)
  920                                 ctl = &((*ctl)->m_next);
  921                 }
  922 
  923                 /*
  924                  * copy to socket
  925                  */
  926                 m0 = m_copypacket(m, M_DONTWAIT);
  927                 if (m0 && sbappendaddr(&pcb->hp_socket->so_rcv,
  928                                 (struct sockaddr *)&sa, m0, ctlmsg)) {
  929                         sorwakeup(pcb->hp_socket);
  930                 } else {
  931                         m_freem(ctlmsg);
  932                         m_freem(m0);
  933                 }
  934         }
  935 }

Cache object: 5171705d6be3836040893a3ace635ed9


[ 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.