Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next

This commit is contained in:
John W. Linville 2012-01-02 16:43:54 -05:00
commit dc0d633e35
21 changed files with 496 additions and 459 deletions

View File

@ -101,6 +101,7 @@ static struct usb_device_id btusb_table[] = {
{ USB_DEVICE(0x0c10, 0x0000) },
/* Broadcom BCM20702A0 */
{ USB_DEVICE(0x0a5c, 0x21e3) },
{ USB_DEVICE(0x413c, 0x8197) },
{ } /* Terminating entry */
@ -508,15 +509,10 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress);
urb->dev = data->udev;
urb->pipe = pipe;
urb->context = hdev;
urb->complete = btusb_isoc_complete;
urb->interval = data->isoc_rx_ep->bInterval;
usb_fill_int_urb(urb, data->udev, pipe, buf, size, btusb_isoc_complete,
hdev, data->isoc_rx_ep->bInterval);
urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP;
urb->transfer_buffer = buf;
urb->transfer_buffer_length = size;
__fill_isoc_descriptor(urb, size,
le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize));

View File

@ -250,32 +250,10 @@ extern void bt_sysfs_cleanup(void);
extern struct dentry *bt_debugfs;
#ifdef CONFIG_BT_L2CAP
int l2cap_init(void);
void l2cap_exit(void);
#else
static inline int l2cap_init(void)
{
return 0;
}
static inline void l2cap_exit(void)
{
}
#endif
#ifdef CONFIG_BT_SCO
int sco_init(void);
void sco_exit(void);
#else
static inline int sco_init(void)
{
return 0;
}
static inline void sco_exit(void)
{
}
#endif
#endif /* __BLUETOOTH_H */

View File

