root/netbt/hci_ioctl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hci_dump
  2. hci_ioctl

    1 /*      $OpenBSD: hci_ioctl.c,v 1.1 2007/06/01 02:46:11 uwe Exp $       */
    2 /*      $NetBSD: hci_ioctl.c,v 1.5 2007/01/04 19:07:03 elad Exp $       */
    3 
    4 /*-
    5  * Copyright (c) 2005 Iain Hibbert.
    6  * Copyright (c) 2006 Itronix Inc.
    7  * All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. The name of Itronix Inc. may not be used to endorse
   18  *    or promote products derived from this software without specific
   19  *    prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
   25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   28  * ON ANY THEORY OF LIABILITY, WHETHER IN
   29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   31  * POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 
   36 #include <sys/param.h>
   37 #include <sys/domain.h>
   38 #include <sys/ioctl.h>
   39 #include <sys/kernel.h>
   40 #include <sys/mbuf.h>
   41 #include <sys/proc.h>
   42 #include <sys/systm.h>
   43 
   44 #include <netbt/bluetooth.h>
   45 #include <netbt/hci.h>
   46 #include <netbt/l2cap.h>
   47 #include <netbt/rfcomm.h>
   48 
   49 #ifdef BLUETOOTH_DEBUG
   50 #define BDADDR(bd)      (bd).b[5], (bd).b[4], (bd).b[3],        \
   51                         (bd).b[2], (bd).b[1], (bd).b[0]
   52 
   53 static void
   54 hci_dump(void)
   55 {
   56         struct hci_unit *unit;
   57         struct hci_link *link;
   58         struct l2cap_channel *chan;
   59         struct rfcomm_session *rs;
   60         struct rfcomm_dlc *dlc;
   61 
   62         printf("HCI:\n");
   63         TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
   64                 printf("UNIT %s: flags 0x%4.4x, "
   65                         "num_cmd=%d, num_acl=%d, num_sco=%d\n",
   66                         unit->hci_devname, unit->hci_flags,
   67                         unit->hci_num_cmd_pkts,
   68                         unit->hci_num_acl_pkts,
   69                         unit->hci_num_sco_pkts);
   70                 TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
   71                         printf("+HANDLE #%d: %s "
   72                             "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
   73                             "state %d, refcnt %d\n",
   74                             link->hl_handle,
   75                             (link->hl_type == HCI_LINK_ACL ? "ACL":"SCO"),
   76                             BDADDR(link->hl_bdaddr),
   77                             link->hl_state, link->hl_refcnt);
   78                 }
   79         }
   80 
   81         printf("L2CAP:\n");
   82         LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) {
   83                 printf("CID #%d state %d, psm=0x%4.4x, "
   84                     "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
   85                     "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
   86                     chan->lc_lcid, chan->lc_state, chan->lc_raddr.bt_psm,
   87                     BDADDR(chan->lc_laddr.bt_bdaddr),
   88                     BDADDR(chan->lc_raddr.bt_bdaddr));
   89         }
   90 
   91         LIST_FOREACH(chan, &l2cap_listen_list, lc_ncid) {
   92                 printf("LISTEN psm=0x%4.4x, "
   93                     "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
   94                     chan->lc_laddr.bt_psm,
   95                     BDADDR(chan->lc_laddr.bt_bdaddr));
   96         }
   97 
   98         printf("RFCOMM:\n");
   99         LIST_FOREACH(rs, &rfcomm_session_active, rs_next) {
  100                 chan = rs->rs_l2cap;
  101                 printf("SESSION: state=%d, flags=0x%4.4x, psm 0x%4.4x "
  102                     "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
  103                     "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
  104                     rs->rs_state, rs->rs_flags, chan->lc_raddr.bt_psm,
  105                     BDADDR(chan->lc_laddr.bt_bdaddr),
  106                     BDADDR(chan->lc_raddr.bt_bdaddr));
  107                 LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
  108                         printf("+DLC channel=%d, dlci=%d, "
  109                             "state=%d, flags=0x%4.4x, rxcred=%d, rxsize=%ld, "
  110                             "txcred=%d, pending=%d, txqlen=%d\n",
  111                             dlc->rd_raddr.bt_channel, dlc->rd_dlci,
  112                             dlc->rd_state, dlc->rd_flags,
  113                             dlc->rd_rxcred, (unsigned long)dlc->rd_rxsize,
  114                             dlc->rd_txcred, dlc->rd_pending,
  115                             (dlc->rd_txbuf ? dlc->rd_txbuf->m_pkthdr.len : 0));
  116                 }
  117         }
  118 
  119         LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
  120                 chan = rs->rs_l2cap;
  121                 printf("LISTEN: psm 0x%4.4x, "
  122                     "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
  123                     chan->lc_laddr.bt_psm,
  124                     BDADDR(chan->lc_laddr.bt_bdaddr));
  125                 LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next)
  126                         printf("+DLC channel=%d\n", dlc->rd_laddr.bt_channel);
  127         }
  128 }
  129 
  130 #undef BDADDR
  131 #endif
  132 
  133 int
  134 hci_ioctl(unsigned long cmd, void *data, struct proc *p)
  135 {
  136         struct btreq *btr = data;
  137         struct hci_unit *unit;
  138         int s, err = 0;
  139 
  140         DPRINTFN(1, "cmd %#lx\n", cmd);
  141 
  142         switch(cmd) {
  143 #ifdef BLUETOOTH_DEBUG
  144         case SIOCBTDUMP:
  145                 hci_dump();
  146                 return 0;
  147 #endif
  148         /*
  149          * Get unit info based on address rather than name
  150          */
  151         case SIOCGBTINFOA:
  152                 unit = hci_unit_lookup(&btr->btr_bdaddr);
  153                 if (unit == NULL)
  154                         return ENXIO;
  155 
  156                 break;
  157 
  158         /*
  159          * The remaining ioctl's all use the same btreq structure and
  160          * index on the name of the device, so we look that up first.
  161          */
  162         case SIOCNBTINFO:
  163                 /* empty name means give the first unit */
  164                 if (btr->btr_name[0] == '\0') {
  165                         unit = NULL;
  166                         break;
  167                 }
  168 
  169                 /* else fall through and look it up */
  170         case SIOCGBTINFO:
  171         case SIOCSBTFLAGS:
  172         case SIOCSBTPOLICY:
  173         case SIOCSBTPTYPE:
  174         case SIOCGBTSTATS:
  175         case SIOCZBTSTATS:
  176         case SIOCSBTSCOMTU:
  177                 TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
  178                         if (strncmp(unit->hci_devname, btr->btr_name,
  179                             HCI_DEVNAME_SIZE) == 0)
  180                                 break;
  181                 }
  182 
  183                 if (unit == NULL)
  184                         return ENXIO;
  185 
  186                 break;
  187 
  188         default:        /* not one of mine */
  189                 return EPASSTHROUGH;
  190         }
  191 
  192         switch(cmd) {
  193         case SIOCNBTINFO:       /* get next info */
  194                 if (unit)
  195                         unit = TAILQ_NEXT(unit, hci_next);
  196                 else
  197                         unit = TAILQ_FIRST(&hci_unit_list);
  198 
  199                 if (unit == NULL) {
  200                         err = ENXIO;
  201                         break;
  202                 }
  203 
  204                 /* and fall through to */
  205         case SIOCGBTINFO:       /* get unit info */
  206         case SIOCGBTINFOA:      /* get info by address */
  207                 memset(btr, 0, sizeof(struct btreq));
  208                 strlcpy(btr->btr_name, unit->hci_devname, HCI_DEVNAME_SIZE);
  209                 bdaddr_copy(&btr->btr_bdaddr, &unit->hci_bdaddr);
  210 
  211                 btr->btr_flags = unit->hci_flags;
  212 
  213                 btr->btr_num_cmd = unit->hci_num_cmd_pkts;
  214                 btr->btr_num_acl = unit->hci_num_acl_pkts;
  215                 btr->btr_num_sco = unit->hci_num_sco_pkts;
  216                 btr->btr_acl_mtu = unit->hci_max_acl_size;
  217                 btr->btr_sco_mtu = unit->hci_max_sco_size;
  218 
  219                 btr->btr_packet_type = unit->hci_packet_type;
  220                 btr->btr_link_policy = unit->hci_link_policy;
  221                 break;
  222 
  223         case SIOCSBTFLAGS:      /* set unit flags (privileged) */
  224                 err = suser(p, 0);
  225                 if (err)
  226                         break;
  227 
  228                 if ((unit->hci_flags & BTF_UP)
  229                     && (btr->btr_flags & BTF_UP) == 0) {
  230                         hci_disable(unit);
  231                         unit->hci_flags &= ~BTF_UP;
  232                 }
  233 
  234                 s = splraiseipl(unit->hci_ipl);
  235                 unit->hci_flags |= (btr->btr_flags & BTF_INIT);
  236                 splx(s);
  237 
  238                 if ((unit->hci_flags & BTF_UP) == 0
  239                     && (btr->btr_flags & BTF_UP)) {
  240                         err = hci_enable(unit);
  241                         if (err)
  242                                 break;
  243 
  244                         s = splraiseipl(unit->hci_ipl);
  245                         unit->hci_flags |= BTF_UP;
  246                         splx(s);
  247                 }
  248 
  249                 btr->btr_flags = unit->hci_flags;
  250                 break;
  251 
  252         case SIOCSBTPOLICY:     /* set unit link policy (privileged) */
  253                 err = suser(p, 0);
  254                 if (err)
  255                         break;
  256 
  257                 unit->hci_link_policy = btr->btr_link_policy;
  258                 unit->hci_link_policy &= unit->hci_lmp_mask;
  259                 btr->btr_link_policy = unit->hci_link_policy;
  260                 break;
  261 
  262         case SIOCSBTPTYPE:      /* set unit packet types (privileged) */
  263                 err = suser(p, 0);
  264                 if (err)
  265                         break;
  266 
  267                 unit->hci_packet_type = btr->btr_packet_type;
  268                 unit->hci_packet_type &= unit->hci_acl_mask;
  269                 btr->btr_packet_type = unit->hci_packet_type;
  270                 break;
  271 
  272         case SIOCGBTSTATS:      /* get unit statistics */
  273                 s = splraiseipl(unit->hci_ipl);
  274                 memcpy(&btr->btr_stats, &unit->hci_stats,
  275                         sizeof(struct bt_stats));
  276                 splx(s);
  277                 break;
  278 
  279         case SIOCZBTSTATS:      /* get & reset unit statistics */
  280                 err = suser(p, 0);
  281                 if (err)
  282                         break;
  283 
  284                 s = splraiseipl(unit->hci_ipl);
  285                 memcpy(&btr->btr_stats, &unit->hci_stats,
  286                         sizeof(struct bt_stats));
  287                 memset(&unit->hci_stats, 0, sizeof(struct bt_stats));
  288                 splx(s);
  289 
  290                 break;
  291 
  292         case SIOCSBTSCOMTU:     /* set sco_mtu value for unit */
  293                 /*
  294                  * This is a temporary ioctl and may not be supported
  295                  * in the future. The need is that if SCO packets are
  296                  * sent to USB bluetooth controllers that are not an
  297                  * integer number of frame sizes, the USB bus locks up.
  298                  */
  299                 err = suser(p, 0);
  300                 if (err)
  301                         break;
  302 
  303                 unit->hci_max_sco_size = btr->btr_sco_mtu;
  304                 break;
  305 
  306         default:
  307                 err = EFAULT;
  308                 break;
  309         }
  310 
  311         return err;
  312 }

/* [<][>][^][v][top][bottom][index][help] */