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

Cache object: 8e32129657677503b7100c366470e2b5


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