Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1480 commits) bonding: enable netpoll without checking link status xfrm: Refcount destination entry on xfrm_lookup net: introduce rx_handler results and logic around that bonding: get rid of IFF_SLAVE_INACTIVE netdev->priv_flag bonding: wrap slave state work net: get rid of multiple bond-related netdevice->priv_flags bonding: register slave pointer for rx_handler be2net: Bump up the version number be2net: Copyright notice change. Update to Emulex instead of ServerEngines e1000e: fix kconfig for crc32 dependency netfilter ebtables: fix xt_AUDIT to work with ebtables xen network backend driver bonding: Improve syslog message at device creation time bonding: Call netif_carrier_off after register_netdevice bonding: Incorrect TX queue offset net_sched: fix ip_tos2prio xfrm: fix __xfrm_route_forward() be2net: Fix UDP packet detected status in RX compl Phonet: fix aligned-mode pipe socket buffer header reserve netxen: support for GbE port settings ... Fix up conflicts in drivers/staging/brcm80211/brcmsmac/wl_mac80211.c with the staging updates.
This commit is contained in:
@@ -27,31 +27,27 @@ menuconfig BT
|
||||
compile it as module (bluetooth).
|
||||
|
||||
To use Linux Bluetooth subsystem, you will need several user-space
|
||||
utilities like hciconfig and hcid. These utilities and updates to
|
||||
Bluetooth kernel modules are provided in the BlueZ packages.
|
||||
For more information, see <http://www.bluez.org/>.
|
||||
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/>.
|
||||
|
||||
if BT != n
|
||||
|
||||
config BT_L2CAP
|
||||
tristate "L2CAP protocol support"
|
||||
depends on BT
|
||||
bool "L2CAP protocol support"
|
||||
select CRC16
|
||||
help
|
||||
L2CAP (Logical Link Control and Adaptation Protocol) provides
|
||||
connection oriented and connection-less data transport. L2CAP
|
||||
support is required for most Bluetooth applications.
|
||||
|
||||
Say Y here to compile L2CAP support into the kernel or say M to
|
||||
compile it as module (l2cap).
|
||||
|
||||
config BT_SCO
|
||||
tristate "SCO links support"
|
||||
depends on BT
|
||||
bool "SCO links support"
|
||||
help
|
||||
SCO link provides voice transport over Bluetooth. SCO support is
|
||||
required for voice applications like Headset and Audio.
|
||||
|
||||
Say Y here to compile SCO support into the kernel or say M to
|
||||
compile it as module (sco).
|
||||
endif
|
||||
|
||||
source "net/bluetooth/rfcomm/Kconfig"
|
||||
|
||||
|
@@ -3,11 +3,11 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_BT) += bluetooth.o
|
||||
obj-$(CONFIG_BT_L2CAP) += l2cap.o
|
||||
obj-$(CONFIG_BT_SCO) += sco.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 lib.o
|
||||
bluetooth-$(CONFIG_BT_L2CAP) += l2cap_core.o l2cap_sock.o
|
||||
bluetooth-$(CONFIG_BT_SCO) += sco.o
|
||||
|
@@ -40,7 +40,7 @@
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
|
||||
#define VERSION "2.15"
|
||||
#define VERSION "2.16"
|
||||
|
||||
/* Bluetooth sockets */
|
||||
#define BT_MAX_PROTO 8
|
||||
@@ -199,14 +199,15 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
|
||||
|
||||
BT_DBG("parent %p", parent);
|
||||
|
||||
local_bh_disable();
|
||||
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);
|
||||
bh_lock_sock(sk);
|
||||
|
||||
/* FIXME: Is this check still needed */
|
||||
if (sk->sk_state == BT_CLOSED) {
|
||||
release_sock(sk);
|
||||
bh_unlock_sock(sk);
|
||||
bt_accept_unlink(sk);
|
||||
continue;
|
||||
}
|
||||
@@ -216,12 +217,16 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
|
||||
bt_accept_unlink(sk);
|
||||
if (newsock)
|
||||
sock_graft(sk, newsock);
|
||||
release_sock(sk);
|
||||
|
||||
bh_unlock_sock(sk);
|
||||
local_bh_enable();
|
||||
return sk;
|
||||
}
|
||||
|
||||
release_sock(sk);
|
||||
bh_unlock_sock(sk);
|
||||
}
|
||||
local_bh_enable();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(bt_accept_dequeue);
|
||||
@@ -240,7 +245,8 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||
if (flags & (MSG_OOB))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) {
|
||||
skb = skb_recv_datagram(sk, flags, noblock, &err);
|
||||
if (!skb) {
|
||||
if (sk->sk_shutdown & RCV_SHUTDOWN)
|
||||
return 0;
|
||||
return err;
|
||||
@@ -323,7 +329,8 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||
if (copied >= target)
|
||||
break;
|
||||
|
||||
if ((err = sock_error(sk)) != 0)
|
||||
err = sock_error(sk);
|
||||
if (err)
|
||||
break;
|
||||
if (sk->sk_shutdown & RCV_SHUTDOWN)
|
||||
break;
|
||||
@@ -390,7 +397,7 @@ static inline unsigned int bt_accept_poll(struct sock *parent)
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
|
||||
unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
unsigned int mask = 0;
|
||||
@@ -538,13 +545,39 @@ static int __init bt_init(void)
|
||||
|
||||
BT_INFO("HCI device and connection manager initialized");
|
||||
|
||||
hci_sock_init();
|
||||
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);
|
||||
|
@@ -708,8 +708,6 @@ static int __init bnep_init(void)
|
||||
{
|
||||
char flt[50] = "";
|
||||
|
||||
l2cap_load();
|
||||
|
||||
#ifdef CONFIG_BT_BNEP_PROTO_FILTER
|
||||
strcat(flt, "protocol ");
|
||||
#endif
|
||||
|
@@ -88,6 +88,7 @@ static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
|
||||
sockfd_put(nsock);
|
||||
return -EBADFD;
|
||||
}
|
||||
ca.device[sizeof(ca.device)-1] = 0;
|
||||
|
||||
err = bnep_add_connection(&ca, nsock);
|
||||
if (!err) {
|
||||
|
@@ -155,7 +155,8 @@ static void cmtp_send_interopmsg(struct cmtp_session *session,
|
||||
|
||||
BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
|
||||
|
||||
if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) {
|
||||
skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
BT_ERR("Can't allocate memory for interoperability packet");
|
||||
return;
|
||||
}
|
||||
|
@@ -115,7 +115,8 @@ static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const
|
||||
|
||||
size = (skb) ? skb->len + count : count;
|
||||
|
||||
if (!(nskb = alloc_skb(size, GFP_ATOMIC))) {
|
||||
nskb = alloc_skb(size, GFP_ATOMIC);
|
||||
if (!nskb) {
|
||||
BT_ERR("Can't allocate memory for CAPI message");
|
||||
return;
|
||||
}
|
||||
@@ -216,7 +217,8 @@ static void cmtp_process_transmit(struct cmtp_session *session)
|
||||
|
||||
BT_DBG("session %p", session);
|
||||
|
||||
if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) {
|
||||
nskb = alloc_skb(session->mtu, GFP_ATOMIC);
|
||||
if (!nskb) {
|
||||
BT_ERR("Can't allocate memory for new frame");
|
||||
return;
|
||||
}
|
||||
@@ -224,7 +226,8 @@ static void cmtp_process_transmit(struct cmtp_session *session)
|
||||
while ((skb = skb_dequeue(&session->transmit))) {
|
||||
struct cmtp_scb *scb = (void *) skb->cb;
|
||||
|
||||
if ((tail = (session->mtu - nskb->len)) < 5) {
|
||||
tail = session->mtu - nskb->len;
|
||||
if (tail < 5) {
|
||||
cmtp_send_frame(session, nskb->data, nskb->len);
|
||||
skb_trim(nskb, 0);
|
||||
tail = session->mtu;
|
||||
@@ -466,8 +469,6 @@ int cmtp_get_conninfo(struct cmtp_conninfo *ci)
|
||||
|
||||
static int __init cmtp_init(void)
|
||||
{
|
||||
l2cap_load();
|
||||
|
||||
BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION);
|
||||
|
||||
cmtp_init_sockets();
|
||||
|
@@ -45,6 +45,33 @@
|
||||
#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 = 1;
|
||||
conn->link_mode |= HCI_LM_MASTER;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.scan_interval = cpu_to_le16(0x0004);
|
||||
cp.scan_window = cpu_to_le16(0x0004);
|
||||
bacpy(&cp.peer_addr, &conn->dst);
|
||||
cp.conn_interval_min = cpu_to_le16(0x0008);
|
||||
cp.conn_interval_max = cpu_to_le16(0x0100);
|
||||
cp.supervision_timeout = cpu_to_le16(0x0064);
|
||||
cp.min_ce_len = cpu_to_le16(0x0001);
|
||||
cp.max_ce_len = cpu_to_le16(0x0001);
|
||||
|
||||
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;
|
||||
@@ -156,6 +183,26 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
|
||||
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);
|
||||
|
||||
/* Device _must_ be locked */
|
||||
void hci_sco_setup(struct hci_conn *conn, __u8 status)
|
||||
{
|
||||
@@ -193,8 +240,12 @@ static void hci_conn_timeout(unsigned long arg)
|
||||
switch (conn->state) {
|
||||
case BT_CONNECT:
|
||||
case BT_CONNECT2:
|
||||
if (conn->type == ACL_LINK && conn->out)
|
||||
hci_acl_connect_cancel(conn);
|
||||
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:
|
||||
@@ -234,6 +285,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
|
||||
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->power_save = 1;
|
||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
@@ -295,6 +348,11 @@ int hci_conn_del(struct hci_conn *conn)
|
||||
|
||||
/* 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) {
|
||||
@@ -360,15 +418,31 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
|
||||
}
|
||||
EXPORT_SYMBOL(hci_get_route);
|
||||
|
||||
/* Create SCO or ACL connection.
|
||||
/* 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) {
|
||||
le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
|
||||
if (le)
|
||||
return ERR_PTR(-EBUSY);
|
||||
le = hci_conn_add(hdev, LE_LINK, dst);
|
||||
if (!le)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (le->state == BT_OPEN)
|
||||
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);
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/timer.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
@@ -50,6 +51,8 @@
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
||||
#define AUTO_OFF_TIMEOUT 2000
|
||||
|
||||
static void hci_cmd_task(unsigned long arg);
|
||||
static void hci_rx_task(unsigned long arg);
|
||||
static void hci_tx_task(unsigned long arg);
|
||||
@@ -95,11 +98,10 @@ 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 the request has set req_last_cmd (typical for multi-HCI
|
||||
* command requests) check if the completed command matches
|
||||
* this, and if not just return. Single HCI command requests
|
||||
* typically leave req_last_cmd as 0 */
|
||||
if (hdev->req_last_cmd && cmd != hdev->req_last_cmd)
|
||||
/* 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)
|
||||
return;
|
||||
|
||||
if (hdev->req_status == HCI_REQ_PEND) {
|
||||
@@ -122,7 +124,7 @@ static void hci_req_cancel(struct hci_dev *hdev, int err)
|
||||
|
||||
/* 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)
|
||||
unsigned long opt, __u32 timeout)
|
||||
{
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
int err = 0;
|
||||
@@ -156,7 +158,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
|
||||
break;
|
||||
}
|
||||
|
||||
hdev->req_last_cmd = hdev->req_status = hdev->req_result = 0;
|
||||
hdev->req_status = hdev->req_result = 0;
|
||||
|
||||
BT_DBG("%s end: err %d", hdev->name, err);
|
||||
|
||||
@@ -164,7 +166,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
|
||||
}
|
||||
|
||||
static inline int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
|
||||
unsigned long opt, __u32 timeout)
|
||||
unsigned long opt, __u32 timeout)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -189,6 +191,7 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
|
||||
|
||||
static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
|
||||
{
|
||||
struct hci_cp_delete_stored_link_key cp;
|
||||
struct sk_buff *skb;
|
||||
__le16 param;
|
||||
__u8 flt_type;
|
||||
@@ -252,15 +255,21 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
|
||||
flt_type = HCI_FLT_CLEAR_ALL;
|
||||
hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
|
||||
|
||||
/* Page timeout ~20 secs */
|
||||
param = cpu_to_le16(0x8000);
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_PG_TIMEOUT, 2, ¶m);
|
||||
|
||||
/* Connection accept timeout ~20 secs */
|
||||
param = cpu_to_le16(0x7d00);
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m);
|
||||
|
||||
hdev->req_last_cmd = HCI_OP_WRITE_CA_TIMEOUT;
|
||||
bacpy(&cp.bdaddr, BDADDR_ANY);
|
||||
cp.delete_all = 1;
|
||||
hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -429,7 +438,8 @@ int hci_inquiry(void __user *arg)
|
||||
if (copy_from_user(&ir, ptr, sizeof(ir)))
|
||||
return -EFAULT;
|
||||
|
||||
if (!(hdev = hci_dev_get(ir.dev_id)))
|
||||
hdev = hci_dev_get(ir.dev_id);
|
||||
if (!hdev)
|
||||
return -ENODEV;
|
||||
|
||||
hci_dev_lock_bh(hdev);
|
||||
@@ -455,7 +465,7 @@ int hci_inquiry(void __user *arg)
|
||||
/* 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);
|
||||
buf = kmalloc(sizeof(struct inquiry_info) * max_rsp, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
err = -ENOMEM;
|
||||
goto done;
|
||||
@@ -489,7 +499,8 @@ int hci_dev_open(__u16 dev)
|
||||
struct hci_dev *hdev;
|
||||
int ret = 0;
|
||||
|
||||
if (!(hdev = hci_dev_get(dev)))
|
||||
hdev = hci_dev_get(dev);
|
||||
if (!hdev)
|
||||
return -ENODEV;
|
||||
|
||||
BT_DBG("%s %p", hdev->name, hdev);
|
||||
@@ -521,11 +532,15 @@ int hci_dev_open(__u16 dev)
|
||||
if (!test_bit(HCI_RAW, &hdev->flags)) {
|
||||
atomic_set(&hdev->cmd_cnt, 1);
|
||||
set_bit(HCI_INIT, &hdev->flags);
|
||||
hdev->init_last_cmd = 0;
|
||||
|
||||
//__hci_request(hdev, hci_reset_req, 0, HZ);
|
||||
ret = __hci_request(hdev, hci_init_req, 0,
|
||||
msecs_to_jiffies(HCI_INIT_TIMEOUT));
|
||||
|
||||
if (lmp_le_capable(hdev))
|
||||
ret = __hci_request(hdev, hci_le_init_req, 0,
|
||||
msecs_to_jiffies(HCI_INIT_TIMEOUT));
|
||||
|
||||
clear_bit(HCI_INIT, &hdev->flags);
|
||||
}
|
||||
|
||||
@@ -533,6 +548,8 @@ int hci_dev_open(__u16 dev)
|
||||
hci_dev_hold(hdev);
|
||||
set_bit(HCI_UP, &hdev->flags);
|
||||
hci_notify(hdev, HCI_DEV_UP);
|
||||
if (!test_bit(HCI_SETUP, &hdev->flags))
|
||||
mgmt_powered(hdev->id, 1);
|
||||
} else {
|
||||
/* Init failed, cleanup */
|
||||
tasklet_kill(&hdev->rx_task);
|
||||
@@ -606,6 +623,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
|
||||
|
||||
/* Drop last sent command */
|
||||
if (hdev->sent_cmd) {
|
||||
del_timer_sync(&hdev->cmd_timer);
|
||||
kfree_skb(hdev->sent_cmd);
|
||||
hdev->sent_cmd = NULL;
|
||||
}
|
||||
@@ -614,6 +632,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
|
||||
* and no tasks are scheduled. */
|
||||
hdev->close(hdev);
|
||||
|
||||
mgmt_powered(hdev->id, 0);
|
||||
|
||||
/* Clear flags */
|
||||
hdev->flags = 0;
|
||||
|
||||
@@ -664,7 +684,7 @@ int hci_dev_reset(__u16 dev)
|
||||
hdev->flush(hdev);
|
||||
|
||||
atomic_set(&hdev->cmd_cnt, 1);
|
||||
hdev->acl_cnt = 0; hdev->sco_cnt = 0;
|
||||
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,
|
||||
@@ -793,9 +813,17 @@ int hci_get_dev_list(void __user *arg)
|
||||
read_lock_bh(&hci_dev_list_lock);
|
||||
list_for_each(p, &hci_dev_list) {
|
||||
struct hci_dev *hdev;
|
||||
|
||||
hdev = list_entry(p, struct hci_dev, list);
|
||||
|
||||
hci_del_off_timer(hdev);
|
||||
|
||||
if (!test_bit(HCI_MGMT, &hdev->flags))
|
||||
set_bit(HCI_PAIRABLE, &hdev->flags);
|
||||
|
||||
(dr + n)->dev_id = hdev->id;
|
||||
(dr + n)->dev_opt = hdev->flags;
|
||||
|
||||
if (++n >= dev_num)
|
||||
break;
|
||||
}
|
||||
@@ -823,6 +851,11 @@ int hci_get_dev_info(void __user *arg)
|
||||
if (!hdev)
|
||||
return -ENODEV;
|
||||
|
||||
hci_del_off_timer(hdev);
|
||||
|
||||
if (!test_bit(HCI_MGMT, &hdev->flags))
|
||||
set_bit(HCI_PAIRABLE, &hdev->flags);
|
||||
|
||||
strcpy(di.name, hdev->name);
|
||||
di.bdaddr = hdev->bdaddr;
|
||||
di.type = (hdev->bus & 0x0f) | (hdev->dev_type << 4);
|
||||
@@ -891,6 +924,159 @@ void hci_free_dev(struct hci_dev *hdev)
|
||||
}
|
||||
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->flags))
|
||||
mod_timer(&hdev->off_timer,
|
||||
jiffies + msecs_to_jiffies(AUTO_OFF_TIMEOUT));
|
||||
|
||||
if (test_and_clear_bit(HCI_SETUP, &hdev->flags))
|
||||
mgmt_index_added(hdev->id);
|
||||
}
|
||||
|
||||
static void hci_power_off(struct work_struct *work)
|
||||
{
|
||||
struct hci_dev *hdev = container_of(work, struct hci_dev, power_off);
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
hci_dev_close(hdev->id);
|
||||
}
|
||||
|
||||
static void hci_auto_off(unsigned long data)
|
||||
{
|
||||
struct hci_dev *hdev = (struct hci_dev *) data;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
clear_bit(HCI_AUTO_OFF, &hdev->flags);
|
||||
|
||||
queue_work(hdev->workqueue, &hdev->power_off);
|
||||
}
|
||||
|
||||
void hci_del_off_timer(struct hci_dev *hdev)
|
||||
{
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
clear_bit(HCI_AUTO_OFF, &hdev->flags);
|
||||
del_timer(&hdev->off_timer);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
||||
{
|
||||
struct list_head *p;
|
||||
|
||||
list_for_each(p, &hdev->link_keys) {
|
||||
struct link_key *k;
|
||||
|
||||
k = list_entry(p, struct link_key, list);
|
||||
|
||||
if (bacmp(bdaddr, &k->bdaddr) == 0)
|
||||
return k;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
|
||||
u8 *val, u8 type, u8 pin_len)
|
||||
{
|
||||
struct link_key *key, *old_key;
|
||||
u8 old_key_type;
|
||||
|
||||
old_key = hci_find_link_key(hdev, bdaddr);
|
||||
if (old_key) {
|
||||
old_key_type = old_key->type;
|
||||
key = old_key;
|
||||
} else {
|
||||
old_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);
|
||||
|
||||
bacpy(&key->bdaddr, bdaddr);
|
||||
memcpy(key->val, val, 16);
|
||||
key->type = type;
|
||||
key->pin_len = pin_len;
|
||||
|
||||
if (new_key)
|
||||
mgmt_new_key(hdev->id, key, old_key_type);
|
||||
|
||||
if (type == 0x06)
|
||||
key->type = old_key_type;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
tasklet_schedule(&hdev->cmd_task);
|
||||
}
|
||||
|
||||
/* Register HCI device */
|
||||
int hci_register_dev(struct hci_dev *hdev)
|
||||
{
|
||||
@@ -923,6 +1109,7 @@ int hci_register_dev(struct hci_dev *hdev)
|
||||
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;
|
||||
@@ -936,6 +1123,8 @@ int hci_register_dev(struct hci_dev *hdev)
|
||||
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;
|
||||
|
||||
@@ -948,6 +1137,14 @@ int hci_register_dev(struct hci_dev *hdev)
|
||||
|
||||
INIT_LIST_HEAD(&hdev->blacklist);
|
||||
|
||||
INIT_LIST_HEAD(&hdev->uuids);
|
||||
|
||||
INIT_LIST_HEAD(&hdev->link_keys);
|
||||
|
||||
INIT_WORK(&hdev->power_on, hci_power_on);
|
||||
INIT_WORK(&hdev->power_off, hci_power_off);
|
||||
setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
|
||||
|
||||
memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
|
||||
|
||||
atomic_set(&hdev->promisc, 0);
|
||||
@@ -969,7 +1166,10 @@ int hci_register_dev(struct hci_dev *hdev)
|
||||
}
|
||||
}
|
||||
|
||||
mgmt_index_added(hdev->id);
|
||||
set_bit(HCI_AUTO_OFF, &hdev->flags);
|
||||
set_bit(HCI_SETUP, &hdev->flags);
|
||||
queue_work(hdev->workqueue, &hdev->power_on);
|
||||
|
||||
hci_notify(hdev, HCI_DEV_REG);
|
||||
|
||||
return id;
|
||||
@@ -999,7 +1199,10 @@ int hci_unregister_dev(struct hci_dev *hdev)
|
||||
for (i = 0; i < NUM_REASSEMBLY; i++)
|
||||
kfree_skb(hdev->reassembly[i]);
|
||||
|
||||
mgmt_index_removed(hdev->id);
|
||||
if (!test_bit(HCI_INIT, &hdev->flags) &&
|
||||
!test_bit(HCI_SETUP, &hdev->flags))
|
||||
mgmt_index_removed(hdev->id);
|
||||
|
||||
hci_notify(hdev, HCI_DEV_UNREG);
|
||||
|
||||
if (hdev->rfkill) {
|
||||
@@ -1009,10 +1212,14 @@ int hci_unregister_dev(struct hci_dev *hdev)
|
||||
|
||||
hci_unregister_sysfs(hdev);
|
||||
|
||||
hci_del_off_timer(hdev);
|
||||
|
||||
destroy_workqueue(hdev->workqueue);
|
||||
|
||||
hci_dev_lock_bh(hdev);
|
||||
hci_blacklist_clear(hdev);
|
||||
hci_uuids_clear(hdev);
|
||||
hci_link_keys_clear(hdev);
|
||||
hci_dev_unlock_bh(hdev);
|
||||
|
||||
__hci_dev_put(hdev);
|
||||
@@ -1313,7 +1520,7 @@ static int hci_send_frame(struct sk_buff *skb)
|
||||
/* Time stamp */
|
||||
__net_timestamp(skb);
|
||||
|
||||
hci_send_to_sock(hdev, skb);
|
||||
hci_send_to_sock(hdev, skb, NULL);
|
||||
}
|
||||
|
||||
/* Get rid of skb owner, prior to sending to the driver. */
|
||||
@@ -1349,6 +1556,9 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
|
||||
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);
|
||||
tasklet_schedule(&hdev->cmd_task);
|
||||
|
||||
@@ -1395,7 +1605,7 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
|
||||
|
||||
skb->dev = (void *) hdev;
|
||||
bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
|
||||
hci_add_acl_hdr(skb, conn->handle, flags | ACL_START);
|
||||
hci_add_acl_hdr(skb, conn->handle, flags);
|
||||
|
||||
list = skb_shinfo(skb)->frag_list;
|
||||
if (!list) {
|
||||
@@ -1413,12 +1623,15 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
|
||||
spin_lock_bh(&conn->data_q.lock);
|
||||
|
||||
__skb_queue_tail(&conn->data_q, 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 | ACL_CONT);
|
||||
hci_add_acl_hdr(skb, conn->handle, flags);
|
||||
|
||||
BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
|
||||
|
||||
@@ -1486,8 +1699,25 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
|
||||
}
|
||||
|
||||
if (conn) {
|
||||
int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt);
|
||||
int q = cnt / num;
|
||||
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;
|
||||
@@ -1496,19 +1726,19 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
|
||||
return conn;
|
||||
}
|
||||
|
||||
static inline void hci_acl_tx_to(struct hci_dev *hdev)
|
||||
static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
struct list_head *p;
|
||||
struct hci_conn *c;
|
||||
|
||||
BT_ERR("%s ACL tx timeout", hdev->name);
|
||||
BT_ERR("%s link tx timeout", hdev->name);
|
||||
|
||||
/* Kill stalled connections */
|
||||
list_for_each(p, &h->list) {
|
||||
c = list_entry(p, struct hci_conn, list);
|
||||
if (c->type == ACL_LINK && c->sent) {
|
||||
BT_ERR("%s killing stalled ACL connection %s",
|
||||
if (c->type == type && c->sent) {
|
||||
BT_ERR("%s killing stalled connection %s",
|
||||
hdev->name, batostr(&c->dst));
|
||||
hci_acl_disconn(c, 0x13);
|
||||
}
|
||||
@@ -1527,7 +1757,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
|
||||
/* ACL tx timeout must be longer than maximum
|
||||
* link supervision timeout (40.9 seconds) */
|
||||
if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + HZ * 45))
|
||||
hci_acl_tx_to(hdev);
|
||||
hci_link_tx_to(hdev, ACL_LINK);
|
||||
}
|
||||
|
||||
while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) {
|
||||
@@ -1586,6 +1816,40 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hci_sched_le(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
struct sk_buff *skb;
|
||||
int quote, cnt;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
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;
|
||||
while (cnt && (conn = hci_low_sent(hdev, LE_LINK, "e))) {
|
||||
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
|
||||
BT_DBG("skb %p len %d", skb, skb->len);
|
||||
|
||||
hci_send_frame(skb);
|
||||
hdev->le_last_tx = jiffies;
|
||||
|
||||
cnt--;
|
||||
conn->sent++;
|
||||
}
|
||||
}
|
||||
if (hdev->le_pkts)
|
||||
hdev->le_cnt = cnt;
|
||||
else
|
||||
hdev->acl_cnt = cnt;
|
||||
}
|
||||
|
||||
static void hci_tx_task(unsigned long arg)
|
||||
{
|
||||
struct hci_dev *hdev = (struct hci_dev *) arg;
|
||||
@@ -1593,7 +1857,8 @@ static void hci_tx_task(unsigned long arg)
|
||||
|
||||
read_lock(&hci_task_lock);
|
||||
|
||||
BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt);
|
||||
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 */
|
||||
|
||||
@@ -1603,6 +1868,8 @@ static void hci_tx_task(unsigned long arg)
|
||||
|
||||
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);
|
||||
@@ -1700,7 +1967,7 @@ static void hci_rx_task(unsigned long arg)
|
||||
while ((skb = skb_dequeue(&hdev->rx_q))) {
|
||||
if (atomic_read(&hdev->promisc)) {
|
||||
/* Send copy to the sockets */
|
||||
hci_send_to_sock(hdev, skb);
|
||||
hci_send_to_sock(hdev, skb, NULL);
|
||||
}
|
||||
|
||||
if (test_bit(HCI_RAW, &hdev->flags)) {
|
||||
@@ -1750,20 +2017,20 @@ static void hci_cmd_task(unsigned long arg)
|
||||
|
||||
BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
|
||||
|
||||
if (!atomic_read(&hdev->cmd_cnt) && time_after(jiffies, hdev->cmd_last_tx + HZ)) {
|
||||
BT_ERR("%s command tx timeout", hdev->name);
|
||||
atomic_set(&hdev->cmd_cnt, 1);
|
||||
}
|
||||
|
||||
/* Send queued commands */
|
||||
if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) {
|
||||
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);
|
||||
hdev->cmd_last_tx = jiffies;
|
||||
mod_timer(&hdev->cmd_timer,
|
||||
jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT));
|
||||
} else {
|
||||
skb_queue_head(&hdev->cmd_q, skb);
|
||||
tasklet_schedule(&hdev->cmd_task);
|
||||
|
@@ -274,15 +274,24 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
if (!status) {
|
||||
__u8 param = *((__u8 *) sent);
|
||||
int old_pscan, old_iscan;
|
||||
|
||||
clear_bit(HCI_PSCAN, &hdev->flags);
|
||||
clear_bit(HCI_ISCAN, &hdev->flags);
|
||||
old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags);
|
||||
old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags);
|
||||
|
||||
if (param & SCAN_INQUIRY)
|
||||
if (param & SCAN_INQUIRY) {
|
||||
set_bit(HCI_ISCAN, &hdev->flags);
|
||||
if (!old_iscan)
|
||||
mgmt_discoverable(hdev->id, 1);
|
||||
} else if (old_iscan)
|
||||
mgmt_discoverable(hdev->id, 0);
|
||||
|
||||
if (param & SCAN_PAGE)
|
||||
if (param & SCAN_PAGE) {
|
||||
set_bit(HCI_PSCAN, &hdev->flags);
|
||||
if (!old_pscan)
|
||||
mgmt_connectable(hdev->id, 1);
|
||||
} else if (old_pscan)
|
||||
mgmt_connectable(hdev->id, 0);
|
||||
}
|
||||
|
||||
hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status);
|
||||
@@ -415,6 +424,115 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hdev->ssp_mode = *((__u8 *) sent);
|
||||
}
|
||||
|
||||
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 };
|
||||
|
||||
/* Events for 1.2 and newer controllers */
|
||||
if (hdev->lmp_ver > 1) {
|
||||
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] |= 0x04; /* 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)
|
||||
{
|
||||
hci_setup_event_mask(hdev);
|
||||
|
||||
if (hdev->lmp_ver > 1)
|
||||
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
|
||||
|
||||
if (hdev->features[6] & LMP_SIMPLE_PAIR) {
|
||||
u8 mode = 0x01;
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -426,11 +544,34 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -440,9 +581,15 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb
|
||||
BT_DBG("%s status 0x%x", hdev->name, rp->status);
|
||||
|
||||
if (rp->status)
|
||||
return;
|
||||
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)
|
||||
@@ -548,6 +695,130 @@ static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, 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);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_pin_code_reply_complete(hdev->id, &rp->bdaddr, rp->status);
|
||||
|
||||
if (rp->status != 0)
|
||||
return;
|
||||
|
||||
cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
|
||||
if (!cp)
|
||||
return;
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
|
||||
if (conn)
|
||||
conn->pin_length = cp->pin_len;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_pin_code_neg_reply_complete(hdev->id, &rp->bdaddr,
|
||||
rp->status);
|
||||
}
|
||||
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);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_user_confirm_reply_complete(hdev->id, &rp->bdaddr,
|
||||
rp->status);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_user_confirm_neg_reply_complete(hdev->id, &rp->bdaddr,
|
||||
rp->status);
|
||||
}
|
||||
|
||||
static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
|
||||
{
|
||||
BT_DBG("%s status 0x%x", hdev->name, status);
|
||||
@@ -622,11 +893,14 @@ static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status)
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
acl = hci_conn_hash_lookup_handle(hdev, handle);
|
||||
if (acl && (sco = acl->link)) {
|
||||
sco->state = BT_CLOSED;
|
||||
if (acl) {
|
||||
sco = acl->link;
|
||||
if (sco) {
|
||||
sco->state = BT_CLOSED;
|
||||
|
||||
hci_proto_connect_cfm(sco, status);
|
||||
hci_conn_del(sco);
|
||||
hci_proto_connect_cfm(sco, status);
|
||||
hci_conn_del(sco);
|
||||
}
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
@@ -687,7 +961,7 @@ static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status)
|
||||
}
|
||||
|
||||
static int hci_outgoing_auth_needed(struct hci_dev *hdev,
|
||||
struct hci_conn *conn)
|
||||
struct hci_conn *conn)
|
||||
{
|
||||
if (conn->state != BT_CONFIG || !conn->out)
|
||||
return 0;
|
||||
@@ -808,11 +1082,14 @@ static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status)
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
acl = hci_conn_hash_lookup_handle(hdev, handle);
|
||||
if (acl && (sco = acl->link)) {
|
||||
sco->state = BT_CLOSED;
|
||||
if (acl) {
|
||||
sco = acl->link;
|
||||
if (sco) {
|
||||
sco->state = BT_CLOSED;
|
||||
|
||||
hci_proto_connect_cfm(sco, status);
|
||||
hci_conn_del(sco);
|
||||
hci_proto_connect_cfm(sco, status);
|
||||
hci_conn_del(sco);
|
||||
}
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
@@ -872,6 +1149,43 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 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->out = 1;
|
||||
else
|
||||
BT_ERR("No memory for new connection");
|
||||
}
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
@@ -942,6 +1256,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
||||
conn->state = BT_CONFIG;
|
||||
hci_conn_hold(conn);
|
||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
mgmt_connected(hdev->id, &ev->bdaddr);
|
||||
} else
|
||||
conn->state = BT_CONNECTED;
|
||||
|
||||
@@ -970,8 +1285,11 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
||||
hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE,
|
||||
sizeof(cp), &cp);
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
conn->state = BT_CLOSED;
|
||||
if (conn->type == ACL_LINK)
|
||||
mgmt_connect_failed(hdev->id, &ev->bdaddr, ev->status);
|
||||
}
|
||||
|
||||
if (conn->type == ACL_LINK)
|
||||
hci_sco_setup(conn, ev->status);
|
||||
@@ -998,7 +1316,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
|
||||
|
||||
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
|
||||
|
||||
if ((mask & HCI_LM_ACCEPT) && !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
|
||||
if ((mask & HCI_LM_ACCEPT) &&
|
||||
!hci_blacklist_lookup(hdev, &ev->bdaddr)) {
|
||||
/* Connection accepted */
|
||||
struct inquiry_entry *ie;
|
||||
struct hci_conn *conn;
|
||||
@@ -1068,19 +1387,26 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
|
||||
|
||||
BT_DBG("%s status %d", hdev->name, ev->status);
|
||||
|
||||
if (ev->status)
|
||||
if (ev->status) {
|
||||
mgmt_disconnect_failed(hdev->id);
|
||||
return;
|
||||
}
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
|
||||
if (conn) {
|
||||
conn->state = BT_CLOSED;
|
||||
if (!conn)
|
||||
goto unlock;
|
||||
|
||||
hci_proto_disconn_cfm(conn, ev->reason);
|
||||
hci_conn_del(conn);
|
||||
}
|
||||
conn->state = BT_CLOSED;
|
||||
|
||||
if (conn->type == ACL_LINK)
|
||||
mgmt_disconnected(hdev->id, &conn->dst);
|
||||
|
||||
hci_proto_disconn_cfm(conn, ev->reason);
|
||||
hci_conn_del(conn);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
@@ -1098,8 +1424,10 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
||||
if (!ev->status) {
|
||||
conn->link_mode |= HCI_LM_AUTH;
|
||||
conn->sec_level = conn->pending_sec_level;
|
||||
} else
|
||||
} else {
|
||||
mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
|
||||
conn->sec_level = BT_SECURITY_LOW;
|
||||
}
|
||||
|
||||
clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
|
||||
|
||||
@@ -1393,11 +1721,54 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
|
||||
hci_cc_write_ca_timeout(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_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;
|
||||
|
||||
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))
|
||||
@@ -1459,11 +1830,23 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_cs_exit_sniff_mode(hdev, ev->status);
|
||||
break;
|
||||
|
||||
case HCI_OP_DISCONNECT:
|
||||
if (ev->status != 0)
|
||||
mgmt_disconnect_failed(hdev->id);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_CREATE_CONN:
|
||||
hci_cs_le_create_conn(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) {
|
||||
atomic_set(&hdev->cmd_cnt, 1);
|
||||
if (!skb_queue_empty(&hdev->cmd_q))
|
||||
@@ -1529,6 +1912,16 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
|
||||
hdev->acl_cnt += count;
|
||||
if (hdev->acl_cnt > hdev->acl_pkts)
|
||||
hdev->acl_cnt = hdev->acl_pkts;
|
||||
} else if (conn->type == 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;
|
||||
}
|
||||
} else {
|
||||
hdev->sco_cnt += count;
|
||||
if (hdev->sco_cnt > hdev->sco_pkts)
|
||||
@@ -1586,18 +1979,72 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
|
||||
hci_conn_put(conn);
|
||||
}
|
||||
|
||||
if (!test_bit(HCI_PAIRABLE, &hdev->flags))
|
||||
hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
|
||||
sizeof(ev->bdaddr), &ev->bdaddr);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_pin_code_request(hdev->id, &ev->bdaddr);
|
||||
|
||||
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->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->flags) && key->type == 0x03) {
|
||||
BT_DBG("%s ignoring debug key", hdev->name);
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
|
||||
|
||||
if (key->type == 0x04 && conn && conn->auth_type != 0xff &&
|
||||
(conn->auth_type & 0x01)) {
|
||||
BT_DBG("%s ignoring unauthenticated key", hdev->name);
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -1607,9 +2054,14 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
|
||||
if (conn) {
|
||||
hci_conn_hold(conn);
|
||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
pin_len = conn->pin_length;
|
||||
hci_conn_put(conn);
|
||||
}
|
||||
|
||||
if (test_bit(HCI_LINK_KEYS, &hdev->flags))
|
||||
hci_add_link_key(hdev, 1, &ev->bdaddr, ev->link_key,
|
||||
ev->key_type, pin_len);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
@@ -1683,7 +2135,8 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
|
||||
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 = (void *) (skb->data + 1);
|
||||
struct inquiry_info_with_rssi_and_pscan_mode *info;
|
||||
info = (void *) (skb->data + 1);
|
||||
|
||||
for (; num_rsp; num_rsp--) {
|
||||
bacpy(&data.bdaddr, &info->bdaddr);
|
||||
@@ -1824,17 +2277,8 @@ static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buf
|
||||
static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_sniff_subrate *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) {
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
@@ -1852,12 +2296,12 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
|
||||
|
||||
for (; num_rsp; num_rsp--) {
|
||||
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;
|
||||
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.clock_offset = info->clock_offset;
|
||||
data.rssi = info->rssi;
|
||||
data.ssp_mode = 0x01;
|
||||
info++;
|
||||
hci_inquiry_cache_update(hdev, &data);
|
||||
@@ -1866,6 +2310,25 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
|
||||
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 0x00;
|
||||
|
||||
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;
|
||||
@@ -1876,8 +2339,73 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
|
||||
if (conn)
|
||||
hci_conn_hold(conn);
|
||||
if (!conn)
|
||||
goto unlock;
|
||||
|
||||
hci_conn_hold(conn);
|
||||
|
||||
if (!test_bit(HCI_MGMT, &hdev->flags))
|
||||
goto unlock;
|
||||
|
||||
if (test_bit(HCI_PAIRABLE, &hdev->flags) ||
|
||||
(conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) {
|
||||
struct hci_cp_io_capability_reply cp;
|
||||
|
||||
bacpy(&cp.bdaddr, &ev->bdaddr);
|
||||
cp.capability = conn->io_capability;
|
||||
cp.oob_data = 0;
|
||||
cp.authentication = hci_get_auth_req(conn);
|
||||
|
||||
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 = 0x16; /* 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;
|
||||
|
||||
hci_conn_hold(conn);
|
||||
|
||||
conn->remote_cap = ev->capability;
|
||||
conn->remote_oob = ev->oob_data;
|
||||
conn->remote_auth = ev->authentication;
|
||||
|
||||
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;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
@@ -1892,9 +2420,20 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
|
||||
if (conn)
|
||||
hci_conn_put(conn);
|
||||
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->pend) && ev->status != 0)
|
||||
mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
|
||||
|
||||
hci_conn_put(conn);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
@@ -1914,6 +2453,60 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (ev->status) {
|
||||
hci_proto_connect_cfm(conn, ev->status);
|
||||
conn->state = BT_CLOSED;
|
||||
hci_conn_del(conn);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
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_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;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_event_hdr *hdr = (void *) skb->data;
|
||||
@@ -2042,6 +2635,14 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
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_SIMPLE_PAIR_COMPLETE:
|
||||
hci_simple_pair_complete_evt(hdev, skb);
|
||||
break;
|
||||
@@ -2050,6 +2651,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_remote_host_features_evt(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_EV_LE_META:
|
||||
hci_le_meta_evt(hdev, skb);
|
||||
break;
|
||||
|
||||
default:
|
||||
BT_DBG("%s event 0x%x", hdev->name, event);
|
||||
break;
|
||||
@@ -2083,6 +2688,6 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
|
||||
|
||||
bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
|
||||
skb->dev = (void *) hdev;
|
||||
hci_send_to_sock(hdev, skb);
|
||||
hci_send_to_sock(hdev, skb, NULL);
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
@@ -85,7 +85,8 @@ static struct bt_sock_list hci_sk_list = {
|
||||
};
|
||||
|
||||
/* Send frame to RAW socket */
|
||||
void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
|
||||
struct sock *skip_sk)
|
||||
{
|
||||
struct sock *sk;
|
||||
struct hlist_node *node;
|
||||
@@ -97,6 +98,9 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
struct hci_filter *flt;
|
||||
struct sk_buff *nskb;
|
||||
|
||||
if (sk == skip_sk)
|
||||
continue;
|
||||
|
||||
if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev)
|
||||
continue;
|
||||
|
||||
@@ -857,7 +861,7 @@ error:
|
||||
return err;
|
||||
}
|
||||
|
||||
void __exit hci_sock_cleanup(void)
|
||||
void hci_sock_cleanup(void)
|
||||
{
|
||||
if (bt_sock_unregister(BTPROTO_HCI) < 0)
|
||||
BT_ERR("HCI socket unregistration failed");
|
||||
|
@@ -11,7 +11,7 @@
|
||||
|
||||
static struct class *bt_class;
|
||||
|
||||
struct dentry *bt_debugfs = NULL;
|
||||
struct dentry *bt_debugfs;
|
||||
EXPORT_SYMBOL_GPL(bt_debugfs);
|
||||
|
||||
static inline char *link_typetostr(int type)
|
||||
@@ -51,8 +51,8 @@ static ssize_t show_link_features(struct device *dev, struct device_attribute *a
|
||||
conn->features[6], conn->features[7]);
|
||||
}
|
||||
|
||||
#define LINK_ATTR(_name,_mode,_show,_store) \
|
||||
struct device_attribute link_attr_##_name = __ATTR(_name,_mode,_show,_store)
|
||||
#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);
|
||||
@@ -461,6 +461,56 @@ static const struct file_operations blacklist_fops = {
|
||||
.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 list_head *l;
|
||||
|
||||
hci_dev_lock_bh(hdev);
|
||||
|
||||
list_for_each(l, &hdev->uuids) {
|
||||
struct bt_uuid *uuid;
|
||||
|
||||
uuid = list_entry(l, struct bt_uuid, list);
|
||||
|
||||
print_bt_uuid(f, uuid->uuid);
|
||||
}
|
||||
|
||||
hci_dev_unlock_bh(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,
|
||||
};
|
||||
|
||||
int hci_register_sysfs(struct hci_dev *hdev)
|
||||
{
|
||||
struct device *dev = &hdev->dev;
|
||||
@@ -493,6 +543,8 @@ int hci_register_sysfs(struct hci_dev *hdev)
|
||||
debugfs_create_file("blacklist", 0444, hdev->debugfs,
|
||||
hdev, &blacklist_fops);
|
||||
|
||||
debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -157,7 +157,8 @@ static int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
|
||||
|
||||
session->leds = newleds;
|
||||
|
||||
if (!(skb = alloc_skb(3, GFP_ATOMIC))) {
|
||||
skb = alloc_skb(3, GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
BT_ERR("Can't allocate memory for new frame");
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -250,7 +251,8 @@ static int __hidp_send_ctrl_message(struct hidp_session *session,
|
||||
|
||||
BT_DBG("session %p data %p size %d", session, data, size);
|
||||
|
||||
if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
|
||||
skb = alloc_skb(size + 1, GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
BT_ERR("Can't allocate memory for new frame");
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -283,7 +285,8 @@ static int hidp_queue_report(struct hidp_session *session,
|
||||
|
||||
BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
|
||||
|
||||
if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
|
||||
skb = alloc_skb(size + 1, GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
BT_ERR("Can't allocate memory for new frame");
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -1016,8 +1019,6 @@ static int __init hidp_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
l2cap_load();
|
||||
|
||||
BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
|
||||
|
||||
ret = hid_register_driver(&hidp_driver);
|
||||
|
File diff suppressed because it is too large
Load Diff
1156
net/bluetooth/l2cap_sock.c
Normal file
1156
net/bluetooth/l2cap_sock.c
Normal file
File diff suppressed because it is too large
Load Diff
1569
net/bluetooth/mgmt.c
1569
net/bluetooth/mgmt.c
File diff suppressed because it is too large
Load Diff
@@ -2154,8 +2154,6 @@ static int __init rfcomm_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
l2cap_load();
|
||||
|
||||
hci_register_cb(&rfcomm_cb);
|
||||
|
||||
rfcomm_thread = kthread_run(rfcomm_run, NULL, "krfcommd");
|
||||
|
@@ -50,8 +50,6 @@
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <net/bluetooth/sco.h>
|
||||
|
||||
#define VERSION "0.6"
|
||||
|
||||
static int disable_esco;
|
||||
|
||||
static const struct proto_ops sco_sock_ops;
|
||||
@@ -192,20 +190,21 @@ static int sco_connect(struct sock *sk)
|
||||
|
||||
hci_dev_lock_bh(hdev);
|
||||
|
||||
err = -ENOMEM;
|
||||
|
||||
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 (!hcon)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -703,6 +702,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user
|
||||
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);
|
||||
|
||||
@@ -1023,7 +1023,7 @@ static struct hci_proto sco_hci_proto = {
|
||||
.recv_scodata = sco_recv_scodata
|
||||
};
|
||||
|
||||
static int __init sco_init(void)
|
||||
int __init sco_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
@@ -1051,7 +1051,6 @@ static int __init sco_init(void)
|
||||
BT_ERR("Failed to create SCO debug file");
|
||||
}
|
||||
|
||||
BT_INFO("SCO (Voice Link) ver %s", VERSION);
|
||||
BT_INFO("SCO socket layer initialized");
|
||||
|
||||
return 0;
|
||||
@@ -1061,7 +1060,7 @@ error:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit sco_exit(void)
|
||||
void __exit sco_exit(void)
|
||||
{
|
||||
debugfs_remove(sco_debugfs);
|
||||
|
||||
@@ -1074,14 +1073,5 @@ static void __exit sco_exit(void)
|
||||
proto_unregister(&sco_proto);
|
||||
}
|
||||
|
||||
module_init(sco_init);
|
||||
module_exit(sco_exit);
|
||||
|
||||
module_param(disable_esco, bool, 0644);
|
||||
MODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation");
|
||||
|
||||
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
|
||||
MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("bt-proto-2");
|
||||
|
Reference in New Issue
Block a user