@ -280,6 +280,10 @@ enum {
#define HCI_ERROR_LOCAL_HOST_TERM 0x16
#define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18
/* Flow control modes */
#define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00
#define HCI_FLOW_CTL_MODE_BLOCK_BASED 0x01
/* ----- HCI Commands ---- */
#define HCI_OP_NOP 0x0000
@ -800,6 +804,9 @@ struct hci_cp_le_set_scan_param {
__u8 filter_policy;
} __packed;
#define LE_SCANNING_DISABLED 0x00
#define LE_SCANNING_ENABLED 0x01
#define HCI_OP_LE_SET_SCAN_ENABLE 0x200c
struct hci_cp_le_set_scan_enable {
__u8 enable;
@ -975,9 +982,14 @@ struct hci_ev_role_change {
} __packed;
#define HCI_EV_NUM_COMP_PKTS 0x13
struct hci_comp_pkts_info {
__le16 handle;
__le16 count;
} __packed;
struct hci_ev_num_comp_pkts {
__u8 num_hndl;
/* variable length part */
struct hci_comp_pkts_info handles[0];
} __packed;
#define HCI_EV_MODE_CHANGE 0x14

View File

@ -28,10 +28,6 @@
#include <linux/interrupt.h>
#include <net/bluetooth/hci.h>
/* HCI upper protocols */
#define HCI_PROTO_L2CAP 0
#define HCI_PROTO_SCO 1
/* HCI priority */
#define HCI_PRIO_MAX 7
@ -54,7 +50,6 @@ struct inquiry_entry {
};
struct inquiry_cache {
spinlock_t lock;
__u32 timestamp;
struct inquiry_entry *list;
};
@ -314,6 +309,7 @@ struct hci_conn {
struct hci_dev *hdev;
void *l2cap_data;
void *sco_data;
void *smp_conn;
struct hci_conn *link;
@ -330,25 +326,31 @@ struct hci_chan {
unsigned int sent;
};
extern struct hci_proto *hci_proto[];
extern struct list_head hci_dev_list;
extern struct list_head hci_cb_list;
extern rwlock_t hci_dev_list_lock;
extern rwlock_t hci_cb_list_lock;
/* ----- HCI interface to upper protocols ----- */
extern int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
extern int l2cap_connect_cfm(struct hci_conn *hcon, u8 status);
extern int l2cap_disconn_ind(struct hci_conn *hcon);
extern int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason);
extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt);
extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags);
extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
extern int sco_connect_cfm(struct hci_conn *hcon, __u8 status);
extern int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason);
extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);
/* ----- Inquiry cache ----- */
#define INQUIRY_CACHE_AGE_MAX (HZ*30) /* 30 seconds */
#define INQUIRY_ENTRY_AGE_MAX (HZ*60) /* 60 seconds */
#define inquiry_cache_lock(c) spin_lock(&c->lock)
#define inquiry_cache_unlock(c) spin_unlock(&c->lock)
#define inquiry_cache_lock_bh(c) spin_lock_bh(&c->lock)
#define inquiry_cache_unlock_bh(c) spin_unlock_bh(&c->lock)
static inline void inquiry_cache_init(struct hci_dev *hdev)
{
struct inquiry_cache *c = &hdev->inq_cache;
spin_lock_init(&c->lock);
c->list = NULL;
}
@ -677,53 +679,40 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_host_le_capable(dev) ((dev)->extfeatures[0] & LMP_HOST_LE)
/* ----- HCI protocols ----- */
struct hci_proto {
char *name;
unsigned int id;
unsigned long flags;
void *priv;
int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr,
__u8 type);
int (*connect_cfm) (struct hci_conn *conn, __u8 status);
int (*disconn_ind) (struct hci_conn *conn);
int (*disconn_cfm) (struct hci_conn *conn, __u8 reason);
int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb,
__u16 flags);
int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb);
int (*security_cfm) (struct hci_conn *conn, __u8 status,
__u8 encrypt);
};
static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
__u8 type)
{
register struct hci_proto *hp;
int mask = 0;
switch (type) {
case ACL_LINK:
return l2cap_connect_ind(hdev, bdaddr);
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->connect_ind)
mask |= hp->connect_ind(hdev, bdaddr, type);
case SCO_LINK:
case ESCO_LINK:
return sco_connect_ind(hdev, bdaddr);
hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->connect_ind)
mask |= hp->connect_ind(hdev, bdaddr, type);
return mask;
default:
BT_ERR("unknown link type %d", type);
return -EINVAL;
}
}
static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
{
register struct hci_proto *hp;
switch (conn->type) {
case ACL_LINK:
case LE_LINK:
l2cap_connect_cfm(conn, status);
break;
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->connect_cfm)
hp->connect_cfm(conn, status);
case SCO_LINK:
case ESCO_LINK:
sco_connect_cfm(conn, status);
break;
hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->connect_cfm)
hp->connect_cfm(conn, status);
default:
BT_ERR("unknown link type %d", conn->type);
break;
}
if (conn->connect_cfm_cb)
conn->connect_cfm_cb(conn, status);
@ -731,31 +720,29 @@ static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
static inline int hci_proto_disconn_ind(struct hci_conn *conn)
{
register struct hci_proto *hp;
int reason = HCI_ERROR_REMOTE_USER_TERM;
if (conn->type != ACL_LINK && conn->type != LE_LINK)
return HCI_ERROR_REMOTE_USER_TERM;
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->disconn_ind)
reason = hp->disconn_ind(conn);
hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->disconn_ind)
reason = hp->disconn_ind(conn);
return reason;
return l2cap_disconn_ind(conn);
}
static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
{
register struct hci_proto *hp;
switch (conn->type) {
case ACL_LINK:
case LE_LINK:
l2cap_disconn_cfm(conn, reason);
break;
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->disconn_cfm)
hp->disconn_cfm(conn, reason);
case SCO_LINK:
case ESCO_LINK:
sco_disconn_cfm(conn, reason);
break;
hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->disconn_cfm)
hp->disconn_cfm(conn, reason);
default:
BT_ERR("unknown link type %d", conn->type);
break;
}
if (conn->disconn_cfm_cb)
conn->disconn_cfm_cb(conn, reason);
@ -763,21 +750,16 @@ static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
{
register struct hci_proto *hp;
__u8 encrypt;
if (conn->type != ACL_LINK && conn->type != LE_LINK)
return;
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
return;
encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->security_cfm)
hp->security_cfm(conn, status, encrypt);
hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->security_cfm)
hp->security_cfm(conn, status, encrypt);
l2cap_security_cfm(conn, status, encrypt);
if (conn->security_cfm_cb)
conn->security_cfm_cb(conn, status);
@ -786,23 +768,15 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status,
__u8 encrypt)
{
register struct hci_proto *hp;
if (conn->type != ACL_LINK && conn->type != LE_LINK)
return;
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->security_cfm)
hp->security_cfm(conn, status, encrypt);
hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->security_cfm)
hp->security_cfm(conn, status, encrypt);
l2cap_security_cfm(conn, status, encrypt);
if (conn->security_cfm_cb)
conn->security_cfm_cb(conn, status);
}
int hci_register_proto(struct hci_proto *hproto);
int hci_unregister_proto(struct hci_proto *hproto);
/* ----- HCI callbacks ----- */
struct hci_cb {
struct list_head list;
@ -827,13 +801,13 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
read_lock_bh(&hci_cb_list_lock);
read_lock(&hci_cb_list_lock);
list_for_each(p, &hci_cb_list) {
struct hci_cb *cb = list_entry(p, struct hci_cb, list);
if (cb->security_cfm)
cb->security_cfm(conn, status, encrypt);
}
read_unlock_bh(&hci_cb_list_lock);
read_unlock(&hci_cb_list_lock);
}
static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
@ -849,26 +823,26 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
hci_proto_encrypt_cfm(conn, status, encrypt);
read_lock_bh(&hci_cb_list_lock);
read_lock(&hci_cb_list_lock);
list_for_each(p, &hci_cb_list) {
struct hci_cb *cb = list_entry(p, struct hci_cb, list);
if (cb->security_cfm)
cb->security_cfm(conn, status, encrypt);
}
read_unlock_bh(&hci_cb_list_lock);
read_unlock(&hci_cb_list_lock);
}
static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status)
{
struct list_head *p;
read_lock_bh(&hci_cb_list_lock);
read_lock(&hci_cb_list_lock);
list_for_each(p, &hci_cb_list) {
struct hci_cb *cb = list_entry(p, struct hci_cb, list);
if (cb->key_change_cfm)
cb->key_change_cfm(conn, status);
}
read_unlock_bh(&hci_cb_list_lock);
read_unlock(&hci_cb_list_lock);
}
static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
@ -876,13 +850,13 @@ static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
{
struct list_head *p;
read_lock_bh(&hci_cb_list_lock);
read_lock(&hci_cb_list_lock);
list_for_each(p, &hci_cb_list) {
struct hci_cb *cb = list_entry(p, struct hci_cb, list);
if (cb->role_switch_cfm)
cb->role_switch_cfm(conn, status, role);
}
read_unlock_bh(&hci_cb_list_lock);
read_unlock(&hci_cb_list_lock);
}
int hci_register_cb(struct hci_cb *hcb);

