sys/vfs/msdosfs: Sync with FreeBSD (non functional diffs)
[dragonfly.git] / sys / netbt / hci_ioctl.c
1 /* $OpenBSD: src/sys/netbt/hci_ioctl.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */
2 /* $NetBSD: hci_ioctl.c,v 1.7 2007/11/28 20:16:12 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 #include <sys/param.h>
35 #include <sys/domain.h>
36 #include <sys/kernel.h>
37 #include <sys/mbuf.h>
38 #include <sys/proc.h>
39 #include <sys/priv.h>
40 #include <sys/systm.h>
41 #include <sys/bus.h>
42
43 #include <netbt/bluetooth.h>
44 #include <netbt/hci.h>
45 #include <netbt/l2cap.h>
46 #include <netbt/rfcomm.h>
47
48 #ifdef BLUETOOTH_DEBUG
49 #define BDADDR(bd)      (bd).b[5], (bd).b[4], (bd).b[3],        \
50                         (bd).b[2], (bd).b[1], (bd).b[0]
51
52 static void
53 hci_dump(void)
54 {
55         struct hci_unit *unit;
56         struct hci_link *link;
57         struct l2cap_channel *chan;
58         struct rfcomm_session *rs;
59         struct rfcomm_dlc *dlc;
60
61         kprintf("HCI:\n");
62         TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
63                 kprintf("UNIT %s: flags 0x%4.4x, "
64                         "num_cmd=%d, num_acl=%d, num_sco=%d\n",
65                         device_get_nameunit(unit->hci_dev), unit->hci_flags,
66                         unit->hci_num_cmd_pkts,
67                         unit->hci_num_acl_pkts,
68                         unit->hci_num_sco_pkts);
69                 TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
70                         kprintf("+HANDLE #%d: %s "
71                             "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
72                             "state %d, refcnt %d\n",
73                             link->hl_handle,
74                             (link->hl_type == HCI_LINK_ACL ? "ACL":"SCO"),
75                             BDADDR(link->hl_bdaddr),
76                             link->hl_state, link->hl_refcnt);
77                 }
78         }
79
80         kprintf("L2CAP:\n");
81         LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) {
82                 kprintf("CID #%d state %d, psm=0x%4.4x, "
83                     "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
84                     "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
85                     chan->lc_lcid, chan->lc_state, chan->lc_raddr.bt_psm,
86                     BDADDR(chan->lc_laddr.bt_bdaddr),
87                     BDADDR(chan->lc_raddr.bt_bdaddr));
88         }
89
90         LIST_FOREACH(chan, &l2cap_listen_list, lc_ncid) {
91                 kprintf("LISTEN psm=0x%4.4x, "
92                     "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
93                     chan->lc_laddr.bt_psm,
94                     BDADDR(chan->lc_laddr.bt_bdaddr));
95         }
96
97         kprintf("RFCOMM:\n");
98         LIST_FOREACH(rs, &rfcomm_session_active, rs_next) {
99                 chan = rs->rs_l2cap;
100                 kprintf("SESSION: state=%d, flags=0x%4.4x, psm 0x%4.4x "
101                     "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
102                     "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
103                     rs->rs_state, rs->rs_flags, chan->lc_raddr.bt_psm,
104                     BDADDR(chan->lc_laddr.bt_bdaddr),
105                     BDADDR(chan->lc_raddr.bt_bdaddr));
106                 LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
107                         kprintf("+DLC channel=%d, dlci=%d, "
108                             "state=%d, flags=0x%4.4x, rxcred=%d, rxsize=%ld, "
109                             "txcred=%d, pending=%d, txqlen=%d\n",
110                             dlc->rd_raddr.bt_channel, dlc->rd_dlci,
111                             dlc->rd_state, dlc->rd_flags,
112                             dlc->rd_rxcred, (unsigned long)dlc->rd_rxsize,
113                             dlc->rd_txcred, dlc->rd_pending,
114                             (dlc->rd_txbuf ? dlc->rd_txbuf->m_pkthdr.len : 0));
115                 }
116         }
117
118         LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
119                 chan = rs->rs_l2cap;
120                 kprintf("LISTEN: psm 0x%4.4x, "
121                     "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
122                     chan->lc_laddr.bt_psm,
123                     BDADDR(chan->lc_laddr.bt_bdaddr));
124                 LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next)
125                         kprintf("+DLC channel=%d\n", dlc->rd_laddr.bt_channel);
126         }
127 }
128
129 #undef BDADDR
130 #endif
131
132 int
133 hci_ioctl(unsigned long cmd, void *data, struct proc *p)
134 {
135         struct btreq *btr = data;
136         struct thread *td = curthread; 
137         struct hci_unit *unit;
138         int 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(device_get_nameunit(unit->hci_dev),
179                             btr->btr_name, 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, device_get_nameunit(unit->hci_dev),
209                     HCI_DEVNAME_SIZE);
210                 bdaddr_copy(&btr->btr_bdaddr, &unit->hci_bdaddr);
211
212                 btr->btr_flags = unit->hci_flags;
213
214                 btr->btr_num_cmd = unit->hci_num_cmd_pkts;
215                 btr->btr_num_acl = unit->hci_num_acl_pkts;
216                 btr->btr_num_sco = unit->hci_num_sco_pkts;
217                 btr->btr_acl_mtu = unit->hci_max_acl_size;
218                 btr->btr_sco_mtu = unit->hci_max_sco_size;
219
220                 btr->btr_packet_type = unit->hci_packet_type;
221                 btr->btr_link_policy = unit->hci_link_policy;
222                 break;
223
224         case SIOCSBTFLAGS:      /* set unit flags (privileged) */
225                 err = priv_check(td, PRIV_ROOT);
226                 if (err)
227                         break;
228
229                 if ((unit->hci_flags & BTF_UP)
230                     && (btr->btr_flags & BTF_UP) == 0) {
231                         hci_disable(unit);
232                         unit->hci_flags &= ~BTF_UP;
233                 }
234
235                 unit->hci_flags |= (btr->btr_flags & BTF_INIT);
236
237                 if ((unit->hci_flags & BTF_UP) == 0
238                     && (btr->btr_flags & BTF_UP)) {
239                         err = hci_enable(unit);
240                         if (err)
241                                 break;
242
243                         unit->hci_flags |= BTF_UP;
244                 }
245
246                 btr->btr_flags = unit->hci_flags;
247                 break;
248
249         case SIOCSBTPOLICY:     /* set unit link policy (privileged) */
250                 err = priv_check(td, PRIV_ROOT);
251                 if (err)
252                         break;
253
254                 unit->hci_link_policy = btr->btr_link_policy;
255                 unit->hci_link_policy &= unit->hci_lmp_mask;
256                 btr->btr_link_policy = unit->hci_link_policy;
257                 break;
258
259         case SIOCSBTPTYPE:      /* set unit packet types (privileged) */
260                 err = priv_check(td, PRIV_ROOT);
261                 if (err)
262                         break;
263
264                 unit->hci_packet_type = btr->btr_packet_type;
265                 unit->hci_packet_type &= unit->hci_acl_mask;
266                 btr->btr_packet_type = unit->hci_packet_type;
267                 break;
268
269         case SIOCGBTSTATS:      /* get unit statistics */
270                 (*unit->hci_if->get_stats)(unit->hci_dev, &btr->btr_stats, 0);
271                 break;
272
273         case SIOCZBTSTATS:      /* get & reset unit statistics */
274                 err = priv_check(td, PRIV_ROOT);
275                 if (err)
276                         break;
277
278                 (*unit->hci_if->get_stats)(unit->hci_dev, &btr->btr_stats, 1);
279                 break;
280
281         case SIOCSBTSCOMTU:     /* set sco_mtu value for unit */
282                 /*
283                  * This is a temporary ioctl and may not be supported
284                  * in the future. The need is that if SCO packets are
285                  * sent to USB bluetooth controllers that are not an
286                  * integer number of frame sizes, the USB bus locks up.
287                  */
288                 err = priv_check(td, PRIV_ROOT);
289                 if (err)
290                         break;
291
292                 unit->hci_max_sco_size = btr->btr_sco_mtu;
293                 break;
294
295         default:
296                 err = EFAULT;
297                 break;
298         }
299
300         return err;
301 }