aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth_tizen
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth_tizen')
-rw-r--r--net/bluetooth_tizen/Kconfig49
-rw-r--r--net/bluetooth_tizen/Makefile12
-rw-r--r--net/bluetooth_tizen/af_bluetooth.c616
-rw-r--r--net/bluetooth_tizen/bnep/Kconfig24
-rw-r--r--net/bluetooth_tizen/bnep/Makefile7
-rw-r--r--net/bluetooth_tizen/bnep/bnep.h180
-rw-r--r--net/bluetooth_tizen/bnep/core.c747
-rw-r--r--net/bluetooth_tizen/bnep/netdev.c238
-rw-r--r--net/bluetooth_tizen/bnep/sock.c259
-rw-r--r--net/bluetooth_tizen/cmtp/Kconfig11
-rw-r--r--net/bluetooth_tizen/cmtp/Makefile7
-rw-r--r--net/bluetooth_tizen/cmtp/capi.c624
-rw-r--r--net/bluetooth_tizen/cmtp/cmtp.h129
-rw-r--r--net/bluetooth_tizen/cmtp/core.c500
-rw-r--r--net/bluetooth_tizen/cmtp/sock.c253
-rw-r--r--net/bluetooth_tizen/hci_conn.c984
-rw-r--r--net/bluetooth_tizen/hci_core.c2966
-rw-r--r--net/bluetooth_tizen/hci_event.c3604
-rw-r--r--net/bluetooth_tizen/hci_sock.c1102
-rw-r--r--net/bluetooth_tizen/hci_sysfs.c588
-rw-r--r--net/bluetooth_tizen/hidp/Kconfig12
-rw-r--r--net/bluetooth_tizen/hidp/Makefile7
-rw-r--r--net/bluetooth_tizen/hidp/core.c1242
-rw-r--r--net/bluetooth_tizen/hidp/hidp.h191
-rw-r--r--net/bluetooth_tizen/hidp/sock.c305
-rw-r--r--net/bluetooth_tizen/l2cap_core.c4803
-rw-r--r--net/bluetooth_tizen/l2cap_sock.c1156
-rw-r--r--net/bluetooth_tizen/lib.c192
-rw-r--r--net/bluetooth_tizen/mgmt.c3599
-rw-r--r--net/bluetooth_tizen/rfcomm/Kconfig17
-rw-r--r--net/bluetooth_tizen/rfcomm/Makefile8
-rw-r--r--net/bluetooth_tizen/rfcomm/core.c2245
-rw-r--r--net/bluetooth_tizen/rfcomm/sock.c1078
-rw-r--r--net/bluetooth_tizen/rfcomm/tty.c1188
-rw-r--r--net/bluetooth_tizen/sco.c1061
-rw-r--r--net/bluetooth_tizen/smp.c1003
36 files changed, 0 insertions, 31007 deletions
diff --git a/net/bluetooth_tizen/Kconfig b/net/bluetooth_tizen/Kconfig
deleted file mode 100644
index 6d17deb..0000000
--- a/net/bluetooth_tizen/Kconfig
+++ /dev/null
@@ -1,49 +0,0 @@
-#
-# Bluetooth subsystem configuration
-#
-
-menuconfig BT
- tristate "Bluetooth subsystem support(Tizen)"
- depends on NET && !S390
- depends on RFKILL || !RFKILL
- select CRC16
- select CRYPTO
- select CRYPTO_BLKCIPHER
- select CRYPTO_AES
- select CRYPTO_ECB
- help
- Bluetooth is low-cost, low-power, short-range wireless technology.
- It was designed as a replacement for cables and other short-range
- technologies like IrDA. Bluetooth operates in personal area range
- that typically extends up to 10 meters. More information about
- Bluetooth can be found at <http://www.bluetooth.com/>.
-
- Linux Bluetooth subsystem consist of several layers:
- Bluetooth Core
- HCI device and connection manager, scheduler
- SCO audio links
- L2CAP (Logical Link Control and Adaptation Protocol)
- SMP (Security Manager Protocol) on LE (Low Energy) links
- HCI Device drivers (Interface to the hardware)
- RFCOMM Module (RFCOMM Protocol)
- BNEP Module (Bluetooth Network Encapsulation Protocol)
- CMTP Module (CAPI Message Transport Protocol)
- HIDP Module (Human Interface Device Protocol)
-
- Say Y here to compile Bluetooth support into the kernel or say M to
- compile it as module (bluetooth).
-
- To use Linux Bluetooth subsystem, you will need several user-space
- utilities like hciconfig and bluetoothd. These utilities and updates
- to Bluetooth kernel modules are provided in the BlueZ packages. For
- more information, see <http://www.bluez.org/>.
-
-source "net/bluetooth_tizen/rfcomm/Kconfig"
-
-source "net/bluetooth_tizen/bnep/Kconfig"
-
-source "net/bluetooth_tizen/cmtp/Kconfig"
-
-source "net/bluetooth_tizen/hidp/Kconfig"
-
-source "drivers/bluetooth_tizen/Kconfig"
diff --git a/net/bluetooth_tizen/Makefile b/net/bluetooth_tizen/Makefile
deleted file mode 100644
index 2dc5a57..0000000
--- a/net/bluetooth_tizen/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Makefile for the Linux Bluetooth subsystem.
-#
-
-obj-$(CONFIG_BT) += bluetooth.o
-obj-$(CONFIG_BT_RFCOMM) += rfcomm/
-obj-$(CONFIG_BT_BNEP) += bnep/
-obj-$(CONFIG_BT_CMTP) += cmtp/
-obj-$(CONFIG_BT_HIDP) += hidp/
-
-bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
- hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o
diff --git a/net/bluetooth_tizen/af_bluetooth.c b/net/bluetooth_tizen/af_bluetooth.c
deleted file mode 100644
index 6fb68a9..0000000
--- a/net/bluetooth_tizen/af_bluetooth.c
+++ /dev/null
@@ -1,616 +0,0 @@
-/*
- BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
-
- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/* Bluetooth address family and sockets. */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <net/sock.h>
-#include <asm/ioctls.h>
-#include <linux/kmod.h>
-
-#include <net/bluetooth/bluetooth.h>
-
-#define VERSION "2.16"
-
-/* Bluetooth sockets */
-#define BT_MAX_PROTO 8
-static const struct net_proto_family *bt_proto[BT_MAX_PROTO];
-static DEFINE_RWLOCK(bt_proto_lock);
-
-static struct lock_class_key bt_lock_key[BT_MAX_PROTO];
-static const char *const bt_key_strings[BT_MAX_PROTO] = {
- "sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP",
- "sk_lock-AF_BLUETOOTH-BTPROTO_HCI",
- "sk_lock-AF_BLUETOOTH-BTPROTO_SCO",
- "sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM",
- "sk_lock-AF_BLUETOOTH-BTPROTO_BNEP",
- "sk_lock-AF_BLUETOOTH-BTPROTO_CMTP",
- "sk_lock-AF_BLUETOOTH-BTPROTO_HIDP",
- "sk_lock-AF_BLUETOOTH-BTPROTO_AVDTP",
-};
-
-static struct lock_class_key bt_slock_key[BT_MAX_PROTO];
-static const char *const bt_slock_key_strings[BT_MAX_PROTO] = {
- "slock-AF_BLUETOOTH-BTPROTO_L2CAP",
- "slock-AF_BLUETOOTH-BTPROTO_HCI",
- "slock-AF_BLUETOOTH-BTPROTO_SCO",
- "slock-AF_BLUETOOTH-BTPROTO_RFCOMM",
- "slock-AF_BLUETOOTH-BTPROTO_BNEP",
- "slock-AF_BLUETOOTH-BTPROTO_CMTP",
- "slock-AF_BLUETOOTH-BTPROTO_HIDP",
- "slock-AF_BLUETOOTH-BTPROTO_AVDTP",
-};
-
-void bt_sock_reclassify_lock(struct sock *sk, int proto)
-{
- BUG_ON(!sk);
- BUG_ON(sock_owned_by_user(sk));
-
- sock_lock_init_class_and_name(sk,
- bt_slock_key_strings[proto], &bt_slock_key[proto],
- bt_key_strings[proto], &bt_lock_key[proto]);
-}
-EXPORT_SYMBOL(bt_sock_reclassify_lock);
-
-int bt_sock_register(int proto, const struct net_proto_family *ops)
-{
- int err = 0;
-
- if (proto < 0 || proto >= BT_MAX_PROTO)
- return -EINVAL;
-
- write_lock(&bt_proto_lock);
-
- if (bt_proto[proto])
- err = -EEXIST;
- else
- bt_proto[proto] = ops;
-
- write_unlock(&bt_proto_lock);
-
- return err;
-}
-EXPORT_SYMBOL(bt_sock_register);
-
-int bt_sock_unregister(int proto)
-{
- int err = 0;
-
- if (proto < 0 || proto >= BT_MAX_PROTO)
- return -EINVAL;
-
- write_lock(&bt_proto_lock);
-
- if (!bt_proto[proto])
- err = -ENOENT;
- else
- bt_proto[proto] = NULL;
-
- write_unlock(&bt_proto_lock);
-
- return err;
-}
-EXPORT_SYMBOL(bt_sock_unregister);
-
-static int bt_sock_create(struct net *net, struct socket *sock, int proto,
- int kern)
-{
- int err;
-
- if (net != &init_net)
- return -EAFNOSUPPORT;
-
- if (proto < 0 || proto >= BT_MAX_PROTO)
- return -EINVAL;
-
- if (!bt_proto[proto])
- request_module("bt-proto-%d", proto);
-
- err = -EPROTONOSUPPORT;
-
- read_lock(&bt_proto_lock);
-
- if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) {
- err = bt_proto[proto]->create(net, sock, proto, kern);
- if (!err)
- bt_sock_reclassify_lock(sock->sk, proto);
- module_put(bt_proto[proto]->owner);
- }
-
- read_unlock(&bt_proto_lock);
-
- return err;
-}
-
-void bt_sock_link(struct bt_sock_list *l, struct sock *sk)
-{
- write_lock(&l->lock);
- sk_add_node(sk, &l->head);
- write_unlock(&l->lock);
-}
-EXPORT_SYMBOL(bt_sock_link);
-
-void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk)
-{
- write_lock(&l->lock);
- sk_del_node_init(sk);
- write_unlock(&l->lock);
-}
-EXPORT_SYMBOL(bt_sock_unlink);
-
-void bt_accept_enqueue(struct sock *parent, struct sock *sk)
-{
- BT_DBG("parent %p, sk %p", parent, sk);
-
- sock_hold(sk);
- list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q);
- bt_sk(sk)->parent = parent;
- parent->sk_ack_backlog++;
-}
-EXPORT_SYMBOL(bt_accept_enqueue);
-
-void bt_accept_unlink(struct sock *sk)
-{
- BT_DBG("sk %p state %d", sk, sk->sk_state);
-
- list_del_init(&bt_sk(sk)->accept_q);
- bt_sk(sk)->parent->sk_ack_backlog--;
- bt_sk(sk)->parent = NULL;
- sock_put(sk);
-}
-EXPORT_SYMBOL(bt_accept_unlink);
-
-struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
-{
- struct list_head *p, *n;
- struct sock *sk;
-
- BT_DBG("parent %p", parent);
-
- list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
- sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
-
- lock_sock(sk);
-
- /* FIXME: Is this check still needed */
- if (sk->sk_state == BT_CLOSED) {
- release_sock(sk);
- bt_accept_unlink(sk);
- continue;
- }
-
- if (sk->sk_state == BT_CONNECTED || !newsock ||
- bt_sk(parent)->defer_setup) {
- bt_accept_unlink(sk);
- if (newsock)
- sock_graft(sk, newsock);
-
- release_sock(sk);
- return sk;
- }
-
- release_sock(sk);
- }
-
- return NULL;
-}
-EXPORT_SYMBOL(bt_accept_dequeue);
-
-int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t len, int flags)
-{
- int noblock = flags & MSG_DONTWAIT;
- struct sock *sk = sock->sk;
- struct sk_buff *skb;
- size_t copied;
- int err;
-
- BT_DBG("sock %p sk %p len %zu", sock, sk, len);
-
- if (flags & (MSG_OOB))
- return -EOPNOTSUPP;
-
- skb = skb_recv_datagram(sk, flags, noblock, &err);
- if (!skb) {
- if (sk->sk_shutdown & RCV_SHUTDOWN)
- return 0;
- return err;
- }
-
- msg->msg_namelen = 0;
-
- copied = skb->len;
- if (len < copied) {
- msg->msg_flags |= MSG_TRUNC;
- copied = len;
- }
-
- skb_reset_transport_header(skb);
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
- if (err == 0)
- sock_recv_ts_and_drops(msg, sk, skb);
-
- skb_free_datagram(sk, skb);
-
- return err ? : copied;
-}
-EXPORT_SYMBOL(bt_sock_recvmsg);
-
-static long bt_sock_data_wait(struct sock *sk, long timeo)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(sk_sleep(sk), &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (!skb_queue_empty(&sk->sk_receive_queue))
- break;
-
- if (sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN))
- break;
-
- if (signal_pending(current) || !timeo)
- break;
-
- set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
- clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
- }
-
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(sk), &wait);
- return timeo;
-}
-
-int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t size, int flags)
-{
- struct sock *sk = sock->sk;
- int err = 0;
- size_t target, copied = 0;
- long timeo;
-
- if (flags & MSG_OOB)
- return -EOPNOTSUPP;
-
- msg->msg_namelen = 0;
-
- BT_DBG("sk %p size %zu", sk, size);
-
- lock_sock(sk);
-
- target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
- timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
-
- do {
- struct sk_buff *skb;
- int chunk;
-
- skb = skb_dequeue(&sk->sk_receive_queue);
- if (!skb) {
- if (copied >= target)
- break;
-
- err = sock_error(sk);
- if (err)
- break;
- if (sk->sk_shutdown & RCV_SHUTDOWN)
- break;
-
- err = -EAGAIN;
- if (!timeo)
- break;
-
- timeo = bt_sock_data_wait(sk, timeo);
-
- if (signal_pending(current)) {
- err = sock_intr_errno(timeo);
- goto out;
- }
- continue;
- }
-
- chunk = min_t(unsigned int, skb->len, size);
- if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, chunk)) {
- skb_queue_head(&sk->sk_receive_queue, skb);
- if (!copied)
- copied = -EFAULT;
- break;
- }
- copied += chunk;
- size -= chunk;
-
- sock_recv_ts_and_drops(msg, sk, skb);
-
- if (!(flags & MSG_PEEK)) {
- int skb_len = skb_headlen(skb);
-
- if (chunk <= skb_len) {
- __skb_pull(skb, chunk);
- } else {
- struct sk_buff *frag;
-
- __skb_pull(skb, skb_len);
- chunk -= skb_len;
-
- skb_walk_frags(skb, frag) {
- if (chunk <= frag->len) {
- /* Pulling partial data */
- skb->len -= chunk;
- skb->data_len -= chunk;
- __skb_pull(frag, chunk);
- break;
- } else if (frag->len) {
- /* Pulling all frag data */
- chunk -= frag->len;
- skb->len -= frag->len;
- skb->data_len -= frag->len;
- __skb_pull(frag, frag->len);
- }
- }
- }
-
- if (skb->len) {
- skb_queue_head(&sk->sk_receive_queue, skb);
- break;
- }
- kfree_skb(skb);
-
- } else {
- /* put message back and return */
- skb_queue_head(&sk->sk_receive_queue, skb);
- break;
- }
- } while (size);
-
-out:
- release_sock(sk);
- return copied ? : err;
-}
-EXPORT_SYMBOL(bt_sock_stream_recvmsg);
-
-static inline unsigned int bt_accept_poll(struct sock *parent)
-{
- struct list_head *p, *n;
- struct sock *sk;
-
- list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
- sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
- if (sk->sk_state == BT_CONNECTED ||
- (bt_sk(parent)->defer_setup &&
- sk->sk_state == BT_CONNECT2))
- return POLLIN | POLLRDNORM;
- }
-
- return 0;
-}
-
-unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait)
-{
- struct sock *sk = sock->sk;
- unsigned int mask = 0;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- poll_wait(file, sk_sleep(sk), wait);
-
- if (sk->sk_state == BT_LISTEN)
- return bt_accept_poll(sk);
-
- if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
- mask |= POLLERR;
-
- if (sk->sk_shutdown & RCV_SHUTDOWN)
- mask |= POLLRDHUP | POLLIN | POLLRDNORM;
-
- if (sk->sk_shutdown == SHUTDOWN_MASK)
- mask |= POLLHUP;
-
- if (!skb_queue_empty(&sk->sk_receive_queue))
- mask |= POLLIN | POLLRDNORM;
-
- if (sk->sk_state == BT_CLOSED)
- mask |= POLLHUP;
-
- if (sk->sk_state == BT_CONNECT ||
- sk->sk_state == BT_CONNECT2 ||
- sk->sk_state == BT_CONFIG)
- return mask;
-
- if (!bt_sk(sk)->suspended && sock_writeable(sk))
- mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
- else
- set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
-
- return mask;
-}
-EXPORT_SYMBOL(bt_sock_poll);
-
-int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct sock *sk = sock->sk;
- struct sk_buff *skb;
- long amount;
- int err;
-
- BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg);
-
- switch (cmd) {
- case TIOCOUTQ:
- if (sk->sk_state == BT_LISTEN)
- return -EINVAL;
-
- amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
- if (amount < 0)
- amount = 0;
- err = put_user(amount, (int __user *) arg);
- break;
-
- case TIOCINQ:
- if (sk->sk_state == BT_LISTEN)
- return -EINVAL;
-
- lock_sock(sk);
- skb = skb_peek(&sk->sk_receive_queue);
- amount = skb ? skb->len : 0;
- release_sock(sk);
- err = put_user(amount, (int __user *) arg);
- break;
-
- case SIOCGSTAMP:
- err = sock_get_timestamp(sk, (struct timeval __user *) arg);
- break;
-
- case SIOCGSTAMPNS:
- err = sock_get_timestampns(sk, (struct timespec __user *) arg);
- break;
-
- default:
- err = -ENOIOCTLCMD;
- break;
- }
-
- return err;
-}
-EXPORT_SYMBOL(bt_sock_ioctl);
-
-int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
-{
- DECLARE_WAITQUEUE(wait, current);
- int err = 0;
-
- BT_DBG("sk %p", sk);
-
- add_wait_queue(sk_sleep(sk), &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- while (sk->sk_state != state) {
- if (!timeo) {
- err = -EINPROGRESS;
- break;
- }
-
- if (signal_pending(current)) {
- err = sock_intr_errno(timeo);
- break;
- }
-
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
- set_current_state(TASK_INTERRUPTIBLE);
-
- err = sock_error(sk);
- if (err)
- break;
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(sk), &wait);
- return err;
-}
-EXPORT_SYMBOL(bt_sock_wait_state);
-
-static struct net_proto_family bt_sock_family_ops = {
- .owner = THIS_MODULE,
- .family = PF_BLUETOOTH,
- .create = bt_sock_create,
-};
-
-static int __init bt_init(void)
-{
- int err;
-
- BT_INFO("Core ver %s", VERSION);
-
- err = bt_sysfs_init();
- if (err < 0)
- return err;
-
- err = sock_register(&bt_sock_family_ops);
- if (err < 0) {
- bt_sysfs_cleanup();
- return err;
- }
-
- BT_INFO("HCI device and connection manager initialized");
-
- err = hci_sock_init();
- if (err < 0)
- goto error;
-
- err = l2cap_init();
- if (err < 0)
- goto sock_err;
-
- err = sco_init();
- if (err < 0) {
- l2cap_exit();
- goto sock_err;
- }
-
- return 0;
-
-sock_err:
- hci_sock_cleanup();
-
-error:
- sock_unregister(PF_BLUETOOTH);
- bt_sysfs_cleanup();
-
- return err;
-}
-
-static void __exit bt_exit(void)
-{
-
- sco_exit();
-
- l2cap_exit();
-
- hci_sock_cleanup();
-
- sock_unregister(PF_BLUETOOTH);
-
- bt_sysfs_cleanup();
-}
-
-subsys_initcall(bt_init);
-module_exit(bt_exit);
-
-MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("Bluetooth Core ver " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_NETPROTO(PF_BLUETOOTH);
diff --git a/net/bluetooth_tizen/bnep/Kconfig b/net/bluetooth_tizen/bnep/Kconfig
deleted file mode 100644
index 71791fc..0000000
--- a/net/bluetooth_tizen/bnep/Kconfig
+++ /dev/null
@@ -1,24 +0,0 @@
-config BT_BNEP
- tristate "BNEP protocol support"
- depends on BT
- select CRC32
- help
- BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
- emulation layer on top of Bluetooth. BNEP is required for
- Bluetooth PAN (Personal Area Network).
-
- Say Y here to compile BNEP support into the kernel or say M to
- compile it as module (bnep).
-
-config BT_BNEP_MC_FILTER
- bool "Multicast filter support"
- depends on BT_BNEP
- help
- This option enables the multicast filter support for BNEP.
-
-config BT_BNEP_PROTO_FILTER
- bool "Protocol filter support"
- depends on BT_BNEP
- help
- This option enables the protocol filter support for BNEP.
-
diff --git a/net/bluetooth_tizen/bnep/Makefile b/net/bluetooth_tizen/bnep/Makefile
deleted file mode 100644
index c7821e7..0000000
--- a/net/bluetooth_tizen/bnep/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for the Linux Bluetooth BNEP layer.
-#
-
-obj-$(CONFIG_BT_BNEP) += bnep.o
-
-bnep-objs := core.o sock.o netdev.o
diff --git a/net/bluetooth_tizen/bnep/bnep.h b/net/bluetooth_tizen/bnep/bnep.h
deleted file mode 100644
index e7ee531..0000000
--- a/net/bluetooth_tizen/bnep/bnep.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- BNEP protocol definition for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License, version 2, as
- published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef _BNEP_H
-#define _BNEP_H
-
-#include <linux/types.h>
-#include <linux/crc32.h>
-#include <net/bluetooth/bluetooth.h>
-
-/* Limits */
-#define BNEP_MAX_PROTO_FILTERS 5
-#define BNEP_MAX_MULTICAST_FILTERS 20
-
-/* UUIDs */
-#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB
-#define BNEP_UUID16 0x02
-#define BNEP_UUID32 0x04
-#define BNEP_UUID128 0x16
-
-#define BNEP_SVC_PANU 0x1115
-#define BNEP_SVC_NAP 0x1116
-#define BNEP_SVC_GN 0x1117
-
-/* Packet types */
-#define BNEP_GENERAL 0x00
-#define BNEP_CONTROL 0x01
-#define BNEP_COMPRESSED 0x02
-#define BNEP_COMPRESSED_SRC_ONLY 0x03
-#define BNEP_COMPRESSED_DST_ONLY 0x04
-
-/* Control types */
-#define BNEP_CMD_NOT_UNDERSTOOD 0x00
-#define BNEP_SETUP_CONN_REQ 0x01
-#define BNEP_SETUP_CONN_RSP 0x02
-#define BNEP_FILTER_NET_TYPE_SET 0x03
-#define BNEP_FILTER_NET_TYPE_RSP 0x04
-#define BNEP_FILTER_MULTI_ADDR_SET 0x05
-#define BNEP_FILTER_MULTI_ADDR_RSP 0x06
-
-/* Extension types */
-#define BNEP_EXT_CONTROL 0x00
-
-/* Response messages */
-#define BNEP_SUCCESS 0x00
-
-#define BNEP_CONN_INVALID_DST 0x01
-#define BNEP_CONN_INVALID_SRC 0x02
-#define BNEP_CONN_INVALID_SVC 0x03
-#define BNEP_CONN_NOT_ALLOWED 0x04
-
-#define BNEP_FILTER_UNSUPPORTED_REQ 0x01
-#define BNEP_FILTER_INVALID_RANGE 0x02
-#define BNEP_FILTER_INVALID_MCADDR 0x02
-#define BNEP_FILTER_LIMIT_REACHED 0x03
-#define BNEP_FILTER_DENIED_SECURITY 0x04
-
-/* L2CAP settings */
-#define BNEP_MTU 1691
-#define BNEP_PSM 0x0f
-#define BNEP_FLUSH_TO 0xffff
-#define BNEP_CONNECT_TO 15
-#define BNEP_FILTER_TO 15
-
-/* Headers */
-#define BNEP_TYPE_MASK 0x7f
-#define BNEP_EXT_HEADER 0x80
-
-struct bnep_setup_conn_req {
- __u8 type;
- __u8 ctrl;
- __u8 uuid_size;
- __u8 service[0];
-} __packed;
-
-struct bnep_set_filter_req {
- __u8 type;
- __u8 ctrl;
- __be16 len;
- __u8 list[0];
-} __packed;
-
-struct bnep_control_rsp {
- __u8 type;
- __u8 ctrl;
- __be16 resp;
-} __packed;
-
-struct bnep_ext_hdr {
- __u8 type;
- __u8 len;
- __u8 data[0];
-} __packed;
-
-/* BNEP ioctl defines */
-#define BNEPCONNADD _IOW('B', 200, int)
-#define BNEPCONNDEL _IOW('B', 201, int)
-#define BNEPGETCONNLIST _IOR('B', 210, int)
-#define BNEPGETCONNINFO _IOR('B', 211, int)
-
-struct bnep_connadd_req {
- int sock; /* Connected socket */
- __u32 flags;
- __u16 role;
- char device[16]; /* Name of the Ethernet device */
-};
-
-struct bnep_conndel_req {
- __u32 flags;
- __u8 dst[ETH_ALEN];
-};
-
-struct bnep_conninfo {
- __u32 flags;
- __u16 role;
- __u16 state;
- __u8 dst[ETH_ALEN];
- char device[16];
-};
-
-struct bnep_connlist_req {
- __u32 cnum;
- struct bnep_conninfo __user *ci;
-};
-
-struct bnep_proto_filter {
- __u16 start;
- __u16 end;
-};
-
-int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock);
-int bnep_del_connection(struct bnep_conndel_req *req);
-int bnep_get_connlist(struct bnep_connlist_req *req);
-int bnep_get_conninfo(struct bnep_conninfo *ci);
-
-/* BNEP sessions */
-struct bnep_session {
- struct list_head list;
-
- unsigned int role;
- unsigned long state;
- unsigned long flags;
- atomic_t terminate;
- struct task_struct *task;
-
- struct ethhdr eh;
- struct msghdr msg;
-
- struct bnep_proto_filter proto_filter[BNEP_MAX_PROTO_FILTERS];
- unsigned long long mc_filter;
-
- struct socket *sock;
- struct net_device *dev;
-};
-
-void bnep_net_setup(struct net_device *dev);
-int bnep_sock_init(void);
-void bnep_sock_cleanup(void);
-
-static inline int bnep_mc_hash(__u8 *addr)
-{
- return crc32_be(~0, addr, ETH_ALEN) >> 26;
-}
-
-#endif
diff --git a/net/bluetooth_tizen/bnep/core.c b/net/bluetooth_tizen/bnep/core.c
deleted file mode 100644
index a779ec7..0000000
--- a/net/bluetooth_tizen/bnep/core.c
+++ /dev/null
@@ -1,747 +0,0 @@
-/*
- BNEP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2001-2002 Inventel Systemes
- Written 2001-2002 by
- Clément Moreau <clement.moreau@inventel.fr>
- David Libault <david.libault@inventel.fr>
-
- Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/freezer.h>
-#include <linux/errno.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <linux/kthread.h>
-#include <net/sock.h>
-
-#include <linux/socket.h>
-#include <linux/file.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/unaligned.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/l2cap.h>
-
-#include "bnep.h"
-
-#define VERSION "1.3"
-
-static bool compress_src = true;
-static bool compress_dst = true;
-
-static LIST_HEAD(bnep_session_list);
-static DECLARE_RWSEM(bnep_session_sem);
-
-static struct bnep_session *__bnep_get_session(u8 *dst)
-{
- struct bnep_session *s;
-
- BT_DBG("");
-
- list_for_each_entry(s, &bnep_session_list, list)
- if (!compare_ether_addr(dst, s->eh.h_source))
- return s;
-
- return NULL;
-}
-
-static void __bnep_link_session(struct bnep_session *s)
-{
- list_add(&s->list, &bnep_session_list);
-}
-
-static void __bnep_unlink_session(struct bnep_session *s)
-{
- list_del(&s->list);
-}
-
-static int bnep_send(struct bnep_session *s, void *data, size_t len)
-{
- struct socket *sock = s->sock;
- struct kvec iv = { data, len };
-
- return kernel_sendmsg(sock, &s->msg, &iv, 1, len);
-}
-
-static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
-{
- struct bnep_control_rsp rsp;
- rsp.type = BNEP_CONTROL;
- rsp.ctrl = ctrl;
- rsp.resp = htons(resp);
- return bnep_send(s, &rsp, sizeof(rsp));
-}
-
-#ifdef CONFIG_BT_BNEP_PROTO_FILTER
-static inline void bnep_set_default_proto_filter(struct bnep_session *s)
-{
- /* (IPv4, ARP) */
- s->proto_filter[0].start = ETH_P_IP;
- s->proto_filter[0].end = ETH_P_ARP;
- /* (RARP, AppleTalk) */
- s->proto_filter[1].start = ETH_P_RARP;
- s->proto_filter[1].end = ETH_P_AARP;
- /* (IPX, IPv6) */
- s->proto_filter[2].start = ETH_P_IPX;
- s->proto_filter[2].end = ETH_P_IPV6;
-}
-#endif
-
-static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len)
-{
- int n;
-
- if (len < 2)
- return -EILSEQ;
-
- n = get_unaligned_be16(data);
- data++;
- len -= 2;
-
- if (len < n)
- return -EILSEQ;
-
- BT_DBG("filter len %d", n);
-
-#ifdef CONFIG_BT_BNEP_PROTO_FILTER
- n /= 4;
- if (n <= BNEP_MAX_PROTO_FILTERS) {
- struct bnep_proto_filter *f = s->proto_filter;
- int i;
-
- for (i = 0; i < n; i++) {
- f[i].start = get_unaligned_be16(data++);
- f[i].end = get_unaligned_be16(data++);
-
- BT_DBG("proto filter start %d end %d",
- f[i].start, f[i].end);
- }
-
- if (i < BNEP_MAX_PROTO_FILTERS)
- memset(f + i, 0, sizeof(*f));
-
- if (n == 0)
- bnep_set_default_proto_filter(s);
-
- bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
- } else {
- bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
- }
-#else
- bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
-#endif
- return 0;
-}
-
-static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
-{
- int n;
-
- if (len < 2)
- return -EILSEQ;
-
- n = get_unaligned_be16(data);
- data += 2;
- len -= 2;
-
- if (len < n)
- return -EILSEQ;
-
- BT_DBG("filter len %d", n);
-
-#ifdef CONFIG_BT_BNEP_MC_FILTER
- n /= (ETH_ALEN * 2);
-
- if (n > 0) {
- int i;
-
- s->mc_filter = 0;
-
- /* Always send broadcast */
- set_bit(bnep_mc_hash(s->dev->broadcast), (ulong *) &s->mc_filter);
-
- /* Add address ranges to the multicast hash */
- for (; n > 0; n--) {
- u8 a1[6], *a2;
-
- memcpy(a1, data, ETH_ALEN);
- data += ETH_ALEN;
- a2 = data;
- data += ETH_ALEN;
-
- BT_DBG("mc filter %s -> %s",
- batostr((void *) a1), batostr((void *) a2));
-
- /* Iterate from a1 to a2 */
- set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
- while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
- /* Increment a1 */
- i = 5;
- while (i >= 0 && ++a1[i--] == 0)
- ;
-
- set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
- }
- }
- }
-
- BT_DBG("mc filter hash 0x%llx", s->mc_filter);
-
- bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
-#else
- bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
-#endif
- return 0;
-}
-
-static int bnep_rx_control(struct bnep_session *s, void *data, int len)
-{
- u8 cmd = *(u8 *)data;
- int err = 0;
-
- data++;
- len--;
-
- switch (cmd) {
- case BNEP_CMD_NOT_UNDERSTOOD:
- case BNEP_SETUP_CONN_RSP:
- case BNEP_FILTER_NET_TYPE_RSP:
- case BNEP_FILTER_MULTI_ADDR_RSP:
- /* Ignore these for now */
- break;
-
- case BNEP_FILTER_NET_TYPE_SET:
- err = bnep_ctrl_set_netfilter(s, data, len);
- break;
-
- case BNEP_FILTER_MULTI_ADDR_SET:
- err = bnep_ctrl_set_mcfilter(s, data, len);
- break;
-
- case BNEP_SETUP_CONN_REQ:
- err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP, BNEP_CONN_NOT_ALLOWED);
- break;
-
- default: {
- u8 pkt[3];
- pkt[0] = BNEP_CONTROL;
- pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
- pkt[2] = cmd;
- bnep_send(s, pkt, sizeof(pkt));
- }
- break;
- }
-
- return err;
-}
-
-static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
-{
- struct bnep_ext_hdr *h;
- int err = 0;
-
- do {
- h = (void *) skb->data;
- if (!skb_pull(skb, sizeof(*h))) {
- err = -EILSEQ;
- break;
- }
-
- BT_DBG("type 0x%x len %d", h->type, h->len);
-
- switch (h->type & BNEP_TYPE_MASK) {
- case BNEP_EXT_CONTROL:
- bnep_rx_control(s, skb->data, skb->len);
- break;
-
- default:
- /* Unknown extension, skip it. */
- break;
- }
-
- if (!skb_pull(skb, h->len)) {
- err = -EILSEQ;
- break;
- }
- } while (!err && (h->type & BNEP_EXT_HEADER));
-
- return err;
-}
-
-static u8 __bnep_rx_hlen[] = {
- ETH_HLEN, /* BNEP_GENERAL */
- 0, /* BNEP_CONTROL */
- 2, /* BNEP_COMPRESSED */
- ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
- ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */
-};
-
-static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
-{
- struct net_device *dev = s->dev;
- struct sk_buff *nskb;
- u8 type;
-
- dev->stats.rx_bytes += skb->len;
-
- type = *(u8 *) skb->data;
- skb_pull(skb, 1);
-
- if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen))
- goto badframe;
-
- if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
- bnep_rx_control(s, skb->data, skb->len);
- kfree_skb(skb);
- return 0;
- }
-
- skb_reset_mac_header(skb);
-
- /* Verify and pull out header */
- if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
- goto badframe;
-
- s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
-
- if (type & BNEP_EXT_HEADER) {
- if (bnep_rx_extension(s, skb) < 0)
- goto badframe;
- }
-
- /* Strip 802.1p header */
- if (ntohs(s->eh.h_proto) == 0x8100) {
- if (!skb_pull(skb, 4))
- goto badframe;
- s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
- }
-
- /* We have to alloc new skb and copy data here :(. Because original skb
- * may not be modified and because of the alignment requirements. */
- nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
- if (!nskb) {
- dev->stats.rx_dropped++;
- kfree_skb(skb);
- return -ENOMEM;
- }
- skb_reserve(nskb, 2);
-
- /* Decompress header and construct ether frame */
- switch (type & BNEP_TYPE_MASK) {
- case BNEP_COMPRESSED:
- memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
- break;
-
- case BNEP_COMPRESSED_SRC_ONLY:
- memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
- memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb), ETH_ALEN);
- put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
- break;
-
- case BNEP_COMPRESSED_DST_ONLY:
- memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb),
- ETH_ALEN);
- memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source,
- ETH_ALEN + 2);
- break;
-
- case BNEP_GENERAL:
- memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb),
- ETH_ALEN * 2);
- put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
- break;
- }
-
- skb_copy_from_linear_data(skb, __skb_put(nskb, skb->len), skb->len);
- kfree_skb(skb);
-
- dev->stats.rx_packets++;
- nskb->ip_summed = CHECKSUM_NONE;
- nskb->protocol = eth_type_trans(nskb, dev);
- netif_rx_ni(nskb);
- return 0;
-
-badframe:
- dev->stats.rx_errors++;
- kfree_skb(skb);
- return 0;
-}
-
-static u8 __bnep_tx_types[] = {
- BNEP_GENERAL,
- BNEP_COMPRESSED_SRC_ONLY,
- BNEP_COMPRESSED_DST_ONLY,
- BNEP_COMPRESSED
-};
-
-static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
-{
- struct ethhdr *eh = (void *) skb->data;
- struct socket *sock = s->sock;
- struct kvec iv[3];
- int len = 0, il = 0;
- u8 type = 0;
-
- BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
-
- if (!skb->dev) {
- /* Control frame sent by us */
- goto send;
- }
-
- iv[il++] = (struct kvec) { &type, 1 };
- len++;
-
- if (compress_src && !compare_ether_addr(eh->h_dest, s->eh.h_source))
- type |= 0x01;
-
- if (compress_dst && !compare_ether_addr(eh->h_source, s->eh.h_dest))
- type |= 0x02;
-
- if (type)
- skb_pull(skb, ETH_ALEN * 2);
-
- type = __bnep_tx_types[type];
- switch (type) {
- case BNEP_COMPRESSED_SRC_ONLY:
- iv[il++] = (struct kvec) { eh->h_source, ETH_ALEN };
- len += ETH_ALEN;
- break;
-
- case BNEP_COMPRESSED_DST_ONLY:
- iv[il++] = (struct kvec) { eh->h_dest, ETH_ALEN };
- len += ETH_ALEN;
- break;
- }
-
-send:
- iv[il++] = (struct kvec) { skb->data, skb->len };
- len += skb->len;
-
- /* FIXME: linearize skb */
- {
- len = kernel_sendmsg(sock, &s->msg, iv, il, len);
- }
- kfree_skb(skb);
-
- if (len > 0) {
- s->dev->stats.tx_bytes += len;
- s->dev->stats.tx_packets++;
- return 0;
- }
-
- return len;
-}
-
-static int bnep_session(void *arg)
-{
- struct bnep_session *s = arg;
- struct net_device *dev = s->dev;
- struct sock *sk = s->sock->sk;
- struct sk_buff *skb;
- wait_queue_t wait;
-
- BT_DBG("");
-
- set_user_nice(current, -15);
-
- init_waitqueue_entry(&wait, current);
- add_wait_queue(sk_sleep(sk), &wait);
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (atomic_read(&s->terminate))
- break;
- /* RX */
- while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
- skb_orphan(skb);
- if (!skb_linearize(skb))
- bnep_rx_frame(s, skb);
- else
- kfree_skb(skb);
- }
-
- if (sk->sk_state != BT_CONNECTED)
- break;
-
- /* TX */
- while ((skb = skb_dequeue(&sk->sk_write_queue)))
- if (bnep_tx_frame(s, skb))
- break;
- netif_wake_queue(dev);
-
- schedule();
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(sk), &wait);
-
- /* Cleanup session */
- down_write(&bnep_session_sem);
-
- /* Delete network device */
- unregister_netdev(dev);
-
- /* Wakeup user-space polling for socket errors */
- s->sock->sk->sk_err = EUNATCH;
-
- wake_up_interruptible(sk_sleep(s->sock->sk));
-
- /* Release the socket */
- fput(s->sock->file);
-
- __bnep_unlink_session(s);
-
- up_write(&bnep_session_sem);
- free_netdev(dev);
- module_put_and_exit(0);
- return 0;
-}
-
-static struct device *bnep_get_device(struct bnep_session *session)
-{
- bdaddr_t *src = &bt_sk(session->sock->sk)->src;
- bdaddr_t *dst = &bt_sk(session->sock->sk)->dst;
- struct hci_dev *hdev;
- struct hci_conn *conn;
-
- hdev = hci_get_route(dst, src);
- if (!hdev)
- return NULL;
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
-
- hci_dev_put(hdev);
-
- return conn ? &conn->dev : NULL;
-}
-
-static struct device_type bnep_type = {
- .name = "bluetooth",
-};
-
-int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
-{
- struct net_device *dev;
- struct bnep_session *s, *ss;
- u8 dst[ETH_ALEN], src[ETH_ALEN];
- int err;
-
- BT_DBG("");
-
- baswap((void *) dst, &bt_sk(sock->sk)->dst);
- baswap((void *) src, &bt_sk(sock->sk)->src);
-
- /* session struct allocated as private part of net_device */
- dev = alloc_netdev(sizeof(struct bnep_session),
- (*req->device) ? req->device : "bnep%d",
- bnep_net_setup);
- if (!dev)
- return -ENOMEM;
-
- down_write(&bnep_session_sem);
-
- ss = __bnep_get_session(dst);
- if (ss && ss->state == BT_CONNECTED) {
- err = -EEXIST;
- goto failed;
- }
-
- s = netdev_priv(dev);
-
- /* This is rx header therefore addresses are swapped.
- * ie. eh.h_dest is our local address. */
- memcpy(s->eh.h_dest, &src, ETH_ALEN);
- memcpy(s->eh.h_source, &dst, ETH_ALEN);
- memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
-
- s->dev = dev;
- s->sock = sock;
- s->role = req->role;
- s->state = BT_CONNECTED;
-
- s->msg.msg_flags = MSG_NOSIGNAL;
-
-#ifdef CONFIG_BT_BNEP_MC_FILTER
- /* Set default mc filter */
- set_bit(bnep_mc_hash(dev->broadcast), (ulong *) &s->mc_filter);
-#endif
-
-#ifdef CONFIG_BT_BNEP_PROTO_FILTER
- /* Set default protocol filter */
- bnep_set_default_proto_filter(s);
-#endif
-
- SET_NETDEV_DEV(dev, bnep_get_device(s));
- SET_NETDEV_DEVTYPE(dev, &bnep_type);
-
- err = register_netdev(dev);
- if (err)
- goto failed;
-
- __bnep_link_session(s);
-
- __module_get(THIS_MODULE);
- s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
- if (IS_ERR(s->task)) {
- /* Session thread start failed, gotta cleanup. */
- module_put(THIS_MODULE);
- unregister_netdev(dev);
- __bnep_unlink_session(s);
- err = PTR_ERR(s->task);
- goto failed;
- }
-
- up_write(&bnep_session_sem);
- strcpy(req->device, dev->name);
- return 0;
-
-failed:
- up_write(&bnep_session_sem);
- free_netdev(dev);
- return err;
-}
-
-int bnep_del_connection(struct bnep_conndel_req *req)
-{
- struct bnep_session *s;
- int err = 0;
-
- BT_DBG("");
-
- down_read(&bnep_session_sem);
-
- s = __bnep_get_session(req->dst);
- if (s) {
- atomic_inc(&s->terminate);
- wake_up_process(s->task);
- } else
- err = -ENOENT;
-
- up_read(&bnep_session_sem);
- return err;
-}
-
-static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
-{
- memset(ci, 0, sizeof(*ci));
- memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
- strcpy(ci->device, s->dev->name);
- ci->flags = s->flags;
- ci->state = s->state;
- ci->role = s->role;
-}
-
-int bnep_get_connlist(struct bnep_connlist_req *req)
-{
- struct bnep_session *s;
- int err = 0, n = 0;
-
- down_read(&bnep_session_sem);
-
- list_for_each_entry(s, &bnep_session_list, list) {
- struct bnep_conninfo ci;
-
- __bnep_copy_ci(&ci, s);
-
- if (copy_to_user(req->ci, &ci, sizeof(ci))) {
- err = -EFAULT;
- break;
- }
-
- if (++n >= req->cnum)
- break;
-
- req->ci++;
- }
- req->cnum = n;
-
- up_read(&bnep_session_sem);
- return err;
-}
-
-int bnep_get_conninfo(struct bnep_conninfo *ci)
-{
- struct bnep_session *s;
- int err = 0;
-
- down_read(&bnep_session_sem);
-
- s = __bnep_get_session(ci->dst);
- if (s)
- __bnep_copy_ci(ci, s);
- else
- err = -ENOENT;
-
- up_read(&bnep_session_sem);
- return err;
-}
-
-static int __init bnep_init(void)
-{
- char flt[50] = "";
-
-#ifdef CONFIG_BT_BNEP_PROTO_FILTER
- strcat(flt, "protocol ");
-#endif
-
-#ifdef CONFIG_BT_BNEP_MC_FILTER
- strcat(flt, "multicast");
-#endif
-
- BT_INFO("BNEP (Ethernet Emulation) ver %s", VERSION);
- if (flt[0])
- BT_INFO("BNEP filters: %s", flt);
-
- bnep_sock_init();
- return 0;
-}
-
-static void __exit bnep_exit(void)
-{
- bnep_sock_cleanup();
-}
-
-module_init(bnep_init);
-module_exit(bnep_exit);
-
-module_param(compress_src, bool, 0644);
-MODULE_PARM_DESC(compress_src, "Compress sources headers");
-
-module_param(compress_dst, bool, 0644);
-MODULE_PARM_DESC(compress_dst, "Compress destination headers");
-
-MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("bt-proto-4");
diff --git a/net/bluetooth_tizen/bnep/netdev.c b/net/bluetooth_tizen/bnep/netdev.c
deleted file mode 100644
index bc40864..0000000
--- a/net/bluetooth_tizen/bnep/netdev.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- BNEP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2001-2002 Inventel Systemes
- Written 2001-2002 by
- Clément Moreau <clement.moreau@inventel.fr>
- David Libault <david.libault@inventel.fr>
-
- Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include <linux/socket.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/wait.h>
-
-#include <asm/unaligned.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/l2cap.h>
-
-#include "bnep.h"
-
-#define BNEP_TX_QUEUE_LEN 20
-
-static int bnep_net_open(struct net_device *dev)
-{
- netif_start_queue(dev);
- return 0;
-}
-
-static int bnep_net_close(struct net_device *dev)
-{
- netif_stop_queue(dev);
- return 0;
-}
-
-static void bnep_net_set_mc_list(struct net_device *dev)
-{
-#ifdef CONFIG_BT_BNEP_MC_FILTER
- struct bnep_session *s = netdev_priv(dev);
- struct sock *sk = s->sock->sk;
- struct bnep_set_filter_req *r;
- struct sk_buff *skb;
- int size;
-
- BT_DBG("%s mc_count %d", dev->name, netdev_mc_count(dev));
-
- size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2;
- skb = alloc_skb(size, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("%s Multicast list allocation failed", dev->name);
- return;
- }
-
- r = (void *) skb->data;
- __skb_put(skb, sizeof(*r));
-
- r->type = BNEP_CONTROL;
- r->ctrl = BNEP_FILTER_MULTI_ADDR_SET;
-
- if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
- u8 start[ETH_ALEN] = { 0x01 };
-
- /* Request all addresses */
- memcpy(__skb_put(skb, ETH_ALEN), start, ETH_ALEN);
- memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
- r->len = htons(ETH_ALEN * 2);
- } else {
- struct netdev_hw_addr *ha;
- int i, len = skb->len;
-
- if (dev->flags & IFF_BROADCAST) {
- memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
- memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
- }
-
- /* FIXME: We should group addresses here. */
-
- i = 0;
- netdev_for_each_mc_addr(ha, dev) {
- if (i == BNEP_MAX_MULTICAST_FILTERS)
- break;
- memcpy(__skb_put(skb, ETH_ALEN), ha->addr, ETH_ALEN);
- memcpy(__skb_put(skb, ETH_ALEN), ha->addr, ETH_ALEN);
-
- i++;
- }
- r->len = htons(skb->len - len);
- }
-
- skb_queue_tail(&sk->sk_write_queue, skb);
- wake_up_interruptible(sk_sleep(sk));
-#endif
-}
-
-static int bnep_net_set_mac_addr(struct net_device *dev, void *arg)
-{
- BT_DBG("%s", dev->name);
- return 0;
-}
-
-static void bnep_net_timeout(struct net_device *dev)
-{
- BT_DBG("net_timeout");
- netif_wake_queue(dev);
-}
-
-#ifdef CONFIG_BT_BNEP_MC_FILTER
-static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
-{
- struct ethhdr *eh = (void *) skb->data;
-
- if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), (ulong *) &s->mc_filter))
- return 1;
- return 0;
-}
-#endif
-
-#ifdef CONFIG_BT_BNEP_PROTO_FILTER
-/* Determine ether protocol. Based on eth_type_trans. */
-static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
-{
- struct ethhdr *eh = (void *) skb->data;
- u16 proto = ntohs(eh->h_proto);
-
- if (proto >= 1536)
- return proto;
-
- if (get_unaligned((__be16 *) skb->data) == htons(0xFFFF))
- return ETH_P_802_3;
-
- return ETH_P_802_2;
-}
-
-static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
-{
- u16 proto = bnep_net_eth_proto(skb);
- struct bnep_proto_filter *f = s->proto_filter;
- int i;
-
- for (i = 0; i < BNEP_MAX_PROTO_FILTERS && f[i].end; i++) {
- if (proto >= f[i].start && proto <= f[i].end)
- return 0;
- }
-
- BT_DBG("BNEP: filtered skb %p, proto 0x%.4x", skb, proto);
- return 1;
-}
-#endif
-
-static netdev_tx_t bnep_net_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct bnep_session *s = netdev_priv(dev);
- struct sock *sk = s->sock->sk;
-
- BT_DBG("skb %p, dev %p", skb, dev);
-
-#ifdef CONFIG_BT_BNEP_MC_FILTER
- if (bnep_net_mc_filter(skb, s)) {
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-#endif
-
-#ifdef CONFIG_BT_BNEP_PROTO_FILTER
- if (bnep_net_proto_filter(skb, s)) {
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-#endif
-
- /*
- * We cannot send L2CAP packets from here as we are potentially in a bh.
- * So we have to queue them and wake up session thread which is sleeping
- * on the sk_sleep(sk).
- */
- dev->trans_start = jiffies;
- skb_queue_tail(&sk->sk_write_queue, skb);
- wake_up_interruptible(sk_sleep(sk));
-
- if (skb_queue_len(&sk->sk_write_queue) >= BNEP_TX_QUEUE_LEN) {
- BT_DBG("tx queue is full");
-
- /* Stop queuing.
- * Session thread will do netif_wake_queue() */
- netif_stop_queue(dev);
- }
-
- return NETDEV_TX_OK;
-}
-
-static const struct net_device_ops bnep_netdev_ops = {
- .ndo_open = bnep_net_open,
- .ndo_stop = bnep_net_close,
- .ndo_start_xmit = bnep_net_xmit,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_rx_mode = bnep_net_set_mc_list,
- .ndo_set_mac_address = bnep_net_set_mac_addr,
- .ndo_tx_timeout = bnep_net_timeout,
- .ndo_change_mtu = eth_change_mtu,
-
-};
-
-void bnep_net_setup(struct net_device *dev)
-{
-
- memset(dev->broadcast, 0xff, ETH_ALEN);
- dev->addr_len = ETH_ALEN;
-
- ether_setup(dev);
- dev->priv_flags &= ~IFF_TX_SKB_SHARING;
- dev->netdev_ops = &bnep_netdev_ops;
-
- dev->watchdog_timeo = HZ * 2;
-}
diff --git a/net/bluetooth_tizen/bnep/sock.c b/net/bluetooth_tizen/bnep/sock.c
deleted file mode 100644
index 9f9c8dc..0000000
--- a/net/bluetooth_tizen/bnep/sock.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- BNEP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2001-2002 Inventel Systemes
- Written 2001-2002 by
- David Libault <david.libault@inventel.fr>
-
- Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <linux/file.h>
-#include <linux/init.h>
-#include <linux/compat.h>
-#include <linux/gfp.h>
-#include <linux/uaccess.h>
-#include <net/sock.h>
-
-#include <asm/system.h>
-
-#include "bnep.h"
-
-static int bnep_sock_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
-
- BT_DBG("sock %p sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
- sock_orphan(sk);
- sock_put(sk);
- return 0;
-}
-
-static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct bnep_connlist_req cl;
- struct bnep_connadd_req ca;
- struct bnep_conndel_req cd;
- struct bnep_conninfo ci;
- struct socket *nsock;
- void __user *argp = (void __user *)arg;
- int err;
-
- BT_DBG("cmd %x arg %lx", cmd, arg);
-
- switch (cmd) {
- case BNEPCONNADD:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
-
- if (copy_from_user(&ca, argp, sizeof(ca)))
- return -EFAULT;
-
- nsock = sockfd_lookup(ca.sock, &err);
- if (!nsock)
- return err;
-
- if (nsock->sk->sk_state != BT_CONNECTED) {
- sockfd_put(nsock);
- return -EBADFD;
- }
- ca.device[sizeof(ca.device)-1] = 0;
-
- err = bnep_add_connection(&ca, nsock);
- if (!err) {
- if (copy_to_user(argp, &ca, sizeof(ca)))
- err = -EFAULT;
- } else
- sockfd_put(nsock);
-
- return err;
-
- case BNEPCONNDEL:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
-
- if (copy_from_user(&cd, argp, sizeof(cd)))
- return -EFAULT;
-
- return bnep_del_connection(&cd);
-
- case BNEPGETCONNLIST:
- if (copy_from_user(&cl, argp, sizeof(cl)))
- return -EFAULT;
-
- if (cl.cnum <= 0)
- return -EINVAL;
-
- err = bnep_get_connlist(&cl);
- if (!err && copy_to_user(argp, &cl, sizeof(cl)))
- return -EFAULT;
-
- return err;
-
- case BNEPGETCONNINFO:
- if (copy_from_user(&ci, argp, sizeof(ci)))
- return -EFAULT;
-
- err = bnep_get_conninfo(&ci);
- if (!err && copy_to_user(argp, &ci, sizeof(ci)))
- return -EFAULT;
-
- return err;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-#ifdef CONFIG_COMPAT
-static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- if (cmd == BNEPGETCONNLIST) {
- struct bnep_connlist_req cl;
- u32 uci;
- int err;
-
- if (get_user(cl.cnum, (u32 __user *) arg) ||
- get_user(uci, (u32 __user *) (arg + 4)))
- return -EFAULT;
-
- cl.ci = compat_ptr(uci);
-
- if (cl.cnum <= 0)
- return -EINVAL;
-
- err = bnep_get_connlist(&cl);
-
- if (!err && put_user(cl.cnum, (u32 __user *) arg))
- err = -EFAULT;
-
- return err;
- }
-
- return bnep_sock_ioctl(sock, cmd, arg);
-}
-#endif
-
-static const struct proto_ops bnep_sock_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .release = bnep_sock_release,
- .ioctl = bnep_sock_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = bnep_sock_compat_ioctl,
-#endif
- .bind = sock_no_bind,
- .getname = sock_no_getname,
- .sendmsg = sock_no_sendmsg,
- .recvmsg = sock_no_recvmsg,
- .poll = sock_no_poll,
- .listen = sock_no_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = sock_no_setsockopt,
- .getsockopt = sock_no_getsockopt,
- .connect = sock_no_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .mmap = sock_no_mmap
-};
-
-static struct proto bnep_proto = {
- .name = "BNEP",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct bt_sock)
-};
-
-static int bnep_sock_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
-
- BT_DBG("sock %p", sock);
-
- if (sock->type != SOCK_RAW)
- return -ESOCKTNOSUPPORT;
-
- sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto);
- if (!sk)
- return -ENOMEM;
-
- sock_init_data(sock, sk);
-
- sock->ops = &bnep_sock_ops;
-
- sock->state = SS_UNCONNECTED;
-
- sock_reset_flag(sk, SOCK_ZAPPED);
-
- sk->sk_protocol = protocol;
- sk->sk_state = BT_OPEN;
-
- return 0;
-}
-
-static const struct net_proto_family bnep_sock_family_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .create = bnep_sock_create
-};
-
-int __init bnep_sock_init(void)
-{
- int err;
-
- err = proto_register(&bnep_proto, 0);
- if (err < 0)
- return err;
-
- err = bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
- if (err < 0)
- goto error;
-
- return 0;
-
-error:
- BT_ERR("Can't register BNEP socket");
- proto_unregister(&bnep_proto);
- return err;
-}
-
-void __exit bnep_sock_cleanup(void)
-{
- if (bt_sock_unregister(BTPROTO_BNEP) < 0)
- BT_ERR("Can't unregister BNEP socket");
-
- proto_unregister(&bnep_proto);
-}
diff --git a/net/bluetooth_tizen/cmtp/Kconfig b/net/bluetooth_tizen/cmtp/Kconfig
deleted file mode 100644
index 94cbf42..0000000
--- a/net/bluetooth_tizen/cmtp/Kconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-config BT_CMTP
- tristate "CMTP protocol support"
- depends on BT && ISDN_CAPI
- help
- CMTP (CAPI Message Transport Protocol) is a transport layer
- for CAPI messages. CMTP is required for the Bluetooth Common
- ISDN Access Profile.
-
- Say Y here to compile CMTP support into the kernel or say M to
- compile it as module (cmtp).
-
diff --git a/net/bluetooth_tizen/cmtp/Makefile b/net/bluetooth_tizen/cmtp/Makefile
deleted file mode 100644
index 890a9a5..0000000
--- a/net/bluetooth_tizen/cmtp/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for the Linux Bluetooth CMTP layer
-#
-
-obj-$(CONFIG_BT_CMTP) += cmtp.o
-
-cmtp-objs := core.o sock.o capi.o
diff --git a/net/bluetooth_tizen/cmtp/capi.c b/net/bluetooth_tizen/cmtp/capi.c
deleted file mode 100644
index 50f0d13..0000000
--- a/net/bluetooth_tizen/cmtp/capi.c
+++ /dev/null
@@ -1,624 +0,0 @@
-/*
- CMTP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <linux/file.h>
-#include <linux/wait.h>
-#include <linux/kthread.h>
-#include <net/sock.h>
-
-#include <linux/isdn/capilli.h>
-#include <linux/isdn/capicmd.h>
-#include <linux/isdn/capiutil.h>
-
-#include "cmtp.h"
-
-#define CAPI_INTEROPERABILITY 0x20
-
-#define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
-#define CAPI_INTEROPERABILITY_CONF CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
-#define CAPI_INTEROPERABILITY_IND CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
-#define CAPI_INTEROPERABILITY_RESP CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
-
-#define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2)
-#define CAPI_INTEROPERABILITY_CONF_LEN (CAPI_MSG_BASELEN + 4)
-#define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2)
-#define CAPI_INTEROPERABILITY_RESP_LEN (CAPI_MSG_BASELEN + 2)
-
-#define CAPI_FUNCTION_REGISTER 0
-#define CAPI_FUNCTION_RELEASE 1
-#define CAPI_FUNCTION_GET_PROFILE 2
-#define CAPI_FUNCTION_GET_MANUFACTURER 3
-#define CAPI_FUNCTION_GET_VERSION 4
-#define CAPI_FUNCTION_GET_SERIAL_NUMBER 5
-#define CAPI_FUNCTION_MANUFACTURER 6
-#define CAPI_FUNCTION_LOOPBACK 7
-
-
-#define CMTP_MSGNUM 1
-#define CMTP_APPLID 2
-#define CMTP_MAPPING 3
-
-static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
-{
- struct cmtp_application *app = kzalloc(sizeof(*app), GFP_KERNEL);
-
- BT_DBG("session %p application %p appl %d", session, app, appl);
-
- if (!app)
- return NULL;
-
- app->state = BT_OPEN;
- app->appl = appl;
-
- list_add_tail(&app->list, &session->applications);
-
- return app;
-}
-
-static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
-{
- BT_DBG("session %p application %p", session, app);
-
- if (app) {
- list_del(&app->list);
- kfree(app);
- }
-}
-
-static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
-{
- struct cmtp_application *app;
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &session->applications) {
- app = list_entry(p, struct cmtp_application, list);
- switch (pattern) {
- case CMTP_MSGNUM:
- if (app->msgnum == value)
- return app;
- break;
- case CMTP_APPLID:
- if (app->appl == value)
- return app;
- break;
- case CMTP_MAPPING:
- if (app->mapping == value)
- return app;
- break;
- }
- }
-
- return NULL;
-}
-
-static int cmtp_msgnum_get(struct cmtp_session *session)
-{
- session->msgnum++;
-
- if ((session->msgnum & 0xff) > 200)
- session->msgnum = CMTP_INITIAL_MSGNUM + 1;
-
- return session->msgnum;
-}
-
-static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
-{
- struct cmtp_scb *scb = (void *) skb->cb;
-
- BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-
- scb->id = -1;
- scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
-
- skb_queue_tail(&session->transmit, skb);
-
- wake_up_interruptible(sk_sleep(session->sock->sk));
-}
-
-static void cmtp_send_interopmsg(struct cmtp_session *session,
- __u8 subcmd, __u16 appl, __u16 msgnum,
- __u16 function, unsigned char *buf, int len)
-{
- struct sk_buff *skb;
- unsigned char *s;
-
- BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
-
- skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("Can't allocate memory for interoperability packet");
- return;
- }
-
- s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
-
- capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
- capimsg_setu16(s, 2, appl);
- capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
- capimsg_setu8 (s, 5, subcmd);
- capimsg_setu16(s, 6, msgnum);
-
- /* Interoperability selector (Bluetooth Device Management) */
- capimsg_setu16(s, 8, 0x0001);
-
- capimsg_setu8 (s, 10, 3 + len);
- capimsg_setu16(s, 11, function);
- capimsg_setu8 (s, 13, len);
-
- if (len > 0)
- memcpy(s + 14, buf, len);
-
- cmtp_send_capimsg(session, skb);
-}
-
-static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
-{
- struct capi_ctr *ctrl = &session->ctrl;
- struct cmtp_application *application;
- __u16 appl, msgnum, func, info;
- __u32 controller;
-
- BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-
- switch (CAPIMSG_SUBCOMMAND(skb->data)) {
- case CAPI_CONF:
- if (skb->len < CAPI_MSG_BASELEN + 10)
- break;
-
- func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
- info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
-
- switch (func) {
- case CAPI_FUNCTION_REGISTER:
- msgnum = CAPIMSG_MSGID(skb->data);
-
- application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
- if (application) {
- application->state = BT_CONNECTED;
- application->msgnum = 0;
- application->mapping = CAPIMSG_APPID(skb->data);
- wake_up_interruptible(&session->wait);
- }
-
- break;
-
- case CAPI_FUNCTION_RELEASE:
- appl = CAPIMSG_APPID(skb->data);
-
- application = cmtp_application_get(session, CMTP_MAPPING, appl);
- if (application) {
- application->state = BT_CLOSED;
- application->msgnum = 0;
- wake_up_interruptible(&session->wait);
- }
-
- break;
-
- case CAPI_FUNCTION_GET_PROFILE:
- if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
- break;
-
- controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
- msgnum = CAPIMSG_MSGID(skb->data);
-
- if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
- session->ncontroller = controller;
- wake_up_interruptible(&session->wait);
- break;
- }
-
- if (!info && ctrl) {
- memcpy(&ctrl->profile,
- skb->data + CAPI_MSG_BASELEN + 11,
- sizeof(capi_profile));
- session->state = BT_CONNECTED;
- capi_ctr_ready(ctrl);
- }
-
- break;
-
- case CAPI_FUNCTION_GET_MANUFACTURER:
- if (skb->len < CAPI_MSG_BASELEN + 15)
- break;
-
- controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
-
- if (!info && ctrl) {
- int len = min_t(uint, CAPI_MANUFACTURER_LEN,
- skb->data[CAPI_MSG_BASELEN + 14]);
-
- memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
- strncpy(ctrl->manu,
- skb->data + CAPI_MSG_BASELEN + 15, len);
- }
-
- break;
-
- case CAPI_FUNCTION_GET_VERSION:
- if (skb->len < CAPI_MSG_BASELEN + 32)
- break;
-
- controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
-
- if (!info && ctrl) {
- ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
- ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
- ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
- ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
- }
-
- break;
-
- case CAPI_FUNCTION_GET_SERIAL_NUMBER:
- if (skb->len < CAPI_MSG_BASELEN + 17)
- break;
-
- controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
-
- if (!info && ctrl) {
- int len = min_t(uint, CAPI_SERIAL_LEN,
- skb->data[CAPI_MSG_BASELEN + 16]);
-
- memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
- strncpy(ctrl->serial,
- skb->data + CAPI_MSG_BASELEN + 17, len);
- }
-
- break;
- }
-
- break;
-
- case CAPI_IND:
- if (skb->len < CAPI_MSG_BASELEN + 6)
- break;
-
- func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
-
- if (func == CAPI_FUNCTION_LOOPBACK) {
- int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
- skb->data[CAPI_MSG_BASELEN + 5]);
- appl = CAPIMSG_APPID(skb->data);
- msgnum = CAPIMSG_MSGID(skb->data);
- cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
- skb->data + CAPI_MSG_BASELEN + 6, len);
- }
-
- break;
- }
-
- kfree_skb(skb);
-}
-
-void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
-{
- struct capi_ctr *ctrl = &session->ctrl;
- struct cmtp_application *application;
- __u16 appl;
- __u32 contr;
-
- BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-
- if (skb->len < CAPI_MSG_BASELEN)
- return;
-
- if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
- cmtp_recv_interopmsg(session, skb);
- return;
- }
-
- if (session->flags & (1 << CMTP_LOOPBACK)) {
- kfree_skb(skb);
- return;
- }
-
- appl = CAPIMSG_APPID(skb->data);
- contr = CAPIMSG_CONTROL(skb->data);
-
- application = cmtp_application_get(session, CMTP_MAPPING, appl);
- if (application) {
- appl = application->appl;
- CAPIMSG_SETAPPID(skb->data, appl);
- } else {
- BT_ERR("Can't find application with id %d", appl);
- kfree_skb(skb);
- return;
- }
-
- if ((contr & 0x7f) == 0x01) {
- contr = (contr & 0xffffff80) | session->num;
- CAPIMSG_SETCONTROL(skb->data, contr);
- }
-
- if (!ctrl) {
- BT_ERR("Can't find controller %d for message", session->num);
- kfree_skb(skb);
- return;
- }
-
- capi_ctr_handle_message(ctrl, appl, skb);
-}
-
-static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
-{
- BT_DBG("ctrl %p data %p", ctrl, data);
-
- return 0;
-}
-
-static void cmtp_reset_ctr(struct capi_ctr *ctrl)
-{
- struct cmtp_session *session = ctrl->driverdata;
-
- BT_DBG("ctrl %p", ctrl);
-
- capi_ctr_down(ctrl);
-
- atomic_inc(&session->terminate);
- wake_up_process(session->task);
-}
-
-static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct cmtp_session *session = ctrl->driverdata;
- struct cmtp_application *application;
- unsigned long timeo = CMTP_INTEROP_TIMEOUT;
- unsigned char buf[8];
- int err = 0, nconn, want = rp->level3cnt;
-
- BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
- ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
-
- application = cmtp_application_add(session, appl);
- if (!application) {
- BT_ERR("Can't allocate memory for new application");
- return;
- }
-
- if (want < 0)
- nconn = ctrl->profile.nbchannel * -want;
- else
- nconn = want;
-
- if (nconn == 0)
- nconn = ctrl->profile.nbchannel;
-
- capimsg_setu16(buf, 0, nconn);
- capimsg_setu16(buf, 2, rp->datablkcnt);
- capimsg_setu16(buf, 4, rp->datablklen);
-
- application->state = BT_CONFIG;
- application->msgnum = cmtp_msgnum_get(session);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
- CAPI_FUNCTION_REGISTER, buf, 6);
-
- add_wait_queue(&session->wait, &wait);
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (!timeo) {
- err = -EAGAIN;
- break;
- }
-
- if (application->state == BT_CLOSED) {
- err = -application->err;
- break;
- }
-
- if (application->state == BT_CONNECTED)
- break;
-
- if (signal_pending(current)) {
- err = -EINTR;
- break;
- }
-
- timeo = schedule_timeout(timeo);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&session->wait, &wait);
-
- if (err) {
- cmtp_application_del(session, application);
- return;
- }
-}
-
-static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
-{
- struct cmtp_session *session = ctrl->driverdata;
- struct cmtp_application *application;
-
- BT_DBG("ctrl %p appl %d", ctrl, appl);
-
- application = cmtp_application_get(session, CMTP_APPLID, appl);
- if (!application) {
- BT_ERR("Can't find application");
- return;
- }
-
- application->msgnum = cmtp_msgnum_get(session);
-
- cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
- CAPI_FUNCTION_RELEASE, NULL, 0);
-
- wait_event_interruptible_timeout(session->wait,
- (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
-
- cmtp_application_del(session, application);
-}
-
-static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
-{
- struct cmtp_session *session = ctrl->driverdata;
- struct cmtp_application *application;
- __u16 appl;
- __u32 contr;
-
- BT_DBG("ctrl %p skb %p", ctrl, skb);
-
- appl = CAPIMSG_APPID(skb->data);
- contr = CAPIMSG_CONTROL(skb->data);
-
- application = cmtp_application_get(session, CMTP_APPLID, appl);
- if ((!application) || (application->state != BT_CONNECTED)) {
- BT_ERR("Can't find application with id %d", appl);
- return CAPI_ILLAPPNR;
- }
-
- CAPIMSG_SETAPPID(skb->data, application->mapping);
-
- if ((contr & 0x7f) == session->num) {
- contr = (contr & 0xffffff80) | 0x01;
- CAPIMSG_SETCONTROL(skb->data, contr);
- }
-
- cmtp_send_capimsg(session, skb);
-
- return CAPI_NOERROR;
-}
-
-static char *cmtp_procinfo(struct capi_ctr *ctrl)
-{
- return "CAPI Message Transport Protocol";
-}
-
-static int cmtp_proc_show(struct seq_file *m, void *v)
-{
- struct capi_ctr *ctrl = m->private;
- struct cmtp_session *session = ctrl->driverdata;
- struct cmtp_application *app;
- struct list_head *p, *n;
-
- seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
- seq_printf(m, "addr %s\n", session->name);
- seq_printf(m, "ctrl %d\n", session->num);
-
- list_for_each_safe(p, n, &session->applications) {
- app = list_entry(p, struct cmtp_application, list);
- seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
- }
-
- return 0;
-}
-
-static int cmtp_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, cmtp_proc_show, PDE(inode)->data);
-}
-
-static const struct file_operations cmtp_proc_fops = {
- .owner = THIS_MODULE,
- .open = cmtp_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-int cmtp_attach_device(struct cmtp_session *session)
-{
- unsigned char buf[4];
- long ret;
-
- BT_DBG("session %p", session);
-
- capimsg_setu32(buf, 0, 0);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
- CAPI_FUNCTION_GET_PROFILE, buf, 4);
-
- ret = wait_event_interruptible_timeout(session->wait,
- session->ncontroller, CMTP_INTEROP_TIMEOUT);
-
- BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
-
- if (!ret)
- return -ETIMEDOUT;
-
- if (!session->ncontroller)
- return -ENODEV;
-
- if (session->ncontroller > 1)
- BT_INFO("Setting up only CAPI controller 1");
-
- session->ctrl.owner = THIS_MODULE;
- session->ctrl.driverdata = session;
- strcpy(session->ctrl.name, session->name);
-
- session->ctrl.driver_name = "cmtp";
- session->ctrl.load_firmware = cmtp_load_firmware;
- session->ctrl.reset_ctr = cmtp_reset_ctr;
- session->ctrl.register_appl = cmtp_register_appl;
- session->ctrl.release_appl = cmtp_release_appl;
- session->ctrl.send_message = cmtp_send_message;
-
- session->ctrl.procinfo = cmtp_procinfo;
- session->ctrl.proc_fops = &cmtp_proc_fops;
-
- if (attach_capi_ctr(&session->ctrl) < 0) {
- BT_ERR("Can't attach new controller");
- return -EBUSY;
- }
-
- session->num = session->ctrl.cnr;
-
- BT_DBG("session %p num %d", session, session->num);
-
- capimsg_setu32(buf, 0, 1);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
- CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
- CAPI_FUNCTION_GET_VERSION, buf, 4);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
- CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
- CAPI_FUNCTION_GET_PROFILE, buf, 4);
-
- return 0;
-}
-
-void cmtp_detach_device(struct cmtp_session *session)
-{
- BT_DBG("session %p", session);
-
- detach_capi_ctr(&session->ctrl);
-}
diff --git a/net/bluetooth_tizen/cmtp/cmtp.h b/net/bluetooth_tizen/cmtp/cmtp.h
deleted file mode 100644
index c32638d..0000000
--- a/net/bluetooth_tizen/cmtp/cmtp.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- CMTP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#ifndef __CMTP_H
-#define __CMTP_H
-
-#include <linux/types.h>
-#include <net/bluetooth/bluetooth.h>
-
-#define BTNAMSIZ 18
-
-/* CMTP ioctl defines */
-#define CMTPCONNADD _IOW('C', 200, int)
-#define CMTPCONNDEL _IOW('C', 201, int)
-#define CMTPGETCONNLIST _IOR('C', 210, int)
-#define CMTPGETCONNINFO _IOR('C', 211, int)
-
-#define CMTP_LOOPBACK 0
-
-struct cmtp_connadd_req {
- int sock; /* Connected socket */
- __u32 flags;
-};
-
-struct cmtp_conndel_req {
- bdaddr_t bdaddr;
- __u32 flags;
-};
-
-struct cmtp_conninfo {
- bdaddr_t bdaddr;
- __u32 flags;
- __u16 state;
- int num;
-};
-
-struct cmtp_connlist_req {
- __u32 cnum;
- struct cmtp_conninfo __user *ci;
-};
-
-int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock);
-int cmtp_del_connection(struct cmtp_conndel_req *req);
-int cmtp_get_connlist(struct cmtp_connlist_req *req);
-int cmtp_get_conninfo(struct cmtp_conninfo *ci);
-
-/* CMTP session defines */
-#define CMTP_INTEROP_TIMEOUT (HZ * 5)
-#define CMTP_INITIAL_MSGNUM 0xff00
-
-struct cmtp_session {
- struct list_head list;
-
- struct socket *sock;
-
- bdaddr_t bdaddr;
-
- unsigned long state;
- unsigned long flags;
-
- uint mtu;
-
- char name[BTNAMSIZ];
-
- atomic_t terminate;
- struct task_struct *task;
-
- wait_queue_head_t wait;
-
- int ncontroller;
- int num;
- struct capi_ctr ctrl;
-
- struct list_head applications;
-
- unsigned long blockids;
- int msgnum;
-
- struct sk_buff_head transmit;
-
- struct sk_buff *reassembly[16];
-};
-
-struct cmtp_application {
- struct list_head list;
-
- unsigned long state;
- int err;
-
- __u16 appl;
- __u16 mapping;
-
- __u16 msgnum;
-};
-
-struct cmtp_scb {
- int id;
- int data;
-};
-
-int cmtp_attach_device(struct cmtp_session *session);
-void cmtp_detach_device(struct cmtp_session *session);
-
-void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb);
-
-/* CMTP init defines */
-int cmtp_init_sockets(void);
-void cmtp_cleanup_sockets(void);
-
-#endif /* __CMTP_H */
diff --git a/net/bluetooth_tizen/cmtp/core.c b/net/bluetooth_tizen/cmtp/core.c
deleted file mode 100644
index 6c9c1fd..0000000
--- a/net/bluetooth_tizen/cmtp/core.c
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- CMTP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/freezer.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <linux/file.h>
-#include <linux/init.h>
-#include <linux/kthread.h>
-#include <net/sock.h>
-
-#include <linux/isdn/capilli.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/l2cap.h>
-
-#include "cmtp.h"
-
-#define VERSION "1.0"
-
-static DECLARE_RWSEM(cmtp_session_sem);
-static LIST_HEAD(cmtp_session_list);
-
-static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
-{
- struct cmtp_session *session;
-
- BT_DBG("");
-
- list_for_each_entry(session, &cmtp_session_list, list)
- if (!bacmp(bdaddr, &session->bdaddr))
- return session;
-
- return NULL;
-}
-
-static void __cmtp_link_session(struct cmtp_session *session)
-{
- list_add(&session->list, &cmtp_session_list);
-}
-
-static void __cmtp_unlink_session(struct cmtp_session *session)
-{
- list_del(&session->list);
-}
-
-static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
-{
- memset(ci, 0, sizeof(*ci));
- bacpy(&ci->bdaddr, &session->bdaddr);
-
- ci->flags = session->flags;
- ci->state = session->state;
-
- ci->num = session->num;
-}
-
-
-static inline int cmtp_alloc_block_id(struct cmtp_session *session)
-{
- int i, id = -1;
-
- for (i = 0; i < 16; i++)
- if (!test_and_set_bit(i, &session->blockids)) {
- id = i;
- break;
- }
-
- return id;
-}
-
-static inline void cmtp_free_block_id(struct cmtp_session *session, int id)
-{
- clear_bit(id, &session->blockids);
-}
-
-static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count)
-{
- struct sk_buff *skb = session->reassembly[id], *nskb;
- int size;
-
- BT_DBG("session %p buf %p count %d", session, buf, count);
-
- size = (skb) ? skb->len + count : count;
-
- nskb = alloc_skb(size, GFP_ATOMIC);
- if (!nskb) {
- BT_ERR("Can't allocate memory for CAPI message");
- return;
- }
-
- if (skb && (skb->len > 0))
- skb_copy_from_linear_data(skb, skb_put(nskb, skb->len), skb->len);
-
- memcpy(skb_put(nskb, count), buf, count);
-
- session->reassembly[id] = nskb;
-
- kfree_skb(skb);
-}
-
-static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
-{
- __u8 hdr, hdrlen, id;
- __u16 len;
-
- BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-
- while (skb->len > 0) {
- hdr = skb->data[0];
-
- switch (hdr & 0xc0) {
- case 0x40:
- hdrlen = 2;
- len = skb->data[1];
- break;
- case 0x80:
- hdrlen = 3;
- len = skb->data[1] | (skb->data[2] << 8);
- break;
- default:
- hdrlen = 1;
- len = 0;
- break;
- }
-
- id = (hdr & 0x3c) >> 2;
-
- BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id);
-
- if (hdrlen + len > skb->len) {
- BT_ERR("Wrong size or header information in CMTP frame");
- break;
- }
-
- if (len == 0) {
- skb_pull(skb, hdrlen);
- continue;
- }
-
- switch (hdr & 0x03) {
- case 0x00:
- cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
- cmtp_recv_capimsg(session, session->reassembly[id]);
- session->reassembly[id] = NULL;
- break;
- case 0x01:
- cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
- break;
- default:
- if (session->reassembly[id] != NULL)
- kfree_skb(session->reassembly[id]);
- session->reassembly[id] = NULL;
- break;
- }
-
- skb_pull(skb, hdrlen + len);
- }
-
- kfree_skb(skb);
- return 0;
-}
-
-static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len)
-{
- struct socket *sock = session->sock;
- struct kvec iv = { data, len };
- struct msghdr msg;
-
- BT_DBG("session %p data %p len %d", session, data, len);
-
- if (!len)
- return 0;
-
- memset(&msg, 0, sizeof(msg));
-
- return kernel_sendmsg(sock, &msg, &iv, 1, len);
-}
-
-static void cmtp_process_transmit(struct cmtp_session *session)
-{
- struct sk_buff *skb, *nskb;
- unsigned char *hdr;
- unsigned int size, tail;
-
- BT_DBG("session %p", session);
-
- nskb = alloc_skb(session->mtu, GFP_ATOMIC);
- if (!nskb) {
- BT_ERR("Can't allocate memory for new frame");
- return;
- }
-
- while ((skb = skb_dequeue(&session->transmit))) {
- struct cmtp_scb *scb = (void *) skb->cb;
-
- tail = session->mtu - nskb->len;
- if (tail < 5) {
- cmtp_send_frame(session, nskb->data, nskb->len);
- skb_trim(nskb, 0);
- tail = session->mtu;
- }
-
- size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len);
-
- if (scb->id < 0) {
- scb->id = cmtp_alloc_block_id(session);
- if (scb->id < 0) {
- skb_queue_head(&session->transmit, skb);
- break;
- }
- }
-
- if (size < 256) {
- hdr = skb_put(nskb, 2);
- hdr[0] = 0x40
- | ((scb->id << 2) & 0x3c)
- | ((skb->len == size) ? 0x00 : 0x01);
- hdr[1] = size;
- } else {
- hdr = skb_put(nskb, 3);
- hdr[0] = 0x80
- | ((scb->id << 2) & 0x3c)
- | ((skb->len == size) ? 0x00 : 0x01);
- hdr[1] = size & 0xff;
- hdr[2] = size >> 8;
- }
-
- skb_copy_from_linear_data(skb, skb_put(nskb, size), size);
- skb_pull(skb, size);
-
- if (skb->len > 0) {
- skb_queue_head(&session->transmit, skb);
- } else {
- cmtp_free_block_id(session, scb->id);
- if (scb->data) {
- cmtp_send_frame(session, nskb->data, nskb->len);
- skb_trim(nskb, 0);
- }
- kfree_skb(skb);
- }
- }
-
- cmtp_send_frame(session, nskb->data, nskb->len);
-
- kfree_skb(nskb);
-}
-
-static int cmtp_session(void *arg)
-{
- struct cmtp_session *session = arg;
- struct sock *sk = session->sock->sk;
- struct sk_buff *skb;
- wait_queue_t wait;
-
- BT_DBG("session %p", session);
-
- set_user_nice(current, -15);
-
- init_waitqueue_entry(&wait, current);
- add_wait_queue(sk_sleep(sk), &wait);
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (atomic_read(&session->terminate))
- break;
- if (sk->sk_state != BT_CONNECTED)
- break;
-
- while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
- skb_orphan(skb);
- if (!skb_linearize(skb))
- cmtp_recv_frame(session, skb);
- else
- kfree_skb(skb);
- }
-
- cmtp_process_transmit(session);
-
- schedule();
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(sk), &wait);
-
- down_write(&cmtp_session_sem);
-
- if (!(session->flags & (1 << CMTP_LOOPBACK)))
- cmtp_detach_device(session);
-
- fput(session->sock->file);
-
- __cmtp_unlink_session(session);
-
- up_write(&cmtp_session_sem);
-
- kfree(session);
- module_put_and_exit(0);
- return 0;
-}
-
-int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
-{
- struct cmtp_session *session, *s;
- int i, err;
-
- BT_DBG("");
-
- session = kzalloc(sizeof(struct cmtp_session), GFP_KERNEL);
- if (!session)
- return -ENOMEM;
-
- down_write(&cmtp_session_sem);
-
- s = __cmtp_get_session(&bt_sk(sock->sk)->dst);
- if (s && s->state == BT_CONNECTED) {
- err = -EEXIST;
- goto failed;
- }
-
- bacpy(&session->bdaddr, &bt_sk(sock->sk)->dst);
-
- session->mtu = min_t(uint, l2cap_pi(sock->sk)->chan->omtu,
- l2cap_pi(sock->sk)->chan->imtu);
-
- BT_DBG("mtu %d", session->mtu);
-
- sprintf(session->name, "%s", batostr(&bt_sk(sock->sk)->dst));
-
- session->sock = sock;
- session->state = BT_CONFIG;
-
- init_waitqueue_head(&session->wait);
-
- session->msgnum = CMTP_INITIAL_MSGNUM;
-
- INIT_LIST_HEAD(&session->applications);
-
- skb_queue_head_init(&session->transmit);
-
- for (i = 0; i < 16; i++)
- session->reassembly[i] = NULL;
-
- session->flags = req->flags;
-
- __cmtp_link_session(session);
-
- __module_get(THIS_MODULE);
- session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d",
- session->num);
- if (IS_ERR(session->task)) {
- module_put(THIS_MODULE);
- err = PTR_ERR(session->task);
- goto unlink;
- }
-
- if (!(session->flags & (1 << CMTP_LOOPBACK))) {
- err = cmtp_attach_device(session);
- if (err < 0) {
- atomic_inc(&session->terminate);
- wake_up_process(session->task);
- up_write(&cmtp_session_sem);
- return err;
- }
- }
-
- up_write(&cmtp_session_sem);
- return 0;
-
-unlink:
- __cmtp_unlink_session(session);
-
-failed:
- up_write(&cmtp_session_sem);
- kfree(session);
- return err;
-}
-
-int cmtp_del_connection(struct cmtp_conndel_req *req)
-{
- struct cmtp_session *session;
- int err = 0;
-
- BT_DBG("");
-
- down_read(&cmtp_session_sem);
-
- session = __cmtp_get_session(&req->bdaddr);
- if (session) {
- /* Flush the transmit queue */
- skb_queue_purge(&session->transmit);
-
- /* Stop session thread */
- atomic_inc(&session->terminate);
- wake_up_process(session->task);
- } else
- err = -ENOENT;
-
- up_read(&cmtp_session_sem);
- return err;
-}
-
-int cmtp_get_connlist(struct cmtp_connlist_req *req)
-{
- struct cmtp_session *session;
- int err = 0, n = 0;
-
- BT_DBG("");
-
- down_read(&cmtp_session_sem);
-
- list_for_each_entry(session, &cmtp_session_list, list) {
- struct cmtp_conninfo ci;
-
- __cmtp_copy_session(session, &ci);
-
- if (copy_to_user(req->ci, &ci, sizeof(ci))) {
- err = -EFAULT;
- break;
- }
-
- if (++n >= req->cnum)
- break;
-
- req->ci++;
- }
- req->cnum = n;
-
- up_read(&cmtp_session_sem);
- return err;
-}
-
-int cmtp_get_conninfo(struct cmtp_conninfo *ci)
-{
- struct cmtp_session *session;
- int err = 0;
-
- down_read(&cmtp_session_sem);
-
- session = __cmtp_get_session(&ci->bdaddr);
- if (session)
- __cmtp_copy_session(session, ci);
- else
- err = -ENOENT;
-
- up_read(&cmtp_session_sem);
- return err;
-}
-
-
-static int __init cmtp_init(void)
-{
- BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION);
-
- cmtp_init_sockets();
-
- return 0;
-}
-
-static void __exit cmtp_exit(void)
-{
- cmtp_cleanup_sockets();
-}
-
-module_init(cmtp_init);
-module_exit(cmtp_exit);
-
-MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("Bluetooth CMTP ver " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("bt-proto-5");
diff --git a/net/bluetooth_tizen/cmtp/sock.c b/net/bluetooth_tizen/cmtp/sock.c
deleted file mode 100644
index 1230faa..0000000
--- a/net/bluetooth_tizen/cmtp/sock.c
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- CMTP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <linux/file.h>
-#include <linux/compat.h>
-#include <linux/gfp.h>
-#include <linux/uaccess.h>
-#include <net/sock.h>
-
-#include <linux/isdn/capilli.h>
-
-#include <asm/system.h>
-
-#include "cmtp.h"
-
-static int cmtp_sock_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
-
- BT_DBG("sock %p sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
- sock_orphan(sk);
- sock_put(sk);
-
- return 0;
-}
-
-static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct cmtp_connadd_req ca;
- struct cmtp_conndel_req cd;
- struct cmtp_connlist_req cl;
- struct cmtp_conninfo ci;
- struct socket *nsock;
- void __user *argp = (void __user *)arg;
- int err;
-
- BT_DBG("cmd %x arg %lx", cmd, arg);
-
- switch (cmd) {
- case CMTPCONNADD:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
-
- if (copy_from_user(&ca, argp, sizeof(ca)))
- return -EFAULT;
-
- nsock = sockfd_lookup(ca.sock, &err);
- if (!nsock)
- return err;
-
- if (nsock->sk->sk_state != BT_CONNECTED) {
- sockfd_put(nsock);
- return -EBADFD;
- }
-
- err = cmtp_add_connection(&ca, nsock);
- if (!err) {
- if (copy_to_user(argp, &ca, sizeof(ca)))
- err = -EFAULT;
- } else
- sockfd_put(nsock);
-
- return err;
-
- case CMTPCONNDEL:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
-
- if (copy_from_user(&cd, argp, sizeof(cd)))
- return -EFAULT;
-
- return cmtp_del_connection(&cd);
-
- case CMTPGETCONNLIST:
- if (copy_from_user(&cl, argp, sizeof(cl)))
- return -EFAULT;
-
- if (cl.cnum <= 0)
- return -EINVAL;
-
- err = cmtp_get_connlist(&cl);
- if (!err && copy_to_user(argp, &cl, sizeof(cl)))
- return -EFAULT;
-
- return err;
-
- case CMTPGETCONNINFO:
- if (copy_from_user(&ci, argp, sizeof(ci)))
- return -EFAULT;
-
- err = cmtp_get_conninfo(&ci);
- if (!err && copy_to_user(argp, &ci, sizeof(ci)))
- return -EFAULT;
-
- return err;
- }
-
- return -EINVAL;
-}
-
-#ifdef CONFIG_COMPAT
-static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- if (cmd == CMTPGETCONNLIST) {
- struct cmtp_connlist_req cl;
- u32 uci;
- int err;
-
- if (get_user(cl.cnum, (u32 __user *) arg) ||
- get_user(uci, (u32 __user *) (arg + 4)))
- return -EFAULT;
-
- cl.ci = compat_ptr(uci);
-
- if (cl.cnum <= 0)
- return -EINVAL;
-
- err = cmtp_get_connlist(&cl);
-
- if (!err && put_user(cl.cnum, (u32 __user *) arg))
- err = -EFAULT;
-
- return err;
- }
-
- return cmtp_sock_ioctl(sock, cmd, arg);
-}
-#endif
-
-static const struct proto_ops cmtp_sock_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .release = cmtp_sock_release,
- .ioctl = cmtp_sock_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = cmtp_sock_compat_ioctl,
-#endif
- .bind = sock_no_bind,
- .getname = sock_no_getname,
- .sendmsg = sock_no_sendmsg,
- .recvmsg = sock_no_recvmsg,
- .poll = sock_no_poll,
- .listen = sock_no_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = sock_no_setsockopt,
- .getsockopt = sock_no_getsockopt,
- .connect = sock_no_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .mmap = sock_no_mmap
-};
-
-static struct proto cmtp_proto = {
- .name = "CMTP",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct bt_sock)
-};
-
-static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
-
- BT_DBG("sock %p", sock);
-
- if (sock->type != SOCK_RAW)
- return -ESOCKTNOSUPPORT;
-
- sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto);
- if (!sk)
- return -ENOMEM;
-
- sock_init_data(sock, sk);
-
- sock->ops = &cmtp_sock_ops;
-
- sock->state = SS_UNCONNECTED;
-
- sock_reset_flag(sk, SOCK_ZAPPED);
-
- sk->sk_protocol = protocol;
- sk->sk_state = BT_OPEN;
-
- return 0;
-}
-
-static const struct net_proto_family cmtp_sock_family_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .create = cmtp_sock_create
-};
-
-int cmtp_init_sockets(void)
-{
- int err;
-
- err = proto_register(&cmtp_proto, 0);
- if (err < 0)
- return err;
-
- err = bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops);
- if (err < 0)
- goto error;
-
- return 0;
-
-error:
- BT_ERR("Can't register CMTP socket");
- proto_unregister(&cmtp_proto);
- return err;
-}
-
-void cmtp_cleanup_sockets(void)
-{
- if (bt_sock_unregister(BTPROTO_CMTP) < 0)
- BT_ERR("Can't unregister CMTP socket");
-
- proto_unregister(&cmtp_proto);
-}
diff --git a/net/bluetooth_tizen/hci_conn.c b/net/bluetooth_tizen/hci_conn.c
deleted file mode 100644
index 459227d..0000000
--- a/net/bluetooth_tizen/hci_conn.c
+++ /dev/null
@@ -1,984 +0,0 @@
-/*
- BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
-
- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/* Bluetooth HCI connection handling. */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <linux/notifier.h>
-#include <net/sock.h>
-
-#include <asm/system.h>
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
-static void hci_le_connect(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_cp_le_create_conn cp;
-
- conn->state = BT_CONNECT;
- conn->out = true;
- conn->link_mode |= HCI_LM_MASTER;
- conn->sec_level = BT_SECURITY_LOW;
-
- memset(&cp, 0, sizeof(cp));
- cp.scan_interval = cpu_to_le16(0x0060);
- cp.scan_window = cpu_to_le16(0x0030);
- bacpy(&cp.peer_addr, &conn->dst);
- cp.peer_addr_type = conn->dst_type;
- cp.conn_interval_min = cpu_to_le16(0x0028);
- cp.conn_interval_max = cpu_to_le16(0x0038);
- cp.supervision_timeout = cpu_to_le16(0x002a);
- cp.min_ce_len = cpu_to_le16(0x0000);
- cp.max_ce_len = cpu_to_le16(0x0000);
-
- hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
-}
-
-static void hci_le_connect_cancel(struct hci_conn *conn)
-{
- hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL);
-}
-
-void hci_acl_connect(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
- struct inquiry_entry *ie;
- struct hci_cp_create_conn cp;
-
- BT_DBG("hcon %p", conn);
-
- conn->state = BT_CONNECT;
- conn->out = true;
-
- conn->link_mode = HCI_LM_MASTER;
-
- conn->attempt++;
-
- conn->link_policy = hdev->link_policy;
-
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, &conn->dst);
- cp.pscan_rep_mode = 0x02;
-
- ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
- if (ie) {
- if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
- cp.pscan_rep_mode = ie->data.pscan_rep_mode;
- cp.pscan_mode = ie->data.pscan_mode;
- cp.clock_offset = ie->data.clock_offset |
- cpu_to_le16(0x8000);
- }
-
- memcpy(conn->dev_class, ie->data.dev_class, 3);
- if (ie->data.ssp_mode > 0)
- set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
- }
-
- cp.pkt_type = cpu_to_le16(conn->pkt_type);
- if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
- cp.role_switch = 0x01;
- else
- cp.role_switch = 0x00;
-
- hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);
-}
-
-static void hci_acl_connect_cancel(struct hci_conn *conn)
-{
- struct hci_cp_create_conn_cancel cp;
-
- BT_DBG("%p", conn);
-
- if (conn->hdev->hci_ver < BLUETOOTH_VER_1_2)
- return;
-
- bacpy(&cp.bdaddr, &conn->dst);
- hci_send_cmd(conn->hdev, HCI_OP_CREATE_CONN_CANCEL, sizeof(cp), &cp);
-}
-
-void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
-{
- struct hci_cp_disconnect cp;
-
- BT_DBG("%p", conn);
-
- conn->state = BT_DISCONN;
-
- cp.handle = cpu_to_le16(conn->handle);
- cp.reason = reason;
- hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
-}
-
-void hci_add_sco(struct hci_conn *conn, __u16 handle)
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_cp_add_sco cp;
-
- BT_DBG("%p", conn);
-
- conn->state = BT_CONNECT;
- conn->out = true;
-
- conn->attempt++;
-
- cp.handle = cpu_to_le16(handle);
- cp.pkt_type = cpu_to_le16(conn->pkt_type);
-
- hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp);
-}
-
-void hci_setup_sync(struct hci_conn *conn, __u16 handle)
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_cp_setup_sync_conn cp;
-
- BT_DBG("%p", conn);
-
- conn->state = BT_CONNECT;
- conn->out = true;
-
- conn->attempt++;
-
- cp.handle = cpu_to_le16(handle);
- cp.pkt_type = cpu_to_le16(conn->pkt_type);
-
- cp.tx_bandwidth = cpu_to_le32(0x00001f40);
- cp.rx_bandwidth = cpu_to_le32(0x00001f40);
- cp.max_latency = cpu_to_le16(0xffff);
- cp.voice_setting = cpu_to_le16(hdev->voice_setting);
- cp.retrans_effort = 0xff;
-
- hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
-}
-
-void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
- u16 latency, u16 to_multiplier)
-{
- struct hci_cp_le_conn_update cp;
- struct hci_dev *hdev = conn->hdev;
-
- memset(&cp, 0, sizeof(cp));
-
- cp.handle = cpu_to_le16(conn->handle);
- cp.conn_interval_min = cpu_to_le16(min);
- cp.conn_interval_max = cpu_to_le16(max);
- cp.conn_latency = cpu_to_le16(latency);
- cp.supervision_timeout = cpu_to_le16(to_multiplier);
- cp.min_ce_len = cpu_to_le16(0x0001);
- cp.max_ce_len = cpu_to_le16(0x0001);
-
- hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp);
-}
-EXPORT_SYMBOL(hci_le_conn_update);
-
-void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
- __u8 ltk[16])
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_cp_le_start_enc cp;
-
- BT_DBG("%p", conn);
-
- memset(&cp, 0, sizeof(cp));
-
- cp.handle = cpu_to_le16(conn->handle);
- memcpy(cp.ltk, ltk, sizeof(cp.ltk));
- cp.ediv = ediv;
- memcpy(cp.rand, rand, sizeof(cp.rand));
-
- hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
-}
-EXPORT_SYMBOL(hci_le_start_enc);
-
-void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16])
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_cp_le_ltk_reply cp;
-
- BT_DBG("%p", conn);
-
- memset(&cp, 0, sizeof(cp));
-
- cp.handle = cpu_to_le16(conn->handle);
- memcpy(cp.ltk, ltk, sizeof(ltk));
-
- hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
-}
-EXPORT_SYMBOL(hci_le_ltk_reply);
-
-void hci_le_ltk_neg_reply(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_cp_le_ltk_neg_reply cp;
-
- BT_DBG("%p", conn);
-
- memset(&cp, 0, sizeof(cp));
-
- cp.handle = cpu_to_le16(conn->handle);
-
- hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(cp), &cp);
-}
-
-/* Device _must_ be locked */
-void hci_sco_setup(struct hci_conn *conn, __u8 status)
-{
- struct hci_conn *sco = conn->link;
-
- BT_DBG("%p", conn);
-
- if (!sco)
- return;
-
- if (!status) {
- if (lmp_esco_capable(conn->hdev))
- hci_setup_sync(sco, conn->handle);
- else
- hci_add_sco(sco, conn->handle);
- } else {
- hci_proto_connect_cfm(sco, status);
- hci_conn_del(sco);
- }
-}
-
-static void hci_conn_timeout(struct work_struct *work)
-{
- struct hci_conn *conn = container_of(work, struct hci_conn,
- disc_work.work);
- __u8 reason;
-
- BT_DBG("conn %p state %s", conn, state_to_string(conn->state));
-
- if (atomic_read(&conn->refcnt))
- return;
-
- switch (conn->state) {
- case BT_CONNECT:
- case BT_CONNECT2:
- if (conn->out) {
- if (conn->type == ACL_LINK)
- hci_acl_connect_cancel(conn);
- else if (conn->type == LE_LINK)
- hci_le_connect_cancel(conn);
- }
- break;
- case BT_CONFIG:
- case BT_CONNECTED:
- reason = hci_proto_disconn_ind(conn);
- hci_acl_disconn(conn, reason);
- break;
- default:
- conn->state = BT_CLOSED;
- break;
- }
-}
-
-/* Enter sniff mode */
-static void hci_conn_enter_sniff_mode(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
-
- BT_DBG("conn %p mode %d", conn, conn->mode);
-
- if (test_bit(HCI_RAW, &hdev->flags))
- return;
-
- if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn))
- return;
-
- if (conn->mode != HCI_CM_ACTIVE || !(conn->link_policy & HCI_LP_SNIFF))
- return;
-
- if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) {
- struct hci_cp_sniff_subrate cp;
- cp.handle = cpu_to_le16(conn->handle);
- cp.max_latency = cpu_to_le16(0);
- cp.min_remote_timeout = cpu_to_le16(0);
- cp.min_local_timeout = cpu_to_le16(0);
- hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
- }
-
- if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
- struct hci_cp_sniff_mode cp;
- cp.handle = cpu_to_le16(conn->handle);
- cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
- cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
- cp.attempt = cpu_to_le16(4);
- cp.timeout = cpu_to_le16(1);
- hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
- }
-}
-
-static void hci_conn_idle(unsigned long arg)
-{
- struct hci_conn *conn = (void *) arg;
-
- BT_DBG("conn %p mode %d", conn, conn->mode);
-
- hci_conn_enter_sniff_mode(conn);
-}
-
-static void hci_conn_auto_accept(unsigned long arg)
-{
- struct hci_conn *conn = (void *) arg;
- struct hci_dev *hdev = conn->hdev;
-
- hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst),
- &conn->dst);
-}
-
-struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
-{
- struct hci_conn *conn;
-
- BT_DBG("%s dst %s", hdev->name, batostr(dst));
-
- conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL);
- if (!conn)
- return NULL;
-
- bacpy(&conn->dst, dst);
- conn->hdev = hdev;
- conn->type = type;
- conn->mode = HCI_CM_ACTIVE;
- conn->state = BT_OPEN;
- conn->auth_type = HCI_AT_GENERAL_BONDING;
- conn->io_capability = hdev->io_capability;
- conn->remote_auth = 0xff;
- conn->key_type = 0xff;
-
- set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
- conn->disc_timeout = HCI_DISCONN_TIMEOUT;
-
- switch (type) {
- case ACL_LINK:
- conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
- break;
- case SCO_LINK:
- if (lmp_esco_capable(hdev))
- conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
- (hdev->esco_type & EDR_ESCO_MASK);
- else
- conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK;
- break;
- case ESCO_LINK:
- conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK;
- break;
- }
-
- skb_queue_head_init(&conn->data_q);
-
- INIT_LIST_HEAD(&conn->chan_list);
-
- INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout);
- setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
- setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept,
- (unsigned long) conn);
-
- atomic_set(&conn->refcnt, 0);
-
- hci_dev_hold(hdev);
-
- hci_conn_hash_add(hdev, conn);
- if (hdev->notify)
- hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
-
- atomic_set(&conn->devref, 0);
-
- hci_conn_init_sysfs(conn);
-
- return conn;
-}
-
-int hci_conn_del(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
-
- BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
-
- del_timer(&conn->idle_timer);
-
- cancel_delayed_work_sync(&conn->disc_work);
-
- del_timer(&conn->auto_accept_timer);
-
- if (conn->type == ACL_LINK) {
- struct hci_conn *sco = conn->link;
- if (sco)
- sco->link = NULL;
-
- /* Unacked frames */
- hdev->acl_cnt += conn->sent;
- } else if (conn->type == LE_LINK) {
- if (hdev->le_pkts)
- hdev->le_cnt += conn->sent;
- else
- hdev->acl_cnt += conn->sent;
- } else {
- struct hci_conn *acl = conn->link;
- if (acl) {
- acl->link = NULL;
- hci_conn_put(acl);
- }
- }
-
-
- hci_chan_list_flush(conn);
-
- hci_conn_hash_del(hdev, conn);
- if (hdev->notify)
- hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
-
- skb_queue_purge(&conn->data_q);
-
- hci_conn_put_device(conn);
-
- hci_dev_put(hdev);
-
- if (conn->handle == 0)
- kfree(conn);
-
- return 0;
-}
-
-struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
-{
- int use_src = bacmp(src, BDADDR_ANY);
- struct hci_dev *hdev = NULL, *d;
-
- BT_DBG("%s -> %s", batostr(src), batostr(dst));
-
- read_lock(&hci_dev_list_lock);
-
- list_for_each_entry(d, &hci_dev_list, list) {
- if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags))
- continue;
-
- /* Simple routing:
- * No source address - find interface with bdaddr != dst
- * Source address - find interface with bdaddr == src
- */
-
- if (use_src) {
- if (!bacmp(&d->bdaddr, src)) {
- hdev = d; break;
- }
- } else {
- if (bacmp(&d->bdaddr, dst)) {
- hdev = d; break;
- }
- }
- }
-
- if (hdev)
- hdev = hci_dev_hold(hdev);
-
- read_unlock(&hci_dev_list_lock);
- return hdev;
-}
-EXPORT_SYMBOL(hci_get_route);
-
-/* Create SCO, ACL or LE connection.
- * Device _must_ be locked */
-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type)
-{
- struct hci_conn *acl;
- struct hci_conn *sco;
- struct hci_conn *le;
-
- BT_DBG("%s dst %s", hdev->name, batostr(dst));
-
- if (type == LE_LINK) {
- struct adv_entry *entry;
-
- le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
- if (le)
- return ERR_PTR(-EBUSY);
-
- entry = hci_find_adv_entry(hdev, dst);
- if (!entry)
- return ERR_PTR(-EHOSTUNREACH);
-
- le = hci_conn_add(hdev, LE_LINK, dst);
- if (!le)
- return ERR_PTR(-ENOMEM);
-
- le->dst_type = entry->bdaddr_type;
-
- hci_le_connect(le);
-
- hci_conn_hold(le);
-
- return le;
- }
-
- acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
- if (!acl) {
- acl = hci_conn_add(hdev, ACL_LINK, dst);
- if (!acl)
- return ERR_PTR(-ENOMEM);
- }
-
- hci_conn_hold(acl);
-
- if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
- acl->sec_level = BT_SECURITY_LOW;
- acl->pending_sec_level = sec_level;
- acl->auth_type = auth_type;
- hci_acl_connect(acl);
- }
-
- if (type == ACL_LINK)
- return acl;
-
- sco = hci_conn_hash_lookup_ba(hdev, type, dst);
- if (!sco) {
- sco = hci_conn_add(hdev, type, dst);
- if (!sco) {
- hci_conn_put(acl);
- return ERR_PTR(-ENOMEM);
- }
- }
-
- acl->link = sco;
- sco->link = acl;
-
- hci_conn_hold(sco);
-
- if (acl->state == BT_CONNECTED &&
- (sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
- set_bit(HCI_CONN_POWER_SAVE, &acl->flags);
- hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON);
-
- if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->flags)) {
- /* defer SCO setup until mode change completed */
- set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->flags);
- return sco;
- }
-
- hci_sco_setup(acl, 0x00);
- }
-
- return sco;
-}
-EXPORT_SYMBOL(hci_connect);
-
-/* Check link security requirement */
-int hci_conn_check_link_mode(struct hci_conn *conn)
-{
- BT_DBG("conn %p", conn);
-
- if (hci_conn_ssp_enabled(conn) && !(conn->link_mode & HCI_LM_ENCRYPT))
- return 0;
-
- return 1;
-}
-EXPORT_SYMBOL(hci_conn_check_link_mode);
-
-/* Authenticate remote device */
-static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
-{
- BT_DBG("conn %p", conn);
-
- if (conn->pending_sec_level > sec_level)
- sec_level = conn->pending_sec_level;
-
- if (sec_level > conn->sec_level)
- conn->pending_sec_level = sec_level;
- else if (conn->link_mode & HCI_LM_AUTH)
- return 1;
-
- /* Make sure we preserve an existing MITM requirement*/
- auth_type |= (conn->auth_type & 0x01);
-
- conn->auth_type = auth_type;
-
- if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
- struct hci_cp_auth_requested cp;
-
- /* encrypt must be pending if auth is also pending */
- set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
-
- cp.handle = cpu_to_le16(conn->handle);
- hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
- sizeof(cp), &cp);
- if (conn->key_type != 0xff)
- set_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
- }
-
- return 0;
-}
-
-/* Encrypt the the link */
-static void hci_conn_encrypt(struct hci_conn *conn)
-{
- BT_DBG("conn %p", conn);
-
- if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) {
- struct hci_cp_set_conn_encrypt cp;
- cp.handle = cpu_to_le16(conn->handle);
- cp.encrypt = 0x01;
- hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
- &cp);
- }
-}
-
-/* Enable security */
-int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
-{
- BT_DBG("conn %p", conn);
-
- /* For sdp we don't need the link key. */
- if (sec_level == BT_SECURITY_SDP)
- return 1;
-
- /* For non 2.1 devices and low security level we don't need the link
- key. */
- if (sec_level == BT_SECURITY_LOW && !hci_conn_ssp_enabled(conn))
- return 1;
-
- /* For other security levels we need the link key. */
- if (!(conn->link_mode & HCI_LM_AUTH))
- goto auth;
-
- /* An authenticated combination key has sufficient security for any
- security level. */
- if (conn->key_type == HCI_LK_AUTH_COMBINATION)
- goto encrypt;
-
- /* An unauthenticated combination key has sufficient security for
- security level 1 and 2. */
- if (conn->key_type == HCI_LK_UNAUTH_COMBINATION &&
- (sec_level == BT_SECURITY_MEDIUM ||
- sec_level == BT_SECURITY_LOW))
- goto encrypt;
-
- /* A combination key has always sufficient security for the security
- levels 1 or 2. High security level requires the combination key
- is generated using maximum PIN code length (16).
- For pre 2.1 units. */
- if (conn->key_type == HCI_LK_COMBINATION &&
- (sec_level != BT_SECURITY_HIGH ||
- conn->pin_length == 16))
- goto encrypt;
-
-auth:
- if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
- return 0;
-
- if (!hci_conn_auth(conn, sec_level, auth_type))
- return 0;
-
-encrypt:
- if (conn->link_mode & HCI_LM_ENCRYPT)
- return 1;
-
- hci_conn_encrypt(conn);
- return 0;
-}
-EXPORT_SYMBOL(hci_conn_security);
-
-/* Check secure link requirement */
-int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level)
-{
- BT_DBG("conn %p", conn);
-
- if (sec_level != BT_SECURITY_HIGH)
- return 1; /* Accept if non-secure is required */
-
- if (conn->sec_level == BT_SECURITY_HIGH)
- return 1;
-
- return 0; /* Reject not secure link */
-}
-EXPORT_SYMBOL(hci_conn_check_secure);
-
-/* Change link key */
-int hci_conn_change_link_key(struct hci_conn *conn)
-{
- BT_DBG("conn %p", conn);
-
- if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
- struct hci_cp_change_conn_link_key cp;
- cp.handle = cpu_to_le16(conn->handle);
- hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
- sizeof(cp), &cp);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(hci_conn_change_link_key);
-
-/* Switch role */
-int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
-{
- BT_DBG("conn %p", conn);
-
- if (!role && conn->link_mode & HCI_LM_MASTER)
- return 1;
-
- if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) {
- struct hci_cp_switch_role cp;
- bacpy(&cp.bdaddr, &conn->dst);
- cp.role = role;
- hci_send_cmd(conn->hdev, HCI_OP_SWITCH_ROLE, sizeof(cp), &cp);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(hci_conn_switch_role);
-
-/* Enter active mode */
-void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
-{
- struct hci_dev *hdev = conn->hdev;
-
- BT_DBG("conn %p mode %d", conn, conn->mode);
-
- if (test_bit(HCI_RAW, &hdev->flags))
- return;
-
- if (conn->mode != HCI_CM_SNIFF)
- goto timer;
-
- if (!test_bit(HCI_CONN_POWER_SAVE, &conn->flags) && !force_active)
- goto timer;
-
- if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
- struct hci_cp_exit_sniff_mode cp;
- cp.handle = cpu_to_le16(conn->handle);
- hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp);
- }
-
-timer:
- if (hdev->idle_timeout > 0)
- mod_timer(&conn->idle_timer,
- jiffies + msecs_to_jiffies(hdev->idle_timeout));
-}
-
-/* Drop all connection on the device */
-void hci_conn_hash_flush(struct hci_dev *hdev)
-{
- struct hci_conn_hash *h = &hdev->conn_hash;
- struct hci_conn *c, *n;
-
- BT_DBG("hdev %s", hdev->name);
-
- list_for_each_entry_safe(c, n, &h->list, list) {
- c->state = BT_CLOSED;
-
- hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);
- hci_conn_del(c);
- }
-}
-
-/* Check pending connect attempts */
-void hci_conn_check_pending(struct hci_dev *hdev)
-{
- struct hci_conn *conn;
-
- BT_DBG("hdev %s", hdev->name);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
- if (conn)
- hci_acl_connect(conn);
-
- hci_dev_unlock(hdev);
-}
-
-void hci_conn_hold_device(struct hci_conn *conn)
-{
- atomic_inc(&conn->devref);
-}
-EXPORT_SYMBOL(hci_conn_hold_device);
-
-void hci_conn_put_device(struct hci_conn *conn)
-{
- if (atomic_dec_and_test(&conn->devref))
- hci_conn_del_sysfs(conn);
-}
-EXPORT_SYMBOL(hci_conn_put_device);
-
-int hci_get_conn_list(void __user *arg)
-{
- register struct hci_conn *c;
- struct hci_conn_list_req req, *cl;
- struct hci_conn_info *ci;
- struct hci_dev *hdev;
- int n = 0, size, err;
-
- if (copy_from_user(&req, arg, sizeof(req)))
- return -EFAULT;
-
- if (!req.conn_num || req.conn_num > (PAGE_SIZE * 2) / sizeof(*ci))
- return -EINVAL;
-
- size = sizeof(req) + req.conn_num * sizeof(*ci);
-
- cl = kmalloc(size, GFP_KERNEL);
- if (!cl)
- return -ENOMEM;
-
- hdev = hci_dev_get(req.dev_id);
- if (!hdev) {
- kfree(cl);
- return -ENODEV;
- }
-
- ci = cl->conn_info;
-
- hci_dev_lock(hdev);
- list_for_each_entry(c, &hdev->conn_hash.list, list) {
- bacpy(&(ci + n)->bdaddr, &c->dst);
- (ci + n)->handle = c->handle;
- (ci + n)->type = c->type;
- (ci + n)->out = c->out;
- (ci + n)->state = c->state;
- (ci + n)->link_mode = c->link_mode;
- if (++n >= req.conn_num)
- break;
- }
- hci_dev_unlock(hdev);
-
- cl->dev_id = hdev->id;
- cl->conn_num = n;
- size = sizeof(req) + n * sizeof(*ci);
-
- hci_dev_put(hdev);
-
- err = copy_to_user(arg, cl, size);
- kfree(cl);
-
- return err ? -EFAULT : 0;
-}
-
-int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
-{
- struct hci_conn_info_req req;
- struct hci_conn_info ci;
- struct hci_conn *conn;
- char __user *ptr = arg + sizeof(req);
-
- if (copy_from_user(&req, arg, sizeof(req)))
- return -EFAULT;
-
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
- if (conn) {
- bacpy(&ci.bdaddr, &conn->dst);
- ci.handle = conn->handle;
- ci.type = conn->type;
- ci.out = conn->out;
- ci.state = conn->state;
- ci.link_mode = conn->link_mode;
- }
- hci_dev_unlock(hdev);
-
- if (!conn)
- return -ENOENT;
-
- return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
-}
-
-int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
-{
- struct hci_auth_info_req req;
- struct hci_conn *conn;
-
- if (copy_from_user(&req, arg, sizeof(req)))
- return -EFAULT;
-
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr);
- if (conn)
- req.type = conn->auth_type;
- hci_dev_unlock(hdev);
-
- if (!conn)
- return -ENOENT;
-
- return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0;
-}
-
-struct hci_chan *hci_chan_create(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_chan *chan;
-
- BT_DBG("%s conn %p", hdev->name, conn);
-
- chan = kzalloc(sizeof(struct hci_chan), GFP_KERNEL);
- if (!chan)
- return NULL;
-
- chan->conn = conn;
- skb_queue_head_init(&chan->data_q);
-
- list_add_rcu(&chan->list, &conn->chan_list);
-
- return chan;
-}
-
-int hci_chan_del(struct hci_chan *chan)
-{
- struct hci_conn *conn = chan->conn;
- struct hci_dev *hdev = conn->hdev;
-
- BT_DBG("%s conn %p chan %p", hdev->name, conn, chan);
-
- list_del_rcu(&chan->list);
-
- synchronize_rcu();
-
- skb_queue_purge(&chan->data_q);
- kfree(chan);
-
- return 0;
-}
-
-void hci_chan_list_flush(struct hci_conn *conn)
-{
- struct hci_chan *chan, *n;
-
- BT_DBG("conn %p", conn);
-
- list_for_each_entry_safe(chan, n, &conn->chan_list, list)
- hci_chan_del(chan);
-}
diff --git a/net/bluetooth_tizen/hci_core.c b/net/bluetooth_tizen/hci_core.c
deleted file mode 100644
index 1c69c54..0000000
--- a/net/bluetooth_tizen/hci_core.c
+++ /dev/null
@@ -1,2966 +0,0 @@
-/*
- BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
- Copyright (C) 2011 ProFUSION Embedded Systems
-
- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/* Bluetooth HCI core. */
-
-#include <linux/jiffies.h>
-#include <linux/module.h>
-#include <linux/kmod.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-#include <linux/notifier.h>
-#include <linux/rfkill.h>
-#include <linux/timer.h>
-#include <linux/crypto.h>
-#include <net/sock.h>
-
-#include <asm/system.h>
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
-#define AUTO_OFF_TIMEOUT 2000
-
-static void hci_rx_work(struct work_struct *work);
-static void hci_cmd_work(struct work_struct *work);
-static void hci_tx_work(struct work_struct *work);
-
-/* HCI device list */
-LIST_HEAD(hci_dev_list);
-DEFINE_RWLOCK(hci_dev_list_lock);
-
-/* HCI callback list */
-LIST_HEAD(hci_cb_list);
-DEFINE_RWLOCK(hci_cb_list_lock);
-
-/* HCI notifiers list */
-static ATOMIC_NOTIFIER_HEAD(hci_notifier);
-
-/* ---- HCI notifications ---- */
-
-int hci_register_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_register(&hci_notifier, nb);
-}
-
-int hci_unregister_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister(&hci_notifier, nb);
-}
-
-static void hci_notify(struct hci_dev *hdev, int event)
-{
- atomic_notifier_call_chain(&hci_notifier, event, hdev);
-}
-
-/* ---- HCI requests ---- */
-
-void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result)
-{
- BT_DBG("%s command 0x%04x result 0x%2.2x", hdev->name, cmd, result);
-
- /* If this is the init phase check if the completed command matches
- * the last init command, and if not just return.
- */
- if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd) {
- struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
- struct sk_buff *skb;
-
- /* Some CSR based controllers generate a spontaneous
- * reset complete event during init and any pending
- * command will never be completed. In such a case we
- * need to resend whatever was the last sent
- * command.
- */
-
- if (cmd != HCI_OP_RESET || sent->opcode == HCI_OP_RESET)
- return;
-
- skb = skb_clone(hdev->sent_cmd, GFP_ATOMIC);
- if (skb) {
- skb_queue_head(&hdev->cmd_q, skb);
- queue_work(hdev->workqueue, &hdev->cmd_work);
- }
-
- return;
- }
-
- if (hdev->req_status == HCI_REQ_PEND) {
- hdev->req_result = result;
- hdev->req_status = HCI_REQ_DONE;
- wake_up_interruptible(&hdev->req_wait_q);
- }
-}
-
-static void hci_req_cancel(struct hci_dev *hdev, int err)
-{
- BT_DBG("%s err 0x%2.2x", hdev->name, err);
-
- if (hdev->req_status == HCI_REQ_PEND) {
- hdev->req_result = err;
- hdev->req_status = HCI_REQ_CANCELED;
- wake_up_interruptible(&hdev->req_wait_q);
- }
-}
-
-/* Execute request and wait for completion. */
-static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
- unsigned long opt, __u32 timeout)
-{
- DECLARE_WAITQUEUE(wait, current);
- int err = 0;
-
- BT_DBG("%s start", hdev->name);
-
- hdev->req_status = HCI_REQ_PEND;
-
- add_wait_queue(&hdev->req_wait_q, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
-
- req(hdev, opt);
- schedule_timeout(timeout);
-
- remove_wait_queue(&hdev->req_wait_q, &wait);
-
- if (signal_pending(current))
- return -EINTR;
-
- switch (hdev->req_status) {
- case HCI_REQ_DONE:
- err = -bt_to_errno(hdev->req_result);
- break;
-
- case HCI_REQ_CANCELED:
- err = -hdev->req_result;
- break;
-
- default:
- err = -ETIMEDOUT;
- break;
- }
-
- hdev->req_status = hdev->req_result = 0;
-
- BT_DBG("%s end: err %d", hdev->name, err);
-
- return err;
-}
-
-static inline int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
- unsigned long opt, __u32 timeout)
-{
- int ret;
-
- if (!test_bit(HCI_UP, &hdev->flags))
- return -ENETDOWN;
-
- /* Serialize all requests */
- hci_req_lock(hdev);
- ret = __hci_request(hdev, req, opt, timeout);
- hci_req_unlock(hdev);
-
- return ret;
-}
-
-static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
-{
- BT_DBG("%s %ld", hdev->name, opt);
-
- /* Reset device */
- set_bit(HCI_RESET, &hdev->flags);
- hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
-}
-
-static void bredr_init(struct hci_dev *hdev)
-{
- struct hci_cp_delete_stored_link_key cp;
- __le16 param;
- __u8 flt_type;
-
- hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
-
- /* Mandatory initialization */
-
- /* Reset */
- if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
- set_bit(HCI_RESET, &hdev->flags);
- hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
- }
-
- /* Read Local Supported Features */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
-
- /* Read Local Version */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
-
- /* Read Buffer Size (ACL mtu, max pkt, etc.) */
- hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
-
- /* Read BD Address */
- hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
-
- /* Read Class of Device */
- hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
-
- /* Read Local Name */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
-
- /* Read Voice Setting */
- hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
-
- /* Optional initialization */
-
- /* Clear Event Filters */
- flt_type = HCI_FLT_CLEAR_ALL;
- hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
-
- /* Connection accept timeout ~20 secs */
- param = cpu_to_le16(0x7d00);
- hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
-
- bacpy(&cp.bdaddr, BDADDR_ANY);
- cp.delete_all = 1;
- hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
-}
-
-static void amp_init(struct hci_dev *hdev)
-{
- hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED;
-
- /* Reset */
- hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
-
- /* Read Local Version */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
-}
-
-static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
-{
- struct sk_buff *skb;
-
- BT_DBG("%s %ld", hdev->name, opt);
-
- /* Driver initialization */
-
- /* Special commands */
- while ((skb = skb_dequeue(&hdev->driver_init))) {
- bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
- skb->dev = (void *) hdev;
-
- skb_queue_tail(&hdev->cmd_q, skb);
- queue_work(hdev->workqueue, &hdev->cmd_work);
- }
- skb_queue_purge(&hdev->driver_init);
-
- switch (hdev->dev_type) {
- case HCI_BREDR:
- bredr_init(hdev);
- break;
-
- case HCI_AMP:
- amp_init(hdev);
- break;
-
- default:
- BT_ERR("Unknown device type %d", hdev->dev_type);
- break;
- }
-
-}
-
-static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt)
-{
- BT_DBG("%s", hdev->name);
-
- /* Read LE buffer size */
- hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
-}
-
-static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
-{
- __u8 scan = opt;
-
- BT_DBG("%s %x", hdev->name, scan);
-
- /* Inquiry and Page scans */
- hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
-}
-
-static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
-{
- __u8 auth = opt;
-
- BT_DBG("%s %x", hdev->name, auth);
-
- /* Authentication */
- hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, 1, &auth);
-}
-
-static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
-{
- __u8 encrypt = opt;
-
- BT_DBG("%s %x", hdev->name, encrypt);
-
- /* Encryption */
- hci_send_cmd(hdev, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
-}
-
-static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt)
-{
- __le16 policy = cpu_to_le16(opt);
-
- BT_DBG("%s %x", hdev->name, policy);
-
- /* Default link policy */
- hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy);
-}
-
-/* Get HCI device by index.
- * Device is held on return. */
-struct hci_dev *hci_dev_get(int index)
-{
- struct hci_dev *hdev = NULL, *d;
-
- BT_DBG("%d", index);
-
- if (index < 0)
- return NULL;
-
- read_lock(&hci_dev_list_lock);
- list_for_each_entry(d, &hci_dev_list, list) {
- if (d->id == index) {
- hdev = hci_dev_hold(d);
- break;
- }
- }
- read_unlock(&hci_dev_list_lock);
- return hdev;
-}
-
-/* ---- Inquiry support ---- */
-
-bool hci_discovery_active(struct hci_dev *hdev)
-{
- struct discovery_state *discov = &hdev->discovery;
-
- switch (discov->state) {
- case DISCOVERY_FINDING:
- case DISCOVERY_RESOLVING:
- return true;
-
- default:
- return false;
- }
-}
-
-void hci_discovery_set_state(struct hci_dev *hdev, int state)
-{
- BT_DBG("%s state %u -> %u", hdev->name, hdev->discovery.state, state);
-
- if (hdev->discovery.state == state)
- return;
-
- switch (state) {
- case DISCOVERY_STOPPED:
- if (hdev->discovery.state != DISCOVERY_STARTING)
- mgmt_discovering(hdev, 0);
- hdev->discovery.type = 0;
- break;
- case DISCOVERY_STARTING:
- break;
- case DISCOVERY_FINDING:
- mgmt_discovering(hdev, 1);
- break;
- case DISCOVERY_RESOLVING:
- break;
- case DISCOVERY_STOPPING:
- break;
- }
-
- hdev->discovery.state = state;
-}
-
-static void inquiry_cache_flush(struct hci_dev *hdev)
-{
- struct discovery_state *cache = &hdev->discovery;
- struct inquiry_entry *p, *n;
-
- list_for_each_entry_safe(p, n, &cache->all, all) {
- list_del(&p->all);
- kfree(p);
- }
-
- INIT_LIST_HEAD(&cache->unknown);
- INIT_LIST_HEAD(&cache->resolve);
-}
-
-struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct discovery_state *cache = &hdev->discovery;
- struct inquiry_entry *e;
-
- BT_DBG("cache %p, %s", cache, batostr(bdaddr));
-
- list_for_each_entry(e, &cache->all, all) {
- if (!bacmp(&e->data.bdaddr, bdaddr))
- return e;
- }
-
- return NULL;
-}
-
-struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev,
- bdaddr_t *bdaddr)
-{
- struct discovery_state *cache = &hdev->discovery;
- struct inquiry_entry *e;
-
- BT_DBG("cache %p, %s", cache, batostr(bdaddr));
-
- list_for_each_entry(e, &cache->unknown, list) {
- if (!bacmp(&e->data.bdaddr, bdaddr))
- return e;
- }
-
- return NULL;
-}
-
-struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev,
- bdaddr_t *bdaddr,
- int state)
-{
- struct discovery_state *cache = &hdev->discovery;
- struct inquiry_entry *e;
-
- BT_DBG("cache %p bdaddr %s state %d", cache, batostr(bdaddr), state);
-
- list_for_each_entry(e, &cache->resolve, list) {
- if (!bacmp(bdaddr, BDADDR_ANY) && e->name_state == state)
- return e;
- if (!bacmp(&e->data.bdaddr, bdaddr))
- return e;
- }
-
- return NULL;
-}
-
-void hci_inquiry_cache_update_resolve(struct hci_dev *hdev,
- struct inquiry_entry *ie)
-{
- struct discovery_state *cache = &hdev->discovery;
- struct list_head *pos = &cache->resolve;
- struct inquiry_entry *p;
-
- list_del(&ie->list);
-
- list_for_each_entry(p, &cache->resolve, list) {
- if (p->name_state != NAME_PENDING &&
- abs(p->data.rssi) >= abs(ie->data.rssi))
- break;
- pos = &p->list;
- }
-
- list_add(&ie->list, pos);
-}
-
-bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
- bool name_known, bool *ssp)
-{
- struct discovery_state *cache = &hdev->discovery;
- struct inquiry_entry *ie;
-
- BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr));
-
- if (ssp)
- *ssp = data->ssp_mode;
-
- ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr);
- if (ie) {
- if (ie->data.ssp_mode && ssp)
- *ssp = true;
-
- if (ie->name_state == NAME_NEEDED &&
- data->rssi != ie->data.rssi) {
- ie->data.rssi = data->rssi;
- hci_inquiry_cache_update_resolve(hdev, ie);
- }
-
- goto update;
- }
-
- /* Entry not in the cache. Add new one. */
- ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC);
- if (!ie)
- return false;
-
- list_add(&ie->all, &cache->all);
-
- if (name_known) {
- ie->name_state = NAME_KNOWN;
- } else {
- ie->name_state = NAME_NOT_KNOWN;
- list_add(&ie->list, &cache->unknown);
- }
-
-update:
- if (name_known && ie->name_state != NAME_KNOWN &&
- ie->name_state != NAME_PENDING) {
- ie->name_state = NAME_KNOWN;
- list_del(&ie->list);
- }
-
- memcpy(&ie->data, data, sizeof(*data));
- ie->timestamp = jiffies;
- cache->timestamp = jiffies;
-
- if (ie->name_state == NAME_NOT_KNOWN)
- return false;
-
- return true;
-}
-
-static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
-{
- struct discovery_state *cache = &hdev->discovery;
- struct inquiry_info *info = (struct inquiry_info *) buf;
- struct inquiry_entry *e;
- int copied = 0;
-
- list_for_each_entry(e, &cache->all, all) {
- struct inquiry_data *data = &e->data;
-
- if (copied >= num)
- break;
-
- bacpy(&info->bdaddr, &data->bdaddr);
- info->pscan_rep_mode = data->pscan_rep_mode;
- info->pscan_period_mode = data->pscan_period_mode;
- info->pscan_mode = data->pscan_mode;
- memcpy(info->dev_class, data->dev_class, 3);
- info->clock_offset = data->clock_offset;
-
- info++;
- copied++;
- }
-
- BT_DBG("cache %p, copied %d", cache, copied);
- return copied;
-}
-
-static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
-{
- struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
- struct hci_cp_inquiry cp;
-
- BT_DBG("%s", hdev->name);
-
- if (test_bit(HCI_INQUIRY, &hdev->flags))
- return;
-
- /* Start Inquiry */
- memcpy(&cp.lap, &ir->lap, 3);
- cp.length = ir->length;
- cp.num_rsp = ir->num_rsp;
- hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
-}
-
-int hci_inquiry(void __user *arg)
-{
- __u8 __user *ptr = arg;
- struct hci_inquiry_req ir;
- struct hci_dev *hdev;
- int err = 0, do_inquiry = 0, max_rsp;
- long timeo;
- __u8 *buf;
-
- if (copy_from_user(&ir, ptr, sizeof(ir)))
- return -EFAULT;
-
- hdev = hci_dev_get(ir.dev_id);
- if (!hdev)
- return -ENODEV;
-
- hci_dev_lock(hdev);
- if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
- inquiry_cache_empty(hdev) ||
- ir.flags & IREQ_CACHE_FLUSH) {
- inquiry_cache_flush(hdev);
- do_inquiry = 1;
- }
- hci_dev_unlock(hdev);
-
- timeo = ir.length * msecs_to_jiffies(2000);
-
- if (do_inquiry) {
- err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo);
- if (err < 0)
- goto done;
- }
-
- /* for unlimited number of responses we will use buffer with 255 entries */
- max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;
-
- /* cache_dump can't sleep. Therefore we allocate temp buffer and then
- * copy it to the user space.
- */
- buf = kmalloc(sizeof(struct inquiry_info) * max_rsp, GFP_KERNEL);
- if (!buf) {
- err = -ENOMEM;
- goto done;
- }
-
- hci_dev_lock(hdev);
- ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf);
- hci_dev_unlock(hdev);
-
- BT_DBG("num_rsp %d", ir.num_rsp);
-
- if (!copy_to_user(ptr, &ir, sizeof(ir))) {
- ptr += sizeof(ir);
- if (copy_to_user(ptr, buf, sizeof(struct inquiry_info) *
- ir.num_rsp))
- err = -EFAULT;
- } else
- err = -EFAULT;
-
- kfree(buf);
-
-done:
- hci_dev_put(hdev);
- return err;
-}
-
-/* ---- HCI ioctl helpers ---- */
-
-int hci_dev_open(__u16 dev)
-{
- struct hci_dev *hdev;
- int ret = 0;
-
- hdev = hci_dev_get(dev);
- if (!hdev)
- return -ENODEV;
-
- BT_DBG("%s %p", hdev->name, hdev);
-
- hci_req_lock(hdev);
-
- if (test_bit(HCI_UNREGISTER, &hdev->dev_flags)) {
- ret = -ENODEV;
- goto done;
- }
-
- if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) {
- ret = -ERFKILL;
- goto done;
- }
-
- if (test_bit(HCI_UP, &hdev->flags)) {
- ret = -EALREADY;
- goto done;
- }
-
- if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
- set_bit(HCI_RAW, &hdev->flags);
-
- /* Treat all non BR/EDR controllers as raw devices if
- enable_hs is not set */
- if (hdev->dev_type != HCI_BREDR && !enable_hs)
- set_bit(HCI_RAW, &hdev->flags);
-
- if (hdev->open(hdev)) {
- ret = -EIO;
- goto done;
- }
-
- if (!test_bit(HCI_RAW, &hdev->flags)) {
- atomic_set(&hdev->cmd_cnt, 1);
- set_bit(HCI_INIT, &hdev->flags);
- hdev->init_last_cmd = 0;
-
- ret = __hci_request(hdev, hci_init_req, 0,
- msecs_to_jiffies(HCI_INIT_TIMEOUT));
-
- if (lmp_host_le_capable(hdev))
- ret = __hci_request(hdev, hci_le_init_req, 0,
- msecs_to_jiffies(HCI_INIT_TIMEOUT));
-
- clear_bit(HCI_INIT, &hdev->flags);
- }
-
- if (!ret) {
- hci_dev_hold(hdev);
- set_bit(HCI_UP, &hdev->flags);
- hci_notify(hdev, HCI_DEV_UP);
- if (!test_bit(HCI_SETUP, &hdev->dev_flags)) {
- hci_dev_lock(hdev);
- mgmt_powered(hdev, 1);
- hci_dev_unlock(hdev);
- }
- } else {
- /* Init failed, cleanup */
- flush_work(&hdev->tx_work);
- flush_work(&hdev->cmd_work);
- flush_work(&hdev->rx_work);
-
- skb_queue_purge(&hdev->cmd_q);
- skb_queue_purge(&hdev->rx_q);
-
- if (hdev->flush)
- hdev->flush(hdev);
-
- if (hdev->sent_cmd) {
- kfree_skb(hdev->sent_cmd);
- hdev->sent_cmd = NULL;
- }
-
- hdev->close(hdev);
- hdev->flags = 0;
- }
-
-done:
- hci_req_unlock(hdev);
- hci_dev_put(hdev);
- return ret;
-}
-
-static int hci_dev_do_close(struct hci_dev *hdev)
-{
- BT_DBG("%s %p", hdev->name, hdev);
-
- cancel_work_sync(&hdev->le_scan);
-
- hci_req_cancel(hdev, ENODEV);
- hci_req_lock(hdev);
-
- if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
- del_timer_sync(&hdev->cmd_timer);
- hci_req_unlock(hdev);
- return 0;
- }
-
- /* Flush RX and TX works */
- flush_work(&hdev->tx_work);
- flush_work(&hdev->rx_work);
-
- if (hdev->discov_timeout > 0) {
- cancel_delayed_work(&hdev->discov_off);
- hdev->discov_timeout = 0;
- clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
- }
-
- if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
- cancel_delayed_work(&hdev->service_cache);
-
- cancel_delayed_work_sync(&hdev->le_scan_disable);
-
- hci_dev_lock(hdev);
- inquiry_cache_flush(hdev);
- hci_conn_hash_flush(hdev);
- hci_dev_unlock(hdev);
-
- hci_notify(hdev, HCI_DEV_DOWN);
-
- if (hdev->flush)
- hdev->flush(hdev);
-
- /* Reset device */
- skb_queue_purge(&hdev->cmd_q);
- atomic_set(&hdev->cmd_cnt, 1);
- if (!test_bit(HCI_RAW, &hdev->flags) &&
- test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
- set_bit(HCI_INIT, &hdev->flags);
- __hci_request(hdev, hci_reset_req, 0,
- msecs_to_jiffies(250));
- clear_bit(HCI_INIT, &hdev->flags);
- }
-
- /* flush cmd work */
- flush_work(&hdev->cmd_work);
-
- /* Drop queues */
- skb_queue_purge(&hdev->rx_q);
- skb_queue_purge(&hdev->cmd_q);
- skb_queue_purge(&hdev->raw_q);
-
- /* Drop last sent command */
- if (hdev->sent_cmd) {
- del_timer_sync(&hdev->cmd_timer);
- kfree_skb(hdev->sent_cmd);
- hdev->sent_cmd = NULL;
- }
-
- /* After this point our queues are empty
- * and no tasks are scheduled. */
- hdev->close(hdev);
-
- if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
- hci_dev_lock(hdev);
- mgmt_powered(hdev, 0);
- hci_dev_unlock(hdev);
- }
-
- /* Clear flags */
- hdev->flags = 0;
-
- memset(hdev->eir, 0, sizeof(hdev->eir));
- memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
-
- hci_req_unlock(hdev);
-
- hci_dev_put(hdev);
- return 0;
-}
-
-int hci_dev_close(__u16 dev)
-{
- struct hci_dev *hdev;
- int err;
-
- hdev = hci_dev_get(dev);
- if (!hdev)
- return -ENODEV;
-
- if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
- cancel_delayed_work(&hdev->power_off);
-
- err = hci_dev_do_close(hdev);
-
- hci_dev_put(hdev);
- return err;
-}
-
-int hci_dev_reset(__u16 dev)
-{
- struct hci_dev *hdev;
- int ret = 0;
-
- hdev = hci_dev_get(dev);
- if (!hdev)
- return -ENODEV;
-
- hci_req_lock(hdev);
-
- if (!test_bit(HCI_UP, &hdev->flags))
- goto done;
-
- /* Drop queues */
- skb_queue_purge(&hdev->rx_q);
- skb_queue_purge(&hdev->cmd_q);
-
- hci_dev_lock(hdev);
- inquiry_cache_flush(hdev);
- hci_conn_hash_flush(hdev);
- hci_dev_unlock(hdev);
-
- if (hdev->flush)
- hdev->flush(hdev);
-
- atomic_set(&hdev->cmd_cnt, 1);
- hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0;
-
- if (!test_bit(HCI_RAW, &hdev->flags))
- ret = __hci_request(hdev, hci_reset_req, 0,
- msecs_to_jiffies(HCI_INIT_TIMEOUT));
-
-done:
- hci_req_unlock(hdev);
- hci_dev_put(hdev);
- return ret;
-}
-
-int hci_dev_reset_stat(__u16 dev)
-{
- struct hci_dev *hdev;
- int ret = 0;
-
- hdev = hci_dev_get(dev);
- if (!hdev)
- return -ENODEV;
-
- memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
-
- hci_dev_put(hdev);
-
- return ret;
-}
-
-int hci_dev_cmd(unsigned int cmd, void __user *arg)
-{
- struct hci_dev *hdev;
- struct hci_dev_req dr;
- int err = 0;
-
- if (copy_from_user(&dr, arg, sizeof(dr)))
- return -EFAULT;
-
- hdev = hci_dev_get(dr.dev_id);
- if (!hdev)
- return -ENODEV;
-
- switch (cmd) {
- case HCISETAUTH:
- err = hci_request(hdev, hci_auth_req, dr.dev_opt,
- msecs_to_jiffies(HCI_INIT_TIMEOUT));
- break;
-
- case HCISETENCRYPT:
- if (!lmp_encrypt_capable(hdev)) {
- err = -EOPNOTSUPP;
- break;
- }
-
- if (!test_bit(HCI_AUTH, &hdev->flags)) {
- /* Auth must be enabled first */
- err = hci_request(hdev, hci_auth_req, dr.dev_opt,
- msecs_to_jiffies(HCI_INIT_TIMEOUT));
- if (err)
- break;
- }
-
- err = hci_request(hdev, hci_encrypt_req, dr.dev_opt,
- msecs_to_jiffies(HCI_INIT_TIMEOUT));
- break;
-
- case HCISETSCAN:
- err = hci_request(hdev, hci_scan_req, dr.dev_opt,
- msecs_to_jiffies(HCI_INIT_TIMEOUT));
- break;
-
- case HCISETLINKPOL:
- err = hci_request(hdev, hci_linkpol_req, dr.dev_opt,
- msecs_to_jiffies(HCI_INIT_TIMEOUT));
- break;
-
- case HCISETLINKMODE:
- hdev->link_mode = ((__u16) dr.dev_opt) &
- (HCI_LM_MASTER | HCI_LM_ACCEPT);
- break;
-
- case HCISETPTYPE:
- hdev->pkt_type = (__u16) dr.dev_opt;
- break;
-
- case HCISETACLMTU:
- hdev->acl_mtu = *((__u16 *) &dr.dev_opt + 1);
- hdev->acl_pkts = *((__u16 *) &dr.dev_opt + 0);
- break;
-
- case HCISETSCOMTU:
- hdev->sco_mtu = *((__u16 *) &dr.dev_opt + 1);
- hdev->sco_pkts = *((__u16 *) &dr.dev_opt + 0);
- break;
-
- default:
- err = -EINVAL;
- break;
- }
-
- hci_dev_put(hdev);
- return err;
-}
-
-int hci_get_dev_list(void __user *arg)
-{
- struct hci_dev *hdev;
- struct hci_dev_list_req *dl;
- struct hci_dev_req *dr;
- int n = 0, size, err;
- __u16 dev_num;
-
- if (get_user(dev_num, (__u16 __user *) arg))
- return -EFAULT;
-
- if (!dev_num || dev_num > (PAGE_SIZE * 2) / sizeof(*dr))
- return -EINVAL;
-
- size = sizeof(*dl) + dev_num * sizeof(*dr);
-
- dl = kzalloc(size, GFP_KERNEL);
- if (!dl)
- return -ENOMEM;
-
- dr = dl->dev_req;
-
- read_lock(&hci_dev_list_lock);
- list_for_each_entry(hdev, &hci_dev_list, list) {
- if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
- cancel_delayed_work(&hdev->power_off);
-
- if (!test_bit(HCI_MGMT, &hdev->dev_flags))
- set_bit(HCI_PAIRABLE, &hdev->dev_flags);
-
- (dr + n)->dev_id = hdev->id;
- (dr + n)->dev_opt = hdev->flags;
-
- if (++n >= dev_num)
- break;
- }
- read_unlock(&hci_dev_list_lock);
-
- dl->dev_num = n;
- size = sizeof(*dl) + n * sizeof(*dr);
-
- err = copy_to_user(arg, dl, size);
- kfree(dl);
-
- return err ? -EFAULT : 0;
-}
-
-int hci_get_dev_info(void __user *arg)
-{
- struct hci_dev *hdev;
- struct hci_dev_info di;
- int err = 0;
-
- if (copy_from_user(&di, arg, sizeof(di)))
- return -EFAULT;
-
- hdev = hci_dev_get(di.dev_id);
- if (!hdev)
- return -ENODEV;
-
- if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
- cancel_delayed_work_sync(&hdev->power_off);
-
- if (!test_bit(HCI_MGMT, &hdev->dev_flags))
- set_bit(HCI_PAIRABLE, &hdev->dev_flags);
-
- strcpy(di.name, hdev->name);
- di.bdaddr = hdev->bdaddr;
- di.type = (hdev->bus & 0x0f) | (hdev->dev_type << 4);
- di.flags = hdev->flags;
- di.pkt_type = hdev->pkt_type;
- di.acl_mtu = hdev->acl_mtu;
- di.acl_pkts = hdev->acl_pkts;
- di.sco_mtu = hdev->sco_mtu;
- di.sco_pkts = hdev->sco_pkts;
- di.link_policy = hdev->link_policy;
- di.link_mode = hdev->link_mode;
-
- memcpy(&di.stat, &hdev->stat, sizeof(di.stat));
- memcpy(&di.features, &hdev->features, sizeof(di.features));
-
- if (copy_to_user(arg, &di, sizeof(di)))
- err = -EFAULT;
-
- hci_dev_put(hdev);
-
- return err;
-}
-
-/* ---- Interface to HCI drivers ---- */
-
-static int hci_rfkill_set_block(void *data, bool blocked)
-{
- struct hci_dev *hdev = data;
-
- BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked);
-
- if (!blocked)
- return 0;
-
- hci_dev_do_close(hdev);
-
- return 0;
-}
-
-static const struct rfkill_ops hci_rfkill_ops = {
- .set_block = hci_rfkill_set_block,
-};
-
-/* Alloc HCI device */
-struct hci_dev *hci_alloc_dev(void)
-{
- struct hci_dev *hdev;
-
- hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL);
- if (!hdev)
- return NULL;
-
- hci_init_sysfs(hdev);
- skb_queue_head_init(&hdev->driver_init);
-
- return hdev;
-}
-EXPORT_SYMBOL(hci_alloc_dev);
-
-/* Free HCI device */
-void hci_free_dev(struct hci_dev *hdev)
-{
- skb_queue_purge(&hdev->driver_init);
-
- /* will free via device release */
- put_device(&hdev->dev);
-}
-EXPORT_SYMBOL(hci_free_dev);
-
-static void hci_power_on(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev, power_on);
-
- BT_DBG("%s", hdev->name);
-
- if (hci_dev_open(hdev->id) < 0)
- return;
-
- if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
- schedule_delayed_work(&hdev->power_off,
- msecs_to_jiffies(AUTO_OFF_TIMEOUT));
-
- if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags))
- mgmt_index_added(hdev);
-}
-
-static void hci_power_off(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- power_off.work);
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_do_close(hdev);
-}
-
-static void hci_discov_off(struct work_struct *work)
-{
- struct hci_dev *hdev;
- u8 scan = SCAN_PAGE;
-
- hdev = container_of(work, struct hci_dev, discov_off.work);
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
-
- hdev->discov_timeout = 0;
-
- hci_dev_unlock(hdev);
-}
-
-int hci_uuids_clear(struct hci_dev *hdev)
-{
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &hdev->uuids) {
- struct bt_uuid *uuid;
-
- uuid = list_entry(p, struct bt_uuid, list);
-
- list_del(p);
- kfree(uuid);
- }
-
- return 0;
-}
-
-int hci_link_keys_clear(struct hci_dev *hdev)
-{
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &hdev->link_keys) {
- struct link_key *key;
-
- key = list_entry(p, struct link_key, list);
-
- list_del(p);
- kfree(key);
- }
-
- return 0;
-}
-
-int hci_smp_ltks_clear(struct hci_dev *hdev)
-{
- struct smp_ltk *k, *tmp;
-
- list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) {
- list_del(&k->list);
- kfree(k);
- }
-
- return 0;
-}
-
-struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct link_key *k;
-
- list_for_each_entry(k, &hdev->link_keys, list)
- if (bacmp(bdaddr, &k->bdaddr) == 0)
- return k;
-
- return NULL;
-}
-
-static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
- u8 key_type, u8 old_key_type)
-{
- /* Legacy key */
- if (key_type < 0x03)
- return true;
-
- /* Debug keys are insecure so don't store them persistently */
- if (key_type == HCI_LK_DEBUG_COMBINATION)
- return false;
-
- /* Changed combination key and there's no previous one */
- if (key_type == HCI_LK_CHANGED_COMBINATION && old_key_type == 0xff)
- return false;
-
- /* Security mode 3 case */
- if (!conn)
- return true;
-
- /* Neither local nor remote side had no-bonding as requirement */
- if (conn->auth_type > 0x01 && conn->remote_auth > 0x01)
- return true;
-
- /* Local side had dedicated bonding as requirement */
- if (conn->auth_type == 0x02 || conn->auth_type == 0x03)
- return true;
-
- /* Remote side had dedicated bonding as requirement */
- if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03)
- return true;
-
- /* If none of the above criteria match, then don't store the key
- * persistently */
- return false;
-}
-
-struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
-{
- struct smp_ltk *k;
-
- list_for_each_entry(k, &hdev->long_term_keys, list) {
- if (k->ediv != ediv ||
- memcmp(rand, k->rand, sizeof(k->rand)))
- continue;
-
- return k;
- }
-
- return NULL;
-}
-EXPORT_SYMBOL(hci_find_ltk);
-
-struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
- u8 addr_type)
-{
- struct smp_ltk *k;
-
- list_for_each_entry(k, &hdev->long_term_keys, list)
- if (addr_type == k->bdaddr_type &&
- bacmp(bdaddr, &k->bdaddr) == 0)
- return k;
-
- return NULL;
-}
-EXPORT_SYMBOL(hci_find_ltk_by_addr);
-
-int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
- bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
-{
- struct link_key *key, *old_key;
- u8 old_key_type;
- bool persistent;
-
- old_key = hci_find_link_key(hdev, bdaddr);
- if (old_key) {
- old_key_type = old_key->type;
- key = old_key;
- } else {
- old_key_type = conn ? conn->key_type : 0xff;
- key = kzalloc(sizeof(*key), GFP_ATOMIC);
- if (!key)
- return -ENOMEM;
- list_add(&key->list, &hdev->link_keys);
- }
-
- BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type);
-
- /* Some buggy controller combinations generate a changed
- * combination key for legacy pairing even when there's no
- * previous key */
- if (type == HCI_LK_CHANGED_COMBINATION &&
- (!conn || conn->remote_auth == 0xff) &&
- old_key_type == 0xff) {
- type = HCI_LK_COMBINATION;
- if (conn)
- conn->key_type = type;
- }
-
- bacpy(&key->bdaddr, bdaddr);
- memcpy(key->val, val, 16);
- key->pin_len = pin_len;
-
- if (type == HCI_LK_CHANGED_COMBINATION)
- key->type = old_key_type;
- else
- key->type = type;
-
- if (!new_key)
- return 0;
-
- persistent = hci_persistent_key(hdev, conn, type, old_key_type);
-
- mgmt_new_link_key(hdev, key, persistent);
-
- if (conn)
- conn->flush_key = !persistent;
-
- return 0;
-}
-
-int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
- int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16
- ediv, u8 rand[8])
-{
- struct smp_ltk *key, *old_key;
-
- if (!(type & HCI_SMP_STK) && !(type & HCI_SMP_LTK))
- return 0;
-
- old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type);
- if (old_key)
- key = old_key;
- else {
- key = kzalloc(sizeof(*key), GFP_ATOMIC);
- if (!key)
- return -ENOMEM;
- list_add(&key->list, &hdev->long_term_keys);
- }
-
- bacpy(&key->bdaddr, bdaddr);
- key->bdaddr_type = addr_type;
- memcpy(key->val, tk, sizeof(key->val));
- key->authenticated = authenticated;
- key->ediv = ediv;
- key->enc_size = enc_size;
- key->type = type;
- memcpy(key->rand, rand, sizeof(key->rand));
-
- if (!new_key)
- return 0;
-
- if (type & HCI_SMP_LTK)
- mgmt_new_ltk(hdev, key, 1);
-
- return 0;
-}
-
-int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct link_key *key;
-
- key = hci_find_link_key(hdev, bdaddr);
- if (!key)
- return -ENOENT;
-
- BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
-
- list_del(&key->list);
- kfree(key);
-
- return 0;
-}
-
-int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct smp_ltk *k, *tmp;
-
- list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) {
- if (bacmp(bdaddr, &k->bdaddr))
- continue;
-
- BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
-
- list_del(&k->list);
- kfree(k);
- }
-
- return 0;
-}
-
-/* HCI command timer function */
-static void hci_cmd_timer(unsigned long arg)
-{
- struct hci_dev *hdev = (void *) arg;
-
- BT_ERR("%s command tx timeout", hdev->name);
- atomic_set(&hdev->cmd_cnt, 1);
- queue_work(hdev->workqueue, &hdev->cmd_work);
-}
-
-struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
- bdaddr_t *bdaddr)
-{
- struct oob_data *data;
-
- list_for_each_entry(data, &hdev->remote_oob_data, list)
- if (bacmp(bdaddr, &data->bdaddr) == 0)
- return data;
-
- return NULL;
-}
-
-int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct oob_data *data;
-
- data = hci_find_remote_oob_data(hdev, bdaddr);
- if (!data)
- return -ENOENT;
-
- BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
-
- list_del(&data->list);
- kfree(data);
-
- return 0;
-}
-
-int hci_remote_oob_data_clear(struct hci_dev *hdev)
-{
- struct oob_data *data, *n;
-
- list_for_each_entry_safe(data, n, &hdev->remote_oob_data, list) {
- list_del(&data->list);
- kfree(data);
- }
-
- return 0;
-}
-
-int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
- u8 *randomizer)
-{
- struct oob_data *data;
-
- data = hci_find_remote_oob_data(hdev, bdaddr);
-
- if (!data) {
- data = kmalloc(sizeof(*data), GFP_ATOMIC);
- if (!data)
- return -ENOMEM;
-
- bacpy(&data->bdaddr, bdaddr);
- list_add(&data->list, &hdev->remote_oob_data);
- }
-
- memcpy(data->hash, hash, sizeof(data->hash));
- memcpy(data->randomizer, randomizer, sizeof(data->randomizer));
-
- BT_DBG("%s for %s", hdev->name, batostr(bdaddr));
-
- return 0;
-}
-
-struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct bdaddr_list *b;
-
- list_for_each_entry(b, &hdev->blacklist, list)
- if (bacmp(bdaddr, &b->bdaddr) == 0)
- return b;
-
- return NULL;
-}
-
-int hci_blacklist_clear(struct hci_dev *hdev)
-{
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &hdev->blacklist) {
- struct bdaddr_list *b;
-
- b = list_entry(p, struct bdaddr_list, list);
-
- list_del(p);
- kfree(b);
- }
-
- return 0;
-}
-
-int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
-{
- struct bdaddr_list *entry;
-
- if (bacmp(bdaddr, BDADDR_ANY) == 0)
- return -EBADF;
-
- if (hci_blacklist_lookup(hdev, bdaddr))
- return -EEXIST;
-
- entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
-
- bacpy(&entry->bdaddr, bdaddr);
-
- list_add(&entry->list, &hdev->blacklist);
-
- return mgmt_device_blocked(hdev, bdaddr, type);
-}
-
-int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
-{
- struct bdaddr_list *entry;
-
- if (bacmp(bdaddr, BDADDR_ANY) == 0)
- return hci_blacklist_clear(hdev);
-
- entry = hci_blacklist_lookup(hdev, bdaddr);
- if (!entry)
- return -ENOENT;
-
- list_del(&entry->list);
- kfree(entry);
-
- return mgmt_device_unblocked(hdev, bdaddr, type);
-}
-
-static void hci_clear_adv_cache(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- adv_work.work);
-
- hci_dev_lock(hdev);
-
- hci_adv_entries_clear(hdev);
-
- hci_dev_unlock(hdev);
-}
-
-int hci_adv_entries_clear(struct hci_dev *hdev)
-{
- struct adv_entry *entry, *tmp;
-
- list_for_each_entry_safe(entry, tmp, &hdev->adv_entries, list) {
- list_del(&entry->list);
- kfree(entry);
- }
-
- BT_DBG("%s adv cache cleared", hdev->name);
-
- return 0;
-}
-
-struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct adv_entry *entry;
-
- list_for_each_entry(entry, &hdev->adv_entries, list)
- if (bacmp(bdaddr, &entry->bdaddr) == 0)
- return entry;
-
- return NULL;
-}
-
-static inline int is_connectable_adv(u8 evt_type)
-{
- if (evt_type == ADV_IND || evt_type == ADV_DIRECT_IND)
- return 1;
-
- return 0;
-}
-
-int hci_add_adv_entry(struct hci_dev *hdev,
- struct hci_ev_le_advertising_info *ev) { struct adv_entry *entry; if (!is_connectable_adv(ev->evt_type))
- return -EINVAL;
-
- /* Only new entries should be added to adv_entries. So, if
- * bdaddr was found, don't add it. */
- if (hci_find_adv_entry(hdev, &ev->bdaddr))
- return 0;
-
- entry = kzalloc(sizeof(*entry), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
-
- bacpy(&entry->bdaddr, &ev->bdaddr);
- entry->bdaddr_type = ev->bdaddr_type;
-
- list_add(&entry->list, &hdev->adv_entries);
-
- BT_DBG("%s adv entry added: address %s type %u", hdev->name,
- batostr(&entry->bdaddr), entry->bdaddr_type);
-
- return 0;
-}
-
-static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt)
-{
- struct le_scan_params *param = (struct le_scan_params *) opt;
- struct hci_cp_le_set_scan_param cp;
-
- memset(&cp, 0, sizeof(cp));
- cp.type = param->type;
- cp.interval = cpu_to_le16(param->interval);
- cp.window = cpu_to_le16(param->window);
-
- hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAM, sizeof(cp), &cp);
-}
-
-static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt)
-{
- struct hci_cp_le_set_scan_enable cp;
-
- memset(&cp, 0, sizeof(cp));
- cp.enable = 1;
-
- hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
-}
-
-static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval,
- u16 window, int timeout)
-{
- long timeo = msecs_to_jiffies(3000);
- struct le_scan_params param;
- int err;
-
- BT_DBG("%s", hdev->name);
-
- if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
- return -EINPROGRESS;
-
- param.type = type;
- param.interval = interval;
- param.window = window;
-
- hci_req_lock(hdev);
-
- err = __hci_request(hdev, le_scan_param_req, (unsigned long) &param,
- timeo);
- if (!err)
- err = __hci_request(hdev, le_scan_enable_req, 0, timeo);
-
- hci_req_unlock(hdev);
-
- if (err < 0)
- return err;
-
- schedule_delayed_work(&hdev->le_scan_disable,
- msecs_to_jiffies(timeout));
-
- return 0;
-}
-
-static void le_scan_disable_work(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- le_scan_disable.work);
- struct hci_cp_le_set_scan_enable cp;
-
- BT_DBG("%s", hdev->name);
-
- memset(&cp, 0, sizeof(cp));
-
- hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
-}
-
-static void le_scan_work(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev, le_scan);
- struct le_scan_params *param = &hdev->le_scan_params;
-
- BT_DBG("%s", hdev->name);
-
- hci_do_le_scan(hdev, param->type, param->interval, param->window,
- param->timeout);
-}
-
-int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
- int timeout)
-{
- struct le_scan_params *param = &hdev->le_scan_params;
-
- BT_DBG("%s", hdev->name);
-
- if (work_busy(&hdev->le_scan))
- return -EINPROGRESS;
-
- param->type = type;
- param->interval = interval;
- param->window = window;
- param->timeout = timeout;
-
- queue_work(system_long_wq, &hdev->le_scan);
-
- return 0;
-}
-
-/* Register HCI device */
-int hci_register_dev(struct hci_dev *hdev)
-{
- struct list_head *head = &hci_dev_list, *p;
- int i, id, error;
-
- BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
-
- if (!hdev->open || !hdev->close)
- return -EINVAL;
-
- /* Do not allow HCI_AMP devices to register at index 0,
- * so the index can be used as the AMP controller ID.
- */
- id = (hdev->dev_type == HCI_BREDR) ? 0 : 1;
-
- write_lock(&hci_dev_list_lock);
-
- /* Find first available device id */
- list_for_each(p, &hci_dev_list) {
- if (list_entry(p, struct hci_dev, list)->id != id)
- break;
- head = p; id++;
- }
-
- sprintf(hdev->name, "hci%d", id);
- hdev->id = id;
- list_add_tail(&hdev->list, head);
-
- mutex_init(&hdev->lock);
-
- hdev->flags = 0;
- hdev->dev_flags = 0;
- hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1);
- hdev->esco_type = (ESCO_HV1);
- hdev->link_mode = (HCI_LM_ACCEPT);
- hdev->io_capability = 0x03; /* No Input No Output */
-
- hdev->idle_timeout = 0;
- hdev->sniff_max_interval = 800;
- hdev->sniff_min_interval = 80;
-
- INIT_WORK(&hdev->rx_work, hci_rx_work);
- INIT_WORK(&hdev->cmd_work, hci_cmd_work);
- INIT_WORK(&hdev->tx_work, hci_tx_work);
-
-
- skb_queue_head_init(&hdev->rx_q);
- skb_queue_head_init(&hdev->cmd_q);
- skb_queue_head_init(&hdev->raw_q);
-
- setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev);
-
- for (i = 0; i < NUM_REASSEMBLY; i++)
- hdev->reassembly[i] = NULL;
-
- init_waitqueue_head(&hdev->req_wait_q);
- mutex_init(&hdev->req_lock);
-
- discovery_init(hdev);
-
- hci_conn_hash_init(hdev);
-
- INIT_LIST_HEAD(&hdev->mgmt_pending);
-
- INIT_LIST_HEAD(&hdev->blacklist);
-
- INIT_LIST_HEAD(&hdev->uuids);
-
- INIT_LIST_HEAD(&hdev->link_keys);
- INIT_LIST_HEAD(&hdev->long_term_keys);
-
- INIT_LIST_HEAD(&hdev->remote_oob_data);
-
- INIT_LIST_HEAD(&hdev->adv_entries);
-
- INIT_DELAYED_WORK(&hdev->adv_work, hci_clear_adv_cache);
- INIT_WORK(&hdev->power_on, hci_power_on);
- INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
-
- INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
-
- memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
-
- atomic_set(&hdev->promisc, 0);
-
- INIT_WORK(&hdev->le_scan, le_scan_work);
-
- INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
-
- write_unlock(&hci_dev_list_lock);
-
- hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND |
- WQ_MEM_RECLAIM, 1);
- if (!hdev->workqueue) {
- error = -ENOMEM;
- goto err;
- }
-
- error = hci_add_sysfs(hdev);
- if (error < 0)
- goto err_wqueue;
-
- hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
- RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev);
- if (hdev->rfkill) {
- if (rfkill_register(hdev->rfkill) < 0) {
- rfkill_destroy(hdev->rfkill);
- hdev->rfkill = NULL;
- }
- }
-
- set_bit(HCI_AUTO_OFF, &hdev->dev_flags);
- set_bit(HCI_SETUP, &hdev->dev_flags);
- schedule_work(&hdev->power_on);
-
- hci_notify(hdev, HCI_DEV_REG);
- hci_dev_hold(hdev);
-
- return id;
-
-err_wqueue:
- destroy_workqueue(hdev->workqueue);
-err:
- write_lock(&hci_dev_list_lock);
- list_del(&hdev->list);
- write_unlock(&hci_dev_list_lock);
-
- return error;
-}
-EXPORT_SYMBOL(hci_register_dev);
-
-/* Unregister HCI device */
-void hci_unregister_dev(struct hci_dev *hdev)
-{
- int i;
-
- BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
-
- set_bit(HCI_UNREGISTER, &hdev->dev_flags);
-
- write_lock(&hci_dev_list_lock);
- list_del(&hdev->list);
- write_unlock(&hci_dev_list_lock);
-
- hci_dev_do_close(hdev);
-
- for (i = 0; i < NUM_REASSEMBLY; i++)
- kfree_skb(hdev->reassembly[i]);
-
- if (!test_bit(HCI_INIT, &hdev->flags) &&
- !test_bit(HCI_SETUP, &hdev->dev_flags)) {
- hci_dev_lock(hdev);
- mgmt_index_removed(hdev);
- hci_dev_unlock(hdev);
- }
-
- /* mgmt_index_removed should take care of emptying the
- * pending list */
- BUG_ON(!list_empty(&hdev->mgmt_pending));
-
- hci_notify(hdev, HCI_DEV_UNREG);
-
- if (hdev->rfkill) {
- rfkill_unregister(hdev->rfkill);
- rfkill_destroy(hdev->rfkill);
- }
-
- hci_del_sysfs(hdev);
-
- cancel_delayed_work_sync(&hdev->adv_work);
-
- destroy_workqueue(hdev->workqueue);
-
- hci_dev_lock(hdev);
- hci_blacklist_clear(hdev);
- hci_uuids_clear(hdev);
- hci_link_keys_clear(hdev);
- hci_smp_ltks_clear(hdev);
- hci_remote_oob_data_clear(hdev);
- hci_adv_entries_clear(hdev);
- hci_dev_unlock(hdev);
-
- hci_dev_put(hdev);
-}
-EXPORT_SYMBOL(hci_unregister_dev);
-
-/* Suspend HCI device */
-int hci_suspend_dev(struct hci_dev *hdev)
-{
- hci_notify(hdev, HCI_DEV_SUSPEND);
- return 0;
-}
-EXPORT_SYMBOL(hci_suspend_dev);
-
-/* Resume HCI device */
-int hci_resume_dev(struct hci_dev *hdev)
-{
- hci_notify(hdev, HCI_DEV_RESUME);
- return 0;
-}
-EXPORT_SYMBOL(hci_resume_dev);
-
-/* Receive frame from HCI drivers */
-int hci_recv_frame(struct sk_buff *skb)
-{
- struct hci_dev *hdev = (struct hci_dev *) skb->dev;
- if (!hdev || (!test_bit(HCI_UP, &hdev->flags)
- && !test_bit(HCI_INIT, &hdev->flags))) {
- kfree_skb(skb);
- return -ENXIO;
- }
-
- /* Incomming skb */
- bt_cb(skb)->incoming = 1;
-
- /* Time stamp */
- __net_timestamp(skb);
-
- skb_queue_tail(&hdev->rx_q, skb);
- queue_work(hdev->workqueue, &hdev->rx_work);
-
- return 0;
-}
-EXPORT_SYMBOL(hci_recv_frame);
-
-static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
- int count, __u8 index)
-{
- int len = 0;
- int hlen = 0;
- int remain = count;
- struct sk_buff *skb;
- struct bt_skb_cb *scb;
-
- if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) ||
- index >= NUM_REASSEMBLY)
- return -EILSEQ;
-
- skb = hdev->reassembly[index];
-
- if (!skb) {
- switch (type) {
- case HCI_ACLDATA_PKT:
- len = HCI_MAX_FRAME_SIZE;
- hlen = HCI_ACL_HDR_SIZE;
- break;
- case HCI_EVENT_PKT:
- len = HCI_MAX_EVENT_SIZE;
- hlen = HCI_EVENT_HDR_SIZE;
- break;
- case HCI_SCODATA_PKT:
- len = HCI_MAX_SCO_SIZE;
- hlen = HCI_SCO_HDR_SIZE;
- break;
- }
-
- skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- scb = (void *) skb->cb;
- scb->expect = hlen;
- scb->pkt_type = type;
-
- skb->dev = (void *) hdev;
- hdev->reassembly[index] = skb;
- }
-
- while (count) {
- scb = (void *) skb->cb;
- len = min_t(uint, scb->expect, count);
-
- memcpy(skb_put(skb, len), data, len);
-
- count -= len;
- data += len;
- scb->expect -= len;
- remain = count;
-
- switch (type) {
- case HCI_EVENT_PKT:
- if (skb->len == HCI_EVENT_HDR_SIZE) {
- struct hci_event_hdr *h = hci_event_hdr(skb);
- scb->expect = h->plen;
-
- if (skb_tailroom(skb) < scb->expect) {
- kfree_skb(skb);
- hdev->reassembly[index] = NULL;
- return -ENOMEM;
- }
- }
- break;
-
- case HCI_ACLDATA_PKT:
- if (skb->len == HCI_ACL_HDR_SIZE) {
- struct hci_acl_hdr *h = hci_acl_hdr(skb);
- scb->expect = __le16_to_cpu(h->dlen);
-
- if (skb_tailroom(skb) < scb->expect) {
- kfree_skb(skb);
- hdev->reassembly[index] = NULL;
- return -ENOMEM;
- }
- }
- break;
-
- case HCI_SCODATA_PKT:
- if (skb->len == HCI_SCO_HDR_SIZE) {
- struct hci_sco_hdr *h = hci_sco_hdr(skb);
- scb->expect = h->dlen;
-
- if (skb_tailroom(skb) < scb->expect) {
- kfree_skb(skb);
- hdev->reassembly[index] = NULL;
- return -ENOMEM;
- }
- }
- break;
- }
-
- if (scb->expect == 0) {
- /* Complete frame */
-
- bt_cb(skb)->pkt_type = type;
- hci_recv_frame(skb);
-
- hdev->reassembly[index] = NULL;
- return remain;
- }
- }
-
- return remain;
-}
-
-int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
-{
- int rem = 0;
-
- if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT)
- return -EILSEQ;
-
- while (count) {
- rem = hci_reassembly(hdev, type, data, count, type - 1);
- if (rem < 0)
- return rem;
-
- data += (count - rem);
- count = rem;
- }
-
- return rem;
-}
-EXPORT_SYMBOL(hci_recv_fragment);
-
-#define STREAM_REASSEMBLY 0
-
-int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
-{
- int type;
- int rem = 0;
-
- while (count) {
- struct sk_buff *skb = hdev->reassembly[STREAM_REASSEMBLY];
-
- if (!skb) {
- struct { char type; } *pkt;
-
- /* Start of the frame */
- pkt = data;
- type = pkt->type;
-
- data++;
- count--;
- } else
- type = bt_cb(skb)->pkt_type;
-
- rem = hci_reassembly(hdev, type, data, count,
- STREAM_REASSEMBLY);
- if (rem < 0)
- return rem;
-
- data += (count - rem);
- count = rem;
- }
-
- return rem;
-}
-EXPORT_SYMBOL(hci_recv_stream_fragment);
-
-/* ---- Interface to upper protocols ---- */
-
-int hci_register_cb(struct hci_cb *cb)
-{
- BT_DBG("%p name %s", cb, cb->name);
-
- write_lock(&hci_cb_list_lock);
- list_add(&cb->list, &hci_cb_list);
- write_unlock(&hci_cb_list_lock);
-
- return 0;
-}
-EXPORT_SYMBOL(hci_register_cb);
-
-int hci_unregister_cb(struct hci_cb *cb)
-{
- BT_DBG("%p name %s", cb, cb->name);
-
- write_lock(&hci_cb_list_lock);
- list_del(&cb->list);
- write_unlock(&hci_cb_list_lock);
-
- return 0;
-}
-EXPORT_SYMBOL(hci_unregister_cb);
-
-static int hci_send_frame(struct sk_buff *skb)
-{
- struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-
- if (!hdev) {
- kfree_skb(skb);
- return -ENODEV;
- }
-
- BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
-
- /* Time stamp */
- __net_timestamp(skb);
-
- /* Send copy to monitor */
- hci_send_to_monitor(hdev, skb);
-
- if (atomic_read(&hdev->promisc)) {
- /* Send copy to the sockets */
- hci_send_to_sock(hdev, skb);
- }
-
- /* Get rid of skb owner, prior to sending to the driver. */
- skb_orphan(skb);
-
- return hdev->send(skb);
-}
-
-/* Send HCI command */
-int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
-{
- int len = HCI_COMMAND_HDR_SIZE + plen;
- struct hci_command_hdr *hdr;
- struct sk_buff *skb;
-
- BT_DBG("%s opcode 0x%x plen %d", hdev->name, opcode, plen);
-
- skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("%s no memory for command", hdev->name);
- return -ENOMEM;
- }
-
- hdr = (struct hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE);
- hdr->opcode = cpu_to_le16(opcode);
- hdr->plen = plen;
-
- if (plen)
- memcpy(skb_put(skb, plen), param, plen);
-
- BT_DBG("skb len %d", skb->len);
-
- bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
- skb->dev = (void *) hdev;
-
- if (test_bit(HCI_INIT, &hdev->flags))
- hdev->init_last_cmd = opcode;
-
- skb_queue_tail(&hdev->cmd_q, skb);
- queue_work(hdev->workqueue, &hdev->cmd_work);
-
- return 0;
-}
-
-/* Get data from the previously sent command */
-void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
-{
- struct hci_command_hdr *hdr;
-
- if (!hdev->sent_cmd)
- return NULL;
-
- hdr = (void *) hdev->sent_cmd->data;
-
- if (hdr->opcode != cpu_to_le16(opcode))
- return NULL;
-
- BT_DBG("%s opcode 0x%x", hdev->name, opcode);
-
- return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
-}
-
-/* Send ACL data */
-static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
-{
- struct hci_acl_hdr *hdr;
- int len = skb->len;
-
- skb_push(skb, HCI_ACL_HDR_SIZE);
- skb_reset_transport_header(skb);
- hdr = (struct hci_acl_hdr *)skb_transport_header(skb);
- hdr->handle = cpu_to_le16(hci_handle_pack(handle, flags));
- hdr->dlen = cpu_to_le16(len);
-}
-
-static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
- struct sk_buff *skb, __u16 flags)
-{
- struct hci_dev *hdev = conn->hdev;
- struct sk_buff *list;
-
- list = skb_shinfo(skb)->frag_list;
- if (!list) {
- /* Non fragmented */
- BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
-
- skb_queue_tail(queue, skb);
- } else {
- /* Fragmented */
- BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
-
- skb_shinfo(skb)->frag_list = NULL;
-
- /* Queue all fragments atomically */
- spin_lock(&queue->lock);
-
- __skb_queue_tail(queue, skb);
-
- flags &= ~ACL_START;
- flags |= ACL_CONT;
- do {
- skb = list; list = list->next;
-
- skb->dev = (void *) hdev;
- bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
- hci_add_acl_hdr(skb, conn->handle, flags);
-
- BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
-
- __skb_queue_tail(queue, skb);
- } while (list);
-
- spin_unlock(&queue->lock);
- }
-}
-
-void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
-{
- struct hci_conn *conn = chan->conn;
- struct hci_dev *hdev = conn->hdev;
-
- BT_DBG("%s chan %p flags 0x%x", hdev->name, chan, flags);
-
- skb->dev = (void *) hdev;
- bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
- hci_add_acl_hdr(skb, conn->handle, flags);
-
- hci_queue_acl(conn, &chan->data_q, skb, flags);
-
- queue_work(hdev->workqueue, &hdev->tx_work);
-}
-EXPORT_SYMBOL(hci_send_acl);
-
-/* Send SCO data */
-void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_sco_hdr hdr;
-
- BT_DBG("%s len %d", hdev->name, skb->len);
-
- hdr.handle = cpu_to_le16(conn->handle);
- hdr.dlen = skb->len;
-
- skb_push(skb, HCI_SCO_HDR_SIZE);
- skb_reset_transport_header(skb);
- memcpy(skb_transport_header(skb), &hdr, HCI_SCO_HDR_SIZE);
-
- skb->dev = (void *) hdev;
- bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
-
- skb_queue_tail(&conn->data_q, skb);
- queue_work(hdev->workqueue, &hdev->tx_work);
-}
-EXPORT_SYMBOL(hci_send_sco);
-
-/* ---- HCI TX task (outgoing data) ---- */
-
-/* HCI Connection scheduler */
-static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
-{
- struct hci_conn_hash *h = &hdev->conn_hash;
- struct hci_conn *conn = NULL, *c;
- int num = 0, min = ~0;
-
- /* We don't have to lock device here. Connections are always
- * added and removed with TX task disabled. */
-
- rcu_read_lock();
-
- list_for_each_entry_rcu(c, &h->list, list) {
- if (c->type != type || skb_queue_empty(&c->data_q))
- continue;
-
- if (c->state != BT_CONNECTED && c->state != BT_CONFIG)
- continue;
-
- num++;
-
- if (c->sent < min) {
- min = c->sent;
- conn = c;
- }
-
- if (hci_conn_num(hdev, type) == num)
- break;
- }
-
- rcu_read_unlock();
-
- if (conn) {
- int cnt, q;
-
- switch (conn->type) {
- case ACL_LINK:
- cnt = hdev->acl_cnt;
- break;
- case SCO_LINK:
- case ESCO_LINK:
- cnt = hdev->sco_cnt;
- break;
- case LE_LINK:
- cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
- break;
- default:
- cnt = 0;
- BT_ERR("Unknown link type");
- }
-
- q = cnt / num;
- *quote = q ? q : 1;
- } else
- *quote = 0;
-
- BT_DBG("conn %p quote %d", conn, *quote);
- return conn;
-}
-
-static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
-{
- struct hci_conn_hash *h = &hdev->conn_hash;
- struct hci_conn *c;
-
- BT_ERR("%s link tx timeout", hdev->name);
-
- rcu_read_lock();
-
- /* Kill stalled connections */
- list_for_each_entry_rcu(c, &h->list, list) {
- if (c->type == type && c->sent) {
- BT_ERR("%s killing stalled connection %s",
- hdev->name, batostr(&c->dst));
- hci_acl_disconn(c, 0x13);
- }
- }
-
- rcu_read_unlock();
-}
-
-static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
- int *quote)
-{
- struct hci_conn_hash *h = &hdev->conn_hash;
- struct hci_chan *chan = NULL;
- int num = 0, min = ~0, cur_prio = 0;
- struct hci_conn *conn;
- int cnt, q, conn_num = 0;
-
- BT_DBG("%s", hdev->name);
-
- rcu_read_lock();
-
- list_for_each_entry_rcu(conn, &h->list, list) {
- struct hci_chan *tmp;
-
- if (conn->type != type)
- continue;
-
- if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
- continue;
-
- conn_num++;
-
- list_for_each_entry_rcu(tmp, &conn->chan_list, list) {
- struct sk_buff *skb;
-
- if (skb_queue_empty(&tmp->data_q))
- continue;
-
- skb = skb_peek(&tmp->data_q);
- if (skb->priority < cur_prio)
- continue;
-
- if (skb->priority > cur_prio) {
- num = 0;
- min = ~0;
- cur_prio = skb->priority;
- }
-
- num++;
-
- if (conn->sent < min) {
- min = conn->sent;
- chan = tmp;
- }
- }
-
- if (hci_conn_num(hdev, type) == conn_num)
- break;
- }
-
- rcu_read_unlock();
-
- if (!chan)
- return NULL;
-
- switch (chan->conn->type) {
- case ACL_LINK:
- cnt = hdev->acl_cnt;
- break;
- case SCO_LINK:
- case ESCO_LINK:
- cnt = hdev->sco_cnt;
- break;
- case LE_LINK:
- cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
- break;
- default:
- cnt = 0;
- BT_ERR("Unknown link type");
- }
-
- q = cnt / num;
- *quote = q ? q : 1;
- BT_DBG("chan %p quote %d", chan, *quote);
- return chan;
-}
-
-static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
-{
- struct hci_conn_hash *h = &hdev->conn_hash;
- struct hci_conn *conn;
- int num = 0;
-
- BT_DBG("%s", hdev->name);
-
- rcu_read_lock();
-
- list_for_each_entry_rcu(conn, &h->list, list) {
- struct hci_chan *chan;
-
- if (conn->type != type)
- continue;
-
- if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
- continue;
-
- num++;
-
- list_for_each_entry_rcu(chan, &conn->chan_list, list) {
- struct sk_buff *skb;
-
- if (chan->sent) {
- chan->sent = 0;
- continue;
- }
-
- if (skb_queue_empty(&chan->data_q))
- continue;
-
- skb = skb_peek(&chan->data_q);
- if (skb->priority >= HCI_PRIO_MAX - 1)
- continue;
-
- skb->priority = HCI_PRIO_MAX - 1;
-
- BT_DBG("chan %p skb %p promoted to %d", chan, skb,
- skb->priority);
- }
-
- if (hci_conn_num(hdev, type) == num)
- break;
- }
-
- rcu_read_unlock();
-
-}
-
-static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb)
-{
- /* Calculate count of blocks used by this packet */
- return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len);
-}
-
-static inline void __check_timeout(struct hci_dev *hdev, unsigned int cnt)
-{
- if (!test_bit(HCI_RAW, &hdev->flags)) {
- /* ACL tx timeout must be longer than maximum
- * link supervision timeout (40.9 seconds) */
- if (!cnt && time_after(jiffies, hdev->acl_last_tx +
- msecs_to_jiffies(HCI_ACL_TX_TIMEOUT)))
- hci_link_tx_to(hdev, ACL_LINK);
- }
-}
-
-static inline void hci_sched_acl_pkt(struct hci_dev *hdev)
-{
- unsigned int cnt = hdev->acl_cnt;
- struct hci_chan *chan;
- struct sk_buff *skb;
- int quote;
-
- __check_timeout(hdev, cnt);
-
- while (hdev->acl_cnt &&
- (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
- u32 priority = (skb_peek(&chan->data_q))->priority;
- while (quote-- && (skb = skb_peek(&chan->data_q))) {
- BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
- skb->len, skb->priority);
-
- /* Stop if priority has changed */
- if (skb->priority < priority)
- break;
-
- skb = skb_dequeue(&chan->data_q);
-
- hci_conn_enter_active_mode(chan->conn,
- bt_cb(skb)->force_active);
-
- hci_send_frame(skb);
- hdev->acl_last_tx = jiffies;
-
- hdev->acl_cnt--;
- chan->sent++;
- chan->conn->sent++;
- }
- }
-
- if (cnt != hdev->acl_cnt)
- hci_prio_recalculate(hdev, ACL_LINK);
-}
-
-static inline void hci_sched_acl_blk(struct hci_dev *hdev)
-{
- unsigned int cnt = hdev->block_cnt;
- struct hci_chan *chan;
- struct sk_buff *skb;
- int quote;
-
- __check_timeout(hdev, cnt);
-
- while (hdev->block_cnt > 0 &&
- (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
- u32 priority = (skb_peek(&chan->data_q))->priority;
- while (quote > 0 && (skb = skb_peek(&chan->data_q))) {
- int blocks;
-
- BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
- skb->len, skb->priority);
-
- /* Stop if priority has changed */
- if (skb->priority < priority)
- break;
-
- skb = skb_dequeue(&chan->data_q);
-
- blocks = __get_blocks(hdev, skb);
- if (blocks > hdev->block_cnt)
- return;
-
- hci_conn_enter_active_mode(chan->conn,
- bt_cb(skb)->force_active);
-
- hci_send_frame(skb);
- hdev->acl_last_tx = jiffies;
-
- hdev->block_cnt -= blocks;
- quote -= blocks;
-
- chan->sent += blocks;
- chan->conn->sent += blocks;
- }
- }
-
- if (cnt != hdev->block_cnt)
- hci_prio_recalculate(hdev, ACL_LINK);
-}
-
-static inline void hci_sched_acl(struct hci_dev *hdev)
-{
- BT_DBG("%s", hdev->name);
-
- if (!hci_conn_num(hdev, ACL_LINK))
- return;
-
- switch (hdev->flow_ctl_mode) {
- case HCI_FLOW_CTL_MODE_PACKET_BASED:
- hci_sched_acl_pkt(hdev);
- break;
-
- case HCI_FLOW_CTL_MODE_BLOCK_BASED:
- hci_sched_acl_blk(hdev);
- break;
- }
-}
-
-/* Schedule SCO */
-static inline void hci_sched_sco(struct hci_dev *hdev)
-{
- struct hci_conn *conn;
- struct sk_buff *skb;
- int quote;
-
- BT_DBG("%s", hdev->name);
-
- if (!hci_conn_num(hdev, SCO_LINK))
- return;
-
- while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
- while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
- BT_DBG("skb %p len %d", skb, skb->len);
- hci_send_frame(skb);
-
- conn->sent++;
- if (conn->sent == ~0)
- conn->sent = 0;
- }
- }
-}
-
-static inline void hci_sched_esco(struct hci_dev *hdev)
-{
- struct hci_conn *conn;
- struct sk_buff *skb;
- int quote;
-
- BT_DBG("%s", hdev->name);
-
- if (!hci_conn_num(hdev, ESCO_LINK))
- return;
-
- while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, &quote))) {
- while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
- BT_DBG("skb %p len %d", skb, skb->len);
- hci_send_frame(skb);
-
- conn->sent++;
- if (conn->sent == ~0)
- conn->sent = 0;
- }
- }
-}
-
-static inline void hci_sched_le(struct hci_dev *hdev)
-{
- struct hci_chan *chan;
- struct sk_buff *skb;
- int quote, cnt, tmp;
-
- BT_DBG("%s", hdev->name);
-
- if (!hci_conn_num(hdev, LE_LINK))
- return;
-
- if (!test_bit(HCI_RAW, &hdev->flags)) {
- /* LE tx timeout must be longer than maximum
- * link supervision timeout (40.9 seconds) */
- if (!hdev->le_cnt && hdev->le_pkts &&
- time_after(jiffies, hdev->le_last_tx + HZ * 45))
- hci_link_tx_to(hdev, LE_LINK);
- }
-
- cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt;
- tmp = cnt;
- while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, &quote))) {
- u32 priority = (skb_peek(&chan->data_q))->priority;
- while (quote-- && (skb = skb_peek(&chan->data_q))) {
- BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
- skb->len, skb->priority);
-
- /* Stop if priority has changed */
- if (skb->priority < priority)
- break;
-
- skb = skb_dequeue(&chan->data_q);
-
- hci_send_frame(skb);
- hdev->le_last_tx = jiffies;
-
- cnt--;
- chan->sent++;
- chan->conn->sent++;
- }
- }
-
- if (hdev->le_pkts)
- hdev->le_cnt = cnt;
- else
- hdev->acl_cnt = cnt;
-
- if (cnt != tmp)
- hci_prio_recalculate(hdev, LE_LINK);
-}
-
-static void hci_tx_work(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev, tx_work);
- struct sk_buff *skb;
-
- BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt,
- hdev->sco_cnt, hdev->le_cnt);
-
- /* Schedule queues and send stuff to HCI driver */
-
- hci_sched_acl(hdev);
-
- hci_sched_sco(hdev);
-
- hci_sched_esco(hdev);
-
- hci_sched_le(hdev);
-
- /* Send next queued raw (unknown type) packet */
- while ((skb = skb_dequeue(&hdev->raw_q)))
- hci_send_frame(skb);
-}
-
-/* ----- HCI RX task (incoming data processing) ----- */
-
-/* ACL data packet */
-static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_acl_hdr *hdr = (void *) skb->data;
- struct hci_conn *conn;
- __u16 handle, flags;
-
- skb_pull(skb, HCI_ACL_HDR_SIZE);
-
- handle = __le16_to_cpu(hdr->handle);
- flags = hci_flags(handle);
- handle = hci_handle(handle);
-
- BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
-
- hdev->stat.acl_rx++;
-
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, handle);
- hci_dev_unlock(hdev);
-
- if (conn) {
- hci_conn_enter_active_mode(conn, BT_POWER_FORCE_ACTIVE_OFF);
-
- hci_dev_lock(hdev);
- if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
- !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
- mgmt_device_connected(hdev, &conn->dst, conn->type,
- conn->dst_type, 0, NULL, 0,
- conn->dev_class);
- hci_dev_unlock(hdev);
-
- /* Send to upper protocol */
- l2cap_recv_acldata(conn, skb, flags);
- return;
- } else {
- BT_ERR("%s ACL packet for unknown connection handle %d",
- hdev->name, handle);
- }
-
- kfree_skb(skb);
-}
-
-/* SCO data packet */
-static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_sco_hdr *hdr = (void *) skb->data;
- struct hci_conn *conn;
- __u16 handle;
-
- skb_pull(skb, HCI_SCO_HDR_SIZE);
-
- handle = __le16_to_cpu(hdr->handle);
-
- BT_DBG("%s len %d handle 0x%x", hdev->name, skb->len, handle);
-
- hdev->stat.sco_rx++;
-
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, handle);
- hci_dev_unlock(hdev);
-
- if (conn) {
- /* Send to upper protocol */
- sco_recv_scodata(conn, skb);
- return;
- } else {
- BT_ERR("%s SCO packet for unknown connection handle %d",
- hdev->name, handle);
- }
-
- kfree_skb(skb);
-}
-
-static void hci_rx_work(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work);
- struct sk_buff *skb;
-
- BT_DBG("%s", hdev->name);
-
- while ((skb = skb_dequeue(&hdev->rx_q))) {
- /* Send copy to monitor */
- hci_send_to_monitor(hdev, skb);
-
- if (atomic_read(&hdev->promisc)) {
- /* Send copy to the sockets */
- hci_send_to_sock(hdev, skb);
- }
-
- if (test_bit(HCI_RAW, &hdev->flags)) {
- kfree_skb(skb);
- continue;
- }
-
- if (test_bit(HCI_INIT, &hdev->flags)) {
- /* Don't process data packets in this states. */
- switch (bt_cb(skb)->pkt_type) {
- case HCI_ACLDATA_PKT:
- case HCI_SCODATA_PKT:
- kfree_skb(skb);
- continue;
- }
- }
-
- /* Process frame */
- switch (bt_cb(skb)->pkt_type) {
- case HCI_EVENT_PKT:
- BT_DBG("%s Event packet", hdev->name);
- hci_event_packet(hdev, skb);
- break;
-
- case HCI_ACLDATA_PKT:
- BT_DBG("%s ACL data packet", hdev->name);
- hci_acldata_packet(hdev, skb);
- break;
-
- case HCI_SCODATA_PKT:
- BT_DBG("%s SCO data packet", hdev->name);
- hci_scodata_packet(hdev, skb);
- break;
-
- default:
- kfree_skb(skb);
- break;
- }
- }
-}
-
-static void hci_cmd_work(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_work);
- struct sk_buff *skb;
-
- BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
-
- /* Send queued commands */
- if (atomic_read(&hdev->cmd_cnt)) {
- skb = skb_dequeue(&hdev->cmd_q);
- if (!skb)
- return;
-
- kfree_skb(hdev->sent_cmd);
-
- hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
- if (hdev->sent_cmd) {
- atomic_dec(&hdev->cmd_cnt);
- hci_send_frame(skb);
- if (test_bit(HCI_RESET, &hdev->flags))
- del_timer(&hdev->cmd_timer);
- else
- mod_timer(&hdev->cmd_timer,
- jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT));
- } else {
- skb_queue_head(&hdev->cmd_q, skb);
- queue_work(hdev->workqueue, &hdev->cmd_work);
- }
- }
-}
-
-int hci_do_inquiry(struct hci_dev *hdev, u8 length)
-{
- /* General inquiry access code (GIAC) */
- u8 lap[3] = { 0x33, 0x8b, 0x9e };
- struct hci_cp_inquiry cp;
-
- BT_DBG("%s", hdev->name);
-
- if (test_bit(HCI_INQUIRY, &hdev->flags))
- return -EINPROGRESS;
-
- inquiry_cache_flush(hdev);
-
- memset(&cp, 0, sizeof(cp));
- memcpy(&cp.lap, lap, sizeof(cp.lap));
- cp.length = length;
-
- return hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
-}
-
-int hci_cancel_inquiry(struct hci_dev *hdev)
-{
- BT_DBG("%s", hdev->name);
-
- if (!test_bit(HCI_INQUIRY, &hdev->flags))
- return -EPERM;
-
- return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
-}
diff --git a/net/bluetooth_tizen/hci_event.c b/net/bluetooth_tizen/hci_event.c
deleted file mode 100644
index 17aaa11..0000000
--- a/net/bluetooth_tizen/hci_event.c
+++ /dev/null
@@ -1,3604 +0,0 @@
-/*
- BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
-
- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/* Bluetooth HCI event handling. */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <linux/notifier.h>
-#include <net/sock.h>
-
-#include <asm/system.h>
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
-/* Handle HCI Event packets */
-
-static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (status) {
- hci_dev_lock(hdev);
- mgmt_stop_discovery_failed(hdev, status);
- hci_dev_unlock(hdev);
- return;
- }
-
- clear_bit(HCI_INQUIRY, &hdev->flags);
-
- hci_dev_lock(hdev);
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- hci_dev_unlock(hdev);
-
- hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
-
- hci_conn_check_pending(hdev);
-}
-
-static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (status)
- return;
-
- hci_conn_check_pending(hdev);
-}
-
-static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev, struct sk_buff *skb)
-{
- BT_DBG("%s", hdev->name);
-}
-
-static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_role_discovery *rp = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
- if (conn) {
- if (rp->role)
- conn->link_mode &= ~HCI_LM_MASTER;
- else
- conn->link_mode |= HCI_LM_MASTER;
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_read_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_link_policy *rp = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
- if (conn)
- conn->link_policy = __le16_to_cpu(rp->policy);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_write_link_policy *rp = (void *) skb->data;
- struct hci_conn *conn;
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LINK_POLICY);
- if (!sent)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
- if (conn)
- conn->link_policy = get_unaligned_le16(sent + 2);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_def_link_policy *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hdev->link_policy = __le16_to_cpu(rp->policy);
-}
-
-static void hci_cc_write_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_LINK_POLICY);
- if (!sent)
- return;
-
- if (!status)
- hdev->link_policy = get_unaligned_le16(sent);
-
- hci_req_complete(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, status);
-}
-
-static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- clear_bit(HCI_RESET, &hdev->flags);
-
- hci_req_complete(hdev, HCI_OP_RESET, status);
-
- /* Reset all non-persistent flags */
- hdev->dev_flags &= ~(BIT(HCI_LE_SCAN) | BIT(HCI_PENDING_CLASS));
-
- hdev->discovery.state = DISCOVERY_STOPPED;
-}
-
-static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
- if (!sent)
- return;
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_set_local_name_complete(hdev, sent, status);
- else if (!status)
- memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
-
- hci_dev_unlock(hdev);
-
- hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status);
-}
-
-static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_local_name *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- if (test_bit(HCI_SETUP, &hdev->dev_flags))
- memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH);
-}
-
-static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_AUTH_ENABLE);
- if (!sent)
- return;
-
- if (!status) {
- __u8 param = *((__u8 *) sent);
-
- if (param == AUTH_ENABLED)
- set_bit(HCI_AUTH, &hdev->flags);
- else
- clear_bit(HCI_AUTH, &hdev->flags);
- }
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_auth_enable_complete(hdev, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_AUTH_ENABLE, status);
-}
-
-static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_ENCRYPT_MODE);
- if (!sent)
- return;
-
- if (!status) {
- __u8 param = *((__u8 *) sent);
-
- if (param)
- set_bit(HCI_ENCRYPT, &hdev->flags);
- else
- clear_bit(HCI_ENCRYPT, &hdev->flags);
- }
-
- hci_req_complete(hdev, HCI_OP_WRITE_ENCRYPT_MODE, status);
-}
-
-static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 param, status = *((__u8 *) skb->data);
- int old_pscan, old_iscan;
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SCAN_ENABLE);
- if (!sent)
- return;
-
- param = *((__u8 *) sent);
-
- hci_dev_lock(hdev);
-
- if (status != 0) {
- mgmt_write_scan_failed(hdev, param, status);
- hdev->discov_timeout = 0;
- goto done;
- }
-
- old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags);
- old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags);
-
- if (param & SCAN_INQUIRY) {
- set_bit(HCI_ISCAN, &hdev->flags);
- if (!old_iscan)
- mgmt_discoverable(hdev, 1);
- if (hdev->discov_timeout > 0) {
- int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
- queue_delayed_work(hdev->workqueue, &hdev->discov_off,
- to);
- }
- } else if (old_iscan)
- mgmt_discoverable(hdev, 0);
-
- if (param & SCAN_PAGE) {
- set_bit(HCI_PSCAN, &hdev->flags);
- if (!old_pscan)
- mgmt_connectable(hdev, 1);
- } else if (old_pscan)
- mgmt_connectable(hdev, 0);
-
-done:
- hci_dev_unlock(hdev);
- hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status);
-}
-
-static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_class_of_dev *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- memcpy(hdev->dev_class, rp->dev_class, 3);
-
- BT_DBG("%s class 0x%.2x%.2x%.2x", hdev->name,
- hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
-}
-
-static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV);
- if (!sent)
- return;
-
- hci_dev_lock(hdev);
-
- if (status == 0)
- memcpy(hdev->dev_class, sent, 3);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_set_class_of_dev_complete(hdev, sent, status);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_voice_setting *rp = (void *) skb->data;
- __u16 setting;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- setting = __le16_to_cpu(rp->voice_setting);
-
- if (hdev->voice_setting == setting)
- return;
-
- hdev->voice_setting = setting;
-
- BT_DBG("%s voice setting 0x%04x", hdev->name, setting);
-
- if (hdev->notify)
- hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
-}
-
-static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
- __u16 setting;
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (status)
- return;
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_VOICE_SETTING);
- if (!sent)
- return;
-
- setting = get_unaligned_le16(sent);
-
- if (hdev->voice_setting == setting)
- return;
-
- hdev->voice_setting = setting;
-
- BT_DBG("%s voice setting 0x%04x", hdev->name, setting);
-
- if (hdev->notify)
- hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
-}
-
-static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status);
-}
-
-static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE);
- if (!sent)
- return;
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_ssp_enable_complete(hdev, *((u8 *) sent), status);
- else if (!status) {
- if (*((u8 *) sent))
- set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
- else
- clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
- }
-}
-
-static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
-{
- if (hdev->features[6] & LMP_EXT_INQ)
- return 2;
-
- if (hdev->features[3] & LMP_RSSI_INQ)
- return 1;
-
- if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 &&
- hdev->lmp_subver == 0x0757)
- return 1;
-
- if (hdev->manufacturer == 15) {
- if (hdev->hci_rev == 0x03 && hdev->lmp_subver == 0x6963)
- return 1;
- if (hdev->hci_rev == 0x09 && hdev->lmp_subver == 0x6963)
- return 1;
- if (hdev->hci_rev == 0x00 && hdev->lmp_subver == 0x6965)
- return 1;
- }
-
- if (hdev->manufacturer == 31 && hdev->hci_rev == 0x2005 &&
- hdev->lmp_subver == 0x1805)
- return 1;
-
- return 0;
-}
-
-static void hci_setup_inquiry_mode(struct hci_dev *hdev)
-{
- u8 mode;
-
- mode = hci_get_inquiry_mode(hdev);
-
- hci_send_cmd(hdev, HCI_OP_WRITE_INQUIRY_MODE, 1, &mode);
-}
-
-static void hci_setup_event_mask(struct hci_dev *hdev)
-{
- /* The second byte is 0xff instead of 0x9f (two reserved bits
- * disabled) since a Broadcom 1.2 dongle doesn't respond to the
- * command otherwise */
- u8 events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
-
- /* CSR 1.1 dongles does not accept any bitfield so don't try to set
- * any event mask for pre 1.2 devices */
- if (hdev->hci_ver < BLUETOOTH_VER_1_2)
- return;
-
- events[4] |= 0x01; /* Flow Specification Complete */
- events[4] |= 0x02; /* Inquiry Result with RSSI */
- events[4] |= 0x04; /* Read Remote Extended Features Complete */
- events[5] |= 0x08; /* Synchronous Connection Complete */
- events[5] |= 0x10; /* Synchronous Connection Changed */
-
- if (hdev->features[3] & LMP_RSSI_INQ)
- events[4] |= 0x02; /* Inquiry Result with RSSI */
-
- if (hdev->features[5] & LMP_SNIFF_SUBR)
- events[5] |= 0x20; /* Sniff Subrating */
-
- if (hdev->features[5] & LMP_PAUSE_ENC)
- events[5] |= 0x80; /* Encryption Key Refresh Complete */
-
- if (hdev->features[6] & LMP_EXT_INQ)
- events[5] |= 0x40; /* Extended Inquiry Result */
-
- if (hdev->features[6] & LMP_NO_FLUSH)
- events[7] |= 0x01; /* Enhanced Flush Complete */
-
- if (hdev->features[7] & LMP_LSTO)
- events[6] |= 0x80; /* Link Supervision Timeout Changed */
-
- if (hdev->features[6] & LMP_SIMPLE_PAIR) {
- events[6] |= 0x01; /* IO Capability Request */
- events[6] |= 0x02; /* IO Capability Response */
- events[6] |= 0x04; /* User Confirmation Request */
- events[6] |= 0x08; /* User Passkey Request */
- events[6] |= 0x10; /* Remote OOB Data Request */
- events[6] |= 0x20; /* Simple Pairing Complete */
- events[7] |= 0x04; /* User Passkey Notification */
- events[7] |= 0x08; /* Keypress Notification */
- events[7] |= 0x10; /* Remote Host Supported
- * Features Notification */
- }
-
- if (hdev->features[4] & LMP_LE)
- events[7] |= 0x20; /* LE Meta-Event */
-
- hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
-}
-
-static void hci_setup(struct hci_dev *hdev)
-{
- if (hdev->dev_type != HCI_BREDR)
- return;
-
- hci_setup_event_mask(hdev);
-
- if (hdev->hci_ver > BLUETOOTH_VER_1_1)
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
-
- if (hdev->features[6] & LMP_SIMPLE_PAIR) {
- if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
- u8 mode = 0x01;
- hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE,
- sizeof(mode), &mode);
- } else {
- struct hci_cp_write_eir cp;
-
- memset(hdev->eir, 0, sizeof(hdev->eir));
- memset(&cp, 0, sizeof(cp));
-
- hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
- }
- }
-
- if (hdev->features[3] & LMP_RSSI_INQ)
- hci_setup_inquiry_mode(hdev);
-
- if (hdev->features[7] & LMP_INQ_TX_PWR)
- hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
-
- if (hdev->features[7] & LMP_EXTFEATURES) {
- struct hci_cp_read_local_ext_features cp;
-
- cp.page = 0x01;
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp),
- &cp);
- }
-
- if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) {
- u8 enable = 1;
- hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable),
- &enable);
- }
-}
-
-static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_local_version *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- goto done;
-
- hdev->hci_ver = rp->hci_ver;
- hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
- hdev->lmp_ver = rp->lmp_ver;
- hdev->manufacturer = __le16_to_cpu(rp->manufacturer);
- hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver);
-
- BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
- hdev->manufacturer,
- hdev->hci_ver, hdev->hci_rev);
-
- if (test_bit(HCI_INIT, &hdev->flags))
- hci_setup(hdev);
-
-done:
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_VERSION, rp->status);
-}
-
-static void hci_setup_link_policy(struct hci_dev *hdev)
-{
- u16 link_policy = 0;
-
- if (hdev->features[0] & LMP_RSWITCH)
- link_policy |= HCI_LP_RSWITCH;
- if (hdev->features[0] & LMP_HOLD)
- link_policy |= HCI_LP_HOLD;
- if (hdev->features[0] & LMP_SNIFF)
- link_policy |= HCI_LP_SNIFF;
- if (hdev->features[1] & LMP_PARK)
- link_policy |= HCI_LP_PARK;
-
- link_policy = cpu_to_le16(link_policy);
- hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(link_policy),
- &link_policy);
-}
-
-static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_local_commands *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- goto done;
-
- memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
-
- if (test_bit(HCI_INIT, &hdev->flags) && (hdev->commands[5] & 0x10))
- hci_setup_link_policy(hdev);
-
-done:
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_COMMANDS, rp->status);
-}
-
-static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_local_features *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- memcpy(hdev->features, rp->features, 8);
-
- /* Adjust default settings according to features
- * supported by device. */
-
- if (hdev->features[0] & LMP_3SLOT)
- hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
-
- if (hdev->features[0] & LMP_5SLOT)
- hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
-
- if (hdev->features[1] & LMP_HV2) {
- hdev->pkt_type |= (HCI_HV2);
- hdev->esco_type |= (ESCO_HV2);
- }
-
- if (hdev->features[1] & LMP_HV3) {
- hdev->pkt_type |= (HCI_HV3);
- hdev->esco_type |= (ESCO_HV3);
- }
-
- if (hdev->features[3] & LMP_ESCO)
- hdev->esco_type |= (ESCO_EV3);
-
- if (hdev->features[4] & LMP_EV4)
- hdev->esco_type |= (ESCO_EV4);
-
- if (hdev->features[4] & LMP_EV5)
- hdev->esco_type |= (ESCO_EV5);
-
- if (hdev->features[5] & LMP_EDR_ESCO_2M)
- hdev->esco_type |= (ESCO_2EV3);
-
- if (hdev->features[5] & LMP_EDR_ESCO_3M)
- hdev->esco_type |= (ESCO_3EV3);
-
- if (hdev->features[5] & LMP_EDR_3S_ESCO)
- hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
-
- BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
- hdev->features[0], hdev->features[1],
- hdev->features[2], hdev->features[3],
- hdev->features[4], hdev->features[5],
- hdev->features[6], hdev->features[7]);
-}
-
-static void hci_set_le_support(struct hci_dev *hdev)
-{
- struct hci_cp_write_le_host_supported cp;
-
- memset(&cp, 0, sizeof(cp));
-
- if (enable_le && test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
- cp.le = 1;
- cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
- }
-
- if (cp.le != !!(hdev->host_features[0] & LMP_HOST_LE))
- hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),
- &cp);
-}
-
-static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_rp_read_local_ext_features *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- goto done;
-
- switch (rp->page) {
- case 0:
- memcpy(hdev->features, rp->features, 8);
- break;
- case 1:
- memcpy(hdev->host_features, rp->features, 8);
- break;
- }
-
- if (test_bit(HCI_INIT, &hdev->flags) && hdev->features[4] & LMP_LE)
- hci_set_le_support(hdev);
-
-done:
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
-}
-
-static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_rp_read_flow_control_mode *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hdev->flow_ctl_mode = rp->mode;
-
- hci_req_complete(hdev, HCI_OP_READ_FLOW_CONTROL_MODE, rp->status);
-}
-
-static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_buffer_size *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hdev->acl_mtu = __le16_to_cpu(rp->acl_mtu);
- hdev->sco_mtu = rp->sco_mtu;
- hdev->acl_pkts = __le16_to_cpu(rp->acl_max_pkt);
- hdev->sco_pkts = __le16_to_cpu(rp->sco_max_pkt);
-
- if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) {
- hdev->sco_mtu = 64;
- hdev->sco_pkts = 8;
- }
-
- hdev->acl_cnt = hdev->acl_pkts;
- hdev->sco_cnt = hdev->sco_pkts;
-
- BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name,
- hdev->acl_mtu, hdev->acl_pkts,
- hdev->sco_mtu, hdev->sco_pkts);
-}
-
-static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_bd_addr *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (!rp->status)
- bacpy(&hdev->bdaddr, &rp->bdaddr);
-
- hci_req_complete(hdev, HCI_OP_READ_BD_ADDR, rp->status);
-}
-
-static void hci_cc_read_data_block_size(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_rp_read_data_block_size *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hdev->block_mtu = __le16_to_cpu(rp->max_acl_len);
- hdev->block_len = __le16_to_cpu(rp->block_len);
- hdev->num_blocks = __le16_to_cpu(rp->num_blocks);
-
- hdev->block_cnt = hdev->num_blocks;
-
- BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu,
- hdev->block_cnt, hdev->block_len);
-
- hci_req_complete(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, rp->status);
-}
-
-static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status);
-}
-
-static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_rp_read_local_amp_info *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hdev->amp_status = rp->amp_status;
- hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
- hdev->amp_max_bw = __le32_to_cpu(rp->max_bw);
- hdev->amp_min_latency = __le32_to_cpu(rp->min_latency);
- hdev->amp_max_pdu = __le32_to_cpu(rp->max_pdu);
- hdev->amp_type = rp->amp_type;
- hdev->amp_pal_cap = __le16_to_cpu(rp->pal_cap);
- hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size);
- hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
- hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
-
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_AMP_INFO, rp->status);
-}
-
-static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_DELETE_STORED_LINK_KEY, status);
-}
-
-static void hci_cc_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_SET_EVENT_MASK, status);
-}
-
-static void hci_cc_write_inquiry_mode(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_INQUIRY_MODE, status);
-}
-
-static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, status);
-}
-
-static void hci_cc_set_event_flt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_SET_EVENT_FLT, status);
-}
-
-static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_pin_code_reply *rp = (void *) skb->data;
- struct hci_cp_pin_code_reply *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status);
-
- if (rp->status != 0)
- goto unlock;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
- if (!cp)
- goto unlock;
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
- if (conn)
- conn->pin_length = cp->pin_len;
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_pin_code_neg_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr,
- rp->status);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_rp_le_read_buffer_size *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hdev->le_mtu = __le16_to_cpu(rp->le_mtu);
- hdev->le_pkts = rp->le_max_pkt;
-
- hdev->le_cnt = hdev->le_pkts;
-
- BT_DBG("%s le mtu %d:%d", hdev->name, hdev->le_mtu, hdev->le_pkts);
-
- hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status);
-}
-
-static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, ACL_LINK, 0,
- rp->status);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr,
- ACL_LINK, 0, rp->status);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr, ACL_LINK,
- 0, rp->status);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr,
- ACL_LINK, 0, rp->status);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- hci_dev_lock(hdev);
- mgmt_read_local_oob_data_reply_complete(hdev, rp->hash,
- rp->randomizer, rp->status);
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_PARAM, status);
-
- if (status) {
- hci_dev_lock(hdev);
- mgmt_start_discovery_failed(hdev, status);
- hci_dev_unlock(hdev);
- return;
- }
-}
-
-static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_cp_le_set_scan_enable *cp;
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE);
- if (!cp)
- return;
-
- switch (cp->enable) {
- case LE_SCANNING_ENABLED:
- hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_ENABLE, status);
-
- if (status) {
- hci_dev_lock(hdev);
- mgmt_start_discovery_failed(hdev, status);
- hci_dev_unlock(hdev);
- return;
- }
-
- set_bit(HCI_LE_SCAN, &hdev->dev_flags);
-
- cancel_delayed_work_sync(&hdev->adv_work);
-
- hci_dev_lock(hdev);
- hci_adv_entries_clear(hdev);
- hci_discovery_set_state(hdev, DISCOVERY_FINDING);
- hci_dev_unlock(hdev);
- break;
-
- case LE_SCANNING_DISABLED:
- if (status)
- return;
-
- clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
-
- schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT);
-
- if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED) {
- mgmt_interleaved_discovery(hdev);
- } else {
- hci_dev_lock(hdev);
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- hci_dev_unlock(hdev);
- }
-
- break;
-
- default:
- BT_ERR("Used reserved LE_Scan_Enable param %d", cp->enable);
- break;
- }
-}
-
-static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_le_ltk_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hci_req_complete(hdev, HCI_OP_LE_LTK_REPLY, rp->status);
-}
-
-static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_le_ltk_neg_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status);
-}
-
-static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_cp_write_le_host_supported *sent;
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED);
- if (!sent)
- return;
-
- if (!status) {
- if (sent->le)
- hdev->host_features[0] |= LMP_HOST_LE;
- else
- hdev->host_features[0] &= ~LMP_HOST_LE;
- }
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
- !test_bit(HCI_INIT, &hdev->flags))
- mgmt_le_enable_complete(hdev, sent->le, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status);
-}
-
-static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
-{
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (status) {
- hci_req_complete(hdev, HCI_OP_INQUIRY, status);
- hci_conn_check_pending(hdev);
- hci_dev_lock(hdev);
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_start_discovery_failed(hdev, status);
- hci_dev_unlock(hdev);
- return;
- }
-
- set_bit(HCI_INQUIRY, &hdev->flags);
-
- hci_dev_lock(hdev);
- hci_discovery_set_state(hdev, DISCOVERY_FINDING);
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_create_conn *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_CONN);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
-
- BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->bdaddr), conn);
-
- if (status) {
- if (conn && conn->state == BT_CONNECT) {
- if (status != 0x0c || conn->attempt > 2) {
- conn->state = BT_CLOSED;
- hci_proto_connect_cfm(conn, status);
- hci_conn_del(conn);
- } else
- conn->state = BT_CONNECT2;
- }
- } else {
- if (!conn) {
- conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr);
- if (conn) {
- conn->out = true;
- conn->link_mode |= HCI_LM_MASTER;
- } else
- BT_ERR("No memory for new connection");
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_add_sco *cp;
- struct hci_conn *acl, *sco;
- __u16 handle;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_ADD_SCO);
- if (!cp)
- return;
-
- handle = __le16_to_cpu(cp->handle);
-
- BT_DBG("%s handle %d", hdev->name, handle);
-
- hci_dev_lock(hdev);
-
- acl = hci_conn_hash_lookup_handle(hdev, handle);
- if (acl) {
- sco = acl->link;
- if (sco) {
- sco->state = BT_CLOSED;
-
- hci_proto_connect_cfm(sco, status);
- hci_conn_del(sco);
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_auth_requested(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_auth_requested *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_AUTH_REQUESTED);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- if (conn->state == BT_CONFIG) {
- hci_proto_connect_cfm(conn, status);
- hci_conn_put(conn);
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_set_conn_encrypt *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_SET_CONN_ENCRYPT);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- if (conn->state == BT_CONFIG) {
- hci_proto_connect_cfm(conn, status);
- hci_conn_put(conn);
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static int hci_outgoing_auth_needed(struct hci_dev *hdev,
- struct hci_conn *conn)
-{
- if (conn->state != BT_CONFIG || !conn->out)
- return 0;
-
- if (conn->pending_sec_level == BT_SECURITY_SDP)
- return 0;
-
- /* Only request authentication for SSP connections or non-SSP
- * devices with sec_level HIGH or if MITM protection is requested */
- if (!hci_conn_ssp_enabled(conn) &&
- conn->pending_sec_level != BT_SECURITY_HIGH &&
- !(conn->auth_type & 0x01))
- return 0;
-
- return 1;
-}
-
-static inline int hci_resolve_name(struct hci_dev *hdev,
- struct inquiry_entry *e)
-{
- struct hci_cp_remote_name_req cp;
-
- memset(&cp, 0, sizeof(cp));
-
- bacpy(&cp.bdaddr, &e->data.bdaddr);
- cp.pscan_rep_mode = e->data.pscan_rep_mode;
- cp.pscan_mode = e->data.pscan_mode;
- cp.clock_offset = e->data.clock_offset;
-
- return hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
-}
-
-static bool hci_resolve_next_name(struct hci_dev *hdev)
-{
- struct discovery_state *discov = &hdev->discovery;
- struct inquiry_entry *e;
-
- if (list_empty(&discov->resolve))
- return false;
-
- e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED);
- if (hci_resolve_name(hdev, e) == 0) {
- e->name_state = NAME_PENDING;
- return true;
- }
-
- return false;
-}
-
-static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn,
- bdaddr_t *bdaddr, u8 *name, u8 name_len)
-{
- struct discovery_state *discov = &hdev->discovery;
- struct inquiry_entry *e;
-
- if (conn && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
- mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, 0, name,
- name_len, conn->dev_class);
-
- if (discov->state == DISCOVERY_STOPPED)
- return;
-
- if (discov->state == DISCOVERY_STOPPING)
- goto discov_complete;
-
- if (discov->state != DISCOVERY_RESOLVING)
- return;
-
- e = hci_inquiry_cache_lookup_resolve(hdev, bdaddr, NAME_PENDING);
- if (e) {
- e->name_state = NAME_KNOWN;
- list_del(&e->list);
- if (name)
- mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00,
- e->data.rssi, name, name_len);
- }
-
- if (hci_resolve_next_name(hdev))
- return;
-
-discov_complete:
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
-}
-
-static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_remote_name_req *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- /* If successful wait for the name req complete event before
- * checking for the need to do authentication */
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_REMOTE_NAME_REQ);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- hci_check_pending_name(hdev, conn, &cp->bdaddr, NULL, 0);
-
- if (!conn)
- goto unlock;
-
- if (!hci_outgoing_auth_needed(hdev, conn))
- goto unlock;
-
- if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
- struct hci_cp_auth_requested cp;
- cp.handle = __cpu_to_le16(conn->handle);
- hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_read_remote_features(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_read_remote_features *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_READ_REMOTE_FEATURES);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- if (conn->state == BT_CONFIG) {
- hci_proto_connect_cfm(conn, status);
- hci_conn_put(conn);
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_read_remote_ext_features(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_read_remote_ext_features *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_READ_REMOTE_EXT_FEATURES);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- if (conn->state == BT_CONFIG) {
- hci_proto_connect_cfm(conn, status);
- hci_conn_put(conn);
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_setup_sync_conn *cp;
- struct hci_conn *acl, *sco;
- __u16 handle;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_SETUP_SYNC_CONN);
- if (!cp)
- return;
-
- handle = __le16_to_cpu(cp->handle);
-
- BT_DBG("%s handle %d", hdev->name, handle);
-
- hci_dev_lock(hdev);
-
- acl = hci_conn_hash_lookup_handle(hdev, handle);
- if (acl) {
- sco = acl->link;
- if (sco) {
- sco->state = BT_CLOSED;
-
- hci_proto_connect_cfm(sco, status);
- hci_conn_del(sco);
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_sniff_mode *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_SNIFF_MODE);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags);
-
- if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
- hci_sco_setup(conn, status);
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_exit_sniff_mode *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_EXIT_SNIFF_MODE);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags);
-
- if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
- hci_sco_setup(conn, status);
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
-{
- struct hci_cp_disconnect *cp;
- struct hci_conn *conn;
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_DISCONNECT);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn)
- mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
- conn->dst_type, status);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_le_create_conn *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
-
- BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->peer_addr),
- conn);
-
- if (status) {
- if (conn && conn->state == BT_CONNECT) {
- conn->state = BT_CLOSED;
- hci_proto_connect_cfm(conn, status);
- hci_conn_del(conn);
- }
- } else {
- if (!conn) {
- conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr);
- if (conn) {
- conn->dst_type = cp->peer_addr_type;
- conn->out = true;
- } else {
- BT_ERR("No memory for new connection");
- }
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
-{
- BT_DBG("%s status 0x%x", hdev->name, status);
-}
-
-static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
- struct discovery_state *discov = &hdev->discovery;
- struct inquiry_entry *e;
-
- BT_DBG("%s status %d", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_INQUIRY, status);
-
- hci_conn_check_pending(hdev);
-
- if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
- return;
-
- if (!test_bit(HCI_MGMT, &hdev->dev_flags))
- return;
-
- hci_dev_lock(hdev);
-
- if (discov->state != DISCOVERY_FINDING)
- goto unlock;
-
- if (list_empty(&discov->resolve)) {
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- goto unlock;
- }
-
- e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED);
- if (e && hci_resolve_name(hdev, e) == 0) {
- e->name_state = NAME_PENDING;
- hci_discovery_set_state(hdev, DISCOVERY_RESOLVING);
- } else {
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct inquiry_data data;
- struct inquiry_info *info = (void *) (skb->data + 1);
- int num_rsp = *((__u8 *) skb->data);
-
- BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
-
- if (!num_rsp)
- return;
-
- hci_dev_lock(hdev);
-
- for (; num_rsp; num_rsp--, info++) {
- bool name_known, ssp;
-
- bacpy(&data.bdaddr, &info->bdaddr);
- data.pscan_rep_mode = info->pscan_rep_mode;
- data.pscan_period_mode = info->pscan_period_mode;
- data.pscan_mode = info->pscan_mode;
- memcpy(data.dev_class, info->dev_class, 3);
- data.clock_offset = info->clock_offset;
- data.rssi = 0x00;
- data.ssp_mode = 0x00;
-
- name_known = hci_inquiry_cache_update(hdev, &data, false, &ssp);
- mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
- info->dev_class, 0, !name_known, ssp, NULL,
- 0);
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_conn_complete *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
- if (!conn) {
- if (ev->link_type != SCO_LINK)
- goto unlock;
-
- conn = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, &ev->bdaddr);
- if (!conn)
- goto unlock;
-
- conn->type = SCO_LINK;
- }
-
- if (!ev->status) {
- conn->handle = __le16_to_cpu(ev->handle);
-
- if (conn->type == ACL_LINK) {
- conn->state = BT_CONFIG;
- hci_conn_hold(conn);
- conn->disc_timeout = HCI_DISCONN_TIMEOUT;
- } else
- conn->state = BT_CONNECTED;
-
- hci_conn_hold_device(conn);
- hci_conn_add_sysfs(conn);
-
- if (test_bit(HCI_AUTH, &hdev->flags))
- conn->link_mode |= HCI_LM_AUTH;
-
- if (test_bit(HCI_ENCRYPT, &hdev->flags))
- conn->link_mode |= HCI_LM_ENCRYPT;
-
- /* Get remote features */
- if (conn->type == ACL_LINK) {
- struct hci_cp_read_remote_features cp;
- cp.handle = ev->handle;
- hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES,
- sizeof(cp), &cp);
- }
-
- /* Set packet type for incoming connection */
- if (!conn->out && hdev->hci_ver < BLUETOOTH_VER_2_0) {
- struct hci_cp_change_conn_ptype cp;
- cp.handle = ev->handle;
- cp.pkt_type = cpu_to_le16(conn->pkt_type);
- hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp),
- &cp);
- }
- } else {
- conn->state = BT_CLOSED;
- if (conn->type == ACL_LINK)
- mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
- conn->dst_type, ev->status);
- }
-
- if (conn->type == ACL_LINK)
- hci_sco_setup(conn, ev->status);
-
- if (ev->status) {
- hci_proto_connect_cfm(conn, ev->status);
- hci_conn_del(conn);
- } else if (ev->link_type != ACL_LINK)
- hci_proto_connect_cfm(conn, ev->status);
-
-unlock:
- hci_dev_unlock(hdev);
-
- hci_conn_check_pending(hdev);
-}
-
-static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_conn_request *ev = (void *) skb->data;
- int mask = hdev->link_mode;
-
- BT_DBG("%s bdaddr %s type 0x%x", hdev->name,
- batostr(&ev->bdaddr), ev->link_type);
-
- mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
-
- if ((mask & HCI_LM_ACCEPT) &&
- !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
- /* Connection accepted */
- struct inquiry_entry *ie;
- struct hci_conn *conn;
-
- hci_dev_lock(hdev);
-
- ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
- if (ie)
- memcpy(ie->data.dev_class, ev->dev_class, 3);
-
- conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
- if (!conn) {
- conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr);
- if (!conn) {
- BT_ERR("No memory for new connection");
- hci_dev_unlock(hdev);
- return;
- }
- }
-
- memcpy(conn->dev_class, ev->dev_class, 3);
- conn->state = BT_CONNECT;
-
- hci_dev_unlock(hdev);
-
- if (ev->link_type == ACL_LINK || !lmp_esco_capable(hdev)) {
- struct hci_cp_accept_conn_req cp;
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
-
- if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
- cp.role = 0x00; /* Become master */
- else
- cp.role = 0x01; /* Remain slave */
-
- hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp),
- &cp);
- } else {
- struct hci_cp_accept_sync_conn_req cp;
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
- cp.pkt_type = cpu_to_le16(conn->pkt_type);
-
- cp.tx_bandwidth = cpu_to_le32(0x00001f40);
- cp.rx_bandwidth = cpu_to_le32(0x00001f40);
- cp.max_latency = cpu_to_le16(0xffff);
- cp.content_format = cpu_to_le16(hdev->voice_setting);
- cp.retrans_effort = 0xff;
-
- hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
- sizeof(cp), &cp);
- }
- } else {
- /* Connection rejected */
- struct hci_cp_reject_conn_req cp;
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
- cp.reason = HCI_ERROR_REJ_BAD_ADDR;
- hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, sizeof(cp), &cp);
- }
-}
-
-static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_disconn_complete *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (!conn)
- goto unlock;
-
- if (ev->status == 0)
- conn->state = BT_CLOSED;
-
- if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
- (conn->type == ACL_LINK || conn->type == LE_LINK)) {
- if (ev->status != 0)
- mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
- conn->dst_type, ev->status);
- else
- mgmt_device_disconnected(hdev, &conn->dst, conn->type,
- conn->dst_type);
- }
-
- if (ev->status == 0) {
- if (conn->type == ACL_LINK && conn->flush_key)
- hci_remove_link_key(hdev, &conn->dst);
- hci_proto_disconn_cfm(conn, ev->reason);
- hci_conn_del(conn);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_auth_complete *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (!conn)
- goto unlock;
-
- if (!ev->status) {
- if (!hci_conn_ssp_enabled(conn) &&
- test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) {
- BT_INFO("re-auth of legacy device is not possible.");
- } else {
- conn->link_mode |= HCI_LM_AUTH;
- conn->sec_level = conn->pending_sec_level;
- }
- } else {
- mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
- ev->status);
- }
-
- clear_bit(HCI_CONN_AUTH_PEND, &conn->flags);
- clear_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
-
- if (conn->state == BT_CONFIG) {
- if (!ev->status && hci_conn_ssp_enabled(conn)) {
- struct hci_cp_set_conn_encrypt cp;
- cp.handle = ev->handle;
- cp.encrypt = 0x01;
- hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
- &cp);
- } else {
- conn->state = BT_CONNECTED;
- hci_proto_connect_cfm(conn, ev->status);
- hci_conn_put(conn);
- }
- } else {
- hci_auth_cfm(conn, ev->status);
-
- hci_conn_hold(conn);
- conn->disc_timeout = HCI_DISCONN_TIMEOUT;
- hci_conn_put(conn);
- }
-
- if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) {
- if (!ev->status) {
- struct hci_cp_set_conn_encrypt cp;
- cp.handle = ev->handle;
- cp.encrypt = 0x01;
- hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
- &cp);
- } else {
- clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
- hci_encrypt_cfm(conn, ev->status, 0x00);
- }
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_remote_name *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s", hdev->name);
-
- hci_conn_check_pending(hdev);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
-
- if (!test_bit(HCI_MGMT, &hdev->dev_flags))
- goto check_auth;
-
- if (ev->status == 0)
- hci_check_pending_name(hdev, conn, &ev->bdaddr, ev->name,
- strnlen(ev->name, HCI_MAX_NAME_LENGTH));
- else
- hci_check_pending_name(hdev, conn, &ev->bdaddr, NULL, 0);
-
-check_auth:
- if (!conn)
- goto unlock;
-
- if (!hci_outgoing_auth_needed(hdev, conn))
- goto unlock;
-
- if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
- struct hci_cp_auth_requested cp;
- cp.handle = __cpu_to_le16(conn->handle);
- hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_encrypt_change *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (conn) {
- if (!ev->status) {
- if (ev->encrypt) {
- /* Encryption implies authentication */
- conn->link_mode |= HCI_LM_AUTH;
- conn->link_mode |= HCI_LM_ENCRYPT;
- conn->sec_level = conn->pending_sec_level;
- } else
- conn->link_mode &= ~HCI_LM_ENCRYPT;
- }
-
- clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
-
- if (ev->status && conn->state == BT_CONNECTED) {
- hci_acl_disconn(conn, 0x13);
- hci_conn_put(conn);
- goto unlock;
- }
-
- if (conn->state == BT_CONFIG) {
- if (!ev->status)
- conn->state = BT_CONNECTED;
-
- hci_proto_connect_cfm(conn, ev->status);
- hci_conn_put(conn);
- } else
- hci_encrypt_cfm(conn, ev->status, ev->encrypt);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_change_link_key_complete *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (conn) {
- if (!ev->status)
- conn->link_mode |= HCI_LM_SECURE;
-
- clear_bit(HCI_CONN_AUTH_PEND, &conn->flags);
-
- hci_key_change_cfm(conn, ev->status);
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_remote_features *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (!conn)
- goto unlock;
-
- if (!ev->status)
- memcpy(conn->features, ev->features, 8);
-
- if (conn->state != BT_CONFIG)
- goto unlock;
-
- if (!ev->status && lmp_ssp_capable(hdev) && lmp_ssp_capable(conn)) {
- struct hci_cp_read_remote_ext_features cp;
- cp.handle = ev->handle;
- cp.page = 0x01;
- hci_send_cmd(hdev, HCI_OP_READ_REMOTE_EXT_FEATURES,
- sizeof(cp), &cp);
- goto unlock;
- }
-
- if (!ev->status && !test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) {
- struct hci_cp_remote_name_req cp;
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, &conn->dst);
- cp.pscan_rep_mode = 0x02;
- hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
- } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
- mgmt_device_connected(hdev, &conn->dst, conn->type,
- conn->dst_type, 0, NULL, 0,
- conn->dev_class);
-
- if (!hci_outgoing_auth_needed(hdev, conn)) {
- conn->state = BT_CONNECTED;
- hci_proto_connect_cfm(conn, ev->status);
- hci_conn_put(conn);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- BT_DBG("%s", hdev->name);
-}
-
-static inline void hci_qos_setup_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- BT_DBG("%s", hdev->name);
-}
-
-static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_cmd_complete *ev = (void *) skb->data;
- __u16 opcode;
-
- skb_pull(skb, sizeof(*ev));
-
- opcode = __le16_to_cpu(ev->opcode);
-
- switch (opcode) {
- case HCI_OP_INQUIRY_CANCEL:
- hci_cc_inquiry_cancel(hdev, skb);
- break;
-
- case HCI_OP_EXIT_PERIODIC_INQ:
- hci_cc_exit_periodic_inq(hdev, skb);
- break;
-
- case HCI_OP_REMOTE_NAME_REQ_CANCEL:
- hci_cc_remote_name_req_cancel(hdev, skb);
- break;
-
- case HCI_OP_ROLE_DISCOVERY:
- hci_cc_role_discovery(hdev, skb);
- break;
-
- case HCI_OP_READ_LINK_POLICY:
- hci_cc_read_link_policy(hdev, skb);
- break;
-
- case HCI_OP_WRITE_LINK_POLICY:
- hci_cc_write_link_policy(hdev, skb);
- break;
-
- case HCI_OP_READ_DEF_LINK_POLICY:
- hci_cc_read_def_link_policy(hdev, skb);
- break;
-
- case HCI_OP_WRITE_DEF_LINK_POLICY:
- hci_cc_write_def_link_policy(hdev, skb);
- break;
-
- case HCI_OP_RESET:
- hci_cc_reset(hdev, skb);
- break;
-
- case HCI_OP_WRITE_LOCAL_NAME:
- hci_cc_write_local_name(hdev, skb);
- break;
-
- case HCI_OP_READ_LOCAL_NAME:
- hci_cc_read_local_name(hdev, skb);
- break;
-
- case HCI_OP_WRITE_AUTH_ENABLE:
- hci_cc_write_auth_enable(hdev, skb);
- break;
-
- case HCI_OP_WRITE_ENCRYPT_MODE:
- hci_cc_write_encrypt_mode(hdev, skb);
- break;
-
- case HCI_OP_WRITE_SCAN_ENABLE:
- hci_cc_write_scan_enable(hdev, skb);
- break;
-
- case HCI_OP_READ_CLASS_OF_DEV:
- hci_cc_read_class_of_dev(hdev, skb);
- break;
-
- case HCI_OP_WRITE_CLASS_OF_DEV:
- hci_cc_write_class_of_dev(hdev, skb);
- break;
-
- case HCI_OP_READ_VOICE_SETTING:
- hci_cc_read_voice_setting(hdev, skb);
- break;
-
- case HCI_OP_WRITE_VOICE_SETTING:
- hci_cc_write_voice_setting(hdev, skb);
- break;
-
- case HCI_OP_HOST_BUFFER_SIZE:
- hci_cc_host_buffer_size(hdev, skb);
- break;
-
- case HCI_OP_WRITE_SSP_MODE:
- hci_cc_write_ssp_mode(hdev, skb);
- break;
-
- case HCI_OP_READ_LOCAL_VERSION:
- hci_cc_read_local_version(hdev, skb);
- break;
-
- case HCI_OP_READ_LOCAL_COMMANDS:
- hci_cc_read_local_commands(hdev, skb);
- break;
-
- case HCI_OP_READ_LOCAL_FEATURES:
- hci_cc_read_local_features(hdev, skb);
- break;
-
- case HCI_OP_READ_LOCAL_EXT_FEATURES:
- hci_cc_read_local_ext_features(hdev, skb);
- break;
-
- case HCI_OP_READ_BUFFER_SIZE:
- hci_cc_read_buffer_size(hdev, skb);
- break;
-
- case HCI_OP_READ_BD_ADDR:
- hci_cc_read_bd_addr(hdev, skb);
- break;
-
- case HCI_OP_READ_DATA_BLOCK_SIZE:
- hci_cc_read_data_block_size(hdev, skb);
- break;
-
- case HCI_OP_WRITE_CA_TIMEOUT:
- hci_cc_write_ca_timeout(hdev, skb);
- break;
-
- case HCI_OP_READ_FLOW_CONTROL_MODE:
- hci_cc_read_flow_control_mode(hdev, skb);
- break;
-
- case HCI_OP_READ_LOCAL_AMP_INFO:
- hci_cc_read_local_amp_info(hdev, skb);
- break;
-
- case HCI_OP_DELETE_STORED_LINK_KEY:
- hci_cc_delete_stored_link_key(hdev, skb);
- break;
-
- case HCI_OP_SET_EVENT_MASK:
- hci_cc_set_event_mask(hdev, skb);
- break;
-
- case HCI_OP_WRITE_INQUIRY_MODE:
- hci_cc_write_inquiry_mode(hdev, skb);
- break;
-
- case HCI_OP_READ_INQ_RSP_TX_POWER:
- hci_cc_read_inq_rsp_tx_power(hdev, skb);
- break;
-
- case HCI_OP_SET_EVENT_FLT:
- hci_cc_set_event_flt(hdev, skb);
- break;
-
- case HCI_OP_PIN_CODE_REPLY:
- hci_cc_pin_code_reply(hdev, skb);
- break;
-
- case HCI_OP_PIN_CODE_NEG_REPLY:
- hci_cc_pin_code_neg_reply(hdev, skb);
- break;
-
- case HCI_OP_READ_LOCAL_OOB_DATA:
- hci_cc_read_local_oob_data_reply(hdev, skb);
- break;
-
- case HCI_OP_LE_READ_BUFFER_SIZE:
- hci_cc_le_read_buffer_size(hdev, skb);
- break;
-
- case HCI_OP_USER_CONFIRM_REPLY:
- hci_cc_user_confirm_reply(hdev, skb);
- break;
-
- case HCI_OP_USER_CONFIRM_NEG_REPLY:
- hci_cc_user_confirm_neg_reply(hdev, skb);
- break;
-
- case HCI_OP_USER_PASSKEY_REPLY:
- hci_cc_user_passkey_reply(hdev, skb);
- break;
-
- case HCI_OP_USER_PASSKEY_NEG_REPLY:
- hci_cc_user_passkey_neg_reply(hdev, skb);
- break;
-
- case HCI_OP_LE_SET_SCAN_PARAM:
- hci_cc_le_set_scan_param(hdev, skb);
- break;
-
- case HCI_OP_LE_SET_SCAN_ENABLE:
- hci_cc_le_set_scan_enable(hdev, skb);
- break;
-
- case HCI_OP_LE_LTK_REPLY:
- hci_cc_le_ltk_reply(hdev, skb);
- break;
-
- case HCI_OP_LE_LTK_NEG_REPLY:
- hci_cc_le_ltk_neg_reply(hdev, skb);
- break;
-
- case HCI_OP_WRITE_LE_HOST_SUPPORTED:
- hci_cc_write_le_host_supported(hdev, skb);
- break;
-
- default:
- BT_DBG("%s opcode 0x%x", hdev->name, opcode);
- break;
- }
-
- if (ev->opcode != HCI_OP_NOP)
- del_timer(&hdev->cmd_timer);
-
- if (ev->ncmd) {
- atomic_set(&hdev->cmd_cnt, 1);
- if (!skb_queue_empty(&hdev->cmd_q))
- queue_work(hdev->workqueue, &hdev->cmd_work);
- }
-}
-
-static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_cmd_status *ev = (void *) skb->data;
- __u16 opcode;
-
- skb_pull(skb, sizeof(*ev));
-
- opcode = __le16_to_cpu(ev->opcode);
-
- switch (opcode) {
- case HCI_OP_INQUIRY:
- hci_cs_inquiry(hdev, ev->status);
- break;
-
- case HCI_OP_CREATE_CONN:
- hci_cs_create_conn(hdev, ev->status);
- break;
-
- case HCI_OP_ADD_SCO:
- hci_cs_add_sco(hdev, ev->status);
- break;
-
- case HCI_OP_AUTH_REQUESTED:
- hci_cs_auth_requested(hdev, ev->status);
- break;
-
- case HCI_OP_SET_CONN_ENCRYPT:
- hci_cs_set_conn_encrypt(hdev, ev->status);
- break;
-
- case HCI_OP_REMOTE_NAME_REQ:
- hci_cs_remote_name_req(hdev, ev->status);
- break;
-
- case HCI_OP_READ_REMOTE_FEATURES:
- hci_cs_read_remote_features(hdev, ev->status);
- break;
-
- case HCI_OP_READ_REMOTE_EXT_FEATURES:
- hci_cs_read_remote_ext_features(hdev, ev->status);
- break;
-
- case HCI_OP_SETUP_SYNC_CONN:
- hci_cs_setup_sync_conn(hdev, ev->status);
- break;
-
- case HCI_OP_SNIFF_MODE:
- hci_cs_sniff_mode(hdev, ev->status);
- break;
-
- case HCI_OP_EXIT_SNIFF_MODE:
- hci_cs_exit_sniff_mode(hdev, ev->status);
- break;
-
- case HCI_OP_DISCONNECT:
- hci_cs_disconnect(hdev, ev->status);
- break;
-
- case HCI_OP_LE_CREATE_CONN:
- hci_cs_le_create_conn(hdev, ev->status);
- break;
-
- case HCI_OP_LE_START_ENC:
- hci_cs_le_start_enc(hdev, ev->status);
- break;
-
- default:
- BT_DBG("%s opcode 0x%x", hdev->name, opcode);
- break;
- }
-
- if (ev->opcode != HCI_OP_NOP)
- del_timer(&hdev->cmd_timer);
-
- if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
- atomic_set(&hdev->cmd_cnt, 1);
- if (!skb_queue_empty(&hdev->cmd_q))
- queue_work(hdev->workqueue, &hdev->cmd_work);
- }
-}
-
-static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_role_change *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (conn) {
- if (!ev->status) {
- if (ev->role)
- conn->link_mode &= ~HCI_LM_MASTER;
- else
- conn->link_mode |= HCI_LM_MASTER;
- }
-
- clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags);
-
- hci_role_switch_cfm(conn, ev->status, ev->role);
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
- int i;
-
- if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_PACKET_BASED) {
- BT_ERR("Wrong event for mode %d", hdev->flow_ctl_mode);
- return;
- }
-
- if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) +
- ev->num_hndl * sizeof(struct hci_comp_pkts_info)) {
- BT_DBG("%s bad parameters", hdev->name);
- return;
- }
-
- BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
-
- for (i = 0; i < ev->num_hndl; i++) {
- struct hci_comp_pkts_info *info = &ev->handles[i];
- struct hci_conn *conn;
- __u16 handle, count;
-
- handle = __le16_to_cpu(info->handle);
- count = __le16_to_cpu(info->count);
-
- conn = hci_conn_hash_lookup_handle(hdev, handle);
- if (!conn)
- continue;
-
- conn->sent -= count;
-
- switch (conn->type) {
- case ACL_LINK:
- hdev->acl_cnt += count;
- if (hdev->acl_cnt > hdev->acl_pkts)
- hdev->acl_cnt = hdev->acl_pkts;
- break;
-
- case LE_LINK:
- if (hdev->le_pkts) {
- hdev->le_cnt += count;
- if (hdev->le_cnt > hdev->le_pkts)
- hdev->le_cnt = hdev->le_pkts;
- } else {
- hdev->acl_cnt += count;
- if (hdev->acl_cnt > hdev->acl_pkts)
- hdev->acl_cnt = hdev->acl_pkts;
- }
- break;
-
- case SCO_LINK:
- hdev->sco_cnt += count;
- if (hdev->sco_cnt > hdev->sco_pkts)
- hdev->sco_cnt = hdev->sco_pkts;
- break;
-
- default:
- BT_ERR("Unknown type %d conn %p", conn->type, conn);
- break;
- }
- }
-
- queue_work(hdev->workqueue, &hdev->tx_work);
-}
-
-static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_ev_num_comp_blocks *ev = (void *) skb->data;
- int i;
-
- if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_BLOCK_BASED) {
- BT_ERR("Wrong event for mode %d", hdev->flow_ctl_mode);
- return;
- }
-
- if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) +
- ev->num_hndl * sizeof(struct hci_comp_blocks_info)) {
- BT_DBG("%s bad parameters", hdev->name);
- return;
- }
-
- BT_DBG("%s num_blocks %d num_hndl %d", hdev->name, ev->num_blocks,
- ev->num_hndl);
-
- for (i = 0; i < ev->num_hndl; i++) {
- struct hci_comp_blocks_info *info = &ev->handles[i];
- struct hci_conn *conn;
- __u16 handle, block_count;
-
- handle = __le16_to_cpu(info->handle);
- block_count = __le16_to_cpu(info->blocks);
-
- conn = hci_conn_hash_lookup_handle(hdev, handle);
- if (!conn)
- continue;
-
- conn->sent -= block_count;
-
- switch (conn->type) {
- case ACL_LINK:
- hdev->block_cnt += block_count;
- if (hdev->block_cnt > hdev->num_blocks)
- hdev->block_cnt = hdev->num_blocks;
- break;
-
- default:
- BT_ERR("Unknown type %d conn %p", conn->type, conn);
- break;
- }
- }
-
- queue_work(hdev->workqueue, &hdev->tx_work);
-}
-
-static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_mode_change *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (conn) {
- conn->mode = ev->mode;
- conn->interval = __le16_to_cpu(ev->interval);
-
- if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
- if (conn->mode == HCI_CM_ACTIVE)
- set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
- else
- clear_bit(HCI_CONN_POWER_SAVE, &conn->flags);
- }
-
- if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
- hci_sco_setup(conn, ev->status);
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_pin_code_req *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (!conn)
- goto unlock;
-
- if (conn->state == BT_CONNECTED) {
- hci_conn_hold(conn);
- conn->disc_timeout = HCI_PAIRING_TIMEOUT;
- hci_conn_put(conn);
- }
-
- if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags))
- hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
- sizeof(ev->bdaddr), &ev->bdaddr);
- else if (test_bit(HCI_MGMT, &hdev->dev_flags)) {
- u8 secure;
-
- if (conn->pending_sec_level == BT_SECURITY_HIGH)
- secure = 1;
- else
- secure = 0;
-
- mgmt_pin_code_request(hdev, &ev->bdaddr, secure);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_link_key_req *ev = (void *) skb->data;
- struct hci_cp_link_key_reply cp;
- struct hci_conn *conn;
- struct link_key *key;
-
- BT_DBG("%s", hdev->name);
-
- if (!test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
- return;
-
- hci_dev_lock(hdev);
-
- key = hci_find_link_key(hdev, &ev->bdaddr);
- if (!key) {
- BT_DBG("%s link key not found for %s", hdev->name,
- batostr(&ev->bdaddr));
- goto not_found;
- }
-
- BT_DBG("%s found key type %u for %s", hdev->name, key->type,
- batostr(&ev->bdaddr));
-
- if (!test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) &&
- key->type == HCI_LK_DEBUG_COMBINATION) {
- BT_DBG("%s ignoring debug key", hdev->name);
- goto not_found;
- }
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (conn) {
- if (key->type == HCI_LK_UNAUTH_COMBINATION &&
- conn->auth_type != 0xff &&
- (conn->auth_type & 0x01)) {
- BT_DBG("%s ignoring unauthenticated key", hdev->name);
- goto not_found;
- }
-
- if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 &&
- conn->pending_sec_level == BT_SECURITY_HIGH) {
- BT_DBG("%s ignoring key unauthenticated for high \
- security", hdev->name);
- goto not_found;
- }
-
- conn->key_type = key->type;
- conn->pin_length = key->pin_len;
- }
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
- memcpy(cp.link_key, key->val, 16);
-
- hci_send_cmd(hdev, HCI_OP_LINK_KEY_REPLY, sizeof(cp), &cp);
-
- hci_dev_unlock(hdev);
-
- return;
-
-not_found:
- hci_send_cmd(hdev, HCI_OP_LINK_KEY_NEG_REPLY, 6, &ev->bdaddr);
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_link_key_notify *ev = (void *) skb->data;
- struct hci_conn *conn;
- u8 pin_len = 0;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (conn) {
- hci_conn_hold(conn);
- conn->disc_timeout = HCI_DISCONN_TIMEOUT;
- pin_len = conn->pin_length;
-
- if (ev->key_type != HCI_LK_CHANGED_COMBINATION)
- conn->key_type = ev->key_type;
-
- hci_conn_put(conn);
- }
-
- if (test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
- hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key,
- ev->key_type, pin_len);
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_clock_offset *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (conn && !ev->status) {
- struct inquiry_entry *ie;
-
- ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
- if (ie) {
- ie->data.clock_offset = ev->clock_offset;
- ie->timestamp = jiffies;
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_pkt_type_change *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (conn && !ev->status)
- conn->pkt_type = __le16_to_cpu(ev->pkt_type);
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_pscan_rep_mode *ev = (void *) skb->data;
- struct inquiry_entry *ie;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
- if (ie) {
- ie->data.pscan_rep_mode = ev->pscan_rep_mode;
- ie->timestamp = jiffies;
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct inquiry_data data;
- int num_rsp = *((__u8 *) skb->data);
- bool name_known, ssp;
-
- BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
-
- if (!num_rsp)
- return;
-
- hci_dev_lock(hdev);
-
- if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
- struct inquiry_info_with_rssi_and_pscan_mode *info;
- info = (void *) (skb->data + 1);
-
- for (; num_rsp; num_rsp--, info++) {
- bacpy(&data.bdaddr, &info->bdaddr);
- data.pscan_rep_mode = info->pscan_rep_mode;
- data.pscan_period_mode = info->pscan_period_mode;
- data.pscan_mode = info->pscan_mode;
- memcpy(data.dev_class, info->dev_class, 3);
- data.clock_offset = info->clock_offset;
- data.rssi = info->rssi;
- data.ssp_mode = 0x00;
-
- name_known = hci_inquiry_cache_update(hdev, &data,
- false, &ssp);
- mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
- info->dev_class, info->rssi,
- !name_known, ssp, NULL, 0);
- }
- } else {
- struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
-
- for (; num_rsp; num_rsp--, info++) {
- bacpy(&data.bdaddr, &info->bdaddr);
- data.pscan_rep_mode = info->pscan_rep_mode;
- data.pscan_period_mode = info->pscan_period_mode;
- data.pscan_mode = 0x00;
- memcpy(data.dev_class, info->dev_class, 3);
- data.clock_offset = info->clock_offset;
- data.rssi = info->rssi;
- data.ssp_mode = 0x00;
- name_known = hci_inquiry_cache_update(hdev, &data,
- false, &ssp);
- mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
- info->dev_class, info->rssi,
- !name_known, ssp, NULL, 0);
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_remote_ext_features *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (!conn)
- goto unlock;
-
- if (!ev->status && ev->page == 0x01) {
- struct inquiry_entry *ie;
-
- ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
- if (ie)
- ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP);
-
- if (ev->features[0] & LMP_HOST_SSP)
- set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
- }
-
- if (conn->state != BT_CONFIG)
- goto unlock;
-
- if (!ev->status && !test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) {
- struct hci_cp_remote_name_req cp;
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, &conn->dst);
- cp.pscan_rep_mode = 0x02;
- hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
- } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
- mgmt_device_connected(hdev, &conn->dst, conn->type,
- conn->dst_type, 0, NULL, 0,
- conn->dev_class);
-
- if (!hci_outgoing_auth_needed(hdev, conn)) {
- conn->state = BT_CONNECTED;
- hci_proto_connect_cfm(conn, ev->status);
- hci_conn_put(conn);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_sync_conn_complete *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
- if (!conn) {
- if (ev->link_type == ESCO_LINK)
- goto unlock;
-
- conn = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, &ev->bdaddr);
- if (!conn)
- goto unlock;
-
- conn->type = SCO_LINK;
- }
-
- switch (ev->status) {
- case 0x00:
- conn->handle = __le16_to_cpu(ev->handle);
- conn->state = BT_CONNECTED;
-
- hci_conn_hold_device(conn);
- hci_conn_add_sysfs(conn);
- break;
-
- case 0x11: /* Unsupported Feature or Parameter Value */
- case 0x1c: /* SCO interval rejected */
- case 0x1a: /* Unsupported Remote Feature */
- case 0x1f: /* Unspecified error */
- if (conn->out && conn->attempt < 2) {
- conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
- (hdev->esco_type & EDR_ESCO_MASK);
- hci_setup_sync(conn, conn->link->handle);
- goto unlock;
- }
- /* fall through */
-
- default:
- conn->state = BT_CLOSED;
- break;
- }
-
- hci_proto_connect_cfm(conn, ev->status);
- if (ev->status)
- hci_conn_del(conn);
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- BT_DBG("%s", hdev->name);
-}
-
-static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_sniff_subrate *ev = (void *) skb->data;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-}
-
-static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct inquiry_data data;
- struct extended_inquiry_info *info = (void *) (skb->data + 1);
- int num_rsp = *((__u8 *) skb->data);
- size_t eir_len;
-
- BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
-
- if (!num_rsp)
- return;
-
- hci_dev_lock(hdev);
-
- for (; num_rsp; num_rsp--, info++) {
- bool name_known, ssp;
-
- bacpy(&data.bdaddr, &info->bdaddr);
- data.pscan_rep_mode = info->pscan_rep_mode;
- data.pscan_period_mode = info->pscan_period_mode;
- data.pscan_mode = 0x00;
- memcpy(data.dev_class, info->dev_class, 3);
- data.clock_offset = info->clock_offset;
- data.rssi = info->rssi;
- data.ssp_mode = 0x01;
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- name_known = eir_has_data_type(info->data,
- sizeof(info->data),
- EIR_NAME_COMPLETE);
- else
- name_known = true;
-
- name_known = hci_inquiry_cache_update(hdev, &data, name_known,
- &ssp);
- eir_len = eir_get_length(info->data, sizeof(info->data));
- mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
- info->dev_class, info->rssi, !name_known,
- ssp, info->data, eir_len);
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline u8 hci_get_auth_req(struct hci_conn *conn)
-{
- /* If remote requests dedicated bonding follow that lead */
- if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) {
- /* If both remote and local IO capabilities allow MITM
- * protection then require it, otherwise don't */
- if (conn->remote_cap == 0x03 || conn->io_capability == 0x03)
- return 0x02;
- else
- return 0x03;
- }
-
- /* If remote requests no-bonding follow that lead */
- if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01)
- return conn->remote_auth | (conn->auth_type & 0x01);
-
- return conn->auth_type;
-}
-
-static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_io_capa_request *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (!conn)
- goto unlock;
-
- hci_conn_hold(conn);
-
- if (!test_bit(HCI_MGMT, &hdev->dev_flags))
- goto unlock;
-
- if (test_bit(HCI_PAIRABLE, &hdev->dev_flags) ||
- (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) {
- struct hci_cp_io_capability_reply cp;
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
- /* Change the IO capability from KeyboardDisplay
- * to DisplayYesNo as it is not supported by BT spec. */
- cp.capability = (conn->io_capability == 0x04) ?
- 0x01 : conn->io_capability;
- conn->auth_type = hci_get_auth_req(conn);
- cp.authentication = conn->auth_type;
-
- if ((conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)) &&
- hci_find_remote_oob_data(hdev, &conn->dst))
- cp.oob_data = 0x01;
- else
- cp.oob_data = 0x00;
-
- hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY,
- sizeof(cp), &cp);
- } else {
- struct hci_cp_io_capability_neg_reply cp;
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
- cp.reason = HCI_ERROR_PAIRING_NOT_ALLOWED;
-
- hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY,
- sizeof(cp), &cp);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_io_capa_reply *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (!conn)
- goto unlock;
-
- conn->remote_cap = ev->capability;
- conn->remote_auth = ev->authentication;
- if (ev->oob_data)
- set_bit(HCI_CONN_REMOTE_OOB, &conn->flags);
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_ev_user_confirm_req *ev = (void *) skb->data;
- int loc_mitm, rem_mitm, confirm_hint = 0;
- struct hci_conn *conn;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (!test_bit(HCI_MGMT, &hdev->dev_flags))
- goto unlock;
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (!conn)
- goto unlock;
-
- loc_mitm = (conn->auth_type & 0x01);
- rem_mitm = (conn->remote_auth & 0x01);
-
- /* If we require MITM but the remote device can't provide that
- * (it has NoInputNoOutput) then reject the confirmation
- * request. The only exception is when we're dedicated bonding
- * initiators (connect_cfm_cb set) since then we always have the MITM
- * bit set. */
- if (!conn->connect_cfm_cb && loc_mitm && conn->remote_cap == 0x03) {
- BT_DBG("Rejecting request: remote device can't provide MITM");
- hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY,
- sizeof(ev->bdaddr), &ev->bdaddr);
- goto unlock;
- }
-
- /* If no side requires MITM protection; auto-accept */
- if ((!loc_mitm || conn->remote_cap == 0x03) &&
- (!rem_mitm || conn->io_capability == 0x03)) {
-
- /* If we're not the initiators request authorization to
- * proceed from user space (mgmt_user_confirm with
- * confirm_hint set to 1). */
- if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
- BT_DBG("Confirming auto-accept as acceptor");
- confirm_hint = 1;
- goto confirm;
- }
-
- BT_DBG("Auto-accept of user confirmation with %ums delay",
- hdev->auto_accept_delay);
-
- if (hdev->auto_accept_delay > 0) {
- int delay = msecs_to_jiffies(hdev->auto_accept_delay);
- mod_timer(&conn->auto_accept_timer, jiffies + delay);
- goto unlock;
- }
-
- hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY,
- sizeof(ev->bdaddr), &ev->bdaddr);
- goto unlock;
- }
-
-confirm:
- mgmt_user_confirm_request(hdev, &ev->bdaddr, ACL_LINK, 0, ev->passkey,
- confirm_hint);
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_user_passkey_request_evt(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_ev_user_passkey_req *ev = (void *) skb->data;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0);
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_simple_pair_complete *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (!conn)
- goto unlock;
-
- /* To avoid duplicate auth_failed events to user space we check
- * the HCI_CONN_AUTH_PEND flag which will be set if we
- * initiated the authentication. A traditional auth_complete
- * event gets always produced as initiator and is also mapped to
- * the mgmt_auth_failed event */
- if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status != 0)
- mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
- ev->status);
-
- hci_conn_put(conn);
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_remote_host_features *ev = (void *) skb->data;
- struct inquiry_entry *ie;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
- if (ie)
- ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP);
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
- struct oob_data *data;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (!test_bit(HCI_MGMT, &hdev->dev_flags))
- goto unlock;
-
- data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
- if (data) {
- struct hci_cp_remote_oob_data_reply cp;
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
- memcpy(cp.hash, data->hash, sizeof(cp.hash));
- memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer));
-
- hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp),
- &cp);
- } else {
- struct hci_cp_remote_oob_data_neg_reply cp;
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
- hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp),
- &cp);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_le_conn_complete *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
- if (!conn) {
- conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
- if (!conn) {
- BT_ERR("No memory for new connection");
- hci_dev_unlock(hdev);
- return;
- }
-
- conn->dst_type = ev->bdaddr_type;
- }
-
- if (ev->status) {
- mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
- conn->dst_type, ev->status);
- hci_proto_connect_cfm(conn, ev->status);
- conn->state = BT_CLOSED;
- hci_conn_del(conn);
- goto unlock;
- }
-
- if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
- mgmt_device_connected(hdev, &ev->bdaddr, conn->type,
- conn->dst_type, 0, NULL, 0, NULL);
-
- conn->sec_level = BT_SECURITY_LOW;
- conn->handle = __le16_to_cpu(ev->handle);
- conn->state = BT_CONNECTED;
-
- hci_conn_hold_device(conn);
- hci_conn_add_sysfs(conn);
-
- hci_proto_connect_cfm(conn, ev->status);
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- u8 num_reports = skb->data[0];
- void *ptr = &skb->data[1];
- s8 rssi;
-
- hci_dev_lock(hdev);
-
- while (num_reports--) {
- struct hci_ev_le_advertising_info *ev = ptr;
-
- hci_add_adv_entry(hdev, ev);
-
- rssi = ev->data[ev->length];
- mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type,
- NULL, rssi, 0, 1, ev->data, ev->length);
-
- ptr += sizeof(*ev) + ev->length + 1;
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_ev_le_ltk_req *ev = (void *) skb->data;
- struct hci_cp_le_ltk_reply cp;
- struct hci_cp_le_ltk_neg_reply neg;
- struct hci_conn *conn;
- struct smp_ltk *ltk;
-
- BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle));
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (conn == NULL)
- goto not_found;
-
- ltk = hci_find_ltk(hdev, ev->ediv, ev->random);
- if (ltk == NULL)
- goto not_found;
-
- memcpy(cp.ltk, ltk->val, sizeof(ltk->val));
- cp.handle = cpu_to_le16(conn->handle);
-
- if (ltk->authenticated)
- conn->sec_level = BT_SECURITY_HIGH;
-
- hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
-
- if (ltk->type & HCI_SMP_STK) {
- list_del(&ltk->list);
- kfree(ltk);
- }
-
- hci_dev_unlock(hdev);
-
- return;
-
-not_found:
- neg.handle = ev->handle;
- hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(neg), &neg);
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_le_meta *le_ev = (void *) skb->data;
-
- skb_pull(skb, sizeof(*le_ev));
-
- switch (le_ev->subevent) {
- case HCI_EV_LE_CONN_COMPLETE:
- hci_le_conn_complete_evt(hdev, skb);
- break;
-
- case HCI_EV_LE_ADVERTISING_REPORT:
- hci_le_adv_report_evt(hdev, skb);
- break;
-
- case HCI_EV_LE_LTK_REQ:
- hci_le_ltk_request_evt(hdev, skb);
- break;
-
- default:
- break;
- }
-}
-
-void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_event_hdr *hdr = (void *) skb->data;
- __u8 event = hdr->evt;
-
- skb_pull(skb, HCI_EVENT_HDR_SIZE);
-
- switch (event) {
- case HCI_EV_INQUIRY_COMPLETE:
- hci_inquiry_complete_evt(hdev, skb);
- break;
-
- case HCI_EV_INQUIRY_RESULT:
- hci_inquiry_result_evt(hdev, skb);
- break;
-
- case HCI_EV_CONN_COMPLETE:
- hci_conn_complete_evt(hdev, skb);
- break;
-
- case HCI_EV_CONN_REQUEST:
- hci_conn_request_evt(hdev, skb);
- break;
-
- case HCI_EV_DISCONN_COMPLETE:
- hci_disconn_complete_evt(hdev, skb);
- break;
-
- case HCI_EV_AUTH_COMPLETE:
- hci_auth_complete_evt(hdev, skb);
- break;
-
- case HCI_EV_REMOTE_NAME:
- hci_remote_name_evt(hdev, skb);
- break;
-
- case HCI_EV_ENCRYPT_CHANGE:
- hci_encrypt_change_evt(hdev, skb);
- break;
-
- case HCI_EV_CHANGE_LINK_KEY_COMPLETE:
- hci_change_link_key_complete_evt(hdev, skb);
- break;
-
- case HCI_EV_REMOTE_FEATURES:
- hci_remote_features_evt(hdev, skb);
- break;
-
- case HCI_EV_REMOTE_VERSION:
- hci_remote_version_evt(hdev, skb);
- break;
-
- case HCI_EV_QOS_SETUP_COMPLETE:
- hci_qos_setup_complete_evt(hdev, skb);
- break;
-
- case HCI_EV_CMD_COMPLETE:
- hci_cmd_complete_evt(hdev, skb);
- break;
-
- case HCI_EV_CMD_STATUS:
- hci_cmd_status_evt(hdev, skb);
- break;
-
- case HCI_EV_ROLE_CHANGE:
- hci_role_change_evt(hdev, skb);
- break;
-
- case HCI_EV_NUM_COMP_PKTS:
- hci_num_comp_pkts_evt(hdev, skb);
- break;
-
- case HCI_EV_MODE_CHANGE:
- hci_mode_change_evt(hdev, skb);
- break;
-
- case HCI_EV_PIN_CODE_REQ:
- hci_pin_code_request_evt(hdev, skb);
- break;
-
- case HCI_EV_LINK_KEY_REQ:
- hci_link_key_request_evt(hdev, skb);
- break;
-
- case HCI_EV_LINK_KEY_NOTIFY:
- hci_link_key_notify_evt(hdev, skb);
- break;
-
- case HCI_EV_CLOCK_OFFSET:
- hci_clock_offset_evt(hdev, skb);
- break;
-
- case HCI_EV_PKT_TYPE_CHANGE:
- hci_pkt_type_change_evt(hdev, skb);
- break;
-
- case HCI_EV_PSCAN_REP_MODE:
- hci_pscan_rep_mode_evt(hdev, skb);
- break;
-
- case HCI_EV_INQUIRY_RESULT_WITH_RSSI:
- hci_inquiry_result_with_rssi_evt(hdev, skb);
- break;
-
- case HCI_EV_REMOTE_EXT_FEATURES:
- hci_remote_ext_features_evt(hdev, skb);
- break;
-
- case HCI_EV_SYNC_CONN_COMPLETE:
- hci_sync_conn_complete_evt(hdev, skb);
- break;
-
- case HCI_EV_SYNC_CONN_CHANGED:
- hci_sync_conn_changed_evt(hdev, skb);
- break;
-
- case HCI_EV_SNIFF_SUBRATE:
- hci_sniff_subrate_evt(hdev, skb);
- break;
-
- case HCI_EV_EXTENDED_INQUIRY_RESULT:
- hci_extended_inquiry_result_evt(hdev, skb);
- break;
-
- case HCI_EV_IO_CAPA_REQUEST:
- hci_io_capa_request_evt(hdev, skb);
- break;
-
- case HCI_EV_IO_CAPA_REPLY:
- hci_io_capa_reply_evt(hdev, skb);
- break;
-
- case HCI_EV_USER_CONFIRM_REQUEST:
- hci_user_confirm_request_evt(hdev, skb);
- break;
-
- case HCI_EV_USER_PASSKEY_REQUEST:
- hci_user_passkey_request_evt(hdev, skb);
- break;
-
- case HCI_EV_SIMPLE_PAIR_COMPLETE:
- hci_simple_pair_complete_evt(hdev, skb);
- break;
-
- case HCI_EV_REMOTE_HOST_FEATURES:
- hci_remote_host_features_evt(hdev, skb);
- break;
-
- case HCI_EV_LE_META:
- hci_le_meta_evt(hdev, skb);
- break;
-
- case HCI_EV_REMOTE_OOB_DATA_REQUEST:
- hci_remote_oob_data_request_evt(hdev, skb);
- break;
-
- case HCI_EV_NUM_COMP_BLOCKS:
- hci_num_comp_blocks_evt(hdev, skb);
- break;
-
- default:
- BT_DBG("%s event 0x%x", hdev->name, event);
- break;
- }
-
- kfree_skb(skb);
- hdev->stat.evt_rx++;
-}
-
-/* Generate internal stack event */
-void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
-{
- struct hci_event_hdr *hdr;
- struct hci_ev_stack_internal *ev;
- struct sk_buff *skb;
-
- skb = bt_skb_alloc(HCI_EVENT_HDR_SIZE + sizeof(*ev) + dlen, GFP_ATOMIC);
- if (!skb)
- return;
-
- hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE);
- hdr->evt = HCI_EV_STACK_INTERNAL;
- hdr->plen = sizeof(*ev) + dlen;
-
- ev = (void *) skb_put(skb, sizeof(*ev) + dlen);
- ev->type = type;
- memcpy(ev->data, data, dlen);
-
- bt_cb(skb)->incoming = 1;
- __net_timestamp(skb);
-
- bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
- skb->dev = (void *) hdev;
- hci_send_to_sock(hdev, skb);
- kfree_skb(skb);
-}
diff --git a/net/bluetooth_tizen/hci_sock.c b/net/bluetooth_tizen/hci_sock.c
deleted file mode 100644
index 63c1516..0000000
--- a/net/bluetooth_tizen/hci_sock.c
+++ /dev/null
@@ -1,1102 +0,0 @@
-/*
- BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
-
- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/* Bluetooth HCI sockets. */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-#include <linux/compat.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <net/sock.h>
-
-#include <asm/system.h>
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/hci_mon.h>
-
-static atomic_t monitor_promisc = ATOMIC_INIT(0);
-
-/* ----- HCI socket interface ----- */
-
-static inline int hci_test_bit(int nr, void *addr)
-{
- return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31));
-}
-
-/* Security filter */
-static struct hci_sec_filter hci_sec_filter = {
- /* Packet types */
- 0x10,
- /* Events */
- { 0x1000d9fe, 0x0000b00c },
- /* Commands */
- {
- { 0x0 },
- /* OGF_LINK_CTL */
- { 0xbe000006, 0x00000001, 0x00000000, 0x00 },
- /* OGF_LINK_POLICY */
- { 0x00005200, 0x00000000, 0x00000000, 0x00 },
- /* OGF_HOST_CTL */
- { 0xaab00200, 0x2b402aaa, 0x05220154, 0x00 },
- /* OGF_INFO_PARAM */
- { 0x000002be, 0x00000000, 0x00000000, 0x00 },
- /* OGF_STATUS_PARAM */
- { 0x000000ea, 0x00000000, 0x00000000, 0x00 }
- }
-};
-
-static struct bt_sock_list hci_sk_list = {
- .lock = __RW_LOCK_UNLOCKED(hci_sk_list.lock)
-};
-
-/* Send frame to RAW socket */
-void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct sock *sk;
- struct hlist_node *node;
- struct sk_buff *skb_copy = NULL;
-
- BT_DBG("hdev %p len %d", hdev, skb->len);
-
- read_lock(&hci_sk_list.lock);
-
- sk_for_each(sk, node, &hci_sk_list.head) {
- struct hci_filter *flt;
- struct sk_buff *nskb;
-
- if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev)
- continue;
-
- /* Don't send frame to the socket it came from */
- if (skb->sk == sk)
- continue;
-
- if (hci_pi(sk)->channel != HCI_CHANNEL_RAW)
- continue;
-
- /* Apply filter */
- flt = &hci_pi(sk)->filter;
-
- if (!test_bit((bt_cb(skb)->pkt_type == HCI_VENDOR_PKT) ?
- 0 : (bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
- continue;
-
- if (bt_cb(skb)->pkt_type == HCI_EVENT_PKT) {
- register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
-
- if (!hci_test_bit(evt, &flt->event_mask))
- continue;
-
- if (flt->opcode &&
- ((evt == HCI_EV_CMD_COMPLETE &&
- flt->opcode !=
- get_unaligned((__le16 *)(skb->data + 3))) ||
- (evt == HCI_EV_CMD_STATUS &&
- flt->opcode !=
- get_unaligned((__le16 *)(skb->data + 4)))))
- continue;
- }
-
- if (!skb_copy) {
- /* Create a private copy with headroom */
- skb_copy = __pskb_copy(skb, 1, GFP_ATOMIC);
- if (!skb_copy)
- continue;
-
- /* Put type byte before the data */
- memcpy(skb_push(skb_copy, 1), &bt_cb(skb)->pkt_type, 1);
- }
-
- nskb = skb_clone(skb_copy, GFP_ATOMIC);
- if (!nskb)
- continue;
-
- if (sock_queue_rcv_skb(sk, nskb))
- kfree_skb(nskb);
- }
-
- read_unlock(&hci_sk_list.lock);
-
- kfree_skb(skb_copy);
-}
-
-/* Send frame to control socket */
-void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk)
-{
- struct sock *sk;
- struct hlist_node *node;
-
- BT_DBG("len %d", skb->len);
-
- read_lock(&hci_sk_list.lock);
-
- sk_for_each(sk, node, &hci_sk_list.head) {
- struct sk_buff *nskb;
-
- /* Skip the original socket */
- if (sk == skip_sk)
- continue;
-
- if (sk->sk_state != BT_BOUND)
- continue;
-
- if (hci_pi(sk)->channel != HCI_CHANNEL_CONTROL)
- continue;
-
- nskb = skb_clone(skb, GFP_ATOMIC);
- if (!nskb)
- continue;
-
- if (sock_queue_rcv_skb(sk, nskb))
- kfree_skb(nskb);
- }
-
- read_unlock(&hci_sk_list.lock);
-}
-
-/* Send frame to monitor socket */
-void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct sock *sk;
- struct hlist_node *node;
- struct sk_buff *skb_copy = NULL;
- __le16 opcode;
-
- if (!atomic_read(&monitor_promisc))
- return;
-
- BT_DBG("hdev %p len %d", hdev, skb->len);
-
- switch (bt_cb(skb)->pkt_type) {
- case HCI_COMMAND_PKT:
- opcode = __constant_cpu_to_le16(HCI_MON_COMMAND_PKT);
- break;
- case HCI_EVENT_PKT:
- opcode = __constant_cpu_to_le16(HCI_MON_EVENT_PKT);
- break;
- case HCI_ACLDATA_PKT:
- if (bt_cb(skb)->incoming)
- opcode = __constant_cpu_to_le16(HCI_MON_ACL_RX_PKT);
- else
- opcode = __constant_cpu_to_le16(HCI_MON_ACL_TX_PKT);
- break;
- case HCI_SCODATA_PKT:
- if (bt_cb(skb)->incoming)
- opcode = __constant_cpu_to_le16(HCI_MON_SCO_RX_PKT);
- else
- opcode = __constant_cpu_to_le16(HCI_MON_SCO_TX_PKT);
- break;
- default:
- return;
- }
-
- read_lock(&hci_sk_list.lock);
-
- sk_for_each(sk, node, &hci_sk_list.head) {
- struct sk_buff *nskb;
-
- if (sk->sk_state != BT_BOUND)
- continue;
-
- if (hci_pi(sk)->channel != HCI_CHANNEL_MONITOR)
- continue;
-
- if (!skb_copy) {
- struct hci_mon_hdr *hdr;
-
- /* Create a private copy with headroom */
- skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE, GFP_ATOMIC);
- if (!skb_copy)
- continue;
-
- /* Put header before the data */
- hdr = (void *) skb_push(skb_copy, HCI_MON_HDR_SIZE);
- hdr->opcode = opcode;
- hdr->index = cpu_to_le16(hdev->id);
- hdr->len = cpu_to_le16(skb->len);
- }
-
- nskb = skb_clone(skb_copy, GFP_ATOMIC);
- if (!nskb)
- continue;
-
- if (sock_queue_rcv_skb(sk, nskb))
- kfree_skb(nskb);
- }
-
- read_unlock(&hci_sk_list.lock);
-
- kfree_skb(skb_copy);
-}
-
-static void send_monitor_event(struct sk_buff *skb)
-{
- struct sock *sk;
- struct hlist_node *node;
-
- BT_DBG("len %d", skb->len);
-
- read_lock(&hci_sk_list.lock);
-
- sk_for_each(sk, node, &hci_sk_list.head) {
- struct sk_buff *nskb;
-
- if (sk->sk_state != BT_BOUND)
- continue;
-
- if (hci_pi(sk)->channel != HCI_CHANNEL_MONITOR)
- continue;
-
- nskb = skb_clone(skb, GFP_ATOMIC);
- if (!nskb)
- continue;
-
- if (sock_queue_rcv_skb(sk, nskb))
- kfree_skb(nskb);
- }
-
- read_unlock(&hci_sk_list.lock);
-}
-
-static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
-{
- struct hci_mon_hdr *hdr;
- struct hci_mon_new_index *ni;
- struct sk_buff *skb;
- __le16 opcode;
-
- switch (event) {
- case HCI_DEV_REG:
- skb = bt_skb_alloc(HCI_MON_NEW_INDEX_SIZE, GFP_ATOMIC);
- if (!skb)
- return NULL;
-
- ni = (void *) skb_put(skb, HCI_MON_NEW_INDEX_SIZE);
- ni->type = hdev->dev_type;
- ni->bus = hdev->bus;
- bacpy(&ni->bdaddr, &hdev->bdaddr);
- memcpy(ni->name, hdev->name, 8);
-
- opcode = __constant_cpu_to_le16(HCI_MON_NEW_INDEX);
- break;
-
- case HCI_DEV_UNREG:
- skb = bt_skb_alloc(0, GFP_ATOMIC);
- if (!skb)
- return NULL;
-
- opcode = __constant_cpu_to_le16(HCI_MON_DEL_INDEX);
- break;
-
- default:
- return NULL;
- }
-
- __net_timestamp(skb);
-
- hdr = (void *) skb_push(skb, HCI_MON_HDR_SIZE);
- hdr->opcode = opcode;
- hdr->index = cpu_to_le16(hdev->id);
- hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
-
- return skb;
-}
-
-static void send_monitor_replay(struct sock *sk)
-{
- struct hci_dev *hdev;
-
- read_lock(&hci_dev_list_lock);
-
- list_for_each_entry(hdev, &hci_dev_list, list) {
- struct sk_buff *skb;
-
- skb = create_monitor_event(hdev, HCI_DEV_REG);
- if (!skb)
- continue;
-
- if (sock_queue_rcv_skb(sk, skb))
- kfree_skb(skb);
- }
-
- read_unlock(&hci_dev_list_lock);
-}
-
-static int hci_sock_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
- struct hci_dev *hdev;
-
- BT_DBG("sock %p sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
- hdev = hci_pi(sk)->hdev;
-
- if (hci_pi(sk)->channel == HCI_CHANNEL_MONITOR)
- atomic_dec(&monitor_promisc);
-
- bt_sock_unlink(&hci_sk_list, sk);
-
- if (hdev) {
- atomic_dec(&hdev->promisc);
- hci_dev_put(hdev);
- }
-
- sock_orphan(sk);
-
- skb_queue_purge(&sk->sk_receive_queue);
- skb_queue_purge(&sk->sk_write_queue);
-
- sock_put(sk);
- return 0;
-}
-
-static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg)
-{
- bdaddr_t bdaddr;
- int err;
-
- if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
- return -EFAULT;
-
- hci_dev_lock(hdev);
-
- err = hci_blacklist_add(hdev, &bdaddr, 0);
-
- hci_dev_unlock(hdev);
-
- return err;
-}
-
-static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
-{
- bdaddr_t bdaddr;
- int err;
-
- if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
- return -EFAULT;
-
- hci_dev_lock(hdev);
-
- err = hci_blacklist_del(hdev, &bdaddr, 0);
-
- hci_dev_unlock(hdev);
-
- return err;
-}
-
-/* Ioctls that require bound socket */
-static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
-{
- struct hci_dev *hdev = hci_pi(sk)->hdev;
-
- if (!hdev)
- return -EBADFD;
-
- switch (cmd) {
- case HCISETRAW:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
-
- if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
- return -EPERM;
-
- if (arg)
- set_bit(HCI_RAW, &hdev->flags);
- else
- clear_bit(HCI_RAW, &hdev->flags);
-
- return 0;
-
- case HCIGETCONNINFO:
- return hci_get_conn_info(hdev, (void __user *) arg);
-
- case HCIGETAUTHINFO:
- return hci_get_auth_info(hdev, (void __user *) arg);
-
- case HCIBLOCKADDR:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
- return hci_sock_blacklist_add(hdev, (void __user *) arg);
-
- case HCIUNBLOCKADDR:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
- return hci_sock_blacklist_del(hdev, (void __user *) arg);
-
- default:
- if (hdev->ioctl)
- return hdev->ioctl(hdev, cmd, arg);
- return -EINVAL;
- }
-}
-
-static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct sock *sk = sock->sk;
- void __user *argp = (void __user *) arg;
- int err;
-
- BT_DBG("cmd %x arg %lx", cmd, arg);
-
- switch (cmd) {
- case HCIGETDEVLIST:
- return hci_get_dev_list(argp);
-
- case HCIGETDEVINFO:
- return hci_get_dev_info(argp);
-
- case HCIGETCONNLIST:
- return hci_get_conn_list(argp);
-
- case HCIDEVUP:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
- return hci_dev_open(arg);
-
- case HCIDEVDOWN:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
- return hci_dev_close(arg);
-
- case HCIDEVRESET:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
- return hci_dev_reset(arg);
-
- case HCIDEVRESTAT:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
- return hci_dev_reset_stat(arg);
-
- case HCISETSCAN:
- case HCISETAUTH:
- case HCISETENCRYPT:
- case HCISETPTYPE:
- case HCISETLINKPOL:
- case HCISETLINKMODE:
- case HCISETACLMTU:
- case HCISETSCOMTU:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
- return hci_dev_cmd(cmd, argp);
-
- case HCIINQUIRY:
- return hci_inquiry(argp);
-
- default:
- lock_sock(sk);
- err = hci_sock_bound_ioctl(sk, cmd, arg);
- release_sock(sk);
- return err;
- }
-}
-
-static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
-{
- struct sockaddr_hci haddr;
- struct sock *sk = sock->sk;
- struct hci_dev *hdev = NULL;
- int len, err = 0;
-
- BT_DBG("sock %p sk %p", sock, sk);
-
- if (!addr)
- return -EINVAL;
-
- memset(&haddr, 0, sizeof(haddr));
- len = min_t(unsigned int, sizeof(haddr), addr_len);
- memcpy(&haddr, addr, len);
-
- if (haddr.hci_family != AF_BLUETOOTH)
- return -EINVAL;
-
- lock_sock(sk);
-
- if (sk->sk_state == BT_BOUND) {
- err = -EALREADY;
- goto done;
- }
-
- switch (haddr.hci_channel) {
- case HCI_CHANNEL_RAW:
- if (hci_pi(sk)->hdev) {
- err = -EALREADY;
- goto done;
- }
-
- if (haddr.hci_dev != HCI_DEV_NONE) {
- hdev = hci_dev_get(haddr.hci_dev);
- if (!hdev) {
- err = -ENODEV;
- goto done;
- }
-
- atomic_inc(&hdev->promisc);
- }
-
- hci_pi(sk)->hdev = hdev;
- break;
-
- case HCI_CHANNEL_CONTROL:
- if (haddr.hci_dev != HCI_DEV_NONE) {
- err = -EINVAL;
- goto done;
- }
-
- if (!capable(CAP_NET_ADMIN)) {
- err = -EPERM;
- goto done;
- }
-
- break;
-
- case HCI_CHANNEL_MONITOR:
- if (haddr.hci_dev != HCI_DEV_NONE) {
- err = -EINVAL;
- goto done;
- }
-
- if (!capable(CAP_NET_RAW)) {
- err = -EPERM;
- goto done;
- }
-
- send_monitor_replay(sk);
-
- atomic_inc(&monitor_promisc);
- break;
-
- default:
- err = -EINVAL;
- goto done;
- }
-
-
- hci_pi(sk)->channel = haddr.hci_channel;
- sk->sk_state = BT_BOUND;
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer)
-{
- struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
- struct sock *sk = sock->sk;
- struct hci_dev *hdev = hci_pi(sk)->hdev;
-
- BT_DBG("sock %p sk %p", sock, sk);
-
- if (!hdev)
- return -EBADFD;
-
- lock_sock(sk);
-
- *addr_len = sizeof(*haddr);
- haddr->hci_family = AF_BLUETOOTH;
- haddr->hci_dev = hdev->id;
-
- release_sock(sk);
- return 0;
-}
-
-static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
-{
- __u32 mask = hci_pi(sk)->cmsg_mask;
-
- if (mask & HCI_CMSG_DIR) {
- int incoming = bt_cb(skb)->incoming;
- put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(incoming), &incoming);
- }
-
- if (mask & HCI_CMSG_TSTAMP) {
-#ifdef CONFIG_COMPAT
- struct compat_timeval ctv;
-#endif
- struct timeval tv;
- void *data;
- int len;
-
- skb_get_timestamp(skb, &tv);
-
- data = &tv;
- len = sizeof(tv);
-#ifdef CONFIG_COMPAT
- if (msg->msg_flags & MSG_CMSG_COMPAT) {
- ctv.tv_sec = tv.tv_sec;
- ctv.tv_usec = tv.tv_usec;
- data = &ctv;
- len = sizeof(ctv);
- }
-#endif
-
- put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, len, data);
- }
-}
-
-static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t len, int flags)
-{
- int noblock = flags & MSG_DONTWAIT;
- struct sock *sk = sock->sk;
- struct sk_buff *skb;
- int copied, err;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- if (flags & (MSG_OOB))
- return -EOPNOTSUPP;
-
- if (sk->sk_state == BT_CLOSED)
- return 0;
-
- skb = skb_recv_datagram(sk, flags, noblock, &err);
- if (!skb)
- return err;
-
- msg->msg_namelen = 0;
-
- copied = skb->len;
- if (len < copied) {
- msg->msg_flags |= MSG_TRUNC;
- copied = len;
- }
-
- skb_reset_transport_header(skb);
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
-
- switch (hci_pi(sk)->channel) {
- case HCI_CHANNEL_RAW:
- hci_sock_cmsg(sk, msg, skb);
- break;
- case HCI_CHANNEL_CONTROL:
- case HCI_CHANNEL_MONITOR:
- sock_recv_timestamp(msg, sk, skb);
- break;
- }
-
- skb_free_datagram(sk, skb);
-
- return err ? : copied;
-}
-
-static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t len)
-{
- struct sock *sk = sock->sk;
- struct hci_dev *hdev;
- struct sk_buff *skb;
- int err;
-
- BT_DBG("sock %p sk %p", sock, sk);
-
- if (msg->msg_flags & MSG_OOB)
- return -EOPNOTSUPP;
-
- if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
- return -EINVAL;
-
- if (len < 4 || len > HCI_MAX_FRAME_SIZE)
- return -EINVAL;
-
- lock_sock(sk);
-
- switch (hci_pi(sk)->channel) {
- case HCI_CHANNEL_RAW:
- break;
- case HCI_CHANNEL_CONTROL:
- err = mgmt_control(sk, msg, len);
- goto done;
- case HCI_CHANNEL_MONITOR:
- err = -EOPNOTSUPP;
- goto done;
- default:
- err = -EINVAL;
- goto done;
- }
-
- hdev = hci_pi(sk)->hdev;
- if (!hdev) {
- err = -EBADFD;
- goto done;
- }
-
- if (!test_bit(HCI_UP, &hdev->flags)) {
- err = -ENETDOWN;
- goto done;
- }
-
- skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err);
- if (!skb)
- goto done;
-
- if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
- err = -EFAULT;
- goto drop;
- }
-
- bt_cb(skb)->pkt_type = *((unsigned char *) skb->data);
- skb_pull(skb, 1);
- skb->dev = (void *) hdev;
-
- if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
- u16 opcode = get_unaligned_le16(skb->data);
- u16 ogf = hci_opcode_ogf(opcode);
- u16 ocf = hci_opcode_ocf(opcode);
-
- if (((ogf > HCI_SFLT_MAX_OGF) ||
- !hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) &&
- !capable(CAP_NET_RAW)) {
- err = -EPERM;
- goto drop;
- }
-
- if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) {
- skb_queue_tail(&hdev->raw_q, skb);
- queue_work(hdev->workqueue, &hdev->tx_work);
- } else {
- skb_queue_tail(&hdev->cmd_q, skb);
- queue_work(hdev->workqueue, &hdev->cmd_work);
- }
- } else {
- if (!capable(CAP_NET_RAW)) {
- err = -EPERM;
- goto drop;
- }
-
- skb_queue_tail(&hdev->raw_q, skb);
- queue_work(hdev->workqueue, &hdev->tx_work);
- }
-
- err = len;
-
-done:
- release_sock(sk);
- return err;
-
-drop:
- kfree_skb(skb);
- goto done;
-}
-
-static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int len)
-{
- struct hci_ufilter uf = { .opcode = 0 };
- struct sock *sk = sock->sk;
- int err = 0, opt = 0;
-
- BT_DBG("sk %p, opt %d", sk, optname);
-
- lock_sock(sk);
-
- if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) {
- err = -EINVAL;
- goto done;
- }
-
- switch (optname) {
- case HCI_DATA_DIR:
- if (get_user(opt, (int __user *)optval)) {
- err = -EFAULT;
- break;
- }
-
- if (opt)
- hci_pi(sk)->cmsg_mask |= HCI_CMSG_DIR;
- else
- hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_DIR;
- break;
-
- case HCI_TIME_STAMP:
- if (get_user(opt, (int __user *)optval)) {
- err = -EFAULT;
- break;
- }
-
- if (opt)
- hci_pi(sk)->cmsg_mask |= HCI_CMSG_TSTAMP;
- else
- hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_TSTAMP;
- break;
-
- case HCI_FILTER:
- {
- struct hci_filter *f = &hci_pi(sk)->filter;
-
- uf.type_mask = f->type_mask;
- uf.opcode = f->opcode;
- uf.event_mask[0] = *((u32 *) f->event_mask + 0);
- uf.event_mask[1] = *((u32 *) f->event_mask + 1);
- }
-
- len = min_t(unsigned int, len, sizeof(uf));
- if (copy_from_user(&uf, optval, len)) {
- err = -EFAULT;
- break;
- }
-
- if (!capable(CAP_NET_RAW)) {
- uf.type_mask &= hci_sec_filter.type_mask;
- uf.event_mask[0] &= *((u32 *) hci_sec_filter.event_mask + 0);
- uf.event_mask[1] &= *((u32 *) hci_sec_filter.event_mask + 1);
- }
-
- {
- struct hci_filter *f = &hci_pi(sk)->filter;
-
- f->type_mask = uf.type_mask;
- f->opcode = uf.opcode;
- *((u32 *) f->event_mask + 0) = uf.event_mask[0];
- *((u32 *) f->event_mask + 1) = uf.event_mask[1];
- }
- break;
-
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
-{
- struct hci_ufilter uf;
- struct sock *sk = sock->sk;
- int len, opt, err = 0;
-
- BT_DBG("sk %p, opt %d", sk, optname);
-
- if (get_user(len, optlen))
- return -EFAULT;
-
- lock_sock(sk);
-
- if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) {
- err = -EINVAL;
- goto done;
- }
-
- switch (optname) {
- case HCI_DATA_DIR:
- if (hci_pi(sk)->cmsg_mask & HCI_CMSG_DIR)
- opt = 1;
- else
- opt = 0;
-
- if (put_user(opt, optval))
- err = -EFAULT;
- break;
-
- case HCI_TIME_STAMP:
- if (hci_pi(sk)->cmsg_mask & HCI_CMSG_TSTAMP)
- opt = 1;
- else
- opt = 0;
-
- if (put_user(opt, optval))
- err = -EFAULT;
- break;
-
- case HCI_FILTER:
- {
- struct hci_filter *f = &hci_pi(sk)->filter;
-
- uf.type_mask = f->type_mask;
- uf.opcode = f->opcode;
- uf.event_mask[0] = *((u32 *) f->event_mask + 0);
- uf.event_mask[1] = *((u32 *) f->event_mask + 1);
- }
-
- len = min_t(unsigned int, len, sizeof(uf));
- if (copy_to_user(optval, &uf, len))
- err = -EFAULT;
- break;
-
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
-done:
- release_sock(sk);
- return err;
-}
-
-static const struct proto_ops hci_sock_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .release = hci_sock_release,
- .bind = hci_sock_bind,
- .getname = hci_sock_getname,
- .sendmsg = hci_sock_sendmsg,
- .recvmsg = hci_sock_recvmsg,
- .ioctl = hci_sock_ioctl,
- .poll = datagram_poll,
- .listen = sock_no_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = hci_sock_setsockopt,
- .getsockopt = hci_sock_getsockopt,
- .connect = sock_no_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .mmap = sock_no_mmap
-};
-
-static struct proto hci_sk_proto = {
- .name = "HCI",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct hci_pinfo)
-};
-
-static int hci_sock_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
-
- BT_DBG("sock %p", sock);
-
- if (sock->type != SOCK_RAW)
- return -ESOCKTNOSUPPORT;
-
- sock->ops = &hci_sock_ops;
-
- sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto);
- if (!sk)
- return -ENOMEM;
-
- sock_init_data(sock, sk);
-
- sock_reset_flag(sk, SOCK_ZAPPED);
-
- sk->sk_protocol = protocol;
-
- sock->state = SS_UNCONNECTED;
- sk->sk_state = BT_OPEN;
-
- bt_sock_link(&hci_sk_list, sk);
- return 0;
-}
-
-static int hci_sock_dev_event(struct notifier_block *this,
- unsigned long event, void *ptr)
-{
- struct hci_dev *hdev = (struct hci_dev *) ptr;
- struct hci_ev_si_device ev;
-
- BT_DBG("hdev %s event %ld", hdev->name, event);
-
- /* Send event to sockets */
- ev.event = event;
- ev.dev_id = hdev->id;
- hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev);
-
- if (event == HCI_DEV_UNREG) {
- struct sock *sk;
- struct hlist_node *node;
-
- /* Detach sockets from device */
- read_lock(&hci_sk_list.lock);
- sk_for_each(sk, node, &hci_sk_list.head) {
- bh_lock_sock_nested(sk);
- if (hci_pi(sk)->hdev == hdev) {
- hci_pi(sk)->hdev = NULL;
- sk->sk_err = EPIPE;
- sk->sk_state = BT_OPEN;
- sk->sk_state_change(sk);
-
- hci_dev_put(hdev);
- }
- bh_unlock_sock(sk);
- }
- read_unlock(&hci_sk_list.lock);
- }
-
- return NOTIFY_DONE;
-}
-
-static const struct net_proto_family hci_sock_family_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .create = hci_sock_create,
-};
-
-static struct notifier_block hci_sock_nblock = {
- .notifier_call = hci_sock_dev_event
-};
-
-int __init hci_sock_init(void)
-{
- int err;
-
- err = proto_register(&hci_sk_proto, 0);
- if (err < 0)
- return err;
-
- err = bt_sock_register(BTPROTO_HCI, &hci_sock_family_ops);
- if (err < 0)
- goto error;
-
- hci_register_notifier(&hci_sock_nblock);
-
- BT_INFO("HCI socket layer initialized");
-
- return 0;
-
-error:
- BT_ERR("HCI socket registration failed");
- proto_unregister(&hci_sk_proto);
- return err;
-}
-
-void hci_sock_cleanup(void)
-{
- if (bt_sock_unregister(BTPROTO_HCI) < 0)
- BT_ERR("HCI socket unregistration failed");
-
- hci_unregister_notifier(&hci_sock_nblock);
-
- proto_unregister(&hci_sk_proto);
-}
diff --git a/net/bluetooth_tizen/hci_sysfs.c b/net/bluetooth_tizen/hci_sysfs.c
deleted file mode 100644
index bc15429..0000000
--- a/net/bluetooth_tizen/hci_sysfs.c
+++ /dev/null
@@ -1,588 +0,0 @@
-/* Bluetooth HCI driver model support. */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/module.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
-static struct class *bt_class;
-
-struct dentry *bt_debugfs;
-EXPORT_SYMBOL_GPL(bt_debugfs);
-
-static inline char *link_typetostr(int type)
-{
- switch (type) {
- case ACL_LINK:
- return "ACL";
- case SCO_LINK:
- return "SCO";
- case ESCO_LINK:
- return "eSCO";
- case LE_LINK:
- return "LE";
- default:
- return "UNKNOWN";
- }
-}
-
-static ssize_t show_link_type(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_conn *conn = to_hci_conn(dev);
- return sprintf(buf, "%s\n", link_typetostr(conn->type));
-}
-
-static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_conn *conn = to_hci_conn(dev);
- return sprintf(buf, "%s\n", batostr(&conn->dst));
-}
-
-static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_conn *conn = to_hci_conn(dev);
-
- return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
- conn->features[0], conn->features[1],
- conn->features[2], conn->features[3],
- conn->features[4], conn->features[5],
- conn->features[6], conn->features[7]);
-}
-
-#define LINK_ATTR(_name, _mode, _show, _store) \
-struct device_attribute link_attr_##_name = __ATTR(_name, _mode, _show, _store)
-
-static LINK_ATTR(type, S_IRUGO, show_link_type, NULL);
-static LINK_ATTR(address, S_IRUGO, show_link_address, NULL);
-static LINK_ATTR(features, S_IRUGO, show_link_features, NULL);
-
-static struct attribute *bt_link_attrs[] = {
- &link_attr_type.attr,
- &link_attr_address.attr,
- &link_attr_features.attr,
- NULL
-};
-
-static struct attribute_group bt_link_group = {
- .attrs = bt_link_attrs,
-};
-
-static const struct attribute_group *bt_link_groups[] = {
- &bt_link_group,
- NULL
-};
-
-static void bt_link_release(struct device *dev)
-{
- struct hci_conn *conn = to_hci_conn(dev);
- kfree(conn);
-}
-
-static struct device_type bt_link = {
- .name = "link",
- .groups = bt_link_groups,
- .release = bt_link_release,
-};
-
-/*
- * The rfcomm tty device will possibly retain even when conn
- * is down, and sysfs doesn't support move zombie device,
- * so we should move the device before conn device is destroyed.
- */
-static int __match_tty(struct device *dev, void *data)
-{
- return !strncmp(dev_name(dev), "rfcomm", 6);
-}
-
-void hci_conn_init_sysfs(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
-
- BT_DBG("conn %p", conn);
-
- conn->dev.type = &bt_link;
- conn->dev.class = bt_class;
- conn->dev.parent = &hdev->dev;
-
- device_initialize(&conn->dev);
-}
-
-void hci_conn_add_sysfs(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
-
- BT_DBG("conn %p", conn);
-
- dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);
-
- if (device_add(&conn->dev) < 0) {
- BT_ERR("Failed to register connection device");
- return;
- }
-
- hci_dev_hold(hdev);
-}
-
-void hci_conn_del_sysfs(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
-
- if (!device_is_registered(&conn->dev))
- return;
-
- while (1) {
- struct device *dev;
-
- dev = device_find_child(&conn->dev, NULL, __match_tty);
- if (!dev)
- break;
- device_move(dev, NULL, DPM_ORDER_DEV_LAST);
- put_device(dev);
- }
-
- device_del(&conn->dev);
- put_device(&conn->dev);
-
- hci_dev_put(hdev);
-}
-
-static inline char *host_bustostr(int bus)
-{
- switch (bus) {
- case HCI_VIRTUAL:
- return "VIRTUAL";
- case HCI_USB:
- return "USB";
- case HCI_PCCARD:
- return "PCCARD";
- case HCI_UART:
- return "UART";
- case HCI_RS232:
- return "RS232";
- case HCI_PCI:
- return "PCI";
- case HCI_SDIO:
- return "SDIO";
- default:
- return "UNKNOWN";
- }
-}
-
-static inline char *host_typetostr(int type)
-{
- switch (type) {
- case HCI_BREDR:
- return "BR/EDR";
- case HCI_AMP:
- return "AMP";
- default:
- return "UNKNOWN";
- }
-}
-
-static ssize_t show_bus(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- return sprintf(buf, "%s\n", host_bustostr(hdev->bus));
-}
-
-static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type));
-}
-
-static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- char name[HCI_MAX_NAME_LENGTH + 1];
- int i;
-
- for (i = 0; i < HCI_MAX_NAME_LENGTH; i++)
- name[i] = hdev->dev_name[i];
-
- name[HCI_MAX_NAME_LENGTH] = '\0';
- return sprintf(buf, "%s\n", name);
-}
-
-static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- return sprintf(buf, "0x%.2x%.2x%.2x\n",
- hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
-}
-
-static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- return sprintf(buf, "%s\n", batostr(&hdev->bdaddr));
-}
-
-static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
-
- return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
- hdev->features[0], hdev->features[1],
- hdev->features[2], hdev->features[3],
- hdev->features[4], hdev->features[5],
- hdev->features[6], hdev->features[7]);
-}
-
-static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- return sprintf(buf, "%d\n", hdev->manufacturer);
-}
-
-static ssize_t show_hci_version(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- return sprintf(buf, "%d\n", hdev->hci_ver);
-}
-
-static ssize_t show_hci_revision(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- return sprintf(buf, "%d\n", hdev->hci_rev);
-}
-
-static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- return sprintf(buf, "%d\n", hdev->idle_timeout);
-}
-
-static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- unsigned int val;
- int rv;
-
- rv = kstrtouint(buf, 0, &val);
- if (rv < 0)
- return rv;
-
- if (val != 0 && (val < 500 || val > 3600000))
- return -EINVAL;
-
- hdev->idle_timeout = val;
-
- return count;
-}
-
-static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- return sprintf(buf, "%d\n", hdev->sniff_max_interval);
-}
-
-static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- u16 val;
- int rv;
-
- rv = kstrtou16(buf, 0, &val);
- if (rv < 0)
- return rv;
-
- if (val == 0 || val % 2 || val < hdev->sniff_min_interval)
- return -EINVAL;
-
- hdev->sniff_max_interval = val;
-
- return count;
-}
-
-static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- return sprintf(buf, "%d\n", hdev->sniff_min_interval);
-}
-
-static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- u16 val;
- int rv;
-
- rv = kstrtou16(buf, 0, &val);
- if (rv < 0)
- return rv;
-
- if (val == 0 || val % 2 || val > hdev->sniff_max_interval)
- return -EINVAL;
-
- hdev->sniff_min_interval = val;
-
- return count;
-}
-
-static DEVICE_ATTR(bus, S_IRUGO, show_bus, NULL);
-static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-static DEVICE_ATTR(class, S_IRUGO, show_class, NULL);
-static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
-static DEVICE_ATTR(features, S_IRUGO, show_features, NULL);
-static DEVICE_ATTR(manufacturer, S_IRUGO, show_manufacturer, NULL);
-static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL);
-static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL);
-
-static DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR,
- show_idle_timeout, store_idle_timeout);
-static DEVICE_ATTR(sniff_max_interval, S_IRUGO | S_IWUSR,
- show_sniff_max_interval, store_sniff_max_interval);
-static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
- show_sniff_min_interval, store_sniff_min_interval);
-
-static struct attribute *bt_host_attrs[] = {
- &dev_attr_bus.attr,
- &dev_attr_type.attr,
- &dev_attr_name.attr,
- &dev_attr_class.attr,
- &dev_attr_address.attr,
- &dev_attr_features.attr,
- &dev_attr_manufacturer.attr,
- &dev_attr_hci_version.attr,
- &dev_attr_hci_revision.attr,
- &dev_attr_idle_timeout.attr,
- &dev_attr_sniff_max_interval.attr,
- &dev_attr_sniff_min_interval.attr,
- NULL
-};
-
-static struct attribute_group bt_host_group = {
- .attrs = bt_host_attrs,
-};
-
-static const struct attribute_group *bt_host_groups[] = {
- &bt_host_group,
- NULL
-};
-
-static void bt_host_release(struct device *dev)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- kfree(hdev);
- module_put(THIS_MODULE);
-}
-
-static struct device_type bt_host = {
- .name = "host",
- .groups = bt_host_groups,
- .release = bt_host_release,
-};
-
-static int inquiry_cache_show(struct seq_file *f, void *p)
-{
- struct hci_dev *hdev = f->private;
- struct discovery_state *cache = &hdev->discovery;
- struct inquiry_entry *e;
-
- hci_dev_lock(hdev);
-
- list_for_each_entry(e, &cache->all, all) {
- struct inquiry_data *data = &e->data;
- seq_printf(f, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
- batostr(&data->bdaddr),
- data->pscan_rep_mode, data->pscan_period_mode,
- data->pscan_mode, data->dev_class[2],
- data->dev_class[1], data->dev_class[0],
- __le16_to_cpu(data->clock_offset),
- data->rssi, data->ssp_mode, e->timestamp);
- }
-
- hci_dev_unlock(hdev);
-
- return 0;
-}
-
-static int inquiry_cache_open(struct inode *inode, struct file *file)
-{
- return single_open(file, inquiry_cache_show, inode->i_private);
-}
-
-static const struct file_operations inquiry_cache_fops = {
- .open = inquiry_cache_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int blacklist_show(struct seq_file *f, void *p)
-{
- struct hci_dev *hdev = f->private;
- struct bdaddr_list *b;
-
- hci_dev_lock(hdev);
-
- list_for_each_entry(b, &hdev->blacklist, list)
- seq_printf(f, "%s\n", batostr(&b->bdaddr));
-
- hci_dev_unlock(hdev);
-
- return 0;
-}
-
-static int blacklist_open(struct inode *inode, struct file *file)
-{
- return single_open(file, blacklist_show, inode->i_private);
-}
-
-static const struct file_operations blacklist_fops = {
- .open = blacklist_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void print_bt_uuid(struct seq_file *f, u8 *uuid)
-{
- u32 data0, data4;
- u16 data1, data2, data3, data5;
-
- memcpy(&data0, &uuid[0], 4);
- memcpy(&data1, &uuid[4], 2);
- memcpy(&data2, &uuid[6], 2);
- memcpy(&data3, &uuid[8], 2);
- memcpy(&data4, &uuid[10], 4);
- memcpy(&data5, &uuid[14], 2);
-
- seq_printf(f, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x\n",
- ntohl(data0), ntohs(data1), ntohs(data2),
- ntohs(data3), ntohl(data4), ntohs(data5));
-}
-
-static int uuids_show(struct seq_file *f, void *p)
-{
- struct hci_dev *hdev = f->private;
- struct bt_uuid *uuid;
-
- hci_dev_lock(hdev);
-
- list_for_each_entry(uuid, &hdev->uuids, list)
- print_bt_uuid(f, uuid->uuid);
-
- hci_dev_unlock(hdev);
-
- return 0;
-}
-
-static int uuids_open(struct inode *inode, struct file *file)
-{
- return single_open(file, uuids_show, inode->i_private);
-}
-
-static const struct file_operations uuids_fops = {
- .open = uuids_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int auto_accept_delay_set(void *data, u64 val)
-{
- struct hci_dev *hdev = data;
-
- hci_dev_lock(hdev);
-
- hdev->auto_accept_delay = val;
-
- hci_dev_unlock(hdev);
-
- return 0;
-}
-
-static int auto_accept_delay_get(void *data, u64 *val)
-{
- struct hci_dev *hdev = data;
-
- hci_dev_lock(hdev);
-
- *val = hdev->auto_accept_delay;
-
- hci_dev_unlock(hdev);
-
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get,
- auto_accept_delay_set, "%llu\n");
-
-void hci_init_sysfs(struct hci_dev *hdev)
-{
- struct device *dev = &hdev->dev;
-
- dev->type = &bt_host;
- dev->class = bt_class;
-
- __module_get(THIS_MODULE);
- device_initialize(dev);
-}
-
-int hci_add_sysfs(struct hci_dev *hdev)
-{
- struct device *dev = &hdev->dev;
- int err;
-
- BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
-
- dev->parent = hdev->parent;
- dev_set_name(dev, "%s", hdev->name);
-
- err = device_add(dev);
- if (err < 0)
- return err;
-
- if (!bt_debugfs)
- return 0;
-
- hdev->debugfs = debugfs_create_dir(hdev->name, bt_debugfs);
- if (!hdev->debugfs)
- return 0;
-
- debugfs_create_file("inquiry_cache", 0444, hdev->debugfs,
- hdev, &inquiry_cache_fops);
-
- debugfs_create_file("blacklist", 0444, hdev->debugfs,
- hdev, &blacklist_fops);
-
- debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops);
-
- debugfs_create_file("auto_accept_delay", 0444, hdev->debugfs, hdev,
- &auto_accept_delay_fops);
- return 0;
-}
-
-void hci_del_sysfs(struct hci_dev *hdev)
-{
- BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
-
- debugfs_remove_recursive(hdev->debugfs);
-
- device_del(&hdev->dev);
-}
-
-int __init bt_sysfs_init(void)
-{
- bt_debugfs = debugfs_create_dir("bluetooth", NULL);
-
- bt_class = class_create(THIS_MODULE, "bluetooth");
- if (IS_ERR(bt_class))
- return PTR_ERR(bt_class);
-
- return 0;
-}
-
-void bt_sysfs_cleanup(void)
-{
- class_destroy(bt_class);
-
- debugfs_remove_recursive(bt_debugfs);
-}
diff --git a/net/bluetooth_tizen/hidp/Kconfig b/net/bluetooth_tizen/hidp/Kconfig
deleted file mode 100644
index 4deaca7..0000000
--- a/net/bluetooth_tizen/hidp/Kconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-config BT_HIDP
- tristate "HIDP protocol support"
- depends on BT && INPUT && HID_SUPPORT
- select HID
- help
- HIDP (Human Interface Device Protocol) is a transport layer
- for HID reports. HIDP is required for the Bluetooth Human
- Interface Device Profile.
-
- Say Y here to compile HIDP support into the kernel or say M to
- compile it as module (hidp).
-
diff --git a/net/bluetooth_tizen/hidp/Makefile b/net/bluetooth_tizen/hidp/Makefile
deleted file mode 100644
index a9ee115..0000000
--- a/net/bluetooth_tizen/hidp/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for the Linux Bluetooth HIDP layer
-#
-
-obj-$(CONFIG_BT_HIDP) += hidp.o
-
-hidp-objs := core.o sock.o
diff --git a/net/bluetooth_tizen/hidp/core.c b/net/bluetooth_tizen/hidp/core.c
deleted file mode 100644
index d478be1..0000000
--- a/net/bluetooth_tizen/hidp/core.c
+++ /dev/null
@@ -1,1242 +0,0 @@
-/*
- HIDP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/freezer.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <linux/file.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/mutex.h>
-#include <linux/kthread.h>
-#include <net/sock.h>
-
-#include <linux/input.h>
-#include <linux/hid.h>
-#include <linux/hidraw.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/l2cap.h>
-
-#include "hidp.h"
-
-#define VERSION "1.2"
-
-static DECLARE_RWSEM(hidp_session_sem);
-static LIST_HEAD(hidp_session_list);
-
-static unsigned char hidp_keycode[256] = {
- 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36,
- 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45,
- 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1,
- 14, 15, 57, 12, 13, 26, 27, 43, 43, 39, 40, 41, 51, 52,
- 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88,
- 99, 70, 119, 110, 102, 104, 111, 107, 109, 106, 105, 108, 103, 69,
- 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73,
- 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190,
- 191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135,
- 136, 113, 115, 114, 0, 0, 0, 121, 0, 89, 93, 124, 92, 94,
- 95, 0, 0, 0, 122, 123, 90, 91, 85, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 29, 42, 56, 125, 97, 54, 100, 126, 164, 166, 165, 163, 161, 115,
- 114, 113, 150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140
-};
-
-static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
-
-static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
-{
- struct hidp_session *session;
-
- BT_DBG("");
-
- list_for_each_entry(session, &hidp_session_list, list) {
- if (!bacmp(bdaddr, &session->bdaddr))
- return session;
- }
-
- return NULL;
-}
-
-static void __hidp_link_session(struct hidp_session *session)
-{
- list_add(&session->list, &hidp_session_list);
-}
-
-static void __hidp_unlink_session(struct hidp_session *session)
-{
- hci_conn_put_device(session->conn);
-
- list_del(&session->list);
-}
-
-static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
-{
- memset(ci, 0, sizeof(*ci));
- bacpy(&ci->bdaddr, &session->bdaddr);
-
- ci->flags = session->flags;
- ci->state = session->state;
-
- ci->vendor = 0x0000;
- ci->product = 0x0000;
- ci->version = 0x0000;
-
- if (session->input) {
- ci->vendor = session->input->id.vendor;
- ci->product = session->input->id.product;
- ci->version = session->input->id.version;
- if (session->input->name)
- strncpy(ci->name, session->input->name, 128);
- else
- strncpy(ci->name, "HID Boot Device", 128);
- }
-
- if (session->hid) {
- ci->vendor = session->hid->vendor;
- ci->product = session->hid->product;
- ci->version = session->hid->version;
- strncpy(ci->name, session->hid->name, 128);
- }
-}
-
-static int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
- unsigned int type, unsigned int code, int value)
-{
- unsigned char newleds;
- struct sk_buff *skb;
-
- BT_DBG("session %p type %d code %d value %d", session, type, code, value);
-
- if (type != EV_LED)
- return -1;
-
- newleds = (!!test_bit(LED_KANA, dev->led) << 3) |
- (!!test_bit(LED_COMPOSE, dev->led) << 3) |
- (!!test_bit(LED_SCROLLL, dev->led) << 2) |
- (!!test_bit(LED_CAPSL, dev->led) << 1) |
- (!!test_bit(LED_NUML, dev->led));
-
- if (session->leds == newleds)
- return 0;
-
- session->leds = newleds;
-
- skb = alloc_skb(3, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("Can't allocate memory for new frame");
- return -ENOMEM;
- }
-
- *skb_put(skb, 1) = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
- *skb_put(skb, 1) = 0x01;
- *skb_put(skb, 1) = newleds;
-
- skb_queue_tail(&session->intr_transmit, skb);
-
- hidp_schedule(session);
-
- return 0;
-}
-
-static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
- struct hid_device *hid = input_get_drvdata(dev);
- struct hidp_session *session = hid->driver_data;
-
- return hidp_queue_event(session, dev, type, code, value);
-}
-
-static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
- struct hidp_session *session = input_get_drvdata(dev);
-
- return hidp_queue_event(session, dev, type, code, value);
-}
-
-static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
-{
- struct input_dev *dev = session->input;
- unsigned char *keys = session->keys;
- unsigned char *udata = skb->data + 1;
- signed char *sdata = skb->data + 1;
- int i, size = skb->len - 1;
-
- switch (skb->data[0]) {
- case 0x01: /* Keyboard report */
- for (i = 0; i < 8; i++)
- input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1);
-
- /* If all the key codes have been set to 0x01, it means
- * too many keys were pressed at the same time. */
- if (!memcmp(udata + 2, hidp_mkeyspat, 6))
- break;
-
- for (i = 2; i < 8; i++) {
- if (keys[i] > 3 && memscan(udata + 2, keys[i], 6) == udata + 8) {
- if (hidp_keycode[keys[i]])
- input_report_key(dev, hidp_keycode[keys[i]], 0);
- else
- BT_ERR("Unknown key (scancode %#x) released.", keys[i]);
- }
-
- if (udata[i] > 3 && memscan(keys + 2, udata[i], 6) == keys + 8) {
- if (hidp_keycode[udata[i]])
- input_report_key(dev, hidp_keycode[udata[i]], 1);
- else
- BT_ERR("Unknown key (scancode %#x) pressed.", udata[i]);
- }
- }
-
- memcpy(keys, udata, 8);
- break;
-
- case 0x02: /* Mouse report */
- input_report_key(dev, BTN_LEFT, sdata[0] & 0x01);
- input_report_key(dev, BTN_RIGHT, sdata[0] & 0x02);
- input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04);
- input_report_key(dev, BTN_SIDE, sdata[0] & 0x08);
- input_report_key(dev, BTN_EXTRA, sdata[0] & 0x10);
-
- input_report_rel(dev, REL_X, sdata[1]);
- input_report_rel(dev, REL_Y, sdata[2]);
-
- if (size > 3)
- input_report_rel(dev, REL_WHEEL, sdata[3]);
- break;
- }
-
- input_sync(dev);
-}
-
-static int __hidp_send_ctrl_message(struct hidp_session *session,
- unsigned char hdr, unsigned char *data, int size)
-{
- struct sk_buff *skb;
-
- BT_DBG("session %p data %p size %d", session, data, size);
-
- if (atomic_read(&session->terminate))
- return -EIO;
-
- skb = alloc_skb(size + 1, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("Can't allocate memory for new frame");
- return -ENOMEM;
- }
-
- *skb_put(skb, 1) = hdr;
- if (data && size > 0)
- memcpy(skb_put(skb, size), data, size);
-
- skb_queue_tail(&session->ctrl_transmit, skb);
-
- return 0;
-}
-
-static inline int hidp_send_ctrl_message(struct hidp_session *session,
- unsigned char hdr, unsigned char *data, int size)
-{
- int err;
-
- err = __hidp_send_ctrl_message(session, hdr, data, size);
-
- hidp_schedule(session);
-
- return err;
-}
-
-static int hidp_queue_report(struct hidp_session *session,
- unsigned char *data, int size)
-{
- struct sk_buff *skb;
-
- BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
-
- skb = alloc_skb(size + 1, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("Can't allocate memory for new frame");
- return -ENOMEM;
- }
-
- *skb_put(skb, 1) = 0xa2;
- if (size > 0)
- memcpy(skb_put(skb, size), data, size);
-
- skb_queue_tail(&session->intr_transmit, skb);
-
- hidp_schedule(session);
-
- return 0;
-}
-
-static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
-{
- unsigned char buf[32];
- int rsize;
-
- rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
- if (rsize > sizeof(buf))
- return -EIO;
-
- hid_output_report(report, buf);
-
- return hidp_queue_report(session, buf, rsize);
-}
-
-static int hidp_get_raw_report(struct hid_device *hid,
- unsigned char report_number,
- unsigned char *data, size_t count,
- unsigned char report_type)
-{
- struct hidp_session *session = hid->driver_data;
- struct sk_buff *skb;
- size_t len;
- int numbered_reports = hid->report_enum[report_type].numbered;
- int ret;
-
- switch (report_type) {
- case HID_FEATURE_REPORT:
- report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_FEATURE;
- break;
- case HID_INPUT_REPORT:
- report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_INPUT;
- break;
- case HID_OUTPUT_REPORT:
- report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_OUPUT;
- break;
- default:
- return -EINVAL;
- }
-
- if (mutex_lock_interruptible(&session->report_mutex))
- return -ERESTARTSYS;
-
- /* Set up our wait, and send the report request to the device. */
- session->waiting_report_type = report_type & HIDP_DATA_RTYPE_MASK;
- session->waiting_report_number = numbered_reports ? report_number : -1;
- set_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
- data[0] = report_number;
- ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, 1);
- if (ret)
- goto err;
-
- /* Wait for the return of the report. The returned report
- gets put in session->report_return. */
- while (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)) {
- int res;
-
- res = wait_event_interruptible_timeout(session->report_queue,
- !test_bit(HIDP_WAITING_FOR_RETURN, &session->flags),
- 5*HZ);
- if (res == 0) {
- /* timeout */
- ret = -EIO;
- goto err;
- }
- if (res < 0) {
- /* signal */
- ret = -ERESTARTSYS;
- goto err;
- }
- }
-
- skb = session->report_return;
- if (skb) {
- len = skb->len < count ? skb->len : count;
- memcpy(data, skb->data, len);
-
- kfree_skb(skb);
- session->report_return = NULL;
- } else {
- /* Device returned a HANDSHAKE, indicating protocol error. */
- len = -EIO;
- }
-
- clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
- mutex_unlock(&session->report_mutex);
-
- return len;
-
-err:
- clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
- mutex_unlock(&session->report_mutex);
- return ret;
-}
-
-static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
- unsigned char report_type)
-{
- struct hidp_session *session = hid->driver_data;
- int ret;
-
- switch (report_type) {
- case HID_FEATURE_REPORT:
- report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
- break;
- case HID_OUTPUT_REPORT:
- report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUPUT;
- break;
- default:
- return -EINVAL;
- }
-
- if (mutex_lock_interruptible(&session->report_mutex))
- return -ERESTARTSYS;
-
- /* Set up our wait, and send the report request to the device. */
- set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
- ret = hidp_send_ctrl_message(hid->driver_data, report_type, data,
- count);
- if (ret)
- goto err;
-
- /* Wait for the ACK from the device. */
- while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
- int res;
-
- res = wait_event_interruptible_timeout(session->report_queue,
- !test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags),
- 10*HZ);
- if (res == 0) {
- /* timeout */
- ret = -EIO;
- goto err;
- }
- if (res < 0) {
- /* signal */
- ret = -ERESTARTSYS;
- goto err;
- }
- }
-
- if (!session->output_report_success) {
- ret = -EIO;
- goto err;
- }
-
- ret = count;
-
-err:
- clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
- mutex_unlock(&session->report_mutex);
- return ret;
-}
-
-static void hidp_idle_timeout(unsigned long arg)
-{
- struct hidp_session *session = (struct hidp_session *) arg;
-
- atomic_inc(&session->terminate);
- wake_up_process(session->task);
-}
-
-static void hidp_set_timer(struct hidp_session *session)
-{
- if (session->idle_to > 0)
- mod_timer(&session->timer, jiffies + HZ * session->idle_to);
-}
-
-static inline void hidp_del_timer(struct hidp_session *session)
-{
- if (session->idle_to > 0)
- del_timer(&session->timer);
-}
-
-static void hidp_process_handshake(struct hidp_session *session,
- unsigned char param)
-{
- BT_DBG("session %p param 0x%02x", session, param);
- session->output_report_success = 0; /* default condition */
-
- switch (param) {
- case HIDP_HSHK_SUCCESSFUL:
- /* FIXME: Call into SET_ GET_ handlers here */
- session->output_report_success = 1;
- break;
-
- case HIDP_HSHK_NOT_READY:
- case HIDP_HSHK_ERR_INVALID_REPORT_ID:
- case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
- case HIDP_HSHK_ERR_INVALID_PARAMETER:
- if (test_and_clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags))
- wake_up_interruptible(&session->report_queue);
-
- /* FIXME: Call into SET_ GET_ handlers here */
- break;
-
- case HIDP_HSHK_ERR_UNKNOWN:
- break;
-
- case HIDP_HSHK_ERR_FATAL:
- /* Device requests a reboot, as this is the only way this error
- * can be recovered. */
- __hidp_send_ctrl_message(session,
- HIDP_TRANS_HID_CONTROL | HIDP_CTRL_SOFT_RESET, NULL, 0);
- break;
-
- default:
- __hidp_send_ctrl_message(session,
- HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
- break;
- }
-
- /* Wake up the waiting thread. */
- if (test_and_clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags))
- wake_up_interruptible(&session->report_queue);
-}
-
-static void hidp_process_hid_control(struct hidp_session *session,
- unsigned char param)
-{
- BT_DBG("session %p param 0x%02x", session, param);
-
- if (param == HIDP_CTRL_VIRTUAL_CABLE_UNPLUG) {
- /* Flush the transmit queues */
- skb_queue_purge(&session->ctrl_transmit);
- skb_queue_purge(&session->intr_transmit);
-
- atomic_inc(&session->terminate);
- wake_up_process(current);
- }
-}
-
-/* Returns true if the passed-in skb should be freed by the caller. */
-static int hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
- unsigned char param)
-{
- int done_with_skb = 1;
- BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
-
- switch (param) {
- case HIDP_DATA_RTYPE_INPUT:
- hidp_set_timer(session);
-
- if (session->input)
- hidp_input_report(session, skb);
-
- if (session->hid)
- hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
- break;
-
- case HIDP_DATA_RTYPE_OTHER:
- case HIDP_DATA_RTYPE_OUPUT:
- case HIDP_DATA_RTYPE_FEATURE:
- break;
-
- default:
- __hidp_send_ctrl_message(session,
- HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
- }
-
- if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags) &&
- param == session->waiting_report_type) {
- if (session->waiting_report_number < 0 ||
- session->waiting_report_number == skb->data[0]) {
- /* hidp_get_raw_report() is waiting on this report. */
- session->report_return = skb;
- done_with_skb = 0;
- clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
- wake_up_interruptible(&session->report_queue);
- }
- }
-
- return done_with_skb;
-}
-
-static void hidp_recv_ctrl_frame(struct hidp_session *session,
- struct sk_buff *skb)
-{
- unsigned char hdr, type, param;
- int free_skb = 1;
-
- BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-
- hdr = skb->data[0];
- skb_pull(skb, 1);
-
- type = hdr & HIDP_HEADER_TRANS_MASK;
- param = hdr & HIDP_HEADER_PARAM_MASK;
-
- switch (type) {
- case HIDP_TRANS_HANDSHAKE:
- hidp_process_handshake(session, param);
- break;
-
- case HIDP_TRANS_HID_CONTROL:
- hidp_process_hid_control(session, param);
- break;
-
- case HIDP_TRANS_DATA:
- free_skb = hidp_process_data(session, skb, param);
- break;
-
- default:
- __hidp_send_ctrl_message(session,
- HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
- break;
- }
-
- if (free_skb)
- kfree_skb(skb);
-}
-
-static void hidp_recv_intr_frame(struct hidp_session *session,
- struct sk_buff *skb)
-{
- unsigned char hdr;
-
- BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-
- hdr = skb->data[0];
- skb_pull(skb, 1);
-
- if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
- hidp_set_timer(session);
-
- if (session->input)
- hidp_input_report(session, skb);
-
- if (session->hid) {
- hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1);
- BT_DBG("report len %d", skb->len);
- }
- } else {
- BT_DBG("Unsupported protocol header 0x%02x", hdr);
- }
-
- kfree_skb(skb);
-}
-
-static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
-{
- struct kvec iv = { data, len };
- struct msghdr msg;
-
- BT_DBG("sock %p data %p len %d", sock, data, len);
-
- if (!len)
- return 0;
-
- memset(&msg, 0, sizeof(msg));
-
- return kernel_sendmsg(sock, &msg, &iv, 1, len);
-}
-
-static void hidp_process_intr_transmit(struct hidp_session *session)
-{
- struct sk_buff *skb;
-
- BT_DBG("session %p", session);
-
- while ((skb = skb_dequeue(&session->intr_transmit))) {
- if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
- skb_queue_head(&session->intr_transmit, skb);
- break;
- }
-
- hidp_set_timer(session);
- kfree_skb(skb);
- }
-}
-
-static void hidp_process_ctrl_transmit(struct hidp_session *session)
-{
- struct sk_buff *skb;
-
- BT_DBG("session %p", session);
-
- while ((skb = skb_dequeue(&session->ctrl_transmit))) {
- if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
- skb_queue_head(&session->ctrl_transmit, skb);
- break;
- }
-
- hidp_set_timer(session);
- kfree_skb(skb);
- }
-}
-
-static int hidp_session(void *arg)
-{
- struct hidp_session *session = arg;
- struct sock *ctrl_sk = session->ctrl_sock->sk;
- struct sock *intr_sk = session->intr_sock->sk;
- struct sk_buff *skb;
- wait_queue_t ctrl_wait, intr_wait;
-
- BT_DBG("session %p", session);
-
- __module_get(THIS_MODULE);
- set_user_nice(current, -15);
-
- init_waitqueue_entry(&ctrl_wait, current);
- init_waitqueue_entry(&intr_wait, current);
- add_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
- add_wait_queue(sk_sleep(intr_sk), &intr_wait);
- session->waiting_for_startup = 0;
- wake_up_interruptible(&session->startup_queue);
- set_current_state(TASK_INTERRUPTIBLE);
- while (!atomic_read(&session->terminate)) {
- if (ctrl_sk->sk_state != BT_CONNECTED ||
- intr_sk->sk_state != BT_CONNECTED)
- break;
-
- while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
- skb_orphan(skb);
- if (!skb_linearize(skb))
- hidp_recv_intr_frame(session, skb);
- else
- kfree_skb(skb);
- }
-
- hidp_process_intr_transmit(session);
-
- while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
- skb_orphan(skb);
- if (!skb_linearize(skb))
- hidp_recv_ctrl_frame(session, skb);
- else
- kfree_skb(skb);
- }
-
- hidp_process_ctrl_transmit(session);
-
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
- remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
-
- clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
- clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
- wake_up_interruptible(&session->report_queue);
-
- down_write(&hidp_session_sem);
-
- hidp_del_timer(session);
-
- if (session->input) {
- input_unregister_device(session->input);
- session->input = NULL;
- }
-
- if (session->hid) {
- hid_destroy_device(session->hid);
- session->hid = NULL;
- }
-
- /* Wakeup user-space polling for socket errors */
- session->intr_sock->sk->sk_err = EUNATCH;
- session->ctrl_sock->sk->sk_err = EUNATCH;
-
- hidp_schedule(session);
-
- fput(session->intr_sock->file);
-
- wait_event_timeout(*(sk_sleep(ctrl_sk)),
- (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
-
- fput(session->ctrl_sock->file);
-
- __hidp_unlink_session(session);
-
- up_write(&hidp_session_sem);
-
- kfree(session->rd_data);
- kfree(session);
- module_put_and_exit(0);
- return 0;
-}
-
-static struct hci_conn *hidp_get_connection(struct hidp_session *session)
-{
- bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
- bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
- struct hci_conn *conn;
- struct hci_dev *hdev;
-
- hdev = hci_get_route(dst, src);
- if (!hdev)
- return NULL;
-
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
- if (conn)
- hci_conn_hold_device(conn);
- hci_dev_unlock(hdev);
-
- hci_dev_put(hdev);
-
- return conn;
-}
-
-static int hidp_setup_input(struct hidp_session *session,
- struct hidp_connadd_req *req)
-{
- struct input_dev *input;
- int i;
-
- input = input_allocate_device();
- if (!input)
- return -ENOMEM;
-
- session->input = input;
-
- input_set_drvdata(input, session);
-
- input->name = "Bluetooth HID Boot Protocol Device";
-
- input->id.bustype = BUS_BLUETOOTH;
- input->id.vendor = req->vendor;
- input->id.product = req->product;
- input->id.version = req->version;
-
- if (req->subclass & 0x40) {
- set_bit(EV_KEY, input->evbit);
- set_bit(EV_LED, input->evbit);
- set_bit(EV_REP, input->evbit);
-
- set_bit(LED_NUML, input->ledbit);
- set_bit(LED_CAPSL, input->ledbit);
- set_bit(LED_SCROLLL, input->ledbit);
- set_bit(LED_COMPOSE, input->ledbit);
- set_bit(LED_KANA, input->ledbit);
-
- for (i = 0; i < sizeof(hidp_keycode); i++)
- set_bit(hidp_keycode[i], input->keybit);
- clear_bit(0, input->keybit);
- }
-
- if (req->subclass & 0x80) {
- input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
- input->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
- BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
- input->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
- input->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
- BIT_MASK(BTN_EXTRA);
- input->relbit[0] |= BIT_MASK(REL_WHEEL);
- }
-
- input->dev.parent = &session->conn->dev;
-
- input->event = hidp_input_event;
-
- return 0;
-}
-
-static int hidp_open(struct hid_device *hid)
-{
- return 0;
-}
-
-static void hidp_close(struct hid_device *hid)
-{
-}
-
-static int hidp_parse(struct hid_device *hid)
-{
- struct hidp_session *session = hid->driver_data;
-
- return hid_parse_report(session->hid, session->rd_data,
- session->rd_size);
-}
-
-static int hidp_start(struct hid_device *hid)
-{
- struct hidp_session *session = hid->driver_data;
- struct hid_report *report;
-
- if (hid->quirks & HID_QUIRK_NO_INIT_REPORTS)
- return 0;
-
- list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
- report_list, list)
- hidp_send_report(session, report);
-
- list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
- report_list, list)
- hidp_send_report(session, report);
-
- return 0;
-}
-
-static void hidp_stop(struct hid_device *hid)
-{
- struct hidp_session *session = hid->driver_data;
-
- skb_queue_purge(&session->ctrl_transmit);
- skb_queue_purge(&session->intr_transmit);
-
- hid->claimed = 0;
-}
-
-static struct hid_ll_driver hidp_hid_driver = {
- .parse = hidp_parse,
- .start = hidp_start,
- .stop = hidp_stop,
- .open = hidp_open,
- .close = hidp_close,
- .hidinput_input_event = hidp_hidinput_event,
-};
-
-/* This function sets up the hid device. It does not add it
- to the HID system. That is done in hidp_add_connection(). */
-static int hidp_setup_hid(struct hidp_session *session,
- struct hidp_connadd_req *req)
-{
- struct hid_device *hid;
- int err;
-
- session->rd_data = kzalloc(req->rd_size, GFP_KERNEL);
- if (!session->rd_data)
- return -ENOMEM;
-
- if (copy_from_user(session->rd_data, req->rd_data, req->rd_size)) {
- err = -EFAULT;
- goto fault;
- }
- session->rd_size = req->rd_size;
-
- hid = hid_allocate_device();
- if (IS_ERR(hid)) {
- err = PTR_ERR(hid);
- goto fault;
- }
-
- session->hid = hid;
-
- hid->driver_data = session;
-
- hid->bus = BUS_BLUETOOTH;
- hid->vendor = req->vendor;
- hid->product = req->product;
- hid->version = req->version;
- hid->country = req->country;
-
- strncpy(hid->name, req->name, 128);
- strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
- strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
-
- hid->dev.parent = &session->conn->dev;
- hid->ll_driver = &hidp_hid_driver;
-
- hid->hid_get_raw_report = hidp_get_raw_report;
- hid->hid_output_raw_report = hidp_output_raw_report;
-
- return 0;
-
-fault:
- kfree(session->rd_data);
- session->rd_data = NULL;
-
- return err;
-}
-
-int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
-{
- struct hidp_session *session, *s;
- int vendor, product;
- int err;
-
- BT_DBG("");
-
- if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
- bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
- return -ENOTUNIQ;
-
- BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
-
- down_write(&hidp_session_sem);
-
- s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
- if (s && s->state == BT_CONNECTED) {
- up_write(&hidp_session_sem);
- return -EEXIST;
- }
-
- session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
- if (!session) {
- up_write(&hidp_session_sem);
- return -ENOMEM;
- }
-
- bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
-
- session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu,
- l2cap_pi(ctrl_sock->sk)->chan->imtu);
- session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->chan->omtu,
- l2cap_pi(intr_sock->sk)->chan->imtu);
-
- BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
-
- session->ctrl_sock = ctrl_sock;
- session->intr_sock = intr_sock;
- session->state = BT_CONNECTED;
-
- session->conn = hidp_get_connection(session);
- if (!session->conn) {
- err = -ENOTCONN;
- goto failed;
- }
-
- setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
-
- skb_queue_head_init(&session->ctrl_transmit);
- skb_queue_head_init(&session->intr_transmit);
-
- mutex_init(&session->report_mutex);
- init_waitqueue_head(&session->report_queue);
- init_waitqueue_head(&session->startup_queue);
- session->waiting_for_startup = 1;
- session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
- session->idle_to = req->idle_to;
-
- __hidp_link_session(session);
-
- if (req->rd_size > 0) {
- err = hidp_setup_hid(session, req);
- if (err)
- goto purge;
- }
-
- if (!session->hid) {
- err = hidp_setup_input(session, req);
- if (err < 0)
- goto purge;
- }
-
- hidp_set_timer(session);
-
- if (session->hid) {
- vendor = session->hid->vendor;
- product = session->hid->product;
- } else if (session->input) {
- vendor = session->input->id.vendor;
- product = session->input->id.product;
- } else {
- vendor = 0x0000;
- product = 0x0000;
- }
-
- session->task = kthread_run(hidp_session, session, "khidpd_%04x%04x",
- vendor, product);
- if (IS_ERR(session->task)) {
- err = PTR_ERR(session->task);
- goto unlink;
- }
-
- while (session->waiting_for_startup) {
- wait_event_interruptible(session->startup_queue,
- !session->waiting_for_startup);
- }
-
- if (session->hid)
- err = hid_add_device(session->hid);
- else
- err = input_register_device(session->input);
-
- if (err < 0) {
- atomic_inc(&session->terminate);
- wake_up_process(session->task);
- up_write(&hidp_session_sem);
- return err;
- }
-
- if (session->input) {
- hidp_send_ctrl_message(session,
- HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
- session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
-
- session->leds = 0xff;
- hidp_input_event(session->input, EV_LED, 0, 0);
- }
-
- up_write(&hidp_session_sem);
- return 0;
-
-unlink:
- hidp_del_timer(session);
-
- if (session->input) {
- input_unregister_device(session->input);
- session->input = NULL;
- }
-
- if (session->hid) {
- hid_destroy_device(session->hid);
- session->hid = NULL;
- }
-
- kfree(session->rd_data);
- session->rd_data = NULL;
-
-purge:
- __hidp_unlink_session(session);
-
- skb_queue_purge(&session->ctrl_transmit);
- skb_queue_purge(&session->intr_transmit);
-
-failed:
- up_write(&hidp_session_sem);
-
- kfree(session);
- return err;
-}
-
-int hidp_del_connection(struct hidp_conndel_req *req)
-{
- struct hidp_session *session;
- int err = 0;
-
- BT_DBG("");
-
- down_read(&hidp_session_sem);
-
- session = __hidp_get_session(&req->bdaddr);
- if (session) {
- if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
- hidp_send_ctrl_message(session,
- HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
- } else {
- /* Flush the transmit queues */
- skb_queue_purge(&session->ctrl_transmit);
- skb_queue_purge(&session->intr_transmit);
-
- atomic_inc(&session->terminate);
- wake_up_process(session->task);
- }
- } else
- err = -ENOENT;
-
- up_read(&hidp_session_sem);
- return err;
-}
-
-int hidp_get_connlist(struct hidp_connlist_req *req)
-{
- struct hidp_session *session;
- int err = 0, n = 0;
-
- BT_DBG("");
-
- down_read(&hidp_session_sem);
-
- list_for_each_entry(session, &hidp_session_list, list) {
- struct hidp_conninfo ci;
-
- __hidp_copy_session(session, &ci);
-
- if (copy_to_user(req->ci, &ci, sizeof(ci))) {
- err = -EFAULT;
- break;
- }
-
- if (++n >= req->cnum)
- break;
-
- req->ci++;
- }
- req->cnum = n;
-
- up_read(&hidp_session_sem);
- return err;
-}
-
-int hidp_get_conninfo(struct hidp_conninfo *ci)
-{
- struct hidp_session *session;
- int err = 0;
-
- down_read(&hidp_session_sem);
-
- session = __hidp_get_session(&ci->bdaddr);
- if (session)
- __hidp_copy_session(session, ci);
- else
- err = -ENOENT;
-
- up_read(&hidp_session_sem);
- return err;
-}
-
-static const struct hid_device_id hidp_table[] = {
- { HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
- { }
-};
-
-static struct hid_driver hidp_driver = {
- .name = "generic-bluetooth",
- .id_table = hidp_table,
-};
-
-static int __init hidp_init(void)
-{
- int ret;
-
- BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
-
- ret = hid_register_driver(&hidp_driver);
- if (ret)
- goto err;
-
- ret = hidp_init_sockets();
- if (ret)
- goto err_drv;
-
- return 0;
-err_drv:
- hid_unregister_driver(&hidp_driver);
-err:
- return ret;
-}
-
-static void __exit hidp_exit(void)
-{
- hidp_cleanup_sockets();
- hid_unregister_driver(&hidp_driver);
-}
-
-module_init(hidp_init);
-module_exit(hidp_exit);
-
-MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("bt-proto-6");
diff --git a/net/bluetooth_tizen/hidp/hidp.h b/net/bluetooth_tizen/hidp/hidp.h
deleted file mode 100644
index af1bcc8..0000000
--- a/net/bluetooth_tizen/hidp/hidp.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- HIDP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#ifndef __HIDP_H
-#define __HIDP_H
-
-#include <linux/types.h>
-#include <net/bluetooth/bluetooth.h>
-
-/* HIDP header masks */
-#define HIDP_HEADER_TRANS_MASK 0xf0
-#define HIDP_HEADER_PARAM_MASK 0x0f
-
-/* HIDP transaction types */
-#define HIDP_TRANS_HANDSHAKE 0x00
-#define HIDP_TRANS_HID_CONTROL 0x10
-#define HIDP_TRANS_GET_REPORT 0x40
-#define HIDP_TRANS_SET_REPORT 0x50
-#define HIDP_TRANS_GET_PROTOCOL 0x60
-#define HIDP_TRANS_SET_PROTOCOL 0x70
-#define HIDP_TRANS_GET_IDLE 0x80
-#define HIDP_TRANS_SET_IDLE 0x90
-#define HIDP_TRANS_DATA 0xa0
-#define HIDP_TRANS_DATC 0xb0
-
-/* HIDP handshake results */
-#define HIDP_HSHK_SUCCESSFUL 0x00
-#define HIDP_HSHK_NOT_READY 0x01
-#define HIDP_HSHK_ERR_INVALID_REPORT_ID 0x02
-#define HIDP_HSHK_ERR_UNSUPPORTED_REQUEST 0x03
-#define HIDP_HSHK_ERR_INVALID_PARAMETER 0x04
-#define HIDP_HSHK_ERR_UNKNOWN 0x0e
-#define HIDP_HSHK_ERR_FATAL 0x0f
-
-/* HIDP control operation parameters */
-#define HIDP_CTRL_NOP 0x00
-#define HIDP_CTRL_HARD_RESET 0x01
-#define HIDP_CTRL_SOFT_RESET 0x02
-#define HIDP_CTRL_SUSPEND 0x03
-#define HIDP_CTRL_EXIT_SUSPEND 0x04
-#define HIDP_CTRL_VIRTUAL_CABLE_UNPLUG 0x05
-
-/* HIDP data transaction headers */
-#define HIDP_DATA_RTYPE_MASK 0x03
-#define HIDP_DATA_RSRVD_MASK 0x0c
-#define HIDP_DATA_RTYPE_OTHER 0x00
-#define HIDP_DATA_RTYPE_INPUT 0x01
-#define HIDP_DATA_RTYPE_OUPUT 0x02
-#define HIDP_DATA_RTYPE_FEATURE 0x03
-
-/* HIDP protocol header parameters */
-#define HIDP_PROTO_BOOT 0x00
-#define HIDP_PROTO_REPORT 0x01
-
-/* HIDP ioctl defines */
-#define HIDPCONNADD _IOW('H', 200, int)
-#define HIDPCONNDEL _IOW('H', 201, int)
-#define HIDPGETCONNLIST _IOR('H', 210, int)
-#define HIDPGETCONNINFO _IOR('H', 211, int)
-
-#define HIDP_VIRTUAL_CABLE_UNPLUG 0
-#define HIDP_BOOT_PROTOCOL_MODE 1
-#define HIDP_BLUETOOTH_VENDOR_ID 9
-#define HIDP_WAITING_FOR_RETURN 10
-#define HIDP_WAITING_FOR_SEND_ACK 11
-
-struct hidp_connadd_req {
- int ctrl_sock; /* Connected control socket */
- int intr_sock; /* Connected interrupt socket */
- __u16 parser;
- __u16 rd_size;
- __u8 __user *rd_data;
- __u8 country;
- __u8 subclass;
- __u16 vendor;
- __u16 product;
- __u16 version;
- __u32 flags;
- __u32 idle_to;
- char name[128];
-};
-
-struct hidp_conndel_req {
- bdaddr_t bdaddr;
- __u32 flags;
-};
-
-struct hidp_conninfo {
- bdaddr_t bdaddr;
- __u32 flags;
- __u16 state;
- __u16 vendor;
- __u16 product;
- __u16 version;
- char name[128];
-};
-
-struct hidp_connlist_req {
- __u32 cnum;
- struct hidp_conninfo __user *ci;
-};
-
-int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock);
-int hidp_del_connection(struct hidp_conndel_req *req);
-int hidp_get_connlist(struct hidp_connlist_req *req);
-int hidp_get_conninfo(struct hidp_conninfo *ci);
-
-/* HIDP session defines */
-struct hidp_session {
- struct list_head list;
-
- struct hci_conn *conn;
-
- struct socket *ctrl_sock;
- struct socket *intr_sock;
-
- bdaddr_t bdaddr;
-
- unsigned long state;
- unsigned long flags;
- unsigned long idle_to;
-
- uint ctrl_mtu;
- uint intr_mtu;
-
- atomic_t terminate;
- struct task_struct *task;
-
- unsigned char keys[8];
- unsigned char leds;
-
- struct input_dev *input;
-
- struct hid_device *hid;
-
- struct timer_list timer;
-
- struct sk_buff_head ctrl_transmit;
- struct sk_buff_head intr_transmit;
-
- /* Used in hidp_get_raw_report() */
- int waiting_report_type; /* HIDP_DATA_RTYPE_* */
- int waiting_report_number; /* -1 for not numbered */
- struct mutex report_mutex;
- struct sk_buff *report_return;
- wait_queue_head_t report_queue;
-
- /* Used in hidp_output_raw_report() */
- int output_report_success; /* boolean */
-
- /* Report descriptor */
- __u8 *rd_data;
- uint rd_size;
-
- wait_queue_head_t startup_queue;
- int waiting_for_startup;
-};
-
-static inline void hidp_schedule(struct hidp_session *session)
-{
- struct sock *ctrl_sk = session->ctrl_sock->sk;
- struct sock *intr_sk = session->intr_sock->sk;
-
- wake_up_interruptible(sk_sleep(ctrl_sk));
- wake_up_interruptible(sk_sleep(intr_sk));
-}
-
-/* HIDP init defines */
-extern int __init hidp_init_sockets(void);
-extern void __exit hidp_cleanup_sockets(void);
-
-#endif /* __HIDP_H */
diff --git a/net/bluetooth_tizen/hidp/sock.c b/net/bluetooth_tizen/hidp/sock.c
deleted file mode 100644
index 73a32d7..0000000
--- a/net/bluetooth_tizen/hidp/sock.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- HIDP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <linux/file.h>
-#include <linux/init.h>
-#include <linux/compat.h>
-#include <linux/gfp.h>
-#include <net/sock.h>
-
-#include "hidp.h"
-
-static int hidp_sock_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
-
- BT_DBG("sock %p sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
- sock_orphan(sk);
- sock_put(sk);
-
- return 0;
-}
-
-static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- void __user *argp = (void __user *) arg;
- struct hidp_connadd_req ca;
- struct hidp_conndel_req cd;
- struct hidp_connlist_req cl;
- struct hidp_conninfo ci;
- struct socket *csock;
- struct socket *isock;
- int err;
-
- BT_DBG("cmd %x arg %lx", cmd, arg);
-
- switch (cmd) {
- case HIDPCONNADD:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
-
- if (copy_from_user(&ca, argp, sizeof(ca)))
- return -EFAULT;
-
- csock = sockfd_lookup(ca.ctrl_sock, &err);
- if (!csock)
- return err;
-
- isock = sockfd_lookup(ca.intr_sock, &err);
- if (!isock) {
- sockfd_put(csock);
- return err;
- }
-
- if (csock->sk->sk_state != BT_CONNECTED ||
- isock->sk->sk_state != BT_CONNECTED) {
- sockfd_put(csock);
- sockfd_put(isock);
- return -EBADFD;
- }
-
- err = hidp_add_connection(&ca, csock, isock);
- if (!err) {
- if (copy_to_user(argp, &ca, sizeof(ca)))
- err = -EFAULT;
- } else {
- sockfd_put(csock);
- sockfd_put(isock);
- }
-
- return err;
-
- case HIDPCONNDEL:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
-
- if (copy_from_user(&cd, argp, sizeof(cd)))
- return -EFAULT;
-
- return hidp_del_connection(&cd);
-
- case HIDPGETCONNLIST:
- if (copy_from_user(&cl, argp, sizeof(cl)))
- return -EFAULT;
-
- if (cl.cnum <= 0)
- return -EINVAL;
-
- err = hidp_get_connlist(&cl);
- if (!err && copy_to_user(argp, &cl, sizeof(cl)))
- return -EFAULT;
-
- return err;
-
- case HIDPGETCONNINFO:
- if (copy_from_user(&ci, argp, sizeof(ci)))
- return -EFAULT;
-
- err = hidp_get_conninfo(&ci);
- if (!err && copy_to_user(argp, &ci, sizeof(ci)))
- return -EFAULT;
-
- return err;
- }
-
- return -EINVAL;
-}
-
-#ifdef CONFIG_COMPAT
-struct compat_hidp_connadd_req {
- int ctrl_sock; /* Connected control socket */
- int intr_sock; /* Connected interrupt socket */
- __u16 parser;
- __u16 rd_size;
- compat_uptr_t rd_data;
- __u8 country;
- __u8 subclass;
- __u16 vendor;
- __u16 product;
- __u16 version;
- __u32 flags;
- __u32 idle_to;
- char name[128];
-};
-
-static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- if (cmd == HIDPGETCONNLIST) {
- struct hidp_connlist_req cl;
- u32 uci;
- int err;
-
- if (get_user(cl.cnum, (u32 __user *) arg) ||
- get_user(uci, (u32 __user *) (arg + 4)))
- return -EFAULT;
-
- cl.ci = compat_ptr(uci);
-
- if (cl.cnum <= 0)
- return -EINVAL;
-
- err = hidp_get_connlist(&cl);
-
- if (!err && put_user(cl.cnum, (u32 __user *) arg))
- err = -EFAULT;
-
- return err;
- } else if (cmd == HIDPCONNADD) {
- struct compat_hidp_connadd_req ca;
- struct hidp_connadd_req __user *uca;
-
- uca = compat_alloc_user_space(sizeof(*uca));
-
- if (copy_from_user(&ca, (void __user *) arg, sizeof(ca)))
- return -EFAULT;
-
- if (put_user(ca.ctrl_sock, &uca->ctrl_sock) ||
- put_user(ca.intr_sock, &uca->intr_sock) ||
- put_user(ca.parser, &uca->parser) ||
- put_user(ca.rd_size, &uca->rd_size) ||
- put_user(compat_ptr(ca.rd_data), &uca->rd_data) ||
- put_user(ca.country, &uca->country) ||
- put_user(ca.subclass, &uca->subclass) ||
- put_user(ca.vendor, &uca->vendor) ||
- put_user(ca.product, &uca->product) ||
- put_user(ca.version, &uca->version) ||
- put_user(ca.flags, &uca->flags) ||
- put_user(ca.idle_to, &uca->idle_to) ||
- copy_to_user(&uca->name[0], &ca.name[0], 128))
- return -EFAULT;
-
- arg = (unsigned long) uca;
-
- /* Fall through. We don't actually write back any _changes_
- to the structure anyway, so there's no need to copy back
- into the original compat version */
- }
-
- return hidp_sock_ioctl(sock, cmd, arg);
-}
-#endif
-
-static const struct proto_ops hidp_sock_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .release = hidp_sock_release,
- .ioctl = hidp_sock_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = hidp_sock_compat_ioctl,
-#endif
- .bind = sock_no_bind,
- .getname = sock_no_getname,
- .sendmsg = sock_no_sendmsg,
- .recvmsg = sock_no_recvmsg,
- .poll = sock_no_poll,
- .listen = sock_no_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = sock_no_setsockopt,
- .getsockopt = sock_no_getsockopt,
- .connect = sock_no_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .mmap = sock_no_mmap
-};
-
-static struct proto hidp_proto = {
- .name = "HIDP",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct bt_sock)
-};
-
-static int hidp_sock_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
-
- BT_DBG("sock %p", sock);
-
- if (sock->type != SOCK_RAW)
- return -ESOCKTNOSUPPORT;
-
- sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto);
- if (!sk)
- return -ENOMEM;
-
- sock_init_data(sock, sk);
-
- sock->ops = &hidp_sock_ops;
-
- sock->state = SS_UNCONNECTED;
-
- sock_reset_flag(sk, SOCK_ZAPPED);
-
- sk->sk_protocol = protocol;
- sk->sk_state = BT_OPEN;
-
- return 0;
-}
-
-static const struct net_proto_family hidp_sock_family_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .create = hidp_sock_create
-};
-
-int __init hidp_init_sockets(void)
-{
- int err;
-
- err = proto_register(&hidp_proto, 0);
- if (err < 0)
- return err;
-
- err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
- if (err < 0)
- goto error;
-
- return 0;
-
-error:
- BT_ERR("Can't register HIDP socket");
- proto_unregister(&hidp_proto);
- return err;
-}
-
-void __exit hidp_cleanup_sockets(void)
-{
- if (bt_sock_unregister(BTPROTO_HIDP) < 0)
- BT_ERR("Can't unregister HIDP socket");
-
- proto_unregister(&hidp_proto);
-}
diff --git a/net/bluetooth_tizen/l2cap_core.c b/net/bluetooth_tizen/l2cap_core.c
deleted file mode 100644
index 48268ab..0000000
--- a/net/bluetooth_tizen/l2cap_core.c
+++ /dev/null
@@ -1,4803 +0,0 @@
-/*
- BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
- Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
- Copyright (C) 2010 Google Inc.
- Copyright (C) 2011 ProFUSION Embedded Systems
-
- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/* Bluetooth L2CAP core. */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/socket.h>
-#include <linux/skbuff.h>
-#include <linux/list.h>
-#include <linux/device.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/uaccess.h>
-#include <linux/crc16.h>
-#include <net/sock.h>
-
-#include <asm/system.h>
-#include <asm/unaligned.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/l2cap.h>
-#include <net/bluetooth/smp.h>
-
-bool disable_ertm;
-
-static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
-static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
-
-static LIST_HEAD(chan_list);
-static DEFINE_RWLOCK(chan_list_lock);
-
-static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
- u8 code, u8 ident, u16 dlen, void *data);
-static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
- void *data);
-static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
-static void l2cap_send_disconn_req(struct l2cap_conn *conn,
- struct l2cap_chan *chan, int err);
-
-/* ---- L2CAP channels ---- */
-
-static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
-{
- struct l2cap_chan *c;
-
- list_for_each_entry(c, &conn->chan_l, list) {
- if (c->dcid == cid)
- return c;
- }
- return NULL;
-}
-
-static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
-{
- struct l2cap_chan *c;
-
- list_for_each_entry(c, &conn->chan_l, list) {
- if (c->scid == cid)
- return c;
- }
- return NULL;
-}
-
-/* Find channel with given SCID.
- * Returns locked channel. */
-static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
-{
- struct l2cap_chan *c;
-
- mutex_lock(&conn->chan_lock);
- c = __l2cap_get_chan_by_scid(conn, cid);
- if (c)
- l2cap_chan_lock(c);
- mutex_unlock(&conn->chan_lock);
-
- return c;
-}
-
-static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
-{
- struct l2cap_chan *c;
-
- list_for_each_entry(c, &conn->chan_l, list) {
- if (c->ident == ident)
- return c;
- }
- return NULL;
-}
-
-static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
-{
- struct l2cap_chan *c;
-
- mutex_lock(&conn->chan_lock);
- c = __l2cap_get_chan_by_ident(conn, ident);
- mutex_unlock(&conn->chan_lock);
-
- return c;
-}
-
-static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
-{
- struct l2cap_chan *c;
-
- list_for_each_entry(c, &chan_list, global_l) {
- if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
- return c;
- }
- return NULL;
-}
-
-int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
-{
- int err;
-
- write_lock(&chan_list_lock);
-
- if (psm && __l2cap_global_chan_by_addr(psm, src)) {
- err = -EADDRINUSE;
- goto done;
- }
-
- if (psm) {
- chan->psm = psm;
- chan->sport = psm;
- err = 0;
- } else {
- u16 p;
-
- err = -EINVAL;
- for (p = 0x1001; p < 0x1100; p += 2)
- if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
- chan->psm = cpu_to_le16(p);
- chan->sport = cpu_to_le16(p);
- err = 0;
- break;
- }
- }
-
-done:
- write_unlock(&chan_list_lock);
- return err;
-}
-
-int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
-{
- write_lock(&chan_list_lock);
-
- chan->scid = scid;
-
- write_unlock(&chan_list_lock);
-
- return 0;
-}
-
-static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
-{
- u16 cid = L2CAP_CID_DYN_START;
-
- for (; cid < L2CAP_CID_DYN_END; cid++) {
- if (!__l2cap_get_chan_by_scid(conn, cid))
- return cid;
- }
-
- return 0;
-}
-
-static void __l2cap_state_change(struct l2cap_chan *chan, int state)
-{
- BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state),
- state_to_string(state));
-
- chan->state = state;
- chan->ops->state_change(chan->data, state);
-}
-
-static void l2cap_state_change(struct l2cap_chan *chan, int state)
-{
- struct sock *sk = chan->sk;
-
- lock_sock(sk);
- __l2cap_state_change(chan, state);
- release_sock(sk);
-}
-
-static inline void __l2cap_chan_set_err(struct l2cap_chan *chan, int err)
-{
- struct sock *sk = chan->sk;
-
- sk->sk_err = err;
-}
-
-static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
-{
- struct sock *sk = chan->sk;
-
- lock_sock(sk);
- __l2cap_chan_set_err(chan, err);
- release_sock(sk);
-}
-
-static void l2cap_chan_timeout(struct work_struct *work)
-{
- struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
- chan_timer.work);
- struct l2cap_conn *conn = chan->conn;
- int reason;
-
- BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
-
- mutex_lock(&conn->chan_lock);
- l2cap_chan_lock(chan);
-
- if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
- reason = ECONNREFUSED;
- else if (chan->state == BT_CONNECT &&
- chan->sec_level != BT_SECURITY_SDP)
- reason = ECONNREFUSED;
- else
- reason = ETIMEDOUT;
-
- l2cap_chan_close(chan, reason);
-
- l2cap_chan_unlock(chan);
-
- chan->ops->close(chan->data);
- mutex_unlock(&conn->chan_lock);
-
- l2cap_chan_put(chan);
-}
-
-struct l2cap_chan *l2cap_chan_create(struct sock *sk)
-{
- struct l2cap_chan *chan;
-
- chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
- if (!chan)
- return NULL;
-
- mutex_init(&chan->lock);
-
- chan->sk = sk;
-
- write_lock(&chan_list_lock);
- list_add(&chan->global_l, &chan_list);
- write_unlock(&chan_list_lock);
-
- INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
-
- chan->state = BT_OPEN;
-
- atomic_set(&chan->refcnt, 1);
-
- BT_DBG("sk %p chan %p", sk, chan);
-
- return chan;
-}
-
-void l2cap_chan_destroy(struct l2cap_chan *chan)
-{
- write_lock(&chan_list_lock);
- list_del(&chan->global_l);
- write_unlock(&chan_list_lock);
-
- l2cap_chan_put(chan);
-}
-
-void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
-{
- BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
- chan->psm, chan->dcid);
-
- conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
-
- chan->conn = conn;
-
- switch (chan->chan_type) {
- case L2CAP_CHAN_CONN_ORIENTED:
- if (conn->hcon->type == LE_LINK) {
- /* LE connection */
- chan->omtu = L2CAP_LE_DEFAULT_MTU;
- chan->scid = L2CAP_CID_LE_DATA;
- chan->dcid = L2CAP_CID_LE_DATA;
- } else {
- /* Alloc CID for connection-oriented socket */
- chan->scid = l2cap_alloc_cid(conn);
- chan->omtu = L2CAP_DEFAULT_MTU;
- }
- break;
-
- case L2CAP_CHAN_CONN_LESS:
- /* Connectionless socket */
- chan->scid = L2CAP_CID_CONN_LESS;
- chan->dcid = L2CAP_CID_CONN_LESS;
- chan->omtu = L2CAP_DEFAULT_MTU;
- break;
-
- default:
- /* Raw socket can send/recv signalling messages only */
- chan->scid = L2CAP_CID_SIGNALING;
- chan->dcid = L2CAP_CID_SIGNALING;
- chan->omtu = L2CAP_DEFAULT_MTU;
- }
-
- chan->local_id = L2CAP_BESTEFFORT_ID;
- chan->local_stype = L2CAP_SERV_BESTEFFORT;
- chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
- chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
- chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
- chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
-
- l2cap_chan_hold(chan);
-
- list_add(&chan->list, &conn->chan_l);
-}
-
-void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
-{
- mutex_lock(&conn->chan_lock);
- __l2cap_chan_add(conn, chan);
- mutex_unlock(&conn->chan_lock);
-}
-
-static void l2cap_chan_del(struct l2cap_chan *chan, int err)
-{
- struct sock *sk = chan->sk;
- struct l2cap_conn *conn = chan->conn;
- struct sock *parent = bt_sk(sk)->parent;
-
- __clear_chan_timer(chan);
-
- BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
-
- if (conn) {
- /* Delete from channel list */
- list_del(&chan->list);
-
- l2cap_chan_put(chan);
-
- chan->conn = NULL;
- hci_conn_put(conn->hcon);
- }
-
- lock_sock(sk);
-
- __l2cap_state_change(chan, BT_CLOSED);
- sock_set_flag(sk, SOCK_ZAPPED);
-
- if (err)
- __l2cap_chan_set_err(chan, err);
-
- if (parent) {
- bt_accept_unlink(sk);
- parent->sk_data_ready(parent, 0);
- } else
- sk->sk_state_change(sk);
-
- release_sock(sk);
-
- if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
- test_bit(CONF_INPUT_DONE, &chan->conf_state)))
- return;
-
- skb_queue_purge(&chan->tx_q);
-
- if (chan->mode == L2CAP_MODE_ERTM) {
- struct srej_list *l, *tmp;
-
- __clear_retrans_timer(chan);
- __clear_monitor_timer(chan);
- __clear_ack_timer(chan);
-
- skb_queue_purge(&chan->srej_q);
-
- list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
- list_del(&l->list);
- kfree(l);
- }
- }
-}
-
-static void l2cap_chan_cleanup_listen(struct sock *parent)
-{
- struct sock *sk;
-
- BT_DBG("parent %p", parent);
-
- /* Close not yet accepted channels */
- while ((sk = bt_accept_dequeue(parent, NULL))) {
- struct l2cap_chan *chan = l2cap_pi(sk)->chan;
-
- l2cap_chan_lock(chan);
- __clear_chan_timer(chan);
- l2cap_chan_close(chan, ECONNRESET);
- l2cap_chan_unlock(chan);
-
- chan->ops->close(chan->data);
- }
-}
-
-void l2cap_chan_close(struct l2cap_chan *chan, int reason)
-{
- struct l2cap_conn *conn = chan->conn;
- struct sock *sk = chan->sk;
-
- BT_DBG("chan %p state %s sk %p", chan,
- state_to_string(chan->state), sk);
-
- switch (chan->state) {
- case BT_LISTEN:
- lock_sock(sk);
- l2cap_chan_cleanup_listen(sk);
-
- __l2cap_state_change(chan, BT_CLOSED);
- sock_set_flag(sk, SOCK_ZAPPED);
- release_sock(sk);
- break;
-
- case BT_CONNECTED:
- case BT_CONFIG:
- if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
- conn->hcon->type == ACL_LINK) {
- __clear_chan_timer(chan);
- __set_chan_timer(chan, sk->sk_sndtimeo);
- l2cap_send_disconn_req(conn, chan, reason);
- } else
- l2cap_chan_del(chan, reason);
- break;
-
- case BT_CONNECT2:
- if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
- conn->hcon->type == ACL_LINK) {
- struct l2cap_conn_rsp rsp;
- __u16 result;
-
- if (bt_sk(sk)->defer_setup)
- result = L2CAP_CR_SEC_BLOCK;
- else
- result = L2CAP_CR_BAD_PSM;
- l2cap_state_change(chan, BT_DISCONN);
-
- rsp.scid = cpu_to_le16(chan->dcid);
- rsp.dcid = cpu_to_le16(chan->scid);
- rsp.result = cpu_to_le16(result);
- rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
- l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
- sizeof(rsp), &rsp);
- }
-
- l2cap_chan_del(chan, reason);
- break;
-
- case BT_CONNECT:
- case BT_DISCONN:
- l2cap_chan_del(chan, reason);
- break;
-
- default:
- lock_sock(sk);
- sock_set_flag(sk, SOCK_ZAPPED);
- release_sock(sk);
- break;
- }
-}
-
-static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
-{
- if (chan->chan_type == L2CAP_CHAN_RAW) {
- switch (chan->sec_level) {
- case BT_SECURITY_HIGH:
- return HCI_AT_DEDICATED_BONDING_MITM;
- case BT_SECURITY_MEDIUM:
- return HCI_AT_DEDICATED_BONDING;
- default:
- return HCI_AT_NO_BONDING;
- }
- } else if (chan->psm == cpu_to_le16(0x0001)) {
- if (chan->sec_level == BT_SECURITY_LOW)
- chan->sec_level = BT_SECURITY_SDP;
-
- if (chan->sec_level == BT_SECURITY_HIGH)
- return HCI_AT_NO_BONDING_MITM;
- else
- return HCI_AT_NO_BONDING;
- } else {
- switch (chan->sec_level) {
- case BT_SECURITY_HIGH:
- return HCI_AT_GENERAL_BONDING_MITM;
- case BT_SECURITY_MEDIUM:
- return HCI_AT_GENERAL_BONDING;
- default:
- return HCI_AT_NO_BONDING;
- }
- }
-}
-
-/* Service level security */
-int l2cap_chan_check_security(struct l2cap_chan *chan)
-{
- struct l2cap_conn *conn = chan->conn;
- __u8 auth_type;
-
- auth_type = l2cap_get_auth_type(chan);
-
- return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
-}
-
-static u8 l2cap_get_ident(struct l2cap_conn *conn)
-{
- u8 id;
-
- /* Get next available identificator.
- * 1 - 128 are used by kernel.
- * 129 - 199 are reserved.
- * 200 - 254 are used by utilities like l2ping, etc.
- */
-
- spin_lock(&conn->lock);
-
- if (++conn->tx_ident > 128)
- conn->tx_ident = 1;
-
- id = conn->tx_ident;
-
- spin_unlock(&conn->lock);
-
- return id;
-}
-
-static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
-{
- struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
- u8 flags;
-
- BT_DBG("code 0x%2.2x", code);
-
- if (!skb)
- return;
-
- if (lmp_no_flush_capable(conn->hcon->hdev))
- flags = ACL_START_NO_FLUSH;
- else
- flags = ACL_START;
-
- bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
- skb->priority = HCI_PRIO_MAX;
-
- hci_send_acl(conn->hchan, skb, flags);
-}
-
-static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
-{
- struct hci_conn *hcon = chan->conn->hcon;
- u16 flags;
-
- BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
- skb->priority);
-
- if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
- lmp_no_flush_capable(hcon->hdev))
- flags = ACL_START_NO_FLUSH;
- else
- flags = ACL_START;
-
- bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
- hci_send_acl(chan->conn->hchan, skb, flags);
-}
-
-static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
-{
- struct sk_buff *skb;
- struct l2cap_hdr *lh;
- struct l2cap_conn *conn = chan->conn;
- int count, hlen;
-
- if (chan->state != BT_CONNECTED)
- return;
-
- if (test_bit(FLAG_EXT_CTRL, &chan->flags))
- hlen = L2CAP_EXT_HDR_SIZE;
- else
- hlen = L2CAP_ENH_HDR_SIZE;
-
- if (chan->fcs == L2CAP_FCS_CRC16)
- hlen += L2CAP_FCS_SIZE;
-
- BT_DBG("chan %p, control 0x%8.8x", chan, control);
-
- count = min_t(unsigned int, conn->mtu, hlen);
-
- control |= __set_sframe(chan);
-
- if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
- control |= __set_ctrl_final(chan);
-
- if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
- control |= __set_ctrl_poll(chan);
-
- skb = bt_skb_alloc(count, GFP_ATOMIC);
- if (!skb)
- return;
-
- lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
- lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
- lh->cid = cpu_to_le16(chan->dcid);
-
- __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
-
- if (chan->fcs == L2CAP_FCS_CRC16) {
- u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
- put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
- }
-
- skb->priority = HCI_PRIO_MAX;
- l2cap_do_send(chan, skb);
-}
-
-static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
-{
- if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
- control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
- set_bit(CONN_RNR_SENT, &chan->conn_state);
- } else
- control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
-
- control |= __set_reqseq(chan, chan->buffer_seq);
-
- l2cap_send_sframe(chan, control);
-}
-
-static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
-{
- return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
-}
-
-static void l2cap_send_conn_req(struct l2cap_chan *chan)
-{
- struct l2cap_conn *conn = chan->conn;
- struct l2cap_conn_req req;
-
- req.scid = cpu_to_le16(chan->scid);
- req.psm = chan->psm;
-
- chan->ident = l2cap_get_ident(conn);
-
- set_bit(CONF_CONNECT_PEND, &chan->conf_state);
-
- l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
-}
-
-static void l2cap_do_start(struct l2cap_chan *chan)
-{
- struct l2cap_conn *conn = chan->conn;
-
- if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
- if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
- return;
-
- if (l2cap_chan_check_security(chan) &&
- __l2cap_no_conn_pending(chan))
- l2cap_send_conn_req(chan);
- } else {
- struct l2cap_info_req req;
- req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
-
- conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
- conn->info_ident = l2cap_get_ident(conn);
-
- schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
-
- l2cap_send_cmd(conn, conn->info_ident,
- L2CAP_INFO_REQ, sizeof(req), &req);
- }
-}
-
-static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
-{
- u32 local_feat_mask = l2cap_feat_mask;
- if (!disable_ertm)
- local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
-
- switch (mode) {
- case L2CAP_MODE_ERTM:
- return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
- case L2CAP_MODE_STREAMING:
- return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
- default:
- return 0x00;
- }
-}
-
-static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
-{
- struct sock *sk = chan->sk;
- struct l2cap_disconn_req req;
-
- if (!conn)
- return;
-
- if (chan->mode == L2CAP_MODE_ERTM) {
- __clear_retrans_timer(chan);
- __clear_monitor_timer(chan);
- __clear_ack_timer(chan);
- }
-
- req.dcid = cpu_to_le16(chan->dcid);
- req.scid = cpu_to_le16(chan->scid);
- l2cap_send_cmd(conn, l2cap_get_ident(conn),
- L2CAP_DISCONN_REQ, sizeof(req), &req);
-
- lock_sock(sk);
- __l2cap_state_change(chan, BT_DISCONN);
- __l2cap_chan_set_err(chan, err);
- release_sock(sk);
-}
-
-/* ---- L2CAP connections ---- */
-static void l2cap_conn_start(struct l2cap_conn *conn)
-{
- struct l2cap_chan *chan, *tmp;
-
- BT_DBG("conn %p", conn);
-
- mutex_lock(&conn->chan_lock);
-
- list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
- struct sock *sk = chan->sk;
-
- l2cap_chan_lock(chan);
-
- if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
- l2cap_chan_unlock(chan);
- continue;
- }
-
- if (chan->state == BT_CONNECT) {
- if (!l2cap_chan_check_security(chan) ||
- !__l2cap_no_conn_pending(chan)) {
- l2cap_chan_unlock(chan);
- continue;
- }
-
- if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
- && test_bit(CONF_STATE2_DEVICE,
- &chan->conf_state)) {
- l2cap_chan_close(chan, ECONNRESET);
- l2cap_chan_unlock(chan);
- continue;
- }
-
- l2cap_send_conn_req(chan);
-
- } else if (chan->state == BT_CONNECT2) {
- struct l2cap_conn_rsp rsp;
- char buf[128];
- rsp.scid = cpu_to_le16(chan->dcid);
- rsp.dcid = cpu_to_le16(chan->scid);
-
- if (l2cap_chan_check_security(chan)) {
- lock_sock(sk);
- if (bt_sk(sk)->defer_setup) {
- struct sock *parent = bt_sk(sk)->parent;
- rsp.result = cpu_to_le16(L2CAP_CR_PEND);
- rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
- if (parent)
- parent->sk_data_ready(parent, 0);
-
- } else {
- __l2cap_state_change(chan, BT_CONFIG);
- rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
- rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
- }
- release_sock(sk);
- } else {
- rsp.result = cpu_to_le16(L2CAP_CR_PEND);
- rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
- }
-
- l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
- sizeof(rsp), &rsp);
-
- if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
- rsp.result != L2CAP_CR_SUCCESS) {
- l2cap_chan_unlock(chan);
- continue;
- }
-
- set_bit(CONF_REQ_SENT, &chan->conf_state);
- l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
- l2cap_build_conf_req(chan, buf), buf);
- chan->num_conf_req++;
- }
-
- l2cap_chan_unlock(chan);
- }
-
- mutex_unlock(&conn->chan_lock);
-}
-
-/* Find socket with cid and source bdaddr.
- * Returns closest match, locked.
- */
-static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
-{
- struct l2cap_chan *c, *c1 = NULL;
-
- read_lock(&chan_list_lock);
-
- list_for_each_entry(c, &chan_list, global_l) {
- struct sock *sk = c->sk;
-
- if (state && c->state != state)
- continue;
-
- if (c->scid == cid) {
- /* Exact match. */
- if (!bacmp(&bt_sk(sk)->src, src)) {
- read_unlock(&chan_list_lock);
- return c;
- }
-
- /* Closest match */
- if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
- c1 = c;
- }
- }
-
- read_unlock(&chan_list_lock);
-
- return c1;
-}
-
-static void l2cap_le_conn_ready(struct l2cap_conn *conn)
-{
- struct sock *parent, *sk;
- struct l2cap_chan *chan, *pchan;
-
- BT_DBG("");
-
- /* Check if we have socket listening on cid */
- pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
- conn->src);
- if (!pchan)
- return;
-
- parent = pchan->sk;
-
- lock_sock(parent);
-
- /* Check for backlog size */
- if (sk_acceptq_is_full(parent)) {
- BT_DBG("backlog full %d", parent->sk_ack_backlog);
- goto clean;
- }
-
- chan = pchan->ops->new_connection(pchan->data);
- if (!chan)
- goto clean;
-
- sk = chan->sk;
-
- hci_conn_hold(conn->hcon);
-
- bacpy(&bt_sk(sk)->src, conn->src);
- bacpy(&bt_sk(sk)->dst, conn->dst);
-
- bt_accept_enqueue(parent, sk);
-
- l2cap_chan_add(conn, chan);
-
- __set_chan_timer(chan, sk->sk_sndtimeo);
-
- __l2cap_state_change(chan, BT_CONNECTED);
- parent->sk_data_ready(parent, 0);
-
-clean:
- release_sock(parent);
-}
-
-static void l2cap_chan_ready(struct l2cap_chan *chan)
-{
- struct sock *sk = chan->sk;
- struct sock *parent;
-
- lock_sock(sk);
-
- parent = bt_sk(sk)->parent;
-
- BT_DBG("sk %p, parent %p", sk, parent);
-
- chan->conf_state = 0;
- __clear_chan_timer(chan);
-
- __l2cap_state_change(chan, BT_CONNECTED);
- sk->sk_state_change(sk);
-
- if (parent)
- parent->sk_data_ready(parent, 0);
-
- release_sock(sk);
-}
-
-static void l2cap_conn_ready(struct l2cap_conn *conn)
-{
- struct l2cap_chan *chan;
-
- BT_DBG("conn %p", conn);
-
- if (!conn->hcon->out && conn->hcon->type == LE_LINK)
- l2cap_le_conn_ready(conn);
-
- if (conn->hcon->out && conn->hcon->type == LE_LINK)
- smp_conn_security(conn, conn->hcon->pending_sec_level);
-
- mutex_lock(&conn->chan_lock);
-
- list_for_each_entry(chan, &conn->chan_l, list) {
-
- l2cap_chan_lock(chan);
-
- if (conn->hcon->type == LE_LINK) {
- if (smp_conn_security(conn, chan->sec_level))
- l2cap_chan_ready(chan);
-
- } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
- struct sock *sk = chan->sk;
- __clear_chan_timer(chan);
- lock_sock(sk);
- __l2cap_state_change(chan, BT_CONNECTED);
- sk->sk_state_change(sk);
- release_sock(sk);
-
- } else if (chan->state == BT_CONNECT)
- l2cap_do_start(chan);
-
- l2cap_chan_unlock(chan);
- }
-
- mutex_unlock(&conn->chan_lock);
-}
-
-/* Notify sockets that we cannot guaranty reliability anymore */
-static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
-{
- struct l2cap_chan *chan;
-
- BT_DBG("conn %p", conn);
-
- mutex_lock(&conn->chan_lock);
-
- list_for_each_entry(chan, &conn->chan_l, list) {
- if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
- __l2cap_chan_set_err(chan, err);
- }
-
- mutex_unlock(&conn->chan_lock);
-}
-
-static void l2cap_info_timeout(struct work_struct *work)
-{
- struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
- info_timer.work);
-
- conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
- conn->info_ident = 0;
-
- l2cap_conn_start(conn);
-}
-
-static void l2cap_conn_del(struct hci_conn *hcon, int err)
-{
- struct l2cap_conn *conn = hcon->l2cap_data;
- struct l2cap_chan *chan, *l;
-
- if (!conn)
- return;
-
- BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
-
- kfree_skb(conn->rx_skb);
-
- mutex_lock(&conn->chan_lock);
-
- /* Kill channels */
- list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
- l2cap_chan_lock(chan);
-
- l2cap_chan_del(chan, err);
-
- l2cap_chan_unlock(chan);
-
- chan->ops->close(chan->data);
- }
-
- mutex_unlock(&conn->chan_lock);
-
- hci_chan_del(conn->hchan);
-
- if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
- cancel_delayed_work_sync(&conn->info_timer);
-
- if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
- cancel_delayed_work_sync(&conn->security_timer);
- smp_chan_destroy(conn);
- }
-
- hcon->l2cap_data = NULL;
- kfree(conn);
-}
-
-static void security_timeout(struct work_struct *work)
-{
- struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
- security_timer.work);
-
- l2cap_conn_del(conn->hcon, ETIMEDOUT);
-}
-
-static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
-{
- struct l2cap_conn *conn = hcon->l2cap_data;
- struct hci_chan *hchan;
-
- if (conn || status)
- return conn;
-
- hchan = hci_chan_create(hcon);
- if (!hchan)
- return NULL;
-
- conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
- if (!conn) {
- hci_chan_del(hchan);
- return NULL;
- }
-
- hcon->l2cap_data = conn;
- conn->hcon = hcon;
- conn->hchan = hchan;
-
- BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
-
- if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
- conn->mtu = hcon->hdev->le_mtu;
- else
- conn->mtu = hcon->hdev->acl_mtu;
-
- conn->src = &hcon->hdev->bdaddr;
- conn->dst = &hcon->dst;
-
- conn->feat_mask = 0;
-
- spin_lock_init(&conn->lock);
- mutex_init(&conn->chan_lock);
-
- INIT_LIST_HEAD(&conn->chan_l);
-
- if (hcon->type == LE_LINK)
- INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
- else
- INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
-
- conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
-
- return conn;
-}
-
-/* ---- Socket interface ---- */
-
-/* Find socket with psm and source bdaddr.
- * Returns closest match.
- */
-static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
-{
- struct l2cap_chan *c, *c1 = NULL;
-
- read_lock(&chan_list_lock);
-
- list_for_each_entry(c, &chan_list, global_l) {
- struct sock *sk = c->sk;
-
- if (state && c->state != state)
- continue;
-
- if (c->psm == psm) {
- /* Exact match. */
- if (!bacmp(&bt_sk(sk)->src, src)) {
- read_unlock(&chan_list_lock);
- return c;
- }
-
- /* Closest match */
- if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
- c1 = c;
- }
- }
-
- read_unlock(&chan_list_lock);
-
- return c1;
-}
-
-int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
-{
- struct sock *sk = chan->sk;
- bdaddr_t *src = &bt_sk(sk)->src;
- struct l2cap_conn *conn;
- struct hci_conn *hcon;
- struct hci_dev *hdev;
- __u8 auth_type;
- int err;
-
- BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
- chan->psm);
-
- hdev = hci_get_route(dst, src);
- if (!hdev)
- return -EHOSTUNREACH;
-
- hci_dev_lock(hdev);
-
- l2cap_chan_lock(chan);
-
- /* PSM must be odd and lsb of upper byte must be 0 */
- if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
- chan->chan_type != L2CAP_CHAN_RAW) {
- err = -EINVAL;
- goto done;
- }
-
- if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
- err = -EINVAL;
- goto done;
- }
-
- switch (chan->mode) {
- case L2CAP_MODE_BASIC:
- break;
- case L2CAP_MODE_ERTM:
- case L2CAP_MODE_STREAMING:
- if (!disable_ertm)
- break;
- /* fall through */
- default:
- err = -ENOTSUPP;
- goto done;
- }
-
- lock_sock(sk);
-
- switch (sk->sk_state) {
- case BT_CONNECT:
- case BT_CONNECT2:
- case BT_CONFIG:
- /* Already connecting */
- err = 0;
- release_sock(sk);
- goto done;
-
- case BT_CONNECTED:
- /* Already connected */
- err = -EISCONN;
- release_sock(sk);
- goto done;
-
- case BT_OPEN:
- case BT_BOUND:
- /* Can connect */
- break;
-
- default:
- err = -EBADFD;
- release_sock(sk);
- goto done;
- }
-
- /* Set destination address and psm */
- bacpy(&bt_sk(sk)->dst, dst);
-
- release_sock(sk);
-
- chan->psm = psm;
- chan->dcid = cid;
-
- auth_type = l2cap_get_auth_type(chan);
-
- if (chan->dcid == L2CAP_CID_LE_DATA)
- hcon = hci_connect(hdev, LE_LINK, dst,
- chan->sec_level, auth_type);
- else
- hcon = hci_connect(hdev, ACL_LINK, dst,
- chan->sec_level, auth_type);
-
- if (IS_ERR(hcon)) {
- err = PTR_ERR(hcon);
- goto done;
- }
-
- conn = l2cap_conn_add(hcon, 0);
- if (!conn) {
- hci_conn_put(hcon);
- err = -ENOMEM;
- goto done;
- }
-
- /* Update source addr of the socket */
- bacpy(src, conn->src);
-
- l2cap_chan_unlock(chan);
- l2cap_chan_add(conn, chan);
- l2cap_chan_lock(chan);
-
- l2cap_state_change(chan, BT_CONNECT);
- __set_chan_timer(chan, sk->sk_sndtimeo);
-
- if (hcon->state == BT_CONNECTED) {
- if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
- __clear_chan_timer(chan);
- if (l2cap_chan_check_security(chan))
- l2cap_state_change(chan, BT_CONNECTED);
- } else
- l2cap_do_start(chan);
- }
-
- err = 0;
-
-done:
- l2cap_chan_unlock(chan);
- hci_dev_unlock(hdev);
- hci_dev_put(hdev);
- return err;
-}
-
-int __l2cap_wait_ack(struct sock *sk)
-{
- struct l2cap_chan *chan = l2cap_pi(sk)->chan;
- DECLARE_WAITQUEUE(wait, current);
- int err = 0;
- int timeo = HZ/5;
-
- add_wait_queue(sk_sleep(sk), &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- while (chan->unacked_frames > 0 && chan->conn) {
- if (!timeo)
- timeo = HZ/5;
-
- if (signal_pending(current)) {
- err = sock_intr_errno(timeo);
- break;
- }
-
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
- set_current_state(TASK_INTERRUPTIBLE);
-
- err = sock_error(sk);
- if (err)
- break;
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(sk), &wait);
- return err;
-}
-
-static void l2cap_monitor_timeout(struct work_struct *work)
-{
- struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
- monitor_timer.work);
-
- BT_DBG("chan %p", chan);
-
- l2cap_chan_lock(chan);
-
- if (chan->retry_count >= chan->remote_max_tx) {
- l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
- l2cap_chan_unlock(chan);
- l2cap_chan_put(chan);
- return;
- }
-
- chan->retry_count++;
- __set_monitor_timer(chan);
-
- l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
- l2cap_chan_unlock(chan);
- l2cap_chan_put(chan);
-}
-
-static void l2cap_retrans_timeout(struct work_struct *work)
-{
- struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
- retrans_timer.work);
-
- BT_DBG("chan %p", chan);
-
- l2cap_chan_lock(chan);
-
- chan->retry_count = 1;
- __set_monitor_timer(chan);
-
- set_bit(CONN_WAIT_F, &chan->conn_state);
-
- l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
-
- l2cap_chan_unlock(chan);
- l2cap_chan_put(chan);
-}
-
-static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
-{
- struct sk_buff *skb;
-
- while ((skb = skb_peek(&chan->tx_q)) &&
- chan->unacked_frames) {
- if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
- break;
-
- skb = skb_dequeue(&chan->tx_q);
- kfree_skb(skb);
-
- chan->unacked_frames--;
- }
-
- if (!chan->unacked_frames)
- __clear_retrans_timer(chan);
-}
-
-static void l2cap_streaming_send(struct l2cap_chan *chan)
-{
- struct sk_buff *skb;
- u32 control;
- u16 fcs;
-
- while ((skb = skb_dequeue(&chan->tx_q))) {
- control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
- control |= __set_txseq(chan, chan->next_tx_seq);
- __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
-
- if (chan->fcs == L2CAP_FCS_CRC16) {
- fcs = crc16(0, (u8 *)skb->data,
- skb->len - L2CAP_FCS_SIZE);
- put_unaligned_le16(fcs,
- skb->data + skb->len - L2CAP_FCS_SIZE);
- }
-
- l2cap_do_send(chan, skb);
-
- chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
- }
-}
-
-static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
-{
- struct sk_buff *skb, *tx_skb;
- u16 fcs;
- u32 control;
-
- skb = skb_peek(&chan->tx_q);
- if (!skb)
- return;
-
- while (bt_cb(skb)->tx_seq != tx_seq) {
- if (skb_queue_is_last(&chan->tx_q, skb))
- return;
-
- skb = skb_queue_next(&chan->tx_q, skb);
- }
-
- if (chan->remote_max_tx &&
- bt_cb(skb)->retries == chan->remote_max_tx) {
- l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
- return;
- }
-
- tx_skb = skb_clone(skb, GFP_ATOMIC);
- bt_cb(skb)->retries++;
-
- control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
- control &= __get_sar_mask(chan);
-
- if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
- control |= __set_ctrl_final(chan);
-
- control |= __set_reqseq(chan, chan->buffer_seq);
- control |= __set_txseq(chan, tx_seq);
-
- __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
-
- if (chan->fcs == L2CAP_FCS_CRC16) {
- fcs = crc16(0, (u8 *)tx_skb->data,
- tx_skb->len - L2CAP_FCS_SIZE);
- put_unaligned_le16(fcs,
- tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
- }
-
- l2cap_do_send(chan, tx_skb);
-}
-
-static int l2cap_ertm_send(struct l2cap_chan *chan)
-{
- struct sk_buff *skb, *tx_skb;
- u16 fcs;
- u32 control;
- int nsent = 0;
-
- if (chan->state != BT_CONNECTED)
- return -ENOTCONN;
-
- while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
-
- if (chan->remote_max_tx &&
- bt_cb(skb)->retries == chan->remote_max_tx) {
- l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
- break;
- }
-
- tx_skb = skb_clone(skb, GFP_ATOMIC);
-
- bt_cb(skb)->retries++;
-
- control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
- control &= __get_sar_mask(chan);
-
- if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
- control |= __set_ctrl_final(chan);
-
- control |= __set_reqseq(chan, chan->buffer_seq);
- control |= __set_txseq(chan, chan->next_tx_seq);
-
- __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
-
- if (chan->fcs == L2CAP_FCS_CRC16) {
- fcs = crc16(0, (u8 *)skb->data,
- tx_skb->len - L2CAP_FCS_SIZE);
- put_unaligned_le16(fcs, skb->data +
- tx_skb->len - L2CAP_FCS_SIZE);
- }
-
- l2cap_do_send(chan, tx_skb);
-
- __set_retrans_timer(chan);
-
- bt_cb(skb)->tx_seq = chan->next_tx_seq;
-
- chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
-
- if (bt_cb(skb)->retries == 1) {
- chan->unacked_frames++;
-
- if (!nsent++)
- __clear_ack_timer(chan);
- }
-
- chan->frames_sent++;
-
- if (skb_queue_is_last(&chan->tx_q, skb))
- chan->tx_send_head = NULL;
- else
- chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
- }
-
- return nsent;
-}
-
-static int l2cap_retransmit_frames(struct l2cap_chan *chan)
-{
- int ret;
-
- if (!skb_queue_empty(&chan->tx_q))
- chan->tx_send_head = chan->tx_q.next;
-
- chan->next_tx_seq = chan->expected_ack_seq;
- ret = l2cap_ertm_send(chan);
- return ret;
-}
-
-static void __l2cap_send_ack(struct l2cap_chan *chan)
-{
- u32 control = 0;
-
- control |= __set_reqseq(chan, chan->buffer_seq);
-
- if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
- control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
- set_bit(CONN_RNR_SENT, &chan->conn_state);
- l2cap_send_sframe(chan, control);
- return;
- }
-
- if (l2cap_ertm_send(chan) > 0)
- return;
-
- control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
- l2cap_send_sframe(chan, control);
-}
-
-static void l2cap_send_ack(struct l2cap_chan *chan)
-{
- __clear_ack_timer(chan);
- __l2cap_send_ack(chan);
-}
-
-static void l2cap_send_srejtail(struct l2cap_chan *chan)
-{
- struct srej_list *tail;
- u32 control;
-
- control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
- control |= __set_ctrl_final(chan);
-
- tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
- control |= __set_reqseq(chan, tail->tx_seq);
-
- l2cap_send_sframe(chan, control);
-}
-
-static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
- struct msghdr *msg, int len,
- int count, struct sk_buff *skb)
-{
- struct l2cap_conn *conn = chan->conn;
- struct sk_buff **frag;
- int err, sent = 0;
-
- if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
- return -EFAULT;
-
- sent += count;
- len -= count;
-
- /* Continuation fragments (no L2CAP header) */
- frag = &skb_shinfo(skb)->frag_list;
- while (len) {
- count = min_t(unsigned int, conn->mtu, len);
-
- *frag = chan->ops->alloc_skb(chan, count,
- msg->msg_flags & MSG_DONTWAIT,
- &err);
-
- if (!*frag)
- return err;
- if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
- return -EFAULT;
-
- (*frag)->priority = skb->priority;
-
- sent += count;
- len -= count;
-
- frag = &(*frag)->next;
- }
-
- return sent;
-}
-
-static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
- struct msghdr *msg, size_t len,
- u32 priority)
-{
- struct l2cap_conn *conn = chan->conn;
- struct sk_buff *skb;
- int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
- struct l2cap_hdr *lh;
-
- BT_DBG("chan %p len %d priority %u", chan, (int)len, priority);
-
- count = min_t(unsigned int, (conn->mtu - hlen), len);
-
- skb = chan->ops->alloc_skb(chan, count + hlen,
- msg->msg_flags & MSG_DONTWAIT, &err);
-
- if (!skb)
- return ERR_PTR(err);
-
- skb->priority = priority;
-
- /* Create L2CAP header */
- lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
- lh->cid = cpu_to_le16(chan->dcid);
- lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
- put_unaligned_le16(chan->psm, skb_put(skb, 2));
-
- err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
- if (unlikely(err < 0)) {
- kfree_skb(skb);
- return ERR_PTR(err);
- }
- return skb;
-}
-
-static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
- struct msghdr *msg, size_t len,
- u32 priority)
-{
- struct l2cap_conn *conn = chan->conn;
- struct sk_buff *skb;
- int err, count, hlen = L2CAP_HDR_SIZE;
- struct l2cap_hdr *lh;
-
- BT_DBG("chan %p len %d", chan, (int)len);
-
- count = min_t(unsigned int, (conn->mtu - hlen), len);
-
- skb = chan->ops->alloc_skb(chan, count + hlen,
- msg->msg_flags & MSG_DONTWAIT, &err);
-
- if (!skb)
- return ERR_PTR(err);
-
- skb->priority = priority;
-
- /* Create L2CAP header */
- lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
- lh->cid = cpu_to_le16(chan->dcid);
- lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
-
- err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
- if (unlikely(err < 0)) {
- kfree_skb(skb);
- return ERR_PTR(err);
- }
- return skb;
-}
-
-static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
- struct msghdr *msg, size_t len,
- u32 control, u16 sdulen)
-{
- struct l2cap_conn *conn = chan->conn;
- struct sk_buff *skb;
- int err, count, hlen;
- struct l2cap_hdr *lh;
-
- BT_DBG("chan %p len %d", chan, (int)len);
-
- if (!conn)
- return ERR_PTR(-ENOTCONN);
-
- if (test_bit(FLAG_EXT_CTRL, &chan->flags))
- hlen = L2CAP_EXT_HDR_SIZE;
- else
- hlen = L2CAP_ENH_HDR_SIZE;
-
- if (sdulen)
- hlen += L2CAP_SDULEN_SIZE;
-
- if (chan->fcs == L2CAP_FCS_CRC16)
- hlen += L2CAP_FCS_SIZE;
-
- count = min_t(unsigned int, (conn->mtu - hlen), len);
-
- skb = chan->ops->alloc_skb(chan, count + hlen,
- msg->msg_flags & MSG_DONTWAIT, &err);
-
- if (!skb)
- return ERR_PTR(err);
-
- /* Create L2CAP header */
- lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
- lh->cid = cpu_to_le16(chan->dcid);
- lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
-
- __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
-
- if (sdulen)
- put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
-
- err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
- if (unlikely(err < 0)) {
- kfree_skb(skb);
- return ERR_PTR(err);
- }
-
- if (chan->fcs == L2CAP_FCS_CRC16)
- put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
-
- bt_cb(skb)->retries = 0;
- return skb;
-}
-
-static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
-{
- struct sk_buff *skb;
- struct sk_buff_head sar_queue;
- u32 control;
- size_t size = 0;
-
- skb_queue_head_init(&sar_queue);
- control = __set_ctrl_sar(chan, L2CAP_SAR_START);
- skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- __skb_queue_tail(&sar_queue, skb);
- len -= chan->remote_mps;
- size += chan->remote_mps;
-
- while (len > 0) {
- size_t buflen;
-
- if (len > chan->remote_mps) {
- control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
- buflen = chan->remote_mps;
- } else {
- control = __set_ctrl_sar(chan, L2CAP_SAR_END);
- buflen = len;
- }
-
- skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
- if (IS_ERR(skb)) {
- skb_queue_purge(&sar_queue);
- return PTR_ERR(skb);
- }
-
- __skb_queue_tail(&sar_queue, skb);
- len -= buflen;
- size += buflen;
- }
- skb_queue_splice_tail(&sar_queue, &chan->tx_q);
- if (chan->tx_send_head == NULL)
- chan->tx_send_head = sar_queue.next;
-
- return size;
-}
-
-int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
- u32 priority)
-{
- struct sk_buff *skb;
- u32 control;
- int err;
-
- /* Connectionless channel */
- if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
- skb = l2cap_create_connless_pdu(chan, msg, len, priority);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- l2cap_do_send(chan, skb);
- return len;
- }
-
- switch (chan->mode) {
- case L2CAP_MODE_BASIC:
- /* Check outgoing MTU */
- if (len > chan->omtu)
- return -EMSGSIZE;
-
- /* Create a basic PDU */
- skb = l2cap_create_basic_pdu(chan, msg, len, priority);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- l2cap_do_send(chan, skb);
- err = len;
- break;
-
- case L2CAP_MODE_ERTM:
- case L2CAP_MODE_STREAMING:
- /* Entire SDU fits into one PDU */
- if (len <= chan->remote_mps) {
- control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
- skb = l2cap_create_iframe_pdu(chan, msg, len, control,
- 0);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- __skb_queue_tail(&chan->tx_q, skb);
-
- if (chan->tx_send_head == NULL)
- chan->tx_send_head = skb;
-
- } else {
- /* Segment SDU into multiples PDUs */
- err = l2cap_sar_segment_sdu(chan, msg, len);
- if (err < 0)
- return err;
- }
-
- if (chan->mode == L2CAP_MODE_STREAMING) {
- l2cap_streaming_send(chan);
- err = len;
- break;
- }
-
- if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
- test_bit(CONN_WAIT_F, &chan->conn_state)) {
- err = len;
- break;
- }
-
- err = l2cap_ertm_send(chan);
- if (err >= 0)
- err = len;
-
- break;
-
- default:
- BT_DBG("bad state %1.1x", chan->mode);
- err = -EBADFD;
- }
-
- return err;
-}
-
-/* Copy frame to all raw sockets on that connection */
-static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
-{
- struct sk_buff *nskb;
- struct l2cap_chan *chan;
-
- BT_DBG("conn %p", conn);
-
- mutex_lock(&conn->chan_lock);
-
- list_for_each_entry(chan, &conn->chan_l, list) {
- struct sock *sk = chan->sk;
- if (chan->chan_type != L2CAP_CHAN_RAW)
- continue;
-
- /* Don't send frame to the socket it came from */
- if (skb->sk == sk)
- continue;
- nskb = skb_clone(skb, GFP_ATOMIC);
- if (!nskb)
- continue;
-
- if (chan->ops->recv(chan->data, nskb))
- kfree_skb(nskb);
- }
-
- mutex_unlock(&conn->chan_lock);
-}
-
-/* ---- L2CAP signalling commands ---- */
-static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
- u8 code, u8 ident, u16 dlen, void *data)
-{
- struct sk_buff *skb, **frag;
- struct l2cap_cmd_hdr *cmd;
- struct l2cap_hdr *lh;
- int len, count;
-
- BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
- conn, code, ident, dlen);
-
- len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
- count = min_t(unsigned int, conn->mtu, len);
-
- skb = bt_skb_alloc(count, GFP_ATOMIC);
- if (!skb)
- return NULL;
-
- lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
- lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
-
- if (conn->hcon->type == LE_LINK)
- lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
- else
- lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
-
- cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
- cmd->code = code;
- cmd->ident = ident;
- cmd->len = cpu_to_le16(dlen);
-
- if (dlen) {
- count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
- memcpy(skb_put(skb, count), data, count);
- data += count;
- }
-
- len -= skb->len;
-
- /* Continuation fragments (no L2CAP header) */
- frag = &skb_shinfo(skb)->frag_list;
- while (len) {
- count = min_t(unsigned int, conn->mtu, len);
-
- *frag = bt_skb_alloc(count, GFP_ATOMIC);
- if (!*frag)
- goto fail;
-
- memcpy(skb_put(*frag, count), data, count);
-
- len -= count;
- data += count;
-
- frag = &(*frag)->next;
- }
-
- return skb;
-
-fail:
- kfree_skb(skb);
- return NULL;
-}
-
-static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
-{
- struct l2cap_conf_opt *opt = *ptr;
- int len;
-
- len = L2CAP_CONF_OPT_SIZE + opt->len;
- *ptr += len;
-
- *type = opt->type;
- *olen = opt->len;
-
- switch (opt->len) {
- case 1:
- *val = *((u8 *) opt->val);
- break;
-
- case 2:
- *val = get_unaligned_le16(opt->val);
- break;
-
- case 4:
- *val = get_unaligned_le32(opt->val);
- break;
-
- default:
- *val = (unsigned long) opt->val;
- break;
- }
-
- BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
- return len;
-}
-
-static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
-{
- struct l2cap_conf_opt *opt = *ptr;
-
- BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
-
- opt->type = type;
- opt->len = len;
-
- switch (len) {
- case 1:
- *((u8 *) opt->val) = val;
- break;
-
- case 2:
- put_unaligned_le16(val, opt->val);
- break;
-
- case 4:
- put_unaligned_le32(val, opt->val);
- break;
-
- default:
- memcpy(opt->val, (void *) val, len);
- break;
- }
-
- *ptr += L2CAP_CONF_OPT_SIZE + len;
-}
-
-static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
-{
- struct l2cap_conf_efs efs;
-
- switch (chan->mode) {
- case L2CAP_MODE_ERTM:
- efs.id = chan->local_id;
- efs.stype = chan->local_stype;
- efs.msdu = cpu_to_le16(chan->local_msdu);
- efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
- efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
- efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
- break;
-
- case L2CAP_MODE_STREAMING:
- efs.id = 1;
- efs.stype = L2CAP_SERV_BESTEFFORT;
- efs.msdu = cpu_to_le16(chan->local_msdu);
- efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
- efs.acc_lat = 0;
- efs.flush_to = 0;
- break;
-
- default:
- return;
- }
-
- l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
- (unsigned long) &efs);
-}
-
-static void l2cap_ack_timeout(struct work_struct *work)
-{
- struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
- ack_timer.work);
-
- BT_DBG("chan %p", chan);
-
- l2cap_chan_lock(chan);
-
- __l2cap_send_ack(chan);
-
- l2cap_chan_unlock(chan);
-
- l2cap_chan_put(chan);
-}
-
-static inline void l2cap_ertm_init(struct l2cap_chan *chan)
-{
- chan->expected_ack_seq = 0;
- chan->unacked_frames = 0;
- chan->buffer_seq = 0;
- chan->num_acked = 0;
- chan->frames_sent = 0;
-
- INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
- INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
- INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
-
- skb_queue_head_init(&chan->srej_q);
-
- INIT_LIST_HEAD(&chan->srej_l);
-}
-
-static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
-{
- switch (mode) {
- case L2CAP_MODE_STREAMING:
- case L2CAP_MODE_ERTM:
- if (l2cap_mode_supported(mode, remote_feat_mask))
- return mode;
- /* fall through */
- default:
- return L2CAP_MODE_BASIC;
- }
-}
-
-static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
-{
- return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
-}
-
-static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
-{
- return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
-}
-
-static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
-{
- if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
- __l2cap_ews_supported(chan)) {
- /* use extended control field */
- set_bit(FLAG_EXT_CTRL, &chan->flags);
- chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
- } else {
- chan->tx_win = min_t(u16, chan->tx_win,
- L2CAP_DEFAULT_TX_WINDOW);
- chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
- }
-}
-
-static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
-{
- struct l2cap_conf_req *req = data;
- struct l2cap_conf_rfc rfc = { .mode = chan->mode };
- void *ptr = req->data;
- u16 size;
-
- BT_DBG("chan %p", chan);
-
- if (chan->num_conf_req || chan->num_conf_rsp)
- goto done;
-
- switch (chan->mode) {
- case L2CAP_MODE_STREAMING:
- case L2CAP_MODE_ERTM:
- if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
- break;
-
- if (__l2cap_efs_supported(chan))
- set_bit(FLAG_EFS_ENABLE, &chan->flags);
-
- /* fall through */
- default:
- chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
- break;
- }
-
-done:
- if (chan->imtu != L2CAP_DEFAULT_MTU)
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
-
- switch (chan->mode) {
- case L2CAP_MODE_BASIC:
- if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
- !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
- break;
-
- rfc.mode = L2CAP_MODE_BASIC;
- rfc.txwin_size = 0;
- rfc.max_transmit = 0;
- rfc.retrans_timeout = 0;
- rfc.monitor_timeout = 0;
- rfc.max_pdu_size = 0;
-
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
- (unsigned long) &rfc);
- break;
-
- case L2CAP_MODE_ERTM:
- rfc.mode = L2CAP_MODE_ERTM;
- rfc.max_transmit = chan->max_tx;
- rfc.retrans_timeout = 0;
- rfc.monitor_timeout = 0;
-
- size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
- L2CAP_EXT_HDR_SIZE -
- L2CAP_SDULEN_SIZE -
- L2CAP_FCS_SIZE);
- rfc.max_pdu_size = cpu_to_le16(size);
-
- l2cap_txwin_setup(chan);
-
- rfc.txwin_size = min_t(u16, chan->tx_win,
- L2CAP_DEFAULT_TX_WINDOW);
-
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
- (unsigned long) &rfc);
-
- if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
- l2cap_add_opt_efs(&ptr, chan);
-
- if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
- break;
-
- if (chan->fcs == L2CAP_FCS_NONE ||
- test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
- chan->fcs = L2CAP_FCS_NONE;
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
- }
-
- if (test_bit(FLAG_EXT_CTRL, &chan->flags))
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
- chan->tx_win);
- break;
-
- case L2CAP_MODE_STREAMING:
- rfc.mode = L2CAP_MODE_STREAMING;
- rfc.txwin_size = 0;
- rfc.max_transmit = 0;
- rfc.retrans_timeout = 0;
- rfc.monitor_timeout = 0;
-
- size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
- L2CAP_EXT_HDR_SIZE -
- L2CAP_SDULEN_SIZE -
- L2CAP_FCS_SIZE);
- rfc.max_pdu_size = cpu_to_le16(size);
-
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
- (unsigned long) &rfc);
-
- if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
- l2cap_add_opt_efs(&ptr, chan);
-
- if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
- break;
-
- if (chan->fcs == L2CAP_FCS_NONE ||
- test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
- chan->fcs = L2CAP_FCS_NONE;
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
- }
- break;
- }
-
- req->dcid = cpu_to_le16(chan->dcid);
- req->flags = cpu_to_le16(0);
-
- return ptr - data;
-}
-
-static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
-{
- struct l2cap_conf_rsp *rsp = data;
- void *ptr = rsp->data;
- void *req = chan->conf_req;
- int len = chan->conf_len;
- int type, hint, olen;
- unsigned long val;
- struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
- struct l2cap_conf_efs efs;
- u8 remote_efs = 0;
- u16 mtu = L2CAP_DEFAULT_MTU;
- u16 result = L2CAP_CONF_SUCCESS;
- u16 size;
-
- BT_DBG("chan %p", chan);
-
- while (len >= L2CAP_CONF_OPT_SIZE) {
- len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
-
- hint = type & L2CAP_CONF_HINT;
- type &= L2CAP_CONF_MASK;
-
- switch (type) {
- case L2CAP_CONF_MTU:
- mtu = val;
- break;
-
- case L2CAP_CONF_FLUSH_TO:
- chan->flush_to = val;
- break;
-
- case L2CAP_CONF_QOS:
- break;
-
- case L2CAP_CONF_RFC:
- if (olen == sizeof(rfc))
- memcpy(&rfc, (void *) val, olen);
- break;
-
- case L2CAP_CONF_FCS:
- if (val == L2CAP_FCS_NONE)
- set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
- break;
-
- case L2CAP_CONF_EFS:
- remote_efs = 1;
- if (olen == sizeof(efs))
- memcpy(&efs, (void *) val, olen);
- break;
-
- case L2CAP_CONF_EWS:
- if (!enable_hs)
- return -ECONNREFUSED;
-
- set_bit(FLAG_EXT_CTRL, &chan->flags);
- set_bit(CONF_EWS_RECV, &chan->conf_state);
- chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
- chan->remote_tx_win = val;
- break;
-
- default:
- if (hint)
- break;
-
- result = L2CAP_CONF_UNKNOWN;
- *((u8 *) ptr++) = type;
- break;
- }
- }
-
- if (chan->num_conf_rsp || chan->num_conf_req > 1)
- goto done;
-
- switch (chan->mode) {
- case L2CAP_MODE_STREAMING:
- case L2CAP_MODE_ERTM:
- if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
- chan->mode = l2cap_select_mode(rfc.mode,
- chan->conn->feat_mask);
- break;
- }
-
- if (remote_efs) {
- if (__l2cap_efs_supported(chan))
- set_bit(FLAG_EFS_ENABLE, &chan->flags);
- else
- return -ECONNREFUSED;
- }
-
- if (chan->mode != rfc.mode)
- return -ECONNREFUSED;
-
- break;
- }
-
-done:
- if (chan->mode != rfc.mode) {
- result = L2CAP_CONF_UNACCEPT;
- rfc.mode = chan->mode;
-
- if (chan->num_conf_rsp == 1)
- return -ECONNREFUSED;
-
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
- sizeof(rfc), (unsigned long) &rfc);
- }
-
- if (result == L2CAP_CONF_SUCCESS) {
- /* Configure output options and let the other side know
- * which ones we don't like. */
-
- if (mtu < L2CAP_DEFAULT_MIN_MTU)
- result = L2CAP_CONF_UNACCEPT;
- else {
- chan->omtu = mtu;
- set_bit(CONF_MTU_DONE, &chan->conf_state);
- }
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
-
- if (remote_efs) {
- if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
- efs.stype != L2CAP_SERV_NOTRAFIC &&
- efs.stype != chan->local_stype) {
-
- result = L2CAP_CONF_UNACCEPT;
-
- if (chan->num_conf_req >= 1)
- return -ECONNREFUSED;
-
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
- sizeof(efs),
- (unsigned long) &efs);
- } else {
- /* Send PENDING Conf Rsp */
- result = L2CAP_CONF_PENDING;
- set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
- }
- }
-
- switch (rfc.mode) {
- case L2CAP_MODE_BASIC:
- chan->fcs = L2CAP_FCS_NONE;
- set_bit(CONF_MODE_DONE, &chan->conf_state);
- break;
-
- case L2CAP_MODE_ERTM:
- if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
- chan->remote_tx_win = rfc.txwin_size;
- else
- rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
-
- chan->remote_max_tx = rfc.max_transmit;
-
- size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
- chan->conn->mtu -
- L2CAP_EXT_HDR_SIZE -
- L2CAP_SDULEN_SIZE -
- L2CAP_FCS_SIZE);
- rfc.max_pdu_size = cpu_to_le16(size);
- chan->remote_mps = size;
-
- rfc.retrans_timeout =
- le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
- rfc.monitor_timeout =
- le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
-
- set_bit(CONF_MODE_DONE, &chan->conf_state);
-
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
- sizeof(rfc), (unsigned long) &rfc);
-
- if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
- chan->remote_id = efs.id;
- chan->remote_stype = efs.stype;
- chan->remote_msdu = le16_to_cpu(efs.msdu);
- chan->remote_flush_to =
- le32_to_cpu(efs.flush_to);
- chan->remote_acc_lat =
- le32_to_cpu(efs.acc_lat);
- chan->remote_sdu_itime =
- le32_to_cpu(efs.sdu_itime);
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
- sizeof(efs), (unsigned long) &efs);
- }
- break;
-
- case L2CAP_MODE_STREAMING:
- size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
- chan->conn->mtu -
- L2CAP_EXT_HDR_SIZE -
- L2CAP_SDULEN_SIZE -
- L2CAP_FCS_SIZE);
- rfc.max_pdu_size = cpu_to_le16(size);
- chan->remote_mps = size;
-
- set_bit(CONF_MODE_DONE, &chan->conf_state);
-
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
- sizeof(rfc), (unsigned long) &rfc);
-
- break;
-
- default:
- result = L2CAP_CONF_UNACCEPT;
-
- memset(&rfc, 0, sizeof(rfc));
- rfc.mode = chan->mode;
- }
-
- if (result == L2CAP_CONF_SUCCESS)
- set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
- }
- rsp->scid = cpu_to_le16(chan->dcid);
- rsp->result = cpu_to_le16(result);
- rsp->flags = cpu_to_le16(0x0000);
-
- return ptr - data;
-}
-
-static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, void *data, u16 *result)
-{
- struct l2cap_conf_req *req = data;
- void *ptr = req->data;
- int type, olen;
- unsigned long val;
- struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
- struct l2cap_conf_efs efs;
-
- BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
-
- while (len >= L2CAP_CONF_OPT_SIZE) {
- len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
-
- switch (type) {
- case L2CAP_CONF_MTU:
- if (val < L2CAP_DEFAULT_MIN_MTU) {
- *result = L2CAP_CONF_UNACCEPT;
- chan->imtu = L2CAP_DEFAULT_MIN_MTU;
- } else
- chan->imtu = val;
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
- break;
-
- case L2CAP_CONF_FLUSH_TO:
- chan->flush_to = val;
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
- 2, chan->flush_to);
- break;
-
- case L2CAP_CONF_RFC:
- if (olen == sizeof(rfc))
- memcpy(&rfc, (void *)val, olen);
-
- if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
- rfc.mode != chan->mode)
- return -ECONNREFUSED;
-
- chan->fcs = 0;
-
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
- sizeof(rfc), (unsigned long) &rfc);
- break;
-
- case L2CAP_CONF_EWS:
- chan->tx_win = min_t(u16, val,
- L2CAP_DEFAULT_EXT_WINDOW);
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
- chan->tx_win);
- break;
-
- case L2CAP_CONF_EFS:
- if (olen == sizeof(efs))
- memcpy(&efs, (void *)val, olen);
-
- if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
- efs.stype != L2CAP_SERV_NOTRAFIC &&
- efs.stype != chan->local_stype)
- return -ECONNREFUSED;
-
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
- sizeof(efs), (unsigned long) &efs);
- break;
- }
- }
-
- if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
- return -ECONNREFUSED;
-
- chan->mode = rfc.mode;
-
- if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
- switch (rfc.mode) {
- case L2CAP_MODE_ERTM:
- chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
- chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
- chan->mps = le16_to_cpu(rfc.max_pdu_size);
-
- if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
- chan->local_msdu = le16_to_cpu(efs.msdu);
- chan->local_sdu_itime =
- le32_to_cpu(efs.sdu_itime);
- chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
- chan->local_flush_to =
- le32_to_cpu(efs.flush_to);
- }
- break;
-
- case L2CAP_MODE_STREAMING:
- chan->mps = le16_to_cpu(rfc.max_pdu_size);
- }
- }
-
- req->dcid = cpu_to_le16(chan->dcid);
- req->flags = cpu_to_le16(0x0000);
-
- return ptr - data;
-}
-
-static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
-{
- struct l2cap_conf_rsp *rsp = data;
- void *ptr = rsp->data;
-
- BT_DBG("chan %p", chan);
-
- rsp->scid = cpu_to_le16(chan->dcid);
- rsp->result = cpu_to_le16(result);
- rsp->flags = cpu_to_le16(flags);
-
- return ptr - data;
-}
-
-void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
-{
- struct l2cap_conn_rsp rsp;
- struct l2cap_conn *conn = chan->conn;
- u8 buf[128];
-
- rsp.scid = cpu_to_le16(chan->dcid);
- rsp.dcid = cpu_to_le16(chan->scid);
- rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
- rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
- l2cap_send_cmd(conn, chan->ident,
- L2CAP_CONN_RSP, sizeof(rsp), &rsp);
-
- if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
- return;
-
- l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
- l2cap_build_conf_req(chan, buf), buf);
- chan->num_conf_req++;
-}
-
-static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
-{
- int type, olen;
- unsigned long val;
- struct l2cap_conf_rfc rfc;
-
- BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
-
- if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
- return;
-
- while (len >= L2CAP_CONF_OPT_SIZE) {
- len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
-
- switch (type) {
- case L2CAP_CONF_RFC:
- if (olen == sizeof(rfc))
- memcpy(&rfc, (void *)val, olen);
- goto done;
- }
- }
-
- /* Use sane default values in case a misbehaving remote device
- * did not send an RFC option.
- */
- rfc.mode = chan->mode;
- rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
- rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
- rfc.max_pdu_size = cpu_to_le16(chan->imtu);
-
- BT_ERR("Expected RFC option was not found, using defaults");
-
-done:
- switch (rfc.mode) {
- case L2CAP_MODE_ERTM:
- chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
- chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
- chan->mps = le16_to_cpu(rfc.max_pdu_size);
- break;
- case L2CAP_MODE_STREAMING:
- chan->mps = le16_to_cpu(rfc.max_pdu_size);
- }
-}
-
-static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
-{
- struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
-
- if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
- return 0;
-
- if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
- cmd->ident == conn->info_ident) {
- cancel_delayed_work(&conn->info_timer);
-
- conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
- conn->info_ident = 0;
-
- l2cap_conn_start(conn);
- }
-
- return 0;
-}
-
-static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
-{
- struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
- struct l2cap_conn_rsp rsp;
- struct l2cap_chan *chan = NULL, *pchan;
- struct sock *parent, *sk = NULL;
- int result, status = L2CAP_CS_NO_INFO;
-
- u16 dcid = 0, scid = __le16_to_cpu(req->scid);
- __le16 psm = req->psm;
-
- BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
-
- /* Check if we have socket listening on psm */
- pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
- if (!pchan) {
- result = L2CAP_CR_BAD_PSM;
- goto sendresp;
- }
-
- parent = pchan->sk;
-
- mutex_lock(&conn->chan_lock);
- lock_sock(parent);
-
- /* Check if the ACL is secure enough (if not SDP) */
- if (psm != cpu_to_le16(0x0001) &&
- !hci_conn_check_link_mode(conn->hcon)) {
- conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
- result = L2CAP_CR_SEC_BLOCK;
- goto response;
- }
-
- result = L2CAP_CR_NO_MEM;
-
- /* Check for backlog size */
- if (sk_acceptq_is_full(parent)) {
- BT_DBG("backlog full %d", parent->sk_ack_backlog);
- goto response;
- }
-
- chan = pchan->ops->new_connection(pchan->data);
- if (!chan)
- goto response;
-
- sk = chan->sk;
-
- /* Check if we already have channel with that dcid */
- if (__l2cap_get_chan_by_dcid(conn, scid)) {
- sock_set_flag(sk, SOCK_ZAPPED);
- chan->ops->close(chan->data);
- goto response;
- }
-
- hci_conn_hold(conn->hcon);
-
- bacpy(&bt_sk(sk)->src, conn->src);
- bacpy(&bt_sk(sk)->dst, conn->dst);
- chan->psm = psm;
- chan->dcid = scid;
-
- bt_accept_enqueue(parent, sk);
-
- __l2cap_chan_add(conn, chan);
-
- dcid = chan->scid;
-
- __set_chan_timer(chan, sk->sk_sndtimeo);
-
- chan->ident = cmd->ident;
-
- if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
- if (l2cap_chan_check_security(chan)) {
- if (bt_sk(sk)->defer_setup) {
- __l2cap_state_change(chan, BT_CONNECT2);
- result = L2CAP_CR_PEND;
- status = L2CAP_CS_AUTHOR_PEND;
- parent->sk_data_ready(parent, 0);
- } else {
- __l2cap_state_change(chan, BT_CONFIG);
- result = L2CAP_CR_SUCCESS;
- status = L2CAP_CS_NO_INFO;
- }
- } else {
- __l2cap_state_change(chan, BT_CONNECT2);
- result = L2CAP_CR_PEND;
- status = L2CAP_CS_AUTHEN_PEND;
- }
- } else {
- __l2cap_state_change(chan, BT_CONNECT2);
- result = L2CAP_CR_PEND;
- status = L2CAP_CS_NO_INFO;
- }
-
-response:
- release_sock(parent);
- mutex_unlock(&conn->chan_lock);
-
-sendresp:
- rsp.scid = cpu_to_le16(scid);
- rsp.dcid = cpu_to_le16(dcid);
- rsp.result = cpu_to_le16(result);
- rsp.status = cpu_to_le16(status);
- l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
-
- if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
- struct l2cap_info_req info;
- info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
-
- conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
- conn->info_ident = l2cap_get_ident(conn);
-
- schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
-
- l2cap_send_cmd(conn, conn->info_ident,
- L2CAP_INFO_REQ, sizeof(info), &info);
- }
-
- if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
- result == L2CAP_CR_SUCCESS) {
- u8 buf[128];
- set_bit(CONF_REQ_SENT, &chan->conf_state);
- l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
- l2cap_build_conf_req(chan, buf), buf);
- chan->num_conf_req++;
- }
-
- return 0;
-}
-
-static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
-{
- struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
- u16 scid, dcid, result, status;
- struct l2cap_chan *chan;
- u8 req[128];
- int err;
-
- scid = __le16_to_cpu(rsp->scid);
- dcid = __le16_to_cpu(rsp->dcid);
- result = __le16_to_cpu(rsp->result);
- status = __le16_to_cpu(rsp->status);
-
- BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
- dcid, scid, result, status);
-
- mutex_lock(&conn->chan_lock);
-
- if (scid) {
- chan = __l2cap_get_chan_by_scid(conn, scid);
- if (!chan) {
- err = -EFAULT;
- goto unlock;
- }
- } else {
- chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
- if (!chan) {
- err = -EFAULT;
- goto unlock;
- }
- }
-
- err = 0;
-
- l2cap_chan_lock(chan);
-
- switch (result) {
- case L2CAP_CR_SUCCESS:
- l2cap_state_change(chan, BT_CONFIG);
- chan->ident = 0;
- chan->dcid = dcid;
- clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
-
- if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
- break;
-
- l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
- l2cap_build_conf_req(chan, req), req);
- chan->num_conf_req++;
- break;
-
- case L2CAP_CR_PEND:
- set_bit(CONF_CONNECT_PEND, &chan->conf_state);
- break;
-
- default:
- l2cap_chan_del(chan, ECONNREFUSED);
- break;
- }
-
- l2cap_chan_unlock(chan);
-
-unlock:
- mutex_unlock(&conn->chan_lock);
-
- return err;
-}
-
-static inline void set_default_fcs(struct l2cap_chan *chan)
-{
- /* FCS is enabled only in ERTM or streaming mode, if one or both
- * sides request it.
- */
- if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
- chan->fcs = L2CAP_FCS_NONE;
- else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
- chan->fcs = L2CAP_FCS_CRC16;
-}
-
-static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
-{
- struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
- u16 dcid, flags;
- u8 rsp[64];
- struct l2cap_chan *chan;
- int len;
-
- dcid = __le16_to_cpu(req->dcid);
- flags = __le16_to_cpu(req->flags);
-
- BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
-
- chan = l2cap_get_chan_by_scid(conn, dcid);
- if (!chan)
- return -ENOENT;
-
- if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
- struct l2cap_cmd_rej_cid rej;
-
- rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
- rej.scid = cpu_to_le16(chan->scid);
- rej.dcid = cpu_to_le16(chan->dcid);
-
- l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
- sizeof(rej), &rej);
- goto unlock;
- }
-
- /* Reject if config buffer is too small. */
- len = cmd_len - sizeof(*req);
- if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
- l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
- l2cap_build_conf_rsp(chan, rsp,
- L2CAP_CONF_REJECT, flags), rsp);
- goto unlock;
- }
-
- /* Store config. */
- memcpy(chan->conf_req + chan->conf_len, req->data, len);
- chan->conf_len += len;
-
- if (flags & 0x0001) {
- /* Incomplete config. Send empty response. */
- l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
- l2cap_build_conf_rsp(chan, rsp,
- L2CAP_CONF_SUCCESS, 0x0001), rsp);
- goto unlock;
- }
-
- /* Complete config. */
- len = l2cap_parse_conf_req(chan, rsp);
- if (len < 0) {
- l2cap_send_disconn_req(conn, chan, ECONNRESET);
- goto unlock;
- }
-
- l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
- chan->num_conf_rsp++;
-
- /* Reset config buffer. */
- chan->conf_len = 0;
-
- if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
- goto unlock;
-
- if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
- set_default_fcs(chan);
-
- l2cap_state_change(chan, BT_CONNECTED);
-
- chan->next_tx_seq = 0;
- chan->expected_tx_seq = 0;
- skb_queue_head_init(&chan->tx_q);
- if (chan->mode == L2CAP_MODE_ERTM)
- l2cap_ertm_init(chan);
-
- l2cap_chan_ready(chan);
- goto unlock;
- }
-
- if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
- u8 buf[64];
- l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
- l2cap_build_conf_req(chan, buf), buf);
- chan->num_conf_req++;
- }
-
- /* Got Conf Rsp PENDING from remote side and asume we sent
- Conf Rsp PENDING in the code above */
- if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
- test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
-
- /* check compatibility */
-
- clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
- set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
-
- l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
- l2cap_build_conf_rsp(chan, rsp,
- L2CAP_CONF_SUCCESS, 0x0000), rsp);
- }
-
-unlock:
- l2cap_chan_unlock(chan);
- return 0;
-}
-
-static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
-{
- struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
- u16 scid, flags, result;
- struct l2cap_chan *chan;
- int len = cmd->len - sizeof(*rsp);
-
- scid = __le16_to_cpu(rsp->scid);
- flags = __le16_to_cpu(rsp->flags);
- result = __le16_to_cpu(rsp->result);
-
- BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
- scid, flags, result);
-
- chan = l2cap_get_chan_by_scid(conn, scid);
- if (!chan)
- return 0;
-
- switch (result) {
- case L2CAP_CONF_SUCCESS:
- l2cap_conf_rfc_get(chan, rsp->data, len);
- clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
- break;
-
- case L2CAP_CONF_PENDING:
- set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
-
- if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
- char buf[64];
-
- len = l2cap_parse_conf_rsp(chan, rsp->data, len,
- buf, &result);
- if (len < 0) {
- l2cap_send_disconn_req(conn, chan, ECONNRESET);
- goto done;
- }
-
- /* check compatibility */
-
- clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
- set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
-
- l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
- l2cap_build_conf_rsp(chan, buf,
- L2CAP_CONF_SUCCESS, 0x0000), buf);
- }
- goto done;
-
- case L2CAP_CONF_UNACCEPT:
- if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
- char req[64];
-
- if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
- l2cap_send_disconn_req(conn, chan, ECONNRESET);
- goto done;
- }
-
- /* throw out any old stored conf requests */
- result = L2CAP_CONF_SUCCESS;
- len = l2cap_parse_conf_rsp(chan, rsp->data, len,
- req, &result);
- if (len < 0) {
- l2cap_send_disconn_req(conn, chan, ECONNRESET);
- goto done;
- }
-
- l2cap_send_cmd(conn, l2cap_get_ident(conn),
- L2CAP_CONF_REQ, len, req);
- chan->num_conf_req++;
- if (result != L2CAP_CONF_SUCCESS)
- goto done;
- break;
- }
-
- default:
- l2cap_chan_set_err(chan, ECONNRESET);
-
- __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
- l2cap_send_disconn_req(conn, chan, ECONNRESET);
- goto done;
- }
-
- if (flags & 0x01)
- goto done;
-
- set_bit(CONF_INPUT_DONE, &chan->conf_state);
-
- if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
- set_default_fcs(chan);
-
- l2cap_state_change(chan, BT_CONNECTED);
- chan->next_tx_seq = 0;
- chan->expected_tx_seq = 0;
- skb_queue_head_init(&chan->tx_q);
- if (chan->mode == L2CAP_MODE_ERTM)
- l2cap_ertm_init(chan);
-
- l2cap_chan_ready(chan);
- }
-
-done:
- l2cap_chan_unlock(chan);
- return 0;
-}
-
-static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
-{
- struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
- struct l2cap_disconn_rsp rsp;
- u16 dcid, scid;
- struct l2cap_chan *chan;
- struct sock *sk;
-
- scid = __le16_to_cpu(req->scid);
- dcid = __le16_to_cpu(req->dcid);
-
- BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
-
- mutex_lock(&conn->chan_lock);
-
- chan = __l2cap_get_chan_by_scid(conn, dcid);
- if (!chan) {
- mutex_unlock(&conn->chan_lock);
- return 0;
- }
-
- l2cap_chan_lock(chan);
-
- sk = chan->sk;
-
- rsp.dcid = cpu_to_le16(chan->scid);
- rsp.scid = cpu_to_le16(chan->dcid);
- l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
-
- lock_sock(sk);
- sk->sk_shutdown = SHUTDOWN_MASK;
- release_sock(sk);
-
- l2cap_chan_del(chan, ECONNRESET);
-
- l2cap_chan_unlock(chan);
-
- chan->ops->close(chan->data);
-
- mutex_unlock(&conn->chan_lock);
-
- return 0;
-}
-
-static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
-{
- struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
- u16 dcid, scid;
- struct l2cap_chan *chan;
-
- scid = __le16_to_cpu(rsp->scid);
- dcid = __le16_to_cpu(rsp->dcid);
-
- BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
-
- mutex_lock(&conn->chan_lock);
-
- chan = __l2cap_get_chan_by_scid(conn, scid);
- if (!chan) {
- mutex_unlock(&conn->chan_lock);
- return 0;
- }
-
- l2cap_chan_lock(chan);
-
- l2cap_chan_del(chan, 0);
-
- l2cap_chan_unlock(chan);
-
- chan->ops->close(chan->data);
-
- mutex_unlock(&conn->chan_lock);
-
- return 0;
-}
-
-static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
-{
- struct l2cap_info_req *req = (struct l2cap_info_req *) data;
- u16 type;
-
- type = __le16_to_cpu(req->type);
-
- BT_DBG("type 0x%4.4x", type);
-
- if (type == L2CAP_IT_FEAT_MASK) {
- u8 buf[8];
- u32 feat_mask = l2cap_feat_mask;
- struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
- rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
- rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
- if (!disable_ertm)
- feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
- | L2CAP_FEAT_FCS;
- if (enable_hs)
- feat_mask |= L2CAP_FEAT_EXT_FLOW
- | L2CAP_FEAT_EXT_WINDOW;
-
- put_unaligned_le32(feat_mask, rsp->data);
- l2cap_send_cmd(conn, cmd->ident,
- L2CAP_INFO_RSP, sizeof(buf), buf);
- } else if (type == L2CAP_IT_FIXED_CHAN) {
- u8 buf[12];
- struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
-
- if (enable_hs)
- l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
- else
- l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
-
- rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
- rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
- memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
- l2cap_send_cmd(conn, cmd->ident,
- L2CAP_INFO_RSP, sizeof(buf), buf);
- } else {
- struct l2cap_info_rsp rsp;
- rsp.type = cpu_to_le16(type);
- rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
- l2cap_send_cmd(conn, cmd->ident,
- L2CAP_INFO_RSP, sizeof(rsp), &rsp);
- }
-
- return 0;
-}
-
-static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
-{
- struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
- u16 type, result;
-
- type = __le16_to_cpu(rsp->type);
- result = __le16_to_cpu(rsp->result);
-
- BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
-
- /* L2CAP Info req/rsp are unbound to channels, add extra checks */
- if (cmd->ident != conn->info_ident ||
- conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
- return 0;
-
- cancel_delayed_work(&conn->info_timer);
-
- if (result != L2CAP_IR_SUCCESS) {
- conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
- conn->info_ident = 0;
-
- l2cap_conn_start(conn);
-
- return 0;
- }
-
- switch (type) {
- case L2CAP_IT_FEAT_MASK:
- conn->feat_mask = get_unaligned_le32(rsp->data);
-
- if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
- struct l2cap_info_req req;
- req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
-
- conn->info_ident = l2cap_get_ident(conn);
-
- l2cap_send_cmd(conn, conn->info_ident,
- L2CAP_INFO_REQ, sizeof(req), &req);
- } else {
- conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
- conn->info_ident = 0;
-
- l2cap_conn_start(conn);
- }
- break;
-
- case L2CAP_IT_FIXED_CHAN:
- conn->fixed_chan_mask = rsp->data[0];
- conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
- conn->info_ident = 0;
-
- l2cap_conn_start(conn);
- break;
- }
-
- return 0;
-}
-
-static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
- struct l2cap_cmd_hdr *cmd, u16 cmd_len,
- void *data)
-{
- struct l2cap_create_chan_req *req = data;
- struct l2cap_create_chan_rsp rsp;
- u16 psm, scid;
-
- if (cmd_len != sizeof(*req))
- return -EPROTO;
-
- if (!enable_hs)
- return -EINVAL;
-
- psm = le16_to_cpu(req->psm);
- scid = le16_to_cpu(req->scid);
-
- BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
-
- /* Placeholder: Always reject */
- rsp.dcid = 0;
- rsp.scid = cpu_to_le16(scid);
- rsp.result = L2CAP_CR_NO_MEM;
- rsp.status = L2CAP_CS_NO_INFO;
-
- l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
- sizeof(rsp), &rsp);
-
- return 0;
-}
-
-static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
- struct l2cap_cmd_hdr *cmd, void *data)
-{
- BT_DBG("conn %p", conn);
-
- return l2cap_connect_rsp(conn, cmd, data);
-}
-
-static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
- u16 icid, u16 result)
-{
- struct l2cap_move_chan_rsp rsp;
-
- BT_DBG("icid %d, result %d", icid, result);
-
- rsp.icid = cpu_to_le16(icid);
- rsp.result = cpu_to_le16(result);
-
- l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
-}
-
-static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
- struct l2cap_chan *chan, u16 icid, u16 result)
-{
- struct l2cap_move_chan_cfm cfm;
- u8 ident;
-
- BT_DBG("icid %d, result %d", icid, result);
-
- ident = l2cap_get_ident(conn);
- if (chan)
- chan->ident = ident;
-
- cfm.icid = cpu_to_le16(icid);
- cfm.result = cpu_to_le16(result);
-
- l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
-}
-
-static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
- u16 icid)
-{
- struct l2cap_move_chan_cfm_rsp rsp;
-
- BT_DBG("icid %d", icid);
-
- rsp.icid = cpu_to_le16(icid);
- l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
-}
-
-static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
- struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
-{
- struct l2cap_move_chan_req *req = data;
- u16 icid = 0;
- u16 result = L2CAP_MR_NOT_ALLOWED;
-
- if (cmd_len != sizeof(*req))
- return -EPROTO;
-
- icid = le16_to_cpu(req->icid);
-
- BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
-
- if (!enable_hs)
- return -EINVAL;
-
- /* Placeholder: Always refuse */
- l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
-
- return 0;
-}
-
-static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
- struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
-{
- struct l2cap_move_chan_rsp *rsp = data;
- u16 icid, result;
-
- if (cmd_len != sizeof(*rsp))
- return -EPROTO;
-
- icid = le16_to_cpu(rsp->icid);
- result = le16_to_cpu(rsp->result);
-
- BT_DBG("icid %d, result %d", icid, result);
-
- /* Placeholder: Always unconfirmed */
- l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
-
- return 0;
-}
-
-static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
- struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
-{
- struct l2cap_move_chan_cfm *cfm = data;
- u16 icid, result;
-
- if (cmd_len != sizeof(*cfm))
- return -EPROTO;
-
- icid = le16_to_cpu(cfm->icid);
- result = le16_to_cpu(cfm->result);
-
- BT_DBG("icid %d, result %d", icid, result);
-
- l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
-
- return 0;
-}
-
-static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
- struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
-{
- struct l2cap_move_chan_cfm_rsp *rsp = data;
- u16 icid;
-
- if (cmd_len != sizeof(*rsp))
- return -EPROTO;
-
- icid = le16_to_cpu(rsp->icid);
-
- BT_DBG("icid %d", icid);
-
- return 0;
-}
-
-static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
- u16 to_multiplier)
-{
- u16 max_latency;
-
- if (min > max || min < 6 || max > 3200)
- return -EINVAL;
-
- if (to_multiplier < 10 || to_multiplier > 3200)
- return -EINVAL;
-
- if (max >= to_multiplier * 8)
- return -EINVAL;
-
- max_latency = (to_multiplier * 8 / max) - 1;
- if (latency > 499 || latency > max_latency)
- return -EINVAL;
-
- return 0;
-}
-
-static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
- struct l2cap_cmd_hdr *cmd, u8 *data)
-{
- struct hci_conn *hcon = conn->hcon;
- struct l2cap_conn_param_update_req *req;
- struct l2cap_conn_param_update_rsp rsp;
- u16 min, max, latency, to_multiplier, cmd_len;
- int err;
-
- if (!(hcon->link_mode & HCI_LM_MASTER))
- return -EINVAL;
-
- cmd_len = __le16_to_cpu(cmd->len);
- if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
- return -EPROTO;
-
- req = (struct l2cap_conn_param_update_req *) data;
- min = __le16_to_cpu(req->min);
- max = __le16_to_cpu(req->max);
- latency = __le16_to_cpu(req->latency);
- to_multiplier = __le16_to_cpu(req->to_multiplier);
-
- BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
- min, max, latency, to_multiplier);
-
- memset(&rsp, 0, sizeof(rsp));
-
- err = l2cap_check_conn_param(min, max, latency, to_multiplier);
- if (err)
- rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
- else
- rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
-
- l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
- sizeof(rsp), &rsp);
-
- if (!err)
- hci_le_conn_update(hcon, min, max, latency, to_multiplier);
-
- return 0;
-}
-
-static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
- struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
-{
- int err = 0;
-
- switch (cmd->code) {
- case L2CAP_COMMAND_REJ:
- l2cap_command_rej(conn, cmd, data);
- break;
-
- case L2CAP_CONN_REQ:
- err = l2cap_connect_req(conn, cmd, data);
- break;
-
- case L2CAP_CONN_RSP:
- err = l2cap_connect_rsp(conn, cmd, data);
- break;
-
- case L2CAP_CONF_REQ:
- err = l2cap_config_req(conn, cmd, cmd_len, data);
- break;
-
- case L2CAP_CONF_RSP:
- err = l2cap_config_rsp(conn, cmd, data);
- break;
-
- case L2CAP_DISCONN_REQ:
- err = l2cap_disconnect_req(conn, cmd, data);
- break;
-
- case L2CAP_DISCONN_RSP:
- err = l2cap_disconnect_rsp(conn, cmd, data);
- break;
-
- case L2CAP_ECHO_REQ:
- l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
- break;
-
- case L2CAP_ECHO_RSP:
- break;
-
- case L2CAP_INFO_REQ:
- err = l2cap_information_req(conn, cmd, data);
- break;
-
- case L2CAP_INFO_RSP:
- err = l2cap_information_rsp(conn, cmd, data);
- break;
-
- case L2CAP_CREATE_CHAN_REQ:
- err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
- break;
-
- case L2CAP_CREATE_CHAN_RSP:
- err = l2cap_create_channel_rsp(conn, cmd, data);
- break;
-
- case L2CAP_MOVE_CHAN_REQ:
- err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
- break;
-
- case L2CAP_MOVE_CHAN_RSP:
- err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
- break;
-
- case L2CAP_MOVE_CHAN_CFM:
- err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
- break;
-
- case L2CAP_MOVE_CHAN_CFM_RSP:
- err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
- break;
-
- default:
- BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
- err = -EINVAL;
- break;
- }
-
- return err;
-}
-
-static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
- struct l2cap_cmd_hdr *cmd, u8 *data)
-{
- switch (cmd->code) {
- case L2CAP_COMMAND_REJ:
- return 0;
-
- case L2CAP_CONN_PARAM_UPDATE_REQ:
- return l2cap_conn_param_update_req(conn, cmd, data);
-
- case L2CAP_CONN_PARAM_UPDATE_RSP:
- return 0;
-
- default:
- BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
- return -EINVAL;
- }
-}
-
-static inline void l2cap_sig_channel(struct l2cap_conn *conn,
- struct sk_buff *skb)
-{
- u8 *data = skb->data;
- int len = skb->len;
- struct l2cap_cmd_hdr cmd;
- int err;
-
- l2cap_raw_recv(conn, skb);
-
- while (len >= L2CAP_CMD_HDR_SIZE) {
- u16 cmd_len;
- memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
- data += L2CAP_CMD_HDR_SIZE;
- len -= L2CAP_CMD_HDR_SIZE;
-
- cmd_len = le16_to_cpu(cmd.len);
-
- BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd_len, cmd.ident);
-
- if (cmd_len > len || !cmd.ident) {
- BT_DBG("corrupted command");
- break;
- }
-
- if (conn->hcon->type == LE_LINK)
- err = l2cap_le_sig_cmd(conn, &cmd, data);
- else
- err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
-
- if (err) {
- struct l2cap_cmd_rej_unk rej;
-
- BT_ERR("Wrong link type (%d)", err);
-
- /* FIXME: Map err to a valid reason */
- rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
- l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
- }
-
- data += cmd_len;
- len -= cmd_len;
- }
-
- kfree_skb(skb);
-}
-
-static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
-{
- u16 our_fcs, rcv_fcs;
- int hdr_size;
-
- if (test_bit(FLAG_EXT_CTRL, &chan->flags))
- hdr_size = L2CAP_EXT_HDR_SIZE;
- else
- hdr_size = L2CAP_ENH_HDR_SIZE;
-
- if (chan->fcs == L2CAP_FCS_CRC16) {
- skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
- rcv_fcs = get_unaligned_le16(skb->data + skb->len);
- our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
-
- if (our_fcs != rcv_fcs)
- return -EBADMSG;
- }
- return 0;
-}
-
-static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
-{
- u32 control = 0;
-
- chan->frames_sent = 0;
-
- control |= __set_reqseq(chan, chan->buffer_seq);
-
- if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
- control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
- l2cap_send_sframe(chan, control);
- set_bit(CONN_RNR_SENT, &chan->conn_state);
- }
-
- if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
- l2cap_retransmit_frames(chan);
-
- l2cap_ertm_send(chan);
-
- if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
- chan->frames_sent == 0) {
- control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
- l2cap_send_sframe(chan, control);
- }
-}
-
-static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u16 tx_seq, u8 sar)
-{
- struct sk_buff *next_skb;
- int tx_seq_offset, next_tx_seq_offset;
-
- bt_cb(skb)->tx_seq = tx_seq;
- bt_cb(skb)->sar = sar;
-
- next_skb = skb_peek(&chan->srej_q);
-
- tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
-
- while (next_skb) {
- if (bt_cb(next_skb)->tx_seq == tx_seq)
- return -EINVAL;
-
- next_tx_seq_offset = __seq_offset(chan,
- bt_cb(next_skb)->tx_seq, chan->buffer_seq);
-
- if (next_tx_seq_offset > tx_seq_offset) {
- __skb_queue_before(&chan->srej_q, next_skb, skb);
- return 0;
- }
-
- if (skb_queue_is_last(&chan->srej_q, next_skb))
- next_skb = NULL;
- else
- next_skb = skb_queue_next(&chan->srej_q, next_skb);
- }
-
- __skb_queue_tail(&chan->srej_q, skb);
-
- return 0;
-}
-
-static void append_skb_frag(struct sk_buff *skb,
- struct sk_buff *new_frag, struct sk_buff **last_frag)
-{
- /* skb->len reflects data in skb as well as all fragments
- * skb->data_len reflects only data in fragments
- */
- if (!skb_has_frag_list(skb))
- skb_shinfo(skb)->frag_list = new_frag;
-
- new_frag->next = NULL;
-
- (*last_frag)->next = new_frag;
- *last_frag = new_frag;
-
- skb->len += new_frag->len;
- skb->data_len += new_frag->len;
- skb->truesize += new_frag->truesize;
-}
-
-static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
-{
- int err = -EINVAL;
-
- switch (__get_ctrl_sar(chan, control)) {
- case L2CAP_SAR_UNSEGMENTED:
- if (chan->sdu)
- break;
-
- err = chan->ops->recv(chan->data, skb);
- break;
-
- case L2CAP_SAR_START:
- if (chan->sdu)
- break;
-
- chan->sdu_len = get_unaligned_le16(skb->data);
- skb_pull(skb, L2CAP_SDULEN_SIZE);
-
- if (chan->sdu_len > chan->imtu) {
- err = -EMSGSIZE;
- break;
- }
-
- if (skb->len >= chan->sdu_len)
- break;
-
- chan->sdu = skb;
- chan->sdu_last_frag = skb;
-
- skb = NULL;
- err = 0;
- break;
-
- case L2CAP_SAR_CONTINUE:
- if (!chan->sdu)
- break;
-
- append_skb_frag(chan->sdu, skb,
- &chan->sdu_last_frag);
- skb = NULL;
-
- if (chan->sdu->len >= chan->sdu_len)
- break;
-
- err = 0;
- break;
-
- case L2CAP_SAR_END:
- if (!chan->sdu)
- break;
-
- append_skb_frag(chan->sdu, skb,
- &chan->sdu_last_frag);
- skb = NULL;
-
- if (chan->sdu->len != chan->sdu_len)
- break;
-
- err = chan->ops->recv(chan->data, chan->sdu);
-
- if (!err) {
- /* Reassembly complete */
- chan->sdu = NULL;
- chan->sdu_last_frag = NULL;
- chan->sdu_len = 0;
- }
- break;
- }
-
- if (err) {
- kfree_skb(skb);
- kfree_skb(chan->sdu);
- chan->sdu = NULL;
- chan->sdu_last_frag = NULL;
- chan->sdu_len = 0;
- }
-
- return err;
-}
-
-static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
-{
- BT_DBG("chan %p, Enter local busy", chan);
-
- set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
-
- __set_ack_timer(chan);
-}
-
-static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
-{
- u32 control;
-
- if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
- goto done;
-
- control = __set_reqseq(chan, chan->buffer_seq);
- control |= __set_ctrl_poll(chan);
- control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
- l2cap_send_sframe(chan, control);
- chan->retry_count = 1;
-
- __clear_retrans_timer(chan);
- __set_monitor_timer(chan);
-
- set_bit(CONN_WAIT_F, &chan->conn_state);
-
-done:
- clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
- clear_bit(CONN_RNR_SENT, &chan->conn_state);
-
- BT_DBG("chan %p, Exit local busy", chan);
-}
-
-void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
-{
- if (chan->mode == L2CAP_MODE_ERTM) {
- if (busy)
- l2cap_ertm_enter_local_busy(chan);
- else
- l2cap_ertm_exit_local_busy(chan);
- }
-}
-
-static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
-{
- struct sk_buff *skb;
- u32 control;
-
- while ((skb = skb_peek(&chan->srej_q)) &&
- !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
- int err;
-
- if (bt_cb(skb)->tx_seq != tx_seq)
- break;
-
- skb = skb_dequeue(&chan->srej_q);
- control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
- err = l2cap_reassemble_sdu(chan, skb, control);
-
- if (err < 0) {
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
- break;
- }
-
- chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
- tx_seq = __next_seq(chan, tx_seq);
- }
-}
-
-static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
-{
- struct srej_list *l, *tmp;
- u32 control;
-
- list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
- if (l->tx_seq == tx_seq) {
- list_del(&l->list);
- kfree(l);
- return;
- }
- control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
- control |= __set_reqseq(chan, l->tx_seq);
- l2cap_send_sframe(chan, control);
- list_del(&l->list);
- list_add_tail(&l->list, &chan->srej_l);
- }
-}
-
-static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
-{
- struct srej_list *new;
- u32 control;
-
- while (tx_seq != chan->expected_tx_seq) {
- control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
- control |= __set_reqseq(chan, chan->expected_tx_seq);
- l2cap_send_sframe(chan, control);
-
- new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
- if (!new)
- return -ENOMEM;
-
- new->tx_seq = chan->expected_tx_seq;
-
- chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
-
- list_add_tail(&new->list, &chan->srej_l);
- }
-
- chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
-
- return 0;
-}
-
-static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
-{
- u16 tx_seq = __get_txseq(chan, rx_control);
- u16 req_seq = __get_reqseq(chan, rx_control);
- u8 sar = __get_ctrl_sar(chan, rx_control);
- int tx_seq_offset, expected_tx_seq_offset;
- int num_to_ack = (chan->tx_win/6) + 1;
- int err = 0;
-
- BT_DBG("chan %p len %d tx_seq %d rx_control 0x%8.8x", chan, skb->len,
- tx_seq, rx_control);
-
- if (__is_ctrl_final(chan, rx_control) &&
- test_bit(CONN_WAIT_F, &chan->conn_state)) {
- __clear_monitor_timer(chan);
- if (chan->unacked_frames > 0)
- __set_retrans_timer(chan);
- clear_bit(CONN_WAIT_F, &chan->conn_state);
- }
-
- chan->expected_ack_seq = req_seq;
- l2cap_drop_acked_frames(chan);
-
- tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
-
- /* invalid tx_seq */
- if (tx_seq_offset >= chan->tx_win) {
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
- goto drop;
- }
-
- if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
- if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
- l2cap_send_ack(chan);
- goto drop;
- }
-
- if (tx_seq == chan->expected_tx_seq)
- goto expected;
-
- if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
- struct srej_list *first;
-
- first = list_first_entry(&chan->srej_l,
- struct srej_list, list);
- if (tx_seq == first->tx_seq) {
- l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
- l2cap_check_srej_gap(chan, tx_seq);
-
- list_del(&first->list);
- kfree(first);
-
- if (list_empty(&chan->srej_l)) {
- chan->buffer_seq = chan->buffer_seq_srej;
- clear_bit(CONN_SREJ_SENT, &chan->conn_state);
- l2cap_send_ack(chan);
- BT_DBG("chan %p, Exit SREJ_SENT", chan);
- }
- } else {
- struct srej_list *l;
-
- /* duplicated tx_seq */
- if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
- goto drop;
-
- list_for_each_entry(l, &chan->srej_l, list) {
- if (l->tx_seq == tx_seq) {
- l2cap_resend_srejframe(chan, tx_seq);
- return 0;
- }
- }
-
- err = l2cap_send_srejframe(chan, tx_seq);
- if (err < 0) {
- l2cap_send_disconn_req(chan->conn, chan, -err);
- return err;
- }
- }
- } else {
- expected_tx_seq_offset = __seq_offset(chan,
- chan->expected_tx_seq, chan->buffer_seq);
-
- /* duplicated tx_seq */
- if (tx_seq_offset < expected_tx_seq_offset)
- goto drop;
-
- set_bit(CONN_SREJ_SENT, &chan->conn_state);
-
- BT_DBG("chan %p, Enter SREJ", chan);
-
- INIT_LIST_HEAD(&chan->srej_l);
- chan->buffer_seq_srej = chan->buffer_seq;
-
- __skb_queue_head_init(&chan->srej_q);
- l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
-
- /* Set P-bit only if there are some I-frames to ack. */
- if (__clear_ack_timer(chan))
- set_bit(CONN_SEND_PBIT, &chan->conn_state);
-
- err = l2cap_send_srejframe(chan, tx_seq);
- if (err < 0) {
- l2cap_send_disconn_req(chan->conn, chan, -err);
- return err;
- }
- }
- return 0;
-
-expected:
- chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
-
- if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
- bt_cb(skb)->tx_seq = tx_seq;
- bt_cb(skb)->sar = sar;
- __skb_queue_tail(&chan->srej_q, skb);
- return 0;
- }
-
- err = l2cap_reassemble_sdu(chan, skb, rx_control);
- chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
-
- if (err < 0) {
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
- return err;
- }
-
- if (__is_ctrl_final(chan, rx_control)) {
- if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
- l2cap_retransmit_frames(chan);
- }
-
-
- chan->num_acked = (chan->num_acked + 1) % num_to_ack;
- if (chan->num_acked == num_to_ack - 1)
- l2cap_send_ack(chan);
- else
- __set_ack_timer(chan);
-
- return 0;
-
-drop:
- kfree_skb(skb);
- return 0;
-}
-
-static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
-{
- BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
- __get_reqseq(chan, rx_control), rx_control);
-
- chan->expected_ack_seq = __get_reqseq(chan, rx_control);
- l2cap_drop_acked_frames(chan);
-
- if (__is_ctrl_poll(chan, rx_control)) {
- set_bit(CONN_SEND_FBIT, &chan->conn_state);
- if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
- if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
- (chan->unacked_frames > 0))
- __set_retrans_timer(chan);
-
- clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
- l2cap_send_srejtail(chan);
- } else {
- l2cap_send_i_or_rr_or_rnr(chan);
- }
-
- } else if (__is_ctrl_final(chan, rx_control)) {
- clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
-
- if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
- l2cap_retransmit_frames(chan);
-
- } else {
- if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
- (chan->unacked_frames > 0))
- __set_retrans_timer(chan);
-
- clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
- if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
- l2cap_send_ack(chan);
- else
- l2cap_ertm_send(chan);
- }
-}
-
-static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
-{
- u16 tx_seq = __get_reqseq(chan, rx_control);
-
- BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
-
- clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
-
- chan->expected_ack_seq = tx_seq;
- l2cap_drop_acked_frames(chan);
-
- if (__is_ctrl_final(chan, rx_control)) {
- if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
- l2cap_retransmit_frames(chan);
- } else {
- l2cap_retransmit_frames(chan);
-
- if (test_bit(CONN_WAIT_F, &chan->conn_state))
- set_bit(CONN_REJ_ACT, &chan->conn_state);
- }
-}
-static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
-{
- u16 tx_seq = __get_reqseq(chan, rx_control);
-
- BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
-
- clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
-
- if (__is_ctrl_poll(chan, rx_control)) {
- chan->expected_ack_seq = tx_seq;
- l2cap_drop_acked_frames(chan);
-
- set_bit(CONN_SEND_FBIT, &chan->conn_state);
- l2cap_retransmit_one_frame(chan, tx_seq);
-
- l2cap_ertm_send(chan);
-
- if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
- chan->srej_save_reqseq = tx_seq;
- set_bit(CONN_SREJ_ACT, &chan->conn_state);
- }
- } else if (__is_ctrl_final(chan, rx_control)) {
- if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
- chan->srej_save_reqseq == tx_seq)
- clear_bit(CONN_SREJ_ACT, &chan->conn_state);
- else
- l2cap_retransmit_one_frame(chan, tx_seq);
- } else {
- l2cap_retransmit_one_frame(chan, tx_seq);
- if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
- chan->srej_save_reqseq = tx_seq;
- set_bit(CONN_SREJ_ACT, &chan->conn_state);
- }
- }
-}
-
-static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
-{
- u16 tx_seq = __get_reqseq(chan, rx_control);
-
- BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
-
- set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
- chan->expected_ack_seq = tx_seq;
- l2cap_drop_acked_frames(chan);
-
- if (__is_ctrl_poll(chan, rx_control))
- set_bit(CONN_SEND_FBIT, &chan->conn_state);
-
- if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
- __clear_retrans_timer(chan);
- if (__is_ctrl_poll(chan, rx_control))
- l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
- return;
- }
-
- if (__is_ctrl_poll(chan, rx_control)) {
- l2cap_send_srejtail(chan);
- } else {
- rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
- l2cap_send_sframe(chan, rx_control);
- }
-}
-
-static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
-{
- BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
-
- if (__is_ctrl_final(chan, rx_control) &&
- test_bit(CONN_WAIT_F, &chan->conn_state)) {
- __clear_monitor_timer(chan);
- if (chan->unacked_frames > 0)
- __set_retrans_timer(chan);
- clear_bit(CONN_WAIT_F, &chan->conn_state);
- }
-
- switch (__get_ctrl_super(chan, rx_control)) {
- case L2CAP_SUPER_RR:
- l2cap_data_channel_rrframe(chan, rx_control);
- break;
-
- case L2CAP_SUPER_REJ:
- l2cap_data_channel_rejframe(chan, rx_control);
- break;
-
- case L2CAP_SUPER_SREJ:
- l2cap_data_channel_srejframe(chan, rx_control);
- break;
-
- case L2CAP_SUPER_RNR:
- l2cap_data_channel_rnrframe(chan, rx_control);
- break;
- }
-
- kfree_skb(skb);
- return 0;
-}
-
-static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
-{
- u32 control;
- u16 req_seq;
- int len, next_tx_seq_offset, req_seq_offset;
-
- control = __get_control(chan, skb->data);
- skb_pull(skb, __ctrl_size(chan));
- len = skb->len;
-
- /*
- * We can just drop the corrupted I-frame here.
- * Receiver will miss it and start proper recovery
- * procedures and ask retransmission.
- */
- if (l2cap_check_fcs(chan, skb))
- goto drop;
-
- if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
- len -= L2CAP_SDULEN_SIZE;
-
- if (chan->fcs == L2CAP_FCS_CRC16)
- len -= L2CAP_FCS_SIZE;
-
- if (len > chan->mps) {
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
- goto drop;
- }
-
- req_seq = __get_reqseq(chan, control);
-
- req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
-
- next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
- chan->expected_ack_seq);
-
- /* check for invalid req-seq */
- if (req_seq_offset > next_tx_seq_offset) {
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
- goto drop;
- }
-
- if (!__is_sframe(chan, control)) {
- if (len < 0) {
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
- goto drop;
- }
-
- l2cap_data_channel_iframe(chan, control, skb);
- } else {
- if (len != 0) {
- BT_ERR("%d", len);
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
- goto drop;
- }
-
- l2cap_data_channel_sframe(chan, control, skb);
- }
-
- return 0;
-
-drop:
- kfree_skb(skb);
- return 0;
-}
-
-static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
-{
- struct l2cap_chan *chan;
- u32 control;
- u16 tx_seq;
- int len;
-
- chan = l2cap_get_chan_by_scid(conn, cid);
- if (!chan) {
- BT_DBG("unknown cid 0x%4.4x", cid);
- /* Drop packet and return */
- kfree_skb(skb);
- return 0;
- }
-
- BT_DBG("chan %p, len %d", chan, skb->len);
-
- if (chan->state != BT_CONNECTED)
- goto drop;
-
- switch (chan->mode) {
- case L2CAP_MODE_BASIC:
- /* If socket recv buffers overflows we drop data here
- * which is *bad* because L2CAP has to be reliable.
- * But we don't have any other choice. L2CAP doesn't
- * provide flow control mechanism. */
-
- if (chan->imtu < skb->len)
- goto drop;
-
- if (!chan->ops->recv(chan->data, skb))
- goto done;
- break;
-
- case L2CAP_MODE_ERTM:
- l2cap_ertm_data_rcv(chan, skb);
-
- goto done;
-
- case L2CAP_MODE_STREAMING:
- control = __get_control(chan, skb->data);
- skb_pull(skb, __ctrl_size(chan));
- len = skb->len;
-
- if (l2cap_check_fcs(chan, skb))
- goto drop;
-
- if (__is_sar_start(chan, control))
- len -= L2CAP_SDULEN_SIZE;
-
- if (chan->fcs == L2CAP_FCS_CRC16)
- len -= L2CAP_FCS_SIZE;
-
- if (len > chan->mps || len < 0 || __is_sframe(chan, control))
- goto drop;
-
- tx_seq = __get_txseq(chan, control);
-
- if (chan->expected_tx_seq != tx_seq) {
- /* Frame(s) missing - must discard partial SDU */
- kfree_skb(chan->sdu);
- chan->sdu = NULL;
- chan->sdu_last_frag = NULL;
- chan->sdu_len = 0;
-
- /* TODO: Notify userland of missing data */
- }
-
- chan->expected_tx_seq = __next_seq(chan, tx_seq);
-
- if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
-
- goto done;
-
- default:
- BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
- break;
- }
-
-drop:
- kfree_skb(skb);
-
-done:
- l2cap_chan_unlock(chan);
-
- return 0;
-}
-
-static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
-{
- struct l2cap_chan *chan;
-
- chan = l2cap_global_chan_by_psm(0, psm, conn->src);
- if (!chan)
- goto drop;
-
- BT_DBG("chan %p, len %d", chan, skb->len);
-
- if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
- goto drop;
-
- if (chan->imtu < skb->len)
- goto drop;
-
- if (!chan->ops->recv(chan->data, skb))
- return 0;
-
-drop:
- kfree_skb(skb);
-
- return 0;
-}
-
-static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
-{
- struct l2cap_chan *chan;
-
- chan = l2cap_global_chan_by_scid(0, cid, conn->src);
- if (!chan)
- goto drop;
-
- BT_DBG("chan %p, len %d", chan, skb->len);
-
- if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
- goto drop;
-
- if (chan->imtu < skb->len)
- goto drop;
-
- if (!chan->ops->recv(chan->data, skb))
- return 0;
-
-drop:
- kfree_skb(skb);
-
- return 0;
-}
-
-static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
-{
- struct l2cap_hdr *lh = (void *) skb->data;
- u16 cid, len;
- __le16 psm;
-
- skb_pull(skb, L2CAP_HDR_SIZE);
- cid = __le16_to_cpu(lh->cid);
- len = __le16_to_cpu(lh->len);
-
- if (len != skb->len) {
- kfree_skb(skb);
- return;
- }
-
- BT_DBG("len %d, cid 0x%4.4x", len, cid);
-
- switch (cid) {
- case L2CAP_CID_LE_SIGNALING:
- case L2CAP_CID_SIGNALING:
- l2cap_sig_channel(conn, skb);
- break;
-
- case L2CAP_CID_CONN_LESS:
- psm = get_unaligned_le16(skb->data);
- skb_pull(skb, 2);
- l2cap_conless_channel(conn, psm, skb);
- break;
-
- case L2CAP_CID_LE_DATA:
- l2cap_att_channel(conn, cid, skb);
- break;
-
- case L2CAP_CID_SMP:
- if (smp_sig_channel(conn, skb))
- l2cap_conn_del(conn->hcon, EACCES);
- break;
-
- default:
- l2cap_data_channel(conn, cid, skb);
- break;
- }
-}
-
-/* ---- L2CAP interface with lower layer (HCI) ---- */
-
-int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- int exact = 0, lm1 = 0, lm2 = 0;
- struct l2cap_chan *c;
-
- BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
-
- /* Find listening sockets and check their link_mode */
- read_lock(&chan_list_lock);
- list_for_each_entry(c, &chan_list, global_l) {
- struct sock *sk = c->sk;
-
- if (c->state != BT_LISTEN)
- continue;
-
- if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
- lm1 |= HCI_LM_ACCEPT;
- if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
- lm1 |= HCI_LM_MASTER;
- exact++;
- } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
- lm2 |= HCI_LM_ACCEPT;
- if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
- lm2 |= HCI_LM_MASTER;
- }
- }
- read_unlock(&chan_list_lock);
-
- return exact ? lm1 : lm2;
-}
-
-int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
-{
- struct l2cap_conn *conn;
-
- BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
-
- if (!status) {
- conn = l2cap_conn_add(hcon, status);
- if (conn)
- l2cap_conn_ready(conn);
- } else
- l2cap_conn_del(hcon, bt_to_errno(status));
-
- return 0;
-}
-
-int l2cap_disconn_ind(struct hci_conn *hcon)
-{
- struct l2cap_conn *conn = hcon->l2cap_data;
-
- BT_DBG("hcon %p", hcon);
-
- if (!conn)
- return HCI_ERROR_REMOTE_USER_TERM;
- return conn->disc_reason;
-}
-
-int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
-{
- BT_DBG("hcon %p reason %d", hcon, reason);
-
- l2cap_conn_del(hcon, bt_to_errno(reason));
- return 0;
-}
-
-static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
-{
- if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
- return;
-
- if (encrypt == 0x00) {
- if (chan->sec_level == BT_SECURITY_MEDIUM) {
- __clear_chan_timer(chan);
- __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
- } else if (chan->sec_level == BT_SECURITY_HIGH)
- l2cap_chan_close(chan, ECONNREFUSED);
- } else {
- if (chan->sec_level == BT_SECURITY_MEDIUM)
- __clear_chan_timer(chan);
- }
-}
-
-int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
-{
- struct l2cap_conn *conn = hcon->l2cap_data;
- struct l2cap_chan *chan;
-
- if (!conn)
- return 0;
-
- BT_DBG("conn %p", conn);
-
- if (hcon->type == LE_LINK) {
- smp_distribute_keys(conn, 0);
- cancel_delayed_work(&conn->security_timer);
- }
-
- mutex_lock(&conn->chan_lock);
-
- list_for_each_entry(chan, &conn->chan_l, list) {
- l2cap_chan_lock(chan);
-
- BT_DBG("chan->scid %d", chan->scid);
-
- if (chan->scid == L2CAP_CID_LE_DATA) {
- if (!status && encrypt) {
- chan->sec_level = hcon->sec_level;
- l2cap_chan_ready(chan);
- }
-
- l2cap_chan_unlock(chan);
- continue;
- }
-
- if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
- l2cap_chan_unlock(chan);
- continue;
- }
-
- if (!status && (chan->state == BT_CONNECTED ||
- chan->state == BT_CONFIG)) {
- struct sock *sk = chan->sk;
-
- bt_sk(sk)->suspended = false;
- sk->sk_state_change(sk);
-
- l2cap_check_encryption(chan, encrypt);
- l2cap_chan_unlock(chan);
- continue;
- }
-
- if (chan->state == BT_CONNECT) {
- if (!status) {
- l2cap_send_conn_req(chan);
- } else {
- __clear_chan_timer(chan);
- __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
- }
- } else if (chan->state == BT_CONNECT2) {
- struct sock *sk = chan->sk;
- struct l2cap_conn_rsp rsp;
- __u16 res, stat;
-
- lock_sock(sk);
-
- if (!status) {
- if (bt_sk(sk)->defer_setup) {
- struct sock *parent = bt_sk(sk)->parent;
- res = L2CAP_CR_PEND;
- stat = L2CAP_CS_AUTHOR_PEND;
- if (parent)
- parent->sk_data_ready(parent, 0);
- } else {
- __l2cap_state_change(chan, BT_CONFIG);
- res = L2CAP_CR_SUCCESS;
- stat = L2CAP_CS_NO_INFO;
- }
- } else {
- __l2cap_state_change(chan, BT_DISCONN);
- __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
- res = L2CAP_CR_SEC_BLOCK;
- stat = L2CAP_CS_NO_INFO;
- }
-
- release_sock(sk);
-
- rsp.scid = cpu_to_le16(chan->dcid);
- rsp.dcid = cpu_to_le16(chan->scid);
- rsp.result = cpu_to_le16(res);
- rsp.status = cpu_to_le16(stat);
- l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
- sizeof(rsp), &rsp);
- }
-
- l2cap_chan_unlock(chan);
- }
-
- mutex_unlock(&conn->chan_lock);
-
- return 0;
-}
-
-int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
-{
- struct l2cap_conn *conn = hcon->l2cap_data;
-
- if (!conn)
- conn = l2cap_conn_add(hcon, 0);
-
- if (!conn)
- goto drop;
-
- BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
-
- if (!(flags & ACL_CONT)) {
- struct l2cap_hdr *hdr;
- int len;
-
- if (conn->rx_len) {
- BT_ERR("Unexpected start frame (len %d)", skb->len);
- kfree_skb(conn->rx_skb);
- conn->rx_skb = NULL;
- conn->rx_len = 0;
- l2cap_conn_unreliable(conn, ECOMM);
- }
-
- /* Start fragment always begin with Basic L2CAP header */
- if (skb->len < L2CAP_HDR_SIZE) {
- BT_ERR("Frame is too short (len %d)", skb->len);
- l2cap_conn_unreliable(conn, ECOMM);
- goto drop;
- }
-
- hdr = (struct l2cap_hdr *) skb->data;
- len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
-
- if (len == skb->len) {
- /* Complete frame received */
- l2cap_recv_frame(conn, skb);
- return 0;
- }
-
- BT_DBG("Start: total len %d, frag len %d", len, skb->len);
-
- if (skb->len > len) {
- BT_ERR("Frame is too long (len %d, expected len %d)",
- skb->len, len);
- l2cap_conn_unreliable(conn, ECOMM);
- goto drop;
- }
-
- /* Allocate skb for the complete frame (with header) */
- conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (!conn->rx_skb)
- goto drop;
-
- skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
- skb->len);
- conn->rx_len = len - skb->len;
- } else {
- BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
-
- if (!conn->rx_len) {
- BT_ERR("Unexpected continuation frame (len %d)", skb->len);
- l2cap_conn_unreliable(conn, ECOMM);
- goto drop;
- }
-
- if (skb->len > conn->rx_len) {
- BT_ERR("Fragment is too long (len %d, expected %d)",
- skb->len, conn->rx_len);
- kfree_skb(conn->rx_skb);
- conn->rx_skb = NULL;
- conn->rx_len = 0;
- l2cap_conn_unreliable(conn, ECOMM);
- goto drop;
- }
-
- skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
- skb->len);
- conn->rx_len -= skb->len;
-
- if (!conn->rx_len) {
- /* Complete frame received */
- l2cap_recv_frame(conn, conn->rx_skb);
- conn->rx_skb = NULL;
- }
- }
-
-drop:
- kfree_skb(skb);
- return 0;
-}
-
-static int l2cap_debugfs_show(struct seq_file *f, void *p)
-{
- struct l2cap_chan *c;
-
- read_lock(&chan_list_lock);
-
- list_for_each_entry(c, &chan_list, global_l) {
- struct sock *sk = c->sk;
-
- seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
- batostr(&bt_sk(sk)->src),
- batostr(&bt_sk(sk)->dst),
- c->state, __le16_to_cpu(c->psm),
- c->scid, c->dcid, c->imtu, c->omtu,
- c->sec_level, c->mode);
- }
-
- read_unlock(&chan_list_lock);
-
- return 0;
-}
-
-static int l2cap_debugfs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, l2cap_debugfs_show, inode->i_private);
-}
-
-static const struct file_operations l2cap_debugfs_fops = {
- .open = l2cap_debugfs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static struct dentry *l2cap_debugfs;
-
-int __init l2cap_init(void)
-{
- int err;
-
- err = l2cap_init_sockets();
- if (err < 0)
- return err;
-
- if (bt_debugfs) {
- l2cap_debugfs = debugfs_create_file("l2cap", 0444,
- bt_debugfs, NULL, &l2cap_debugfs_fops);
- if (!l2cap_debugfs)
- BT_ERR("Failed to create L2CAP debug file");
- }
-
- return 0;
-}
-
-void l2cap_exit(void)
-{
- debugfs_remove(l2cap_debugfs);
- l2cap_cleanup_sockets();
-}
-
-module_param(disable_ertm, bool, 0644);
-MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
diff --git a/net/bluetooth_tizen/l2cap_sock.c b/net/bluetooth_tizen/l2cap_sock.c
deleted file mode 100644
index 2cae7af..0000000
--- a/net/bluetooth_tizen/l2cap_sock.c
+++ /dev/null
@@ -1,1156 +0,0 @@
-/*
- BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
- Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
- Copyright (C) 2010 Google Inc.
- Copyright (C) 2011 ProFUSION Embedded Systems
-
- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/* Bluetooth L2CAP sockets. */
-
-#include <linux/security.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/l2cap.h>
-#include <net/bluetooth/smp.h>
-
-static const struct proto_ops l2cap_sock_ops;
-static void l2cap_sock_init(struct sock *sk, struct sock *parent);
-static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio);
-
-static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
-{
- struct sock *sk = sock->sk;
- struct l2cap_chan *chan = l2cap_pi(sk)->chan;
- struct sockaddr_l2 la;
- int len, err = 0;
-
- BT_DBG("sk %p", sk);
-
- if (!addr || addr->sa_family != AF_BLUETOOTH)
- return -EINVAL;
-
- memset(&la, 0, sizeof(la));
- len = min_t(unsigned int, sizeof(la), alen);
- memcpy(&la, addr, len);
-
- if (la.l2_cid && la.l2_psm)
- return -EINVAL;
-
- lock_sock(sk);
-
- if (sk->sk_state != BT_OPEN) {
- err = -EBADFD;
- goto done;
- }
-
- if (la.l2_psm) {
- __u16 psm = __le16_to_cpu(la.l2_psm);
-
- /* PSM must be odd and lsb of upper byte must be 0 */
- if ((psm & 0x0101) != 0x0001) {
- err = -EINVAL;
- goto done;
- }
-
- /* Restrict usage of well-known PSMs */
- if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) {
- err = -EACCES;
- goto done;
- }
- }
-
- if (la.l2_cid)
- err = l2cap_add_scid(chan, __le16_to_cpu(la.l2_cid));
- else
- err = l2cap_add_psm(chan, &la.l2_bdaddr, la.l2_psm);
-
- if (err < 0)
- goto done;
-
- if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
- __le16_to_cpu(la.l2_psm) == 0x0003)
- chan->sec_level = BT_SECURITY_SDP;
-
- bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
-
- chan->state = BT_BOUND;
- sk->sk_state = BT_BOUND;
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
-{
- struct sock *sk = sock->sk;
- struct l2cap_chan *chan = l2cap_pi(sk)->chan;
- struct sockaddr_l2 la;
- int len, err = 0;
-
- BT_DBG("sk %p", sk);
-
- if (!addr || alen < sizeof(addr->sa_family) ||
- addr->sa_family != AF_BLUETOOTH)
- return -EINVAL;
-
- memset(&la, 0, sizeof(la));
- len = min_t(unsigned int, sizeof(la), alen);
- memcpy(&la, addr, len);
-
- if (la.l2_cid && la.l2_psm)
- return -EINVAL;
-
- err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid),
- &la.l2_bdaddr);
- if (err)
- return err;
-
- lock_sock(sk);
-
- err = bt_sock_wait_state(sk, BT_CONNECTED,
- sock_sndtimeo(sk, flags & O_NONBLOCK));
-
- release_sock(sk);
-
- return err;
-}
-
-static int l2cap_sock_listen(struct socket *sock, int backlog)
-{
- struct sock *sk = sock->sk;
- struct l2cap_chan *chan = l2cap_pi(sk)->chan;
- int err = 0;
-
- BT_DBG("sk %p backlog %d", sk, backlog);
-
- lock_sock(sk);
-
- if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM)
- || sk->sk_state != BT_BOUND) {
- err = -EBADFD;
- goto done;
- }
-
- switch (chan->mode) {
- case L2CAP_MODE_BASIC:
- break;
- case L2CAP_MODE_ERTM:
- case L2CAP_MODE_STREAMING:
- if (!disable_ertm)
- break;
- /* fall through */
- default:
- err = -ENOTSUPP;
- goto done;
- }
-
- sk->sk_max_ack_backlog = backlog;
- sk->sk_ack_backlog = 0;
-
- chan->state = BT_LISTEN;
- sk->sk_state = BT_LISTEN;
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct sock *sk = sock->sk, *nsk;
- long timeo;
- int err = 0;
-
- lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
-
- timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
-
- BT_DBG("sk %p timeo %ld", sk, timeo);
-
- /* Wait for an incoming connection. (wake-one). */
- add_wait_queue_exclusive(sk_sleep(sk), &wait);
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
- break;
- }
-
- nsk = bt_accept_dequeue(sk, newsock);
- if (nsk)
- break;
-
- if (!timeo) {
- err = -EAGAIN;
- break;
- }
-
- if (signal_pending(current)) {
- err = sock_intr_errno(timeo);
- break;
- }
-
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(sk), &wait);
-
- if (err)
- goto done;
-
- newsock->state = SS_CONNECTED;
-
- BT_DBG("new socket %p", nsk);
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
-{
- struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
- struct sock *sk = sock->sk;
- struct l2cap_chan *chan = l2cap_pi(sk)->chan;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- addr->sa_family = AF_BLUETOOTH;
- *len = sizeof(struct sockaddr_l2);
-
- if (peer) {
- la->l2_psm = chan->psm;
- bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst);
- la->l2_cid = cpu_to_le16(chan->dcid);
- } else {
- la->l2_psm = chan->sport;
- bacpy(&la->l2_bdaddr, &bt_sk(sk)->src);
- la->l2_cid = cpu_to_le16(chan->scid);
- }
-
- return 0;
-}
-
-static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
-{
- struct sock *sk = sock->sk;
- struct l2cap_chan *chan = l2cap_pi(sk)->chan;
- struct l2cap_options opts;
- struct l2cap_conninfo cinfo;
- int len, err = 0;
- u32 opt;
-
- BT_DBG("sk %p", sk);
-
- if (get_user(len, optlen))
- return -EFAULT;
-
- lock_sock(sk);
-
- switch (optname) {
- case L2CAP_OPTIONS:
- memset(&opts, 0, sizeof(opts));
- opts.imtu = chan->imtu;
- opts.omtu = chan->omtu;
- opts.flush_to = chan->flush_to;
- opts.mode = chan->mode;
- opts.fcs = chan->fcs;
- opts.max_tx = chan->max_tx;
- opts.txwin_size = chan->tx_win;
-
- len = min_t(unsigned int, len, sizeof(opts));
- if (copy_to_user(optval, (char *) &opts, len))
- err = -EFAULT;
-
- break;
-
- case L2CAP_LM:
- switch (chan->sec_level) {
- case BT_SECURITY_LOW:
- opt = L2CAP_LM_AUTH;
- break;
- case BT_SECURITY_MEDIUM:
- opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT;
- break;
- case BT_SECURITY_HIGH:
- opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
- L2CAP_LM_SECURE;
- break;
- default:
- opt = 0;
- break;
- }
-
- if (test_bit(FLAG_ROLE_SWITCH, &chan->flags))
- opt |= L2CAP_LM_MASTER;
-
- if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
- opt |= L2CAP_LM_RELIABLE;
-
- if (put_user(opt, (u32 __user *) optval))
- err = -EFAULT;
- break;
-
- case L2CAP_CONNINFO:
- if (sk->sk_state != BT_CONNECTED &&
- !(sk->sk_state == BT_CONNECT2 &&
- bt_sk(sk)->defer_setup)) {
- err = -ENOTCONN;
- break;
- }
-
- memset(&cinfo, 0, sizeof(cinfo));
- cinfo.hci_handle = chan->conn->hcon->handle;
- memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3);
-
- len = min_t(unsigned int, len, sizeof(cinfo));
- if (copy_to_user(optval, (char *) &cinfo, len))
- err = -EFAULT;
-
- break;
-
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
-{
- struct sock *sk = sock->sk;
- struct l2cap_chan *chan = l2cap_pi(sk)->chan;
- struct bt_security sec;
- struct bt_power pwr;
- int len, err = 0;
-
- BT_DBG("sk %p", sk);
-
- if (level == SOL_L2CAP)
- return l2cap_sock_getsockopt_old(sock, optname, optval, optlen);
-
- if (level != SOL_BLUETOOTH)
- return -ENOPROTOOPT;
-
- if (get_user(len, optlen))
- return -EFAULT;
-
- lock_sock(sk);
-
- switch (optname) {
- case BT_SECURITY:
- if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
- chan->chan_type != L2CAP_CHAN_RAW) {
- err = -EINVAL;
- break;
- }
-
- memset(&sec, 0, sizeof(sec));
- if (chan->conn)
- sec.level = chan->conn->hcon->sec_level;
- else
- sec.level = chan->sec_level;
-
- if (sk->sk_state == BT_CONNECTED)
- sec.key_size = chan->conn->hcon->enc_key_size;
-
- len = min_t(unsigned int, len, sizeof(sec));
- if (copy_to_user(optval, (char *) &sec, len))
- err = -EFAULT;
-
- break;
-
- case BT_DEFER_SETUP:
- if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
- err = -EINVAL;
- break;
- }
-
- if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval))
- err = -EFAULT;
-
- break;
-
- case BT_FLUSHABLE:
- if (put_user(test_bit(FLAG_FLUSHABLE, &chan->flags),
- (u32 __user *) optval))
- err = -EFAULT;
-
- break;
-
- case BT_POWER:
- if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
- && sk->sk_type != SOCK_RAW) {
- err = -EINVAL;
- break;
- }
-
- pwr.force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
-
- len = min_t(unsigned int, len, sizeof(pwr));
- if (copy_to_user(optval, (char *) &pwr, len))
- err = -EFAULT;
-
- break;
-
- case BT_CHANNEL_POLICY:
- if (!enable_hs) {
- err = -ENOPROTOOPT;
- break;
- }
-
- if (put_user(chan->chan_policy, (u32 __user *) optval))
- err = -EFAULT;
- break;
-
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
-{
- struct sock *sk = sock->sk;
- struct l2cap_chan *chan = l2cap_pi(sk)->chan;
- struct l2cap_options opts;
- int len, err = 0;
- u32 opt;
-
- BT_DBG("sk %p", sk);
-
- lock_sock(sk);
-
- switch (optname) {
- case L2CAP_OPTIONS:
- if (sk->sk_state == BT_CONNECTED) {
- err = -EINVAL;
- break;
- }
-
- opts.imtu = chan->imtu;
- opts.omtu = chan->omtu;
- opts.flush_to = chan->flush_to;
- opts.mode = chan->mode;
- opts.fcs = chan->fcs;
- opts.max_tx = chan->max_tx;
- opts.txwin_size = chan->tx_win;
-
- len = min_t(unsigned int, sizeof(opts), optlen);
- if (copy_from_user((char *) &opts, optval, len)) {
- err = -EFAULT;
- break;
- }
-
- if (opts.txwin_size > L2CAP_DEFAULT_EXT_WINDOW) {
- err = -EINVAL;
- break;
- }
-
- chan->mode = opts.mode;
- switch (chan->mode) {
- case L2CAP_MODE_BASIC:
- clear_bit(CONF_STATE2_DEVICE, &chan->conf_state);
- break;
- case L2CAP_MODE_ERTM:
- case L2CAP_MODE_STREAMING:
- if (!disable_ertm)
- break;
- /* fall through */
- default:
- err = -EINVAL;
- break;
- }
-
- chan->imtu = opts.imtu;
- chan->omtu = opts.omtu;
- chan->fcs = opts.fcs;
- chan->max_tx = opts.max_tx;
- chan->tx_win = opts.txwin_size;
- break;
-
- case L2CAP_LM:
- if (get_user(opt, (u32 __user *) optval)) {
- err = -EFAULT;
- break;
- }
-
- if (opt & L2CAP_LM_AUTH)
- chan->sec_level = BT_SECURITY_LOW;
- if (opt & L2CAP_LM_ENCRYPT)
- chan->sec_level = BT_SECURITY_MEDIUM;
- if (opt & L2CAP_LM_SECURE)
- chan->sec_level = BT_SECURITY_HIGH;
-
- if (opt & L2CAP_LM_MASTER)
- set_bit(FLAG_ROLE_SWITCH, &chan->flags);
- else
- clear_bit(FLAG_ROLE_SWITCH, &chan->flags);
-
- if (opt & L2CAP_LM_RELIABLE)
- set_bit(FLAG_FORCE_RELIABLE, &chan->flags);
- else
- clear_bit(FLAG_FORCE_RELIABLE, &chan->flags);
- break;
-
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
-{
- struct sock *sk = sock->sk;
- struct l2cap_chan *chan = l2cap_pi(sk)->chan;
- struct bt_security sec;
- struct bt_power pwr;
- struct l2cap_conn *conn;
- int len, err = 0;
- u32 opt;
-
- BT_DBG("sk %p", sk);
-
- if (level == SOL_L2CAP)
- return l2cap_sock_setsockopt_old(sock, optname, optval, optlen);
-
- if (level != SOL_BLUETOOTH)
- return -ENOPROTOOPT;
-
- lock_sock(sk);
-
- switch (optname) {
- case BT_SECURITY:
- if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
- chan->chan_type != L2CAP_CHAN_RAW) {
- err = -EINVAL;
- break;
- }
-
- sec.level = BT_SECURITY_LOW;
-
- len = min_t(unsigned int, sizeof(sec), optlen);
- if (copy_from_user((char *) &sec, optval, len)) {
- err = -EFAULT;
- break;
- }
-
- if (sec.level < BT_SECURITY_LOW ||
- sec.level > BT_SECURITY_HIGH) {
- err = -EINVAL;
- break;
- }
-
- chan->sec_level = sec.level;
-
- if (!chan->conn)
- break;
-
- conn = chan->conn;
-
- /*change security for LE channels */
- if (chan->scid == L2CAP_CID_LE_DATA) {
- if (!conn->hcon->out) {
- err = -EINVAL;
- break;
- }
-
- if (smp_conn_security(conn, sec.level))
- break;
- sk->sk_state = BT_CONFIG;
- chan->state = BT_CONFIG;
-
- /* or for ACL link */
- } else if ((sk->sk_state == BT_CONNECT2 &&
- bt_sk(sk)->defer_setup) ||
- sk->sk_state == BT_CONNECTED) {
- if (!l2cap_chan_check_security(chan))
- bt_sk(sk)->suspended = true;
- else
- sk->sk_state_change(sk);
- }
- else {
- err = -EINVAL;
- }
- break;
-
- case BT_DEFER_SETUP:
- if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
- err = -EINVAL;
- break;
- }
-
- if (get_user(opt, (u32 __user *) optval)) {
- err = -EFAULT;
- break;
- }
-
- bt_sk(sk)->defer_setup = opt;
- break;
-
- case BT_FLUSHABLE:
- if (get_user(opt, (u32 __user *) optval)) {
- err = -EFAULT;
- break;
- }
-
- if (opt > BT_FLUSHABLE_ON) {
- err = -EINVAL;
- break;
- }
-
- if (opt == BT_FLUSHABLE_OFF) {
- struct l2cap_conn *conn = chan->conn;
- /* proceed further only when we have l2cap_conn and
- No Flush support in the LM */
- if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) {
- err = -EINVAL;
- break;
- }
- }
-
- if (opt)
- set_bit(FLAG_FLUSHABLE, &chan->flags);
- else
- clear_bit(FLAG_FLUSHABLE, &chan->flags);
- break;
-
- case BT_POWER:
- if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
- chan->chan_type != L2CAP_CHAN_RAW) {
- err = -EINVAL;
- break;
- }
-
- pwr.force_active = BT_POWER_FORCE_ACTIVE_ON;
-
- len = min_t(unsigned int, sizeof(pwr), optlen);
- if (copy_from_user((char *) &pwr, optval, len)) {
- err = -EFAULT;
- break;
- }
-
- if (pwr.force_active)
- set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
- else
- clear_bit(FLAG_FORCE_ACTIVE, &chan->flags);
- break;
-
- case BT_CHANNEL_POLICY:
- if (!enable_hs) {
- err = -ENOPROTOOPT;
- break;
- }
-
- if (get_user(opt, (u32 __user *) optval)) {
- err = -EFAULT;
- break;
- }
-
- if (opt > BT_CHANNEL_POLICY_AMP_PREFERRED) {
- err = -EINVAL;
- break;
- }
-
- if (chan->mode != L2CAP_MODE_ERTM &&
- chan->mode != L2CAP_MODE_STREAMING) {
- err = -EOPNOTSUPP;
- break;
- }
-
- chan->chan_policy = (u8) opt;
- break;
-
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
- release_sock(sk);
- return err;
-}
-
-static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len)
-{
- struct sock *sk = sock->sk;
- struct l2cap_chan *chan = l2cap_pi(sk)->chan;
- int err;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- err = sock_error(sk);
- if (err)
- return err;
-
- if (msg->msg_flags & MSG_OOB)
- return -EOPNOTSUPP;
-
- l2cap_chan_lock(chan);
-
- if (sk->sk_state != BT_CONNECTED) {
- l2cap_chan_unlock(chan);
- return -ENOTCONN;
- }
-
- err = l2cap_chan_send(chan, msg, len, sk->sk_priority);
- l2cap_chan_unlock(chan);
-
- return err;
-}
-
-static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags)
-{
- struct sock *sk = sock->sk;
- struct l2cap_pinfo *pi = l2cap_pi(sk);
- int err;
-
- lock_sock(sk);
-
- if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
- sk->sk_state = BT_CONFIG;
- pi->chan->state = BT_CONFIG;
-
- __l2cap_connect_rsp_defer(pi->chan);
- release_sock(sk);
- return 0;
- }
-
- release_sock(sk);
-
- if (sock->type == SOCK_STREAM)
- err = bt_sock_stream_recvmsg(iocb, sock, msg, len, flags);
- else
- err = bt_sock_recvmsg(iocb, sock, msg, len, flags);
-
- if (pi->chan->mode != L2CAP_MODE_ERTM)
- return err;
-
- /* Attempt to put pending rx data in the socket buffer */
-
- lock_sock(sk);
-
- if (!test_bit(CONN_LOCAL_BUSY, &pi->chan->conn_state))
- goto done;
-
- if (pi->rx_busy_skb) {
- if (!sock_queue_rcv_skb(sk, pi->rx_busy_skb))
- pi->rx_busy_skb = NULL;
- else
- goto done;
- }
-
- /* Restore data flow when half of the receive buffer is
- * available. This avoids resending large numbers of
- * frames.
- */
- if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf >> 1)
- l2cap_chan_busy(pi->chan, 0);
-
-done:
- release_sock(sk);
- return err;
-}
-
-/* Kill socket (only if zapped and orphan)
- * Must be called on unlocked socket.
- */
-static void l2cap_sock_kill(struct sock *sk)
-{
- if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket ||
- sock_flag(sk, SOCK_DEAD))
- return;
-
- BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state));
-
- /* Kill poor orphan */
-
- l2cap_chan_destroy(l2cap_pi(sk)->chan);
- sock_set_flag(sk, SOCK_DEAD);
- sock_put(sk);
-}
-
-static int l2cap_sock_shutdown(struct socket *sock, int how)
-{
- struct sock *sk = sock->sk;
- struct l2cap_chan *chan;
- struct l2cap_conn *conn;
- int err = 0;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
- chan = l2cap_pi(sk)->chan;
- conn = chan->conn;
-
- if (conn)
- mutex_lock(&conn->chan_lock);
-
- l2cap_chan_lock(chan);
- lock_sock(sk);
-
- if (!sk->sk_shutdown) {
- if (chan->mode == L2CAP_MODE_ERTM)
- err = __l2cap_wait_ack(sk);
-
- sk->sk_shutdown = SHUTDOWN_MASK;
-
- release_sock(sk);
- l2cap_chan_close(chan, 0);
- lock_sock(sk);
-
- if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
- err = bt_sock_wait_state(sk, BT_CLOSED,
- sk->sk_lingertime);
- }
-
- if (!err && sk->sk_err)
- err = -sk->sk_err;
-
- release_sock(sk);
- l2cap_chan_unlock(chan);
-
- if (conn)
- mutex_unlock(&conn->chan_lock);
-
- return err;
-}
-
-static int l2cap_sock_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
- int err;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
- err = l2cap_sock_shutdown(sock, 2);
-
- sock_orphan(sk);
- l2cap_sock_kill(sk);
- return err;
-}
-
-static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data)
-{
- struct sock *sk, *parent = data;
-
- sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP,
- GFP_ATOMIC);
- if (!sk)
- return NULL;
-
- bt_sock_reclassify_lock(sk, BTPROTO_L2CAP);
-
- l2cap_sock_init(sk, parent);
-
- return l2cap_pi(sk)->chan;
-}
-
-static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
-{
- int err;
- struct sock *sk = data;
- struct l2cap_pinfo *pi = l2cap_pi(sk);
-
- lock_sock(sk);
-
- if (pi->rx_busy_skb) {
- err = -ENOMEM;
- goto done;
- }
-
- err = sock_queue_rcv_skb(sk, skb);
-
- /* For ERTM, handle one skb that doesn't fit into the recv
- * buffer. This is important to do because the data frames
- * have already been acked, so the skb cannot be discarded.
- *
- * Notify the l2cap core that the buffer is full, so the
- * LOCAL_BUSY state is entered and no more frames are
- * acked and reassembled until there is buffer space
- * available.
- */
- if (err < 0 && pi->chan->mode == L2CAP_MODE_ERTM) {
- pi->rx_busy_skb = skb;
- l2cap_chan_busy(pi->chan, 1);
- err = 0;
- }
-
-done:
- release_sock(sk);
-
- return err;
-}
-
-static void l2cap_sock_close_cb(void *data)
-{
- struct sock *sk = data;
-
- l2cap_sock_kill(sk);
-}
-
-static void l2cap_sock_state_change_cb(void *data, int state)
-{
- struct sock *sk = data;
-
- sk->sk_state = state;
-}
-
-static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
- unsigned long len, int nb,
- int *err)
-{
- struct sk_buff *skb;
-
- l2cap_chan_unlock(chan);
-
- skb = bt_skb_send_alloc(chan->sk, len, nb, err);
-
- l2cap_chan_lock(chan);
-
- return skb;
-}
-
-static struct l2cap_ops l2cap_chan_ops = {
- .name = "L2CAP Socket Interface",
- .new_connection = l2cap_sock_new_connection_cb,
- .recv = l2cap_sock_recv_cb,
- .close = l2cap_sock_close_cb,
- .state_change = l2cap_sock_state_change_cb,
- .alloc_skb = l2cap_sock_alloc_skb_cb,
-};
-
-static void l2cap_sock_destruct(struct sock *sk)
-{
- BT_DBG("sk %p", sk);
-
- if (l2cap_pi(sk)->rx_busy_skb) {
- kfree_skb(l2cap_pi(sk)->rx_busy_skb);
- l2cap_pi(sk)->rx_busy_skb = NULL;
- }
-
- skb_queue_purge(&sk->sk_receive_queue);
- skb_queue_purge(&sk->sk_write_queue);
-}
-
-static void l2cap_sock_init(struct sock *sk, struct sock *parent)
-{
- struct l2cap_pinfo *pi = l2cap_pi(sk);
- struct l2cap_chan *chan = pi->chan;
-
- BT_DBG("sk %p", sk);
-
- if (parent) {
- struct l2cap_chan *pchan = l2cap_pi(parent)->chan;
-
- sk->sk_type = parent->sk_type;
- bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup;
-
- chan->chan_type = pchan->chan_type;
- chan->imtu = pchan->imtu;
- chan->omtu = pchan->omtu;
- chan->conf_state = pchan->conf_state;
- chan->mode = pchan->mode;
- chan->fcs = pchan->fcs;
- chan->max_tx = pchan->max_tx;
- chan->tx_win = pchan->tx_win;
- chan->tx_win_max = pchan->tx_win_max;
- chan->sec_level = pchan->sec_level;
- chan->flags = pchan->flags;
-
- security_sk_clone(parent, sk);
- } else {
-
- switch (sk->sk_type) {
- case SOCK_RAW:
- chan->chan_type = L2CAP_CHAN_RAW;
- break;
- case SOCK_DGRAM:
- chan->chan_type = L2CAP_CHAN_CONN_LESS;
- break;
- case SOCK_SEQPACKET:
- case SOCK_STREAM:
- chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
- break;
- }
-
- chan->imtu = L2CAP_DEFAULT_MTU;
- chan->omtu = 0;
- if (!disable_ertm && sk->sk_type == SOCK_STREAM) {
- chan->mode = L2CAP_MODE_ERTM;
- set_bit(CONF_STATE2_DEVICE, &chan->conf_state);
- } else {
- chan->mode = L2CAP_MODE_BASIC;
- }
- chan->max_tx = L2CAP_DEFAULT_MAX_TX;
- chan->fcs = L2CAP_FCS_CRC16;
- chan->tx_win = L2CAP_DEFAULT_TX_WINDOW;
- chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
- chan->sec_level = BT_SECURITY_LOW;
- chan->flags = 0;
- set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
- }
-
- /* Default config options */
- chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
-
- chan->data = sk;
- chan->ops = &l2cap_chan_ops;
-}
-
-static struct proto l2cap_proto = {
- .name = "L2CAP",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct l2cap_pinfo)
-};
-
-static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
-{
- struct sock *sk;
- struct l2cap_chan *chan;
-
- sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto);
- if (!sk)
- return NULL;
-
- sock_init_data(sock, sk);
- INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
-
- sk->sk_destruct = l2cap_sock_destruct;
- sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT;
-
- sock_reset_flag(sk, SOCK_ZAPPED);
-
- sk->sk_protocol = proto;
- sk->sk_state = BT_OPEN;
-
- chan = l2cap_chan_create(sk);
- if (!chan) {
- l2cap_sock_kill(sk);
- return NULL;
- }
-
- l2cap_pi(sk)->chan = chan;
-
- return sk;
-}
-
-static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
-
- BT_DBG("sock %p", sock);
-
- sock->state = SS_UNCONNECTED;
-
- if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM &&
- sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
- return -ESOCKTNOSUPPORT;
-
- if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
- return -EPERM;
-
- sock->ops = &l2cap_sock_ops;
-
- sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC);
- if (!sk)
- return -ENOMEM;
-
- l2cap_sock_init(sk, NULL);
- return 0;
-}
-
-static const struct proto_ops l2cap_sock_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .release = l2cap_sock_release,
- .bind = l2cap_sock_bind,
- .connect = l2cap_sock_connect,
- .listen = l2cap_sock_listen,
- .accept = l2cap_sock_accept,
- .getname = l2cap_sock_getname,
- .sendmsg = l2cap_sock_sendmsg,
- .recvmsg = l2cap_sock_recvmsg,
- .poll = bt_sock_poll,
- .ioctl = bt_sock_ioctl,
- .mmap = sock_no_mmap,
- .socketpair = sock_no_socketpair,
- .shutdown = l2cap_sock_shutdown,
- .setsockopt = l2cap_sock_setsockopt,
- .getsockopt = l2cap_sock_getsockopt
-};
-
-static const struct net_proto_family l2cap_sock_family_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .create = l2cap_sock_create,
-};
-
-int __init l2cap_init_sockets(void)
-{
- int err;
-
- err = proto_register(&l2cap_proto, 0);
- if (err < 0)
- return err;
-
- err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
- if (err < 0)
- goto error;
-
- BT_INFO("L2CAP socket layer initialized");
-
- return 0;
-
-error:
- BT_ERR("L2CAP socket registration failed");
- proto_unregister(&l2cap_proto);
- return err;
-}
-
-void l2cap_cleanup_sockets(void)
-{
- if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
- BT_ERR("L2CAP socket unregistration failed");
-
- proto_unregister(&l2cap_proto);
-}
diff --git a/net/bluetooth_tizen/lib.c b/net/bluetooth_tizen/lib.c
deleted file mode 100644
index 5066288..0000000
--- a/net/bluetooth_tizen/lib.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
-
- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/* Bluetooth kernel library. */
-
-#define pr_fmt(fmt) "Bluetooth: " fmt
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <asm/errno.h>
-
-#include <net/bluetooth/bluetooth.h>
-
-void baswap(bdaddr_t *dst, bdaddr_t *src)
-{
- unsigned char *d = (unsigned char *) dst;
- unsigned char *s = (unsigned char *) src;
- unsigned int i;
-
- for (i = 0; i < 6; i++)
- d[i] = s[5 - i];
-}
-EXPORT_SYMBOL(baswap);
-
-char *batostr(bdaddr_t *ba)
-{
- static char str[2][18];
- static int i = 1;
-
- i ^= 1;
- sprintf(str[i], "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
- ba->b[5], ba->b[4], ba->b[3],
- ba->b[2], ba->b[1], ba->b[0]);
-
- return str[i];
-}
-EXPORT_SYMBOL(batostr);
-
-/* Bluetooth error codes to Unix errno mapping */
-int bt_to_errno(__u16 code)
-{
- switch (code) {
- case 0:
- return 0;
-
- case 0x01:
- return EBADRQC;
-
- case 0x02:
- return ENOTCONN;
-
- case 0x03:
- return EIO;
-
- case 0x04:
- return EHOSTDOWN;
-
- case 0x05:
- return EACCES;
-
- case 0x06:
- return EBADE;
-
- case 0x07:
- return ENOMEM;
-
- case 0x08:
- return ETIMEDOUT;
-
- case 0x09:
- return EMLINK;
-
- case 0x0a:
- return EMLINK;
-
- case 0x0b:
- return EALREADY;
-
- case 0x0c:
- return EBUSY;
-
- case 0x0d:
- case 0x0e:
- case 0x0f:
- return ECONNREFUSED;
-
- case 0x10:
- return ETIMEDOUT;
-
- case 0x11:
- case 0x27:
- case 0x29:
- case 0x20:
- return EOPNOTSUPP;
-
- case 0x12:
- return EINVAL;
-
- case 0x13:
- case 0x14:
- case 0x15:
- return ECONNRESET;
-
- case 0x16:
- return ECONNABORTED;
-
- case 0x17:
- return ELOOP;
-
- case 0x18:
- return EACCES;
-
- case 0x1a:
- return EPROTONOSUPPORT;
-
- case 0x1b:
- return ECONNREFUSED;
-
- case 0x19:
- case 0x1e:
- case 0x23:
- case 0x24:
- case 0x25:
- return EPROTO;
-
- default:
- return ENOSYS;
- }
-}
-EXPORT_SYMBOL(bt_to_errno);
-
-int bt_info(const char *format, ...)
-{
- struct va_format vaf;
- va_list args;
- int r;
-
- va_start(args, format);
-
- vaf.fmt = format;
- vaf.va = &args;
-
- r = pr_info("%pV", &vaf);
-
- va_end(args);
-
- return r;
-}
-EXPORT_SYMBOL(bt_info);
-
-int bt_err(const char *format, ...)
-{
- struct va_format vaf;
- va_list args;
- int r;
-
- va_start(args, format);
-
- vaf.fmt = format;
- vaf.va = &args;
-
- r = pr_err("%pV", &vaf);
-
- va_end(args);
-
- return r;
-}
-EXPORT_SYMBOL(bt_err);
diff --git a/net/bluetooth_tizen/mgmt.c b/net/bluetooth_tizen/mgmt.c
deleted file mode 100644
index 4bb03b1..0000000
--- a/net/bluetooth_tizen/mgmt.c
+++ /dev/null
@@ -1,3599 +0,0 @@
-/*
- BlueZ - Bluetooth protocol stack for Linux
-
- Copyright (C) 2010 Nokia Corporation
- Copyright (C) 2011-2012 Intel Corporation
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/* Bluetooth HCI Management interface */
-
-#include <linux/kernel.h>
-#include <linux/uaccess.h>
-#include <linux/module.h>
-#include <asm/unaligned.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/mgmt.h>
-#include <net/bluetooth/smp.h>
-
-bool enable_hs;
-bool enable_le;
-
-#define MGMT_VERSION 1
-#define MGMT_REVISION 0
-
-static const u16 mgmt_commands[] = {
- MGMT_OP_READ_INDEX_LIST,
- MGMT_OP_READ_INFO,
- MGMT_OP_SET_POWERED,
- MGMT_OP_SET_DISCOVERABLE,
- MGMT_OP_SET_CONNECTABLE,
- MGMT_OP_SET_FAST_CONNECTABLE,
- MGMT_OP_SET_PAIRABLE,
- MGMT_OP_SET_LINK_SECURITY,
- MGMT_OP_SET_SSP,
- MGMT_OP_SET_HS,
- MGMT_OP_SET_LE,
- MGMT_OP_SET_DEV_CLASS,
- MGMT_OP_SET_LOCAL_NAME,
- MGMT_OP_ADD_UUID,
- MGMT_OP_REMOVE_UUID,
- MGMT_OP_LOAD_LINK_KEYS,
- MGMT_OP_LOAD_LONG_TERM_KEYS,
- MGMT_OP_DISCONNECT,
- MGMT_OP_GET_CONNECTIONS,
- MGMT_OP_PIN_CODE_REPLY,
- MGMT_OP_PIN_CODE_NEG_REPLY,
- MGMT_OP_SET_IO_CAPABILITY,
- MGMT_OP_PAIR_DEVICE,
- MGMT_OP_CANCEL_PAIR_DEVICE,
- MGMT_OP_UNPAIR_DEVICE,
- MGMT_OP_USER_CONFIRM_REPLY,
- MGMT_OP_USER_CONFIRM_NEG_REPLY,
- MGMT_OP_USER_PASSKEY_REPLY,
- MGMT_OP_USER_PASSKEY_NEG_REPLY,
- MGMT_OP_READ_LOCAL_OOB_DATA,
- MGMT_OP_ADD_REMOTE_OOB_DATA,
- MGMT_OP_REMOVE_REMOTE_OOB_DATA,
- MGMT_OP_START_DISCOVERY,
- MGMT_OP_STOP_DISCOVERY,
- MGMT_OP_CONFIRM_NAME,
- MGMT_OP_BLOCK_DEVICE,
- MGMT_OP_UNBLOCK_DEVICE,
-};
-
-static const u16 mgmt_events[] = {
- MGMT_EV_CONTROLLER_ERROR,
- MGMT_EV_INDEX_ADDED,
- MGMT_EV_INDEX_REMOVED,
- MGMT_EV_NEW_SETTINGS,
- MGMT_EV_CLASS_OF_DEV_CHANGED,
- MGMT_EV_LOCAL_NAME_CHANGED,
- MGMT_EV_NEW_LINK_KEY,
- MGMT_EV_NEW_LONG_TERM_KEY,
- MGMT_EV_DEVICE_CONNECTED,
- MGMT_EV_DEVICE_DISCONNECTED,
- MGMT_EV_CONNECT_FAILED,
- MGMT_EV_PIN_CODE_REQUEST,
- MGMT_EV_USER_CONFIRM_REQUEST,
- MGMT_EV_USER_PASSKEY_REQUEST,
- MGMT_EV_AUTH_FAILED,
- MGMT_EV_DEVICE_FOUND,
- MGMT_EV_DISCOVERING,
- MGMT_EV_DEVICE_BLOCKED,
- MGMT_EV_DEVICE_UNBLOCKED,
- MGMT_EV_DEVICE_UNPAIRED,
-};
-
-/*
- * These LE scan and inquiry parameters were chosen according to LE General
- * Discovery Procedure specification.
- */
-#define LE_SCAN_TYPE 0x01
-#define LE_SCAN_WIN 0x12
-#define LE_SCAN_INT 0x12
-#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
-#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
-
-#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
-#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
-
-#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
-
-#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
- !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
-
-struct pending_cmd {
- struct list_head list;
- u16 opcode;
- int index;
- void *param;
- struct sock *sk;
- void *user_data;
-};
-
-/* HCI to MGMT error code conversion table */
-static u8 mgmt_status_table[] = {
- MGMT_STATUS_SUCCESS,
- MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
- MGMT_STATUS_NOT_CONNECTED, /* No Connection */
- MGMT_STATUS_FAILED, /* Hardware Failure */
- MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
- MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
- MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
- MGMT_STATUS_NO_RESOURCES, /* Memory Full */
- MGMT_STATUS_TIMEOUT, /* Connection Timeout */
- MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
- MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
- MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
- MGMT_STATUS_BUSY, /* Command Disallowed */
- MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
- MGMT_STATUS_REJECTED, /* Rejected Security */
- MGMT_STATUS_REJECTED, /* Rejected Personal */
- MGMT_STATUS_TIMEOUT, /* Host Timeout */
- MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
- MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
- MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
- MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
- MGMT_STATUS_DISCONNECTED, /* OE Power Off */
- MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
- MGMT_STATUS_BUSY, /* Repeated Attempts */
- MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
- MGMT_STATUS_FAILED, /* Unknown LMP PDU */
- MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
- MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
- MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
- MGMT_STATUS_REJECTED, /* Air Mode Rejected */
- MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
- MGMT_STATUS_FAILED, /* Unspecified Error */
- MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
- MGMT_STATUS_FAILED, /* Role Change Not Allowed */
- MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
- MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
- MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
- MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
- MGMT_STATUS_FAILED, /* Unit Link Key Used */
- MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
- MGMT_STATUS_TIMEOUT, /* Instant Passed */
- MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
- MGMT_STATUS_FAILED, /* Transaction Collision */
- MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
- MGMT_STATUS_REJECTED, /* QoS Rejected */
- MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
- MGMT_STATUS_REJECTED, /* Insufficient Security */
- MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
- MGMT_STATUS_BUSY, /* Role Switch Pending */
- MGMT_STATUS_FAILED, /* Slot Violation */
- MGMT_STATUS_FAILED, /* Role Switch Failed */
- MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
- MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
- MGMT_STATUS_BUSY, /* Host Busy Pairing */
- MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
- MGMT_STATUS_BUSY, /* Controller Busy */
- MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
- MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
- MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
- MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
- MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
-};
-
-static u8 mgmt_status(u8 hci_status)
-{
- if (hci_status < ARRAY_SIZE(mgmt_status_table))
- return mgmt_status_table[hci_status];
-
- return MGMT_STATUS_FAILED;
-}
-
-static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
-{
- struct sk_buff *skb;
- struct mgmt_hdr *hdr;
- struct mgmt_ev_cmd_status *ev;
- int err;
-
- BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
-
- skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- hdr = (void *) skb_put(skb, sizeof(*hdr));
-
- hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
- hdr->index = cpu_to_le16(index);
- hdr->len = cpu_to_le16(sizeof(*ev));
-
- ev = (void *) skb_put(skb, sizeof(*ev));
- ev->status = status;
- put_unaligned_le16(cmd, &ev->opcode);
-
- err = sock_queue_rcv_skb(sk, skb);
- if (err < 0)
- kfree_skb(skb);
-
- return err;
-}
-
-static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
- void *rp, size_t rp_len)
-{
- struct sk_buff *skb;
- struct mgmt_hdr *hdr;
- struct mgmt_ev_cmd_complete *ev;
- int err;
-
- BT_DBG("sock %p", sk);
-
- skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- hdr = (void *) skb_put(skb, sizeof(*hdr));
-
- hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
- hdr->index = cpu_to_le16(index);
- hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
-
- ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
- put_unaligned_le16(cmd, &ev->opcode);
- ev->status = status;
-
- if (rp)
- memcpy(ev->data, rp, rp_len);
-
- err = sock_queue_rcv_skb(sk, skb);
- if (err < 0)
- kfree_skb(skb);
-
- return err;
-}
-
-static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 data_len)
-{
- struct mgmt_rp_read_version rp;
-
- BT_DBG("sock %p", sk);
-
- rp.version = MGMT_VERSION;
- put_unaligned_le16(MGMT_REVISION, &rp.revision);
-
- return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
- sizeof(rp));
-}
-
-static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 data_len)
-{
- struct mgmt_rp_read_commands *rp;
- u16 num_commands = ARRAY_SIZE(mgmt_commands);
- u16 num_events = ARRAY_SIZE(mgmt_events);
- u16 *opcode;
- size_t rp_size;
- int i, err;
-
- BT_DBG("sock %p", sk);
-
- rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
-
- rp = kmalloc(rp_size, GFP_KERNEL);
- if (!rp)
- return -ENOMEM;
-
- put_unaligned_le16(num_commands, &rp->num_commands);
- put_unaligned_le16(num_events, &rp->num_events);
-
- for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
- put_unaligned_le16(mgmt_commands[i], opcode);
-
- for (i = 0; i < num_events; i++, opcode++)
- put_unaligned_le16(mgmt_events[i], opcode);
-
- err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
- rp_size);
- kfree(rp);
-
- return err;
-}
-
-static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 data_len)
-{
- struct mgmt_rp_read_index_list *rp;
- struct list_head *p;
- struct hci_dev *d;
- size_t rp_len;
- u16 count;
- int i, err;
-
- BT_DBG("sock %p", sk);
-
- read_lock(&hci_dev_list_lock);
-
- count = 0;
- list_for_each(p, &hci_dev_list) {
- count++;
- }
-
- rp_len = sizeof(*rp) + (2 * count);
- rp = kmalloc(rp_len, GFP_ATOMIC);
- if (!rp) {
- read_unlock(&hci_dev_list_lock);
- return -ENOMEM;
- }
-
- put_unaligned_le16(count, &rp->num_controllers);
-
- i = 0;
- list_for_each_entry(d, &hci_dev_list, list) {
- if (test_bit(HCI_SETUP, &d->dev_flags))
- continue;
-
- put_unaligned_le16(d->id, &rp->index[i++]);
- BT_DBG("Added hci%u", d->id);
- }
-
- read_unlock(&hci_dev_list_lock);
-
- err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
- rp_len);
-
- kfree(rp);
-
- return err;
-}
-
-static u32 get_supported_settings(struct hci_dev *hdev)
-{
- u32 settings = 0;
-
- settings |= MGMT_SETTING_POWERED;
- settings |= MGMT_SETTING_CONNECTABLE;
- settings |= MGMT_SETTING_FAST_CONNECTABLE;
- settings |= MGMT_SETTING_DISCOVERABLE;
- settings |= MGMT_SETTING_PAIRABLE;
-
- if (hdev->features[6] & LMP_SIMPLE_PAIR)
- settings |= MGMT_SETTING_SSP;
-
- if (!(hdev->features[4] & LMP_NO_BREDR)) {
- settings |= MGMT_SETTING_BREDR;
- settings |= MGMT_SETTING_LINK_SECURITY;
- }
-
- if (enable_hs)
- settings |= MGMT_SETTING_HS;
-
- if (enable_le) {
- if (hdev->features[4] & LMP_LE)
- settings |= MGMT_SETTING_LE;
- }
-
- return settings;
-}
-
-static u32 get_current_settings(struct hci_dev *hdev)
-{
- u32 settings = 0;
-
- if (hdev_is_powered(hdev))
- settings |= MGMT_SETTING_POWERED;
-
- if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
- settings |= MGMT_SETTING_CONNECTABLE;
-
- if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
- settings |= MGMT_SETTING_DISCOVERABLE;
-
- if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
- settings |= MGMT_SETTING_PAIRABLE;
-
- if (!(hdev->features[4] & LMP_NO_BREDR))
- settings |= MGMT_SETTING_BREDR;
-
- if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
- settings |= MGMT_SETTING_LE;
-
- if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
- settings |= MGMT_SETTING_LINK_SECURITY;
-
- if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
- settings |= MGMT_SETTING_SSP;
-
- if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
- settings |= MGMT_SETTING_HS;
-
- return settings;
-}
-
-#define PNP_INFO_SVCLASS_ID 0x1200
-
-static u8 bluetooth_base_uuid[] = {
- 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
- 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-static u16 get_uuid16(u8 *uuid128)
-{
- u32 val;
- int i;
-
- for (i = 0; i < 12; i++) {
- if (bluetooth_base_uuid[i] != uuid128[i])
- return 0;
- }
-
- memcpy(&val, &uuid128[12], 4);
-
- val = le32_to_cpu(val);
- if (val > 0xffff)
- return 0;
-
- return (u16) val;
-}
-
-static void create_eir(struct hci_dev *hdev, u8 *data)
-{
- u8 *ptr = data;
- u16 eir_len = 0;
- u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
- int i, truncated = 0;
- struct bt_uuid *uuid;
- size_t name_len;
-
- name_len = strlen(hdev->dev_name);
-
- if (name_len > 0) {
- /* EIR Data type */
- if (name_len > 48) {
- name_len = 48;
- ptr[1] = EIR_NAME_SHORT;
- } else
- ptr[1] = EIR_NAME_COMPLETE;
-
- /* EIR Data length */
- ptr[0] = name_len + 1;
-
- memcpy(ptr + 2, hdev->dev_name, name_len);
-
- eir_len += (name_len + 2);
- ptr += (name_len + 2);
- }
-
- memset(uuid16_list, 0, sizeof(uuid16_list));
-
- /* Group all UUID16 types */
- list_for_each_entry(uuid, &hdev->uuids, list) {
- u16 uuid16;
-
- uuid16 = get_uuid16(uuid->uuid);
- if (uuid16 == 0)
- return;
-
- if (uuid16 < 0x1100)
- continue;
-
- if (uuid16 == PNP_INFO_SVCLASS_ID)
- continue;
-
- /* Stop if not enough space to put next UUID */
- if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
- truncated = 1;
- break;
- }
-
- /* Check for duplicates */
- for (i = 0; uuid16_list[i] != 0; i++)
- if (uuid16_list[i] == uuid16)
- break;
-
- if (uuid16_list[i] == 0) {
- uuid16_list[i] = uuid16;
- eir_len += sizeof(u16);
- }
- }
-
- if (uuid16_list[0] != 0) {
- u8 *length = ptr;
-
- /* EIR Data type */
- ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
-
- ptr += 2;
- eir_len += 2;
-
- for (i = 0; uuid16_list[i] != 0; i++) {
- *ptr++ = (uuid16_list[i] & 0x00ff);
- *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
- }
-
- /* EIR Data length */
- *length = (i * sizeof(u16)) + 1;
- }
-}
-
-static int update_eir(struct hci_dev *hdev)
-{
- struct hci_cp_write_eir cp;
-
- if (!hdev_is_powered(hdev))
- return 0;
-
- if (!(hdev->features[6] & LMP_EXT_INQ))
- return 0;
-
- if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
- return 0;
-
- if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
- return 0;
-
- memset(&cp, 0, sizeof(cp));
-
- create_eir(hdev, cp.data);
-
- if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
- return 0;
-
- memcpy(hdev->eir, cp.data, sizeof(cp.data));
-
- return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
-}
-
-static u8 get_service_classes(struct hci_dev *hdev)
-{
- struct bt_uuid *uuid;
- u8 val = 0;
-
- list_for_each_entry(uuid, &hdev->uuids, list)
- val |= uuid->svc_hint;
-
- return val;
-}
-
-static int update_class(struct hci_dev *hdev)
-{
- u8 cod[3];
- int err;
-
- BT_DBG("%s", hdev->name);
-
- if (!hdev_is_powered(hdev))
- return 0;
-
- if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
- return 0;
-
- cod[0] = hdev->minor_class;
- cod[1] = hdev->major_class;
- cod[2] = get_service_classes(hdev);
-
- if (memcmp(cod, hdev->dev_class, 3) == 0)
- return 0;
-
- err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
- if (err == 0)
- set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
-
- return err;
-}
-
-static void service_cache_off(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- service_cache.work);
-
- if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
- return;
-
- hci_dev_lock(hdev);
-
- update_eir(hdev);
- update_class(hdev);
-
- hci_dev_unlock(hdev);
-}
-
-static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
-{
- if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
- return;
-
- INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
-
- /* Non-mgmt controlled devices get this bit set
- * implicitly so that pairing works for them, however
- * for mgmt we require user-space to explicitly enable
- * it
- */
- clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
-}
-
-static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
- void *data, u16 data_len)
-{
- struct mgmt_rp_read_info rp;
-
- BT_DBG("sock %p %s", sk, hdev->name);
-
- hci_dev_lock(hdev);
-
- memset(&rp, 0, sizeof(rp));
-
- bacpy(&rp.bdaddr, &hdev->bdaddr);
-
- rp.version = hdev->hci_ver;
-
- put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
-
- rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
- rp.current_settings = cpu_to_le32(get_current_settings(hdev));
-
- memcpy(rp.dev_class, hdev->dev_class, 3);
-
- memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
- memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
-
- hci_dev_unlock(hdev);
-
- return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
- sizeof(rp));
-}
-
-static void mgmt_pending_free(struct pending_cmd *cmd)
-{
- sock_put(cmd->sk);
- kfree(cmd->param);
- kfree(cmd);
-}
-
-static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
- struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct pending_cmd *cmd;
-
- cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
- if (!cmd)
- return NULL;
-
- cmd->opcode = opcode;
- cmd->index = hdev->id;
-
- cmd->param = kmalloc(len, GFP_ATOMIC);
- if (!cmd->param) {
- kfree(cmd);
- return NULL;
- }
-
- if (data)
- memcpy(cmd->param, data, len);
-
- cmd->sk = sk;
- sock_hold(sk);
-
- list_add(&cmd->list, &hdev->mgmt_pending);
-
- return cmd;
-}
-
-static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
- void (*cb)(struct pending_cmd *cmd, void *data),
- void *data)
-{
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &hdev->mgmt_pending) {
- struct pending_cmd *cmd;
-
- cmd = list_entry(p, struct pending_cmd, list);
-
- if (opcode > 0 && cmd->opcode != opcode)
- continue;
-
- cb(cmd, data);
- }
-}
-
-static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
-{
- struct pending_cmd *cmd;
-
- list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
- if (cmd->opcode == opcode)
- return cmd;
- }
-
- return NULL;
-}
-
-static void mgmt_pending_remove(struct pending_cmd *cmd)
-{
- list_del(&cmd->list);
- mgmt_pending_free(cmd);
-}
-
-static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
-{
- __le32 settings = cpu_to_le32(get_current_settings(hdev));
-
- return cmd_complete(sk, hdev->id, opcode, 0, &settings,
- sizeof(settings));
-}
-
-static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_mode *cp = data;
- struct pending_cmd *cmd;
- int err;
-
- BT_DBG("request for %s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
- cancel_delayed_work(&hdev->power_off);
-
- if (cp->val) {
- err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
- mgmt_powered(hdev, 1);
- goto failed;
- }
- }
-
- if (!!cp->val == hdev_is_powered(hdev)) {
- err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
- goto failed;
- }
-
- if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
- MGMT_STATUS_BUSY);
- goto failed;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
- if (!cmd) {
- err = -ENOMEM;
- goto failed;
- }
-
- if (cp->val)
- schedule_work(&hdev->power_on);
- else
- schedule_work(&hdev->power_off.work);
-
- err = 0;
-
-failed:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
- struct sock *skip_sk)
-{
- struct sk_buff *skb;
- struct mgmt_hdr *hdr;
-
- skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- hdr = (void *) skb_put(skb, sizeof(*hdr));
- hdr->opcode = cpu_to_le16(event);
- if (hdev)
- hdr->index = cpu_to_le16(hdev->id);
- else
- hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
- hdr->len = cpu_to_le16(data_len);
-
- if (data)
- memcpy(skb_put(skb, data_len), data, data_len);
-
- /* Time stamp */
- __net_timestamp(skb);
-
- hci_send_to_control(skb, skip_sk);
- kfree_skb(skb);
-
- return 0;
-}
-
-static int new_settings(struct hci_dev *hdev, struct sock *skip)
-{
- __le32 ev;
-
- ev = cpu_to_le32(get_current_settings(hdev));
-
- return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
-}
-
-static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_cp_set_discoverable *cp = data;
- struct pending_cmd *cmd;
- u16 timeout;
- u8 scan;
- int err;
-
- BT_DBG("request for %s", hdev->name);
-
- timeout = get_unaligned_le16(&cp->timeout);
- if (!cp->val && timeout > 0)
- return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
- MGMT_STATUS_INVALID_PARAMS);
-
- hci_dev_lock(hdev);
-
- if (!hdev_is_powered(hdev) && timeout > 0) {
- err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
- MGMT_STATUS_NOT_POWERED);
- goto failed;
- }
-
- if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
- mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
- MGMT_STATUS_BUSY);
- goto failed;
- }
-
- if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
- MGMT_STATUS_REJECTED);
- goto failed;
- }
-
- if (!hdev_is_powered(hdev)) {
- bool changed = false;
-
- if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
- change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
- changed = true;
- }
-
- err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
- if (err < 0)
- goto failed;
-
- if (changed)
- err = new_settings(hdev, sk);
-
- goto failed;
- }
-
- if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
- if (hdev->discov_timeout > 0) {
- cancel_delayed_work(&hdev->discov_off);
- hdev->discov_timeout = 0;
- }
-
- if (cp->val && timeout > 0) {
- hdev->discov_timeout = timeout;
- queue_delayed_work(hdev->workqueue, &hdev->discov_off,
- msecs_to_jiffies(hdev->discov_timeout * 1000));
- }
-
- err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
- goto failed;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
- if (!cmd) {
- err = -ENOMEM;
- goto failed;
- }
-
- scan = SCAN_PAGE;
-
- if (cp->val)
- scan |= SCAN_INQUIRY;
- else
- cancel_delayed_work(&hdev->discov_off);
-
- err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
- if (err < 0)
- mgmt_pending_remove(cmd);
-
- if (cp->val)
- hdev->discov_timeout = timeout;
-
-failed:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_mode *cp = data;
- struct pending_cmd *cmd;
- u8 scan;
- int err;
-
- BT_DBG("request for %s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (!hdev_is_powered(hdev)) {
- bool changed = false;
-
- if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
- changed = true;
-
- if (cp->val) {
- set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
- } else {
- clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
- clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
- }
-
- err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
- if (err < 0)
- goto failed;
-
- if (changed)
- err = new_settings(hdev, sk);
-
- goto failed;
- }
-
- if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
- mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
- MGMT_STATUS_BUSY);
- goto failed;
- }
-
- if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
- err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
- goto failed;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
- if (!cmd) {
- err = -ENOMEM;
- goto failed;
- }
-
- if (cp->val) {
- scan = SCAN_PAGE;
- } else {
- scan = 0;
-
- if (test_bit(HCI_ISCAN, &hdev->flags) &&
- hdev->discov_timeout > 0)
- cancel_delayed_work(&hdev->discov_off);
- }
-
- err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
- if (err < 0)
- mgmt_pending_remove(cmd);
-
-failed:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_mode *cp = data;
- int err;
-
- BT_DBG("request for %s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (cp->val)
- set_bit(HCI_PAIRABLE, &hdev->dev_flags);
- else
- clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
-
- err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
- if (err < 0)
- goto failed;
-
- err = new_settings(hdev, sk);
-
-failed:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_mode *cp = data;
- struct pending_cmd *cmd;
- u8 val;
- int err;
-
- BT_DBG("request for %s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (!hdev_is_powered(hdev)) {
- bool changed = false;
-
- if (!!cp->val != test_bit(HCI_LINK_SECURITY,
- &hdev->dev_flags)) {
- change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
- changed = true;
- }
-
- err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
- if (err < 0)
- goto failed;
-
- if (changed)
- err = new_settings(hdev, sk);
-
- goto failed;
- }
-
- if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
- MGMT_STATUS_BUSY);
- goto failed;
- }
-
- val = !!cp->val;
-
- if (test_bit(HCI_AUTH, &hdev->flags) == val) {
- err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
- goto failed;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
- if (!cmd) {
- err = -ENOMEM;
- goto failed;
- }
-
- err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
- if (err < 0) {
- mgmt_pending_remove(cmd);
- goto failed;
- }
-
-failed:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
-{
- struct mgmt_mode *cp = data;
- struct pending_cmd *cmd;
- u8 val;
- int err;
-
- BT_DBG("request for %s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
- MGMT_STATUS_NOT_SUPPORTED);
- goto failed;
- }
-
- val = !!cp->val;
-
- if (!hdev_is_powered(hdev)) {
- bool changed = false;
-
- if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
- change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
- changed = true;
- }
-
- err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
- if (err < 0)
- goto failed;
-
- if (changed)
- err = new_settings(hdev, sk);
-
- goto failed;
- }
-
- if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
- MGMT_STATUS_BUSY);
- goto failed;
- }
-
- if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
- err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
- goto failed;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
- if (!cmd) {
- err = -ENOMEM;
- goto failed;
- }
-
- err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
- if (err < 0) {
- mgmt_pending_remove(cmd);
- goto failed;
- }
-
-failed:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
-{
- struct mgmt_mode *cp = data;
-
- BT_DBG("request for %s", hdev->name);
-
- if (!enable_hs)
- return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
- MGMT_STATUS_NOT_SUPPORTED);
-
- if (cp->val)
- set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
- else
- clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
-
- return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
-}
-
-static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
-{
- struct mgmt_mode *cp = data;
- struct hci_cp_write_le_host_supported hci_cp;
- struct pending_cmd *cmd;
- int err;
- u8 val, enabled;
-
- BT_DBG("request for %s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (!enable_le || !(hdev->features[4] & LMP_LE)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
- MGMT_STATUS_NOT_SUPPORTED);
- goto unlock;
- }
-
- val = !!cp->val;
- enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
-
- if (!hdev_is_powered(hdev) || val == enabled) {
- bool changed = false;
-
- if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
- change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
- changed = true;
- }
-
- err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
- if (err < 0)
- goto unlock;
-
- if (changed)
- err = new_settings(hdev, sk);
-
- goto unlock;
- }
-
- if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
- MGMT_STATUS_BUSY);
- goto unlock;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
- if (!cmd) {
- err = -ENOMEM;
- goto unlock;
- }
-
- memset(&hci_cp, 0, sizeof(hci_cp));
-
- if (val) {
- hci_cp.le = val;
- hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
- }
-
- err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
- &hci_cp);
- if (err < 0) {
- mgmt_pending_remove(cmd);
- goto unlock;
- }
-
-unlock:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
-{
- struct mgmt_cp_add_uuid *cp = data;
- struct pending_cmd *cmd;
- struct bt_uuid *uuid;
- int err;
-
- BT_DBG("request for %s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
- MGMT_STATUS_BUSY);
- goto failed;
- }
-
- uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
- if (!uuid) {
- err = -ENOMEM;
- goto failed;
- }
-
- memcpy(uuid->uuid, cp->uuid, 16);
- uuid->svc_hint = cp->svc_hint;
-
- list_add(&uuid->list, &hdev->uuids);
-
- err = update_class(hdev);
- if (err < 0)
- goto failed;
-
- err = update_eir(hdev);
- if (err < 0)
- goto failed;
-
- if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
- err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
- hdev->dev_class, 3);
- goto failed;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
- if (!cmd) {
- err = -ENOMEM;
- goto failed;
- }
-
-failed:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static bool enable_service_cache(struct hci_dev *hdev)
-{
- if (!hdev_is_powered(hdev))
- return false;
-
- if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
- schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
- return true;
- }
-
- return false;
-}
-
-static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_cp_remove_uuid *cp = data;
- struct pending_cmd *cmd;
- struct list_head *p, *n;
- u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- int err, found;
-
- BT_DBG("request for %s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
- MGMT_STATUS_BUSY);
- goto unlock;
- }
-
- if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
- err = hci_uuids_clear(hdev);
-
- if (enable_service_cache(hdev)) {
- err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
- 0, hdev->dev_class, 3);
- goto unlock;
- }
-
- goto update_class;
- }
-
- found = 0;
-
- list_for_each_safe(p, n, &hdev->uuids) {
- struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
-
- if (memcmp(match->uuid, cp->uuid, 16) != 0)
- continue;
-
- list_del(&match->list);
- found++;
- }
-
- if (found == 0) {
- err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
- MGMT_STATUS_INVALID_PARAMS);
- goto unlock;
- }
-
-update_class:
- err = update_class(hdev);
- if (err < 0)
- goto unlock;
-
- err = update_eir(hdev);
- if (err < 0)
- goto unlock;
-
- if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
- err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
- hdev->dev_class, 3);
- goto unlock;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
- if (!cmd) {
- err = -ENOMEM;
- goto unlock;
- }
-
-unlock:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_cp_set_dev_class *cp = data;
- struct pending_cmd *cmd;
- int err;
-
- BT_DBG("request for %s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
- MGMT_STATUS_BUSY);
- goto unlock;
- }
-
- hdev->major_class = cp->major;
- hdev->minor_class = cp->minor;
-
- if (!hdev_is_powered(hdev)) {
- err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
- hdev->dev_class, 3);
- goto unlock;
- }
-
- if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
- hci_dev_unlock(hdev);
- cancel_delayed_work_sync(&hdev->service_cache);
- hci_dev_lock(hdev);
- update_eir(hdev);
- }
-
- err = update_class(hdev);
- if (err < 0)
- goto unlock;
-
- if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
- err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
- hdev->dev_class, 3);
- goto unlock;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
- if (!cmd) {
- err = -ENOMEM;
- goto unlock;
- }
-
-unlock:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_cp_load_link_keys *cp = data;
- u16 key_count, expected_len;
- int i;
-
- key_count = get_unaligned_le16(&cp->key_count);
-
- expected_len = sizeof(*cp) + key_count *
- sizeof(struct mgmt_link_key_info);
- if (expected_len != len) {
- BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
- len, expected_len);
- return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
- MGMT_STATUS_INVALID_PARAMS);
- }
-
- BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
- key_count);
-
- hci_dev_lock(hdev);
-
- hci_link_keys_clear(hdev);
-
- set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
-
- if (cp->debug_keys)
- set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
- else
- clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
-
- for (i = 0; i < key_count; i++) {
- struct mgmt_link_key_info *key = &cp->keys[i];
-
- hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
- key->type, key->pin_len);
- }
-
- cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
-
- hci_dev_unlock(hdev);
-
- return 0;
-}
-
-static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
- u8 addr_type, struct sock *skip_sk)
-{
- struct mgmt_ev_device_unpaired ev;
-
- bacpy(&ev.addr.bdaddr, bdaddr);
- ev.addr.type = addr_type;
-
- return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
- skip_sk);
-}
-
-static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_cp_unpair_device *cp = data;
- struct mgmt_rp_unpair_device rp;
- struct hci_cp_disconnect dc;
- struct pending_cmd *cmd;
- struct hci_conn *conn;
- int err;
-
- hci_dev_lock(hdev);
-
- memset(&rp, 0, sizeof(rp));
- bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
- rp.addr.type = cp->addr.type;
-
- if (!hdev_is_powered(hdev)) {
- err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
- MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
- goto unlock;
- }
-
- if (cp->addr.type == MGMT_ADDR_BREDR)
- err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
- else
- err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
-
- if (err < 0) {
- err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
- MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
- goto unlock;
- }
-
- if (cp->disconnect) {
- if (cp->addr.type == MGMT_ADDR_BREDR)
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
- &cp->addr.bdaddr);
- else
- conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
- &cp->addr.bdaddr);
- } else {
- conn = NULL;
- }
-
- if (!conn) {
- err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
- &rp, sizeof(rp));
- device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
- goto unlock;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
- sizeof(*cp));
- if (!cmd) {
- err = -ENOMEM;
- goto unlock;
- }
-
- put_unaligned_le16(conn->handle, &dc.handle);
- dc.reason = 0x13; /* Remote User Terminated Connection */
- err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
- if (err < 0)
- mgmt_pending_remove(cmd);
-
-unlock:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_cp_disconnect *cp = data;
- struct hci_cp_disconnect dc;
- struct pending_cmd *cmd;
- struct hci_conn *conn;
- int err;
-
- BT_DBG("");
-
- hci_dev_lock(hdev);
-
- if (!test_bit(HCI_UP, &hdev->flags)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
- MGMT_STATUS_NOT_POWERED);
- goto failed;
- }
-
- if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
- MGMT_STATUS_BUSY);
- goto failed;
- }
-
- if (cp->addr.type == MGMT_ADDR_BREDR)
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
- else
- conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
-
- if (!conn) {
- err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
- MGMT_STATUS_NOT_CONNECTED);
- goto failed;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
- if (!cmd) {
- err = -ENOMEM;
- goto failed;
- }
-
- put_unaligned_le16(conn->handle, &dc.handle);
- dc.reason = 0x13; /* Remote User Terminated Connection */
-
- err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
- if (err < 0)
- mgmt_pending_remove(cmd);
-
-failed:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static u8 link_to_mgmt(u8 link_type, u8 addr_type)
-{
- switch (link_type) {
- case LE_LINK:
- switch (addr_type) {
- case ADDR_LE_DEV_PUBLIC:
- return MGMT_ADDR_LE_PUBLIC;
- case ADDR_LE_DEV_RANDOM:
- return MGMT_ADDR_LE_RANDOM;
- default:
- return MGMT_ADDR_INVALID;
- }
- case ACL_LINK:
- return MGMT_ADDR_BREDR;
- default:
- return MGMT_ADDR_INVALID;
- }
-}
-
-static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 data_len)
-{
- struct mgmt_rp_get_connections *rp;
- struct hci_conn *c;
- size_t rp_len;
- int err;
- u16 i;
-
- BT_DBG("");
-
- hci_dev_lock(hdev);
-
- if (!hdev_is_powered(hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
- MGMT_STATUS_NOT_POWERED);
- goto unlock;
- }
-
- i = 0;
- list_for_each_entry(c, &hdev->conn_hash.list, list) {
- if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
- i++;
- }
-
- rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
- rp = kmalloc(rp_len, GFP_ATOMIC);
- if (!rp) {
- err = -ENOMEM;
- goto unlock;
- }
-
- i = 0;
- list_for_each_entry(c, &hdev->conn_hash.list, list) {
- if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
- continue;
- bacpy(&rp->addr[i].bdaddr, &c->dst);
- rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
- if (rp->addr[i].type == MGMT_ADDR_INVALID)
- continue;
- i++;
- }
-
- put_unaligned_le16(i, &rp->conn_count);
-
- /* Recalculate length in case of filtered SCO connections, etc */
- rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
-
- err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
- rp_len);
-
- kfree(rp);
-
-unlock:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
- struct mgmt_cp_pin_code_neg_reply *cp)
-{
- struct pending_cmd *cmd;
- int err;
-
- cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
- sizeof(*cp));
- if (!cmd)
- return -ENOMEM;
-
- err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
- sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
- if (err < 0)
- mgmt_pending_remove(cmd);
-
- return err;
-}
-
-static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct hci_conn *conn;
- struct mgmt_cp_pin_code_reply *cp = data;
- struct hci_cp_pin_code_reply reply;
- struct pending_cmd *cmd;
- int err;
-
- BT_DBG("");
-
- hci_dev_lock(hdev);
-
- if (!hdev_is_powered(hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
- MGMT_STATUS_NOT_POWERED);
- goto failed;
- }
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
- if (!conn) {
- err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
- MGMT_STATUS_NOT_CONNECTED);
- goto failed;
- }
-
- if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
- struct mgmt_cp_pin_code_neg_reply ncp;
-
- memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
-
- BT_ERR("PIN code is not 16 bytes long");
-
- err = send_pin_code_neg_reply(sk, hdev, &ncp);
- if (err >= 0)
- err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
- MGMT_STATUS_INVALID_PARAMS);
-
- goto failed;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
- if (!cmd) {
- err = -ENOMEM;
- goto failed;
- }
-
- bacpy(&reply.bdaddr, &cp->addr.bdaddr);
- reply.pin_len = cp->pin_len;
- memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
-
- err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
- if (err < 0)
- mgmt_pending_remove(cmd);
-
-failed:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
- void *data, u16 len)
-{
- struct mgmt_cp_pin_code_neg_reply *cp = data;
- int err;
-
- BT_DBG("");
-
- hci_dev_lock(hdev);
-
- if (!hdev_is_powered(hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
- MGMT_STATUS_NOT_POWERED);
- goto failed;
- }
-
- err = send_pin_code_neg_reply(sk, hdev, cp);
-
-failed:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_cp_set_io_capability *cp = data;
-
- BT_DBG("");
-
- hci_dev_lock(hdev);
-
- hdev->io_capability = cp->io_capability;
-
- BT_DBG("%s IO capability set to 0x%02x", hdev->name,
- hdev->io_capability);
-
- hci_dev_unlock(hdev);
-
- return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
- 0);
-}
-
-static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
- struct pending_cmd *cmd;
-
- list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
- if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
- continue;
-
- if (cmd->user_data != conn)
- continue;
-
- return cmd;
- }
-
- return NULL;
-}
-
-static void pairing_complete(struct pending_cmd *cmd, u8 status)
-{
- struct mgmt_rp_pair_device rp;
- struct hci_conn *conn = cmd->user_data;
-
- bacpy(&rp.addr.bdaddr, &conn->dst);
- rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
-
- cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
- &rp, sizeof(rp));
-
- /* So we don't get further callbacks for this connection */
- conn->connect_cfm_cb = NULL;
- conn->security_cfm_cb = NULL;
- conn->disconn_cfm_cb = NULL;
-
- hci_conn_put(conn);
-
- mgmt_pending_remove(cmd);
-}
-
-static void pairing_complete_cb(struct hci_conn *conn, u8 status)
-{
- struct pending_cmd *cmd;
-
- BT_DBG("status %u", status);
-
- cmd = find_pairing(conn);
- if (!cmd)
- BT_DBG("Unable to find a pending command");
- else
- pairing_complete(cmd, mgmt_status(status));
-}
-
-static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_cp_pair_device *cp = data;
- struct mgmt_rp_pair_device rp;
- struct pending_cmd *cmd;
- u8 sec_level, auth_type;
- struct hci_conn *conn;
- int err;
-
- BT_DBG("");
-
- hci_dev_lock(hdev);
-
- if (!hdev_is_powered(hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
- MGMT_STATUS_NOT_POWERED);
- goto unlock;
- }
-
- sec_level = BT_SECURITY_MEDIUM;
- if (cp->io_cap == 0x03)
- auth_type = HCI_AT_DEDICATED_BONDING;
- else
- auth_type = HCI_AT_DEDICATED_BONDING_MITM;
-
- if (cp->addr.type == MGMT_ADDR_BREDR)
- conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
- auth_type);
- else
- conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
- auth_type);
-
- memset(&rp, 0, sizeof(rp));
- bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
- rp.addr.type = cp->addr.type;
-
- if (IS_ERR(conn)) {
- err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
- MGMT_STATUS_CONNECT_FAILED, &rp,
- sizeof(rp));
- goto unlock;
- }
-
- if (conn->connect_cfm_cb) {
- hci_conn_put(conn);
- err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
- MGMT_STATUS_BUSY, &rp, sizeof(rp));
- goto unlock;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
- if (!cmd) {
- err = -ENOMEM;
- hci_conn_put(conn);
- goto unlock;
- }
-
- /* For LE, just connecting isn't a proof that the pairing finished */
- if (cp->addr.type == MGMT_ADDR_BREDR)
- conn->connect_cfm_cb = pairing_complete_cb;
-
- conn->security_cfm_cb = pairing_complete_cb;
- conn->disconn_cfm_cb = pairing_complete_cb;
- conn->io_capability = cp->io_cap;
- cmd->user_data = conn;
-
- if (conn->state == BT_CONNECTED &&
- hci_conn_security(conn, sec_level, auth_type))
- pairing_complete(cmd, 0);
-
- err = 0;
-
-unlock:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_addr_info *addr = data;
- struct pending_cmd *cmd;
- struct hci_conn *conn;
- int err;
-
- BT_DBG("");
-
- hci_dev_lock(hdev);
-
- if (!hdev_is_powered(hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
- MGMT_STATUS_NOT_POWERED);
- goto unlock;
- }
-
- cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
- if (!cmd) {
- err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
- MGMT_STATUS_INVALID_PARAMS);
- goto unlock;
- }
-
- conn = cmd->user_data;
-
- if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
- err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
- MGMT_STATUS_INVALID_PARAMS);
- goto unlock;
- }
-
- pairing_complete(cmd, MGMT_STATUS_CANCELLED);
-
- err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
- addr, sizeof(*addr));
-unlock:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
- bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
- u16 hci_op, __le32 passkey)
-{
- struct pending_cmd *cmd;
- struct hci_conn *conn;
- int err;
-
- hci_dev_lock(hdev);
-
- if (!hdev_is_powered(hdev)) {
- err = cmd_status(sk, hdev->id, mgmt_op,
- MGMT_STATUS_NOT_POWERED);
- goto done;
- }
-
- if (type == MGMT_ADDR_BREDR)
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
- else
- conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
-
- if (!conn) {
- err = cmd_status(sk, hdev->id, mgmt_op,
- MGMT_STATUS_NOT_CONNECTED);
- goto done;
- }
-
- if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
- /* Continue with pairing via SMP */
- err = smp_user_confirm_reply(conn, mgmt_op, passkey);
-
- if (!err)
- err = cmd_status(sk, hdev->id, mgmt_op,
- MGMT_STATUS_SUCCESS);
- else
- err = cmd_status(sk, hdev->id, mgmt_op,
- MGMT_STATUS_FAILED);
-
- goto done;
- }
-
- cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
- if (!cmd) {
- err = -ENOMEM;
- goto done;
- }
-
- /* Continue with pairing via HCI */
- if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
- struct hci_cp_user_passkey_reply cp;
-
- bacpy(&cp.bdaddr, bdaddr);
- cp.passkey = passkey;
- err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
- } else
- err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
-
- if (err < 0)
- mgmt_pending_remove(cmd);
-
-done:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_cp_user_confirm_reply *cp = data;
-
- BT_DBG("");
-
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
- MGMT_STATUS_INVALID_PARAMS);
-
- return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
- MGMT_OP_USER_CONFIRM_REPLY,
- HCI_OP_USER_CONFIRM_REPLY, 0);
-}
-
-static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
- void *data, u16 len)
-{
- struct mgmt_cp_user_confirm_neg_reply *cp = data;
-
- BT_DBG("");
-
- return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
- MGMT_OP_USER_CONFIRM_NEG_REPLY,
- HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
-}
-
-static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_cp_user_passkey_reply *cp = data;
-
- BT_DBG("");
-
- return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
- MGMT_OP_USER_PASSKEY_REPLY,
- HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
-}
-
-static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
- void *data, u16 len)
-{
- struct mgmt_cp_user_passkey_neg_reply *cp = data;
-
- BT_DBG("");
-
- return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
- MGMT_OP_USER_PASSKEY_NEG_REPLY,
- HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
-}
-
-static int update_name(struct hci_dev *hdev, const char *name)
-{
- struct hci_cp_write_local_name cp;
-
- memcpy(cp.name, name, sizeof(cp.name));
-
- return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
-}
-
-static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_cp_set_local_name *cp = data;
- struct pending_cmd *cmd;
- int err;
-
- BT_DBG("");
-
- hci_dev_lock(hdev);
-
- memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
-
- if (!hdev_is_powered(hdev)) {
- memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
-
- err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
- data, len);
- if (err < 0)
- goto failed;
-
- err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
- sk);
-
- goto failed;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
- if (!cmd) {
- err = -ENOMEM;
- goto failed;
- }
-
- err = update_name(hdev, cp->name);
- if (err < 0)
- mgmt_pending_remove(cmd);
-
-failed:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
- void *data, u16 data_len)
-{
- struct pending_cmd *cmd;
- int err;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (!hdev_is_powered(hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
- MGMT_STATUS_NOT_POWERED);
- goto unlock;
- }
-
- if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
- MGMT_STATUS_NOT_SUPPORTED);
- goto unlock;
- }
-
- if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
- MGMT_STATUS_BUSY);
- goto unlock;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
- if (!cmd) {
- err = -ENOMEM;
- goto unlock;
- }
-
- err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
- if (err < 0)
- mgmt_pending_remove(cmd);
-
-unlock:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
- void *data, u16 len)
-{
- struct mgmt_cp_add_remote_oob_data *cp = data;
- u8 status;
- int err;
-
- BT_DBG("%s ", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (!hdev_is_powered(hdev)) {
- err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
- MGMT_STATUS_NOT_POWERED, &cp->addr,
- sizeof(cp->addr));
- goto unlock;
- }
-
- err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
- cp->randomizer);
- if (err < 0)
- status = MGMT_STATUS_FAILED;
- else
- status = 0;
-
- err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
- &cp->addr, sizeof(cp->addr));
-
-unlock:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
- void *data, u16 len)
-{
- struct mgmt_cp_remove_remote_oob_data *cp = data;
- u8 status;
- int err;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (!hdev_is_powered(hdev)) {
- err = cmd_complete(sk, hdev->id,
- MGMT_OP_REMOVE_REMOTE_OOB_DATA,
- MGMT_STATUS_NOT_POWERED, &cp->addr,
- sizeof(cp->addr));
- goto unlock;
- }
-
- err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
- if (err < 0)
- status = MGMT_STATUS_INVALID_PARAMS;
- else
- status = 0;
-
- err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
- status, &cp->addr, sizeof(cp->addr));
-
-unlock:
- hci_dev_unlock(hdev);
- return err;
-}
-
-int mgmt_interleaved_discovery(struct hci_dev *hdev)
-{
- int err;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
- if (err < 0)
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
-
- hci_dev_unlock(hdev);
-
- return err;
-}
-
-static int start_discovery(struct sock *sk, struct hci_dev *hdev,
- void *data, u16 len)
-{
- struct mgmt_cp_start_discovery *cp = data;
- struct pending_cmd *cmd;
- int err;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (!hdev_is_powered(hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
- MGMT_STATUS_NOT_POWERED);
- goto failed;
- }
-
- if (hdev->discovery.state != DISCOVERY_STOPPED) {
- err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
- MGMT_STATUS_BUSY);
- goto failed;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
- if (!cmd) {
- err = -ENOMEM;
- goto failed;
- }
-
- hdev->discovery.type = cp->type;
-
- switch (hdev->discovery.type) {
- case DISCOV_TYPE_BREDR:
- if (lmp_bredr_capable(hdev))
- err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
- else
- err = -ENOTSUPP;
- break;
-
- case DISCOV_TYPE_LE:
- if (lmp_host_le_capable(hdev))
- err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
- LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
- else
- err = -ENOTSUPP;
- break;
-
- case DISCOV_TYPE_INTERLEAVED:
- if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
- err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
- LE_SCAN_WIN,
- LE_SCAN_TIMEOUT_BREDR_LE);
- else
- err = -ENOTSUPP;
- break;
-
- default:
- err = -EINVAL;
- }
-
- if (err < 0)
- mgmt_pending_remove(cmd);
- else
- hci_discovery_set_state(hdev, DISCOVERY_STARTING);
-
-failed:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_cp_stop_discovery *mgmt_cp = data;
- struct pending_cmd *cmd;
- struct hci_cp_remote_name_req_cancel cp;
- struct inquiry_entry *e;
- int err;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (!hci_discovery_active(hdev)) {
- err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
- MGMT_STATUS_REJECTED, &mgmt_cp->type,
- sizeof(mgmt_cp->type));
- goto unlock;
- }
-
- if (hdev->discovery.type != mgmt_cp->type) {
- err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
- MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
- sizeof(mgmt_cp->type));
- goto unlock;
- }
-
- cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
- if (!cmd) {
- err = -ENOMEM;
- goto unlock;
- }
-
- if (hdev->discovery.state == DISCOVERY_FINDING) {
- err = hci_cancel_inquiry(hdev);
- if (err < 0)
- mgmt_pending_remove(cmd);
- else
- hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
- goto unlock;
- }
-
- e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
- if (!e) {
- mgmt_pending_remove(cmd);
- err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
- &mgmt_cp->type, sizeof(mgmt_cp->type));
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- goto unlock;
- }
-
- bacpy(&cp.bdaddr, &e->data.bdaddr);
- err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
- &cp);
- if (err < 0)
- mgmt_pending_remove(cmd);
- else
- hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
-
-unlock:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_cp_confirm_name *cp = data;
- struct inquiry_entry *e;
- int err;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (!hci_discovery_active(hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
- MGMT_STATUS_FAILED);
- goto failed;
- }
-
- e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
- if (!e) {
- err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
- MGMT_STATUS_INVALID_PARAMS);
- goto failed;
- }
-
- if (cp->name_known) {
- e->name_state = NAME_KNOWN;
- list_del(&e->list);
- } else {
- e->name_state = NAME_NEEDED;
- hci_inquiry_cache_update_resolve(hdev, e);
- }
-
- err = 0;
-
-failed:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_cp_block_device *cp = data;
- u8 status;
- int err;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
- if (err < 0)
- status = MGMT_STATUS_FAILED;
- else
- status = 0;
-
- err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
- &cp->addr, sizeof(cp->addr));
-
- hci_dev_unlock(hdev);
-
- return err;
-}
-
-static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
- u16 len)
-{
- struct mgmt_cp_unblock_device *cp = data;
- u8 status;
- int err;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
- if (err < 0)
- status = MGMT_STATUS_INVALID_PARAMS;
- else
- status = 0;
-
- err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
- &cp->addr, sizeof(cp->addr));
-
- hci_dev_unlock(hdev);
-
- return err;
-}
-
-static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
- void *data, u16 len)
-{
- struct mgmt_mode *cp = data;
- struct hci_cp_write_page_scan_activity acp;
- u8 type;
- int err;
-
- BT_DBG("%s", hdev->name);
-
- if (!hdev_is_powered(hdev))
- return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
- MGMT_STATUS_NOT_POWERED);
-
- if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
- return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
- MGMT_STATUS_REJECTED);
-
- hci_dev_lock(hdev);
-
- if (cp->val) {
- type = PAGE_SCAN_TYPE_INTERLACED;
-
- /* 22.5 msec page scan interval */
- acp.interval = __constant_cpu_to_le16(0x0024);
- } else {
- type = PAGE_SCAN_TYPE_STANDARD; /* default */
-
- /* default 1.28 sec page scan */
- acp.interval = __constant_cpu_to_le16(0x0800);
- }
-
- /* default 11.25 msec page scan window */
- acp.window = __constant_cpu_to_le16(0x0012);
-
- err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
- &acp);
- if (err < 0) {
- err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
- MGMT_STATUS_FAILED);
- goto done;
- }
-
- err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
- if (err < 0) {
- err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
- MGMT_STATUS_FAILED);
- goto done;
- }
-
- err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
- NULL, 0);
-done:
- hci_dev_unlock(hdev);
- return err;
-}
-
-static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
- void *cp_data, u16 len)
-{
- struct mgmt_cp_load_long_term_keys *cp = cp_data;
- u16 key_count, expected_len;
- int i;
-
- key_count = get_unaligned_le16(&cp->key_count);
-
- expected_len = sizeof(*cp) + key_count *
- sizeof(struct mgmt_ltk_info);
- if (expected_len != len) {
- BT_ERR("load_keys: expected %u bytes, got %u bytes",
- len, expected_len);
- return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
- EINVAL);
- }
-
- BT_DBG("%s key_count %u", hdev->name, key_count);
-
- hci_dev_lock(hdev);
-
- hci_smp_ltks_clear(hdev);
-
- for (i = 0; i < key_count; i++) {
- struct mgmt_ltk_info *key = &cp->keys[i];
- u8 type;
-
- if (key->master)
- type = HCI_SMP_LTK;
- else
- type = HCI_SMP_LTK_SLAVE;
-
- hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
- type, 0, key->authenticated, key->val,
- key->enc_size, key->ediv, key->rand);
- }
-
- hci_dev_unlock(hdev);
-
- return 0;
-}
-
-struct mgmt_handler {
- int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
- u16 data_len);
- bool var_len;
- size_t data_len;
-} mgmt_handlers[] = {
- { NULL }, /* 0x0000 (no command) */
- { read_version, false, MGMT_READ_VERSION_SIZE },
- { read_commands, false, MGMT_READ_COMMANDS_SIZE },
- { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
- { read_controller_info, false, MGMT_READ_INFO_SIZE },
- { set_powered, false, MGMT_SETTING_SIZE },
- { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
- { set_connectable, false, MGMT_SETTING_SIZE },
- { set_fast_connectable, false, MGMT_SETTING_SIZE },
- { set_pairable, false, MGMT_SETTING_SIZE },
- { set_link_security, false, MGMT_SETTING_SIZE },
- { set_ssp, false, MGMT_SETTING_SIZE },
- { set_hs, false, MGMT_SETTING_SIZE },
- { set_le, false, MGMT_SETTING_SIZE },
- { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
- { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
- { add_uuid, false, MGMT_ADD_UUID_SIZE },
- { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
- { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
- { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
- { disconnect, false, MGMT_DISCONNECT_SIZE },
- { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
- { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
- { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
- { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
- { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
- { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
- { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
- { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
- { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
- { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
- { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
- { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
- { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
- { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
- { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
- { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
- { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
- { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
- { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
-};
-
-
-int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
-{
- void *buf;
- u8 *cp;
- struct mgmt_hdr *hdr;
- u16 opcode, index, len;
- struct hci_dev *hdev = NULL;
- struct mgmt_handler *handler;
- int err;
-
- BT_DBG("got %zu bytes", msglen);
-
- if (msglen < sizeof(*hdr))
- return -EINVAL;
-
- buf = kmalloc(msglen, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
- err = -EFAULT;
- goto done;
- }
-
- hdr = buf;
- opcode = get_unaligned_le16(&hdr->opcode);
- index = get_unaligned_le16(&hdr->index);
- len = get_unaligned_le16(&hdr->len);
-
- if (len != msglen - sizeof(*hdr)) {
- err = -EINVAL;
- goto done;
- }
-
- if (index != MGMT_INDEX_NONE) {
- hdev = hci_dev_get(index);
- if (!hdev) {
- err = cmd_status(sk, index, opcode,
- MGMT_STATUS_INVALID_INDEX);
- goto done;
- }
- }
-
- if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
- mgmt_handlers[opcode].func == NULL) {
- BT_DBG("Unknown op %u", opcode);
- err = cmd_status(sk, index, opcode,
- MGMT_STATUS_UNKNOWN_COMMAND);
- goto done;
- }
-
- if ((hdev && opcode < MGMT_OP_READ_INFO) ||
- (!hdev && opcode >= MGMT_OP_READ_INFO)) {
- err = cmd_status(sk, index, opcode,
- MGMT_STATUS_INVALID_INDEX);
- goto done;
- }
-
- handler = &mgmt_handlers[opcode];
-
- if ((handler->var_len && len < handler->data_len) ||
- (!handler->var_len && len != handler->data_len)) {
- err = cmd_status(sk, index, opcode,
- MGMT_STATUS_INVALID_PARAMS);
- goto done;
- }
-
- if (hdev)
- mgmt_init_hdev(sk, hdev);
-
- cp = buf + sizeof(*hdr);
-
- err = handler->func(sk, hdev, cp, len);
- if (err < 0)
- goto done;
-
- err = msglen;
-
-done:
- if (hdev)
- hci_dev_put(hdev);
-
- kfree(buf);
- return err;
-}
-
-static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
-{
- u8 *status = data;
-
- cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
- mgmt_pending_remove(cmd);
-}
-
-int mgmt_index_added(struct hci_dev *hdev)
-{
- return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
-}
-
-int mgmt_index_removed(struct hci_dev *hdev)
-{
- u8 status = MGMT_STATUS_INVALID_INDEX;
-
- mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
-
- return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
-}
-
-struct cmd_lookup {
- struct sock *sk;
- struct hci_dev *hdev;
- u8 mgmt_status;
-};
-
-static void settings_rsp(struct pending_cmd *cmd, void *data)
-{
- struct cmd_lookup *match = data;
-
- send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
-
- list_del(&cmd->list);
-
- if (match->sk == NULL) {
- match->sk = cmd->sk;
- sock_hold(match->sk);
- }
-
- mgmt_pending_free(cmd);
-}
-
-int mgmt_powered(struct hci_dev *hdev, u8 powered)
-{
- struct cmd_lookup match = { NULL, hdev };
- int err;
-
- if (!test_bit(HCI_MGMT, &hdev->dev_flags))
- return 0;
-
- mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
-
- if (powered) {
- u8 scan = 0;
-
- if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
- scan |= SCAN_PAGE;
- if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
- scan |= SCAN_INQUIRY;
-
- if (scan)
- hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
-
- update_class(hdev);
- update_name(hdev, hdev->dev_name);
- update_eir(hdev);
- } else {
- u8 status = MGMT_STATUS_NOT_POWERED;
- mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
- }
-
- err = new_settings(hdev, match.sk);
-
- if (match.sk)
- sock_put(match.sk);
-
- return err;
-}
-
-int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
-{
- struct cmd_lookup match = { NULL, hdev };
- bool changed = false;
- int err = 0;
-
- if (discoverable) {
- if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
- changed = true;
- } else {
- if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
- changed = true;
- }
-
- mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
- &match);
-
- if (changed)
- err = new_settings(hdev, match.sk);
-
- if (match.sk)
- sock_put(match.sk);
-
- return err;
-}
-
-int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
-{
- struct cmd_lookup match = { NULL, hdev };
- bool changed = false;
- int err = 0;
-
- if (connectable) {
- if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
- changed = true;
- } else {
- if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
- changed = true;
- }
-
- mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
- &match);
-
- if (changed)
- err = new_settings(hdev, match.sk);
-
- if (match.sk)
- sock_put(match.sk);
-
- return err;
-}
-
-int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
-{
- u8 mgmt_err = mgmt_status(status);
-
- if (scan & SCAN_PAGE)
- mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
- cmd_status_rsp, &mgmt_err);
-
- if (scan & SCAN_INQUIRY)
- mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
- cmd_status_rsp, &mgmt_err);
-
- return 0;
-}
-
-int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent)
-{
- struct mgmt_ev_new_link_key ev;
-
- memset(&ev, 0, sizeof(ev));
-
- ev.store_hint = persistent;
- bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
- ev.key.addr.type = MGMT_ADDR_BREDR;
- ev.key.type = key->type;
- memcpy(ev.key.val, key->val, 16);
- ev.key.pin_len = key->pin_len;
-
- return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
-}
-
-int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
-{
- struct mgmt_ev_new_long_term_key ev;
-
- memset(&ev, 0, sizeof(ev));
-
- ev.store_hint = persistent;
- bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
- ev.key.addr.type = key->bdaddr_type;
- ev.key.authenticated = key->authenticated;
- ev.key.enc_size = key->enc_size;
- ev.key.ediv = key->ediv;
-
- if (key->type == HCI_SMP_LTK)
- ev.key.master = 1;
-
- memcpy(ev.key.rand, key->rand, sizeof(key->rand));
- memcpy(ev.key.val, key->val, sizeof(key->val));
-
- return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
- NULL);
-}
-
-int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
- u8 addr_type, u32 flags, u8 *name, u8 name_len,
- u8 *dev_class)
-{
- char buf[512];
- struct mgmt_ev_device_connected *ev = (void *) buf;
- u16 eir_len = 0;
-
- bacpy(&ev->addr.bdaddr, bdaddr);
- ev->addr.type = link_to_mgmt(link_type, addr_type);
-
- ev->flags = __cpu_to_le32(flags);
-
- if (name_len > 0)
- eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
- name, name_len);
-
- if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
- eir_len = eir_append_data(ev->eir, eir_len,
- EIR_CLASS_OF_DEV, dev_class, 3);
-
- put_unaligned_le16(eir_len, &ev->eir_len);
-
- return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
- sizeof(*ev) + eir_len, NULL);
-}
-
-static void disconnect_rsp(struct pending_cmd *cmd, void *data)
-{
- struct mgmt_cp_disconnect *cp = cmd->param;
- struct sock **sk = data;
- struct mgmt_rp_disconnect rp;
-
- bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
- rp.addr.type = cp->addr.type;
-
- cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
- sizeof(rp));
-
- *sk = cmd->sk;
- sock_hold(*sk);
-
- mgmt_pending_remove(cmd);
-}
-
-static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
-{
- struct hci_dev *hdev = data;
- struct mgmt_cp_unpair_device *cp = cmd->param;
- struct mgmt_rp_unpair_device rp;
-
- memset(&rp, 0, sizeof(rp));
- bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
- rp.addr.type = cp->addr.type;
-
- device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
-
- cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
-
- mgmt_pending_remove(cmd);
-}
-
-int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
- u8 link_type, u8 addr_type)
-{
- struct mgmt_addr_info ev;
- struct sock *sk = NULL;
- int err;
-
- mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
-
- bacpy(&ev.bdaddr, bdaddr);
- ev.type = link_to_mgmt(link_type, addr_type);
-
- err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
- sk);
-
- if (sk)
- sock_put(sk);
-
- mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
- hdev);
-
- return err;
-}
-
-int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
- u8 link_type, u8 addr_type, u8 status)
-{
- struct mgmt_rp_disconnect rp;
- struct pending_cmd *cmd;
- int err;
-
- cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
- if (!cmd)
- return -ENOENT;
-
- bacpy(&rp.addr.bdaddr, bdaddr);
- rp.addr.type = link_to_mgmt(link_type, addr_type);
-
- err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
- mgmt_status(status), &rp, sizeof(rp));
-
- mgmt_pending_remove(cmd);
-
- mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
- hdev);
- return err;
-}
-
-int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
- u8 addr_type, u8 status)
-{
- struct mgmt_ev_connect_failed ev;
-
- bacpy(&ev.addr.bdaddr, bdaddr);
- ev.addr.type = link_to_mgmt(link_type, addr_type);
- ev.status = mgmt_status(status);
-
- return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
-}
-
-int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
-{
- struct mgmt_ev_pin_code_request ev;
-
- bacpy(&ev.addr.bdaddr, bdaddr);
- ev.addr.type = MGMT_ADDR_BREDR;
- ev.secure = secure;
-
- return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
- NULL);
-}
-
-int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
- u8 status)
-{
- struct pending_cmd *cmd;
- struct mgmt_rp_pin_code_reply rp;
- int err;
-
- cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
- if (!cmd)
- return -ENOENT;
-
- bacpy(&rp.addr.bdaddr, bdaddr);
- rp.addr.type = MGMT_ADDR_BREDR;
-
- err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
- mgmt_status(status), &rp, sizeof(rp));
-
- mgmt_pending_remove(cmd);
-
- return err;
-}
-
-int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
- u8 status)
-{
- struct pending_cmd *cmd;
- struct mgmt_rp_pin_code_reply rp;
- int err;
-
- cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
- if (!cmd)
- return -ENOENT;
-
- bacpy(&rp.addr.bdaddr, bdaddr);
- rp.addr.type = MGMT_ADDR_BREDR;
-
- err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
- mgmt_status(status), &rp, sizeof(rp));
-
- mgmt_pending_remove(cmd);
-
- return err;
-}
-
-int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
- u8 link_type, u8 addr_type, __le32 value,
- u8 confirm_hint)
-{
- struct mgmt_ev_user_confirm_request ev;
-
- BT_DBG("%s", hdev->name);
-
- bacpy(&ev.addr.bdaddr, bdaddr);
- ev.addr.type = link_to_mgmt(link_type, addr_type);
- ev.confirm_hint = confirm_hint;
- put_unaligned_le32(value, &ev.value);
-
- return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
- NULL);
-}
-
-int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
- u8 link_type, u8 addr_type)
-{
- struct mgmt_ev_user_passkey_request ev;
-
- BT_DBG("%s", hdev->name);
-
- bacpy(&ev.addr.bdaddr, bdaddr);
- ev.addr.type = link_to_mgmt(link_type, addr_type);
-
- return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
- NULL);
-}
-
-static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
- u8 link_type, u8 addr_type, u8 status,
- u8 opcode)
-{
- struct pending_cmd *cmd;
- struct mgmt_rp_user_confirm_reply rp;
- int err;
-
- cmd = mgmt_pending_find(opcode, hdev);
- if (!cmd)
- return -ENOENT;
-
- bacpy(&rp.addr.bdaddr, bdaddr);
- rp.addr.type = link_to_mgmt(link_type, addr_type);
- err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
- &rp, sizeof(rp));
-
- mgmt_pending_remove(cmd);
-
- return err;
-}
-
-int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
- u8 link_type, u8 addr_type, u8 status)
-{
- return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
- status, MGMT_OP_USER_CONFIRM_REPLY);
-}
-
-int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
- u8 link_type, u8 addr_type, u8 status)
-{
- return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
- status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
-}
-
-int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
- u8 link_type, u8 addr_type, u8 status)
-{
- return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
- status, MGMT_OP_USER_PASSKEY_REPLY);
-}
-
-int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
- u8 link_type, u8 addr_type, u8 status)
-{
- return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
- status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
-}
-
-int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
- u8 addr_type, u8 status)
-{
- struct mgmt_ev_auth_failed ev;
-
- bacpy(&ev.addr.bdaddr, bdaddr);
- ev.addr.type = link_to_mgmt(link_type, addr_type);
- ev.status = mgmt_status(status);
-
- return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
-}
-
-int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
-{
- struct cmd_lookup match = { NULL, hdev };
- bool changed = false;
- int err = 0;
-
- if (status) {
- u8 mgmt_err = mgmt_status(status);
- mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
- cmd_status_rsp, &mgmt_err);
- return 0;
- }
-
- if (test_bit(HCI_AUTH, &hdev->flags)) {
- if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
- changed = true;
- } else {
- if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
- changed = true;
- }
-
- mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
- &match);
-
- if (changed)
- err = new_settings(hdev, match.sk);
-
- if (match.sk)
- sock_put(match.sk);
-
- return err;
-}
-
-static int clear_eir(struct hci_dev *hdev)
-{
- struct hci_cp_write_eir cp;
-
- if (!(hdev->features[6] & LMP_EXT_INQ))
- return 0;
-
- memset(hdev->eir, 0, sizeof(hdev->eir));
-
- memset(&cp, 0, sizeof(cp));
-
- return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
-}
-
-int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
-{
- struct cmd_lookup match = { NULL, hdev };
- bool changed = false;
- int err = 0;
-
- if (status) {
- u8 mgmt_err = mgmt_status(status);
-
- if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
- &hdev->dev_flags))
- err = new_settings(hdev, NULL);
-
- mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
- &mgmt_err);
-
- return err;
- }
-
- if (enable) {
- if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
- changed = true;
- } else {
- if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
- changed = true;
- }
-
- mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
-
- if (changed)
- err = new_settings(hdev, match.sk);
-
- if (match.sk)
- sock_put(match.sk);
-
- if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
- update_eir(hdev);
- else
- clear_eir(hdev);
-
- return err;
-}
-
-static void class_rsp(struct pending_cmd *cmd, void *data)
-{
- struct cmd_lookup *match = data;
-
- cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
- match->hdev->dev_class, 3);
-
- list_del(&cmd->list);
-
- if (match->sk == NULL) {
- match->sk = cmd->sk;
- sock_hold(match->sk);
- }
-
- mgmt_pending_free(cmd);
-}
-
-int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
- u8 status)
-{
- struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
- int err = 0;
-
- clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
-
- mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
- mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
- mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
-
- if (!status)
- err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
- 3, NULL);
-
- if (match.sk)
- sock_put(match.sk);
-
- return err;
-}
-
-int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
-{
- struct pending_cmd *cmd;
- struct mgmt_cp_set_local_name ev;
- bool changed = false;
- int err = 0;
-
- if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
- memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
- changed = true;
- }
-
- memset(&ev, 0, sizeof(ev));
- memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
- memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
-
- cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
- if (!cmd)
- goto send_event;
-
- /* Always assume that either the short or the complete name has
- * changed if there was a pending mgmt command */
- changed = true;
-
- if (status) {
- err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
- mgmt_status(status));
- goto failed;
- }
-
- err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
- sizeof(ev));
- if (err < 0)
- goto failed;
-
-send_event:
- if (changed)
- err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
- sizeof(ev), cmd ? cmd->sk : NULL);
-
- update_eir(hdev);
-
-failed:
- if (cmd)
- mgmt_pending_remove(cmd);
- return err;
-}
-
-int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
- u8 *randomizer, u8 status)
-{
- struct pending_cmd *cmd;
- int err;
-
- BT_DBG("%s status %u", hdev->name, status);
-
- cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
- if (!cmd)
- return -ENOENT;
-
- if (status) {
- err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
- mgmt_status(status));
- } else {
- struct mgmt_rp_read_local_oob_data rp;
-
- memcpy(rp.hash, hash, sizeof(rp.hash));
- memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
-
- err = cmd_complete(cmd->sk, hdev->id,
- MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
- sizeof(rp));
- }
-
- mgmt_pending_remove(cmd);
-
- return err;
-}
-
-int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
-{
- struct cmd_lookup match = { NULL, hdev };
- bool changed = false;
- int err = 0;
-
- if (status) {
- u8 mgmt_err = mgmt_status(status);
-
- if (enable && test_and_clear_bit(HCI_LE_ENABLED,
- &hdev->dev_flags))
- err = new_settings(hdev, NULL);
-
- mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
- cmd_status_rsp, &mgmt_err);
-
- return err;
- }
-
- if (enable) {
- if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
- changed = true;
- } else {
- if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
- changed = true;
- }
-
- mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
-
- if (changed)
- err = new_settings(hdev, match.sk);
-
- if (match.sk)
- sock_put(match.sk);
-
- return err;
-}
-
-int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
- u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
- ssp, u8 *eir, u16 eir_len)
-{
- char buf[512];
- struct mgmt_ev_device_found *ev = (void *) buf;
- size_t ev_size;
-
- /* Leave 5 bytes for a potential CoD field */
- if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
- return -EINVAL;
-
- memset(buf, 0, sizeof(buf));
-
- bacpy(&ev->addr.bdaddr, bdaddr);
- ev->addr.type = link_to_mgmt(link_type, addr_type);
- ev->rssi = rssi;
- if (cfm_name)
- ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
- if (!ssp)
- ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
-
- if (eir_len > 0)
- memcpy(ev->eir, eir, eir_len);
-
- if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
- eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
- dev_class, 3);
-
- put_unaligned_le16(eir_len, &ev->eir_len);
-
- ev_size = sizeof(*ev) + eir_len;
-
- return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
-}
-
-int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
- u8 addr_type, s8 rssi, u8 *name, u8 name_len)
-{
- struct mgmt_ev_device_found *ev;
- char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
- u16 eir_len;
-
- ev = (struct mgmt_ev_device_found *) buf;
-
- memset(buf, 0, sizeof(buf));
-
- bacpy(&ev->addr.bdaddr, bdaddr);
- ev->addr.type = link_to_mgmt(link_type, addr_type);
- ev->rssi = rssi;
-
- eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
- name_len);
-
- put_unaligned_le16(eir_len, &ev->eir_len);
-
- return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
- sizeof(*ev) + eir_len, NULL);
-}
-
-int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
-{
- struct pending_cmd *cmd;
- u8 type;
- int err;
-
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
-
- cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
- if (!cmd)
- return -ENOENT;
-
- type = hdev->discovery.type;
-
- err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
- &type, sizeof(type));
- mgmt_pending_remove(cmd);
-
- return err;
-}
-
-int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
-{
- struct pending_cmd *cmd;
- int err;
-
- cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
- if (!cmd)
- return -ENOENT;
-
- err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
- &hdev->discovery.type, sizeof(hdev->discovery.type));
- mgmt_pending_remove(cmd);
-
- return err;
-}
-
-int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
-{
- struct mgmt_ev_discovering ev;
- struct pending_cmd *cmd;
-
- BT_DBG("%s discovering %u", hdev->name, discovering);
-
- if (discovering)
- cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
- else
- cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
-
- if (cmd != NULL) {
- u8 type = hdev->discovery.type;
-
- cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
- sizeof(type));
- mgmt_pending_remove(cmd);
- }
-
- memset(&ev, 0, sizeof(ev));
- ev.type = hdev->discovery.type;
- ev.discovering = discovering;
-
- return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
-}
-
-int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
-{
- struct pending_cmd *cmd;
- struct mgmt_ev_device_blocked ev;
-
- cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
-
- bacpy(&ev.addr.bdaddr, bdaddr);
- ev.addr.type = type;
-
- return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
- cmd ? cmd->sk : NULL);
-}
-
-int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
-{
- struct pending_cmd *cmd;
- struct mgmt_ev_device_unblocked ev;
-
- cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
-
- bacpy(&ev.addr.bdaddr, bdaddr);
- ev.addr.type = type;
-
- return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
- cmd ? cmd->sk : NULL);
-}
-
-module_param(enable_hs, bool, 0644);
-MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
-
-module_param(enable_le, bool, 0644);
-MODULE_PARM_DESC(enable_le, "Enable Low Energy support");
diff --git a/net/bluetooth_tizen/rfcomm/Kconfig b/net/bluetooth_tizen/rfcomm/Kconfig
deleted file mode 100644
index 22e718b..0000000
--- a/net/bluetooth_tizen/rfcomm/Kconfig
+++ /dev/null
@@ -1,17 +0,0 @@
-config BT_RFCOMM
- tristate "RFCOMM protocol support"
- depends on BT
- help
- RFCOMM provides connection oriented stream transport. RFCOMM
- support is required for Dialup Networking, OBEX and other Bluetooth
- applications.
-
- Say Y here to compile RFCOMM support into the kernel or say M to
- compile it as module (rfcomm).
-
-config BT_RFCOMM_TTY
- bool "RFCOMM TTY support"
- depends on BT_RFCOMM
- help
- This option enables TTY emulation support for RFCOMM channels.
-
diff --git a/net/bluetooth_tizen/rfcomm/Makefile b/net/bluetooth_tizen/rfcomm/Makefile
deleted file mode 100644
index fe07988..0000000
--- a/net/bluetooth_tizen/rfcomm/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for the Linux Bluetooth RFCOMM layer.
-#
-
-obj-$(CONFIG_BT_RFCOMM) += rfcomm.o
-
-rfcomm-y := core.o sock.o
-rfcomm-$(CONFIG_BT_RFCOMM_TTY) += tty.o
diff --git a/net/bluetooth_tizen/rfcomm/core.c b/net/bluetooth_tizen/rfcomm/core.c
deleted file mode 100644
index 8a60238..0000000
--- a/net/bluetooth_tizen/rfcomm/core.c
+++ /dev/null
@@ -1,2245 +0,0 @@
-/*
- RFCOMM implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
- Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/*
- * Bluetooth RFCOMM core.
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/device.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/net.h>
-#include <linux/mutex.h>
-#include <linux/kthread.h>
-#include <linux/slab.h>
-
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/l2cap.h>
-#include <net/bluetooth/rfcomm.h>
-
-#define VERSION "1.11"
-
-static bool disable_cfc;
-static bool l2cap_ertm;
-static int channel_mtu = -1;
-static unsigned int l2cap_mtu = RFCOMM_MAX_L2CAP_MTU;
-
-static struct task_struct *rfcomm_thread;
-
-static DEFINE_MUTEX(rfcomm_mutex);
-#define rfcomm_lock() mutex_lock(&rfcomm_mutex)
-#define rfcomm_unlock() mutex_unlock(&rfcomm_mutex)
-
-
-static LIST_HEAD(session_list);
-
-static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
-static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
-static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci);
-static int rfcomm_queue_disc(struct rfcomm_dlc *d);
-static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type);
-static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d);
-static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig);
-static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len);
-static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits);
-static void rfcomm_make_uih(struct sk_buff *skb, u8 addr);
-
-static void rfcomm_process_connect(struct rfcomm_session *s);
-
-static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
- bdaddr_t *dst,
- u8 sec_level,
- int *err);
-static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
-static void rfcomm_session_del(struct rfcomm_session *s);
-
-/* ---- RFCOMM frame parsing macros ---- */
-#define __get_dlci(b) ((b & 0xfc) >> 2)
-#define __get_channel(b) ((b & 0xf8) >> 3)
-#define __get_dir(b) ((b & 0x04) >> 2)
-#define __get_type(b) ((b & 0xef))
-
-#define __test_ea(b) ((b & 0x01))
-#define __test_cr(b) ((b & 0x02))
-#define __test_pf(b) ((b & 0x10))
-
-#define __addr(cr, dlci) (((dlci & 0x3f) << 2) | (cr << 1) | 0x01)
-#define __ctrl(type, pf) (((type & 0xef) | (pf << 4)))
-#define __dlci(dir, chn) (((chn & 0x1f) << 1) | dir)
-#define __srv_channel(dlci) (dlci >> 1)
-#define __dir(dlci) (dlci & 0x01)
-
-#define __len8(len) (((len) << 1) | 1)
-#define __len16(len) ((len) << 1)
-
-/* MCC macros */
-#define __mcc_type(cr, type) (((type << 2) | (cr << 1) | 0x01))
-#define __get_mcc_type(b) ((b & 0xfc) >> 2)
-#define __get_mcc_len(b) ((b & 0xfe) >> 1)
-
-/* RPN macros */
-#define __rpn_line_settings(data, stop, parity) ((data & 0x3) | ((stop & 0x1) << 2) | ((parity & 0x7) << 3))
-#define __get_rpn_data_bits(line) ((line) & 0x3)
-#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
-#define __get_rpn_parity(line) (((line) >> 3) & 0x7)
-
-static inline void rfcomm_schedule(void)
-{
- if (!rfcomm_thread)
- return;
- wake_up_process(rfcomm_thread);
-}
-
-static inline void rfcomm_session_put(struct rfcomm_session *s)
-{
- if (atomic_dec_and_test(&s->refcnt))
- rfcomm_session_del(s);
-}
-
-/* ---- RFCOMM FCS computation ---- */
-
-/* reversed, 8-bit, poly=0x07 */
-static unsigned char rfcomm_crc_table[256] = {
- 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
- 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
- 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
- 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
-
- 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
- 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
- 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
- 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
-
- 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
- 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
- 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
- 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
-
- 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
- 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
- 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
- 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
-
- 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
- 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
- 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
- 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
-
- 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
- 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
- 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
- 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
-
- 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
- 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
- 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
- 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
-
- 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
- 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
- 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
- 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
-};
-
-/* CRC on 2 bytes */
-#define __crc(data) (rfcomm_crc_table[rfcomm_crc_table[0xff ^ data[0]] ^ data[1]])
-
-/* FCS on 2 bytes */
-static inline u8 __fcs(u8 *data)
-{
- return 0xff - __crc(data);
-}
-
-/* FCS on 3 bytes */
-static inline u8 __fcs2(u8 *data)
-{
- return 0xff - rfcomm_crc_table[__crc(data) ^ data[2]];
-}
-
-/* Check FCS */
-static inline int __check_fcs(u8 *data, int type, u8 fcs)
-{
- u8 f = __crc(data);
-
- if (type != RFCOMM_UIH)
- f = rfcomm_crc_table[f ^ data[2]];
-
- return rfcomm_crc_table[f ^ fcs] != 0xcf;
-}
-
-/* ---- L2CAP callbacks ---- */
-static void rfcomm_l2state_change(struct sock *sk)
-{
- BT_DBG("%p state %d", sk, sk->sk_state);
- rfcomm_schedule();
-}
-
-static void rfcomm_l2data_ready(struct sock *sk, int bytes)
-{
- BT_DBG("%p bytes %d", sk, bytes);
- rfcomm_schedule();
-}
-
-static int rfcomm_l2sock_create(struct socket **sock)
-{
- int err;
-
- BT_DBG("");
-
- err = sock_create_kern(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, sock);
- if (!err) {
- struct sock *sk = (*sock)->sk;
- sk->sk_data_ready = rfcomm_l2data_ready;
- sk->sk_state_change = rfcomm_l2state_change;
- }
- return err;
-}
-
-static inline int rfcomm_check_security(struct rfcomm_dlc *d)
-{
- struct sock *sk = d->session->sock->sk;
- struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
-
- __u8 auth_type;
-
- switch (d->sec_level) {
- case BT_SECURITY_HIGH:
- auth_type = HCI_AT_GENERAL_BONDING_MITM;
- break;
- case BT_SECURITY_MEDIUM:
- auth_type = HCI_AT_GENERAL_BONDING;
- break;
- default:
- auth_type = HCI_AT_NO_BONDING;
- break;
- }
-
- return hci_conn_security(conn->hcon, d->sec_level, auth_type);
-}
-
-static void rfcomm_session_timeout(unsigned long arg)
-{
- struct rfcomm_session *s = (void *) arg;
-
- BT_DBG("session %p state %ld", s, s->state);
-
- set_bit(RFCOMM_TIMED_OUT, &s->flags);
- rfcomm_schedule();
-}
-
-static void rfcomm_session_set_timer(struct rfcomm_session *s, long timeout)
-{
- BT_DBG("session %p state %ld timeout %ld", s, s->state, timeout);
-
- if (!mod_timer(&s->timer, jiffies + timeout))
- rfcomm_session_hold(s);
-}
-
-static void rfcomm_session_clear_timer(struct rfcomm_session *s)
-{
- BT_DBG("session %p state %ld", s, s->state);
-
- if (timer_pending(&s->timer) && del_timer(&s->timer))
- rfcomm_session_put(s);
-}
-
-/* ---- RFCOMM DLCs ---- */
-static void rfcomm_dlc_timeout(unsigned long arg)
-{
- struct rfcomm_dlc *d = (void *) arg;
-
- BT_DBG("dlc %p state %ld", d, d->state);
-
- set_bit(RFCOMM_TIMED_OUT, &d->flags);
- rfcomm_dlc_put(d);
- rfcomm_schedule();
-}
-
-static void rfcomm_dlc_set_timer(struct rfcomm_dlc *d, long timeout)
-{
- BT_DBG("dlc %p state %ld timeout %ld", d, d->state, timeout);
-
- if (!mod_timer(&d->timer, jiffies + timeout))
- rfcomm_dlc_hold(d);
-}
-
-static void rfcomm_dlc_clear_timer(struct rfcomm_dlc *d)
-{
- BT_DBG("dlc %p state %ld", d, d->state);
-
- if (timer_pending(&d->timer) && del_timer(&d->timer))
- rfcomm_dlc_put(d);
-}
-
-static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d)
-{
- BT_DBG("%p", d);
-
- d->state = BT_OPEN;
- d->flags = 0;
- d->mscex = 0;
- d->sec_level = BT_SECURITY_LOW;
- d->mtu = RFCOMM_DEFAULT_MTU;
- d->v24_sig = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV;
-
- d->cfc = RFCOMM_CFC_DISABLED;
- d->rx_credits = RFCOMM_DEFAULT_CREDITS;
-}
-
-struct rfcomm_dlc *rfcomm_dlc_alloc(gfp_t prio)
-{
- struct rfcomm_dlc *d = kzalloc(sizeof(*d), prio);
-
- if (!d)
- return NULL;
-
- setup_timer(&d->timer, rfcomm_dlc_timeout, (unsigned long)d);
-
- skb_queue_head_init(&d->tx_queue);
- spin_lock_init(&d->lock);
- atomic_set(&d->refcnt, 1);
-
- rfcomm_dlc_clear_state(d);
-
- BT_DBG("%p", d);
-
- return d;
-}
-
-void rfcomm_dlc_free(struct rfcomm_dlc *d)
-{
- BT_DBG("%p", d);
-
- skb_queue_purge(&d->tx_queue);
- kfree(d);
-}
-
-static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d)
-{
- BT_DBG("dlc %p session %p", d, s);
-
- rfcomm_session_hold(s);
-
- rfcomm_session_clear_timer(s);
- rfcomm_dlc_hold(d);
- list_add(&d->list, &s->dlcs);
- d->session = s;
-}
-
-static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
-{
- struct rfcomm_session *s = d->session;
-
- BT_DBG("dlc %p refcnt %d session %p", d, atomic_read(&d->refcnt), s);
-
- list_del(&d->list);
- d->session = NULL;
- rfcomm_dlc_put(d);
-
- if (list_empty(&s->dlcs))
- rfcomm_session_set_timer(s, RFCOMM_IDLE_TIMEOUT);
-
- rfcomm_session_put(s);
-}
-
-static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
-{
- struct rfcomm_dlc *d;
-
- list_for_each_entry(d, &s->dlcs, list)
- if (d->dlci == dlci)
- return d;
-
- return NULL;
-}
-
-static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
-{
- struct rfcomm_session *s;
- int err = 0;
- u8 dlci;
-
- BT_DBG("dlc %p state %ld %s %s channel %d",
- d, d->state, batostr(src), batostr(dst), channel);
-
- if (channel < 1 || channel > 30)
- return -EINVAL;
-
- if (d->state != BT_OPEN && d->state != BT_CLOSED)
- return 0;
-
- s = rfcomm_session_get(src, dst);
- if (!s) {
- s = rfcomm_session_create(src, dst, d->sec_level, &err);
- if (!s)
- return err;
- }
-
- dlci = __dlci(!s->initiator, channel);
-
- /* Check if DLCI already exists */
- if (rfcomm_dlc_get(s, dlci))
- return -EBUSY;
-
- rfcomm_dlc_clear_state(d);
-
- d->dlci = dlci;
- d->addr = __addr(s->initiator, dlci);
- d->priority = 7;
-
- d->state = BT_CONFIG;
- rfcomm_dlc_link(s, d);
-
- d->out = 1;
-
- d->mtu = s->mtu;
- d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
-
- if (s->state == BT_CONNECTED) {
- if (rfcomm_check_security(d))
- rfcomm_send_pn(s, 1, d);
- else
- set_bit(RFCOMM_AUTH_PENDING, &d->flags);
- }
-
- rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
-
- return 0;
-}
-
-int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
-{
- int r;
-
- rfcomm_lock();
-
- r = __rfcomm_dlc_open(d, src, dst, channel);
-
- rfcomm_unlock();
- return r;
-}
-
-static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
-{
- struct rfcomm_session *s = d->session;
- if (!s)
- return 0;
-
- BT_DBG("dlc %p state %ld dlci %d err %d session %p",
- d, d->state, d->dlci, err, s);
-
- switch (d->state) {
- case BT_CONNECT:
- case BT_CONFIG:
- if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
- set_bit(RFCOMM_AUTH_REJECT, &d->flags);
- rfcomm_schedule();
- break;
- }
- /* Fall through */
-
- case BT_CONNECTED:
- d->state = BT_DISCONN;
- if (skb_queue_empty(&d->tx_queue)) {
- rfcomm_send_disc(s, d->dlci);
- rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT);
- } else {
- rfcomm_queue_disc(d);
- rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2);
- }
- break;
-
- case BT_OPEN:
- case BT_CONNECT2:
- if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
- set_bit(RFCOMM_AUTH_REJECT, &d->flags);
- rfcomm_schedule();
- break;
- }
- /* Fall through */
-
- default:
- rfcomm_dlc_clear_timer(d);
-
- rfcomm_dlc_lock(d);
- d->state = BT_CLOSED;
- d->state_change(d, err);
- rfcomm_dlc_unlock(d);
-
- skb_queue_purge(&d->tx_queue);
- rfcomm_dlc_unlink(d);
- }
-
- return 0;
-}
-
-int rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
-{
- int r;
-
- rfcomm_lock();
-
- r = __rfcomm_dlc_close(d, err);
-
- rfcomm_unlock();
- return r;
-}
-
-int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
-{
- int len = skb->len;
-
- if (d->state != BT_CONNECTED)
- return -ENOTCONN;
-
- BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);
-
- if (len > d->mtu)
- return -EINVAL;
-
- rfcomm_make_uih(skb, d->addr);
- skb_queue_tail(&d->tx_queue, skb);
-
- if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags))
- rfcomm_schedule();
- return len;
-}
-
-void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
-{
- BT_DBG("dlc %p state %ld", d, d->state);
-
- if (!d->cfc) {
- d->v24_sig |= RFCOMM_V24_FC;
- set_bit(RFCOMM_MSC_PENDING, &d->flags);
- }
- rfcomm_schedule();
-}
-
-void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
-{
- BT_DBG("dlc %p state %ld", d, d->state);
-
- if (!d->cfc) {
- d->v24_sig &= ~RFCOMM_V24_FC;
- set_bit(RFCOMM_MSC_PENDING, &d->flags);
- }
- rfcomm_schedule();
-}
-
-/*
- Set/get modem status functions use _local_ status i.e. what we report
- to the other side.
- Remote status is provided by dlc->modem_status() callback.
- */
-int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig)
-{
- BT_DBG("dlc %p state %ld v24_sig 0x%x",
- d, d->state, v24_sig);
-
- if (test_bit(RFCOMM_RX_THROTTLED, &d->flags))
- v24_sig |= RFCOMM_V24_FC;
- else
- v24_sig &= ~RFCOMM_V24_FC;
-
- d->v24_sig = v24_sig;
-
- if (!test_and_set_bit(RFCOMM_MSC_PENDING, &d->flags))
- rfcomm_schedule();
-
- return 0;
-}
-
-int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig)
-{
- BT_DBG("dlc %p state %ld v24_sig 0x%x",
- d, d->state, d->v24_sig);
-
- *v24_sig = d->v24_sig;
- return 0;
-}
-
-/* ---- RFCOMM sessions ---- */
-static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
-{
- struct rfcomm_session *s = kzalloc(sizeof(*s), GFP_KERNEL);
-
- if (!s)
- return NULL;
-
- BT_DBG("session %p sock %p", s, sock);
-
- setup_timer(&s->timer, rfcomm_session_timeout, (unsigned long) s);
-
- INIT_LIST_HEAD(&s->dlcs);
- s->state = state;
- s->sock = sock;
-
- s->mtu = RFCOMM_DEFAULT_MTU;
- s->cfc = disable_cfc ? RFCOMM_CFC_DISABLED : RFCOMM_CFC_UNKNOWN;
-
- /* Do not increment module usage count for listening sessions.
- * Otherwise we won't be able to unload the module. */
- if (state != BT_LISTEN)
- if (!try_module_get(THIS_MODULE)) {
- kfree(s);
- return NULL;
- }
-
- list_add(&s->list, &session_list);
-
- return s;
-}
-
-static void rfcomm_session_del(struct rfcomm_session *s)
-{
- int state = s->state;
-
- BT_DBG("session %p state %ld", s, s->state);
-
- list_del(&s->list);
-
- if (state == BT_CONNECTED)
- rfcomm_send_disc(s, 0);
-
- rfcomm_session_clear_timer(s);
- sock_release(s->sock);
- kfree(s);
-
- if (state != BT_LISTEN)
- module_put(THIS_MODULE);
-}
-
-static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
-{
- struct rfcomm_session *s;
- struct list_head *p, *n;
- struct bt_sock *sk;
- list_for_each_safe(p, n, &session_list) {
- s = list_entry(p, struct rfcomm_session, list);
- sk = bt_sk(s->sock->sk);
-
- if ((!bacmp(src, BDADDR_ANY) || !bacmp(&sk->src, src)) &&
- !bacmp(&sk->dst, dst))
- return s;
- }
- return NULL;
-}
-
-static void rfcomm_session_close(struct rfcomm_session *s, int err)
-{
- struct rfcomm_dlc *d;
- struct list_head *p, *n;
-
- BT_DBG("session %p state %ld err %d", s, s->state, err);
-
- rfcomm_session_hold(s);
-
- s->state = BT_CLOSED;
-
- /* Close all dlcs */
- list_for_each_safe(p, n, &s->dlcs) {
- d = list_entry(p, struct rfcomm_dlc, list);
- d->state = BT_CLOSED;
- __rfcomm_dlc_close(d, err);
- }
-
- rfcomm_session_clear_timer(s);
- rfcomm_session_put(s);
-}
-
-static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
- bdaddr_t *dst,
- u8 sec_level,
- int *err)
-{
- struct rfcomm_session *s = NULL;
- struct sockaddr_l2 addr;
- struct socket *sock;
- struct sock *sk;
-
- BT_DBG("%s %s", batostr(src), batostr(dst));
-
- *err = rfcomm_l2sock_create(&sock);
- if (*err < 0)
- return NULL;
-
- bacpy(&addr.l2_bdaddr, src);
- addr.l2_family = AF_BLUETOOTH;
- addr.l2_psm = 0;
- addr.l2_cid = 0;
- *err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
- if (*err < 0)
- goto failed;
-
- /* Set L2CAP options */
- sk = sock->sk;
- lock_sock(sk);
- l2cap_pi(sk)->chan->imtu = l2cap_mtu;
- l2cap_pi(sk)->chan->sec_level = sec_level;
- if (l2cap_ertm)
- l2cap_pi(sk)->chan->mode = L2CAP_MODE_ERTM;
- release_sock(sk);
-
- s = rfcomm_session_add(sock, BT_BOUND);
- if (!s) {
- *err = -ENOMEM;
- goto failed;
- }
-
- s->initiator = 1;
-
- bacpy(&addr.l2_bdaddr, dst);
- addr.l2_family = AF_BLUETOOTH;
- addr.l2_psm = cpu_to_le16(RFCOMM_PSM);
- addr.l2_cid = 0;
- *err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
- if (*err == 0 || *err == -EINPROGRESS)
- return s;
-
- rfcomm_session_del(s);
- return NULL;
-
-failed:
- sock_release(sock);
- return NULL;
-}
-
-void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst)
-{
- struct sock *sk = s->sock->sk;
- if (src)
- bacpy(src, &bt_sk(sk)->src);
- if (dst)
- bacpy(dst, &bt_sk(sk)->dst);
-}
-
-/* ---- RFCOMM frame sending ---- */
-static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
-{
- struct kvec iv = { data, len };
- struct msghdr msg;
-
- BT_DBG("session %p len %d", s, len);
-
- memset(&msg, 0, sizeof(msg));
-
- return kernel_sendmsg(s->sock, &msg, &iv, 1, len);
-}
-
-static int rfcomm_send_cmd(struct rfcomm_session *s, struct rfcomm_cmd *cmd)
-{
- BT_DBG("%p cmd %u", s, cmd->ctrl);
-
- return rfcomm_send_frame(s, (void *) cmd, sizeof(*cmd));
-}
-
-static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
-{
- struct rfcomm_cmd cmd;
-
- BT_DBG("%p dlci %d", s, dlci);
-
- cmd.addr = __addr(s->initiator, dlci);
- cmd.ctrl = __ctrl(RFCOMM_SABM, 1);
- cmd.len = __len8(0);
- cmd.fcs = __fcs2((u8 *) &cmd);
-
- return rfcomm_send_cmd(s, &cmd);
-}
-
-static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
-{
- struct rfcomm_cmd cmd;
-
- BT_DBG("%p dlci %d", s, dlci);
-
- cmd.addr = __addr(!s->initiator, dlci);
- cmd.ctrl = __ctrl(RFCOMM_UA, 1);
- cmd.len = __len8(0);
- cmd.fcs = __fcs2((u8 *) &cmd);
-
- return rfcomm_send_cmd(s, &cmd);
-}
-
-static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
-{
- struct rfcomm_cmd cmd;
-
- BT_DBG("%p dlci %d", s, dlci);
-
- cmd.addr = __addr(s->initiator, dlci);
- cmd.ctrl = __ctrl(RFCOMM_DISC, 1);
- cmd.len = __len8(0);
- cmd.fcs = __fcs2((u8 *) &cmd);
-
- return rfcomm_send_cmd(s, &cmd);
-}
-
-static int rfcomm_queue_disc(struct rfcomm_dlc *d)
-{
- struct rfcomm_cmd *cmd;
- struct sk_buff *skb;
-
- BT_DBG("dlc %p dlci %d", d, d->dlci);
-
- skb = alloc_skb(sizeof(*cmd), GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
-
- cmd = (void *) __skb_put(skb, sizeof(*cmd));
- cmd->addr = d->addr;
- cmd->ctrl = __ctrl(RFCOMM_DISC, 1);
- cmd->len = __len8(0);
- cmd->fcs = __fcs2((u8 *) cmd);
-
- skb_queue_tail(&d->tx_queue, skb);
- rfcomm_schedule();
- return 0;
-}
-
-static int rfcomm_send_dm(struct rfcomm_session *s, u8 dlci)
-{
- struct rfcomm_cmd cmd;
-
- BT_DBG("%p dlci %d", s, dlci);
-
- cmd.addr = __addr(!s->initiator, dlci);
- cmd.ctrl = __ctrl(RFCOMM_DM, 1);
- cmd.len = __len8(0);
- cmd.fcs = __fcs2((u8 *) &cmd);
-
- return rfcomm_send_cmd(s, &cmd);
-}
-
-static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
-{
- struct rfcomm_hdr *hdr;
- struct rfcomm_mcc *mcc;
- u8 buf[16], *ptr = buf;
-
- BT_DBG("%p cr %d type %d", s, cr, type);
-
- hdr = (void *) ptr; ptr += sizeof(*hdr);
- hdr->addr = __addr(s->initiator, 0);
- hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
- hdr->len = __len8(sizeof(*mcc) + 1);
-
- mcc = (void *) ptr; ptr += sizeof(*mcc);
- mcc->type = __mcc_type(cr, RFCOMM_NSC);
- mcc->len = __len8(1);
-
- /* Type that we didn't like */
- *ptr = __mcc_type(cr, type); ptr++;
-
- *ptr = __fcs(buf); ptr++;
-
- return rfcomm_send_frame(s, buf, ptr - buf);
-}
-
-static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d)
-{
- struct rfcomm_hdr *hdr;
- struct rfcomm_mcc *mcc;
- struct rfcomm_pn *pn;
- u8 buf[16], *ptr = buf;
-
- BT_DBG("%p cr %d dlci %d mtu %d", s, cr, d->dlci, d->mtu);
-
- hdr = (void *) ptr; ptr += sizeof(*hdr);
- hdr->addr = __addr(s->initiator, 0);
- hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
- hdr->len = __len8(sizeof(*mcc) + sizeof(*pn));
-
- mcc = (void *) ptr; ptr += sizeof(*mcc);
- mcc->type = __mcc_type(cr, RFCOMM_PN);
- mcc->len = __len8(sizeof(*pn));
-
- pn = (void *) ptr; ptr += sizeof(*pn);
- pn->dlci = d->dlci;
- pn->priority = d->priority;
- pn->ack_timer = 0;
- pn->max_retrans = 0;
-
- if (s->cfc) {
- pn->flow_ctrl = cr ? 0xf0 : 0xe0;
- pn->credits = RFCOMM_DEFAULT_CREDITS;
- } else {
- pn->flow_ctrl = 0;
- pn->credits = 0;
- }
-
- if (cr && channel_mtu >= 0)
- pn->mtu = cpu_to_le16(channel_mtu);
- else
- pn->mtu = cpu_to_le16(d->mtu);
-
- *ptr = __fcs(buf); ptr++;
-
- return rfcomm_send_frame(s, buf, ptr - buf);
-}
-
-int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
- u8 bit_rate, u8 data_bits, u8 stop_bits,
- u8 parity, u8 flow_ctrl_settings,
- u8 xon_char, u8 xoff_char, u16 param_mask)
-{
- struct rfcomm_hdr *hdr;
- struct rfcomm_mcc *mcc;
- struct rfcomm_rpn *rpn;
- u8 buf[16], *ptr = buf;
-
- BT_DBG("%p cr %d dlci %d bit_r 0x%x data_b 0x%x stop_b 0x%x parity 0x%x"
- " flwc_s 0x%x xon_c 0x%x xoff_c 0x%x p_mask 0x%x",
- s, cr, dlci, bit_rate, data_bits, stop_bits, parity,
- flow_ctrl_settings, xon_char, xoff_char, param_mask);
-
- hdr = (void *) ptr; ptr += sizeof(*hdr);
- hdr->addr = __addr(s->initiator, 0);
- hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
- hdr->len = __len8(sizeof(*mcc) + sizeof(*rpn));
-
- mcc = (void *) ptr; ptr += sizeof(*mcc);
- mcc->type = __mcc_type(cr, RFCOMM_RPN);
- mcc->len = __len8(sizeof(*rpn));
-
- rpn = (void *) ptr; ptr += sizeof(*rpn);
- rpn->dlci = __addr(1, dlci);
- rpn->bit_rate = bit_rate;
- rpn->line_settings = __rpn_line_settings(data_bits, stop_bits, parity);
- rpn->flow_ctrl = flow_ctrl_settings;
- rpn->xon_char = xon_char;
- rpn->xoff_char = xoff_char;
- rpn->param_mask = cpu_to_le16(param_mask);
-
- *ptr = __fcs(buf); ptr++;
-
- return rfcomm_send_frame(s, buf, ptr - buf);
-}
-
-static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
-{
- struct rfcomm_hdr *hdr;
- struct rfcomm_mcc *mcc;
- struct rfcomm_rls *rls;
- u8 buf[16], *ptr = buf;
-
- BT_DBG("%p cr %d status 0x%x", s, cr, status);
-
- hdr = (void *) ptr; ptr += sizeof(*hdr);
- hdr->addr = __addr(s->initiator, 0);
- hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
- hdr->len = __len8(sizeof(*mcc) + sizeof(*rls));
-
- mcc = (void *) ptr; ptr += sizeof(*mcc);
- mcc->type = __mcc_type(cr, RFCOMM_RLS);
- mcc->len = __len8(sizeof(*rls));
-
- rls = (void *) ptr; ptr += sizeof(*rls);
- rls->dlci = __addr(1, dlci);
- rls->status = status;
-
- *ptr = __fcs(buf); ptr++;
-
- return rfcomm_send_frame(s, buf, ptr - buf);
-}
-
-static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
-{
- struct rfcomm_hdr *hdr;
- struct rfcomm_mcc *mcc;
- struct rfcomm_msc *msc;
- u8 buf[16], *ptr = buf;
-
- BT_DBG("%p cr %d v24 0x%x", s, cr, v24_sig);
-
- hdr = (void *) ptr; ptr += sizeof(*hdr);
- hdr->addr = __addr(s->initiator, 0);
- hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
- hdr->len = __len8(sizeof(*mcc) + sizeof(*msc));
-
- mcc = (void *) ptr; ptr += sizeof(*mcc);
- mcc->type = __mcc_type(cr, RFCOMM_MSC);
- mcc->len = __len8(sizeof(*msc));
-
- msc = (void *) ptr; ptr += sizeof(*msc);
- msc->dlci = __addr(1, dlci);
- msc->v24_sig = v24_sig | 0x01;
-
- *ptr = __fcs(buf); ptr++;
-
- return rfcomm_send_frame(s, buf, ptr - buf);
-}
-
-static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
-{
- struct rfcomm_hdr *hdr;
- struct rfcomm_mcc *mcc;
- u8 buf[16], *ptr = buf;
-
- BT_DBG("%p cr %d", s, cr);
-
- hdr = (void *) ptr; ptr += sizeof(*hdr);
- hdr->addr = __addr(s->initiator, 0);
- hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
- hdr->len = __len8(sizeof(*mcc));
-
- mcc = (void *) ptr; ptr += sizeof(*mcc);
- mcc->type = __mcc_type(cr, RFCOMM_FCOFF);
- mcc->len = __len8(0);
-
- *ptr = __fcs(buf); ptr++;
-
- return rfcomm_send_frame(s, buf, ptr - buf);
-}
-
-static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
-{
- struct rfcomm_hdr *hdr;
- struct rfcomm_mcc *mcc;
- u8 buf[16], *ptr = buf;
-
- BT_DBG("%p cr %d", s, cr);
-
- hdr = (void *) ptr; ptr += sizeof(*hdr);
- hdr->addr = __addr(s->initiator, 0);
- hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
- hdr->len = __len8(sizeof(*mcc));
-
- mcc = (void *) ptr; ptr += sizeof(*mcc);
- mcc->type = __mcc_type(cr, RFCOMM_FCON);
- mcc->len = __len8(0);
-
- *ptr = __fcs(buf); ptr++;
-
- return rfcomm_send_frame(s, buf, ptr - buf);
-}
-
-static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
-{
- struct socket *sock = s->sock;
- struct kvec iv[3];
- struct msghdr msg;
- unsigned char hdr[5], crc[1];
-
- if (len > 125)
- return -EINVAL;
-
- BT_DBG("%p cr %d", s, cr);
-
- hdr[0] = __addr(s->initiator, 0);
- hdr[1] = __ctrl(RFCOMM_UIH, 0);
- hdr[2] = 0x01 | ((len + 2) << 1);
- hdr[3] = 0x01 | ((cr & 0x01) << 1) | (RFCOMM_TEST << 2);
- hdr[4] = 0x01 | (len << 1);
-
- crc[0] = __fcs(hdr);
-
- iv[0].iov_base = hdr;
- iv[0].iov_len = 5;
- iv[1].iov_base = pattern;
- iv[1].iov_len = len;
- iv[2].iov_base = crc;
- iv[2].iov_len = 1;
-
- memset(&msg, 0, sizeof(msg));
-
- return kernel_sendmsg(sock, &msg, iv, 3, 6 + len);
-}
-
-static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
-{
- struct rfcomm_hdr *hdr;
- u8 buf[16], *ptr = buf;
-
- BT_DBG("%p addr %d credits %d", s, addr, credits);
-
- hdr = (void *) ptr; ptr += sizeof(*hdr);
- hdr->addr = addr;
- hdr->ctrl = __ctrl(RFCOMM_UIH, 1);
- hdr->len = __len8(0);
-
- *ptr = credits; ptr++;
-
- *ptr = __fcs(buf); ptr++;
-
- return rfcomm_send_frame(s, buf, ptr - buf);
-}
-
-static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
-{
- struct rfcomm_hdr *hdr;
- int len = skb->len;
- u8 *crc;
-
- if (len > 127) {
- hdr = (void *) skb_push(skb, 4);
- put_unaligned(cpu_to_le16(__len16(len)), (__le16 *) &hdr->len);
- } else {
- hdr = (void *) skb_push(skb, 3);
- hdr->len = __len8(len);
- }
- hdr->addr = addr;
- hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-
- crc = skb_put(skb, 1);
- *crc = __fcs((void *) hdr);
-}
-
-/* ---- RFCOMM frame reception ---- */
-static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
-{
- BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-
- if (dlci) {
- /* Data channel */
- struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
- if (!d) {
- rfcomm_send_dm(s, dlci);
- return 0;
- }
-
- switch (d->state) {
- case BT_CONNECT:
- rfcomm_dlc_clear_timer(d);
-
- rfcomm_dlc_lock(d);
- d->state = BT_CONNECTED;
- d->state_change(d, 0);
- rfcomm_dlc_unlock(d);
-
- rfcomm_send_msc(s, 1, dlci, d->v24_sig);
- break;
-
- case BT_DISCONN:
- d->state = BT_CLOSED;
- __rfcomm_dlc_close(d, 0);
-
- if (list_empty(&s->dlcs)) {
- s->state = BT_DISCONN;
- rfcomm_send_disc(s, 0);
- rfcomm_session_clear_timer(s);
- }
-
- break;
- }
- } else {
- /* Control channel */
- switch (s->state) {
- case BT_CONNECT:
- s->state = BT_CONNECTED;
- rfcomm_process_connect(s);
- break;
-
- case BT_DISCONN:
- /* rfcomm_session_put is called later so don't do
- * anything here otherwise we will mess up the session
- * reference counter:
- *
- * (a) when we are the initiator dlc_unlink will drive
- * the reference counter to 0 (there is no initial put
- * after session_add)
- *
- * (b) when we are not the initiator rfcomm_rx_process
- * will explicitly call put to balance the initial hold
- * done after session add.
- */
- break;
- }
- }
- return 0;
-}
-
-static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
-{
- int err = 0;
-
- BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-
- if (dlci) {
- /* Data DLC */
- struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
- if (d) {
- if (d->state == BT_CONNECT || d->state == BT_CONFIG)
- err = ECONNREFUSED;
- else
- err = ECONNRESET;
-
- d->state = BT_CLOSED;
- __rfcomm_dlc_close(d, err);
- }
- } else {
- if (s->state == BT_CONNECT)
- err = ECONNREFUSED;
- else
- err = ECONNRESET;
-
- s->state = BT_CLOSED;
- rfcomm_session_close(s, err);
- }
- return 0;
-}
-
-static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
-{
- int err = 0;
-
- BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-
- if (dlci) {
- struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
- if (d) {
- rfcomm_send_ua(s, dlci);
-
- if (d->state == BT_CONNECT || d->state == BT_CONFIG)
- err = ECONNREFUSED;
- else
- err = ECONNRESET;
-
- d->state = BT_CLOSED;
- __rfcomm_dlc_close(d, err);
- } else
- rfcomm_send_dm(s, dlci);
-
- } else {
- rfcomm_send_ua(s, 0);
-
- if (s->state == BT_CONNECT)
- err = ECONNREFUSED;
- else
- err = ECONNRESET;
-
- s->state = BT_CLOSED;
- rfcomm_session_close(s, err);
- }
-
- return 0;
-}
-
-void rfcomm_dlc_accept(struct rfcomm_dlc *d)
-{
- struct sock *sk = d->session->sock->sk;
- struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
-
- BT_DBG("dlc %p", d);
-
- rfcomm_send_ua(d->session, d->dlci);
-
- rfcomm_dlc_clear_timer(d);
-
- rfcomm_dlc_lock(d);
- d->state = BT_CONNECTED;
- d->state_change(d, 0);
- rfcomm_dlc_unlock(d);
-
- if (d->role_switch)
- hci_conn_switch_role(conn->hcon, 0x00);
-
- rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
-}
-
-static void rfcomm_check_accept(struct rfcomm_dlc *d)
-{
- if (rfcomm_check_security(d)) {
- if (d->defer_setup) {
- set_bit(RFCOMM_DEFER_SETUP, &d->flags);
- rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
-
- rfcomm_dlc_lock(d);
- d->state = BT_CONNECT2;
- d->state_change(d, 0);
- rfcomm_dlc_unlock(d);
- } else
- rfcomm_dlc_accept(d);
- } else {
- set_bit(RFCOMM_AUTH_PENDING, &d->flags);
- rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
- }
-}
-
-static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
-{
- struct rfcomm_dlc *d;
- u8 channel;
-
- BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-
- if (!dlci) {
- rfcomm_send_ua(s, 0);
-
- if (s->state == BT_OPEN) {
- s->state = BT_CONNECTED;
- rfcomm_process_connect(s);
- }
- return 0;
- }
-
- /* Check if DLC exists */
- d = rfcomm_dlc_get(s, dlci);
- if (d) {
- if (d->state == BT_OPEN) {
- /* DLC was previously opened by PN request */
- rfcomm_check_accept(d);
- }
- return 0;
- }
-
- /* Notify socket layer about incoming connection */
- channel = __srv_channel(dlci);
- if (rfcomm_connect_ind(s, channel, &d)) {
- d->dlci = dlci;
- d->addr = __addr(s->initiator, dlci);
- rfcomm_dlc_link(s, d);
-
- rfcomm_check_accept(d);
- } else {
- rfcomm_send_dm(s, dlci);
- }
-
- return 0;
-}
-
-static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
-{
- struct rfcomm_session *s = d->session;
-
- BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d",
- d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits);
-
- if ((pn->flow_ctrl == 0xf0 && s->cfc != RFCOMM_CFC_DISABLED) ||
- pn->flow_ctrl == 0xe0) {
- d->cfc = RFCOMM_CFC_ENABLED;
- d->tx_credits = pn->credits;
- } else {
- d->cfc = RFCOMM_CFC_DISABLED;
- set_bit(RFCOMM_TX_THROTTLED, &d->flags);
- }
-
- if (s->cfc == RFCOMM_CFC_UNKNOWN)
- s->cfc = d->cfc;
-
- d->priority = pn->priority;
-
- d->mtu = __le16_to_cpu(pn->mtu);
-
- if (cr && d->mtu > s->mtu)
- d->mtu = s->mtu;
-
- return 0;
-}
-
-static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb)
-{
- struct rfcomm_pn *pn = (void *) skb->data;
- struct rfcomm_dlc *d;
- u8 dlci = pn->dlci;
-
- BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-
- if (!dlci)
- return 0;
-
- d = rfcomm_dlc_get(s, dlci);
- if (d) {
- if (cr) {
- /* PN request */
- rfcomm_apply_pn(d, cr, pn);
- rfcomm_send_pn(s, 0, d);
- } else {
- /* PN response */
- switch (d->state) {
- case BT_CONFIG:
- rfcomm_apply_pn(d, cr, pn);
-
- d->state = BT_CONNECT;
- rfcomm_send_sabm(s, d->dlci);
- break;
- }
- }
- } else {
- u8 channel = __srv_channel(dlci);
-
- if (!cr)
- return 0;
-
- /* PN request for non existing DLC.
- * Assume incoming connection. */
- if (rfcomm_connect_ind(s, channel, &d)) {
- d->dlci = dlci;
- d->addr = __addr(s->initiator, dlci);
- rfcomm_dlc_link(s, d);
-
- rfcomm_apply_pn(d, cr, pn);
-
- d->state = BT_OPEN;
- rfcomm_send_pn(s, 0, d);
- } else {
- rfcomm_send_dm(s, dlci);
- }
- }
- return 0;
-}
-
-static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb)
-{
- struct rfcomm_rpn *rpn = (void *) skb->data;
- u8 dlci = __get_dlci(rpn->dlci);
-
- u8 bit_rate = 0;
- u8 data_bits = 0;
- u8 stop_bits = 0;
- u8 parity = 0;
- u8 flow_ctrl = 0;
- u8 xon_char = 0;
- u8 xoff_char = 0;
- u16 rpn_mask = RFCOMM_RPN_PM_ALL;
-
- BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x",
- dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl,
- rpn->xon_char, rpn->xoff_char, rpn->param_mask);
-
- if (!cr)
- return 0;
-
- if (len == 1) {
- /* This is a request, return default (according to ETSI TS 07.10) settings */
- bit_rate = RFCOMM_RPN_BR_9600;
- data_bits = RFCOMM_RPN_DATA_8;
- stop_bits = RFCOMM_RPN_STOP_1;
- parity = RFCOMM_RPN_PARITY_NONE;
- flow_ctrl = RFCOMM_RPN_FLOW_NONE;
- xon_char = RFCOMM_RPN_XON_CHAR;
- xoff_char = RFCOMM_RPN_XOFF_CHAR;
- goto rpn_out;
- }
-
- /* Check for sane values, ignore/accept bit_rate, 8 bits, 1 stop bit,
- * no parity, no flow control lines, normal XON/XOFF chars */
-
- if (rpn->param_mask & cpu_to_le16(RFCOMM_RPN_PM_BITRATE)) {
- bit_rate = rpn->bit_rate;
- if (bit_rate > RFCOMM_RPN_BR_230400) {
- BT_DBG("RPN bit rate mismatch 0x%x", bit_rate);
- bit_rate = RFCOMM_RPN_BR_9600;
- rpn_mask ^= RFCOMM_RPN_PM_BITRATE;
- }
- }
-
- if (rpn->param_mask & cpu_to_le16(RFCOMM_RPN_PM_DATA)) {
- data_bits = __get_rpn_data_bits(rpn->line_settings);
- if (data_bits != RFCOMM_RPN_DATA_8) {
- BT_DBG("RPN data bits mismatch 0x%x", data_bits);
- data_bits = RFCOMM_RPN_DATA_8;
- rpn_mask ^= RFCOMM_RPN_PM_DATA;
- }
- }
-
- if (rpn->param_mask & cpu_to_le16(RFCOMM_RPN_PM_STOP)) {
- stop_bits = __get_rpn_stop_bits(rpn->line_settings);
- if (stop_bits != RFCOMM_RPN_STOP_1) {
- BT_DBG("RPN stop bits mismatch 0x%x", stop_bits);
- stop_bits = RFCOMM_RPN_STOP_1;
- rpn_mask ^= RFCOMM_RPN_PM_STOP;
- }
- }
-
- if (rpn->param_mask & cpu_to_le16(RFCOMM_RPN_PM_PARITY)) {
- parity = __get_rpn_parity(rpn->line_settings);
- if (parity != RFCOMM_RPN_PARITY_NONE) {
- BT_DBG("RPN parity mismatch 0x%x", parity);
- parity = RFCOMM_RPN_PARITY_NONE;
- rpn_mask ^= RFCOMM_RPN_PM_PARITY;
- }
- }
-
- if (rpn->param_mask & cpu_to_le16(RFCOMM_RPN_PM_FLOW)) {
- flow_ctrl = rpn->flow_ctrl;
- if (flow_ctrl != RFCOMM_RPN_FLOW_NONE) {
- BT_DBG("RPN flow ctrl mismatch 0x%x", flow_ctrl);
- flow_ctrl = RFCOMM_RPN_FLOW_NONE;
- rpn_mask ^= RFCOMM_RPN_PM_FLOW;
- }
- }
-
- if (rpn->param_mask & cpu_to_le16(RFCOMM_RPN_PM_XON)) {
- xon_char = rpn->xon_char;
- if (xon_char != RFCOMM_RPN_XON_CHAR) {
- BT_DBG("RPN XON char mismatch 0x%x", xon_char);
- xon_char = RFCOMM_RPN_XON_CHAR;
- rpn_mask ^= RFCOMM_RPN_PM_XON;
- }
- }
-
- if (rpn->param_mask & cpu_to_le16(RFCOMM_RPN_PM_XOFF)) {
- xoff_char = rpn->xoff_char;
- if (xoff_char != RFCOMM_RPN_XOFF_CHAR) {
- BT_DBG("RPN XOFF char mismatch 0x%x", xoff_char);
- xoff_char = RFCOMM_RPN_XOFF_CHAR;
- rpn_mask ^= RFCOMM_RPN_PM_XOFF;
- }
- }
-
-rpn_out:
- rfcomm_send_rpn(s, 0, dlci, bit_rate, data_bits, stop_bits,
- parity, flow_ctrl, xon_char, xoff_char, rpn_mask);
-
- return 0;
-}
-
-static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb)
-{
- struct rfcomm_rls *rls = (void *) skb->data;
- u8 dlci = __get_dlci(rls->dlci);
-
- BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status);
-
- if (!cr)
- return 0;
-
- /* We should probably do something with this information here. But
- * for now it's sufficient just to reply -- Bluetooth 1.1 says it's
- * mandatory to recognise and respond to RLS */
-
- rfcomm_send_rls(s, 0, dlci, rls->status);
-
- return 0;
-}
-
-static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb)
-{
- struct rfcomm_msc *msc = (void *) skb->data;
- struct rfcomm_dlc *d;
- u8 dlci = __get_dlci(msc->dlci);
-
- BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);
-
- d = rfcomm_dlc_get(s, dlci);
- if (!d)
- return 0;
-
- if (cr) {
- if (msc->v24_sig & RFCOMM_V24_FC && !d->cfc)
- set_bit(RFCOMM_TX_THROTTLED, &d->flags);
- else
- clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
-
- rfcomm_dlc_lock(d);
-
- d->remote_v24_sig = msc->v24_sig;
-
- if (d->modem_status)
- d->modem_status(d, msc->v24_sig);
-
- rfcomm_dlc_unlock(d);
-
- rfcomm_send_msc(s, 0, dlci, msc->v24_sig);
-
- d->mscex |= RFCOMM_MSCEX_RX;
- } else
- d->mscex |= RFCOMM_MSCEX_TX;
-
- return 0;
-}
-
-static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb)
-{
- struct rfcomm_mcc *mcc = (void *) skb->data;
- u8 type, cr, len;
-
- cr = __test_cr(mcc->type);
- type = __get_mcc_type(mcc->type);
- len = __get_mcc_len(mcc->len);
-
- BT_DBG("%p type 0x%x cr %d", s, type, cr);
-
- skb_pull(skb, 2);
-
- switch (type) {
- case RFCOMM_PN:
- rfcomm_recv_pn(s, cr, skb);
- break;
-
- case RFCOMM_RPN:
- rfcomm_recv_rpn(s, cr, len, skb);
- break;
-
- case RFCOMM_RLS:
- rfcomm_recv_rls(s, cr, skb);
- break;
-
- case RFCOMM_MSC:
- rfcomm_recv_msc(s, cr, skb);
- break;
-
- case RFCOMM_FCOFF:
- if (cr) {
- set_bit(RFCOMM_TX_THROTTLED, &s->flags);
- rfcomm_send_fcoff(s, 0);
- }
- break;
-
- case RFCOMM_FCON:
- if (cr) {
- clear_bit(RFCOMM_TX_THROTTLED, &s->flags);
- rfcomm_send_fcon(s, 0);
- }
- break;
-
- case RFCOMM_TEST:
- if (cr)
- rfcomm_send_test(s, 0, skb->data, skb->len);
- break;
-
- case RFCOMM_NSC:
- break;
-
- default:
- BT_ERR("Unknown control type 0x%02x", type);
- rfcomm_send_nsc(s, cr, type);
- break;
- }
- return 0;
-}
-
-static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk_buff *skb)
-{
- struct rfcomm_dlc *d;
-
- BT_DBG("session %p state %ld dlci %d pf %d", s, s->state, dlci, pf);
-
- d = rfcomm_dlc_get(s, dlci);
- if (!d) {
- rfcomm_send_dm(s, dlci);
- goto drop;
- }
-
- if (pf && d->cfc) {
- u8 credits = *(u8 *) skb->data; skb_pull(skb, 1);
-
- d->tx_credits += credits;
- if (d->tx_credits)
- clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
- }
-
- if (skb->len && d->state == BT_CONNECTED) {
- rfcomm_dlc_lock(d);
- d->rx_credits--;
- d->data_ready(d, skb);
- rfcomm_dlc_unlock(d);
- return 0;
- }
-
-drop:
- kfree_skb(skb);
- return 0;
-}
-
-static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
-{
- struct rfcomm_hdr *hdr = (void *) skb->data;
- u8 type, dlci, fcs;
-
- dlci = __get_dlci(hdr->addr);
- type = __get_type(hdr->ctrl);
-
- /* Trim FCS */
- skb->len--; skb->tail--;
- fcs = *(u8 *)skb_tail_pointer(skb);
-
- if (__check_fcs(skb->data, type, fcs)) {
- BT_ERR("bad checksum in packet");
- kfree_skb(skb);
- return -EILSEQ;
- }
-
- if (__test_ea(hdr->len))
- skb_pull(skb, 3);
- else
- skb_pull(skb, 4);
-
- switch (type) {
- case RFCOMM_SABM:
- if (__test_pf(hdr->ctrl))
- rfcomm_recv_sabm(s, dlci);
- break;
-
- case RFCOMM_DISC:
- if (__test_pf(hdr->ctrl))
- rfcomm_recv_disc(s, dlci);
- break;
-
- case RFCOMM_UA:
- if (__test_pf(hdr->ctrl))
- rfcomm_recv_ua(s, dlci);
- break;
-
- case RFCOMM_DM:
- rfcomm_recv_dm(s, dlci);
- break;
-
- case RFCOMM_UIH:
- if (dlci)
- return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb);
-
- rfcomm_recv_mcc(s, skb);
- break;
-
- default:
- BT_ERR("Unknown packet type 0x%02x", type);
- break;
- }
- kfree_skb(skb);
- return 0;
-}
-
-/* ---- Connection and data processing ---- */
-
-static void rfcomm_process_connect(struct rfcomm_session *s)
-{
- struct rfcomm_dlc *d;
- struct list_head *p, *n;
-
- BT_DBG("session %p state %ld", s, s->state);
-
- list_for_each_safe(p, n, &s->dlcs) {
- d = list_entry(p, struct rfcomm_dlc, list);
- if (d->state == BT_CONFIG) {
- d->mtu = s->mtu;
- if (rfcomm_check_security(d)) {
- rfcomm_send_pn(s, 1, d);
- } else {
- set_bit(RFCOMM_AUTH_PENDING, &d->flags);
- rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
- }
- }
- }
-}
-
-/* Send data queued for the DLC.
- * Return number of frames left in the queue.
- */
-static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
-{
- struct sk_buff *skb;
- int err;
-
- BT_DBG("dlc %p state %ld cfc %d rx_credits %d tx_credits %d",
- d, d->state, d->cfc, d->rx_credits, d->tx_credits);
-
- /* Send pending MSC */
- if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags))
- rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
-
- if (d->cfc) {
- /* CFC enabled.
- * Give them some credits */
- if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) &&
- d->rx_credits <= (d->cfc >> 2)) {
- rfcomm_send_credits(d->session, d->addr, d->cfc - d->rx_credits);
- d->rx_credits = d->cfc;
- }
- } else {
- /* CFC disabled.
- * Give ourselves some credits */
- d->tx_credits = 5;
- }
-
- if (test_bit(RFCOMM_TX_THROTTLED, &d->flags))
- return skb_queue_len(&d->tx_queue);
-
- while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) {
- err = rfcomm_send_frame(d->session, skb->data, skb->len);
- if (err < 0) {
- skb_queue_head(&d->tx_queue, skb);
- break;
- }
- kfree_skb(skb);
- d->tx_credits--;
- }
-
- if (d->cfc && !d->tx_credits) {
- /* We're out of TX credits.
- * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */
- set_bit(RFCOMM_TX_THROTTLED, &d->flags);
- }
-
- return skb_queue_len(&d->tx_queue);
-}
-
-static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
-{
- struct rfcomm_dlc *d;
- struct list_head *p, *n;
-
- BT_DBG("session %p state %ld", s, s->state);
-
- list_for_each_safe(p, n, &s->dlcs) {
- d = list_entry(p, struct rfcomm_dlc, list);
-
- if (test_bit(RFCOMM_TIMED_OUT, &d->flags)) {
- __rfcomm_dlc_close(d, ETIMEDOUT);
- continue;
- }
-
- if (test_bit(RFCOMM_ENC_DROP, &d->flags)) {
- __rfcomm_dlc_close(d, ECONNREFUSED);
- continue;
- }
-
- if (test_and_clear_bit(RFCOMM_AUTH_ACCEPT, &d->flags)) {
- rfcomm_dlc_clear_timer(d);
- if (d->out) {
- rfcomm_send_pn(s, 1, d);
- rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
- } else {
- if (d->defer_setup) {
- set_bit(RFCOMM_DEFER_SETUP, &d->flags);
- rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
-
- rfcomm_dlc_lock(d);
- d->state = BT_CONNECT2;
- d->state_change(d, 0);
- rfcomm_dlc_unlock(d);
- } else
- rfcomm_dlc_accept(d);
- }
- continue;
- } else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) {
- rfcomm_dlc_clear_timer(d);
- if (!d->out)
- rfcomm_send_dm(s, d->dlci);
- else
- d->state = BT_CLOSED;
- __rfcomm_dlc_close(d, ECONNREFUSED);
- continue;
- }
-
- if (test_bit(RFCOMM_SEC_PENDING, &d->flags))
- continue;
-
- if (test_bit(RFCOMM_TX_THROTTLED, &s->flags))
- continue;
-
- if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
- d->mscex == RFCOMM_MSCEX_OK)
- rfcomm_process_tx(d);
- }
-}
-
-static inline void rfcomm_process_rx(struct rfcomm_session *s)
-{
- struct socket *sock = s->sock;
- struct sock *sk = sock->sk;
- struct sk_buff *skb;
-
- BT_DBG("session %p state %ld qlen %d", s, s->state, skb_queue_len(&sk->sk_receive_queue));
-
- /* Get data directly from socket receive queue without copying it. */
- while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
- skb_orphan(skb);
- if (!skb_linearize(skb))
- rfcomm_recv_frame(s, skb);
- else
- kfree_skb(skb);
- }
-
- if (sk->sk_state == BT_CLOSED) {
- if (!s->initiator)
- rfcomm_session_put(s);
-
- rfcomm_session_close(s, sk->sk_err);
- }
-}
-
-static inline void rfcomm_accept_connection(struct rfcomm_session *s)
-{
- struct socket *sock = s->sock, *nsock;
- int err;
-
- /* Fast check for a new connection.
- * Avoids unnesesary socket allocations. */
- if (list_empty(&bt_sk(sock->sk)->accept_q))
- return;
-
- BT_DBG("session %p", s);
-
- err = kernel_accept(sock, &nsock, O_NONBLOCK);
- if (err < 0)
- return;
-
- /* Set our callbacks */
- nsock->sk->sk_data_ready = rfcomm_l2data_ready;
- nsock->sk->sk_state_change = rfcomm_l2state_change;
-
- s = rfcomm_session_add(nsock, BT_OPEN);
- if (s) {
- rfcomm_session_hold(s);
-
- /* We should adjust MTU on incoming sessions.
- * L2CAP MTU minus UIH header and FCS. */
- s->mtu = min(l2cap_pi(nsock->sk)->chan->omtu,
- l2cap_pi(nsock->sk)->chan->imtu) - 5;
-
- rfcomm_schedule();
- } else
- sock_release(nsock);
-}
-
-static inline void rfcomm_check_connection(struct rfcomm_session *s)
-{
- struct sock *sk = s->sock->sk;
-
- BT_DBG("%p state %ld", s, s->state);
-
- switch (sk->sk_state) {
- case BT_CONNECTED:
- s->state = BT_CONNECT;
-
- /* We can adjust MTU on outgoing sessions.
- * L2CAP MTU minus UIH header and FCS. */
- s->mtu = min(l2cap_pi(sk)->chan->omtu, l2cap_pi(sk)->chan->imtu) - 5;
-
- rfcomm_send_sabm(s, 0);
- break;
-
- case BT_CLOSED:
- s->state = BT_CLOSED;
- rfcomm_session_close(s, sk->sk_err);
- break;
- }
-}
-
-static inline void rfcomm_process_sessions(void)
-{
- struct list_head *p, *n;
-
- rfcomm_lock();
-
- list_for_each_safe(p, n, &session_list) {
- struct rfcomm_session *s;
- s = list_entry(p, struct rfcomm_session, list);
-
- if (test_and_clear_bit(RFCOMM_TIMED_OUT, &s->flags)) {
- s->state = BT_DISCONN;
- rfcomm_send_disc(s, 0);
- rfcomm_session_put(s);
- continue;
- }
-
- if (s->state == BT_LISTEN) {
- rfcomm_accept_connection(s);
- continue;
- }
-
- rfcomm_session_hold(s);
-
- switch (s->state) {
- case BT_BOUND:
- rfcomm_check_connection(s);
- break;
-
- default:
- rfcomm_process_rx(s);
- break;
- }
-
- rfcomm_process_dlcs(s);
-
- rfcomm_session_put(s);
- }
-
- rfcomm_unlock();
-}
-
-static int rfcomm_add_listener(bdaddr_t *ba)
-{
- struct sockaddr_l2 addr;
- struct socket *sock;
- struct sock *sk;
- struct rfcomm_session *s;
- int err = 0;
-
- /* Create socket */
- err = rfcomm_l2sock_create(&sock);
- if (err < 0) {
- BT_ERR("Create socket failed %d", err);
- return err;
- }
-
- /* Bind socket */
- bacpy(&addr.l2_bdaddr, ba);
- addr.l2_family = AF_BLUETOOTH;
- addr.l2_psm = cpu_to_le16(RFCOMM_PSM);
- addr.l2_cid = 0;
- err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
- if (err < 0) {
- BT_ERR("Bind failed %d", err);
- goto failed;
- }
-
- /* Set L2CAP options */
- sk = sock->sk;
- lock_sock(sk);
- l2cap_pi(sk)->chan->imtu = l2cap_mtu;
- release_sock(sk);
-
- /* Start listening on the socket */
- err = kernel_listen(sock, 10);
- if (err) {
- BT_ERR("Listen failed %d", err);
- goto failed;
- }
-
- /* Add listening session */
- s = rfcomm_session_add(sock, BT_LISTEN);
- if (!s)
- goto failed;
-
- rfcomm_session_hold(s);
- return 0;
-failed:
- sock_release(sock);
- return err;
-}
-
-static void rfcomm_kill_listener(void)
-{
- struct rfcomm_session *s;
- struct list_head *p, *n;
-
- BT_DBG("");
-
- list_for_each_safe(p, n, &session_list) {
- s = list_entry(p, struct rfcomm_session, list);
- rfcomm_session_del(s);
- }
-}
-
-static int rfcomm_run(void *unused)
-{
- BT_DBG("");
-
- set_user_nice(current, -10);
-
- rfcomm_add_listener(BDADDR_ANY);
-
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (kthread_should_stop())
- break;
-
- /* Process stuff */
- rfcomm_process_sessions();
-
- schedule();
- }
- __set_current_state(TASK_RUNNING);
-
- rfcomm_kill_listener();
-
- return 0;
-}
-
-static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
-{
- struct rfcomm_session *s;
- struct rfcomm_dlc *d;
- struct list_head *p, *n;
-
- BT_DBG("conn %p status 0x%02x encrypt 0x%02x", conn, status, encrypt);
-
- s = rfcomm_session_get(&conn->hdev->bdaddr, &conn->dst);
- if (!s)
- return;
-
- rfcomm_session_hold(s);
-
- list_for_each_safe(p, n, &s->dlcs) {
- d = list_entry(p, struct rfcomm_dlc, list);
-
- if (test_and_clear_bit(RFCOMM_SEC_PENDING, &d->flags)) {
- rfcomm_dlc_clear_timer(d);
- if (status || encrypt == 0x00) {
- set_bit(RFCOMM_ENC_DROP, &d->flags);
- continue;
- }
- }
-
- if (d->state == BT_CONNECTED && !status && encrypt == 0x00) {
- if (d->sec_level == BT_SECURITY_MEDIUM) {
- set_bit(RFCOMM_SEC_PENDING, &d->flags);
- rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
- continue;
- } else if (d->sec_level == BT_SECURITY_HIGH) {
- set_bit(RFCOMM_ENC_DROP, &d->flags);
- continue;
- }
- }
-
- if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
- continue;
-
- if (!status && hci_conn_check_secure(conn, d->sec_level))
- set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
- else
- set_bit(RFCOMM_AUTH_REJECT, &d->flags);
- }
-
- rfcomm_session_put(s);
-
- rfcomm_schedule();
-}
-
-static struct hci_cb rfcomm_cb = {
- .name = "RFCOMM",
- .security_cfm = rfcomm_security_cfm
-};
-
-static int rfcomm_dlc_debugfs_show(struct seq_file *f, void *x)
-{
- struct rfcomm_session *s;
-
- rfcomm_lock();
-
- list_for_each_entry(s, &session_list, list) {
- struct rfcomm_dlc *d;
- list_for_each_entry(d, &s->dlcs, list) {
- struct sock *sk = s->sock->sk;
-
- seq_printf(f, "%s %s %ld %d %d %d %d\n",
- batostr(&bt_sk(sk)->src),
- batostr(&bt_sk(sk)->dst),
- d->state, d->dlci, d->mtu,
- d->rx_credits, d->tx_credits);
- }
- }
-
- rfcomm_unlock();
-
- return 0;
-}
-
-static int rfcomm_dlc_debugfs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, rfcomm_dlc_debugfs_show, inode->i_private);
-}
-
-static const struct file_operations rfcomm_dlc_debugfs_fops = {
- .open = rfcomm_dlc_debugfs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static struct dentry *rfcomm_dlc_debugfs;
-
-/* ---- Initialization ---- */
-static int __init rfcomm_init(void)
-{
- int err;
-
- hci_register_cb(&rfcomm_cb);
-
- rfcomm_thread = kthread_run(rfcomm_run, NULL, "krfcommd");
- if (IS_ERR(rfcomm_thread)) {
- err = PTR_ERR(rfcomm_thread);
- goto unregister;
- }
-
- if (bt_debugfs) {
- rfcomm_dlc_debugfs = debugfs_create_file("rfcomm_dlc", 0444,
- bt_debugfs, NULL, &rfcomm_dlc_debugfs_fops);
- if (!rfcomm_dlc_debugfs)
- BT_ERR("Failed to create RFCOMM debug file");
- }
-
- err = rfcomm_init_ttys();
- if (err < 0)
- goto stop;
-
- err = rfcomm_init_sockets();
- if (err < 0)
- goto cleanup;
-
- BT_INFO("RFCOMM ver %s", VERSION);
-
- return 0;
-
-cleanup:
- rfcomm_cleanup_ttys();
-
-stop:
- kthread_stop(rfcomm_thread);
-
-unregister:
- hci_unregister_cb(&rfcomm_cb);
-
- return err;
-}
-
-static void __exit rfcomm_exit(void)
-{
- debugfs_remove(rfcomm_dlc_debugfs);
-
- hci_unregister_cb(&rfcomm_cb);
-
- kthread_stop(rfcomm_thread);
-
- rfcomm_cleanup_ttys();
-
- rfcomm_cleanup_sockets();
-}
-
-module_init(rfcomm_init);
-module_exit(rfcomm_exit);
-
-module_param(disable_cfc, bool, 0644);
-MODULE_PARM_DESC(disable_cfc, "Disable credit based flow control");
-
-module_param(channel_mtu, int, 0644);
-MODULE_PARM_DESC(channel_mtu, "Default MTU for the RFCOMM channel");
-
-module_param(l2cap_mtu, uint, 0644);
-MODULE_PARM_DESC(l2cap_mtu, "Default MTU for the L2CAP connection");
-
-module_param(l2cap_ertm, bool, 0644);
-MODULE_PARM_DESC(l2cap_ertm, "Use L2CAP ERTM mode for connection");
-
-MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("Bluetooth RFCOMM ver " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("bt-proto-3");
diff --git a/net/bluetooth_tizen/rfcomm/sock.c b/net/bluetooth_tizen/rfcomm/sock.c
deleted file mode 100644
index 22169c3..0000000
--- a/net/bluetooth_tizen/rfcomm/sock.c
+++ /dev/null
@@ -1,1078 +0,0 @@
-/*
- RFCOMM implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
- Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/*
- * RFCOMM sockets.
- */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/socket.h>
-#include <linux/skbuff.h>
-#include <linux/list.h>
-#include <linux/device.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/security.h>
-#include <net/sock.h>
-
-#include <asm/system.h>
-#include <linux/uaccess.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/l2cap.h>
-#include <net/bluetooth/rfcomm.h>
-
-static const struct proto_ops rfcomm_sock_ops;
-
-static struct bt_sock_list rfcomm_sk_list = {
- .lock = __RW_LOCK_UNLOCKED(rfcomm_sk_list.lock)
-};
-
-static void rfcomm_sock_close(struct sock *sk);
-static void rfcomm_sock_kill(struct sock *sk);
-
-/* ---- DLC callbacks ----
- *
- * called under rfcomm_dlc_lock()
- */
-static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
-{
- struct sock *sk = d->owner;
- if (!sk)
- return;
-
- atomic_add(skb->len, &sk->sk_rmem_alloc);
- skb_queue_tail(&sk->sk_receive_queue, skb);
- sk->sk_data_ready(sk, skb->len);
-
- if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
- rfcomm_dlc_throttle(d);
-}
-
-static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
-{
- struct sock *sk = d->owner, *parent;
- unsigned long flags;
-
- if (!sk)
- return;
-
- BT_DBG("dlc %p state %ld err %d", d, d->state, err);
-
- local_irq_save(flags);
- bh_lock_sock(sk);
-
- if (err)
- sk->sk_err = err;
-
- sk->sk_state = d->state;
-
- parent = bt_sk(sk)->parent;
- if (parent) {
- if (d->state == BT_CLOSED) {
- sock_set_flag(sk, SOCK_ZAPPED);
- bt_accept_unlink(sk);
- }
- parent->sk_data_ready(parent, 0);
- } else {
- if (d->state == BT_CONNECTED)
- rfcomm_session_getaddr(d->session, &bt_sk(sk)->src, NULL);
- sk->sk_state_change(sk);
- }
-
- bh_unlock_sock(sk);
- local_irq_restore(flags);
-
- if (parent && sock_flag(sk, SOCK_ZAPPED)) {
- /* We have to drop DLC lock here, otherwise
- * rfcomm_sock_destruct() will dead lock. */
- rfcomm_dlc_unlock(d);
- rfcomm_sock_kill(sk);
- rfcomm_dlc_lock(d);
- }
-}
-
-/* ---- Socket functions ---- */
-static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src)
-{
- struct sock *sk = NULL;
- struct hlist_node *node;
-
- sk_for_each(sk, node, &rfcomm_sk_list.head) {
- if (rfcomm_pi(sk)->channel == channel &&
- !bacmp(&bt_sk(sk)->src, src))
- break;
- }
-
- return node ? sk : NULL;
-}
-
-/* Find socket with channel and source bdaddr.
- * Returns closest match.
- */
-static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
-{
- struct sock *sk = NULL, *sk1 = NULL;
- struct hlist_node *node;
-
- read_lock(&rfcomm_sk_list.lock);
-
- sk_for_each(sk, node, &rfcomm_sk_list.head) {
- if (state && sk->sk_state != state)
- continue;
-
- if (rfcomm_pi(sk)->channel == channel) {
- /* Exact match. */
- if (!bacmp(&bt_sk(sk)->src, src))
- break;
-
- /* Closest match */
- if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
- sk1 = sk;
- }
- }
-
- read_unlock(&rfcomm_sk_list.lock);
-
- return node ? sk : sk1;
-}
-
-static void rfcomm_sock_destruct(struct sock *sk)
-{
- struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
-
- BT_DBG("sk %p dlc %p", sk, d);
-
- skb_queue_purge(&sk->sk_receive_queue);
- skb_queue_purge(&sk->sk_write_queue);
-
- rfcomm_dlc_lock(d);
- rfcomm_pi(sk)->dlc = NULL;
-
- /* Detach DLC if it's owned by this socket */
- if (d->owner == sk)
- d->owner = NULL;
- rfcomm_dlc_unlock(d);
-
- rfcomm_dlc_put(d);
-}
-
-static void rfcomm_sock_cleanup_listen(struct sock *parent)
-{
- struct sock *sk;
-
- BT_DBG("parent %p", parent);
-
- /* Close not yet accepted dlcs */
- while ((sk = bt_accept_dequeue(parent, NULL))) {
- rfcomm_sock_close(sk);
- rfcomm_sock_kill(sk);
- }
-
- parent->sk_state = BT_CLOSED;
- sock_set_flag(parent, SOCK_ZAPPED);
-}
-
-/* Kill socket (only if zapped and orphan)
- * Must be called on unlocked socket.
- */
-static void rfcomm_sock_kill(struct sock *sk)
-{
- if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
- return;
-
- BT_DBG("sk %p state %d refcnt %d", sk, sk->sk_state, atomic_read(&sk->sk_refcnt));
-
- /* Kill poor orphan */
- bt_sock_unlink(&rfcomm_sk_list, sk);
- sock_set_flag(sk, SOCK_DEAD);
- sock_put(sk);
-}
-
-static void __rfcomm_sock_close(struct sock *sk)
-{
- struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
-
- BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
-
- switch (sk->sk_state) {
- case BT_LISTEN:
- rfcomm_sock_cleanup_listen(sk);
- break;
-
- case BT_CONNECT:
- case BT_CONNECT2:
- case BT_CONFIG:
- case BT_CONNECTED:
- rfcomm_dlc_close(d, 0);
-
- default:
- sock_set_flag(sk, SOCK_ZAPPED);
- break;
- }
-}
-
-/* Close socket.
- * Must be called on unlocked socket.
- */
-static void rfcomm_sock_close(struct sock *sk)
-{
- lock_sock(sk);
- __rfcomm_sock_close(sk);
- release_sock(sk);
-}
-
-static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
-{
- struct rfcomm_pinfo *pi = rfcomm_pi(sk);
-
- BT_DBG("sk %p", sk);
-
- if (parent) {
- sk->sk_type = parent->sk_type;
- pi->dlc->defer_setup = bt_sk(parent)->defer_setup;
-
- pi->sec_level = rfcomm_pi(parent)->sec_level;
- pi->role_switch = rfcomm_pi(parent)->role_switch;
-
- security_sk_clone(parent, sk);
- } else {
- pi->dlc->defer_setup = 0;
-
- pi->sec_level = BT_SECURITY_LOW;
- pi->role_switch = 0;
- }
-
- pi->dlc->sec_level = pi->sec_level;
- pi->dlc->role_switch = pi->role_switch;
-}
-
-static struct proto rfcomm_proto = {
- .name = "RFCOMM",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct rfcomm_pinfo)
-};
-
-static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
-{
- struct rfcomm_dlc *d;
- struct sock *sk;
-
- sk = sk_alloc(net, PF_BLUETOOTH, prio, &rfcomm_proto);
- if (!sk)
- return NULL;
-
- sock_init_data(sock, sk);
- INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
-
- d = rfcomm_dlc_alloc(prio);
- if (!d) {
- sk_free(sk);
- return NULL;
- }
-
- d->data_ready = rfcomm_sk_data_ready;
- d->state_change = rfcomm_sk_state_change;
-
- rfcomm_pi(sk)->dlc = d;
- d->owner = sk;
-
- sk->sk_destruct = rfcomm_sock_destruct;
- sk->sk_sndtimeo = RFCOMM_CONN_TIMEOUT;
-
- sk->sk_sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
- sk->sk_rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
-
- sock_reset_flag(sk, SOCK_ZAPPED);
-
- sk->sk_protocol = proto;
- sk->sk_state = BT_OPEN;
-
- bt_sock_link(&rfcomm_sk_list, sk);
-
- BT_DBG("sk %p", sk);
- return sk;
-}
-
-static int rfcomm_sock_create(struct net *net, struct socket *sock,
- int protocol, int kern)
-{
- struct sock *sk;
-
- BT_DBG("sock %p", sock);
-
- sock->state = SS_UNCONNECTED;
-
- if (sock->type != SOCK_STREAM && sock->type != SOCK_RAW)
- return -ESOCKTNOSUPPORT;
-
- sock->ops = &rfcomm_sock_ops;
-
- sk = rfcomm_sock_alloc(net, sock, protocol, GFP_ATOMIC);
- if (!sk)
- return -ENOMEM;
-
- rfcomm_sock_init(sk, NULL);
- return 0;
-}
-
-static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
-{
- struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
- struct sock *sk = sock->sk;
- int err = 0;
-
- BT_DBG("sk %p %s", sk, batostr(&sa->rc_bdaddr));
-
- if (!addr || addr->sa_family != AF_BLUETOOTH)
- return -EINVAL;
-
- lock_sock(sk);
-
- if (sk->sk_state != BT_OPEN) {
- err = -EBADFD;
- goto done;
- }
-
- if (sk->sk_type != SOCK_STREAM) {
- err = -EINVAL;
- goto done;
- }
-
- write_lock(&rfcomm_sk_list.lock);
-
- if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
- err = -EADDRINUSE;
- } else {
- /* Save source address */
- bacpy(&bt_sk(sk)->src, &sa->rc_bdaddr);
- rfcomm_pi(sk)->channel = sa->rc_channel;
- sk->sk_state = BT_BOUND;
- }
-
- write_unlock(&rfcomm_sk_list.lock);
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
-{
- struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
- struct sock *sk = sock->sk;
- struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
- int err = 0;
-
- BT_DBG("sk %p", sk);
-
- if (alen < sizeof(struct sockaddr_rc) ||
- addr->sa_family != AF_BLUETOOTH)
- return -EINVAL;
-
- lock_sock(sk);
-
- if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
- err = -EBADFD;
- goto done;
- }
-
- if (sk->sk_type != SOCK_STREAM) {
- err = -EINVAL;
- goto done;
- }
-
- sk->sk_state = BT_CONNECT;
- bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
- rfcomm_pi(sk)->channel = sa->rc_channel;
-
- d->sec_level = rfcomm_pi(sk)->sec_level;
- d->role_switch = rfcomm_pi(sk)->role_switch;
-
- err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
- if (!err)
- err = bt_sock_wait_state(sk, BT_CONNECTED,
- sock_sndtimeo(sk, flags & O_NONBLOCK));
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int rfcomm_sock_listen(struct socket *sock, int backlog)
-{
- struct sock *sk = sock->sk;
- int err = 0;
-
- BT_DBG("sk %p backlog %d", sk, backlog);
-
- lock_sock(sk);
-
- if (sk->sk_state != BT_BOUND) {
- err = -EBADFD;
- goto done;
- }
-
- if (sk->sk_type != SOCK_STREAM) {
- err = -EINVAL;
- goto done;
- }
-
- if (!rfcomm_pi(sk)->channel) {
- bdaddr_t *src = &bt_sk(sk)->src;
- u8 channel;
-
- err = -EINVAL;
-
- write_lock(&rfcomm_sk_list.lock);
-
- for (channel = 1; channel < 31; channel++)
- if (!__rfcomm_get_sock_by_addr(channel, src)) {
- rfcomm_pi(sk)->channel = channel;
- err = 0;
- break;
- }
-
- write_unlock(&rfcomm_sk_list.lock);
-
- if (err < 0)
- goto done;
- }
-
- sk->sk_max_ack_backlog = backlog;
- sk->sk_ack_backlog = 0;
- sk->sk_state = BT_LISTEN;
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct sock *sk = sock->sk, *nsk;
- long timeo;
- int err = 0;
-
- lock_sock(sk);
-
- if (sk->sk_type != SOCK_STREAM) {
- err = -EINVAL;
- goto done;
- }
-
- timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
-
- BT_DBG("sk %p timeo %ld", sk, timeo);
-
- /* Wait for an incoming connection. (wake-one). */
- add_wait_queue_exclusive(sk_sleep(sk), &wait);
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
- break;
- }
-
- nsk = bt_accept_dequeue(sk, newsock);
- if (nsk)
- break;
-
- if (!timeo) {
- err = -EAGAIN;
- break;
- }
-
- if (signal_pending(current)) {
- err = sock_intr_errno(timeo);
- break;
- }
-
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(sk), &wait);
-
- if (err)
- goto done;
-
- newsock->state = SS_CONNECTED;
-
- BT_DBG("new socket %p", nsk);
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
-{
- struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
- struct sock *sk = sock->sk;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- sa->rc_family = AF_BLUETOOTH;
- sa->rc_channel = rfcomm_pi(sk)->channel;
- if (peer)
- bacpy(&sa->rc_bdaddr, &bt_sk(sk)->dst);
- else
- bacpy(&sa->rc_bdaddr, &bt_sk(sk)->src);
-
- *len = sizeof(struct sockaddr_rc);
- return 0;
-}
-
-static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t len)
-{
- struct sock *sk = sock->sk;
- struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
- struct sk_buff *skb;
- int sent = 0;
-
- if (test_bit(RFCOMM_DEFER_SETUP, &d->flags))
- return -ENOTCONN;
-
- if (msg->msg_flags & MSG_OOB)
- return -EOPNOTSUPP;
-
- if (sk->sk_shutdown & SEND_SHUTDOWN)
- return -EPIPE;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- lock_sock(sk);
-
- while (len) {
- size_t size = min_t(size_t, len, d->mtu);
- int err;
-
- skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
- msg->msg_flags & MSG_DONTWAIT, &err);
- if (!skb) {
- if (sent == 0)
- sent = err;
- break;
- }
- skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
-
- err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
- if (err) {
- kfree_skb(skb);
- if (sent == 0)
- sent = err;
- break;
- }
-
- skb->priority = sk->sk_priority;
-
- err = rfcomm_dlc_send(d, skb);
- if (err < 0) {
- kfree_skb(skb);
- if (sent == 0)
- sent = err;
- break;
- }
-
- sent += size;
- len -= size;
- }
-
- release_sock(sk);
-
- return sent;
-}
-
-static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t size, int flags)
-{
- struct sock *sk = sock->sk;
- struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
- int len;
-
- if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
- rfcomm_dlc_accept(d);
- return 0;
- }
-
- len = bt_sock_stream_recvmsg(iocb, sock, msg, size, flags);
-
- lock_sock(sk);
- if (!(flags & MSG_PEEK) && len > 0)
- atomic_sub(len, &sk->sk_rmem_alloc);
-
- if (atomic_read(&sk->sk_rmem_alloc) <= (sk->sk_rcvbuf >> 2))
- rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
- release_sock(sk);
-
- return len;
-}
-
-static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
-{
- struct sock *sk = sock->sk;
- int err = 0;
- u32 opt;
-
- BT_DBG("sk %p", sk);
-
- lock_sock(sk);
-
- switch (optname) {
- case RFCOMM_LM:
- if (get_user(opt, (u32 __user *) optval)) {
- err = -EFAULT;
- break;
- }
-
- if (opt & RFCOMM_LM_AUTH)
- rfcomm_pi(sk)->sec_level = BT_SECURITY_LOW;
- if (opt & RFCOMM_LM_ENCRYPT)
- rfcomm_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
- if (opt & RFCOMM_LM_SECURE)
- rfcomm_pi(sk)->sec_level = BT_SECURITY_HIGH;
-
- rfcomm_pi(sk)->role_switch = (opt & RFCOMM_LM_MASTER);
- break;
-
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
- release_sock(sk);
- return err;
-}
-
-static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
-{
- struct sock *sk = sock->sk;
- struct bt_security sec;
- int err = 0;
- size_t len;
- u32 opt;
-
- BT_DBG("sk %p", sk);
-
- if (level == SOL_RFCOMM)
- return rfcomm_sock_setsockopt_old(sock, optname, optval, optlen);
-
- if (level != SOL_BLUETOOTH)
- return -ENOPROTOOPT;
-
- lock_sock(sk);
-
- switch (optname) {
- case BT_SECURITY:
- if (sk->sk_type != SOCK_STREAM) {
- err = -EINVAL;
- break;
- }
-
- sec.level = BT_SECURITY_LOW;
-
- len = min_t(unsigned int, sizeof(sec), optlen);
- if (copy_from_user((char *) &sec, optval, len)) {
- err = -EFAULT;
- break;
- }
-
- if (sec.level > BT_SECURITY_HIGH) {
- err = -EINVAL;
- break;
- }
-
- rfcomm_pi(sk)->sec_level = sec.level;
- break;
-
- case BT_DEFER_SETUP:
- if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
- err = -EINVAL;
- break;
- }
-
- if (get_user(opt, (u32 __user *) optval)) {
- err = -EFAULT;
- break;
- }
-
- bt_sk(sk)->defer_setup = opt;
- break;
-
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
- release_sock(sk);
- return err;
-}
-
-static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
-{
- struct sock *sk = sock->sk;
- struct rfcomm_conninfo cinfo;
- struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
- int len, err = 0;
- u32 opt;
-
- BT_DBG("sk %p", sk);
-
- if (get_user(len, optlen))
- return -EFAULT;
-
- lock_sock(sk);
-
- switch (optname) {
- case RFCOMM_LM:
- switch (rfcomm_pi(sk)->sec_level) {
- case BT_SECURITY_LOW:
- opt = RFCOMM_LM_AUTH;
- break;
- case BT_SECURITY_MEDIUM:
- opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
- break;
- case BT_SECURITY_HIGH:
- opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
- RFCOMM_LM_SECURE;
- break;
- default:
- opt = 0;
- break;
- }
-
- if (rfcomm_pi(sk)->role_switch)
- opt |= RFCOMM_LM_MASTER;
-
- if (put_user(opt, (u32 __user *) optval))
- err = -EFAULT;
- break;
-
- case RFCOMM_CONNINFO:
- if (sk->sk_state != BT_CONNECTED &&
- !rfcomm_pi(sk)->dlc->defer_setup) {
- err = -ENOTCONN;
- break;
- }
-
- memset(&cinfo, 0, sizeof(cinfo));
- cinfo.hci_handle = conn->hcon->handle;
- memcpy(cinfo.dev_class, conn->hcon->dev_class, 3);
-
- len = min_t(unsigned int, len, sizeof(cinfo));
- if (copy_to_user(optval, (char *) &cinfo, len))
- err = -EFAULT;
-
- break;
-
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
- release_sock(sk);
- return err;
-}
-
-static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
-{
- struct sock *sk = sock->sk;
- struct bt_security sec;
- int len, err = 0;
-
- BT_DBG("sk %p", sk);
-
- if (level == SOL_RFCOMM)
- return rfcomm_sock_getsockopt_old(sock, optname, optval, optlen);
-
- if (level != SOL_BLUETOOTH)
- return -ENOPROTOOPT;
-
- if (get_user(len, optlen))
- return -EFAULT;
-
- lock_sock(sk);
-
- switch (optname) {
- case BT_SECURITY:
- if (sk->sk_type != SOCK_STREAM) {
- err = -EINVAL;
- break;
- }
-
- sec.level = rfcomm_pi(sk)->sec_level;
-
- len = min_t(unsigned int, len, sizeof(sec));
- if (copy_to_user(optval, (char *) &sec, len))
- err = -EFAULT;
-
- break;
-
- case BT_DEFER_SETUP:
- if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
- err = -EINVAL;
- break;
- }
-
- if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval))
- err = -EFAULT;
-
- break;
-
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
- release_sock(sk);
- return err;
-}
-
-static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct sock *sk __maybe_unused = sock->sk;
- int err;
-
- BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg);
-
- err = bt_sock_ioctl(sock, cmd, arg);
-
- if (err == -ENOIOCTLCMD) {
-#ifdef CONFIG_BT_RFCOMM_TTY
- lock_sock(sk);
- err = rfcomm_dev_ioctl(sk, cmd, (void __user *) arg);
- release_sock(sk);
-#else
- err = -EOPNOTSUPP;
-#endif
- }
-
- return err;
-}
-
-static int rfcomm_sock_shutdown(struct socket *sock, int how)
-{
- struct sock *sk = sock->sk;
- int err = 0;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
- lock_sock(sk);
- if (!sk->sk_shutdown) {
- sk->sk_shutdown = SHUTDOWN_MASK;
- __rfcomm_sock_close(sk);
-
- if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
- err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
- }
- release_sock(sk);
- return err;
-}
-
-static int rfcomm_sock_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
- int err;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
- err = rfcomm_sock_shutdown(sock, 2);
-
- sock_orphan(sk);
- rfcomm_sock_kill(sk);
- return err;
-}
-
-/* ---- RFCOMM core layer callbacks ----
- *
- * called under rfcomm_lock()
- */
-int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d)
-{
- struct sock *sk, *parent;
- bdaddr_t src, dst;
- int result = 0;
-
- BT_DBG("session %p channel %d", s, channel);
-
- rfcomm_session_getaddr(s, &src, &dst);
-
- /* Check if we have socket listening on channel */
- parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src);
- if (!parent)
- return 0;
-
- bh_lock_sock(parent);
-
- /* Check for backlog size */
- if (sk_acceptq_is_full(parent)) {
- BT_DBG("backlog full %d", parent->sk_ack_backlog);
- goto done;
- }
-
- sk = rfcomm_sock_alloc(sock_net(parent), NULL, BTPROTO_RFCOMM, GFP_ATOMIC);
- if (!sk)
- goto done;
-
- bt_sock_reclassify_lock(sk, BTPROTO_RFCOMM);
-
- rfcomm_sock_init(sk, parent);
- bacpy(&bt_sk(sk)->src, &src);
- bacpy(&bt_sk(sk)->dst, &dst);
- rfcomm_pi(sk)->channel = channel;
-
- sk->sk_state = BT_CONFIG;
- bt_accept_enqueue(parent, sk);
-
- /* Accept connection and return socket DLC */
- *d = rfcomm_pi(sk)->dlc;
- result = 1;
-
-done:
- bh_unlock_sock(parent);
-
- if (bt_sk(parent)->defer_setup)
- parent->sk_state_change(parent);
-
- return result;
-}
-
-static int rfcomm_sock_debugfs_show(struct seq_file *f, void *p)
-{
- struct sock *sk;
- struct hlist_node *node;
-
- read_lock(&rfcomm_sk_list.lock);
-
- sk_for_each(sk, node, &rfcomm_sk_list.head) {
- seq_printf(f, "%s %s %d %d\n",
- batostr(&bt_sk(sk)->src),
- batostr(&bt_sk(sk)->dst),
- sk->sk_state, rfcomm_pi(sk)->channel);
- }
-
- read_unlock(&rfcomm_sk_list.lock);
-
- return 0;
-}
-
-static int rfcomm_sock_debugfs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, rfcomm_sock_debugfs_show, inode->i_private);
-}
-
-static const struct file_operations rfcomm_sock_debugfs_fops = {
- .open = rfcomm_sock_debugfs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static struct dentry *rfcomm_sock_debugfs;
-
-static const struct proto_ops rfcomm_sock_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .release = rfcomm_sock_release,
- .bind = rfcomm_sock_bind,
- .connect = rfcomm_sock_connect,
- .listen = rfcomm_sock_listen,
- .accept = rfcomm_sock_accept,
- .getname = rfcomm_sock_getname,
- .sendmsg = rfcomm_sock_sendmsg,
- .recvmsg = rfcomm_sock_recvmsg,
- .shutdown = rfcomm_sock_shutdown,
- .setsockopt = rfcomm_sock_setsockopt,
- .getsockopt = rfcomm_sock_getsockopt,
- .ioctl = rfcomm_sock_ioctl,
- .poll = bt_sock_poll,
- .socketpair = sock_no_socketpair,
- .mmap = sock_no_mmap
-};
-
-static const struct net_proto_family rfcomm_sock_family_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .create = rfcomm_sock_create
-};
-
-int __init rfcomm_init_sockets(void)
-{
- int err;
-
- err = proto_register(&rfcomm_proto, 0);
- if (err < 0)
- return err;
-
- err = bt_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops);
- if (err < 0)
- goto error;
-
- if (bt_debugfs) {
- rfcomm_sock_debugfs = debugfs_create_file("rfcomm", 0444,
- bt_debugfs, NULL, &rfcomm_sock_debugfs_fops);
- if (!rfcomm_sock_debugfs)
- BT_ERR("Failed to create RFCOMM debug file");
- }
-
- BT_INFO("RFCOMM socket layer initialized");
-
- return 0;
-
-error:
- BT_ERR("RFCOMM socket layer registration failed");
- proto_unregister(&rfcomm_proto);
- return err;
-}
-
-void __exit rfcomm_cleanup_sockets(void)
-{
- debugfs_remove(rfcomm_sock_debugfs);
-
- if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)
- BT_ERR("RFCOMM socket layer unregistration failed");
-
- proto_unregister(&rfcomm_proto);
-}
diff --git a/net/bluetooth_tizen/rfcomm/tty.c b/net/bluetooth_tizen/rfcomm/tty.c
deleted file mode 100644
index 4bf54b3..0000000
--- a/net/bluetooth_tizen/rfcomm/tty.c
+++ /dev/null
@@ -1,1188 +0,0 @@
-/*
- RFCOMM implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
- Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/*
- * RFCOMM TTY.
- */
-
-#include <linux/module.h>
-
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-
-#include <linux/capability.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/workqueue.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/rfcomm.h>
-
-#define RFCOMM_TTY_MAGIC 0x6d02 /* magic number for rfcomm struct */
-#define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV /* whole lotta rfcomm devices */
-#define RFCOMM_TTY_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */
-#define RFCOMM_TTY_MINOR 0
-
-static struct tty_driver *rfcomm_tty_driver;
-
-struct rfcomm_dev {
- struct list_head list;
- atomic_t refcnt;
-
- char name[12];
- int id;
- unsigned long flags;
- atomic_t opened;
- int err;
-
- bdaddr_t src;
- bdaddr_t dst;
- u8 channel;
-
- uint modem_status;
-
- struct rfcomm_dlc *dlc;
- struct tty_struct *tty;
- wait_queue_head_t wait;
- struct work_struct wakeup_task;
-
- struct device *tty_dev;
-
- atomic_t wmem_alloc;
-
- struct sk_buff_head pending;
-};
-
-static LIST_HEAD(rfcomm_dev_list);
-static DEFINE_SPINLOCK(rfcomm_dev_lock);
-
-static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
-static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
-static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
-
-static void rfcomm_tty_wakeup(struct work_struct *work);
-
-/* ---- Device functions ---- */
-static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
-{
- struct rfcomm_dlc *dlc = dev->dlc;
-
- BT_DBG("dev %p dlc %p", dev, dlc);
-
- /* Refcount should only hit zero when called from rfcomm_dev_del()
- which will have taken us off the list. Everything else are
- refcounting bugs. */
- BUG_ON(!list_empty(&dev->list));
-
- rfcomm_dlc_lock(dlc);
- /* Detach DLC if it's owned by this dev */
- if (dlc->owner == dev)
- dlc->owner = NULL;
- rfcomm_dlc_unlock(dlc);
-
- rfcomm_dlc_put(dlc);
-
- tty_unregister_device(rfcomm_tty_driver, dev->id);
-
- kfree(dev);
-
- /* It's safe to call module_put() here because socket still
- holds reference to this module. */
- module_put(THIS_MODULE);
-}
-
-static inline void rfcomm_dev_hold(struct rfcomm_dev *dev)
-{
- atomic_inc(&dev->refcnt);
-}
-
-static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
-{
- /* The reason this isn't actually a race, as you no
- doubt have a little voice screaming at you in your
- head, is that the refcount should never actually
- reach zero unless the device has already been taken
- off the list, in rfcomm_dev_del(). And if that's not
- true, we'll hit the BUG() in rfcomm_dev_destruct()
- anyway. */
- if (atomic_dec_and_test(&dev->refcnt))
- rfcomm_dev_destruct(dev);
-}
-
-static struct rfcomm_dev *__rfcomm_dev_get(int id)
-{
- struct rfcomm_dev *dev;
-
- list_for_each_entry(dev, &rfcomm_dev_list, list)
- if (dev->id == id)
- return dev;
-
- return NULL;
-}
-
-static inline struct rfcomm_dev *rfcomm_dev_get(int id)
-{
- struct rfcomm_dev *dev;
-
- spin_lock(&rfcomm_dev_lock);
-
- dev = __rfcomm_dev_get(id);
-
- if (dev) {
- if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
- dev = NULL;
- else
- rfcomm_dev_hold(dev);
- }
-
- spin_unlock(&rfcomm_dev_lock);
-
- return dev;
-}
-
-static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
-{
- struct hci_dev *hdev;
- struct hci_conn *conn;
-
- hdev = hci_get_route(&dev->dst, &dev->src);
- if (!hdev)
- return NULL;
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
-
- hci_dev_put(hdev);
-
- return conn ? &conn->dev : NULL;
-}
-
-static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
-{
- struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
- return sprintf(buf, "%s\n", batostr(&dev->dst));
-}
-
-static ssize_t show_channel(struct device *tty_dev, struct device_attribute *attr, char *buf)
-{
- struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
- return sprintf(buf, "%d\n", dev->channel);
-}
-
-static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
-static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
-
-static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
-{
- struct rfcomm_dev *dev, *entry;
- struct list_head *head = &rfcomm_dev_list;
- int err = 0;
-
- BT_DBG("id %d channel %d", req->dev_id, req->channel);
-
- dev = kzalloc(sizeof(struct rfcomm_dev), GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
-
- spin_lock(&rfcomm_dev_lock);
-
- if (req->dev_id < 0) {
- dev->id = 0;
-
- list_for_each_entry(entry, &rfcomm_dev_list, list) {
- if (entry->id != dev->id)
- break;
-
- dev->id++;
- head = &entry->list;
- }
- } else {
- dev->id = req->dev_id;
-
- list_for_each_entry(entry, &rfcomm_dev_list, list) {
- if (entry->id == dev->id) {
- err = -EADDRINUSE;
- goto out;
- }
-
- if (entry->id > dev->id - 1)
- break;
-
- head = &entry->list;
- }
- }
-
- if ((dev->id < 0) || (dev->id > RFCOMM_MAX_DEV - 1)) {
- err = -ENFILE;
- goto out;
- }
-
- sprintf(dev->name, "rfcomm%d", dev->id);
-
- list_add(&dev->list, head);
- atomic_set(&dev->refcnt, 1);
-
- bacpy(&dev->src, &req->src);
- bacpy(&dev->dst, &req->dst);
- dev->channel = req->channel;
-
- dev->flags = req->flags &
- ((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
-
- atomic_set(&dev->opened, 0);
-
- init_waitqueue_head(&dev->wait);
- INIT_WORK(&dev->wakeup_task, rfcomm_tty_wakeup);
-
- skb_queue_head_init(&dev->pending);
-
- rfcomm_dlc_lock(dlc);
-
- if (req->flags & (1 << RFCOMM_REUSE_DLC)) {
- struct sock *sk = dlc->owner;
- struct sk_buff *skb;
-
- BUG_ON(!sk);
-
- rfcomm_dlc_throttle(dlc);
-
- while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
- skb_orphan(skb);
- skb_queue_tail(&dev->pending, skb);
- atomic_sub(skb->len, &sk->sk_rmem_alloc);
- }
- }
-
- dlc->data_ready = rfcomm_dev_data_ready;
- dlc->state_change = rfcomm_dev_state_change;
- dlc->modem_status = rfcomm_dev_modem_status;
-
- dlc->owner = dev;
- dev->dlc = dlc;
-
- rfcomm_dev_modem_status(dlc, dlc->remote_v24_sig);
-
- rfcomm_dlc_unlock(dlc);
-
- /* It's safe to call __module_get() here because socket already
- holds reference to this module. */
- __module_get(THIS_MODULE);
-
-out:
- spin_unlock(&rfcomm_dev_lock);
-
- if (err < 0)
- goto free;
-
- dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL);
-
- if (IS_ERR(dev->tty_dev)) {
- err = PTR_ERR(dev->tty_dev);
- list_del(&dev->list);
- goto free;
- }
-
- dev_set_drvdata(dev->tty_dev, dev);
-
- if (device_create_file(dev->tty_dev, &dev_attr_address) < 0)
- BT_ERR("Failed to create address attribute");
-
- if (device_create_file(dev->tty_dev, &dev_attr_channel) < 0)
- BT_ERR("Failed to create channel attribute");
-
- return dev->id;
-
-free:
- kfree(dev);
- return err;
-}
-
-static void rfcomm_dev_del(struct rfcomm_dev *dev)
-{
- BT_DBG("dev %p", dev);
-
- BUG_ON(test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags));
-
- if (atomic_read(&dev->opened) > 0)
- return;
-
- spin_lock(&rfcomm_dev_lock);
- list_del_init(&dev->list);
- spin_unlock(&rfcomm_dev_lock);
-
- rfcomm_dev_put(dev);
-}
-
-/* ---- Send buffer ---- */
-static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
-{
- /* We can't let it be zero, because we don't get a callback
- when tx_credits becomes nonzero, hence we'd never wake up */
- return dlc->mtu * (dlc->tx_credits?:1);
-}
-
-static void rfcomm_wfree(struct sk_buff *skb)
-{
- struct rfcomm_dev *dev = (void *) skb->sk;
- atomic_sub(skb->truesize, &dev->wmem_alloc);
- if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
- queue_work(system_nrt_wq, &dev->wakeup_task);
- rfcomm_dev_put(dev);
-}
-
-static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
-{
- rfcomm_dev_hold(dev);
- atomic_add(skb->truesize, &dev->wmem_alloc);
- skb->sk = (void *) dev;
- skb->destructor = rfcomm_wfree;
-}
-
-static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, gfp_t priority)
-{
- if (atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) {
- struct sk_buff *skb = alloc_skb(size, priority);
- if (skb) {
- rfcomm_set_owner_w(skb, dev);
- return skb;
- }
- }
- return NULL;
-}
-
-/* ---- Device IOCTLs ---- */
-
-#define NOCAP_FLAGS ((1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP))
-
-static int rfcomm_create_dev(struct sock *sk, void __user *arg)
-{
- struct rfcomm_dev_req req;
- struct rfcomm_dlc *dlc;
- int id;
-
- if (copy_from_user(&req, arg, sizeof(req)))
- return -EFAULT;
-
- BT_DBG("sk %p dev_id %d flags 0x%x", sk, req.dev_id, req.flags);
-
- if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
- /* Socket must be connected */
- if (sk->sk_state != BT_CONNECTED)
- return -EBADFD;
-
- dlc = rfcomm_pi(sk)->dlc;
- rfcomm_dlc_hold(dlc);
- } else {
- dlc = rfcomm_dlc_alloc(GFP_KERNEL);
- if (!dlc)
- return -ENOMEM;
- }
-
- id = rfcomm_dev_add(&req, dlc);
- if (id < 0) {
- rfcomm_dlc_put(dlc);
- return id;
- }
-
- if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
- /* DLC is now used by device.
- * Socket must be disconnected */
- sk->sk_state = BT_CLOSED;
- }
-
- return id;
-}
-
-static int rfcomm_release_dev(void __user *arg)
-{
- struct rfcomm_dev_req req;
- struct rfcomm_dev *dev;
-
- if (copy_from_user(&req, arg, sizeof(req)))
- return -EFAULT;
-
- BT_DBG("dev_id %d flags 0x%x", req.dev_id, req.flags);
-
- dev = rfcomm_dev_get(req.dev_id);
- if (!dev)
- return -ENODEV;
-
- if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) {
- rfcomm_dev_put(dev);
- return -EPERM;
- }
-
- if (req.flags & (1 << RFCOMM_HANGUP_NOW))
- rfcomm_dlc_close(dev->dlc, 0);
-
- /* Shut down TTY synchronously before freeing rfcomm_dev */
- if (dev->tty)
- tty_vhangup(dev->tty);
-
- if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
- rfcomm_dev_del(dev);
- rfcomm_dev_put(dev);
- return 0;
-}
-
-static int rfcomm_get_dev_list(void __user *arg)
-{
- struct rfcomm_dev *dev;
- struct rfcomm_dev_list_req *dl;
- struct rfcomm_dev_info *di;
- int n = 0, size, err;
- u16 dev_num;
-
- BT_DBG("");
-
- if (get_user(dev_num, (u16 __user *) arg))
- return -EFAULT;
-
- if (!dev_num || dev_num > (PAGE_SIZE * 4) / sizeof(*di))
- return -EINVAL;
-
- size = sizeof(*dl) + dev_num * sizeof(*di);
-
- dl = kmalloc(size, GFP_KERNEL);
- if (!dl)
- return -ENOMEM;
-
- di = dl->dev_info;
-
- spin_lock(&rfcomm_dev_lock);
-
- list_for_each_entry(dev, &rfcomm_dev_list, list) {
- if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
- continue;
- (di + n)->id = dev->id;
- (di + n)->flags = dev->flags;
- (di + n)->state = dev->dlc->state;
- (di + n)->channel = dev->channel;
- bacpy(&(di + n)->src, &dev->src);
- bacpy(&(di + n)->dst, &dev->dst);
- if (++n >= dev_num)
- break;
- }
-
- spin_unlock(&rfcomm_dev_lock);
-
- dl->dev_num = n;
- size = sizeof(*dl) + n * sizeof(*di);
-
- err = copy_to_user(arg, dl, size);
- kfree(dl);
-
- return err ? -EFAULT : 0;
-}
-
-static int rfcomm_get_dev_info(void __user *arg)
-{
- struct rfcomm_dev *dev;
- struct rfcomm_dev_info di;
- int err = 0;
-
- BT_DBG("");
-
- if (copy_from_user(&di, arg, sizeof(di)))
- return -EFAULT;
-
- dev = rfcomm_dev_get(di.id);
- if (!dev)
- return -ENODEV;
-
- di.flags = dev->flags;
- di.channel = dev->channel;
- di.state = dev->dlc->state;
- bacpy(&di.src, &dev->src);
- bacpy(&di.dst, &dev->dst);
-
- if (copy_to_user(arg, &di, sizeof(di)))
- err = -EFAULT;
-
- rfcomm_dev_put(dev);
- return err;
-}
-
-int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
-{
- BT_DBG("cmd %d arg %p", cmd, arg);
-
- switch (cmd) {
- case RFCOMMCREATEDEV:
- return rfcomm_create_dev(sk, arg);
-
- case RFCOMMRELEASEDEV:
- return rfcomm_release_dev(arg);
-
- case RFCOMMGETDEVLIST:
- return rfcomm_get_dev_list(arg);
-
- case RFCOMMGETDEVINFO:
- return rfcomm_get_dev_info(arg);
- }
-
- return -EINVAL;
-}
-
-/* ---- DLC callbacks ---- */
-static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
-{
- struct rfcomm_dev *dev = dlc->owner;
- struct tty_struct *tty;
-
- if (!dev) {
- kfree_skb(skb);
- return;
- }
-
- tty = dev->tty;
- if (!tty || !skb_queue_empty(&dev->pending)) {
- skb_queue_tail(&dev->pending, skb);
- return;
- }
-
- BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len);
-
- tty_insert_flip_string(tty, skb->data, skb->len);
- tty_flip_buffer_push(tty);
-
- kfree_skb(skb);
-}
-
-static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
-{
- struct rfcomm_dev *dev = dlc->owner;
- if (!dev)
- return;
-
- BT_DBG("dlc %p dev %p err %d", dlc, dev, err);
-
- dev->err = err;
- wake_up_interruptible(&dev->wait);
-
- if (dlc->state == BT_CLOSED) {
- if (!dev->tty) {
- if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
- /* Drop DLC lock here to avoid deadlock
- * 1. rfcomm_dev_get will take rfcomm_dev_lock
- * but in rfcomm_dev_add there's lock order:
- * rfcomm_dev_lock -> dlc lock
- * 2. rfcomm_dev_put will deadlock if it's
- * the last reference
- */
- rfcomm_dlc_unlock(dlc);
- if (rfcomm_dev_get(dev->id) == NULL) {
- rfcomm_dlc_lock(dlc);
- return;
- }
-
- rfcomm_dev_del(dev);
- rfcomm_dev_put(dev);
- rfcomm_dlc_lock(dlc);
- }
- } else
- tty_hangup(dev->tty);
- }
-}
-
-static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
-{
- struct rfcomm_dev *dev = dlc->owner;
- if (!dev)
- return;
-
- BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
-
- if ((dev->modem_status & TIOCM_CD) && !(v24_sig & RFCOMM_V24_DV)) {
- if (dev->tty && !C_CLOCAL(dev->tty))
- tty_hangup(dev->tty);
- }
-
- dev->modem_status =
- ((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) |
- ((v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0) |
- ((v24_sig & RFCOMM_V24_IC) ? TIOCM_RI : 0) |
- ((v24_sig & RFCOMM_V24_DV) ? TIOCM_CD : 0);
-}
-
-/* ---- TTY functions ---- */
-static void rfcomm_tty_wakeup(struct work_struct *work)
-{
- struct rfcomm_dev *dev = container_of(work, struct rfcomm_dev,
- wakeup_task);
- struct tty_struct *tty = dev->tty;
- if (!tty)
- return;
-
- BT_DBG("dev %p tty %p", dev, tty);
- tty_wakeup(tty);
-}
-
-static void rfcomm_tty_copy_pending(struct rfcomm_dev *dev)
-{
- struct tty_struct *tty = dev->tty;
- struct sk_buff *skb;
- int inserted = 0;
-
- if (!tty)
- return;
-
- BT_DBG("dev %p tty %p", dev, tty);
-
- rfcomm_dlc_lock(dev->dlc);
-
- while ((skb = skb_dequeue(&dev->pending))) {
- inserted += tty_insert_flip_string(tty, skb->data, skb->len);
- kfree_skb(skb);
- }
-
- rfcomm_dlc_unlock(dev->dlc);
-
- if (inserted > 0)
- tty_flip_buffer_push(tty);
-}
-
-static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct rfcomm_dev *dev;
- struct rfcomm_dlc *dlc;
- int err, id;
-
- id = tty->index;
-
- BT_DBG("tty %p id %d", tty, id);
-
- /* We don't leak this refcount. For reasons which are not entirely
- clear, the TTY layer will call our ->close() method even if the
- open fails. We decrease the refcount there, and decreasing it
- here too would cause breakage. */
- dev = rfcomm_dev_get(id);
- if (!dev)
- return -ENODEV;
-
- BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst),
- dev->channel, atomic_read(&dev->opened));
-
- if (atomic_inc_return(&dev->opened) > 1)
- return 0;
-
- dlc = dev->dlc;
-
- /* Attach TTY and open DLC */
-
- rfcomm_dlc_lock(dlc);
- tty->driver_data = dev;
- dev->tty = tty;
- rfcomm_dlc_unlock(dlc);
- set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
-
- err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel);
- if (err < 0)
- return err;
-
- /* Wait for DLC to connect */
- add_wait_queue(&dev->wait, &wait);
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (dlc->state == BT_CLOSED) {
- err = -dev->err;
- break;
- }
-
- if (dlc->state == BT_CONNECTED)
- break;
-
- if (signal_pending(current)) {
- err = -EINTR;
- break;
- }
-
- tty_unlock();
- schedule();
- tty_lock();
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dev->wait, &wait);
-
- if (err == 0)
- device_move(dev->tty_dev, rfcomm_get_device(dev),
- DPM_ORDER_DEV_AFTER_PARENT);
-
- rfcomm_tty_copy_pending(dev);
-
- rfcomm_dlc_unthrottle(dev->dlc);
-
- return err;
-}
-
-static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
-{
- struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
- if (!dev)
- return;
-
- BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc,
- atomic_read(&dev->opened));
-
- if (atomic_dec_and_test(&dev->opened)) {
- if (dev->tty_dev->parent)
- device_move(dev->tty_dev, NULL, DPM_ORDER_DEV_LAST);
-
- /* Close DLC and dettach TTY */
- rfcomm_dlc_close(dev->dlc, 0);
-
- clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
- cancel_work_sync(&dev->wakeup_task);
-
- rfcomm_dlc_lock(dev->dlc);
- tty->driver_data = NULL;
- dev->tty = NULL;
- rfcomm_dlc_unlock(dev->dlc);
-
- if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) {
- spin_lock(&rfcomm_dev_lock);
- list_del_init(&dev->list);
- spin_unlock(&rfcomm_dev_lock);
-
- rfcomm_dev_put(dev);
- }
- }
-
- rfcomm_dev_put(dev);
-}
-
-static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
- struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
- struct rfcomm_dlc *dlc = dev->dlc;
- struct sk_buff *skb;
- int err = 0, sent = 0, size;
-
- BT_DBG("tty %p count %d", tty, count);
-
- while (count) {
- size = min_t(uint, count, dlc->mtu);
-
- skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_ATOMIC);
-
- if (!skb)
- break;
-
- skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
-
- memcpy(skb_put(skb, size), buf + sent, size);
-
- err = rfcomm_dlc_send(dlc, skb);
- if (err < 0) {
- kfree_skb(skb);
- break;
- }
-
- sent += size;
- count -= size;
- }
-
- return sent ? sent : err;
-}
-
-static int rfcomm_tty_write_room(struct tty_struct *tty)
-{
- struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
- int room;
-
- BT_DBG("tty %p", tty);
-
- if (!dev || !dev->dlc)
- return 0;
-
- room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc);
- if (room < 0)
- room = 0;
-
- return room;
-}
-
-static int rfcomm_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
-{
- BT_DBG("tty %p cmd 0x%02x", tty, cmd);
-
- switch (cmd) {
- case TCGETS:
- BT_DBG("TCGETS is not supported");
- return -ENOIOCTLCMD;
-
- case TCSETS:
- BT_DBG("TCSETS is not supported");
- return -ENOIOCTLCMD;
-
- case TIOCMIWAIT:
- BT_DBG("TIOCMIWAIT");
- break;
-
- case TIOCGSERIAL:
- BT_ERR("TIOCGSERIAL is not supported");
- return -ENOIOCTLCMD;
-
- case TIOCSSERIAL:
- BT_ERR("TIOCSSERIAL is not supported");
- return -ENOIOCTLCMD;
-
- case TIOCSERGSTRUCT:
- BT_ERR("TIOCSERGSTRUCT is not supported");
- return -ENOIOCTLCMD;
-
- case TIOCSERGETLSR:
- BT_ERR("TIOCSERGETLSR is not supported");
- return -ENOIOCTLCMD;
-
- case TIOCSERCONFIG:
- BT_ERR("TIOCSERCONFIG is not supported");
- return -ENOIOCTLCMD;
-
- default:
- return -ENOIOCTLCMD; /* ioctls which we must ignore */
-
- }
-
- return -ENOIOCTLCMD;
-}
-
-static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
- struct ktermios *new = tty->termios;
- int old_baud_rate = tty_termios_baud_rate(old);
- int new_baud_rate = tty_termios_baud_rate(new);
-
- u8 baud, data_bits, stop_bits, parity, x_on, x_off;
- u16 changes = 0;
-
- struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-
- BT_DBG("tty %p termios %p", tty, old);
-
- if (!dev || !dev->dlc || !dev->dlc->session)
- return;
-
- /* Handle turning off CRTSCTS */
- if ((old->c_cflag & CRTSCTS) && !(new->c_cflag & CRTSCTS))
- BT_DBG("Turning off CRTSCTS unsupported");
-
- /* Parity on/off and when on, odd/even */
- if (((old->c_cflag & PARENB) != (new->c_cflag & PARENB)) ||
- ((old->c_cflag & PARODD) != (new->c_cflag & PARODD))) {
- changes |= RFCOMM_RPN_PM_PARITY;
- BT_DBG("Parity change detected.");
- }
-
- /* Mark and space parity are not supported! */
- if (new->c_cflag & PARENB) {
- if (new->c_cflag & PARODD) {
- BT_DBG("Parity is ODD");
- parity = RFCOMM_RPN_PARITY_ODD;
- } else {
- BT_DBG("Parity is EVEN");
- parity = RFCOMM_RPN_PARITY_EVEN;
- }
- } else {
- BT_DBG("Parity is OFF");
- parity = RFCOMM_RPN_PARITY_NONE;
- }
-
- /* Setting the x_on / x_off characters */
- if (old->c_cc[VSTOP] != new->c_cc[VSTOP]) {
- BT_DBG("XOFF custom");
- x_on = new->c_cc[VSTOP];
- changes |= RFCOMM_RPN_PM_XON;
- } else {
- BT_DBG("XOFF default");
- x_on = RFCOMM_RPN_XON_CHAR;
- }
-
- if (old->c_cc[VSTART] != new->c_cc[VSTART]) {
- BT_DBG("XON custom");
- x_off = new->c_cc[VSTART];
- changes |= RFCOMM_RPN_PM_XOFF;
- } else {
- BT_DBG("XON default");
- x_off = RFCOMM_RPN_XOFF_CHAR;
- }
-
- /* Handle setting of stop bits */
- if ((old->c_cflag & CSTOPB) != (new->c_cflag & CSTOPB))
- changes |= RFCOMM_RPN_PM_STOP;
-
- /* POSIX does not support 1.5 stop bits and RFCOMM does not
- * support 2 stop bits. So a request for 2 stop bits gets
- * translated to 1.5 stop bits */
- if (new->c_cflag & CSTOPB)
- stop_bits = RFCOMM_RPN_STOP_15;
- else
- stop_bits = RFCOMM_RPN_STOP_1;
-
- /* Handle number of data bits [5-8] */
- if ((old->c_cflag & CSIZE) != (new->c_cflag & CSIZE))
- changes |= RFCOMM_RPN_PM_DATA;
-
- switch (new->c_cflag & CSIZE) {
- case CS5:
- data_bits = RFCOMM_RPN_DATA_5;
- break;
- case CS6:
- data_bits = RFCOMM_RPN_DATA_6;
- break;
- case CS7:
- data_bits = RFCOMM_RPN_DATA_7;
- break;
- case CS8:
- data_bits = RFCOMM_RPN_DATA_8;
- break;
- default:
- data_bits = RFCOMM_RPN_DATA_8;
- break;
- }
-
- /* Handle baudrate settings */
- if (old_baud_rate != new_baud_rate)
- changes |= RFCOMM_RPN_PM_BITRATE;
-
- switch (new_baud_rate) {
- case 2400:
- baud = RFCOMM_RPN_BR_2400;
- break;
- case 4800:
- baud = RFCOMM_RPN_BR_4800;
- break;
- case 7200:
- baud = RFCOMM_RPN_BR_7200;
- break;
- case 9600:
- baud = RFCOMM_RPN_BR_9600;
- break;
- case 19200:
- baud = RFCOMM_RPN_BR_19200;
- break;
- case 38400:
- baud = RFCOMM_RPN_BR_38400;
- break;
- case 57600:
- baud = RFCOMM_RPN_BR_57600;
- break;
- case 115200:
- baud = RFCOMM_RPN_BR_115200;
- break;
- case 230400:
- baud = RFCOMM_RPN_BR_230400;
- break;
- default:
- /* 9600 is standard accordinag to the RFCOMM specification */
- baud = RFCOMM_RPN_BR_9600;
- break;
-
- }
-
- if (changes)
- rfcomm_send_rpn(dev->dlc->session, 1, dev->dlc->dlci, baud,
- data_bits, stop_bits, parity,
- RFCOMM_RPN_FLOW_NONE, x_on, x_off, changes);
-}
-
-static void rfcomm_tty_throttle(struct tty_struct *tty)
-{
- struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-
- BT_DBG("tty %p dev %p", tty, dev);
-
- rfcomm_dlc_throttle(dev->dlc);
-}
-
-static void rfcomm_tty_unthrottle(struct tty_struct *tty)
-{
- struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-
- BT_DBG("tty %p dev %p", tty, dev);
-
- rfcomm_dlc_unthrottle(dev->dlc);
-}
-
-static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty)
-{
- struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-
- BT_DBG("tty %p dev %p", tty, dev);
-
- if (!dev || !dev->dlc)
- return 0;
-
- if (!skb_queue_empty(&dev->dlc->tx_queue))
- return dev->dlc->mtu;
-
- return 0;
-}
-
-static void rfcomm_tty_flush_buffer(struct tty_struct *tty)
-{
- struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-
- BT_DBG("tty %p dev %p", tty, dev);
-
- if (!dev || !dev->dlc)
- return;
-
- skb_queue_purge(&dev->dlc->tx_queue);
- tty_wakeup(tty);
-}
-
-static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch)
-{
- BT_DBG("tty %p ch %c", tty, ch);
-}
-
-static void rfcomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
-{
- BT_DBG("tty %p timeout %d", tty, timeout);
-}
-
-static void rfcomm_tty_hangup(struct tty_struct *tty)
-{
- struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-
- BT_DBG("tty %p dev %p", tty, dev);
-
- if (!dev)
- return;
-
- rfcomm_tty_flush_buffer(tty);
-
- if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
- if (rfcomm_dev_get(dev->id) == NULL)
- return;
- rfcomm_dev_del(dev);
- rfcomm_dev_put(dev);
- }
-}
-
-static int rfcomm_tty_tiocmget(struct tty_struct *tty)
-{
- struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-
- BT_DBG("tty %p dev %p", tty, dev);
-
- return dev->modem_status;
-}
-
-static int rfcomm_tty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
-{
- struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
- struct rfcomm_dlc *dlc = dev->dlc;
- u8 v24_sig;
-
- BT_DBG("tty %p dev %p set 0x%02x clear 0x%02x", tty, dev, set, clear);
-
- rfcomm_dlc_get_modem_status(dlc, &v24_sig);
-
- if (set & TIOCM_DSR || set & TIOCM_DTR)
- v24_sig |= RFCOMM_V24_RTC;
- if (set & TIOCM_RTS || set & TIOCM_CTS)
- v24_sig |= RFCOMM_V24_RTR;
- if (set & TIOCM_RI)
- v24_sig |= RFCOMM_V24_IC;
- if (set & TIOCM_CD)
- v24_sig |= RFCOMM_V24_DV;
-
- if (clear & TIOCM_DSR || clear & TIOCM_DTR)
- v24_sig &= ~RFCOMM_V24_RTC;
- if (clear & TIOCM_RTS || clear & TIOCM_CTS)
- v24_sig &= ~RFCOMM_V24_RTR;
- if (clear & TIOCM_RI)
- v24_sig &= ~RFCOMM_V24_IC;
- if (clear & TIOCM_CD)
- v24_sig &= ~RFCOMM_V24_DV;
-
- rfcomm_dlc_set_modem_status(dlc, v24_sig);
-
- return 0;
-}
-
-/* ---- TTY structure ---- */
-
-static const struct tty_operations rfcomm_ops = {
- .open = rfcomm_tty_open,
- .close = rfcomm_tty_close,
- .write = rfcomm_tty_write,
- .write_room = rfcomm_tty_write_room,
- .chars_in_buffer = rfcomm_tty_chars_in_buffer,
- .flush_buffer = rfcomm_tty_flush_buffer,
- .ioctl = rfcomm_tty_ioctl,
- .throttle = rfcomm_tty_throttle,
- .unthrottle = rfcomm_tty_unthrottle,
- .set_termios = rfcomm_tty_set_termios,
- .send_xchar = rfcomm_tty_send_xchar,
- .hangup = rfcomm_tty_hangup,
- .wait_until_sent = rfcomm_tty_wait_until_sent,
- .tiocmget = rfcomm_tty_tiocmget,
- .tiocmset = rfcomm_tty_tiocmset,
-};
-
-int __init rfcomm_init_ttys(void)
-{
- int error;
-
- rfcomm_tty_driver = alloc_tty_driver(RFCOMM_TTY_PORTS);
- if (!rfcomm_tty_driver)
- return -ENOMEM;
-
- rfcomm_tty_driver->driver_name = "rfcomm";
- rfcomm_tty_driver->name = "rfcomm";
- rfcomm_tty_driver->major = RFCOMM_TTY_MAJOR;
- rfcomm_tty_driver->minor_start = RFCOMM_TTY_MINOR;
- rfcomm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
- rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
- rfcomm_tty_driver->init_termios = tty_std_termios;
- rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON;
- tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
-
- error = tty_register_driver(rfcomm_tty_driver);
- if (error) {
- BT_ERR("Can't register RFCOMM TTY driver");
- put_tty_driver(rfcomm_tty_driver);
- return error;
- }
-
- BT_INFO("RFCOMM TTY layer initialized");
-
- return 0;
-}
-
-void rfcomm_cleanup_ttys(void)
-{
- tty_unregister_driver(rfcomm_tty_driver);
- put_tty_driver(rfcomm_tty_driver);
-}
diff --git a/net/bluetooth_tizen/sco.c b/net/bluetooth_tizen/sco.c
deleted file mode 100644
index 8bf26d1..0000000
--- a/net/bluetooth_tizen/sco.c
+++ /dev/null
@@ -1,1061 +0,0 @@
-/*
- BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
-
- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/* Bluetooth SCO sockets. */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/socket.h>
-#include <linux/skbuff.h>
-#include <linux/device.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/list.h>
-#include <linux/security.h>
-#include <net/sock.h>
-
-#include <asm/system.h>
-#include <linux/uaccess.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/sco.h>
-
-static bool disable_esco;
-
-static const struct proto_ops sco_sock_ops;
-
-static struct bt_sock_list sco_sk_list = {
- .lock = __RW_LOCK_UNLOCKED(sco_sk_list.lock)
-};
-
-static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
-static void sco_chan_del(struct sock *sk, int err);
-
-static int sco_conn_del(struct hci_conn *conn, int err);
-
-static void sco_sock_close(struct sock *sk);
-static void sco_sock_kill(struct sock *sk);
-
-/* ---- SCO timers ---- */
-static void sco_sock_timeout(unsigned long arg)
-{
- struct sock *sk = (struct sock *) arg;
-
- BT_DBG("sock %p state %d", sk, sk->sk_state);
-
- bh_lock_sock(sk);
- sk->sk_err = ETIMEDOUT;
- sk->sk_state_change(sk);
- bh_unlock_sock(sk);
-
- sco_sock_kill(sk);
- sock_put(sk);
-}
-
-static void sco_sock_set_timer(struct sock *sk, long timeout)
-{
- BT_DBG("sock %p state %d timeout %ld", sk, sk->sk_state, timeout);
- sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout);
-}
-
-static void sco_sock_clear_timer(struct sock *sk)
-{
- BT_DBG("sock %p state %d", sk, sk->sk_state);
- sk_stop_timer(sk, &sk->sk_timer);
-}
-
-/* ---- SCO connections ---- */
-static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status)
-{
- struct hci_dev *hdev = hcon->hdev;
- struct sco_conn *conn = hcon->sco_data;
-
- if (conn || status)
- return conn;
-
- conn = kzalloc(sizeof(struct sco_conn), GFP_ATOMIC);
- if (!conn)
- return NULL;
-
- spin_lock_init(&conn->lock);
-
- hcon->sco_data = conn;
- conn->hcon = hcon;
-
- conn->src = &hdev->bdaddr;
- conn->dst = &hcon->dst;
-
- if (hdev->sco_mtu > 0)
- conn->mtu = hdev->sco_mtu;
- else
- conn->mtu = 60;
-
- BT_DBG("hcon %p conn %p", hcon, conn);
-
- return conn;
-}
-
-static inline struct sock *sco_chan_get(struct sco_conn *conn)
-{
- struct sock *sk = NULL;
- sco_conn_lock(conn);
- sk = conn->sk;
- sco_conn_unlock(conn);
- return sk;
-}
-
-static int sco_conn_del(struct hci_conn *hcon, int err)
-{
- struct sco_conn *conn = hcon->sco_data;
- struct sock *sk;
-
- if (!conn)
- return 0;
-
- BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
-
- /* Kill socket */
- sk = sco_chan_get(conn);
- if (sk) {
- bh_lock_sock(sk);
- sco_sock_clear_timer(sk);
- sco_chan_del(sk, err);
- bh_unlock_sock(sk);
- sco_sock_kill(sk);
- }
-
- hcon->sco_data = NULL;
- kfree(conn);
- return 0;
-}
-
-static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
-{
- int err = 0;
-
- sco_conn_lock(conn);
- if (conn->sk)
- err = -EBUSY;
- else
- __sco_chan_add(conn, sk, parent);
-
- sco_conn_unlock(conn);
- return err;
-}
-
-static int sco_connect(struct sock *sk)
-{
- bdaddr_t *src = &bt_sk(sk)->src;
- bdaddr_t *dst = &bt_sk(sk)->dst;
- struct sco_conn *conn;
- struct hci_conn *hcon;
- struct hci_dev *hdev;
- int err, type;
-
- BT_DBG("%s -> %s", batostr(src), batostr(dst));
-
- hdev = hci_get_route(dst, src);
- if (!hdev)
- return -EHOSTUNREACH;
-
- hci_dev_lock(hdev);
-
- if (lmp_esco_capable(hdev) && !disable_esco)
- type = ESCO_LINK;
- else
- type = SCO_LINK;
-
- hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING);
- if (IS_ERR(hcon)) {
- err = PTR_ERR(hcon);
- goto done;
- }
-
- conn = sco_conn_add(hcon, 0);
- if (!conn) {
- hci_conn_put(hcon);
- err = -ENOMEM;
- goto done;
- }
-
- /* Update source addr of the socket */
- bacpy(src, conn->src);
-
- err = sco_chan_add(conn, sk, NULL);
- if (err)
- goto done;
-
- if (hcon->state == BT_CONNECTED) {
- sco_sock_clear_timer(sk);
- sk->sk_state = BT_CONNECTED;
- } else {
- sk->sk_state = BT_CONNECT;
- sco_sock_set_timer(sk, sk->sk_sndtimeo);
- }
-
-done:
- hci_dev_unlock(hdev);
- hci_dev_put(hdev);
- return err;
-}
-
-static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
-{
- struct sco_conn *conn = sco_pi(sk)->conn;
- struct sk_buff *skb;
- int err, count;
-
- /* Check outgoing MTU */
- if (len > conn->mtu)
- return -EINVAL;
-
- BT_DBG("sk %p len %d", sk, len);
-
- count = min_t(unsigned int, conn->mtu, len);
- skb = bt_skb_send_alloc(sk, count,
- msg->msg_flags & MSG_DONTWAIT, &err);
- if (!skb)
- return err;
-
- if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
- kfree_skb(skb);
- return -EFAULT;
- }
-
- hci_send_sco(conn->hcon, skb);
-
- return count;
-}
-
-static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
-{
- struct sock *sk = sco_chan_get(conn);
-
- if (!sk)
- goto drop;
-
- BT_DBG("sk %p len %d", sk, skb->len);
-
- if (sk->sk_state != BT_CONNECTED)
- goto drop;
-
- if (!sock_queue_rcv_skb(sk, skb))
- return;
-
-drop:
- kfree_skb(skb);
-}
-
-/* -------- Socket interface ---------- */
-static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba)
-{
- struct sock *sk;
- struct hlist_node *node;
-
- sk_for_each(sk, node, &sco_sk_list.head)
- if (!bacmp(&bt_sk(sk)->src, ba))
- goto found;
- sk = NULL;
-found:
- return sk;
-}
-
-/* Find socket listening on source bdaddr.
- * Returns closest match.
- */
-static struct sock *sco_get_sock_listen(bdaddr_t *src)
-{
- struct sock *sk = NULL, *sk1 = NULL;
- struct hlist_node *node;
-
- read_lock(&sco_sk_list.lock);
-
- sk_for_each(sk, node, &sco_sk_list.head) {
- if (sk->sk_state != BT_LISTEN)
- continue;
-
- /* Exact match. */
- if (!bacmp(&bt_sk(sk)->src, src))
- break;
-
- /* Closest match */
- if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
- sk1 = sk;
- }
-
- read_unlock(&sco_sk_list.lock);
-
- return node ? sk : sk1;
-}
-
-static void sco_sock_destruct(struct sock *sk)
-{
- BT_DBG("sk %p", sk);
-
- skb_queue_purge(&sk->sk_receive_queue);
- skb_queue_purge(&sk->sk_write_queue);
-}
-
-static void sco_sock_cleanup_listen(struct sock *parent)
-{
- struct sock *sk;
-
- BT_DBG("parent %p", parent);
-
- /* Close not yet accepted channels */
- while ((sk = bt_accept_dequeue(parent, NULL))) {
- sco_sock_close(sk);
- sco_sock_kill(sk);
- }
-
- parent->sk_state = BT_CLOSED;
- sock_set_flag(parent, SOCK_ZAPPED);
-}
-
-/* Kill socket (only if zapped and orphan)
- * Must be called on unlocked socket.
- */
-static void sco_sock_kill(struct sock *sk)
-{
- if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
- return;
-
- BT_DBG("sk %p state %d", sk, sk->sk_state);
-
- /* Kill poor orphan */
- bt_sock_unlink(&sco_sk_list, sk);
- sock_set_flag(sk, SOCK_DEAD);
- sock_put(sk);
-}
-
-static void __sco_sock_close(struct sock *sk)
-{
- BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
-
- switch (sk->sk_state) {
- case BT_LISTEN:
- sco_sock_cleanup_listen(sk);
- break;
-
- case BT_CONNECTED:
- case BT_CONFIG:
- if (sco_pi(sk)->conn) {
- sk->sk_state = BT_DISCONN;
- sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
- hci_conn_put(sco_pi(sk)->conn->hcon);
- sco_pi(sk)->conn->hcon = NULL;
- } else
- sco_chan_del(sk, ECONNRESET);
- break;
-
- case BT_CONNECT:
- case BT_DISCONN:
- sco_chan_del(sk, ECONNRESET);
- break;
-
- default:
- sock_set_flag(sk, SOCK_ZAPPED);
- break;
- }
-}
-
-/* Must be called on unlocked socket. */
-static void sco_sock_close(struct sock *sk)
-{
- sco_sock_clear_timer(sk);
- lock_sock(sk);
- __sco_sock_close(sk);
- release_sock(sk);
- sco_sock_kill(sk);
-}
-
-static void sco_sock_init(struct sock *sk, struct sock *parent)
-{
- BT_DBG("sk %p", sk);
-
- if (parent) {
- sk->sk_type = parent->sk_type;
- security_sk_clone(parent, sk);
- }
-}
-
-static struct proto sco_proto = {
- .name = "SCO",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct sco_pinfo)
-};
-
-static struct sock *sco_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
-{
- struct sock *sk;
-
- sk = sk_alloc(net, PF_BLUETOOTH, prio, &sco_proto);
- if (!sk)
- return NULL;
-
- sock_init_data(sock, sk);
- INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
-
- sk->sk_destruct = sco_sock_destruct;
- sk->sk_sndtimeo = SCO_CONN_TIMEOUT;
-
- sock_reset_flag(sk, SOCK_ZAPPED);
-
- sk->sk_protocol = proto;
- sk->sk_state = BT_OPEN;
-
- setup_timer(&sk->sk_timer, sco_sock_timeout, (unsigned long)sk);
-
- bt_sock_link(&sco_sk_list, sk);
- return sk;
-}
-
-static int sco_sock_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
-
- BT_DBG("sock %p", sock);
-
- sock->state = SS_UNCONNECTED;
-
- if (sock->type != SOCK_SEQPACKET)
- return -ESOCKTNOSUPPORT;
-
- sock->ops = &sco_sock_ops;
-
- sk = sco_sock_alloc(net, sock, protocol, GFP_ATOMIC);
- if (!sk)
- return -ENOMEM;
-
- sco_sock_init(sk, NULL);
- return 0;
-}
-
-static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
-{
- struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
- struct sock *sk = sock->sk;
- bdaddr_t *src = &sa->sco_bdaddr;
- int err = 0;
-
- BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));
-
- if (!addr || addr->sa_family != AF_BLUETOOTH)
- return -EINVAL;
-
- lock_sock(sk);
-
- if (sk->sk_state != BT_OPEN) {
- err = -EBADFD;
- goto done;
- }
-
- write_lock(&sco_sk_list.lock);
-
- if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) {
- err = -EADDRINUSE;
- } else {
- /* Save source address */
- bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr);
- sk->sk_state = BT_BOUND;
- }
-
- write_unlock(&sco_sk_list.lock);
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
-{
- struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
- struct sock *sk = sock->sk;
- int err = 0;
-
-
- BT_DBG("sk %p", sk);
-
- if (alen < sizeof(struct sockaddr_sco) ||
- addr->sa_family != AF_BLUETOOTH)
- return -EINVAL;
-
- if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
- return -EBADFD;
-
- if (sk->sk_type != SOCK_SEQPACKET)
- return -EINVAL;
-
- lock_sock(sk);
-
- /* Set destination address and psm */
- bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr);
-
- err = sco_connect(sk);
- if (err)
- goto done;
-
- err = bt_sock_wait_state(sk, BT_CONNECTED,
- sock_sndtimeo(sk, flags & O_NONBLOCK));
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int sco_sock_listen(struct socket *sock, int backlog)
-{
- struct sock *sk = sock->sk;
- int err = 0;
-
- BT_DBG("sk %p backlog %d", sk, backlog);
-
- lock_sock(sk);
-
- if (sk->sk_state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
- err = -EBADFD;
- goto done;
- }
-
- sk->sk_max_ack_backlog = backlog;
- sk->sk_ack_backlog = 0;
- sk->sk_state = BT_LISTEN;
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct sock *sk = sock->sk, *ch;
- long timeo;
- int err = 0;
-
- lock_sock(sk);
-
- timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
-
- BT_DBG("sk %p timeo %ld", sk, timeo);
-
- /* Wait for an incoming connection. (wake-one). */
- add_wait_queue_exclusive(sk_sleep(sk), &wait);
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
- break;
- }
-
- ch = bt_accept_dequeue(sk, newsock);
- if (ch)
- break;
-
- if (!timeo) {
- err = -EAGAIN;
- break;
- }
-
- if (signal_pending(current)) {
- err = sock_intr_errno(timeo);
- break;
- }
-
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(sk), &wait);
-
- if (err)
- goto done;
-
- newsock->state = SS_CONNECTED;
-
- BT_DBG("new socket %p", ch);
-
-done:
- release_sock(sk);
- return err;
-}
-
-static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
-{
- struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
- struct sock *sk = sock->sk;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- addr->sa_family = AF_BLUETOOTH;
- *len = sizeof(struct sockaddr_sco);
-
- if (peer)
- bacpy(&sa->sco_bdaddr, &bt_sk(sk)->dst);
- else
- bacpy(&sa->sco_bdaddr, &bt_sk(sk)->src);
-
- return 0;
-}
-
-static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t len)
-{
- struct sock *sk = sock->sk;
- int err;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- err = sock_error(sk);
- if (err)
- return err;
-
- if (msg->msg_flags & MSG_OOB)
- return -EOPNOTSUPP;
-
- lock_sock(sk);
-
- if (sk->sk_state == BT_CONNECTED)
- err = sco_send_frame(sk, msg, len);
- else
- err = -ENOTCONN;
-
- release_sock(sk);
- return err;
-}
-
-static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
-{
- struct sock *sk = sock->sk;
- int err = 0;
-
- BT_DBG("sk %p", sk);
-
- lock_sock(sk);
-
- switch (optname) {
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
- release_sock(sk);
- return err;
-}
-
-static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
-{
- struct sock *sk = sock->sk;
- struct sco_options opts;
- struct sco_conninfo cinfo;
- int len, err = 0;
-
- BT_DBG("sk %p", sk);
-
- if (get_user(len, optlen))
- return -EFAULT;
-
- lock_sock(sk);
-
- switch (optname) {
- case SCO_OPTIONS:
- if (sk->sk_state != BT_CONNECTED) {
- err = -ENOTCONN;
- break;
- }
-
- opts.mtu = sco_pi(sk)->conn->mtu;
-
- BT_DBG("mtu %d", opts.mtu);
-
- len = min_t(unsigned int, len, sizeof(opts));
- if (copy_to_user(optval, (char *)&opts, len))
- err = -EFAULT;
-
- break;
-
- case SCO_CONNINFO:
- if (sk->sk_state != BT_CONNECTED) {
- err = -ENOTCONN;
- break;
- }
-
- memset(&cinfo, 0, sizeof(cinfo));
- cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
- memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
-
- len = min_t(unsigned int, len, sizeof(cinfo));
- if (copy_to_user(optval, (char *)&cinfo, len))
- err = -EFAULT;
-
- break;
-
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
- release_sock(sk);
- return err;
-}
-
-static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
-{
- struct sock *sk = sock->sk;
- int len, err = 0;
-
- BT_DBG("sk %p", sk);
-
- if (level == SOL_SCO)
- return sco_sock_getsockopt_old(sock, optname, optval, optlen);
-
- if (get_user(len, optlen))
- return -EFAULT;
-
- lock_sock(sk);
-
- switch (optname) {
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
- release_sock(sk);
- return err;
-}
-
-static int sco_sock_shutdown(struct socket *sock, int how)
-{
- struct sock *sk = sock->sk;
- int err = 0;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
- lock_sock(sk);
- if (!sk->sk_shutdown) {
- sk->sk_shutdown = SHUTDOWN_MASK;
- sco_sock_clear_timer(sk);
- __sco_sock_close(sk);
-
- if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
- err = bt_sock_wait_state(sk, BT_CLOSED,
- sk->sk_lingertime);
- }
- release_sock(sk);
- return err;
-}
-
-static int sco_sock_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
- int err = 0;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
- sco_sock_close(sk);
-
- if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) {
- lock_sock(sk);
- err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
- release_sock(sk);
- }
-
- sock_orphan(sk);
- sco_sock_kill(sk);
- return err;
-}
-
-static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
-{
- BT_DBG("conn %p", conn);
-
- sco_pi(sk)->conn = conn;
- conn->sk = sk;
-
- if (parent)
- bt_accept_enqueue(parent, sk);
-}
-
-/* Delete channel.
- * Must be called on the locked socket. */
-static void sco_chan_del(struct sock *sk, int err)
-{
- struct sco_conn *conn;
-
- conn = sco_pi(sk)->conn;
-
- BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
-
- if (conn) {
- sco_conn_lock(conn);
- conn->sk = NULL;
- sco_pi(sk)->conn = NULL;
- sco_conn_unlock(conn);
-
- if (conn->hcon)
- hci_conn_put(conn->hcon);
- }
-
- sk->sk_state = BT_CLOSED;
- sk->sk_err = err;
- sk->sk_state_change(sk);
-
- sock_set_flag(sk, SOCK_ZAPPED);
-}
-
-static void sco_conn_ready(struct sco_conn *conn)
-{
- struct sock *parent;
- struct sock *sk = conn->sk;
-
- BT_DBG("conn %p", conn);
-
- sco_conn_lock(conn);
-
- if (sk) {
- sco_sock_clear_timer(sk);
- bh_lock_sock(sk);
- sk->sk_state = BT_CONNECTED;
- sk->sk_state_change(sk);
- bh_unlock_sock(sk);
- } else {
- parent = sco_get_sock_listen(conn->src);
- if (!parent)
- goto done;
-
- bh_lock_sock(parent);
-
- sk = sco_sock_alloc(sock_net(parent), NULL,
- BTPROTO_SCO, GFP_ATOMIC);
- if (!sk) {
- bh_unlock_sock(parent);
- goto done;
- }
-
- sco_sock_init(sk, parent);
-
- bacpy(&bt_sk(sk)->src, conn->src);
- bacpy(&bt_sk(sk)->dst, conn->dst);
-
- hci_conn_hold(conn->hcon);
- __sco_chan_add(conn, sk, parent);
-
- sk->sk_state = BT_CONNECTED;
-
- /* Wake up parent */
- parent->sk_data_ready(parent, 1);
-
- bh_unlock_sock(parent);
- }
-
-done:
- sco_conn_unlock(conn);
-}
-
-/* ----- SCO interface with lower layer (HCI) ----- */
-int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- register struct sock *sk;
- struct hlist_node *node;
- int lm = 0;
-
- BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
-
- /* Find listening sockets */
- read_lock(&sco_sk_list.lock);
- sk_for_each(sk, node, &sco_sk_list.head) {
- if (sk->sk_state != BT_LISTEN)
- continue;
-
- if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) ||
- !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
- lm |= HCI_LM_ACCEPT;
- break;
- }
- }
- read_unlock(&sco_sk_list.lock);
-
- return lm;
-}
-
-int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
-{
- BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
- if (!status) {
- struct sco_conn *conn;
-
- conn = sco_conn_add(hcon, status);
- if (conn)
- sco_conn_ready(conn);
- } else
- sco_conn_del(hcon, bt_to_errno(status));
-
- return 0;
-}
-
-int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
-{
- BT_DBG("hcon %p reason %d", hcon, reason);
-
- sco_conn_del(hcon, bt_to_errno(reason));
- return 0;
-}
-
-int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
-{
- struct sco_conn *conn = hcon->sco_data;
-
- if (!conn)
- goto drop;
-
- BT_DBG("conn %p len %d", conn, skb->len);
-
- if (skb->len) {
- sco_recv_frame(conn, skb);
- return 0;
- }
-
-drop:
- kfree_skb(skb);
- return 0;
-}
-
-static int sco_debugfs_show(struct seq_file *f, void *p)
-{
- struct sock *sk;
- struct hlist_node *node;
-
- read_lock(&sco_sk_list.lock);
-
- sk_for_each(sk, node, &sco_sk_list.head) {
- seq_printf(f, "%s %s %d\n", batostr(&bt_sk(sk)->src),
- batostr(&bt_sk(sk)->dst), sk->sk_state);
- }
-
- read_unlock(&sco_sk_list.lock);
-
- return 0;
-}
-
-static int sco_debugfs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, sco_debugfs_show, inode->i_private);
-}
-
-static const struct file_operations sco_debugfs_fops = {
- .open = sco_debugfs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static struct dentry *sco_debugfs;
-
-static const struct proto_ops sco_sock_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .release = sco_sock_release,
- .bind = sco_sock_bind,
- .connect = sco_sock_connect,
- .listen = sco_sock_listen,
- .accept = sco_sock_accept,
- .getname = sco_sock_getname,
- .sendmsg = sco_sock_sendmsg,
- .recvmsg = bt_sock_recvmsg,
- .poll = bt_sock_poll,
- .ioctl = bt_sock_ioctl,
- .mmap = sock_no_mmap,
- .socketpair = sock_no_socketpair,
- .shutdown = sco_sock_shutdown,
- .setsockopt = sco_sock_setsockopt,
- .getsockopt = sco_sock_getsockopt
-};
-
-static const struct net_proto_family sco_sock_family_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .create = sco_sock_create,
-};
-
-int __init sco_init(void)
-{
- int err;
-
- err = proto_register(&sco_proto, 0);
- if (err < 0)
- return err;
-
- err = bt_sock_register(BTPROTO_SCO, &sco_sock_family_ops);
- if (err < 0) {
- BT_ERR("SCO socket registration failed");
- goto error;
- }
-
- if (bt_debugfs) {
- sco_debugfs = debugfs_create_file("sco", 0444,
- bt_debugfs, NULL, &sco_debugfs_fops);
- if (!sco_debugfs)
- BT_ERR("Failed to create SCO debug file");
- }
-
- BT_INFO("SCO socket layer initialized");
-
- return 0;
-
-error:
- proto_unregister(&sco_proto);
- return err;
-}
-
-void __exit sco_exit(void)
-{
- debugfs_remove(sco_debugfs);
-
- if (bt_sock_unregister(BTPROTO_SCO) < 0)
- BT_ERR("SCO socket unregistration failed");
-
- proto_unregister(&sco_proto);
-}
-
-module_param(disable_esco, bool, 0644);
-MODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation");
diff --git a/net/bluetooth_tizen/smp.c b/net/bluetooth_tizen/smp.c
deleted file mode 100644
index deb1198..0000000
--- a/net/bluetooth_tizen/smp.c
+++ /dev/null
@@ -1,1003 +0,0 @@
-/*
- BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/l2cap.h>
-#include <net/bluetooth/mgmt.h>
-#include <net/bluetooth/smp.h>
-#include <linux/crypto.h>
-#include <linux/scatterlist.h>
-#include <crypto/b128ops.h>
-
-#define SMP_TIMEOUT msecs_to_jiffies(30000)
-
-static inline void swap128(u8 src[16], u8 dst[16])
-{
- int i;
- for (i = 0; i < 16; i++)
- dst[15 - i] = src[i];
-}
-
-static inline void swap56(u8 src[7], u8 dst[7])
-{
- int i;
- for (i = 0; i < 7; i++)
- dst[6 - i] = src[i];
-}
-
-static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
-{
- struct blkcipher_desc desc;
- struct scatterlist sg;
- int err, iv_len;
- unsigned char iv[128];
-
- if (tfm == NULL) {
- BT_ERR("tfm %p", tfm);
- return -EINVAL;
- }
-
- desc.tfm = tfm;
- desc.flags = 0;
-
- err = crypto_blkcipher_setkey(tfm, k, 16);
- if (err) {
- BT_ERR("cipher setkey failed: %d", err);
- return err;
- }
-
- sg_init_one(&sg, r, 16);
-
- iv_len = crypto_blkcipher_ivsize(tfm);
- if (iv_len) {
- memset(&iv, 0xff, iv_len);
- crypto_blkcipher_set_iv(tfm, iv, iv_len);
- }
-
- err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16);
- if (err)
- BT_ERR("Encrypt data error %d", err);
-
- return err;
-}
-
-static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
- u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia,
- u8 _rat, bdaddr_t *ra, u8 res[16])
-{
- u8 p1[16], p2[16];
- int err;
-
- memset(p1, 0, 16);
-
- /* p1 = pres || preq || _rat || _iat */
- swap56(pres, p1);
- swap56(preq, p1 + 7);
- p1[14] = _rat;
- p1[15] = _iat;
-
- memset(p2, 0, 16);
-
- /* p2 = padding || ia || ra */
- baswap((bdaddr_t *) (p2 + 4), ia);
- baswap((bdaddr_t *) (p2 + 10), ra);
-
- /* res = r XOR p1 */
- u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
-
- /* res = e(k, res) */
- err = smp_e(tfm, k, res);
- if (err) {
- BT_ERR("Encrypt data error");
- return err;
- }
-
- /* res = res XOR p2 */
- u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
-
- /* res = e(k, res) */
- err = smp_e(tfm, k, res);
- if (err)
- BT_ERR("Encrypt data error");
-
- return err;
-}
-
-static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16],
- u8 r1[16], u8 r2[16], u8 _r[16])
-{
- int err;
-
- /* Just least significant octets from r1 and r2 are considered */
- memcpy(_r, r1 + 8, 8);
- memcpy(_r + 8, r2 + 8, 8);
-
- err = smp_e(tfm, k, _r);
- if (err)
- BT_ERR("Encrypt data error");
-
- return err;
-}
-
-static int smp_rand(u8 *buf)
-{
- get_random_bytes(buf, 16);
-
- return 0;
-}
-
-static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code,
- u16 dlen, void *data)
-{
- struct sk_buff *skb;
- struct l2cap_hdr *lh;
- int len;
-
- len = L2CAP_HDR_SIZE + sizeof(code) + dlen;
-
- if (len > conn->mtu)
- return NULL;
-
- skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (!skb)
- return NULL;
-
- lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
- lh->len = cpu_to_le16(sizeof(code) + dlen);
- lh->cid = cpu_to_le16(L2CAP_CID_SMP);
-
- memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));
-
- memcpy(skb_put(skb, dlen), data, dlen);
-
- return skb;
-}
-
-static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
-{
- struct sk_buff *skb = smp_build_cmd(conn, code, len, data);
-
- BT_DBG("code 0x%2.2x", code);
-
- if (!skb)
- return;
-
- skb->priority = HCI_PRIO_MAX;
- hci_send_acl(conn->hchan, skb, 0);
-
- cancel_delayed_work_sync(&conn->security_timer);
- schedule_delayed_work(&conn->security_timer, SMP_TIMEOUT);
-}
-
-static __u8 authreq_to_seclevel(__u8 authreq)
-{
- if (authreq & SMP_AUTH_MITM)
- return BT_SECURITY_HIGH;
- else
- return BT_SECURITY_MEDIUM;
-}
-
-static __u8 seclevel_to_authreq(__u8 sec_level)
-{
- switch (sec_level) {
- case BT_SECURITY_HIGH:
- return SMP_AUTH_MITM | SMP_AUTH_BONDING;
- case BT_SECURITY_MEDIUM:
- return SMP_AUTH_BONDING;
- default:
- return SMP_AUTH_NONE;
- }
-}
-
-static void build_pairing_cmd(struct l2cap_conn *conn,
- struct smp_cmd_pairing *req,
- struct smp_cmd_pairing *rsp,
- __u8 authreq)
-{
- u8 dist_keys = 0;
-
- if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) {
- dist_keys = SMP_DIST_ENC_KEY;
- authreq |= SMP_AUTH_BONDING;
- } else {
- authreq &= ~SMP_AUTH_BONDING;
- }
-
- if (rsp == NULL) {
- req->io_capability = conn->hcon->io_capability;
- req->oob_flag = SMP_OOB_NOT_PRESENT;
- req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
- req->init_key_dist = 0;
- req->resp_key_dist = dist_keys;
- req->auth_req = authreq;
- return;
- }
-
- rsp->io_capability = conn->hcon->io_capability;
- rsp->oob_flag = SMP_OOB_NOT_PRESENT;
- rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
- rsp->init_key_dist = 0;
- rsp->resp_key_dist = req->resp_key_dist & dist_keys;
- rsp->auth_req = authreq;
-}
-
-static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
-{
- struct smp_chan *smp = conn->smp_chan;
-
- if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
- (max_key_size < SMP_MIN_ENC_KEY_SIZE))
- return SMP_ENC_KEY_SIZE;
-
- smp->enc_key_size = max_key_size;
-
- return 0;
-}
-
-static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
-{
- struct hci_conn *hcon = conn->hcon;
-
- if (send)
- smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
- &reason);
-
- clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags);
- mgmt_auth_failed(conn->hcon->hdev, conn->dst, hcon->type,
- hcon->dst_type, reason);
-
- if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) {
- cancel_delayed_work_sync(&conn->security_timer);
- smp_chan_destroy(conn);
- }
-}
-
-#define JUST_WORKS 0x00
-#define JUST_CFM 0x01
-#define REQ_PASSKEY 0x02
-#define CFM_PASSKEY 0x03
-#define REQ_OOB 0x04
-#define OVERLAP 0xFF
-
-static const u8 gen_method[5][5] = {
- { JUST_WORKS, JUST_CFM, REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY },
- { JUST_WORKS, JUST_CFM, REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY },
- { CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY },
- { JUST_WORKS, JUST_CFM, JUST_WORKS, JUST_WORKS, JUST_CFM },
- { CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, OVERLAP },
-};
-
-static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
- u8 local_io, u8 remote_io)
-{
- struct hci_conn *hcon = conn->hcon;
- struct smp_chan *smp = conn->smp_chan;
- u8 method;
- u32 passkey = 0;
- int ret = 0;
-
- /* Initialize key for JUST WORKS */
- memset(smp->tk, 0, sizeof(smp->tk));
- clear_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
-
- BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io);
-
- /* If neither side wants MITM, use JUST WORKS */
- /* If either side has unknown io_caps, use JUST WORKS */
- /* Otherwise, look up method from the table */
- if (!(auth & SMP_AUTH_MITM) ||
- local_io > SMP_IO_KEYBOARD_DISPLAY ||
- remote_io > SMP_IO_KEYBOARD_DISPLAY)
- method = JUST_WORKS;
- else
- method = gen_method[remote_io][local_io];
-
- /* If not bonding, don't ask user to confirm a Zero TK */
- if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM)
- method = JUST_WORKS;
-
- /* If Just Works, Continue with Zero TK */
- if (method == JUST_WORKS) {
- set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
- return 0;
- }
-
- /* Not Just Works/Confirm results in MITM Authentication */
- if (method != JUST_CFM)
- set_bit(SMP_FLAG_MITM_AUTH, &smp->smp_flags);
-
- /* If both devices have Keyoard-Display I/O, the master
- * Confirms and the slave Enters the passkey.
- */
- if (method == OVERLAP) {
- if (hcon->link_mode & HCI_LM_MASTER)
- method = CFM_PASSKEY;
- else
- method = REQ_PASSKEY;
- }
-
- /* Generate random passkey. Not valid until confirmed. */
- if (method == CFM_PASSKEY) {
- u8 key[16];
-
- memset(key, 0, sizeof(key));
- get_random_bytes(&passkey, sizeof(passkey));
- passkey %= 1000000;
- put_unaligned_le32(passkey, key);
- swap128(key, smp->tk);
- BT_DBG("PassKey: %d", passkey);
- }
-
- hci_dev_lock(hcon->hdev);
-
- if (method == REQ_PASSKEY)
- ret = mgmt_user_passkey_request(hcon->hdev, conn->dst,
- hcon->type, hcon->dst_type);
- else
- ret = mgmt_user_confirm_request(hcon->hdev, conn->dst,
- hcon->type, hcon->dst_type,
- cpu_to_le32(passkey), 0);
-
- hci_dev_unlock(hcon->hdev);
-
- return ret;
-}
-
-static void confirm_work(struct work_struct *work)
-{
- struct smp_chan *smp = container_of(work, struct smp_chan, confirm);
- struct l2cap_conn *conn = smp->conn;
- struct crypto_blkcipher *tfm;
- struct smp_cmd_pairing_confirm cp;
- int ret;
- u8 res[16], reason;
-
- BT_DBG("conn %p", conn);
-
- tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(tfm)) {
- reason = SMP_UNSPECIFIED;
- goto error;
- }
-
- smp->tfm = tfm;
-
- if (conn->hcon->out)
- ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, 0,
- conn->src, conn->hcon->dst_type, conn->dst, res);
- else
- ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
- conn->hcon->dst_type, conn->dst, 0, conn->src,
- res);
- if (ret) {
- reason = SMP_UNSPECIFIED;
- goto error;
- }
-
- clear_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
-
- swap128(res, cp.confirm_val);
- smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
-
- return;
-
-error:
- smp_failure(conn, reason, 1);
-}
-
-static void random_work(struct work_struct *work)
-{
- struct smp_chan *smp = container_of(work, struct smp_chan, random);
- struct l2cap_conn *conn = smp->conn;
- struct hci_conn *hcon = conn->hcon;
- struct crypto_blkcipher *tfm = smp->tfm;
- u8 reason, confirm[16], res[16], key[16];
- int ret;
-
- if (IS_ERR_OR_NULL(tfm)) {
- reason = SMP_UNSPECIFIED;
- goto error;
- }
-
- BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
-
- if (hcon->out)
- ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, 0,
- conn->src, hcon->dst_type, conn->dst, res);
- else
- ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
- hcon->dst_type, conn->dst, 0, conn->src, res);
- if (ret) {
- reason = SMP_UNSPECIFIED;
- goto error;
- }
-
- swap128(res, confirm);
-
- if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) {
- BT_ERR("Pairing failed (confirmation values mismatch)");
- reason = SMP_CONFIRM_FAILED;
- goto error;
- }
-
- if (hcon->out) {
- u8 stk[16], rand[8];
- __le16 ediv;
-
- memset(rand, 0, sizeof(rand));
- ediv = 0;
-
- smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key);
- swap128(key, stk);
-
- memset(stk + smp->enc_key_size, 0,
- SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
-
- if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) {
- reason = SMP_UNSPECIFIED;
- goto error;
- }
-
- hci_le_start_enc(hcon, ediv, rand, stk);
- hcon->enc_key_size = smp->enc_key_size;
- } else {
- u8 stk[16], r[16], rand[8];
- __le16 ediv;
-
- memset(rand, 0, sizeof(rand));
- ediv = 0;
-
- swap128(smp->prnd, r);
- smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
-
- smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key);
- swap128(key, stk);
-
- memset(stk + smp->enc_key_size, 0,
- SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
-
- hci_add_ltk(hcon->hdev, conn->dst, hcon->dst_type,
- HCI_SMP_STK_SLAVE, 0, 0, stk, smp->enc_key_size,
- ediv, rand);
- }
-
- return;
-
-error:
- smp_failure(conn, reason, 1);
-}
-
-static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
-{
- struct smp_chan *smp;
-
- smp = kzalloc(sizeof(struct smp_chan), GFP_ATOMIC);
- if (!smp)
- return NULL;
-
- INIT_WORK(&smp->confirm, confirm_work);
- INIT_WORK(&smp->random, random_work);
-
- smp->conn = conn;
- conn->smp_chan = smp;
- conn->hcon->smp_conn = conn;
-
- hci_conn_hold(conn->hcon);
-
- return smp;
-}
-
-void smp_chan_destroy(struct l2cap_conn *conn)
-{
- struct smp_chan *smp = conn->smp_chan;
-
- BUG_ON(!smp);
-
- if (smp->tfm)
- crypto_free_blkcipher(smp->tfm);
-
- kfree(smp);
- conn->smp_chan = NULL;
- conn->hcon->smp_conn = NULL;
- hci_conn_put(conn->hcon);
-}
-
-int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
-{
- struct l2cap_conn *conn = hcon->smp_conn;
- struct smp_chan *smp;
- u32 value;
- u8 key[16];
-
- BT_DBG("");
-
- if (!conn)
- return -ENOTCONN;
-
- smp = conn->smp_chan;
-
- switch (mgmt_op) {
- case MGMT_OP_USER_PASSKEY_REPLY:
- value = le32_to_cpu(passkey);
- memset(key, 0, sizeof(key));
- BT_DBG("PassKey: %d", value);
- put_unaligned_le32(value, key);
- swap128(key, smp->tk);
- /* Fall Through */
- case MGMT_OP_USER_CONFIRM_REPLY:
- set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
- break;
- case MGMT_OP_USER_PASSKEY_NEG_REPLY:
- case MGMT_OP_USER_CONFIRM_NEG_REPLY:
- smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED, 1);
- return 0;
- default:
- smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED, 1);
- return -EOPNOTSUPP;
- }
-
- /* If it is our turn to send Pairing Confirm, do so now */
- if (test_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags))
- queue_work(hcon->hdev->workqueue, &smp->confirm);
-
- return 0;
-}
-
-static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
-{
- struct smp_cmd_pairing rsp, *req = (void *) skb->data;
- struct smp_chan *smp;
- u8 key_size;
- u8 auth = SMP_AUTH_NONE;
- int ret;
-
- BT_DBG("conn %p", conn);
-
- if (conn->hcon->link_mode & HCI_LM_MASTER)
- return SMP_CMD_NOTSUPP;
-
- if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
- smp = smp_chan_create(conn);
-
- smp = conn->smp_chan;
-
- smp->preq[0] = SMP_CMD_PAIRING_REQ;
- memcpy(&smp->preq[1], req, sizeof(*req));
- skb_pull(skb, sizeof(*req));
-
- /* We didn't start the pairing, so match remote */
- if (req->auth_req & SMP_AUTH_BONDING)
- auth = req->auth_req;
-
- conn->hcon->pending_sec_level = authreq_to_seclevel(auth);
-
- build_pairing_cmd(conn, req, &rsp, auth);
-
- key_size = min(req->max_key_size, rsp.max_key_size);
- if (check_enc_key_size(conn, key_size))
- return SMP_ENC_KEY_SIZE;
-
- ret = smp_rand(smp->prnd);
- if (ret)
- return SMP_UNSPECIFIED;
-
- smp->prsp[0] = SMP_CMD_PAIRING_RSP;
- memcpy(&smp->prsp[1], &rsp, sizeof(rsp));
-
- smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
-
- /* Request setup of TK */
- ret = tk_request(conn, 0, auth, rsp.io_capability, req->io_capability);
- if (ret)
- return SMP_UNSPECIFIED;
-
- return 0;
-}
-
-static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
-{
- struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
- struct smp_chan *smp = conn->smp_chan;
- struct hci_dev *hdev = conn->hcon->hdev;
- u8 key_size, auth = SMP_AUTH_NONE;
- int ret;
-
- BT_DBG("conn %p", conn);
-
- if (!(conn->hcon->link_mode & HCI_LM_MASTER))
- return SMP_CMD_NOTSUPP;
-
- skb_pull(skb, sizeof(*rsp));
-
- req = (void *) &smp->preq[1];
-
- key_size = min(req->max_key_size, rsp->max_key_size);
- if (check_enc_key_size(conn, key_size))
- return SMP_ENC_KEY_SIZE;
-
- ret = smp_rand(smp->prnd);
- if (ret)
- return SMP_UNSPECIFIED;
-
- smp->prsp[0] = SMP_CMD_PAIRING_RSP;
- memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
-
- if ((req->auth_req & SMP_AUTH_BONDING) &&
- (rsp->auth_req & SMP_AUTH_BONDING))
- auth = SMP_AUTH_BONDING;
-
- auth |= (req->auth_req | rsp->auth_req) & SMP_AUTH_MITM;
-
- ret = tk_request(conn, 0, auth, rsp->io_capability, req->io_capability);
- if (ret)
- return SMP_UNSPECIFIED;
-
- set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
-
- /* Can't compose response until we have been confirmed */
- if (!test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags))
- return 0;
-
- queue_work(hdev->workqueue, &smp->confirm);
-
- return 0;
-}
-
-static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
-{
- struct smp_chan *smp = conn->smp_chan;
- struct hci_dev *hdev = conn->hcon->hdev;
-
- BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
-
- memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
- skb_pull(skb, sizeof(smp->pcnf));
-
- if (conn->hcon->out) {
- u8 random[16];
-
- swap128(smp->prnd, random);
- smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random),
- random);
- } else if (test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags)) {
- queue_work(hdev->workqueue, &smp->confirm);
- } else {
- set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
- }
-
- return 0;
-}
-
-static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
-{
- struct smp_chan *smp = conn->smp_chan;
- struct hci_dev *hdev = conn->hcon->hdev;
-
- BT_DBG("conn %p", conn);
-
- swap128(skb->data, smp->rrnd);
- skb_pull(skb, sizeof(smp->rrnd));
-
- queue_work(hdev->workqueue, &smp->random);
-
- return 0;
-}
-
-static u8 smp_ltk_encrypt(struct l2cap_conn *conn)
-{
- struct smp_ltk *key;
- struct hci_conn *hcon = conn->hcon;
-
- key = hci_find_ltk_by_addr(hcon->hdev, conn->dst, hcon->dst_type);
- if (!key)
- return 0;
-
- if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
- return 1;
-
- hci_le_start_enc(hcon, key->ediv, key->rand, key->val);
- hcon->enc_key_size = key->enc_size;
-
- return 1;
-
-}
-static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
-{
- struct smp_cmd_security_req *rp = (void *) skb->data;
- struct smp_cmd_pairing cp;
- struct hci_conn *hcon = conn->hcon;
- struct smp_chan *smp;
-
- BT_DBG("conn %p", conn);
-
- hcon->pending_sec_level = authreq_to_seclevel(rp->auth_req);
-
- if (smp_ltk_encrypt(conn))
- return 0;
-
- if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
- return 0;
-
- smp = smp_chan_create(conn);
-
- skb_pull(skb, sizeof(*rp));
-
- memset(&cp, 0, sizeof(cp));
- build_pairing_cmd(conn, &cp, NULL, rp->auth_req);
-
- smp->preq[0] = SMP_CMD_PAIRING_REQ;
- memcpy(&smp->preq[1], &cp, sizeof(cp));
-
- smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
-
- return 0;
-}
-
-int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
-{
- struct hci_conn *hcon = conn->hcon;
- struct smp_chan *smp = conn->smp_chan;
- __u8 authreq;
-
- BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
-
- if (!lmp_host_le_capable(hcon->hdev))
- return 1;
-
- if (sec_level == BT_SECURITY_LOW)
- return 1;
-
- if (hcon->sec_level >= sec_level)
- return 1;
-
- if (hcon->link_mode & HCI_LM_MASTER)
- if (smp_ltk_encrypt(conn))
- goto done;
-
- if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
- return 0;
-
- smp = smp_chan_create(conn);
- if (!smp)
- return 1;
-
- authreq = seclevel_to_authreq(sec_level);
-
- if (hcon->link_mode & HCI_LM_MASTER) {
- struct smp_cmd_pairing cp;
-
- build_pairing_cmd(conn, &cp, NULL, authreq);
- smp->preq[0] = SMP_CMD_PAIRING_REQ;
- memcpy(&smp->preq[1], &cp, sizeof(cp));
-
- smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
- } else {
- struct smp_cmd_security_req cp;
- cp.auth_req = authreq;
- smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
- }
-
-done:
- hcon->pending_sec_level = sec_level;
-
- return 0;
-}
-
-static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
-{
- struct smp_cmd_encrypt_info *rp = (void *) skb->data;
- struct smp_chan *smp = conn->smp_chan;
-
- skb_pull(skb, sizeof(*rp));
-
- memcpy(smp->tk, rp->ltk, sizeof(smp->tk));
-
- return 0;
-}
-
-static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
-{
- struct smp_cmd_master_ident *rp = (void *) skb->data;
- struct smp_chan *smp = conn->smp_chan;
- struct hci_dev *hdev = conn->hcon->hdev;
- struct hci_conn *hcon = conn->hcon;
- u8 authenticated;
-
- skb_pull(skb, sizeof(*rp));
-
- hci_dev_lock(hdev);
- authenticated = (conn->hcon->sec_level == BT_SECURITY_HIGH);
- hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type,
- HCI_SMP_LTK, 1, authenticated, smp->tk, smp->enc_key_size,
- rp->ediv, rp->rand);
- smp_distribute_keys(conn, 1);
- hci_dev_unlock(hdev);
-
- return 0;
-}
-
-int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
-{
- __u8 code = skb->data[0];
- __u8 reason;
- int err = 0;
-
- if (!lmp_host_le_capable(conn->hcon->hdev)) {
- err = -ENOTSUPP;
- reason = SMP_PAIRING_NOTSUPP;
- goto done;
- }
-
- skb_pull(skb, sizeof(code));
-
- switch (code) {
- case SMP_CMD_PAIRING_REQ:
- reason = smp_cmd_pairing_req(conn, skb);
- break;
-
- case SMP_CMD_PAIRING_FAIL:
- smp_failure(conn, skb->data[0], 0);
- reason = 0;
- err = -EPERM;
- break;
-
- case SMP_CMD_PAIRING_RSP:
- reason = smp_cmd_pairing_rsp(conn, skb);
- break;
-
- case SMP_CMD_SECURITY_REQ:
- reason = smp_cmd_security_req(conn, skb);
- break;
-
- case SMP_CMD_PAIRING_CONFIRM:
- reason = smp_cmd_pairing_confirm(conn, skb);
- break;
-
- case SMP_CMD_PAIRING_RANDOM:
- reason = smp_cmd_pairing_random(conn, skb);
- break;
-
- case SMP_CMD_ENCRYPT_INFO:
- reason = smp_cmd_encrypt_info(conn, skb);
- break;
-
- case SMP_CMD_MASTER_IDENT:
- reason = smp_cmd_master_ident(conn, skb);
- break;
-
- case SMP_CMD_IDENT_INFO:
- case SMP_CMD_IDENT_ADDR_INFO:
- case SMP_CMD_SIGN_INFO:
- /* Just ignored */
- reason = 0;
- break;
-
- default:
- BT_DBG("Unknown command code 0x%2.2x", code);
-
- reason = SMP_CMD_NOTSUPP;
- err = -EOPNOTSUPP;
- goto done;
- }
-
-done:
- if (reason)
- smp_failure(conn, reason, 1);
-
- kfree_skb(skb);
- return err;
-}
-
-int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
-{
- struct smp_cmd_pairing *req, *rsp;
- struct smp_chan *smp = conn->smp_chan;
- __u8 *keydist;
-
- BT_DBG("conn %p force %d", conn, force);
-
- if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
- return 0;
-
- rsp = (void *) &smp->prsp[1];
-
- /* The responder sends its keys first */
- if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07))
- return 0;
-
- req = (void *) &smp->preq[1];
-
- if (conn->hcon->out) {
- keydist = &rsp->init_key_dist;
- *keydist &= req->init_key_dist;
- } else {
- keydist = &rsp->resp_key_dist;
- *keydist &= req->resp_key_dist;
- }
-
-
- BT_DBG("keydist 0x%x", *keydist);
-
- if (*keydist & SMP_DIST_ENC_KEY) {
- struct smp_cmd_encrypt_info enc;
- struct smp_cmd_master_ident ident;
- struct hci_conn *hcon = conn->hcon;
- u8 authenticated;
- __le16 ediv;
-
- get_random_bytes(enc.ltk, sizeof(enc.ltk));
- get_random_bytes(&ediv, sizeof(ediv));
- get_random_bytes(ident.rand, sizeof(ident.rand));
-
- smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
-
- authenticated = hcon->sec_level == BT_SECURITY_HIGH;
- hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type,
- HCI_SMP_LTK_SLAVE, 1, authenticated,
- enc.ltk, smp->enc_key_size, ediv, ident.rand);
-
- ident.ediv = cpu_to_le16(ediv);
-
- smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
-
- *keydist &= ~SMP_DIST_ENC_KEY;
- }
-
- if (*keydist & SMP_DIST_ID_KEY) {
- struct smp_cmd_ident_addr_info addrinfo;
- struct smp_cmd_ident_info idinfo;
-
- /* Send a dummy key */
- get_random_bytes(idinfo.irk, sizeof(idinfo.irk));
-
- smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
-
- /* Just public address */
- memset(&addrinfo, 0, sizeof(addrinfo));
- bacpy(&addrinfo.bdaddr, conn->src);
-
- smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
- &addrinfo);
-
- *keydist &= ~SMP_DIST_ID_KEY;
- }
-
- if (*keydist & SMP_DIST_SIGN) {
- struct smp_cmd_sign_info sign;
-
- /* Send a dummy key */
- get_random_bytes(sign.csrk, sizeof(sign.csrk));
-
- smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign);
-
- *keydist &= ~SMP_DIST_SIGN;
- }
-
- if (conn->hcon->out || force) {
- clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
- cancel_delayed_work_sync(&conn->security_timer);
- smp_chan_destroy(conn);
- }
-
- return 0;
-}