View File

@ -522,7 +522,7 @@ struct l2cap_conn {
__u8 info_state;
__u8 info_ident;
struct delayed_work info_work;
struct delayed_work info_timer;
spinlock_t lock;
@ -532,7 +532,7 @@ struct l2cap_conn {
__u8 disc_reason;
struct timer_list security_timer;
struct delayed_work security_timer;
struct smp_chan *smp_chan;
struct list_head chan_l;
@ -595,17 +595,45 @@ enum {
FLAG_EFS_ENABLE,
};
static inline void l2cap_chan_hold(struct l2cap_chan *c)
{
atomic_inc(&c->refcnt);
}
static inline void l2cap_chan_put(struct l2cap_chan *c)
{
if (atomic_dec_and_test(&c->refcnt))
kfree(c);
}
static inline void l2cap_set_timer(struct l2cap_chan *chan,
struct delayed_work *work, long timeout)
{
BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
if (!__cancel_delayed_work(work))
l2cap_chan_hold(chan);
schedule_delayed_work(work, timeout);
}
static inline void l2cap_clear_timer(struct l2cap_chan *chan,
struct delayed_work *work)
{
if (__cancel_delayed_work(work))
l2cap_chan_put(chan);
}
#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
#define __clear_chan_timer(c) l2cap_clear_timer(&c->chan_timer)
#define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
#define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
L2CAP_DEFAULT_RETRANS_TO);
#define __clear_retrans_timer(c) l2cap_clear_timer(&c->retrans_timer)
#define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer)
#define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \
L2CAP_DEFAULT_MONITOR_TO);
#define __clear_monitor_timer(c) l2cap_clear_timer(&c->monitor_timer)
#define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer)
#define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \
L2CAP_DEFAULT_ACK_TO);
#define __clear_ack_timer(c) l2cap_clear_timer(&c->ack_timer)
#define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer)
static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2)
{

View File

@ -115,6 +115,10 @@ struct smp_cmd_security_req {
#define SMP_MIN_ENC_KEY_SIZE 7
#define SMP_MAX_ENC_KEY_SIZE 16
#define SMP_FLAG_TK_VALID 1
#define SMP_FLAG_CFM_PENDING 2
#define SMP_FLAG_MITM_AUTH 3
struct smp_chan {
struct l2cap_conn *conn;
u8 preq[7]; /* SMP Pairing Request */
@ -124,6 +128,7 @@ struct smp_chan {
u8 pcnf[16]; /* SMP Pairing Confirm */
u8 tk[16]; /* SMP Temporary Key */
u8 smp_key_size;
unsigned long smp_flags;
struct crypto_blkcipher *tfm;
struct work_struct confirm;
struct work_struct random;
@ -134,6 +139,7 @@ struct smp_chan {
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level);
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
int smp_distribute_keys(struct l2cap_conn *conn, __u8 force);
int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey);
void smp_chan_destroy(struct l2cap_conn *conn);

View File

@ -6,7 +6,11 @@ menuconfig BT
tristate "Bluetooth subsystem support"
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
@ -15,10 +19,12 @@ menuconfig BT
Bluetooth can be found at <http://www.bluetooth.com/>.
Linux Bluetooth subsystem consist of several layers:
Bluetooth Core (HCI device and connection manager, scheduler)
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)
SCO Module (SCO audio links)
L2CAP Module (Logical Link Control and Adaptation Protocol)
RFCOMM Module (RFCOMM Protocol)
BNEP Module (Bluetooth Network Encapsulation Protocol)
CMTP Module (CAPI Message Transport Protocol)
@ -33,31 +39,6 @@ menuconfig BT
to Bluetooth kernel modules are provided in the BlueZ packages. For
more information, see <http://www.bluez.org/>.
if BT != n
config BT_L2CAP
bool "L2CAP protocol support"
select CRC16
select CRYPTO
select CRYPTO_BLKCIPHER
select CRYPTO_AES
select CRYPTO_ECB
help
L2CAP (Logical Link Control and Adaptation Protocol) provides
connection oriented and connection-less data transport. L2CAP
support is required for most Bluetooth applications.
Also included is support for SMP (Security Manager Protocol) which
is the security layer on top of LE (Low Energy) links.
config BT_SCO
bool "SCO links support"
help
SCO link provides voice transport over Bluetooth. SCO support is
required for voice applications like Headset and Audio.
endif
source "net/bluetooth/rfcomm/Kconfig"
source "net/bluetooth/bnep/Kconfig"

View File

@ -8,6 +8,5 @@ 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 smp.o
bluetooth-$(CONFIG_BT_SCO) += sco.o
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

View File

@ -199,15 +199,14 @@ 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);
bh_lock_sock(sk);
lock_sock(sk);
/* FIXME: Is this check still needed */
if (sk->sk_state == BT_CLOSED) {
bh_unlock_sock(sk);
release_sock(sk);
bt_accept_unlink(sk);
continue;
}
@ -218,14 +217,12 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
if (newsock)
sock_graft(sk, newsock);
bh_unlock_sock(sk);
local_bh_enable();
release_sock(sk);
return sk;
}
bh_unlock_sock(sk);
release_sock(sk);
}
local_bh_enable();
return NULL;
}

