162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci BlueZ - Bluetooth protocol stack for Linux 362306a36Sopenharmony_ci Copyright (C) 2000-2001 Qualcomm Incorporated 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci This program is free software; you can redistribute it and/or modify 862306a36Sopenharmony_ci it under the terms of the GNU General Public License version 2 as 962306a36Sopenharmony_ci published by the Free Software Foundation; 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1262306a36Sopenharmony_ci OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1362306a36Sopenharmony_ci FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. 1462306a36Sopenharmony_ci IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY 1562306a36Sopenharmony_ci CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 1662306a36Sopenharmony_ci WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1762306a36Sopenharmony_ci ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1862306a36Sopenharmony_ci OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 2162306a36Sopenharmony_ci COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 2262306a36Sopenharmony_ci SOFTWARE IS DISCLAIMED. 2362306a36Sopenharmony_ci*/ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* Bluetooth address family and sockets. */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <linux/module.h> 2862306a36Sopenharmony_ci#include <linux/debugfs.h> 2962306a36Sopenharmony_ci#include <linux/stringify.h> 3062306a36Sopenharmony_ci#include <linux/sched/signal.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <asm/ioctls.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <net/bluetooth/bluetooth.h> 3562306a36Sopenharmony_ci#include <linux/proc_fs.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include "leds.h" 3862306a36Sopenharmony_ci#include "selftest.h" 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* Bluetooth sockets */ 4162306a36Sopenharmony_ci#define BT_MAX_PROTO (BTPROTO_LAST + 1) 4262306a36Sopenharmony_cistatic const struct net_proto_family *bt_proto[BT_MAX_PROTO]; 4362306a36Sopenharmony_cistatic DEFINE_RWLOCK(bt_proto_lock); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic struct lock_class_key bt_lock_key[BT_MAX_PROTO]; 4662306a36Sopenharmony_cistatic const char *const bt_key_strings[BT_MAX_PROTO] = { 4762306a36Sopenharmony_ci "sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP", 4862306a36Sopenharmony_ci "sk_lock-AF_BLUETOOTH-BTPROTO_HCI", 4962306a36Sopenharmony_ci "sk_lock-AF_BLUETOOTH-BTPROTO_SCO", 5062306a36Sopenharmony_ci "sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM", 5162306a36Sopenharmony_ci "sk_lock-AF_BLUETOOTH-BTPROTO_BNEP", 5262306a36Sopenharmony_ci "sk_lock-AF_BLUETOOTH-BTPROTO_CMTP", 5362306a36Sopenharmony_ci "sk_lock-AF_BLUETOOTH-BTPROTO_HIDP", 5462306a36Sopenharmony_ci "sk_lock-AF_BLUETOOTH-BTPROTO_AVDTP", 5562306a36Sopenharmony_ci "sk_lock-AF_BLUETOOTH-BTPROTO_ISO", 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic struct lock_class_key bt_slock_key[BT_MAX_PROTO]; 5962306a36Sopenharmony_cistatic const char *const bt_slock_key_strings[BT_MAX_PROTO] = { 6062306a36Sopenharmony_ci "slock-AF_BLUETOOTH-BTPROTO_L2CAP", 6162306a36Sopenharmony_ci "slock-AF_BLUETOOTH-BTPROTO_HCI", 6262306a36Sopenharmony_ci "slock-AF_BLUETOOTH-BTPROTO_SCO", 6362306a36Sopenharmony_ci "slock-AF_BLUETOOTH-BTPROTO_RFCOMM", 6462306a36Sopenharmony_ci "slock-AF_BLUETOOTH-BTPROTO_BNEP", 6562306a36Sopenharmony_ci "slock-AF_BLUETOOTH-BTPROTO_CMTP", 6662306a36Sopenharmony_ci "slock-AF_BLUETOOTH-BTPROTO_HIDP", 6762306a36Sopenharmony_ci "slock-AF_BLUETOOTH-BTPROTO_AVDTP", 6862306a36Sopenharmony_ci "slock-AF_BLUETOOTH-BTPROTO_ISO", 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_civoid bt_sock_reclassify_lock(struct sock *sk, int proto) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci BUG_ON(!sk); 7462306a36Sopenharmony_ci BUG_ON(!sock_allow_reclassification(sk)); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci sock_lock_init_class_and_name(sk, 7762306a36Sopenharmony_ci bt_slock_key_strings[proto], &bt_slock_key[proto], 7862306a36Sopenharmony_ci bt_key_strings[proto], &bt_lock_key[proto]); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ciEXPORT_SYMBOL(bt_sock_reclassify_lock); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ciint bt_sock_register(int proto, const struct net_proto_family *ops) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci int err = 0; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (proto < 0 || proto >= BT_MAX_PROTO) 8762306a36Sopenharmony_ci return -EINVAL; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci write_lock(&bt_proto_lock); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (bt_proto[proto]) 9262306a36Sopenharmony_ci err = -EEXIST; 9362306a36Sopenharmony_ci else 9462306a36Sopenharmony_ci bt_proto[proto] = ops; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci write_unlock(&bt_proto_lock); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return err; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ciEXPORT_SYMBOL(bt_sock_register); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_civoid bt_sock_unregister(int proto) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci if (proto < 0 || proto >= BT_MAX_PROTO) 10562306a36Sopenharmony_ci return; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci write_lock(&bt_proto_lock); 10862306a36Sopenharmony_ci bt_proto[proto] = NULL; 10962306a36Sopenharmony_ci write_unlock(&bt_proto_lock); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ciEXPORT_SYMBOL(bt_sock_unregister); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int bt_sock_create(struct net *net, struct socket *sock, int proto, 11462306a36Sopenharmony_ci int kern) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci int err; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (net != &init_net) 11962306a36Sopenharmony_ci return -EAFNOSUPPORT; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (proto < 0 || proto >= BT_MAX_PROTO) 12262306a36Sopenharmony_ci return -EINVAL; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (!bt_proto[proto]) 12562306a36Sopenharmony_ci request_module("bt-proto-%d", proto); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci err = -EPROTONOSUPPORT; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci read_lock(&bt_proto_lock); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) { 13262306a36Sopenharmony_ci err = bt_proto[proto]->create(net, sock, proto, kern); 13362306a36Sopenharmony_ci if (!err) 13462306a36Sopenharmony_ci bt_sock_reclassify_lock(sock->sk, proto); 13562306a36Sopenharmony_ci module_put(bt_proto[proto]->owner); 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci read_unlock(&bt_proto_lock); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return err; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistruct sock *bt_sock_alloc(struct net *net, struct socket *sock, 14462306a36Sopenharmony_ci struct proto *prot, int proto, gfp_t prio, int kern) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct sock *sk; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci sk = sk_alloc(net, PF_BLUETOOTH, prio, prot, kern); 14962306a36Sopenharmony_ci if (!sk) 15062306a36Sopenharmony_ci return NULL; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci sock_init_data(sock, sk); 15362306a36Sopenharmony_ci INIT_LIST_HEAD(&bt_sk(sk)->accept_q); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci sock_reset_flag(sk, SOCK_ZAPPED); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci sk->sk_protocol = proto; 15862306a36Sopenharmony_ci sk->sk_state = BT_OPEN; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* Init peer information so it can be properly monitored */ 16162306a36Sopenharmony_ci if (!kern) { 16262306a36Sopenharmony_ci spin_lock(&sk->sk_peer_lock); 16362306a36Sopenharmony_ci sk->sk_peer_pid = get_pid(task_tgid(current)); 16462306a36Sopenharmony_ci sk->sk_peer_cred = get_current_cred(); 16562306a36Sopenharmony_ci spin_unlock(&sk->sk_peer_lock); 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return sk; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ciEXPORT_SYMBOL(bt_sock_alloc); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_civoid bt_sock_link(struct bt_sock_list *l, struct sock *sk) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci write_lock(&l->lock); 17562306a36Sopenharmony_ci sk_add_node(sk, &l->head); 17662306a36Sopenharmony_ci write_unlock(&l->lock); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ciEXPORT_SYMBOL(bt_sock_link); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_civoid bt_sock_unlink(struct bt_sock_list *l, struct sock *sk) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci write_lock(&l->lock); 18362306a36Sopenharmony_ci sk_del_node_init(sk); 18462306a36Sopenharmony_ci write_unlock(&l->lock); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ciEXPORT_SYMBOL(bt_sock_unlink); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_civoid bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci const struct cred *old_cred; 19162306a36Sopenharmony_ci struct pid *old_pid; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci BT_DBG("parent %p, sk %p", parent, sk); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci sock_hold(sk); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (bh) 19862306a36Sopenharmony_ci bh_lock_sock_nested(sk); 19962306a36Sopenharmony_ci else 20062306a36Sopenharmony_ci lock_sock_nested(sk, SINGLE_DEPTH_NESTING); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q); 20362306a36Sopenharmony_ci bt_sk(sk)->parent = parent; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* Copy credentials from parent since for incoming connections the 20662306a36Sopenharmony_ci * socket is allocated by the kernel. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci spin_lock(&sk->sk_peer_lock); 20962306a36Sopenharmony_ci old_pid = sk->sk_peer_pid; 21062306a36Sopenharmony_ci old_cred = sk->sk_peer_cred; 21162306a36Sopenharmony_ci sk->sk_peer_pid = get_pid(parent->sk_peer_pid); 21262306a36Sopenharmony_ci sk->sk_peer_cred = get_cred(parent->sk_peer_cred); 21362306a36Sopenharmony_ci spin_unlock(&sk->sk_peer_lock); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci put_pid(old_pid); 21662306a36Sopenharmony_ci put_cred(old_cred); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (bh) 21962306a36Sopenharmony_ci bh_unlock_sock(sk); 22062306a36Sopenharmony_ci else 22162306a36Sopenharmony_ci release_sock(sk); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci sk_acceptq_added(parent); 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ciEXPORT_SYMBOL(bt_accept_enqueue); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/* Calling function must hold the sk lock. 22862306a36Sopenharmony_ci * bt_sk(sk)->parent must be non-NULL meaning sk is in the parent list. 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_civoid bt_accept_unlink(struct sock *sk) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci BT_DBG("sk %p state %d", sk, sk->sk_state); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci list_del_init(&bt_sk(sk)->accept_q); 23562306a36Sopenharmony_ci sk_acceptq_removed(bt_sk(sk)->parent); 23662306a36Sopenharmony_ci bt_sk(sk)->parent = NULL; 23762306a36Sopenharmony_ci sock_put(sk); 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ciEXPORT_SYMBOL(bt_accept_unlink); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistruct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct bt_sock *s, *n; 24462306a36Sopenharmony_ci struct sock *sk; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci BT_DBG("parent %p", parent); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cirestart: 24962306a36Sopenharmony_ci list_for_each_entry_safe(s, n, &bt_sk(parent)->accept_q, accept_q) { 25062306a36Sopenharmony_ci sk = (struct sock *)s; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* Prevent early freeing of sk due to unlink and sock_kill */ 25362306a36Sopenharmony_ci sock_hold(sk); 25462306a36Sopenharmony_ci lock_sock(sk); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* Check sk has not already been unlinked via 25762306a36Sopenharmony_ci * bt_accept_unlink() due to serialisation caused by sk locking 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ci if (!bt_sk(sk)->parent) { 26062306a36Sopenharmony_ci BT_DBG("sk %p, already unlinked", sk); 26162306a36Sopenharmony_ci release_sock(sk); 26262306a36Sopenharmony_ci sock_put(sk); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* Restart the loop as sk is no longer in the list 26562306a36Sopenharmony_ci * and also avoid a potential infinite loop because 26662306a36Sopenharmony_ci * list_for_each_entry_safe() is not thread safe. 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_ci goto restart; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* sk is safely in the parent list so reduce reference count */ 27262306a36Sopenharmony_ci sock_put(sk); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* FIXME: Is this check still needed */ 27562306a36Sopenharmony_ci if (sk->sk_state == BT_CLOSED) { 27662306a36Sopenharmony_ci bt_accept_unlink(sk); 27762306a36Sopenharmony_ci release_sock(sk); 27862306a36Sopenharmony_ci continue; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (sk->sk_state == BT_CONNECTED || !newsock || 28262306a36Sopenharmony_ci test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) { 28362306a36Sopenharmony_ci bt_accept_unlink(sk); 28462306a36Sopenharmony_ci if (newsock) 28562306a36Sopenharmony_ci sock_graft(sk, newsock); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci release_sock(sk); 28862306a36Sopenharmony_ci return sk; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci release_sock(sk); 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci return NULL; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ciEXPORT_SYMBOL(bt_accept_dequeue); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ciint bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, 29962306a36Sopenharmony_ci int flags) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct sock *sk = sock->sk; 30262306a36Sopenharmony_ci struct sk_buff *skb; 30362306a36Sopenharmony_ci size_t copied; 30462306a36Sopenharmony_ci size_t skblen; 30562306a36Sopenharmony_ci int err; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci BT_DBG("sock %p sk %p len %zu", sock, sk, len); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (flags & MSG_OOB) 31062306a36Sopenharmony_ci return -EOPNOTSUPP; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci skb = skb_recv_datagram(sk, flags, &err); 31362306a36Sopenharmony_ci if (!skb) { 31462306a36Sopenharmony_ci if (sk->sk_shutdown & RCV_SHUTDOWN) 31562306a36Sopenharmony_ci err = 0; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return err; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci skblen = skb->len; 32162306a36Sopenharmony_ci copied = skb->len; 32262306a36Sopenharmony_ci if (len < copied) { 32362306a36Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 32462306a36Sopenharmony_ci copied = len; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci skb_reset_transport_header(skb); 32862306a36Sopenharmony_ci err = skb_copy_datagram_msg(skb, 0, msg, copied); 32962306a36Sopenharmony_ci if (err == 0) { 33062306a36Sopenharmony_ci sock_recv_cmsgs(msg, sk, skb); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (msg->msg_name && bt_sk(sk)->skb_msg_name) 33362306a36Sopenharmony_ci bt_sk(sk)->skb_msg_name(skb, msg->msg_name, 33462306a36Sopenharmony_ci &msg->msg_namelen); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (test_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags)) { 33762306a36Sopenharmony_ci u8 pkt_status = hci_skb_pkt_status(skb); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci put_cmsg(msg, SOL_BLUETOOTH, BT_SCM_PKT_STATUS, 34062306a36Sopenharmony_ci sizeof(pkt_status), &pkt_status); 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci skb_free_datagram(sk, skb); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (flags & MSG_TRUNC) 34762306a36Sopenharmony_ci copied = skblen; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci return err ? : copied; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ciEXPORT_SYMBOL(bt_sock_recvmsg); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic long bt_sock_data_wait(struct sock *sk, long timeo) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci add_wait_queue(sk_sleep(sk), &wait); 35862306a36Sopenharmony_ci for (;;) { 35962306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (!skb_queue_empty(&sk->sk_receive_queue)) 36262306a36Sopenharmony_ci break; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN)) 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (signal_pending(current) || !timeo) 36862306a36Sopenharmony_ci break; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); 37162306a36Sopenharmony_ci release_sock(sk); 37262306a36Sopenharmony_ci timeo = schedule_timeout(timeo); 37362306a36Sopenharmony_ci lock_sock(sk); 37462306a36Sopenharmony_ci sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci __set_current_state(TASK_RUNNING); 37862306a36Sopenharmony_ci remove_wait_queue(sk_sleep(sk), &wait); 37962306a36Sopenharmony_ci return timeo; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ciint bt_sock_stream_recvmsg(struct socket *sock, struct msghdr *msg, 38362306a36Sopenharmony_ci size_t size, int flags) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct sock *sk = sock->sk; 38662306a36Sopenharmony_ci int err = 0; 38762306a36Sopenharmony_ci size_t target, copied = 0; 38862306a36Sopenharmony_ci long timeo; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (flags & MSG_OOB) 39162306a36Sopenharmony_ci return -EOPNOTSUPP; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci BT_DBG("sk %p size %zu", sk, size); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci lock_sock(sk); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci target = sock_rcvlowat(sk, flags & MSG_WAITALL, size); 39862306a36Sopenharmony_ci timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci do { 40162306a36Sopenharmony_ci struct sk_buff *skb; 40262306a36Sopenharmony_ci int chunk; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci skb = skb_dequeue(&sk->sk_receive_queue); 40562306a36Sopenharmony_ci if (!skb) { 40662306a36Sopenharmony_ci if (copied >= target) 40762306a36Sopenharmony_ci break; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci err = sock_error(sk); 41062306a36Sopenharmony_ci if (err) 41162306a36Sopenharmony_ci break; 41262306a36Sopenharmony_ci if (sk->sk_shutdown & RCV_SHUTDOWN) 41362306a36Sopenharmony_ci break; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci err = -EAGAIN; 41662306a36Sopenharmony_ci if (!timeo) 41762306a36Sopenharmony_ci break; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci timeo = bt_sock_data_wait(sk, timeo); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (signal_pending(current)) { 42262306a36Sopenharmony_ci err = sock_intr_errno(timeo); 42362306a36Sopenharmony_ci goto out; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci continue; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci chunk = min_t(unsigned int, skb->len, size); 42962306a36Sopenharmony_ci if (skb_copy_datagram_msg(skb, 0, msg, chunk)) { 43062306a36Sopenharmony_ci skb_queue_head(&sk->sk_receive_queue, skb); 43162306a36Sopenharmony_ci if (!copied) 43262306a36Sopenharmony_ci copied = -EFAULT; 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci copied += chunk; 43662306a36Sopenharmony_ci size -= chunk; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci sock_recv_cmsgs(msg, sk, skb); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (!(flags & MSG_PEEK)) { 44162306a36Sopenharmony_ci int skb_len = skb_headlen(skb); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (chunk <= skb_len) { 44462306a36Sopenharmony_ci __skb_pull(skb, chunk); 44562306a36Sopenharmony_ci } else { 44662306a36Sopenharmony_ci struct sk_buff *frag; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci __skb_pull(skb, skb_len); 44962306a36Sopenharmony_ci chunk -= skb_len; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci skb_walk_frags(skb, frag) { 45262306a36Sopenharmony_ci if (chunk <= frag->len) { 45362306a36Sopenharmony_ci /* Pulling partial data */ 45462306a36Sopenharmony_ci skb->len -= chunk; 45562306a36Sopenharmony_ci skb->data_len -= chunk; 45662306a36Sopenharmony_ci __skb_pull(frag, chunk); 45762306a36Sopenharmony_ci break; 45862306a36Sopenharmony_ci } else if (frag->len) { 45962306a36Sopenharmony_ci /* Pulling all frag data */ 46062306a36Sopenharmony_ci chunk -= frag->len; 46162306a36Sopenharmony_ci skb->len -= frag->len; 46262306a36Sopenharmony_ci skb->data_len -= frag->len; 46362306a36Sopenharmony_ci __skb_pull(frag, frag->len); 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (skb->len) { 46962306a36Sopenharmony_ci skb_queue_head(&sk->sk_receive_queue, skb); 47062306a36Sopenharmony_ci break; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci kfree_skb(skb); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci } else { 47562306a36Sopenharmony_ci /* put message back and return */ 47662306a36Sopenharmony_ci skb_queue_head(&sk->sk_receive_queue, skb); 47762306a36Sopenharmony_ci break; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci } while (size); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ciout: 48262306a36Sopenharmony_ci release_sock(sk); 48362306a36Sopenharmony_ci return copied ? : err; 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ciEXPORT_SYMBOL(bt_sock_stream_recvmsg); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic inline __poll_t bt_accept_poll(struct sock *parent) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct bt_sock *s, *n; 49062306a36Sopenharmony_ci struct sock *sk; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci list_for_each_entry_safe(s, n, &bt_sk(parent)->accept_q, accept_q) { 49362306a36Sopenharmony_ci sk = (struct sock *)s; 49462306a36Sopenharmony_ci if (sk->sk_state == BT_CONNECTED || 49562306a36Sopenharmony_ci (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags) && 49662306a36Sopenharmony_ci sk->sk_state == BT_CONNECT2)) 49762306a36Sopenharmony_ci return EPOLLIN | EPOLLRDNORM; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return 0; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci__poll_t bt_sock_poll(struct file *file, struct socket *sock, 50462306a36Sopenharmony_ci poll_table *wait) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct sock *sk = sock->sk; 50762306a36Sopenharmony_ci __poll_t mask = 0; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci poll_wait(file, sk_sleep(sk), wait); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (sk->sk_state == BT_LISTEN) 51262306a36Sopenharmony_ci return bt_accept_poll(sk); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue)) 51562306a36Sopenharmony_ci mask |= EPOLLERR | 51662306a36Sopenharmony_ci (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? EPOLLPRI : 0); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (sk->sk_shutdown & RCV_SHUTDOWN) 51962306a36Sopenharmony_ci mask |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (sk->sk_shutdown == SHUTDOWN_MASK) 52262306a36Sopenharmony_ci mask |= EPOLLHUP; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (!skb_queue_empty_lockless(&sk->sk_receive_queue)) 52562306a36Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (sk->sk_state == BT_CLOSED) 52862306a36Sopenharmony_ci mask |= EPOLLHUP; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci if (sk->sk_state == BT_CONNECT || 53162306a36Sopenharmony_ci sk->sk_state == BT_CONNECT2 || 53262306a36Sopenharmony_ci sk->sk_state == BT_CONFIG) 53362306a36Sopenharmony_ci return mask; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (!test_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags) && sock_writeable(sk)) 53662306a36Sopenharmony_ci mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; 53762306a36Sopenharmony_ci else 53862306a36Sopenharmony_ci sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci return mask; 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ciEXPORT_SYMBOL(bt_sock_poll); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ciint bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci struct sock *sk = sock->sk; 54762306a36Sopenharmony_ci struct sk_buff *skb; 54862306a36Sopenharmony_ci long amount; 54962306a36Sopenharmony_ci int err; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci switch (cmd) { 55462306a36Sopenharmony_ci case TIOCOUTQ: 55562306a36Sopenharmony_ci if (sk->sk_state == BT_LISTEN) 55662306a36Sopenharmony_ci return -EINVAL; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); 55962306a36Sopenharmony_ci if (amount < 0) 56062306a36Sopenharmony_ci amount = 0; 56162306a36Sopenharmony_ci err = put_user(amount, (int __user *)arg); 56262306a36Sopenharmony_ci break; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci case TIOCINQ: 56562306a36Sopenharmony_ci if (sk->sk_state == BT_LISTEN) 56662306a36Sopenharmony_ci return -EINVAL; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci spin_lock(&sk->sk_receive_queue.lock); 56962306a36Sopenharmony_ci skb = skb_peek(&sk->sk_receive_queue); 57062306a36Sopenharmony_ci amount = skb ? skb->len : 0; 57162306a36Sopenharmony_ci spin_unlock(&sk->sk_receive_queue.lock); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci err = put_user(amount, (int __user *)arg); 57462306a36Sopenharmony_ci break; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci default: 57762306a36Sopenharmony_ci err = -ENOIOCTLCMD; 57862306a36Sopenharmony_ci break; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci return err; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ciEXPORT_SYMBOL(bt_sock_ioctl); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci/* This function expects the sk lock to be held when called */ 58662306a36Sopenharmony_ciint bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 58962306a36Sopenharmony_ci int err = 0; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci BT_DBG("sk %p", sk); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci add_wait_queue(sk_sleep(sk), &wait); 59462306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 59562306a36Sopenharmony_ci while (sk->sk_state != state) { 59662306a36Sopenharmony_ci if (!timeo) { 59762306a36Sopenharmony_ci err = -EINPROGRESS; 59862306a36Sopenharmony_ci break; 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (signal_pending(current)) { 60262306a36Sopenharmony_ci err = sock_intr_errno(timeo); 60362306a36Sopenharmony_ci break; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci release_sock(sk); 60762306a36Sopenharmony_ci timeo = schedule_timeout(timeo); 60862306a36Sopenharmony_ci lock_sock(sk); 60962306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci err = sock_error(sk); 61262306a36Sopenharmony_ci if (err) 61362306a36Sopenharmony_ci break; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci __set_current_state(TASK_RUNNING); 61662306a36Sopenharmony_ci remove_wait_queue(sk_sleep(sk), &wait); 61762306a36Sopenharmony_ci return err; 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ciEXPORT_SYMBOL(bt_sock_wait_state); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci/* This function expects the sk lock to be held when called */ 62262306a36Sopenharmony_ciint bt_sock_wait_ready(struct sock *sk, unsigned int msg_flags) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 62562306a36Sopenharmony_ci unsigned long timeo; 62662306a36Sopenharmony_ci int err = 0; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci BT_DBG("sk %p", sk); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci timeo = sock_sndtimeo(sk, !!(msg_flags & MSG_DONTWAIT)); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci add_wait_queue(sk_sleep(sk), &wait); 63362306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 63462306a36Sopenharmony_ci while (test_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags)) { 63562306a36Sopenharmony_ci if (!timeo) { 63662306a36Sopenharmony_ci err = -EAGAIN; 63762306a36Sopenharmony_ci break; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci if (signal_pending(current)) { 64162306a36Sopenharmony_ci err = sock_intr_errno(timeo); 64262306a36Sopenharmony_ci break; 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci release_sock(sk); 64662306a36Sopenharmony_ci timeo = schedule_timeout(timeo); 64762306a36Sopenharmony_ci lock_sock(sk); 64862306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci err = sock_error(sk); 65162306a36Sopenharmony_ci if (err) 65262306a36Sopenharmony_ci break; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci __set_current_state(TASK_RUNNING); 65562306a36Sopenharmony_ci remove_wait_queue(sk_sleep(sk), &wait); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci return err; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ciEXPORT_SYMBOL(bt_sock_wait_ready); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 66262306a36Sopenharmony_cistatic void *bt_seq_start(struct seq_file *seq, loff_t *pos) 66362306a36Sopenharmony_ci __acquires(seq->private->l->lock) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci struct bt_sock_list *l = pde_data(file_inode(seq->file)); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci read_lock(&l->lock); 66862306a36Sopenharmony_ci return seq_hlist_start_head(&l->head, *pos); 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic void *bt_seq_next(struct seq_file *seq, void *v, loff_t *pos) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci struct bt_sock_list *l = pde_data(file_inode(seq->file)); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci return seq_hlist_next(v, &l->head, pos); 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic void bt_seq_stop(struct seq_file *seq, void *v) 67962306a36Sopenharmony_ci __releases(seq->private->l->lock) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci struct bt_sock_list *l = pde_data(file_inode(seq->file)); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci read_unlock(&l->lock); 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic int bt_seq_show(struct seq_file *seq, void *v) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci struct bt_sock_list *l = pde_data(file_inode(seq->file)); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (v == SEQ_START_TOKEN) { 69162306a36Sopenharmony_ci seq_puts(seq, "sk RefCnt Rmem Wmem User Inode Parent"); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci if (l->custom_seq_show) { 69462306a36Sopenharmony_ci seq_putc(seq, ' '); 69562306a36Sopenharmony_ci l->custom_seq_show(seq, v); 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci seq_putc(seq, '\n'); 69962306a36Sopenharmony_ci } else { 70062306a36Sopenharmony_ci struct sock *sk = sk_entry(v); 70162306a36Sopenharmony_ci struct bt_sock *bt = bt_sk(sk); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci seq_printf(seq, 70462306a36Sopenharmony_ci "%pK %-6d %-6u %-6u %-6u %-6lu %-6lu", 70562306a36Sopenharmony_ci sk, 70662306a36Sopenharmony_ci refcount_read(&sk->sk_refcnt), 70762306a36Sopenharmony_ci sk_rmem_alloc_get(sk), 70862306a36Sopenharmony_ci sk_wmem_alloc_get(sk), 70962306a36Sopenharmony_ci from_kuid(seq_user_ns(seq), sock_i_uid(sk)), 71062306a36Sopenharmony_ci sock_i_ino(sk), 71162306a36Sopenharmony_ci bt->parent ? sock_i_ino(bt->parent) : 0LU); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci if (l->custom_seq_show) { 71462306a36Sopenharmony_ci seq_putc(seq, ' '); 71562306a36Sopenharmony_ci l->custom_seq_show(seq, v); 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci seq_putc(seq, '\n'); 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci return 0; 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistatic const struct seq_operations bt_seq_ops = { 72462306a36Sopenharmony_ci .start = bt_seq_start, 72562306a36Sopenharmony_ci .next = bt_seq_next, 72662306a36Sopenharmony_ci .stop = bt_seq_stop, 72762306a36Sopenharmony_ci .show = bt_seq_show, 72862306a36Sopenharmony_ci}; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ciint bt_procfs_init(struct net *net, const char *name, 73162306a36Sopenharmony_ci struct bt_sock_list *sk_list, 73262306a36Sopenharmony_ci int (*seq_show)(struct seq_file *, void *)) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci sk_list->custom_seq_show = seq_show; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (!proc_create_seq_data(name, 0, net->proc_net, &bt_seq_ops, sk_list)) 73762306a36Sopenharmony_ci return -ENOMEM; 73862306a36Sopenharmony_ci return 0; 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_civoid bt_procfs_cleanup(struct net *net, const char *name) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci remove_proc_entry(name, net->proc_net); 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci#else 74662306a36Sopenharmony_ciint bt_procfs_init(struct net *net, const char *name, 74762306a36Sopenharmony_ci struct bt_sock_list *sk_list, 74862306a36Sopenharmony_ci int (*seq_show)(struct seq_file *, void *)) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci return 0; 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_civoid bt_procfs_cleanup(struct net *net, const char *name) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci#endif 75762306a36Sopenharmony_ciEXPORT_SYMBOL(bt_procfs_init); 75862306a36Sopenharmony_ciEXPORT_SYMBOL(bt_procfs_cleanup); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic const struct net_proto_family bt_sock_family_ops = { 76162306a36Sopenharmony_ci .owner = THIS_MODULE, 76262306a36Sopenharmony_ci .family = PF_BLUETOOTH, 76362306a36Sopenharmony_ci .create = bt_sock_create, 76462306a36Sopenharmony_ci}; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_cistruct dentry *bt_debugfs; 76762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bt_debugfs); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci#define VERSION __stringify(BT_SUBSYS_VERSION) "." \ 77062306a36Sopenharmony_ci __stringify(BT_SUBSYS_REVISION) 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cistatic int __init bt_init(void) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci int err; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci sock_skb_cb_check_size(sizeof(struct bt_skb_cb)); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci BT_INFO("Core ver %s", VERSION); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci err = bt_selftest(); 78162306a36Sopenharmony_ci if (err < 0) 78262306a36Sopenharmony_ci return err; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci bt_debugfs = debugfs_create_dir("bluetooth", NULL); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci bt_leds_init(); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci err = bt_sysfs_init(); 78962306a36Sopenharmony_ci if (err < 0) 79062306a36Sopenharmony_ci goto cleanup_led; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci err = sock_register(&bt_sock_family_ops); 79362306a36Sopenharmony_ci if (err) 79462306a36Sopenharmony_ci goto cleanup_sysfs; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci BT_INFO("HCI device and connection manager initialized"); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci err = hci_sock_init(); 79962306a36Sopenharmony_ci if (err) 80062306a36Sopenharmony_ci goto unregister_socket; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci err = l2cap_init(); 80362306a36Sopenharmony_ci if (err) 80462306a36Sopenharmony_ci goto cleanup_socket; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci err = sco_init(); 80762306a36Sopenharmony_ci if (err) 80862306a36Sopenharmony_ci goto cleanup_cap; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci err = mgmt_init(); 81162306a36Sopenharmony_ci if (err) 81262306a36Sopenharmony_ci goto cleanup_sco; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci return 0; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_cicleanup_sco: 81762306a36Sopenharmony_ci sco_exit(); 81862306a36Sopenharmony_cicleanup_cap: 81962306a36Sopenharmony_ci l2cap_exit(); 82062306a36Sopenharmony_cicleanup_socket: 82162306a36Sopenharmony_ci hci_sock_cleanup(); 82262306a36Sopenharmony_ciunregister_socket: 82362306a36Sopenharmony_ci sock_unregister(PF_BLUETOOTH); 82462306a36Sopenharmony_cicleanup_sysfs: 82562306a36Sopenharmony_ci bt_sysfs_cleanup(); 82662306a36Sopenharmony_cicleanup_led: 82762306a36Sopenharmony_ci bt_leds_cleanup(); 82862306a36Sopenharmony_ci return err; 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic void __exit bt_exit(void) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci mgmt_exit(); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci sco_exit(); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci l2cap_exit(); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci hci_sock_cleanup(); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci sock_unregister(PF_BLUETOOTH); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci bt_sysfs_cleanup(); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci bt_leds_cleanup(); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci debugfs_remove_recursive(bt_debugfs); 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cisubsys_initcall(bt_init); 85162306a36Sopenharmony_cimodule_exit(bt_exit); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ciMODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); 85462306a36Sopenharmony_ciMODULE_DESCRIPTION("Bluetooth Core ver " VERSION); 85562306a36Sopenharmony_ciMODULE_VERSION(VERSION); 85662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 85762306a36Sopenharmony_ciMODULE_ALIAS_NETPROTO(PF_BLUETOOTH); 858