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