View File

@ -1,6 +1,6 @@
config BT_BNEP
tristate "BNEP protocol support"
depends on BT && BT_L2CAP
depends on BT
select CRC32
help
BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet

View File

@ -1,6 +1,6 @@
config BT_CMTP
tristate "CMTP protocol support"
depends on BT && BT_L2CAP && ISDN_CAPI
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

View File

@ -487,7 +487,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
BT_DBG("%s -> %s", batostr(src), batostr(dst));
read_lock_bh(&hci_dev_list_lock);
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))
@ -512,7 +512,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
if (hdev)
hdev = hci_dev_hold(hdev);
read_unlock_bh(&hci_dev_list_lock);
read_unlock(&hci_dev_list_lock);
return hdev;
}
EXPORT_SYMBOL(hci_get_route);

View File

@ -61,8 +61,6 @@ 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);
static DEFINE_MUTEX(hci_task_lock);
/* HCI device list */
LIST_HEAD(hci_dev_list);
DEFINE_RWLOCK(hci_dev_list_lock);
@ -71,10 +69,6 @@ DEFINE_RWLOCK(hci_dev_list_lock);
LIST_HEAD(hci_cb_list);
DEFINE_RWLOCK(hci_cb_list_lock);
/* HCI protocols */
#define HCI_MAX_PROTO 2
struct hci_proto *hci_proto[HCI_MAX_PROTO];
/* HCI notifiers list */
static ATOMIC_NOTIFIER_HEAD(hci_notifier);
@ -193,33 +187,20 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
}
static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
static void bredr_init(struct hci_dev *hdev)
{
struct hci_cp_delete_stored_link_key cp;
struct sk_buff *skb;
__le16 param;
__u8 flt_type;
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);
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);
set_bit(HCI_RESET, &hdev->flags);
hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
}
/* Read Local Supported Features */
@ -258,6 +239,51 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
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);
@ -818,7 +844,7 @@ int hci_get_dev_list(void __user *arg)
dr = dl->dev_req;
read_lock_bh(&hci_dev_list_lock);
read_lock(&hci_dev_list_lock);
list_for_each_entry(hdev, &hci_dev_list, list) {
if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
cancel_delayed_work(&hdev->power_off);
@ -832,7 +858,7 @@ int hci_get_dev_list(void __user *arg)
if (++n >= dev_num)
break;
}
read_unlock_bh(&hci_dev_list_lock);
read_unlock(&hci_dev_list_lock);
dl->dev_num = n;
size = sizeof(*dl) + n * sizeof(*dr);
@ -1432,7 +1458,7 @@ int hci_register_dev(struct hci_dev *hdev)
*/
id = (hdev->dev_type == HCI_BREDR) ? 0 : 1;
write_lock_bh(&hci_dev_list_lock);
write_lock(&hci_dev_list_lock);
/* Find first available device id */
list_for_each(p, &hci_dev_list) {
@ -1502,7 +1528,7 @@ int hci_register_dev(struct hci_dev *hdev)
atomic_set(&hdev->promisc, 0);
write_unlock_bh(&hci_dev_list_lock);
write_unlock(&hci_dev_list_lock);
hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND |
WQ_MEM_RECLAIM, 1);
@ -1535,9 +1561,9 @@ int hci_register_dev(struct hci_dev *hdev)
err_wqueue:
destroy_workqueue(hdev->workqueue);
err:
write_lock_bh(&hci_dev_list_lock);
write_lock(&hci_dev_list_lock);
list_del(&hdev->list);
write_unlock_bh(&hci_dev_list_lock);
write_unlock(&hci_dev_list_lock);
return error;
}
@ -1550,9 +1576,9 @@ void hci_unregister_dev(struct hci_dev *hdev)
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
write_lock_bh(&hci_dev_list_lock);
write_lock(&hci_dev_list_lock);
list_del(&hdev->list);
write_unlock_bh(&hci_dev_list_lock);
write_unlock(&hci_dev_list_lock);
hci_dev_do_close(hdev);
@ -1800,59 +1826,13 @@ EXPORT_SYMBOL(hci_recv_stream_fragment);
/* ---- Interface to upper protocols ---- */
/* Register/Unregister protocols.
* hci_task_lock is used to ensure that no tasks are running. */
int hci_register_proto(struct hci_proto *hp)
{
int err = 0;
BT_DBG("%p name %s id %d", hp, hp->name, hp->id);
if (hp->id >= HCI_MAX_PROTO)
return -EINVAL;
mutex_lock(&hci_task_lock);
if (!hci_proto[hp->id])
hci_proto[hp->id] = hp;
else
err = -EEXIST;
mutex_unlock(&hci_task_lock);
return err;
}
EXPORT_SYMBOL(hci_register_proto);
int hci_unregister_proto(struct hci_proto *hp)
{
int err = 0;
BT_DBG("%p name %s id %d", hp, hp->name, hp->id);
if (hp->id >= HCI_MAX_PROTO)
return -EINVAL;
mutex_lock(&hci_task_lock);
if (hci_proto[hp->id])
hci_proto[hp->id] = NULL;
else
err = -ENOENT;
mutex_unlock(&hci_task_lock);
return err;
}
EXPORT_SYMBOL(hci_unregister_proto);
int hci_register_cb(struct hci_cb *cb)
{
BT_DBG("%p name %s", cb, cb->name);
write_lock_bh(&hci_cb_list_lock);
write_lock(&hci_cb_list_lock);
list_add(&cb->list, &hci_cb_list);
write_unlock_bh(&hci_cb_list_lock);
write_unlock(&hci_cb_list_lock);
return 0;
}
@ -1862,9 +1842,9 @@ int hci_unregister_cb(struct hci_cb *cb)
{
BT_DBG("%p name %s", cb, cb->name);
write_lock_bh(&hci_cb_list_lock);
write_lock(&hci_cb_list_lock);
list_del(&cb->list);
write_unlock_bh(&hci_cb_list_lock);
write_unlock(&hci_cb_list_lock);
return 0;
}
@ -1980,7 +1960,7 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
skb_shinfo(skb)->frag_list = NULL;
/* Queue all fragments atomically */
spin_lock_bh(&queue->lock);
spin_lock(&queue->lock);
__skb_queue_tail(queue, skb);
@ -1998,7 +1978,7 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
__skb_queue_tail(queue, skb);
} while (list);
spin_unlock_bh(&queue->lock);
spin_unlock(&queue->lock);
}
}
@ -2407,8 +2387,6 @@ 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;
mutex_lock(&hci_task_lock);
BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt,
hdev->sco_cnt, hdev->le_cnt);
@ -2425,8 +2403,6 @@ static void hci_tx_work(struct work_struct *work)
/* Send next queued raw (unknown type) packet */
while ((skb = skb_dequeue(&hdev->raw_q)))
hci_send_frame(skb);
mutex_unlock(&hci_task_lock);
}
/* ----- HCI RX task (incoming data processing) ----- */
@ -2453,16 +2429,11 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_unlock(hdev);
if (conn) {
register struct hci_proto *hp;
hci_conn_enter_active_mode(conn, BT_POWER_FORCE_ACTIVE_OFF);
/* Send to upper protocol */
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->recv_acldata) {
hp->recv_acldata(conn, skb, flags);
return;
}
l2cap_recv_acldata(conn, skb, flags);
return;
} else {
BT_ERR("%s ACL packet for unknown connection handle %d",
hdev->name, handle);
@ -2491,14 +2462,9 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_unlock(hdev);
if (conn) {
register struct hci_proto *hp;
/* Send to upper protocol */
hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->recv_scodata) {
hp->recv_scodata(conn, skb);
return;
}
sco_recv_scodata(conn, skb);
return;
} else {
BT_ERR("%s SCO packet for unknown connection handle %d",
hdev->name, handle);
@ -2514,8 +2480,6 @@ static void hci_rx_work(struct work_struct *work)
BT_DBG("%s", hdev->name);
mutex_lock(&hci_task_lock);
while ((skb = skb_dequeue(&hdev->rx_q))) {
if (atomic_read(&hdev->promisc)) {
/* Send copy to the sockets */
@ -2559,8 +2523,6 @@ static void hci_rx_work(struct work_struct *work)
break;
}
}
mutex_unlock(&hci_task_lock);
}
static void hci_cmd_work(struct work_struct *work)

