blob: 7f260fc431c11e2791433881920406b189a9f5a7 [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2000-2001 Qualcomm Incorporated
4
5 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090015 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090020 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth address family and sockets. */
26
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/module.h>
28
29#include <linux/types.h>
30#include <linux/list.h>
31#include <linux/errno.h>
32#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/skbuff.h>
35#include <linux/init.h>
36#include <linux/poll.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <net/sock.h>
Marcel Holtmann3241ad82008-07-14 20:13:50 +020038#include <asm/ioctls.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <linux/kmod.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41#include <net/bluetooth/bluetooth.h>
42
Robert Love8affb4e2008-10-15 15:35:44 -040043#ifdef CONFIG_ANDROID_PARANOID_NETWORK
44#include <linux/android_aid.h>
45#endif
46
47#ifndef CONFIG_BT_SOCK_DEBUG
48#undef BT_DBG
49#define BT_DBG(D...)
50#endif
51
Gustavo F. Padovan64274512011-02-07 20:08:52 -020052#define VERSION "2.16"
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54/* Bluetooth sockets */
55#define BT_MAX_PROTO 8
Stephen Hemmingerec1b4cf2009-10-05 05:58:39 +000056static const struct net_proto_family *bt_proto[BT_MAX_PROTO];
Marcel Holtmanndb7aa1c2008-11-30 12:17:19 +010057static DEFINE_RWLOCK(bt_proto_lock);
Dave Young68845cb2008-04-01 23:58:35 -070058
Dave Young68845cb2008-04-01 23:58:35 -070059static struct lock_class_key bt_lock_key[BT_MAX_PROTO];
Jan Engelhardt36cbd3d2009-08-05 10:42:58 -070060static const char *const bt_key_strings[BT_MAX_PROTO] = {
Dave Young68845cb2008-04-01 23:58:35 -070061 "sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP",
62 "sk_lock-AF_BLUETOOTH-BTPROTO_HCI",
63 "sk_lock-AF_BLUETOOTH-BTPROTO_SCO",
64 "sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM",
65 "sk_lock-AF_BLUETOOTH-BTPROTO_BNEP",
66 "sk_lock-AF_BLUETOOTH-BTPROTO_CMTP",
67 "sk_lock-AF_BLUETOOTH-BTPROTO_HIDP",
68 "sk_lock-AF_BLUETOOTH-BTPROTO_AVDTP",
69};
70
Marcel Holtmanndb7aa1c2008-11-30 12:17:19 +010071static struct lock_class_key bt_slock_key[BT_MAX_PROTO];
Jan Engelhardt36cbd3d2009-08-05 10:42:58 -070072static const char *const bt_slock_key_strings[BT_MAX_PROTO] = {
Dave Young68845cb2008-04-01 23:58:35 -070073 "slock-AF_BLUETOOTH-BTPROTO_L2CAP",
74 "slock-AF_BLUETOOTH-BTPROTO_HCI",
75 "slock-AF_BLUETOOTH-BTPROTO_SCO",
76 "slock-AF_BLUETOOTH-BTPROTO_RFCOMM",
77 "slock-AF_BLUETOOTH-BTPROTO_BNEP",
78 "slock-AF_BLUETOOTH-BTPROTO_CMTP",
79 "slock-AF_BLUETOOTH-BTPROTO_HIDP",
80 "slock-AF_BLUETOOTH-BTPROTO_AVDTP",
81};
Marcel Holtmanndb7aa1c2008-11-30 12:17:19 +010082
83static inline void bt_sock_reclassify_lock(struct socket *sock, int proto)
84{
85 struct sock *sk = sock->sk;
86
87 if (!sk)
88 return;
89
90 BUG_ON(sock_owned_by_user(sk));
91
92 sock_lock_init_class_and_name(sk,
93 bt_slock_key_strings[proto], &bt_slock_key[proto],
94 bt_key_strings[proto], &bt_lock_key[proto]);
95}
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Stephen Hemmingerec1b4cf2009-10-05 05:58:39 +000097int bt_sock_register(int proto, const struct net_proto_family *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098{
Marcel Holtmann74da6262006-10-15 17:31:14 +020099 int err = 0;
100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 if (proto < 0 || proto >= BT_MAX_PROTO)
102 return -EINVAL;
103
Marcel Holtmann74da6262006-10-15 17:31:14 +0200104 write_lock(&bt_proto_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Marcel Holtmann74da6262006-10-15 17:31:14 +0200106 if (bt_proto[proto])
107 err = -EEXIST;
108 else
109 bt_proto[proto] = ops;
110
111 write_unlock(&bt_proto_lock);
112
113 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114}
115EXPORT_SYMBOL(bt_sock_register);
116
117int bt_sock_unregister(int proto)
118{
Marcel Holtmann74da6262006-10-15 17:31:14 +0200119 int err = 0;
120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 if (proto < 0 || proto >= BT_MAX_PROTO)
122 return -EINVAL;
123
Marcel Holtmann74da6262006-10-15 17:31:14 +0200124 write_lock(&bt_proto_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
Marcel Holtmann74da6262006-10-15 17:31:14 +0200126 if (!bt_proto[proto])
127 err = -ENOENT;
128 else
129 bt_proto[proto] = NULL;
130
131 write_unlock(&bt_proto_lock);
132
133 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134}
135EXPORT_SYMBOL(bt_sock_unregister);
136
Robert Love8affb4e2008-10-15 15:35:44 -0400137#ifdef CONFIG_ANDROID_PARANOID_NETWORK
138static inline int current_has_bt_admin(void)
139{
140 return (!current_euid() || in_egroup_p(AID_NET_BT_ADMIN));
141}
142
143static inline int current_has_bt(void)
144{
145 return (current_has_bt_admin() || in_egroup_p(AID_NET_BT));
146}
147# else
148static inline int current_has_bt_admin(void)
149{
150 return 1;
151}
152
153static inline int current_has_bt(void)
154{
155 return 1;
156}
157#endif
158
Eric Paris3f378b62009-11-05 22:18:14 -0800159static int bt_sock_create(struct net *net, struct socket *sock, int proto,
160 int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161{
Marcel Holtmann74da6262006-10-15 17:31:14 +0200162 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
Robert Love8affb4e2008-10-15 15:35:44 -0400164 if (proto == BTPROTO_RFCOMM || proto == BTPROTO_SCO ||
165 proto == BTPROTO_L2CAP) {
166 if (!current_has_bt())
167 return -EPERM;
168 } else if (!current_has_bt_admin())
169 return -EPERM;
170
Eric W. Biederman1b8d7ae2007-10-08 23:24:22 -0700171 if (net != &init_net)
172 return -EAFNOSUPPORT;
173
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 if (proto < 0 || proto >= BT_MAX_PROTO)
175 return -EINVAL;
176
Johannes Berg95a5afc2008-10-16 15:24:51 -0700177 if (!bt_proto[proto])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 request_module("bt-proto-%d", proto);
Marcel Holtmann74da6262006-10-15 17:31:14 +0200179
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 err = -EPROTONOSUPPORT;
Marcel Holtmann74da6262006-10-15 17:31:14 +0200181
182 read_lock(&bt_proto_lock);
183
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) {
Eric Paris3f378b62009-11-05 22:18:14 -0800185 err = bt_proto[proto]->create(net, sock, proto, kern);
Marcel Holtmanndb7aa1c2008-11-30 12:17:19 +0100186 bt_sock_reclassify_lock(sock, proto);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 module_put(bt_proto[proto]->owner);
188 }
Marcel Holtmann74da6262006-10-15 17:31:14 +0200189
190 read_unlock(&bt_proto_lock);
191
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900192 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193}
194
195void bt_sock_link(struct bt_sock_list *l, struct sock *sk)
196{
197 write_lock_bh(&l->lock);
198 sk_add_node(sk, &l->head);
199 write_unlock_bh(&l->lock);
200}
201EXPORT_SYMBOL(bt_sock_link);
202
203void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk)
204{
205 write_lock_bh(&l->lock);
206 sk_del_node_init(sk);
207 write_unlock_bh(&l->lock);
208}
209EXPORT_SYMBOL(bt_sock_unlink);
210
211void bt_accept_enqueue(struct sock *parent, struct sock *sk)
212{
213 BT_DBG("parent %p, sk %p", parent, sk);
214
215 sock_hold(sk);
216 list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q);
217 bt_sk(sk)->parent = parent;
218 parent->sk_ack_backlog++;
219}
220EXPORT_SYMBOL(bt_accept_enqueue);
221
222void bt_accept_unlink(struct sock *sk)
223{
224 BT_DBG("sk %p state %d", sk, sk->sk_state);
225
226 list_del_init(&bt_sk(sk)->accept_q);
227 bt_sk(sk)->parent->sk_ack_backlog--;
228 bt_sk(sk)->parent = NULL;
229 sock_put(sk);
230}
231EXPORT_SYMBOL(bt_accept_unlink);
232
233struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
234{
235 struct list_head *p, *n;
236 struct sock *sk;
237
238 BT_DBG("parent %p", parent);
239
Andrei Emeltchenkod37f50e2011-01-24 10:53:24 +0200240 local_bh_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
242 sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
243
Andrei Emeltchenkod37f50e2011-01-24 10:53:24 +0200244 bh_lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
246 /* FIXME: Is this check still needed */
247 if (sk->sk_state == BT_CLOSED) {
Andrei Emeltchenkod37f50e2011-01-24 10:53:24 +0200248 bh_unlock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 bt_accept_unlink(sk);
250 continue;
251 }
252
Marcel Holtmannc4f912e2009-01-15 21:52:16 +0100253 if (sk->sk_state == BT_CONNECTED || !newsock ||
254 bt_sk(parent)->defer_setup) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 bt_accept_unlink(sk);
256 if (newsock)
257 sock_graft(sk, newsock);
Andrei Emeltchenkod37f50e2011-01-24 10:53:24 +0200258
259 bh_unlock_sock(sk);
260 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 return sk;
262 }
263
Andrei Emeltchenkod37f50e2011-01-24 10:53:24 +0200264 bh_unlock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 }
Andrei Emeltchenkod37f50e2011-01-24 10:53:24 +0200266 local_bh_enable();
267
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 return NULL;
269}
270EXPORT_SYMBOL(bt_accept_dequeue);
271
272int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
Marcel Holtmannc4f912e2009-01-15 21:52:16 +0100273 struct msghdr *msg, size_t len, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274{
275 int noblock = flags & MSG_DONTWAIT;
276 struct sock *sk = sock->sk;
277 struct sk_buff *skb;
278 size_t copied;
279 int err;
280
Marcel Holtmanna418b892008-11-30 12:17:28 +0100281 BT_DBG("sock %p sk %p len %zu", sock, sk, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
283 if (flags & (MSG_OOB))
284 return -EOPNOTSUPP;
285
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200286 skb = skb_recv_datagram(sk, flags, noblock, &err);
287 if (!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 if (sk->sk_shutdown & RCV_SHUTDOWN)
289 return 0;
290 return err;
291 }
292
293 msg->msg_namelen = 0;
294
295 copied = skb->len;
296 if (len < copied) {
297 msg->msg_flags |= MSG_TRUNC;
298 copied = len;
299 }
300
Arnaldo Carvalho de Melobadff6d2007-03-13 13:06:52 -0300301 skb_reset_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
Marcel Holtmann3241ad82008-07-14 20:13:50 +0200303 if (err == 0)
Neil Horman3b885782009-10-12 13:26:31 -0700304 sock_recv_ts_and_drops(msg, sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
306 skb_free_datagram(sk, skb);
307
308 return err ? : copied;
309}
310EXPORT_SYMBOL(bt_sock_recvmsg);
311
Mat Martineau796c86e2010-09-08 10:05:27 -0700312static long bt_sock_data_wait(struct sock *sk, long timeo)
313{
314 DECLARE_WAITQUEUE(wait, current);
315
316 add_wait_queue(sk_sleep(sk), &wait);
317 for (;;) {
318 set_current_state(TASK_INTERRUPTIBLE);
319
320 if (!skb_queue_empty(&sk->sk_receive_queue))
321 break;
322
323 if (sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN))
324 break;
325
326 if (signal_pending(current) || !timeo)
327 break;
328
329 set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
330 release_sock(sk);
331 timeo = schedule_timeout(timeo);
332 lock_sock(sk);
333 clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
334 }
335
336 __set_current_state(TASK_RUNNING);
337 remove_wait_queue(sk_sleep(sk), &wait);
338 return timeo;
339}
340
341int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
342 struct msghdr *msg, size_t size, int flags)
343{
344 struct sock *sk = sock->sk;
345 int err = 0;
346 size_t target, copied = 0;
347 long timeo;
348
349 if (flags & MSG_OOB)
350 return -EOPNOTSUPP;
351
Mat Martineau796c86e2010-09-08 10:05:27 -0700352 BT_DBG("sk %p size %zu", sk, size);
353
354 lock_sock(sk);
355
356 target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
357 timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
358
359 do {
360 struct sk_buff *skb;
361 int chunk;
362
363 skb = skb_dequeue(&sk->sk_receive_queue);
364 if (!skb) {
365 if (copied >= target)
366 break;
367
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200368 err = sock_error(sk);
369 if (err)
Mat Martineau796c86e2010-09-08 10:05:27 -0700370 break;
371 if (sk->sk_shutdown & RCV_SHUTDOWN)
372 break;
373
374 err = -EAGAIN;
375 if (!timeo)
376 break;
377
378 timeo = bt_sock_data_wait(sk, timeo);
379
380 if (signal_pending(current)) {
381 err = sock_intr_errno(timeo);
382 goto out;
383 }
384 continue;
385 }
386
387 chunk = min_t(unsigned int, skb->len, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, chunk)) {
Mat Martineau796c86e2010-09-08 10:05:27 -0700389 skb_queue_head(&sk->sk_receive_queue, skb);
390 if (!copied)
391 copied = -EFAULT;
392 break;
393 }
394 copied += chunk;
395 size -= chunk;
396
397 sock_recv_ts_and_drops(msg, sk, skb);
398
399 if (!(flags & MSG_PEEK)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700400 int skb_len = skb_headlen(skb);
401
402 if (chunk <= skb_len) {
403 __skb_pull(skb, chunk);
404 } else {
405 struct sk_buff *frag;
406
407 __skb_pull(skb, skb_len);
408 chunk -= skb_len;
409
410 skb_walk_frags(skb, frag) {
411 if (chunk <= frag->len) {
412 /* Pulling partial data */
413 skb->len -= chunk;
414 skb->data_len -= chunk;
415 __skb_pull(frag, chunk);
416 break;
417 } else if (frag->len) {
418 /* Pulling all frag data */
419 chunk -= frag->len;
420 skb->len -= frag->len;
421 skb->data_len -= frag->len;
422 __skb_pull(frag, frag->len);
423 }
424 }
425 }
426
Mat Martineau796c86e2010-09-08 10:05:27 -0700427 if (skb->len) {
428 skb_queue_head(&sk->sk_receive_queue, skb);
429 break;
430 }
431 kfree_skb(skb);
432
433 } else {
434 /* put message back and return */
435 skb_queue_head(&sk->sk_receive_queue, skb);
436 break;
437 }
438 } while (size);
439
440out:
441 release_sock(sk);
442 return copied ? : err;
443}
444EXPORT_SYMBOL(bt_sock_stream_recvmsg);
445
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446static inline unsigned int bt_accept_poll(struct sock *parent)
447{
448 struct list_head *p, *n;
449 struct sock *sk;
450
451 list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
452 sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
Marcel Holtmannd5f2d2b2009-02-16 02:57:30 +0100453 if (sk->sk_state == BT_CONNECTED ||
454 (bt_sk(parent)->defer_setup &&
455 sk->sk_state == BT_CONNECT2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 return POLLIN | POLLRDNORM;
457 }
458
459 return 0;
460}
461
Gustavo F. Padovan8ffd8782011-02-17 19:24:05 -0300462unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463{
464 struct sock *sk = sock->sk;
465 unsigned int mask = 0;
466
467 BT_DBG("sock %p, sk %p", sock, sk);
468
Eric Dumazetaa395142010-04-20 13:03:51 +0000469 poll_wait(file, sk_sleep(sk), wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
471 if (sk->sk_state == BT_LISTEN)
472 return bt_accept_poll(sk);
473
474 if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
475 mask |= POLLERR;
476
Davide Libenzif348d702006-03-25 03:07:39 -0800477 if (sk->sk_shutdown & RCV_SHUTDOWN)
Eric Dumazetdb409802010-09-06 11:13:50 +0000478 mask |= POLLRDHUP | POLLIN | POLLRDNORM;
Davide Libenzif348d702006-03-25 03:07:39 -0800479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 if (sk->sk_shutdown == SHUTDOWN_MASK)
481 mask |= POLLHUP;
482
Eric Dumazetdb409802010-09-06 11:13:50 +0000483 if (!skb_queue_empty(&sk->sk_receive_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 mask |= POLLIN | POLLRDNORM;
485
486 if (sk->sk_state == BT_CLOSED)
487 mask |= POLLHUP;
488
489 if (sk->sk_state == BT_CONNECT ||
490 sk->sk_state == BT_CONNECT2 ||
491 sk->sk_state == BT_CONFIG)
492 return mask;
493
494 if (sock_writeable(sk))
495 mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
496 else
497 set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
498
499 return mask;
500}
501EXPORT_SYMBOL(bt_sock_poll);
502
Marcel Holtmann3241ad82008-07-14 20:13:50 +0200503int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
504{
505 struct sock *sk = sock->sk;
Marcel Holtmann43cbeee2008-07-14 20:13:51 +0200506 struct sk_buff *skb;
507 long amount;
Marcel Holtmann3241ad82008-07-14 20:13:50 +0200508 int err;
509
510 BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg);
511
512 switch (cmd) {
Marcel Holtmann43cbeee2008-07-14 20:13:51 +0200513 case TIOCOUTQ:
514 if (sk->sk_state == BT_LISTEN)
515 return -EINVAL;
516
Eric Dumazet31e6d362009-06-17 19:05:41 -0700517 amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
Marcel Holtmann43cbeee2008-07-14 20:13:51 +0200518 if (amount < 0)
519 amount = 0;
520 err = put_user(amount, (int __user *) arg);
521 break;
522
523 case TIOCINQ:
524 if (sk->sk_state == BT_LISTEN)
525 return -EINVAL;
526
527 lock_sock(sk);
528 skb = skb_peek(&sk->sk_receive_queue);
529 amount = skb ? skb->len : 0;
530 release_sock(sk);
531 err = put_user(amount, (int __user *) arg);
532 break;
533
Marcel Holtmann3241ad82008-07-14 20:13:50 +0200534 case SIOCGSTAMP:
535 err = sock_get_timestamp(sk, (struct timeval __user *) arg);
536 break;
537
538 case SIOCGSTAMPNS:
539 err = sock_get_timestampns(sk, (struct timespec __user *) arg);
540 break;
541
542 default:
543 err = -ENOIOCTLCMD;
544 break;
545 }
546
547 return err;
548}
549EXPORT_SYMBOL(bt_sock_ioctl);
550
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
552{
553 DECLARE_WAITQUEUE(wait, current);
554 int err = 0;
555
556 BT_DBG("sk %p", sk);
557
Eric Dumazetaa395142010-04-20 13:03:51 +0000558 add_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 while (sk->sk_state != state) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700560 set_current_state(TASK_INTERRUPTIBLE);
561
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 if (!timeo) {
Marcel Holtmannb4c612a2006-09-23 09:54:38 +0200563 err = -EINPROGRESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 break;
565 }
566
567 if (signal_pending(current)) {
568 err = sock_intr_errno(timeo);
569 break;
570 }
571
572 release_sock(sk);
573 timeo = schedule_timeout(timeo);
574 lock_sock(sk);
575
Benjamin LaHaisec1cbe4b2005-12-13 23:22:19 -0800576 err = sock_error(sk);
577 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700580 set_current_state(TASK_RUNNING);
Eric Dumazetaa395142010-04-20 13:03:51 +0000581 remove_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 return err;
583}
584EXPORT_SYMBOL(bt_sock_wait_state);
585
586static struct net_proto_family bt_sock_family_ops = {
587 .owner = THIS_MODULE,
588 .family = PF_BLUETOOTH,
589 .create = bt_sock_create,
590};
591
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592static int __init bt_init(void)
593{
Marcel Holtmann27d35282006-07-03 10:02:37 +0200594 int err;
595
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 BT_INFO("Core ver %s", VERSION);
597
Marcel Holtmann27d35282006-07-03 10:02:37 +0200598 err = bt_sysfs_init();
599 if (err < 0)
600 return err;
601
602 err = sock_register(&bt_sock_family_ops);
603 if (err < 0) {
604 bt_sysfs_cleanup();
605 return err;
606 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
608 BT_INFO("HCI device and connection manager initialized");
609
Gustavo F. Padovan64274512011-02-07 20:08:52 -0200610 err = hci_sock_init();
611 if (err < 0)
612 goto error;
613
614 err = l2cap_init();
Anand Gadiyar0ed54da2011-02-22 12:43:26 +0530615 if (err < 0)
Gustavo F. Padovan64274512011-02-07 20:08:52 -0200616 goto sock_err;
Gustavo F. Padovan64274512011-02-07 20:08:52 -0200617
618 err = sco_init();
619 if (err < 0) {
620 l2cap_exit();
621 goto sock_err;
622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
624 return 0;
Gustavo F. Padovan64274512011-02-07 20:08:52 -0200625
626sock_err:
627 hci_sock_cleanup();
628
629error:
630 sock_unregister(PF_BLUETOOTH);
631 bt_sysfs_cleanup();
632
633 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634}
635
636static void __exit bt_exit(void)
637{
Gustavo F. Padovan64274512011-02-07 20:08:52 -0200638
639 sco_exit();
640
641 l2cap_exit();
642
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 hci_sock_cleanup();
644
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 sock_unregister(PF_BLUETOOTH);
Marcel Holtmann27d35282006-07-03 10:02:37 +0200646
647 bt_sysfs_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648}
649
650subsys_initcall(bt_init);
651module_exit(bt_exit);
652
Marcel Holtmann63fbd242008-08-18 13:23:53 +0200653MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654MODULE_DESCRIPTION("Bluetooth Core ver " VERSION);
655MODULE_VERSION(VERSION);
656MODULE_LICENSE("GPL");
657MODULE_ALIAS_NETPROTO(PF_BLUETOOTH);