11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds BlueZ - Bluetooth protocol stack for Linux
31da177e4SLinus Torvalds Copyright (C) 2000-2001 Qualcomm Incorporated
41da177e4SLinus Torvalds
51da177e4SLinus Torvalds Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
61da177e4SLinus Torvalds
71da177e4SLinus Torvalds This program is free software; you can redistribute it and/or modify
81da177e4SLinus Torvalds it under the terms of the GNU General Public License version 2 as
91da177e4SLinus Torvalds published by the Free Software Foundation;
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
121da177e4SLinus Torvalds OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
131da177e4SLinus Torvalds FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
141da177e4SLinus Torvalds IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
151da177e4SLinus Torvalds CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
161da177e4SLinus Torvalds WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
171da177e4SLinus Torvalds ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
181da177e4SLinus Torvalds OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
191da177e4SLinus Torvalds
201da177e4SLinus Torvalds ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
211da177e4SLinus Torvalds COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
221da177e4SLinus Torvalds SOFTWARE IS DISCLAIMED.
231da177e4SLinus Torvalds */
241da177e4SLinus Torvalds
251da177e4SLinus Torvalds /* Bluetooth address family and sockets. */
261da177e4SLinus Torvalds
271da177e4SLinus Torvalds #include <linux/module.h>
28ffcecac6SMarcel Holtmann #include <linux/debugfs.h>
299e8305b3SMarcel Holtmann #include <linux/stringify.h>
30174cd4b1SIngo Molnar #include <linux/sched/signal.h>
31174cd4b1SIngo Molnar
323241ad82SMarcel Holtmann #include <asm/ioctls.h>
331da177e4SLinus Torvalds
341da177e4SLinus Torvalds #include <net/bluetooth/bluetooth.h>
35256a06c8SMasatake YAMATO #include <linux/proc_fs.h>
361da177e4SLinus Torvalds
37e64c97b5SMarcel Holtmann #include "leds.h"
38ee485290SMarcel Holtmann #include "selftest.h"
39ee485290SMarcel Holtmann
401da177e4SLinus Torvalds /* Bluetooth sockets */
41ccf74f23SLuiz Augusto von Dentz #define BT_MAX_PROTO (BTPROTO_LAST + 1)
42ec1b4cf7SStephen Hemminger static const struct net_proto_family *bt_proto[BT_MAX_PROTO];
43db7aa1c2SMarcel Holtmann static DEFINE_RWLOCK(bt_proto_lock);
4468845cb2SDave Young
4568845cb2SDave Young static struct lock_class_key bt_lock_key[BT_MAX_PROTO];
4636cbd3dcSJan Engelhardt static const char *const bt_key_strings[BT_MAX_PROTO] = {
4768845cb2SDave Young "sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP",
4868845cb2SDave Young "sk_lock-AF_BLUETOOTH-BTPROTO_HCI",
4968845cb2SDave Young "sk_lock-AF_BLUETOOTH-BTPROTO_SCO",
5068845cb2SDave Young "sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM",
5168845cb2SDave Young "sk_lock-AF_BLUETOOTH-BTPROTO_BNEP",
5268845cb2SDave Young "sk_lock-AF_BLUETOOTH-BTPROTO_CMTP",
5368845cb2SDave Young "sk_lock-AF_BLUETOOTH-BTPROTO_HIDP",
5468845cb2SDave Young "sk_lock-AF_BLUETOOTH-BTPROTO_AVDTP",
55ccf74f23SLuiz Augusto von Dentz "sk_lock-AF_BLUETOOTH-BTPROTO_ISO",
5668845cb2SDave Young };
5768845cb2SDave Young
58db7aa1c2SMarcel Holtmann static struct lock_class_key bt_slock_key[BT_MAX_PROTO];
5936cbd3dcSJan Engelhardt static const char *const bt_slock_key_strings[BT_MAX_PROTO] = {
6068845cb2SDave Young "slock-AF_BLUETOOTH-BTPROTO_L2CAP",
6168845cb2SDave Young "slock-AF_BLUETOOTH-BTPROTO_HCI",
6268845cb2SDave Young "slock-AF_BLUETOOTH-BTPROTO_SCO",
6368845cb2SDave Young "slock-AF_BLUETOOTH-BTPROTO_RFCOMM",
6468845cb2SDave Young "slock-AF_BLUETOOTH-BTPROTO_BNEP",
6568845cb2SDave Young "slock-AF_BLUETOOTH-BTPROTO_CMTP",
6668845cb2SDave Young "slock-AF_BLUETOOTH-BTPROTO_HIDP",
6768845cb2SDave Young "slock-AF_BLUETOOTH-BTPROTO_AVDTP",
68ccf74f23SLuiz Augusto von Dentz "slock-AF_BLUETOOTH-BTPROTO_ISO",
6968845cb2SDave Young };
70db7aa1c2SMarcel Holtmann
bt_sock_reclassify_lock(struct sock * sk,int proto)71b5a30ddaSOctavian Purdila void bt_sock_reclassify_lock(struct sock *sk, int proto)
72db7aa1c2SMarcel Holtmann {
73b5a30ddaSOctavian Purdila BUG_ON(!sk);
74fafc4e1eSHannes Frederic Sowa BUG_ON(!sock_allow_reclassification(sk));
75db7aa1c2SMarcel Holtmann
76db7aa1c2SMarcel Holtmann sock_lock_init_class_and_name(sk,
77db7aa1c2SMarcel Holtmann bt_slock_key_strings[proto], &bt_slock_key[proto],
78db7aa1c2SMarcel Holtmann bt_key_strings[proto], &bt_lock_key[proto]);
79db7aa1c2SMarcel Holtmann }
80b5a30ddaSOctavian Purdila EXPORT_SYMBOL(bt_sock_reclassify_lock);
811da177e4SLinus Torvalds
bt_sock_register(int proto,const struct net_proto_family * ops)82ec1b4cf7SStephen Hemminger int bt_sock_register(int proto, const struct net_proto_family *ops)
831da177e4SLinus Torvalds {
8474da626aSMarcel Holtmann int err = 0;
8574da626aSMarcel Holtmann
861da177e4SLinus Torvalds if (proto < 0 || proto >= BT_MAX_PROTO)
871da177e4SLinus Torvalds return -EINVAL;
881da177e4SLinus Torvalds
8974da626aSMarcel Holtmann write_lock(&bt_proto_lock);
901da177e4SLinus Torvalds
9174da626aSMarcel Holtmann if (bt_proto[proto])
9274da626aSMarcel Holtmann err = -EEXIST;
9374da626aSMarcel Holtmann else
941da177e4SLinus Torvalds bt_proto[proto] = ops;
9574da626aSMarcel Holtmann
9674da626aSMarcel Holtmann write_unlock(&bt_proto_lock);
9774da626aSMarcel Holtmann
9874da626aSMarcel Holtmann return err;
991da177e4SLinus Torvalds }
1001da177e4SLinus Torvalds EXPORT_SYMBOL(bt_sock_register);
1011da177e4SLinus Torvalds
bt_sock_unregister(int proto)102be9f97f0SDavid Herrmann void bt_sock_unregister(int proto)
1031da177e4SLinus Torvalds {
1041da177e4SLinus Torvalds if (proto < 0 || proto >= BT_MAX_PROTO)
105be9f97f0SDavid Herrmann return;
1061da177e4SLinus Torvalds
10774da626aSMarcel Holtmann write_lock(&bt_proto_lock);
1081da177e4SLinus Torvalds bt_proto[proto] = NULL;
10974da626aSMarcel Holtmann write_unlock(&bt_proto_lock);
1101da177e4SLinus Torvalds }
1111da177e4SLinus Torvalds EXPORT_SYMBOL(bt_sock_unregister);
1121da177e4SLinus Torvalds
bt_sock_create(struct net * net,struct socket * sock,int proto,int kern)1133f378b68SEric Paris static int bt_sock_create(struct net *net, struct socket *sock, int proto,
1143f378b68SEric Paris int kern)
1151da177e4SLinus Torvalds {
11674da626aSMarcel Holtmann int err;
1171da177e4SLinus Torvalds
1181b8d7ae4SEric W. Biederman if (net != &init_net)
1191b8d7ae4SEric W. Biederman return -EAFNOSUPPORT;
1201b8d7ae4SEric W. Biederman
1211da177e4SLinus Torvalds if (proto < 0 || proto >= BT_MAX_PROTO)
1221da177e4SLinus Torvalds return -EINVAL;
1231da177e4SLinus Torvalds
12495a5afcaSJohannes Berg if (!bt_proto[proto])
1251da177e4SLinus Torvalds request_module("bt-proto-%d", proto);
12674da626aSMarcel Holtmann
1271da177e4SLinus Torvalds err = -EPROTONOSUPPORT;
12874da626aSMarcel Holtmann
12974da626aSMarcel Holtmann read_lock(&bt_proto_lock);
13074da626aSMarcel Holtmann
1311da177e4SLinus Torvalds if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) {
1323f378b68SEric Paris err = bt_proto[proto]->create(net, sock, proto, kern);
133b5a30ddaSOctavian Purdila if (!err)
134b5a30ddaSOctavian Purdila bt_sock_reclassify_lock(sock->sk, proto);
1351da177e4SLinus Torvalds module_put(bt_proto[proto]->owner);
1361da177e4SLinus Torvalds }
13774da626aSMarcel Holtmann
13874da626aSMarcel Holtmann read_unlock(&bt_proto_lock);
13974da626aSMarcel Holtmann
1401da177e4SLinus Torvalds return err;
1411da177e4SLinus Torvalds }
1421da177e4SLinus Torvalds
bt_sock_alloc(struct net * net,struct socket * sock,struct proto * prot,int proto,gfp_t prio,int kern)1436bfa273eSLuiz Augusto von Dentz struct sock *bt_sock_alloc(struct net *net, struct socket *sock,
1446bfa273eSLuiz Augusto von Dentz struct proto *prot, int proto, gfp_t prio, int kern)
1456bfa273eSLuiz Augusto von Dentz {
1466bfa273eSLuiz Augusto von Dentz struct sock *sk;
1476bfa273eSLuiz Augusto von Dentz
1486bfa273eSLuiz Augusto von Dentz sk = sk_alloc(net, PF_BLUETOOTH, prio, prot, kern);
1496bfa273eSLuiz Augusto von Dentz if (!sk)
1506bfa273eSLuiz Augusto von Dentz return NULL;
1516bfa273eSLuiz Augusto von Dentz
1526bfa273eSLuiz Augusto von Dentz sock_init_data(sock, sk);
1536bfa273eSLuiz Augusto von Dentz INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
1546bfa273eSLuiz Augusto von Dentz
1556bfa273eSLuiz Augusto von Dentz sock_reset_flag(sk, SOCK_ZAPPED);
1566bfa273eSLuiz Augusto von Dentz
1576bfa273eSLuiz Augusto von Dentz sk->sk_protocol = proto;
1586bfa273eSLuiz Augusto von Dentz sk->sk_state = BT_OPEN;
1596bfa273eSLuiz Augusto von Dentz
160464c702fSLuiz Augusto von Dentz /* Init peer information so it can be properly monitored */
161464c702fSLuiz Augusto von Dentz if (!kern) {
162464c702fSLuiz Augusto von Dentz spin_lock(&sk->sk_peer_lock);
163464c702fSLuiz Augusto von Dentz sk->sk_peer_pid = get_pid(task_tgid(current));
164464c702fSLuiz Augusto von Dentz sk->sk_peer_cred = get_current_cred();
165464c702fSLuiz Augusto von Dentz spin_unlock(&sk->sk_peer_lock);
166464c702fSLuiz Augusto von Dentz }
167464c702fSLuiz Augusto von Dentz
1686bfa273eSLuiz Augusto von Dentz return sk;
1696bfa273eSLuiz Augusto von Dentz }
1706bfa273eSLuiz Augusto von Dentz EXPORT_SYMBOL(bt_sock_alloc);
1716bfa273eSLuiz Augusto von Dentz
bt_sock_link(struct bt_sock_list * l,struct sock * sk)1721da177e4SLinus Torvalds void bt_sock_link(struct bt_sock_list *l, struct sock *sk)
1731da177e4SLinus Torvalds {
17494f5bfb8SGustavo F. Padovan write_lock(&l->lock);
1751da177e4SLinus Torvalds sk_add_node(sk, &l->head);
17694f5bfb8SGustavo F. Padovan write_unlock(&l->lock);
1771da177e4SLinus Torvalds }
1781da177e4SLinus Torvalds EXPORT_SYMBOL(bt_sock_link);
1791da177e4SLinus Torvalds
bt_sock_unlink(struct bt_sock_list * l,struct sock * sk)1801da177e4SLinus Torvalds void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk)
1811da177e4SLinus Torvalds {
18294f5bfb8SGustavo F. Padovan write_lock(&l->lock);
1831da177e4SLinus Torvalds sk_del_node_init(sk);
18494f5bfb8SGustavo F. Padovan write_unlock(&l->lock);
1851da177e4SLinus Torvalds }
1861da177e4SLinus Torvalds EXPORT_SYMBOL(bt_sock_unlink);
1871da177e4SLinus Torvalds
bt_accept_enqueue(struct sock * parent,struct sock * sk,bool bh)188c4f5627fSMatthias Kaehlcke void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh)
1891da177e4SLinus Torvalds {
190464c702fSLuiz Augusto von Dentz const struct cred *old_cred;
191464c702fSLuiz Augusto von Dentz struct pid *old_pid;
192464c702fSLuiz Augusto von Dentz
1931da177e4SLinus Torvalds BT_DBG("parent %p, sk %p", parent, sk);
1941da177e4SLinus Torvalds
1951da177e4SLinus Torvalds sock_hold(sk);
196c4f5627fSMatthias Kaehlcke
197c4f5627fSMatthias Kaehlcke if (bh)
198c4f5627fSMatthias Kaehlcke bh_lock_sock_nested(sk);
199c4f5627fSMatthias Kaehlcke else
200b71c69c2SPhilipp Puschmann lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
201c4f5627fSMatthias Kaehlcke
2021da177e4SLinus Torvalds list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q);
2031da177e4SLinus Torvalds bt_sk(sk)->parent = parent;
204c4f5627fSMatthias Kaehlcke
205464c702fSLuiz Augusto von Dentz /* Copy credentials from parent since for incoming connections the
206464c702fSLuiz Augusto von Dentz * socket is allocated by the kernel.
207464c702fSLuiz Augusto von Dentz */
208464c702fSLuiz Augusto von Dentz spin_lock(&sk->sk_peer_lock);
209464c702fSLuiz Augusto von Dentz old_pid = sk->sk_peer_pid;
210464c702fSLuiz Augusto von Dentz old_cred = sk->sk_peer_cred;
211464c702fSLuiz Augusto von Dentz sk->sk_peer_pid = get_pid(parent->sk_peer_pid);
212464c702fSLuiz Augusto von Dentz sk->sk_peer_cred = get_cred(parent->sk_peer_cred);
213464c702fSLuiz Augusto von Dentz spin_unlock(&sk->sk_peer_lock);
214464c702fSLuiz Augusto von Dentz
215464c702fSLuiz Augusto von Dentz put_pid(old_pid);
216464c702fSLuiz Augusto von Dentz put_cred(old_cred);
217464c702fSLuiz Augusto von Dentz
218c4f5627fSMatthias Kaehlcke if (bh)
219c4f5627fSMatthias Kaehlcke bh_unlock_sock(sk);
220c4f5627fSMatthias Kaehlcke else
221e1633762SDean Jenkins release_sock(sk);
222c4f5627fSMatthias Kaehlcke
2237976a11bSEric Dumazet sk_acceptq_added(parent);
2241da177e4SLinus Torvalds }
2251da177e4SLinus Torvalds EXPORT_SYMBOL(bt_accept_enqueue);
2261da177e4SLinus Torvalds
22727bfbc21SDean Jenkins /* Calling function must hold the sk lock.
22827bfbc21SDean Jenkins * bt_sk(sk)->parent must be non-NULL meaning sk is in the parent list.
22927bfbc21SDean Jenkins */
bt_accept_unlink(struct sock * sk)2301da177e4SLinus Torvalds void bt_accept_unlink(struct sock *sk)
2311da177e4SLinus Torvalds {
2321da177e4SLinus Torvalds BT_DBG("sk %p state %d", sk, sk->sk_state);
2331da177e4SLinus Torvalds
2341da177e4SLinus Torvalds list_del_init(&bt_sk(sk)->accept_q);
2357976a11bSEric Dumazet sk_acceptq_removed(bt_sk(sk)->parent);
2361da177e4SLinus Torvalds bt_sk(sk)->parent = NULL;
2371da177e4SLinus Torvalds sock_put(sk);
2381da177e4SLinus Torvalds }
2391da177e4SLinus Torvalds EXPORT_SYMBOL(bt_accept_unlink);
2401da177e4SLinus Torvalds
bt_accept_dequeue(struct sock * parent,struct socket * newsock)2411da177e4SLinus Torvalds struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
2421da177e4SLinus Torvalds {
2437eb7404fSGeliang Tang struct bt_sock *s, *n;
2441da177e4SLinus Torvalds struct sock *sk;
2451da177e4SLinus Torvalds
2461da177e4SLinus Torvalds BT_DBG("parent %p", parent);
2471da177e4SLinus Torvalds
24827bfbc21SDean Jenkins restart:
2497eb7404fSGeliang Tang list_for_each_entry_safe(s, n, &bt_sk(parent)->accept_q, accept_q) {
2507eb7404fSGeliang Tang sk = (struct sock *)s;
2511da177e4SLinus Torvalds
25227bfbc21SDean Jenkins /* Prevent early freeing of sk due to unlink and sock_kill */
25327bfbc21SDean Jenkins sock_hold(sk);
2548a154a8fSGustavo F. Padovan lock_sock(sk);
2551da177e4SLinus Torvalds
25627bfbc21SDean Jenkins /* Check sk has not already been unlinked via
25727bfbc21SDean Jenkins * bt_accept_unlink() due to serialisation caused by sk locking
25827bfbc21SDean Jenkins */
25927bfbc21SDean Jenkins if (!bt_sk(sk)->parent) {
26027bfbc21SDean Jenkins BT_DBG("sk %p, already unlinked", sk);
26127bfbc21SDean Jenkins release_sock(sk);
26227bfbc21SDean Jenkins sock_put(sk);
26327bfbc21SDean Jenkins
26427bfbc21SDean Jenkins /* Restart the loop as sk is no longer in the list
26527bfbc21SDean Jenkins * and also avoid a potential infinite loop because
26627bfbc21SDean Jenkins * list_for_each_entry_safe() is not thread safe.
26727bfbc21SDean Jenkins */
26827bfbc21SDean Jenkins goto restart;
26927bfbc21SDean Jenkins }
27027bfbc21SDean Jenkins
27127bfbc21SDean Jenkins /* sk is safely in the parent list so reduce reference count */
27227bfbc21SDean Jenkins sock_put(sk);
27327bfbc21SDean Jenkins
2741da177e4SLinus Torvalds /* FIXME: Is this check still needed */
2751da177e4SLinus Torvalds if (sk->sk_state == BT_CLOSED) {
2761da177e4SLinus Torvalds bt_accept_unlink(sk);
2771a11ec89SYichen Zhao release_sock(sk);
2781da177e4SLinus Torvalds continue;
2791da177e4SLinus Torvalds }
2801da177e4SLinus Torvalds
281c4f912e1SMarcel Holtmann if (sk->sk_state == BT_CONNECTED || !newsock ||
282d060991fSVinicius Costa Gomes test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) {
2831da177e4SLinus Torvalds bt_accept_unlink(sk);
2841da177e4SLinus Torvalds if (newsock)
2851da177e4SLinus Torvalds sock_graft(sk, newsock);
286d37f50e1SAndrei Emeltchenko
2878a154a8fSGustavo F. Padovan release_sock(sk);
2881da177e4SLinus Torvalds return sk;
2891da177e4SLinus Torvalds }
2901da177e4SLinus Torvalds
2918a154a8fSGustavo F. Padovan release_sock(sk);
2921da177e4SLinus Torvalds }
293d37f50e1SAndrei Emeltchenko
2941da177e4SLinus Torvalds return NULL;
2951da177e4SLinus Torvalds }
2961da177e4SLinus Torvalds EXPORT_SYMBOL(bt_accept_dequeue);
2971da177e4SLinus Torvalds
bt_sock_recvmsg(struct socket * sock,struct msghdr * msg,size_t len,int flags)2981b784140SYing Xue int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
2991b784140SYing Xue int flags)
3001da177e4SLinus Torvalds {
3011da177e4SLinus Torvalds struct sock *sk = sock->sk;
3021da177e4SLinus Torvalds struct sk_buff *skb;
3031da177e4SLinus Torvalds size_t copied;
304b5f34f94SDenis Kenzior size_t skblen;
3051da177e4SLinus Torvalds int err;
3061da177e4SLinus Torvalds
307a418b893SMarcel Holtmann BT_DBG("sock %p sk %p len %zu", sock, sk, len);
3081da177e4SLinus Torvalds
309d94a6104SMarcel Holtmann if (flags & MSG_OOB)
3101da177e4SLinus Torvalds return -EOPNOTSUPP;
3111da177e4SLinus Torvalds
312f4b41f06SOliver Hartkopp skb = skb_recv_datagram(sk, flags, &err);
3135a08ecceSAndrei Emeltchenko if (!skb) {
314f3d33426SHannes Frederic Sowa if (sk->sk_shutdown & RCV_SHUTDOWN)
3152e07e834SHyunwoo Kim err = 0;
316f3d33426SHannes Frederic Sowa
3171da177e4SLinus Torvalds return err;
3181da177e4SLinus Torvalds }
3191da177e4SLinus Torvalds
320b5f34f94SDenis Kenzior skblen = skb->len;
3211da177e4SLinus Torvalds copied = skb->len;
3221da177e4SLinus Torvalds if (len < copied) {
3231da177e4SLinus Torvalds msg->msg_flags |= MSG_TRUNC;
3241da177e4SLinus Torvalds copied = len;
3251da177e4SLinus Torvalds }
3261da177e4SLinus Torvalds
327badff6d0SArnaldo Carvalho de Melo skb_reset_transport_header(skb);
32851f3d02bSDavid S. Miller err = skb_copy_datagram_msg(skb, 0, msg, copied);
329d9763698SMarcel Holtmann if (err == 0) {
3306fd1d51cSErin MacNeil sock_recv_cmsgs(msg, sk, skb);
3311da177e4SLinus Torvalds
3329dcbc313SEzequiel Garcia if (msg->msg_name && bt_sk(sk)->skb_msg_name)
333d9763698SMarcel Holtmann bt_sk(sk)->skb_msg_name(skb, msg->msg_name,
334d9763698SMarcel Holtmann &msg->msg_namelen);
33500398e1dSAlain Michaud
3363f19ffb2SLuiz Augusto von Dentz if (test_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags)) {
3373f19ffb2SLuiz Augusto von Dentz u8 pkt_status = hci_skb_pkt_status(skb);
3383f19ffb2SLuiz Augusto von Dentz
3393f19ffb2SLuiz Augusto von Dentz put_cmsg(msg, SOL_BLUETOOTH, BT_SCM_PKT_STATUS,
3403f19ffb2SLuiz Augusto von Dentz sizeof(pkt_status), &pkt_status);
3413f19ffb2SLuiz Augusto von Dentz }
342d9763698SMarcel Holtmann }
343d9763698SMarcel Holtmann
3441da177e4SLinus Torvalds skb_free_datagram(sk, skb);
3451da177e4SLinus Torvalds
34690a56f72SLuiz Augusto von Dentz if (flags & MSG_TRUNC)
347b5f34f94SDenis Kenzior copied = skblen;
348b5f34f94SDenis Kenzior
3491da177e4SLinus Torvalds return err ? : copied;
3501da177e4SLinus Torvalds }
3511da177e4SLinus Torvalds EXPORT_SYMBOL(bt_sock_recvmsg);
3521da177e4SLinus Torvalds
bt_sock_data_wait(struct sock * sk,long timeo)353796c86eeSMat Martineau static long bt_sock_data_wait(struct sock *sk, long timeo)
354796c86eeSMat Martineau {
355796c86eeSMat Martineau DECLARE_WAITQUEUE(wait, current);
356796c86eeSMat Martineau
357796c86eeSMat Martineau add_wait_queue(sk_sleep(sk), &wait);
358796c86eeSMat Martineau for (;;) {
359796c86eeSMat Martineau set_current_state(TASK_INTERRUPTIBLE);
360796c86eeSMat Martineau
361796c86eeSMat Martineau if (!skb_queue_empty(&sk->sk_receive_queue))
362796c86eeSMat Martineau break;
363796c86eeSMat Martineau
364796c86eeSMat Martineau if (sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN))
365796c86eeSMat Martineau break;
366796c86eeSMat Martineau
367796c86eeSMat Martineau if (signal_pending(current) || !timeo)
368796c86eeSMat Martineau break;
369796c86eeSMat Martineau
3709cd3e072SEric Dumazet sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
371796c86eeSMat Martineau release_sock(sk);
372796c86eeSMat Martineau timeo = schedule_timeout(timeo);
373796c86eeSMat Martineau lock_sock(sk);
3749cd3e072SEric Dumazet sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
375796c86eeSMat Martineau }
376796c86eeSMat Martineau
377796c86eeSMat Martineau __set_current_state(TASK_RUNNING);
378796c86eeSMat Martineau remove_wait_queue(sk_sleep(sk), &wait);
379796c86eeSMat Martineau return timeo;
380796c86eeSMat Martineau }
381796c86eeSMat Martineau
bt_sock_stream_recvmsg(struct socket * sock,struct msghdr * msg,size_t size,int flags)3821b784140SYing Xue int bt_sock_stream_recvmsg(struct socket *sock, struct msghdr *msg,
3831b784140SYing Xue size_t size, int flags)
384796c86eeSMat Martineau {
385796c86eeSMat Martineau struct sock *sk = sock->sk;
386796c86eeSMat Martineau int err = 0;
387796c86eeSMat Martineau size_t target, copied = 0;
388796c86eeSMat Martineau long timeo;
389796c86eeSMat Martineau
390796c86eeSMat Martineau if (flags & MSG_OOB)
391796c86eeSMat Martineau return -EOPNOTSUPP;
392796c86eeSMat Martineau
393796c86eeSMat Martineau BT_DBG("sk %p size %zu", sk, size);
394796c86eeSMat Martineau
395796c86eeSMat Martineau lock_sock(sk);
396796c86eeSMat Martineau
397796c86eeSMat Martineau target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
398796c86eeSMat Martineau timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
399796c86eeSMat Martineau
400796c86eeSMat Martineau do {
401796c86eeSMat Martineau struct sk_buff *skb;
402796c86eeSMat Martineau int chunk;
403796c86eeSMat Martineau
404796c86eeSMat Martineau skb = skb_dequeue(&sk->sk_receive_queue);
405796c86eeSMat Martineau if (!skb) {
406796c86eeSMat Martineau if (copied >= target)
407796c86eeSMat Martineau break;
408796c86eeSMat Martineau
4095a08ecceSAndrei Emeltchenko err = sock_error(sk);
4105a08ecceSAndrei Emeltchenko if (err)
411796c86eeSMat Martineau break;
412796c86eeSMat Martineau if (sk->sk_shutdown & RCV_SHUTDOWN)
413796c86eeSMat Martineau break;
414796c86eeSMat Martineau
415796c86eeSMat Martineau err = -EAGAIN;
416796c86eeSMat Martineau if (!timeo)
417796c86eeSMat Martineau break;
418796c86eeSMat Martineau
419796c86eeSMat Martineau timeo = bt_sock_data_wait(sk, timeo);
420796c86eeSMat Martineau
421796c86eeSMat Martineau if (signal_pending(current)) {
422796c86eeSMat Martineau err = sock_intr_errno(timeo);
423796c86eeSMat Martineau goto out;
424796c86eeSMat Martineau }
425796c86eeSMat Martineau continue;
426796c86eeSMat Martineau }
427796c86eeSMat Martineau
428796c86eeSMat Martineau chunk = min_t(unsigned int, skb->len, size);
42951f3d02bSDavid S. Miller if (skb_copy_datagram_msg(skb, 0, msg, chunk)) {
430796c86eeSMat Martineau skb_queue_head(&sk->sk_receive_queue, skb);
431796c86eeSMat Martineau if (!copied)
432796c86eeSMat Martineau copied = -EFAULT;
433796c86eeSMat Martineau break;
434796c86eeSMat Martineau }
435796c86eeSMat Martineau copied += chunk;
436796c86eeSMat Martineau size -= chunk;
437796c86eeSMat Martineau
4386fd1d51cSErin MacNeil sock_recv_cmsgs(msg, sk, skb);
439796c86eeSMat Martineau
440796c86eeSMat Martineau if (!(flags & MSG_PEEK)) {
4415b668eb3SMat Martineau int skb_len = skb_headlen(skb);
4425b668eb3SMat Martineau
4435b668eb3SMat Martineau if (chunk <= skb_len) {
4445b668eb3SMat Martineau __skb_pull(skb, chunk);
4455b668eb3SMat Martineau } else {
4465b668eb3SMat Martineau struct sk_buff *frag;
4475b668eb3SMat Martineau
4485b668eb3SMat Martineau __skb_pull(skb, skb_len);
4495b668eb3SMat Martineau chunk -= skb_len;
4505b668eb3SMat Martineau
4515b668eb3SMat Martineau skb_walk_frags(skb, frag) {
4525b668eb3SMat Martineau if (chunk <= frag->len) {
4535b668eb3SMat Martineau /* Pulling partial data */
4545b668eb3SMat Martineau skb->len -= chunk;
4555b668eb3SMat Martineau skb->data_len -= chunk;
4565b668eb3SMat Martineau __skb_pull(frag, chunk);
4575b668eb3SMat Martineau break;
4585b668eb3SMat Martineau } else if (frag->len) {
4595b668eb3SMat Martineau /* Pulling all frag data */
4605b668eb3SMat Martineau chunk -= frag->len;
4615b668eb3SMat Martineau skb->len -= frag->len;
4625b668eb3SMat Martineau skb->data_len -= frag->len;
4635b668eb3SMat Martineau __skb_pull(frag, frag->len);
4645b668eb3SMat Martineau }
4655b668eb3SMat Martineau }
4665b668eb3SMat Martineau }
4675b668eb3SMat Martineau
468796c86eeSMat Martineau if (skb->len) {
469796c86eeSMat Martineau skb_queue_head(&sk->sk_receive_queue, skb);
470796c86eeSMat Martineau break;
471796c86eeSMat Martineau }
472796c86eeSMat Martineau kfree_skb(skb);
473796c86eeSMat Martineau
474796c86eeSMat Martineau } else {
475796c86eeSMat Martineau /* put message back and return */
476796c86eeSMat Martineau skb_queue_head(&sk->sk_receive_queue, skb);
477796c86eeSMat Martineau break;
478796c86eeSMat Martineau }
479796c86eeSMat Martineau } while (size);
480796c86eeSMat Martineau
481796c86eeSMat Martineau out:
482796c86eeSMat Martineau release_sock(sk);
483796c86eeSMat Martineau return copied ? : err;
484796c86eeSMat Martineau }
485796c86eeSMat Martineau EXPORT_SYMBOL(bt_sock_stream_recvmsg);
486796c86eeSMat Martineau
bt_accept_poll(struct sock * parent)487ade994f4SAl Viro static inline __poll_t bt_accept_poll(struct sock *parent)
4881da177e4SLinus Torvalds {
4897eb7404fSGeliang Tang struct bt_sock *s, *n;
4901da177e4SLinus Torvalds struct sock *sk;
4911da177e4SLinus Torvalds
4927eb7404fSGeliang Tang list_for_each_entry_safe(s, n, &bt_sk(parent)->accept_q, accept_q) {
4937eb7404fSGeliang Tang sk = (struct sock *)s;
494d5f2d2beSMarcel Holtmann if (sk->sk_state == BT_CONNECTED ||
495c5daa683SGustavo Padovan (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags) &&
496d5f2d2beSMarcel Holtmann sk->sk_state == BT_CONNECT2))
497a9a08845SLinus Torvalds return EPOLLIN | EPOLLRDNORM;
4981da177e4SLinus Torvalds }
4991da177e4SLinus Torvalds
5001da177e4SLinus Torvalds return 0;
5011da177e4SLinus Torvalds }
5021da177e4SLinus Torvalds
bt_sock_poll(struct file * file,struct socket * sock,poll_table * wait)503a11e1d43SLinus Torvalds __poll_t bt_sock_poll(struct file *file, struct socket *sock,
504a11e1d43SLinus Torvalds poll_table *wait)
5051da177e4SLinus Torvalds {
5061da177e4SLinus Torvalds struct sock *sk = sock->sk;
507ade994f4SAl Viro __poll_t mask = 0;
5081da177e4SLinus Torvalds
509a11e1d43SLinus Torvalds poll_wait(file, sk_sleep(sk), wait);
510a11e1d43SLinus Torvalds
5111da177e4SLinus Torvalds if (sk->sk_state == BT_LISTEN)
5121da177e4SLinus Torvalds return bt_accept_poll(sk);
5131da177e4SLinus Torvalds
5143ef7cf57SEric Dumazet if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue))
515a9a08845SLinus Torvalds mask |= EPOLLERR |
516a9a08845SLinus Torvalds (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? EPOLLPRI : 0);
5171da177e4SLinus Torvalds
518f348d70aSDavide Libenzi if (sk->sk_shutdown & RCV_SHUTDOWN)
519a9a08845SLinus Torvalds mask |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM;
520f348d70aSDavide Libenzi
5211da177e4SLinus Torvalds if (sk->sk_shutdown == SHUTDOWN_MASK)
522a9a08845SLinus Torvalds mask |= EPOLLHUP;
5231da177e4SLinus Torvalds
5243ef7cf57SEric Dumazet if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
525a9a08845SLinus Torvalds mask |= EPOLLIN | EPOLLRDNORM;
5261da177e4SLinus Torvalds
5271da177e4SLinus Torvalds if (sk->sk_state == BT_CLOSED)
528a9a08845SLinus Torvalds mask |= EPOLLHUP;
5291da177e4SLinus Torvalds
5301da177e4SLinus Torvalds if (sk->sk_state == BT_CONNECT ||
5311da177e4SLinus Torvalds sk->sk_state == BT_CONNECT2 ||
5321da177e4SLinus Torvalds sk->sk_state == BT_CONFIG)
5331da177e4SLinus Torvalds return mask;
5341da177e4SLinus Torvalds
535c5daa683SGustavo Padovan if (!test_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags) && sock_writeable(sk))
536a9a08845SLinus Torvalds mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;
5371da177e4SLinus Torvalds else
5389cd3e072SEric Dumazet sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
5391da177e4SLinus Torvalds
5401da177e4SLinus Torvalds return mask;
5411da177e4SLinus Torvalds }
542a11e1d43SLinus Torvalds EXPORT_SYMBOL(bt_sock_poll);
5431da177e4SLinus Torvalds
bt_sock_ioctl(struct socket * sock,unsigned int cmd,unsigned long arg)5443241ad82SMarcel Holtmann int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
5453241ad82SMarcel Holtmann {
5463241ad82SMarcel Holtmann struct sock *sk = sock->sk;
54743cbeee9SMarcel Holtmann struct sk_buff *skb;
54843cbeee9SMarcel Holtmann long amount;
5493241ad82SMarcel Holtmann int err;
5503241ad82SMarcel Holtmann
5513241ad82SMarcel Holtmann BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg);
5523241ad82SMarcel Holtmann
5533241ad82SMarcel Holtmann switch (cmd) {
55443cbeee9SMarcel Holtmann case TIOCOUTQ:
55543cbeee9SMarcel Holtmann if (sk->sk_state == BT_LISTEN)
55643cbeee9SMarcel Holtmann return -EINVAL;
55743cbeee9SMarcel Holtmann
55831e6d363SEric Dumazet amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
55943cbeee9SMarcel Holtmann if (amount < 0)
56043cbeee9SMarcel Holtmann amount = 0;
56143cbeee9SMarcel Holtmann err = put_user(amount, (int __user *)arg);
56243cbeee9SMarcel Holtmann break;
56343cbeee9SMarcel Holtmann
56443cbeee9SMarcel Holtmann case TIOCINQ:
56543cbeee9SMarcel Holtmann if (sk->sk_state == BT_LISTEN)
56643cbeee9SMarcel Holtmann return -EINVAL;
56743cbeee9SMarcel Holtmann
568*f7b94bdcSLuiz Augusto von Dentz spin_lock(&sk->sk_receive_queue.lock);
56943cbeee9SMarcel Holtmann skb = skb_peek(&sk->sk_receive_queue);
57043cbeee9SMarcel Holtmann amount = skb ? skb->len : 0;
571*f7b94bdcSLuiz Augusto von Dentz spin_unlock(&sk->sk_receive_queue.lock);
572*f7b94bdcSLuiz Augusto von Dentz
57343cbeee9SMarcel Holtmann err = put_user(amount, (int __user *)arg);
57443cbeee9SMarcel Holtmann break;
57543cbeee9SMarcel Holtmann
5763241ad82SMarcel Holtmann default:
5773241ad82SMarcel Holtmann err = -ENOIOCTLCMD;
5783241ad82SMarcel Holtmann break;
5793241ad82SMarcel Holtmann }
5803241ad82SMarcel Holtmann
5813241ad82SMarcel Holtmann return err;
5823241ad82SMarcel Holtmann }
5833241ad82SMarcel Holtmann EXPORT_SYMBOL(bt_sock_ioctl);
5843241ad82SMarcel Holtmann
5850fba96f9SJohan Hedberg /* This function expects the sk lock to be held when called */
bt_sock_wait_state(struct sock * sk,int state,unsigned long timeo)5861da177e4SLinus Torvalds int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
5871da177e4SLinus Torvalds {
5881da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current);
5891da177e4SLinus Torvalds int err = 0;
5901da177e4SLinus Torvalds
5911da177e4SLinus Torvalds BT_DBG("sk %p", sk);
5921da177e4SLinus Torvalds
593aa395145SEric Dumazet add_wait_queue(sk_sleep(sk), &wait);
5941da177e4SLinus Torvalds set_current_state(TASK_INTERRUPTIBLE);
5959be4e3fbSPeter Hurley while (sk->sk_state != state) {
5961da177e4SLinus Torvalds if (!timeo) {
597b4c612a4SMarcel Holtmann err = -EINPROGRESS;
5981da177e4SLinus Torvalds break;
5991da177e4SLinus Torvalds }
6001da177e4SLinus Torvalds
6011da177e4SLinus Torvalds if (signal_pending(current)) {
6021da177e4SLinus Torvalds err = sock_intr_errno(timeo);
6031da177e4SLinus Torvalds break;
6041da177e4SLinus Torvalds }
6051da177e4SLinus Torvalds
6061da177e4SLinus Torvalds release_sock(sk);
6071da177e4SLinus Torvalds timeo = schedule_timeout(timeo);
6081da177e4SLinus Torvalds lock_sock(sk);
6099be4e3fbSPeter Hurley set_current_state(TASK_INTERRUPTIBLE);
6101da177e4SLinus Torvalds
6111da177e4SLinus Torvalds err = sock_error(sk);
612c1cbe4b7SBenjamin LaHaise if (err)
6131da177e4SLinus Torvalds break;
6141da177e4SLinus Torvalds }
6159be4e3fbSPeter Hurley __set_current_state(TASK_RUNNING);
616aa395145SEric Dumazet remove_wait_queue(sk_sleep(sk), &wait);
6171da177e4SLinus Torvalds return err;
6181da177e4SLinus Torvalds }
6191da177e4SLinus Torvalds EXPORT_SYMBOL(bt_sock_wait_state);
6201da177e4SLinus Torvalds
621e793dcf0SJohan Hedberg /* This function expects the sk lock to be held when called */
bt_sock_wait_ready(struct sock * sk,unsigned int msg_flags)622da891217SGavin Li int bt_sock_wait_ready(struct sock *sk, unsigned int msg_flags)
623e793dcf0SJohan Hedberg {
624e793dcf0SJohan Hedberg DECLARE_WAITQUEUE(wait, current);
625e793dcf0SJohan Hedberg unsigned long timeo;
626e793dcf0SJohan Hedberg int err = 0;
627e793dcf0SJohan Hedberg
628e793dcf0SJohan Hedberg BT_DBG("sk %p", sk);
629e793dcf0SJohan Hedberg
630da891217SGavin Li timeo = sock_sndtimeo(sk, !!(msg_flags & MSG_DONTWAIT));
631e793dcf0SJohan Hedberg
632e793dcf0SJohan Hedberg add_wait_queue(sk_sleep(sk), &wait);
633e793dcf0SJohan Hedberg set_current_state(TASK_INTERRUPTIBLE);
634e793dcf0SJohan Hedberg while (test_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags)) {
635e793dcf0SJohan Hedberg if (!timeo) {
636e793dcf0SJohan Hedberg err = -EAGAIN;
637e793dcf0SJohan Hedberg break;
638e793dcf0SJohan Hedberg }
639e793dcf0SJohan Hedberg
640e793dcf0SJohan Hedberg if (signal_pending(current)) {
641e793dcf0SJohan Hedberg err = sock_intr_errno(timeo);
642e793dcf0SJohan Hedberg break;
643e793dcf0SJohan Hedberg }
644e793dcf0SJohan Hedberg
645e793dcf0SJohan Hedberg release_sock(sk);
646e793dcf0SJohan Hedberg timeo = schedule_timeout(timeo);
647e793dcf0SJohan Hedberg lock_sock(sk);
648e793dcf0SJohan Hedberg set_current_state(TASK_INTERRUPTIBLE);
649e793dcf0SJohan Hedberg
650e793dcf0SJohan Hedberg err = sock_error(sk);
651e793dcf0SJohan Hedberg if (err)
652e793dcf0SJohan Hedberg break;
653e793dcf0SJohan Hedberg }
654e793dcf0SJohan Hedberg __set_current_state(TASK_RUNNING);
655e793dcf0SJohan Hedberg remove_wait_queue(sk_sleep(sk), &wait);
656e793dcf0SJohan Hedberg
657e793dcf0SJohan Hedberg return err;
658e793dcf0SJohan Hedberg }
659e793dcf0SJohan Hedberg EXPORT_SYMBOL(bt_sock_wait_ready);
660e793dcf0SJohan Hedberg
661256a06c8SMasatake YAMATO #ifdef CONFIG_PROC_FS
bt_seq_start(struct seq_file * seq,loff_t * pos)662256a06c8SMasatake YAMATO static void *bt_seq_start(struct seq_file *seq, loff_t *pos)
663256a06c8SMasatake YAMATO __acquires(seq->private->l->lock)
664256a06c8SMasatake YAMATO {
665359745d7SMuchun Song struct bt_sock_list *l = pde_data(file_inode(seq->file));
666256a06c8SMasatake YAMATO
667256a06c8SMasatake YAMATO read_lock(&l->lock);
668256a06c8SMasatake YAMATO return seq_hlist_start_head(&l->head, *pos);
669256a06c8SMasatake YAMATO }
670256a06c8SMasatake YAMATO
bt_seq_next(struct seq_file * seq,void * v,loff_t * pos)671256a06c8SMasatake YAMATO static void *bt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
672256a06c8SMasatake YAMATO {
673359745d7SMuchun Song struct bt_sock_list *l = pde_data(file_inode(seq->file));
674256a06c8SMasatake YAMATO
675256a06c8SMasatake YAMATO return seq_hlist_next(v, &l->head, pos);
676256a06c8SMasatake YAMATO }
677256a06c8SMasatake YAMATO
bt_seq_stop(struct seq_file * seq,void * v)678256a06c8SMasatake YAMATO static void bt_seq_stop(struct seq_file *seq, void *v)
679256a06c8SMasatake YAMATO __releases(seq->private->l->lock)
680256a06c8SMasatake YAMATO {
681359745d7SMuchun Song struct bt_sock_list *l = pde_data(file_inode(seq->file));
682256a06c8SMasatake YAMATO
683256a06c8SMasatake YAMATO read_unlock(&l->lock);
684256a06c8SMasatake YAMATO }
685256a06c8SMasatake YAMATO
bt_seq_show(struct seq_file * seq,void * v)686256a06c8SMasatake YAMATO static int bt_seq_show(struct seq_file *seq, void *v)
687256a06c8SMasatake YAMATO {
688359745d7SMuchun Song struct bt_sock_list *l = pde_data(file_inode(seq->file));
689256a06c8SMasatake YAMATO
690256a06c8SMasatake YAMATO if (v == SEQ_START_TOKEN) {
691c5605755SMarcel Holtmann seq_puts(seq, "sk RefCnt Rmem Wmem User Inode Parent");
692256a06c8SMasatake YAMATO
693256a06c8SMasatake YAMATO if (l->custom_seq_show) {
694256a06c8SMasatake YAMATO seq_putc(seq, ' ');
695256a06c8SMasatake YAMATO l->custom_seq_show(seq, v);
696256a06c8SMasatake YAMATO }
697256a06c8SMasatake YAMATO
698256a06c8SMasatake YAMATO seq_putc(seq, '\n');
699256a06c8SMasatake YAMATO } else {
70009d5d4aaSAndrei Emeltchenko struct sock *sk = sk_entry(v);
70109d5d4aaSAndrei Emeltchenko struct bt_sock *bt = bt_sk(sk);
702256a06c8SMasatake YAMATO
7037028a886SAndrei Emeltchenko seq_printf(seq,
7045f6cd79fSMarcel Holtmann "%pK %-6d %-6u %-6u %-6u %-6lu %-6lu",
705256a06c8SMasatake YAMATO sk,
70641c6d650SReshetova, Elena refcount_read(&sk->sk_refcnt),
707256a06c8SMasatake YAMATO sk_rmem_alloc_get(sk),
708256a06c8SMasatake YAMATO sk_wmem_alloc_get(sk),
7091bbb3095SEric W. Biederman from_kuid(seq_user_ns(seq), sock_i_uid(sk)),
710256a06c8SMasatake YAMATO sock_i_ino(sk),
711256a06c8SMasatake YAMATO bt->parent ? sock_i_ino(bt->parent) : 0LU);
712256a06c8SMasatake YAMATO
713256a06c8SMasatake YAMATO if (l->custom_seq_show) {
714256a06c8SMasatake YAMATO seq_putc(seq, ' ');
715256a06c8SMasatake YAMATO l->custom_seq_show(seq, v);
716256a06c8SMasatake YAMATO }
717256a06c8SMasatake YAMATO
718256a06c8SMasatake YAMATO seq_putc(seq, '\n');
719256a06c8SMasatake YAMATO }
720256a06c8SMasatake YAMATO return 0;
721256a06c8SMasatake YAMATO }
722256a06c8SMasatake YAMATO
72326b0f4e2SFabian Frederick static const struct seq_operations bt_seq_ops = {
724256a06c8SMasatake YAMATO .start = bt_seq_start,
725256a06c8SMasatake YAMATO .next = bt_seq_next,
726256a06c8SMasatake YAMATO .stop = bt_seq_stop,
727256a06c8SMasatake YAMATO .show = bt_seq_show,
728256a06c8SMasatake YAMATO };
729256a06c8SMasatake YAMATO
bt_procfs_init(struct net * net,const char * name,struct bt_sock_list * sk_list,int (* seq_show)(struct seq_file *,void *))730b0316615SAl Viro int bt_procfs_init(struct net *net, const char *name,
731256a06c8SMasatake YAMATO struct bt_sock_list *sk_list,
732256a06c8SMasatake YAMATO int (*seq_show)(struct seq_file *, void *))
733256a06c8SMasatake YAMATO {
734256a06c8SMasatake YAMATO sk_list->custom_seq_show = seq_show;
735256a06c8SMasatake YAMATO
736a9170e0aSChristoph Hellwig if (!proc_create_seq_data(name, 0, net->proc_net, &bt_seq_ops, sk_list))
737256a06c8SMasatake YAMATO return -ENOMEM;
738256a06c8SMasatake YAMATO return 0;
739256a06c8SMasatake YAMATO }
740256a06c8SMasatake YAMATO
bt_procfs_cleanup(struct net * net,const char * name)741256a06c8SMasatake YAMATO void bt_procfs_cleanup(struct net *net, const char *name)
742256a06c8SMasatake YAMATO {
743ece31ffdSGao feng remove_proc_entry(name, net->proc_net);
744256a06c8SMasatake YAMATO }
745256a06c8SMasatake YAMATO #else
bt_procfs_init(struct net * net,const char * name,struct bt_sock_list * sk_list,int (* seq_show)(struct seq_file *,void *))746b0316615SAl Viro int bt_procfs_init(struct net *net, const char *name,
747256a06c8SMasatake YAMATO struct bt_sock_list *sk_list,
748256a06c8SMasatake YAMATO int (*seq_show)(struct seq_file *, void *))
749256a06c8SMasatake YAMATO {
750256a06c8SMasatake YAMATO return 0;
751256a06c8SMasatake YAMATO }
752256a06c8SMasatake YAMATO
bt_procfs_cleanup(struct net * net,const char * name)753256a06c8SMasatake YAMATO void bt_procfs_cleanup(struct net *net, const char *name)
754256a06c8SMasatake YAMATO {
755256a06c8SMasatake YAMATO }
756256a06c8SMasatake YAMATO #endif
757256a06c8SMasatake YAMATO EXPORT_SYMBOL(bt_procfs_init);
758256a06c8SMasatake YAMATO EXPORT_SYMBOL(bt_procfs_cleanup);
759256a06c8SMasatake YAMATO
760173e7837Slinzhang static const struct net_proto_family bt_sock_family_ops = {
7611da177e4SLinus Torvalds .owner = THIS_MODULE,
7621da177e4SLinus Torvalds .family = PF_BLUETOOTH,
7631da177e4SLinus Torvalds .create = bt_sock_create,
7641da177e4SLinus Torvalds };
7651da177e4SLinus Torvalds
766ffcecac6SMarcel Holtmann struct dentry *bt_debugfs;
767ffcecac6SMarcel Holtmann EXPORT_SYMBOL_GPL(bt_debugfs);
768ffcecac6SMarcel Holtmann
7699e8305b3SMarcel Holtmann #define VERSION __stringify(BT_SUBSYS_VERSION) "." \
7709e8305b3SMarcel Holtmann __stringify(BT_SUBSYS_REVISION)
7719e8305b3SMarcel Holtmann
bt_init(void)7721da177e4SLinus Torvalds static int __init bt_init(void)
7731da177e4SLinus Torvalds {
77427d35284SMarcel Holtmann int err;
77527d35284SMarcel Holtmann
776b4772ef8SEyal Birger sock_skb_cb_check_size(sizeof(struct bt_skb_cb));
7777cb9d20fSMarcel Holtmann
7789e8305b3SMarcel Holtmann BT_INFO("Core ver %s", VERSION);
7791da177e4SLinus Torvalds
780ee485290SMarcel Holtmann err = bt_selftest();
781ee485290SMarcel Holtmann if (err < 0)
782ee485290SMarcel Holtmann return err;
783ee485290SMarcel Holtmann
784ffcecac6SMarcel Holtmann bt_debugfs = debugfs_create_dir("bluetooth", NULL);
785ffcecac6SMarcel Holtmann
786e64c97b5SMarcel Holtmann bt_leds_init();
787e64c97b5SMarcel Holtmann
78827d35284SMarcel Holtmann err = bt_sysfs_init();
78927d35284SMarcel Holtmann if (err < 0)
7902f3957c7SChen Zhongjin goto cleanup_led;
79127d35284SMarcel Holtmann
79227d35284SMarcel Holtmann err = sock_register(&bt_sock_family_ops);
7931b259904SMarkus Elfring if (err)
7941b259904SMarkus Elfring goto cleanup_sysfs;
7951da177e4SLinus Torvalds
7961da177e4SLinus Torvalds BT_INFO("HCI device and connection manager initialized");
7971da177e4SLinus Torvalds
79864274518SGustavo F. Padovan err = hci_sock_init();
7991b259904SMarkus Elfring if (err)
8001b259904SMarkus Elfring goto unregister_socket;
80164274518SGustavo F. Padovan
80264274518SGustavo F. Padovan err = l2cap_init();
8031b259904SMarkus Elfring if (err)
8041b259904SMarkus Elfring goto cleanup_socket;
80564274518SGustavo F. Padovan
80664274518SGustavo F. Padovan err = sco_init();
8071b259904SMarkus Elfring if (err)
8081b259904SMarkus Elfring goto cleanup_cap;
8091da177e4SLinus Torvalds
8106d785aa3SJohan Hedberg err = mgmt_init();
8111b259904SMarkus Elfring if (err)
8121b259904SMarkus Elfring goto cleanup_sco;
8136d785aa3SJohan Hedberg
8141da177e4SLinus Torvalds return 0;
81564274518SGustavo F. Padovan
8161b259904SMarkus Elfring cleanup_sco:
8171b259904SMarkus Elfring sco_exit();
8181b259904SMarkus Elfring cleanup_cap:
8191b259904SMarkus Elfring l2cap_exit();
8201b259904SMarkus Elfring cleanup_socket:
82164274518SGustavo F. Padovan hci_sock_cleanup();
8221b259904SMarkus Elfring unregister_socket:
82364274518SGustavo F. Padovan sock_unregister(PF_BLUETOOTH);
8241b259904SMarkus Elfring cleanup_sysfs:
82564274518SGustavo F. Padovan bt_sysfs_cleanup();
8262f3957c7SChen Zhongjin cleanup_led:
8272f3957c7SChen Zhongjin bt_leds_cleanup();
82864274518SGustavo F. Padovan return err;
8291da177e4SLinus Torvalds }
8301da177e4SLinus Torvalds
bt_exit(void)8311da177e4SLinus Torvalds static void __exit bt_exit(void)
8321da177e4SLinus Torvalds {
8336d785aa3SJohan Hedberg mgmt_exit();
8346d785aa3SJohan Hedberg
83564274518SGustavo F. Padovan sco_exit();
83664274518SGustavo F. Padovan
83764274518SGustavo F. Padovan l2cap_exit();
83864274518SGustavo F. Padovan
8391da177e4SLinus Torvalds hci_sock_cleanup();
8401da177e4SLinus Torvalds
8411da177e4SLinus Torvalds sock_unregister(PF_BLUETOOTH);
84227d35284SMarcel Holtmann
84327d35284SMarcel Holtmann bt_sysfs_cleanup();
844ffcecac6SMarcel Holtmann
845e64c97b5SMarcel Holtmann bt_leds_cleanup();
846e64c97b5SMarcel Holtmann
847ffcecac6SMarcel Holtmann debugfs_remove_recursive(bt_debugfs);
8481da177e4SLinus Torvalds }
8491da177e4SLinus Torvalds
8501da177e4SLinus Torvalds subsys_initcall(bt_init);
8511da177e4SLinus Torvalds module_exit(bt_exit);
8521da177e4SLinus Torvalds
85363fbd24eSMarcel Holtmann MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
8549e8305b3SMarcel Holtmann MODULE_DESCRIPTION("Bluetooth Core ver " VERSION);
8559e8305b3SMarcel Holtmann MODULE_VERSION(VERSION);
8561da177e4SLinus Torvalds MODULE_LICENSE("GPL");
8571da177e4SLinus Torvalds MODULE_ALIAS_NETPROTO(PF_BLUETOOTH);
858