View File

@ -556,6 +556,9 @@ static void hci_set_le_support(struct hci_dev *hdev)
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)
@ -1030,7 +1033,8 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
if (!cp)
return;
if (cp->enable == 0x01) {
switch (cp->enable) {
case LE_SCANNING_ENABLED:
set_bit(HCI_LE_SCAN, &hdev->dev_flags);
cancel_delayed_work_sync(&hdev->adv_work);
@ -1038,12 +1042,19 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
hci_dev_lock(hdev);
hci_adv_entries_clear(hdev);
hci_dev_unlock(hdev);
} else if (cp->enable == 0x00) {
break;
case LE_SCANNING_DISABLED:
clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
cancel_delayed_work_sync(&hdev->adv_work);
queue_delayed_work(hdev->workqueue, &hdev->adv_work,
jiffies + ADV_CLEAR_TIMEOUT);
break;
default:
BT_ERR("Used reserved LE_Scan_Enable param %d", cp->enable);
break;
}
}
@ -2253,24 +2264,29 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb
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;
__le16 *ptr;
int i;
skb_pull(skb, sizeof(*ev));
BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
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 < ev->num_hndl * 4) {
BT_DBG("%s bad parameters", hdev->name);
return;
}
for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) {
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 = get_unaligned_le16(ptr++);
count = get_unaligned_le16(ptr++);
handle = __le16_to_cpu(info->handle);
count = __le16_to_cpu(info->count);
conn = hci_conn_hash_lookup_handle(hdev, handle);
if (!conn)

View File

@ -1,6 +1,6 @@
config BT_HIDP
tristate "HIDP protocol support"
depends on BT && BT_L2CAP && INPUT && HID_SUPPORT
depends on BT && INPUT && HID_SUPPORT
select HID
help
HIDP (Human Interface Device Protocol) is a transport layer

View File

@ -77,17 +77,6 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
/* ---- L2CAP channels ---- */
static inline void chan_hold(struct l2cap_chan *c)
{
atomic_inc(&c->refcnt);
}
static inline void chan_put(struct l2cap_chan *c)
{
if (atomic_dec_and_test(&c->refcnt))
kfree(c);
}
static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
{
struct l2cap_chan *c, *r = NULL;
@ -228,20 +217,6 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
return 0;
}
static void l2cap_set_timer(struct l2cap_chan *chan, struct delayed_work *work, long timeout)
{
BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
cancel_delayed_work_sync(work);
schedule_delayed_work(work, timeout);
}
static void l2cap_clear_timer(struct delayed_work *work)
{
cancel_delayed_work_sync(work);
}
static char *state_to_string(int state)
{
switch(state) {
@ -301,7 +276,7 @@ static void l2cap_chan_timeout(struct work_struct *work)
release_sock(sk);
chan->ops->close(chan->data);
chan_put(chan);
l2cap_chan_put(chan);
}
struct l2cap_chan *l2cap_chan_create(struct sock *sk)
@ -335,7 +310,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan)
list_del(&chan->global_l);
write_unlock_bh(&chan_list_lock);
chan_put(chan);
l2cap_chan_put(chan);
}
static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
@ -377,7 +352,7 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
chan_hold(chan);
l2cap_chan_hold(chan);
list_add_rcu(&chan->list, &conn->chan_l);
}
@ -399,7 +374,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
list_del_rcu(&chan->list);
synchronize_rcu();
chan_put(chan);
l2cap_chan_put(chan);
chan->conn = NULL;
hci_conn_put(conn->hcon);
@ -713,7 +688,7 @@ static void l2cap_do_start(struct l2cap_chan *chan)
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
conn->info_ident = l2cap_get_ident(conn);
schedule_delayed_work(&conn->info_work,
schedule_delayed_work(&conn->info_timer,
msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
l2cap_send_cmd(conn, conn->info_ident,
@ -1010,7 +985,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
static void l2cap_info_timeout(struct work_struct *work)
{
struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
info_work.work);
info_timer.work);
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
conn->info_ident = 0;
@ -1043,10 +1018,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
hci_chan_del(conn->hchan);
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
cancel_delayed_work_sync(&conn->info_work);
__cancel_delayed_work(&conn->info_timer);
if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
del_timer(&conn->security_timer);
__cancel_delayed_work(&conn->security_timer);
smp_chan_destroy(conn);
}
@ -1054,9 +1029,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
kfree(conn);
}
static void security_timeout(unsigned long arg)
static void security_timeout(struct work_struct *work)
{
struct l2cap_conn *conn = (void *) arg;
struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
security_timer.work);
l2cap_conn_del(conn->hcon, ETIMEDOUT);
}
@ -1100,10 +1076,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
INIT_LIST_HEAD(&conn->chan_l);
if (hcon->type == LE_LINK)
setup_timer(&conn->security_timer, security_timeout,
(unsigned long) conn);
INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
else
INIT_DELAYED_WORK(&conn->info_work, l2cap_info_timeout);
INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
@ -2010,6 +1985,8 @@ 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);
lock_sock(chan->sk);
l2cap_send_ack(chan);
release_sock(chan->sk);
@ -2597,7 +2574,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
cmd->ident == conn->info_ident) {
cancel_delayed_work_sync(&conn->info_work);
__cancel_delayed_work(&conn->info_timer);
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
conn->info_ident = 0;
@ -2718,7 +2695,7 @@ sendresp:
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
conn->info_ident = l2cap_get_ident(conn);
schedule_delayed_work(&conn->info_work,
schedule_delayed_work(&conn->info_timer,
msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
l2cap_send_cmd(conn, conn->info_ident,
@ -3143,7 +3120,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
return 0;
cancel_delayed_work_sync(&conn->info_work);
__cancel_delayed_work(&conn->info_timer);
if (result != L2CAP_IR_SUCCESS) {
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
@ -4427,14 +4404,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
/* ---- L2CAP interface with lower layer (HCI) ---- */
static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
int exact = 0, lm1 = 0, lm2 = 0;
struct l2cap_chan *c;
if (type != ACL_LINK)
return -EINVAL;
BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
/* Find listening sockets and check their link_mode */
@ -4461,15 +4435,12 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
return exact ? lm1 : lm2;
}
static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
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 (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
return -EINVAL;
if (!status) {
conn = l2cap_conn_add(hcon, status);
if (conn)
@ -4480,27 +4451,22 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
return 0;
}
static int l2cap_disconn_ind(struct hci_conn *hcon)
int l2cap_disconn_ind(struct hci_conn *hcon)
{
struct l2cap_conn *conn = hcon->l2cap_data;
BT_DBG("hcon %p", hcon);
if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
if (!conn)
return HCI_ERROR_REMOTE_USER_TERM;
return conn->disc_reason;
}
static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
{
BT_DBG("hcon %p reason %d", hcon, reason);
if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
return -EINVAL;
l2cap_conn_del(hcon, bt_to_errno(reason));
return 0;
}
@ -4521,7 +4487,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
}
}
static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct l2cap_chan *chan;
@ -4533,7 +4499,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
if (hcon->type == LE_LINK) {
smp_distribute_keys(conn, 0);
del_timer(&conn->security_timer);
__cancel_delayed_work(&conn->security_timer);
}
rcu_read_lock();
@ -4621,7 +4587,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
return 0;
}
static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
{
struct l2cap_conn *conn = hcon->l2cap_data;
@ -4768,17 +4734,6 @@ static const struct file_operations l2cap_debugfs_fops = {
static struct dentry *l2cap_debugfs;
static struct hci_proto l2cap_hci_proto = {
.name = "L2CAP",
.id = HCI_PROTO_L2CAP,
.connect_ind = l2cap_connect_ind,
.connect_cfm = l2cap_connect_cfm,
.disconn_ind = l2cap_disconn_ind,
.disconn_cfm = l2cap_disconn_cfm,
.security_cfm = l2cap_security_cfm,
.recv_acldata = l2cap_recv_acldata
};
int __init l2cap_init(void)
{
int err;
@ -4787,13 +4742,6 @@ int __init l2cap_init(void)
if (err < 0)
return err;
err = hci_register_proto(&l2cap_hci_proto);
if (err < 0) {
BT_ERR("L2CAP protocol registration failed");
bt_sock_unregister(BTPROTO_L2CAP);
goto error;
}
if (bt_debugfs) {
l2cap_debugfs = debugfs_create_file("l2cap", 0444,
bt_debugfs, NULL, &l2cap_debugfs_fops);
@ -4802,19 +4750,11 @@ int __init l2cap_init(void)
}
return 0;
error:
l2cap_cleanup_sockets();
return err;
}
void l2cap_exit(void)
{
debugfs_remove(l2cap_debugfs);
if (hci_unregister_proto(&l2cap_hci_proto) < 0)
BT_ERR("L2CAP protocol unregistration failed");
l2cap_cleanup_sockets();
}

View File

@ -30,6 +30,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/mgmt.h>
#include <net/bluetooth/smp.h>
#define MGMT_VERSION 0
#define MGMT_REVISION 1
@ -1642,8 +1643,15 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
}
/* Continue with pairing via SMP */
err = smp_user_confirm_reply(conn, mgmt_op, passkey);
if (!err)
err = cmd_status(sk, index, mgmt_op,
MGMT_STATUS_SUCCESS);
else
err = cmd_status(sk, index, mgmt_op,
MGMT_STATUS_FAILED);
err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_SUCCESS);
goto done;
}

View File

@ -1,6 +1,6 @@
config BT_RFCOMM
tristate "RFCOMM protocol support"
depends on BT && BT_L2CAP
depends on BT
help
RFCOMM provides connection oriented stream transport. RFCOMM
support is required for Dialup Networking, OBEX and other Bluetooth

View File

@ -65,8 +65,7 @@ static DEFINE_MUTEX(rfcomm_mutex);
static LIST_HEAD(session_list);
static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len,
u32 priority);
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);
@ -748,32 +747,23 @@ void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *d
}
/* ---- RFCOMM frame sending ---- */
static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len,
u32 priority)
static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
{
struct socket *sock = s->sock;
struct sock *sk = sock->sk;
struct kvec iv = { data, len };
struct msghdr msg;
BT_DBG("session %p len %d priority %u", s, len, priority);
if (sk->sk_priority != priority) {
lock_sock(sk);
sk->sk_priority = priority;
release_sock(sk);
}
BT_DBG("session %p len %d", s, len);
memset(&msg, 0, sizeof(msg));
return kernel_sendmsg(sock, &msg, &iv, 1, len);
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), HCI_PRIO_MAX);
return rfcomm_send_frame(s, (void *) cmd, sizeof(*cmd));
}
static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
@ -829,8 +819,6 @@ static int rfcomm_queue_disc(struct rfcomm_dlc *d)
if (!skb)
return -ENOMEM;
skb->priority = HCI_PRIO_MAX;
cmd = (void *) __skb_put(skb, sizeof(*cmd));
cmd->addr = d->addr;
cmd->ctrl = __ctrl(RFCOMM_DISC, 1);
@ -878,7 +866,7 @@ static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
return rfcomm_send_frame(s, buf, ptr - buf);
}
static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d)
@ -920,7 +908,7 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
return rfcomm_send_frame(s, buf, ptr - buf);
}
int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
@ -958,7 +946,7 @@ int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
return rfcomm_send_frame(s, buf, ptr - buf);
}
static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
@ -985,7 +973,7 @@ static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
return rfcomm_send_frame(s, buf, ptr - buf);
}
static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
@ -1012,7 +1000,7 @@ static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
return rfcomm_send_frame(s, buf, ptr - buf);
}
static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
@ -1034,7 +1022,7 @@ static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
return rfcomm_send_frame(s, buf, ptr - buf);
}
static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
@ -1056,7 +1044,7 @@ static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
return rfcomm_send_frame(s, buf, ptr - buf);
}
static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
@ -1107,7 +1095,7 @@ static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
return rfcomm_send_frame(s, buf, ptr - buf);
}
static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
@ -1786,8 +1774,7 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
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,
skb->priority);
err = rfcomm_send_frame(d->session, skb->data, skb->len);
if (err < 0) {
skb_queue_head(&d->tx_queue, skb);
break;

View File

@ -893,15 +893,12 @@ done:
}
/* ----- SCO interface with lower layer (HCI) ----- */
static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
register struct sock *sk;
struct hlist_node *node;
int lm = 0;
if (type != SCO_LINK && type != ESCO_LINK)
return -EINVAL;
BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
/* Find listening sockets */
@ -921,13 +918,9 @@ static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
return lm;
}
static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
{
BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
return -EINVAL;
if (!status) {
struct sco_conn *conn;
@ -940,19 +933,15 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
return 0;
}
static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
{
BT_DBG("hcon %p reason %d", hcon, reason);
if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
return -EINVAL;
sco_conn_del(hcon, bt_to_errno(reason));
return 0;
}
static int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
{
struct sco_conn *conn = hcon->sco_data;
@ -1028,15 +1017,6 @@ static const struct net_proto_family sco_sock_family_ops = {
.create = sco_sock_create,
};
static struct hci_proto sco_hci_proto = {
.name = "SCO",
.id = HCI_PROTO_SCO,
.connect_ind = sco_connect_ind,
.connect_cfm = sco_connect_cfm,
.disconn_cfm = sco_disconn_cfm,
.recv_scodata = sco_recv_scodata
};
int __init sco_init(void)
{
int err;
@ -1051,13 +1031,6 @@ int __init sco_init(void)
goto error;
}
err = hci_register_proto(&sco_hci_proto);
if (err < 0) {
BT_ERR("SCO protocol registration failed");
bt_sock_unregister(BTPROTO_SCO);
goto error;
}
if (bt_debugfs) {
sco_debugfs = debugfs_create_file("sco", 0444,
bt_debugfs, NULL, &sco_debugfs_fops);
@ -1081,9 +1054,6 @@ void __exit sco_exit(void)
if (bt_sock_unregister(BTPROTO_SCO) < 0)
BT_ERR("SCO socket unregistration failed");
if (hci_unregister_proto(&sco_hci_proto) < 0)
BT_ERR("SCO protocol unregistration failed");
proto_unregister(&sco_proto);
}

View File

@ -23,6 +23,7 @@
#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>
@ -184,28 +185,50 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
skb->priority = HCI_PRIO_MAX;
hci_send_acl(conn->hchan, skb, 0);
mod_timer(&conn->security_timer, jiffies +
cancel_delayed_work_sync(&conn->security_timer);
schedule_delayed_work(&conn->security_timer,
msecs_to_jiffies(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;
u8 dist_keys = 0;
dist_keys = 0;
if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->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 = dist_keys;
req->init_key_dist = 0;
req->resp_key_dist = dist_keys;
req->auth_req = authreq;
return;
@ -214,7 +237,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
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 = req->init_key_dist & dist_keys;
rsp->init_key_dist = 0;
rsp->resp_key_dist = req->resp_key_dist & dist_keys;
rsp->auth_req = authreq;
}
@ -240,10 +263,99 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend);
mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason);
del_timer(&conn->security_timer);
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[local_io][remote_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);
else
ret = mgmt_user_confirm_request(hcon->hdev, conn->dst,
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);
@ -276,6 +388,8 @@ static void confirm_work(struct work_struct *work)
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);
@ -381,6 +495,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
smp->conn = conn;
conn->smp_chan = smp;
conn->hcon->smp_conn = conn;
hci_conn_hold(conn->hcon);
@ -398,18 +513,64 @@ void smp_chan_destroy(struct l2cap_conn *conn)
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->pend))
smp = smp_chan_create(conn);
@ -419,19 +580,16 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
memcpy(&smp->preq[1], req, sizeof(*req));
skb_pull(skb, sizeof(*req));
if (req->oob_flag)
return SMP_OOB_NOT_AVAIL;
/* We didn't start the pairing, so match remote */
if (req->auth_req & SMP_AUTH_BONDING)
auth = req->auth_req;
/* We didn't start the pairing, so no requirements */
build_pairing_cmd(conn, req, &rsp, SMP_AUTH_NONE);
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;
/* Just works */
memset(smp->tk, 0, sizeof(smp->tk));
ret = smp_rand(smp->prnd);
if (ret)
return SMP_UNSPECIFIED;
@ -441,6 +599,11 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
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;
}
@ -449,11 +612,14 @@ 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;
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];
@ -462,12 +628,6 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
if (check_enc_key_size(conn, key_size))
return SMP_ENC_KEY_SIZE;
if (rsp->oob_flag)
return SMP_OOB_NOT_AVAIL;
/* Just works */
memset(smp->tk, 0, sizeof(smp->tk));
ret = smp_rand(smp->prnd);
if (ret)
return SMP_UNSPECIFIED;
@ -475,6 +635,22 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
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;
@ -496,8 +672,10 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
swap128(smp->prnd, random);
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random),
random);
} else {
} 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;
@ -550,7 +728,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
BT_DBG("conn %p", conn);
hcon->pending_sec_level = BT_SECURITY_MEDIUM;
hcon->pending_sec_level = authreq_to_seclevel(rp->auth_req);
if (smp_ltk_encrypt(conn))
return 0;
@ -577,6 +755,7 @@ 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);
@ -597,18 +776,22 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
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, SMP_AUTH_NONE);
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 = SMP_AUTH_NONE;
cp.auth_req = authreq;
smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
}
@ -637,7 +820,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
skb_pull(skb, sizeof(*rp));
hci_add_ltk(conn->hcon->hdev, 1, conn->src, smp->smp_key_size,
hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size,
rp->ediv, rp->rand, smp->tk);
smp_distribute_keys(conn, 1);
@ -800,7 +983,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
if (conn->hcon->out || force) {
clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
del_timer(&conn->security_timer);
cancel_delayed_work_sync(&conn->security_timer);
smp_chan_destroy(conn);
}