blob: 219df5ca811ddc8a0b4e0d382912d22eee4aebf3 [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
352 msg->msg_namelen = 0;
353
354 BT_DBG("sk %p size %zu", sk, size);
355
356 lock_sock(sk);
357
358 target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
359 timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
360
361 do {
362 struct sk_buff *skb;
363 int chunk;
364
365 skb = skb_dequeue(&sk->sk_receive_queue);
366 if (!skb) {
367 if (copied >= target)
368 break;
369
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200370 err = sock_error(sk);
371 if (err)
Mat Martineau796c86e2010-09-08 10:05:27 -0700372 break;
373 if (sk->sk_shutdown & RCV_SHUTDOWN)
374 break;
375
376 err = -EAGAIN;
377 if (!timeo)
378 break;
379
380 timeo = bt_sock_data_wait(sk, timeo);
381
382 if (signal_pending(current)) {
383 err = sock_intr_errno(timeo);
384 goto out;
385 }
386 continue;
387 }
388
389 chunk = min_t(unsigned int, skb->len, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, chunk)) {
Mat Martineau796c86e2010-09-08 10:05:27 -0700391 skb_queue_head(&sk->sk_receive_queue, skb);
392 if (!copied)
393 copied = -EFAULT;
394 break;
395 }
396 copied += chunk;
397 size -= chunk;
398
399 sock_recv_ts_and_drops(msg, sk, skb);
400
401 if (!(flags & MSG_PEEK)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700402 int skb_len = skb_headlen(skb);
403
404 if (chunk <= skb_len) {
405 __skb_pull(skb, chunk);
406 } else {
407 struct sk_buff *frag;
408
409 __skb_pull(skb, skb_len);
410 chunk -= skb_len;
411
412 skb_walk_frags(skb, frag) {
413 if (chunk <= frag->len) {
414 /* Pulling partial data */
415 skb->len -= chunk;
416 skb->data_len -= chunk;
417 __skb_pull(frag, chunk);
418 break;
419 } else if (frag->len) {
420 /* Pulling all frag data */
421 chunk -= frag->len;
422 skb->len -= frag->len;
423 skb->data_len -= frag->len;
424 __skb_pull(frag, frag->len);
425 }
426 }
427 }
428
Mat Martineau796c86e2010-09-08 10:05:27 -0700429 if (skb->len) {
430 skb_queue_head(&sk->sk_receive_queue, skb);
431 break;
432 }
433 kfree_skb(skb);
434
435 } else {
436 /* put message back and return */
437 skb_queue_head(&sk->sk_receive_queue, skb);
438 break;
439 }
440 } while (size);
441
442out:
443 release_sock(sk);
444 return copied ? : err;
445}
446EXPORT_SYMBOL(bt_sock_stream_recvmsg);
447
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448static inline unsigned int bt_accept_poll(struct sock *parent)
449{
450 struct list_head *p, *n;
451 struct sock *sk;
452
453 list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
454 sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
Marcel Holtmannd5f2d2b2009-02-16 02:57:30 +0100455 if (sk->sk_state == BT_CONNECTED ||
456 (bt_sk(parent)->defer_setup &&
457 sk->sk_state == BT_CONNECT2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 return POLLIN | POLLRDNORM;
459 }
460
461 return 0;
462}
463
Gustavo F. Padovan8ffd8782011-02-17 19:24:05 -0300464unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465{
466 struct sock *sk = sock->sk;
467 unsigned int mask = 0;
468
469 BT_DBG("sock %p, sk %p", sock, sk);
470
Eric Dumazetaa395142010-04-20 13:03:51 +0000471 poll_wait(file, sk_sleep(sk), wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
473 if (sk->sk_state == BT_LISTEN)
474 return bt_accept_poll(sk);
475
476 if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
477 mask |= POLLERR;
478
Davide Libenzif348d702006-03-25 03:07:39 -0800479 if (sk->sk_shutdown & RCV_SHUTDOWN)
Eric Dumazetdb409802010-09-06 11:13:50 +0000480 mask |= POLLRDHUP | POLLIN | POLLRDNORM;
Davide Libenzif348d702006-03-25 03:07:39 -0800481
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 if (sk->sk_shutdown == SHUTDOWN_MASK)
483 mask |= POLLHUP;
484
Eric Dumazetdb409802010-09-06 11:13:50 +0000485 if (!skb_queue_empty(&sk->sk_receive_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 mask |= POLLIN | POLLRDNORM;
487
488 if (sk->sk_state == BT_CLOSED)
489 mask |= POLLHUP;
490
491 if (sk->sk_state == BT_CONNECT ||
492 sk->sk_state == BT_CONNECT2 ||
493 sk->sk_state == BT_CONFIG)
494 return mask;
495
496 if (sock_writeable(sk))
497 mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
498 else
499 set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
500
501 return mask;
502}
503EXPORT_SYMBOL(bt_sock_poll);
504
Marcel Holtmann3241ad82008-07-14 20:13:50 +0200505int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
506{
507 struct sock *sk = sock->sk;
Marcel Holtmann43cbeee2008-07-14 20:13:51 +0200508 struct sk_buff *skb;
509 long amount;
Marcel Holtmann3241ad82008-07-14 20:13:50 +0200510 int err;
511
512 BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg);
513
514 switch (cmd) {
Marcel Holtmann43cbeee2008-07-14 20:13:51 +0200515 case TIOCOUTQ:
516 if (sk->sk_state == BT_LISTEN)
517 return -EINVAL;
518
Eric Dumazet31e6d362009-06-17 19:05:41 -0700519 amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
Marcel Holtmann43cbeee2008-07-14 20:13:51 +0200520 if (amount < 0)
521 amount = 0;
522 err = put_user(amount, (int __user *) arg);
523 break;
524
525 case TIOCINQ:
526 if (sk->sk_state == BT_LISTEN)
527 return -EINVAL;
528
529 lock_sock(sk);
530 skb = skb_peek(&sk->sk_receive_queue);
531 amount = skb ? skb->len : 0;
532 release_sock(sk);
533 err = put_user(amount, (int __user *) arg);
534 break;
535
Marcel Holtmann3241ad82008-07-14 20:13:50 +0200536 case SIOCGSTAMP:
537 err = sock_get_timestamp(sk, (struct timeval __user *) arg);
538 break;
539
540 case SIOCGSTAMPNS:
541 err = sock_get_timestampns(sk, (struct timespec __user *) arg);
542 break;
543
544 default:
545 err = -ENOIOCTLCMD;
546 break;
547 }
548
549 return err;
550}
551EXPORT_SYMBOL(bt_sock_ioctl);
552
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
554{
555 DECLARE_WAITQUEUE(wait, current);
556 int err = 0;
557
558 BT_DBG("sk %p", sk);
559
Eric Dumazetaa395142010-04-20 13:03:51 +0000560 add_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 while (sk->sk_state != state) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700562 set_current_state(TASK_INTERRUPTIBLE);
563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 if (!timeo) {
Marcel Holtmannb4c612a2006-09-23 09:54:38 +0200565 err = -EINPROGRESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 break;
567 }
568
569 if (signal_pending(current)) {
570 err = sock_intr_errno(timeo);
571 break;
572 }
573
574 release_sock(sk);
575 timeo = schedule_timeout(timeo);
576 lock_sock(sk);
577
Benjamin LaHaisec1cbe4b2005-12-13 23:22:19 -0800578 err = sock_error(sk);
579 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700582 set_current_state(TASK_RUNNING);
Eric Dumazetaa395142010-04-20 13:03:51 +0000583 remove_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 return err;
585}
586EXPORT_SYMBOL(bt_sock_wait_state);
587
588static struct net_proto_family bt_sock_family_ops = {
589 .owner = THIS_MODULE,
590 .family = PF_BLUETOOTH,
591 .create = bt_sock_create,
592};
593
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594static int __init bt_init(void)
595{
Marcel Holtmann27d35282006-07-03 10:02:37 +0200596 int err;
597
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 BT_INFO("Core ver %s", VERSION);
599
Marcel Holtmann27d35282006-07-03 10:02:37 +0200600 err = bt_sysfs_init();
601 if (err < 0)
602 return err;
603
604 err = sock_register(&bt_sock_family_ops);
605 if (err < 0) {
606 bt_sysfs_cleanup();
607 return err;
608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
610 BT_INFO("HCI device and connection manager initialized");
611
Gustavo F. Padovan64274512011-02-07 20:08:52 -0200612 err = hci_sock_init();
613 if (err < 0)
614 goto error;
615
616 err = l2cap_init();
Anand Gadiyar0ed54da2011-02-22 12:43:26 +0530617 if (err < 0)
Gustavo F. Padovan64274512011-02-07 20:08:52 -0200618 goto sock_err;
Gustavo F. Padovan64274512011-02-07 20:08:52 -0200619
620 err = sco_init();
621 if (err < 0) {
622 l2cap_exit();
623 goto sock_err;
624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
626 return 0;
Gustavo F. Padovan64274512011-02-07 20:08:52 -0200627
628sock_err:
629 hci_sock_cleanup();
630
631error:
632 sock_unregister(PF_BLUETOOTH);
633 bt_sysfs_cleanup();
634
635 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636}
637
638static void __exit bt_exit(void)
639{
Gustavo F. Padovan64274512011-02-07 20:08:52 -0200640
641 sco_exit();
642
643 l2cap_exit();
644
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 hci_sock_cleanup();
646
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 sock_unregister(PF_BLUETOOTH);
Marcel Holtmann27d35282006-07-03 10:02:37 +0200648
649 bt_sysfs_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650}
651
652subsys_initcall(bt_init);
653module_exit(bt_exit);
654
Marcel Holtmann63fbd242008-08-18 13:23:53 +0200655MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656MODULE_DESCRIPTION("Bluetooth Core ver " VERSION);
657MODULE_VERSION(VERSION);
658MODULE_LICENSE("GPL");
659MODULE_ALIAS_NETPROTO(PF_BLUETOOTH);