提交 1c1236e3 编写于 作者: J John W. Linville

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

......@@ -745,6 +745,33 @@ struct hci_cp_le_conn_update {
__le16 max_ce_len;
} __packed;
#define HCI_OP_LE_START_ENC 0x2019
struct hci_cp_le_start_enc {
__le16 handle;
__u8 rand[8];
__le16 ediv;
__u8 ltk[16];
} __packed;
#define HCI_OP_LE_LTK_REPLY 0x201a
struct hci_cp_le_ltk_reply {
__le16 handle;
__u8 ltk[16];
} __packed;
struct hci_rp_le_ltk_reply {
__u8 status;
__le16 handle;
} __packed;
#define HCI_OP_LE_LTK_NEG_REPLY 0x201b
struct hci_cp_le_ltk_neg_reply {
__le16 handle;
} __packed;
struct hci_rp_le_ltk_neg_reply {
__u8 status;
__le16 handle;
} __packed;
/* ---- HCI Events ---- */
#define HCI_EV_INQUIRY_COMPLETE 0x01
......@@ -1035,6 +1062,13 @@ struct hci_ev_le_conn_complete {
__u8 clk_accurancy;
} __packed;
#define HCI_EV_LE_LTK_REQ 0x05
struct hci_ev_le_ltk_req {
__le16 handle;
__u8 random[8];
__le16 ediv;
} __packed;
/* Advertising report event types */
#define ADV_IND 0x00
#define ADV_DIRECT_IND 0x01
......
......@@ -177,6 +177,8 @@ struct hci_dev {
__u16 init_last_cmd;
struct crypto_blkcipher *tfm;
struct inquiry_cache inq_cache;
struct hci_conn_hash conn_hash;
struct list_head blacklist;
......@@ -247,6 +249,7 @@ struct hci_conn {
__u8 power_save;
__u16 disc_timeout;
unsigned long pend;
__u8 ltk[16];
__u8 remote_cap;
__u8 remote_oob;
......@@ -526,6 +529,8 @@ int hci_inquiry(void __user *arg);
struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
int hci_blacklist_clear(struct hci_dev *hdev);
int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr);
int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr);
int hci_uuids_clear(struct hci_dev *hdev);
......@@ -742,6 +747,9 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
if (conn->sec_level == BT_SECURITY_SDP)
conn->sec_level = BT_SECURITY_LOW;
if (conn->pending_sec_level > conn->sec_level)
conn->sec_level = conn->pending_sec_level;
hci_proto_encrypt_cfm(conn, status, encrypt);
read_lock_bh(&hci_cb_list_lock);
......@@ -859,4 +867,9 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result);
void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
u16 latency, u16 to_multiplier);
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
__u8 ltk[16]);
void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]);
void hci_le_ltk_neg_reply(struct hci_conn *conn);
#endif /* __HCI_CORE_H */
......@@ -287,6 +287,10 @@ struct l2cap_chan {
struct l2cap_conn *conn;
__u8 state;
atomic_t refcnt;
__le16 psm;
__u16 dcid;
__u16 scid;
......@@ -320,8 +324,8 @@ struct l2cap_chan {
__u16 monitor_timeout;
__u16 mps;
__u8 conf_state;
__u16 conn_state;
unsigned long conf_state;
unsigned long conn_state;
__u8 next_tx_seq;
__u8 expected_ack_seq;
......@@ -354,6 +358,18 @@ struct l2cap_chan {
struct list_head list;
struct list_head global_l;
void *data;
struct l2cap_ops *ops;
};
struct l2cap_ops {
char *name;
struct l2cap_chan *(*new_connection) (void *data);
int (*recv) (void *data, struct sk_buff *skb);
void (*close) (void *data);
void (*state_change) (void *data, int state);
};
struct l2cap_conn {
......@@ -379,6 +395,15 @@ struct l2cap_conn {
__u8 disc_reason;
__u8 preq[7]; /* SMP Pairing Request */
__u8 prsp[7]; /* SMP Pairing Response */
__u8 prnd[16]; /* SMP Pairing Random */
__u8 pcnf[16]; /* SMP Pairing Confirm */
__u8 tk[16]; /* SMP Temporary Key */
__u8 smp_key_size;
struct timer_list security_timer;
struct list_head chan_l;
rwlock_t chan_lock;
};
......@@ -399,36 +424,45 @@ struct l2cap_pinfo {
struct l2cap_chan *chan;
};
#define L2CAP_CONF_REQ_SENT 0x01
#define L2CAP_CONF_INPUT_DONE 0x02
#define L2CAP_CONF_OUTPUT_DONE 0x04
#define L2CAP_CONF_MTU_DONE 0x08
#define L2CAP_CONF_MODE_DONE 0x10
#define L2CAP_CONF_CONNECT_PEND 0x20
#define L2CAP_CONF_NO_FCS_RECV 0x40
#define L2CAP_CONF_STATE2_DEVICE 0x80
enum {
CONF_REQ_SENT,
CONF_INPUT_DONE,
CONF_OUTPUT_DONE,
CONF_MTU_DONE,
CONF_MODE_DONE,
CONF_CONNECT_PEND,
CONF_NO_FCS_RECV,
CONF_STATE2_DEVICE,
};
#define L2CAP_CONF_MAX_CONF_REQ 2
#define L2CAP_CONF_MAX_CONF_RSP 2
#define L2CAP_CONN_SAR_SDU 0x0001
#define L2CAP_CONN_SREJ_SENT 0x0002
#define L2CAP_CONN_WAIT_F 0x0004
#define L2CAP_CONN_SREJ_ACT 0x0008
#define L2CAP_CONN_SEND_PBIT 0x0010
#define L2CAP_CONN_REMOTE_BUSY 0x0020
#define L2CAP_CONN_LOCAL_BUSY 0x0040
#define L2CAP_CONN_REJ_ACT 0x0080
#define L2CAP_CONN_SEND_FBIT 0x0100
#define L2CAP_CONN_RNR_SENT 0x0200
#define L2CAP_CONN_SAR_RETRY 0x0400
#define __mod_retrans_timer() mod_timer(&chan->retrans_timer, \
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
#define __mod_monitor_timer() mod_timer(&chan->monitor_timer, \
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO));
#define __mod_ack_timer() mod_timer(&chan->ack_timer, \
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO));
enum {
CONN_SAR_SDU,
CONN_SREJ_SENT,
CONN_WAIT_F,
CONN_SREJ_ACT,
CONN_SEND_PBIT,
CONN_REMOTE_BUSY,
CONN_LOCAL_BUSY,
CONN_REJ_ACT,
CONN_SEND_FBIT,
CONN_RNR_SENT,
CONN_SAR_RETRY,
};
#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
#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, &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, &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, &c->ack_timer)
static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
{
......@@ -459,11 +493,6 @@ int __l2cap_wait_ack(struct sock *sk);
int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm);
int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid);
void l2cap_sock_kill(struct sock *sk);
void l2cap_sock_init(struct sock *sk, struct sock *parent);
struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
int proto, gfp_t prio);
struct l2cap_chan *l2cap_chan_create(struct sock *sk);
void l2cap_chan_close(struct l2cap_chan *chan, int reason);
void l2cap_chan_destroy(struct l2cap_chan *chan);
......
......@@ -199,6 +199,16 @@ struct mgmt_cp_remove_remote_oob_data {
#define MGMT_OP_STOP_DISCOVERY 0x001C
#define MGMT_OP_BLOCK_DEVICE 0x001D
struct mgmt_cp_block_device {
bdaddr_t bdaddr;
} __packed;
#define MGMT_OP_UNBLOCK_DEVICE 0x001E
struct mgmt_cp_unblock_device {
bdaddr_t bdaddr;
} __packed;
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
......
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
#ifndef __SMP_H
#define __SMP_H
......@@ -16,6 +38,23 @@ struct smp_cmd_pairing {
__u8 resp_key_dist;
} __packed;
#define SMP_IO_DISPLAY_ONLY 0x00
#define SMP_IO_DISPLAY_YESNO 0x01
#define SMP_IO_KEYBOARD_ONLY 0x02
#define SMP_IO_NO_INPUT_OUTPUT 0x03
#define SMP_IO_KEYBOARD_DISPLAY 0x04
#define SMP_OOB_NOT_PRESENT 0x00
#define SMP_OOB_PRESENT 0x01
#define SMP_DIST_ENC_KEY 0x01
#define SMP_DIST_ID_KEY 0x02
#define SMP_DIST_SIGN 0x04
#define SMP_AUTH_NONE 0x00
#define SMP_AUTH_BONDING 0x01
#define SMP_AUTH_MITM 0x04
#define SMP_CMD_PAIRING_CONFIRM 0x03
struct smp_cmd_pairing_confirm {
__u8 confirm_val[16];
......@@ -73,4 +112,11 @@ struct smp_cmd_security_req {
#define SMP_UNSPECIFIED 0x08
#define SMP_REPEATED_ATTEMPTS 0x09
#define SMP_MIN_ENC_KEY_SIZE 7
#define SMP_MAX_ENC_KEY_SIZE 16
/* SMP Commands */
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level);
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
#endif /* __SMP_H */
......@@ -22,6 +22,7 @@ menuconfig BT
BNEP Module (Bluetooth Network Encapsulation Protocol)
CMTP Module (CAPI Message Transport Protocol)
HIDP Module (Human Interface Device Protocol)
SMP Module (Security Manager Protocol)
Say Y here to compile Bluetooth support into the kernel or say M to
compile it as module (bluetooth).
......@@ -36,11 +37,18 @@ 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
......
......@@ -9,5 +9,5 @@ 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_L2CAP) += l2cap_core.o l2cap_sock.o smp.o
bluetooth-$(CONFIG_BT_SCO) += sco.o
......@@ -53,6 +53,7 @@ static void hci_le_connect(struct hci_conn *conn)
conn->state = BT_CONNECT;
conn->out = 1;
conn->link_mode |= HCI_LM_MASTER;
conn->sec_level = BT_SECURITY_LOW;
memset(&cp, 0, sizeof(cp));
cp.scan_interval = cpu_to_le16(0x0004);
......@@ -204,6 +205,55 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
}
EXPORT_SYMBOL(hci_le_conn_update);
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
__u8 ltk[16])
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_le_start_enc cp;
BT_DBG("%p", conn);
memset(&cp, 0, sizeof(cp));
cp.handle = cpu_to_le16(conn->handle);
memcpy(cp.ltk, ltk, sizeof(cp.ltk));
cp.ediv = ediv;
memcpy(cp.rand, rand, sizeof(rand));
hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
}
EXPORT_SYMBOL(hci_le_start_enc);
void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16])
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_le_ltk_reply cp;
BT_DBG("%p", conn);
memset(&cp, 0, sizeof(cp));
cp.handle = cpu_to_le16(conn->handle);
memcpy(cp.ltk, ltk, sizeof(ltk));
hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
}
EXPORT_SYMBOL(hci_le_ltk_reply);
void hci_le_ltk_neg_reply(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_le_ltk_neg_reply cp;
BT_DBG("%p", conn);
memset(&cp, 0, sizeof(cp));
cp.handle = cpu_to_le16(conn->handle);
hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(cp), &cp);
}
/* Device _must_ be locked */
void hci_sco_setup(struct hci_conn *conn, __u8 status)
{
......@@ -620,10 +670,10 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
goto encrypt;
auth:
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
return 0;
hci_conn_auth(conn, sec_level, auth_type);
if (!hci_conn_auth(conn, sec_level, auth_type))
return 0;
encrypt:
......
......@@ -42,6 +42,7 @@
#include <linux/notifier.h>
#include <linux/rfkill.h>
#include <linux/timer.h>
#include <linux/crypto.h>
#include <net/sock.h>
#include <asm/system.h>
......@@ -59,6 +60,8 @@ static void hci_tx_task(unsigned long arg);
static DEFINE_RWLOCK(hci_task_lock);
static int enable_smp;
/* HCI device list */
LIST_HEAD(hci_dev_list);
DEFINE_RWLOCK(hci_dev_list_lock);
......@@ -1202,6 +1205,97 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
return 0;
}
struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
bdaddr_t *bdaddr)
{
struct list_head *p;
list_for_each(p, &hdev->blacklist) {
struct bdaddr_list *b;
b = list_entry(p, struct bdaddr_list, list);
if (bacmp(bdaddr, &b->bdaddr) == 0)
return b;
}
return NULL;
}
int hci_blacklist_clear(struct hci_dev *hdev)
{
struct list_head *p, *n;
list_for_each_safe(p, n, &hdev->blacklist) {
struct bdaddr_list *b;
b = list_entry(p, struct bdaddr_list, list);
list_del(p);
kfree(b);
}
return 0;
}
int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct bdaddr_list *entry;
int err;
if (bacmp(bdaddr, BDADDR_ANY) == 0)
return -EBADF;
hci_dev_lock(hdev);
if (hci_blacklist_lookup(hdev, bdaddr)) {
err = -EEXIST;
goto err;
}
entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
if (!entry) {
return -ENOMEM;
goto err;
}
bacpy(&entry->bdaddr, bdaddr);
list_add(&entry->list, &hdev->blacklist);
err = 0;
err:
hci_dev_unlock(hdev);
return err;
}
int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct bdaddr_list *entry;
int err = 0;
hci_dev_lock(hdev);
if (bacmp(bdaddr, BDADDR_ANY) == 0) {
hci_blacklist_clear(hdev);
goto done;
}
entry = hci_blacklist_lookup(hdev, bdaddr);
if (!entry) {
err = -ENOENT;
goto done;
}
list_del(&entry->list);
kfree(entry);
done:
hci_dev_unlock(hdev);
return err;
}
static void hci_clear_adv_cache(unsigned long arg)
{
struct hci_dev *hdev = (void *) arg;
......@@ -1274,6 +1368,14 @@ int hci_add_adv_entry(struct hci_dev *hdev,
return 0;
}
static struct crypto_blkcipher *alloc_cypher(void)
{
if (enable_smp)
return crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
return ERR_PTR(-ENOTSUPP);
}
/* Register HCI device */
int hci_register_dev(struct hci_dev *hdev)
{
......@@ -1358,6 +1460,11 @@ int hci_register_dev(struct hci_dev *hdev)
if (!hdev->workqueue)
goto nomem;
hdev->tfm = alloc_cypher();
if (IS_ERR(hdev->tfm))
BT_INFO("Failed to load transform for ecb(aes): %ld",
PTR_ERR(hdev->tfm));
hci_register_sysfs(hdev);
hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
......@@ -1406,6 +1513,9 @@ int hci_unregister_dev(struct hci_dev *hdev)
!test_bit(HCI_SETUP, &hdev->flags))
mgmt_index_removed(hdev->id);
if (!IS_ERR(hdev->tfm))
crypto_free_blkcipher(hdev->tfm);
hci_notify(hdev, HCI_DEV_UNREG);
if (hdev->rfkill) {
......@@ -2242,3 +2352,6 @@ static void hci_cmd_task(unsigned long arg)
}
}
}
module_param(enable_smp, bool, 0644);
MODULE_PARM_DESC(enable_smp, "Enable SMP support (LE only)");
......@@ -868,6 +868,30 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
hci_dev_unlock(hdev);
}
static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_le_ltk_reply *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
if (rp->status)
return;
hci_req_complete(hdev, HCI_OP_LE_LTK_REPLY, rp->status);
}
static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_le_ltk_neg_reply *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
if (rp->status)
return;
hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status);
}
static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
{
BT_DBG("%s status 0x%x", hdev->name, status);
......@@ -1248,6 +1272,11 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
hci_dev_unlock(hdev);
}
static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
{
BT_DBG("%s status 0x%x", hdev->name, status);
}
static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
......@@ -1593,6 +1622,7 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
/* Encryption implies authentication */
conn->link_mode |= HCI_LM_AUTH;
conn->link_mode |= HCI_LM_ENCRYPT;
conn->sec_level = conn->pending_sec_level;
} else
conn->link_mode &= ~HCI_LM_ENCRYPT;
}
......@@ -1856,6 +1886,14 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_le_set_scan_enable(hdev, skb);
break;
case HCI_OP_LE_LTK_REPLY:
hci_cc_le_ltk_reply(hdev, skb);
break;
case HCI_OP_LE_LTK_NEG_REPLY:
hci_cc_le_ltk_neg_reply(hdev, skb);
break;
default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break;
......@@ -1934,6 +1972,10 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_le_create_conn(hdev, ev->status);
break;
case HCI_OP_LE_START_ENC:
hci_cs_le_start_enc(hdev, ev->status);
break;
default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break;
......@@ -2712,6 +2754,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
mgmt_connected(hdev->id, &ev->bdaddr);
conn->sec_level = BT_SECURITY_LOW;
conn->handle = __le16_to_cpu(ev->handle);
conn->state = BT_CONNECTED;
......@@ -2745,6 +2788,28 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
hci_dev_unlock(hdev);
}
static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_ev_le_ltk_req *ev = (void *) skb->data;
struct hci_cp_le_ltk_reply cp;
struct hci_conn *conn;
BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle));
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
memset(&cp, 0, sizeof(cp));
cp.handle = cpu_to_le16(conn->handle);
memcpy(cp.ltk, conn->ltk, sizeof(conn->ltk));
hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
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;
......@@ -2760,6 +2825,10 @@ static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_le_adv_report_evt(hdev, skb);
break;
case HCI_EV_LE_LTK_REQ:
hci_le_ltk_request_evt(hdev, skb);
break;
default:
break;
}
......
......@@ -180,82 +180,24 @@ static int hci_sock_release(struct socket *sock)
return 0;
}
struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct list_head *p;
list_for_each(p, &hdev->blacklist) {
struct bdaddr_list *b;
b = list_entry(p, struct bdaddr_list, list);
if (bacmp(bdaddr, &b->bdaddr) == 0)
return b;
}
return NULL;
}
static int hci_blacklist_add(struct hci_dev *hdev, void __user *arg)
static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg)
{
bdaddr_t bdaddr;
struct bdaddr_list *entry;
if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
return -EFAULT;
if (bacmp(&bdaddr, BDADDR_ANY) == 0)
return -EBADF;
if (hci_blacklist_lookup(hdev, &bdaddr))
return -EEXIST;
entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
if (!entry)
return -ENOMEM;
bacpy(&entry->bdaddr, &bdaddr);
list_add(&entry->list, &hdev->blacklist);
return 0;
}
int hci_blacklist_clear(struct hci_dev *hdev)
{
struct list_head *p, *n;
list_for_each_safe(p, n, &hdev->blacklist) {
struct bdaddr_list *b;
b = list_entry(p, struct bdaddr_list, list);
list_del(p);
kfree(b);
}
return 0;
return hci_blacklist_add(hdev, &bdaddr);
}
static int hci_blacklist_del(struct hci_dev *hdev, void __user *arg)
static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
{
bdaddr_t bdaddr;
struct bdaddr_list *entry;
if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
return -EFAULT;
if (bacmp(&bdaddr, BDADDR_ANY) == 0)
return hci_blacklist_clear(hdev);
entry = hci_blacklist_lookup(hdev, &bdaddr);
if (!entry)
return -ENOENT;
list_del(&entry->list);
kfree(entry);
return 0;
return hci_blacklist_del(hdev, &bdaddr);
}
/* Ioctls that require bound socket */
......@@ -290,12 +232,12 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
case HCIBLOCKADDR:
if (!capable(CAP_NET_ADMIN))
return -EACCES;
return hci_blacklist_add(hdev, (void __user *) arg);
return hci_sock_blacklist_add(hdev, (void __user *) arg);
case HCIUNBLOCKADDR:
if (!capable(CAP_NET_ADMIN))
return -EACCES;
return hci_blacklist_del(hdev, (void __user *) arg);
return hci_sock_blacklist_del(hdev, (void __user *) arg);
default:
if (hdev->ioctl)
......
......@@ -54,6 +54,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/smp.h>
int disable_ertm;
......@@ -78,6 +79,18 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn,
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;
......@@ -208,20 +221,26 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
return 0;
}
static void l2cap_chan_set_timer(struct l2cap_chan *chan, long timeout)
static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
{
BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->sk->sk_state,
timeout);
if (!mod_timer(&chan->chan_timer, jiffies + timeout))
sock_hold(chan->sk);
BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout);
if (!mod_timer(timer, jiffies + timeout))
chan_hold(chan);
}
static void l2cap_chan_clear_timer(struct l2cap_chan *chan)
static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
{
BT_DBG("chan %p state %d", chan, chan->sk->sk_state);
BT_DBG("chan %p state %d", chan, chan->state);
if (timer_pending(&chan->chan_timer) && del_timer(&chan->chan_timer))
__sock_put(chan->sk);
if (timer_pending(timer) && del_timer(timer))
chan_put(chan);
}
static void l2cap_state_change(struct l2cap_chan *chan, int state)
{
chan->state = state;
chan->ops->state_change(chan->data, state);
}
static void l2cap_chan_timeout(unsigned long arg)
......@@ -230,21 +249,21 @@ static void l2cap_chan_timeout(unsigned long arg)
struct sock *sk = chan->sk;
int reason;
BT_DBG("chan %p state %d", chan, sk->sk_state);
BT_DBG("chan %p state %d", chan, chan->state);
bh_lock_sock(sk);
if (sock_owned_by_user(sk)) {
/* sk is owned by user. Try again later */
l2cap_chan_set_timer(chan, HZ / 5);
__set_chan_timer(chan, HZ / 5);
bh_unlock_sock(sk);
sock_put(sk);
chan_put(chan);
return;
}
if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
reason = ECONNREFUSED;
else if (sk->sk_state == BT_CONNECT &&
else if (chan->state == BT_CONNECT &&
chan->sec_level != BT_SECURITY_SDP)
reason = ECONNREFUSED;
else
......@@ -254,8 +273,8 @@ static void l2cap_chan_timeout(unsigned long arg)
bh_unlock_sock(sk);
l2cap_sock_kill(sk);
sock_put(sk);
chan->ops->close(chan->data);
chan_put(chan);
}
struct l2cap_chan *l2cap_chan_create(struct sock *sk)
......@@ -274,6 +293,10 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan);
chan->state = BT_OPEN;
atomic_set(&chan->refcnt, 1);
return chan;
}
......@@ -283,13 +306,11 @@ void l2cap_chan_destroy(struct l2cap_chan *chan)
list_del(&chan->global_l);
write_unlock_bh(&chan_list_lock);
kfree(chan);
chan_put(chan);
}
static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
{
struct sock *sk = chan->sk;
BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
chan->psm, chan->dcid);
......@@ -320,7 +341,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
chan->omtu = L2CAP_DEFAULT_MTU;
}
sock_hold(sk);
chan_hold(chan);
list_add(&chan->list, &conn->chan_l);
}
......@@ -333,7 +354,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
struct l2cap_conn *conn = chan->conn;
struct sock *parent = bt_sk(sk)->parent;
l2cap_chan_clear_timer(chan);
__clear_chan_timer(chan);
BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
......@@ -342,13 +363,13 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
write_lock_bh(&conn->chan_lock);
list_del(&chan->list);
write_unlock_bh(&conn->chan_lock);
__sock_put(sk);
chan_put(chan);
chan->conn = NULL;
hci_conn_put(conn->hcon);
}
sk->sk_state = BT_CLOSED;
l2cap_state_change(chan, BT_CLOSED);
sock_set_flag(sk, SOCK_ZAPPED);
if (err)
......@@ -360,8 +381,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
} else
sk->sk_state_change(sk);
if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE &&
chan->conf_state & L2CAP_CONF_INPUT_DONE))
if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
test_bit(CONF_INPUT_DONE, &chan->conf_state)))
return;
skb_queue_purge(&chan->tx_q);
......@@ -369,9 +390,9 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
if (chan->mode == L2CAP_MODE_ERTM) {
struct srej_list *l, *tmp;
del_timer(&chan->retrans_timer);
del_timer(&chan->monitor_timer);
del_timer(&chan->ack_timer);
__clear_retrans_timer(chan);
__clear_monitor_timer(chan);
__clear_ack_timer(chan);
skb_queue_purge(&chan->srej_q);
skb_queue_purge(&chan->busy_q);
......@@ -391,15 +412,13 @@ static void l2cap_chan_cleanup_listen(struct sock *parent)
/* Close not yet accepted channels */
while ((sk = bt_accept_dequeue(parent, NULL))) {
l2cap_chan_clear_timer(l2cap_pi(sk)->chan);
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
__clear_chan_timer(chan);
lock_sock(sk);
l2cap_chan_close(l2cap_pi(sk)->chan, ECONNRESET);
l2cap_chan_close(chan, ECONNRESET);
release_sock(sk);
l2cap_sock_kill(sk);
chan->ops->close(chan->data);
}
parent->sk_state = BT_CLOSED;
sock_set_flag(parent, SOCK_ZAPPED);
}
void l2cap_chan_close(struct l2cap_chan *chan, int reason)
......@@ -407,19 +426,22 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
struct l2cap_conn *conn = chan->conn;
struct sock *sk = chan->sk;
BT_DBG("chan %p state %d socket %p", chan, sk->sk_state, sk->sk_socket);
BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
switch (sk->sk_state) {
switch (chan->state) {
case BT_LISTEN:
l2cap_chan_cleanup_listen(sk);
l2cap_state_change(chan, BT_CLOSED);
sock_set_flag(sk, SOCK_ZAPPED);
break;
case BT_CONNECTED:
case BT_CONFIG:
if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
conn->hcon->type == ACL_LINK) {
l2cap_chan_clear_timer(chan);
l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
__clear_chan_timer(chan);
__set_chan_timer(chan, sk->sk_sndtimeo);
l2cap_send_disconn_req(conn, chan, reason);
} else
l2cap_chan_del(chan, reason);
......@@ -435,7 +457,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
result = L2CAP_CR_SEC_BLOCK;
else
result = L2CAP_CR_BAD_PSM;
sk->sk_state = BT_DISCONN;
l2cap_state_change(chan, BT_DISCONN);
rsp.scid = cpu_to_le16(chan->dcid);
rsp.dcid = cpu_to_le16(chan->scid);
......@@ -547,13 +569,11 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
{
struct sk_buff *skb;
struct l2cap_hdr *lh;
struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
struct l2cap_conn *conn = chan->conn;
struct sock *sk = (struct sock *)pi;
int count, hlen = L2CAP_HDR_SIZE + 2;
u8 flags;
if (sk->sk_state != BT_CONNECTED)
if (chan->state != BT_CONNECTED)
return;
if (chan->fcs == L2CAP_FCS_CRC16)
......@@ -564,15 +584,11 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
count = min_t(unsigned int, conn->mtu, hlen);
control |= L2CAP_CTRL_FRAME_TYPE;
if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
control |= L2CAP_CTRL_FINAL;
chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
}
if (chan->conn_state & L2CAP_CONN_SEND_PBIT) {
if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
control |= L2CAP_CTRL_POLL;
chan->conn_state &= ~L2CAP_CONN_SEND_PBIT;
}
skb = bt_skb_alloc(count, GFP_ATOMIC);
if (!skb)
......@@ -600,9 +616,9 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
{
if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
control |= L2CAP_SUPER_RCV_NOT_READY;
chan->conn_state |= L2CAP_CONN_RNR_SENT;
set_bit(CONN_RNR_SENT, &chan->conn_state);
} else
control |= L2CAP_SUPER_RCV_READY;
......@@ -613,7 +629,7 @@ static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
{
return !(chan->conf_state & L2CAP_CONF_CONNECT_PEND);
return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
}
static void l2cap_do_start(struct l2cap_chan *chan)
......@@ -631,7 +647,7 @@ static void l2cap_do_start(struct l2cap_chan *chan)
req.psm = chan->psm;
chan->ident = l2cap_get_ident(conn);
chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
set_bit(CONF_CONNECT_PEND, &chan->conf_state);
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
sizeof(req), &req);
......@@ -678,9 +694,9 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
sk = chan->sk;
if (chan->mode == L2CAP_MODE_ERTM) {
del_timer(&chan->retrans_timer);
del_timer(&chan->monitor_timer);
del_timer(&chan->ack_timer);
__clear_retrans_timer(chan);
__clear_monitor_timer(chan);
__clear_ack_timer(chan);
}
req.dcid = cpu_to_le16(chan->dcid);
......@@ -688,7 +704,7 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
l2cap_send_cmd(conn, l2cap_get_ident(conn),
L2CAP_DISCONN_REQ, sizeof(req), &req);
sk->sk_state = BT_DISCONN;
l2cap_state_change(chan, BT_DISCONN);
sk->sk_err = err;
}
......@@ -711,7 +727,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
continue;
}
if (sk->sk_state == BT_CONNECT) {
if (chan->state == BT_CONNECT) {
struct l2cap_conn_req req;
if (!l2cap_check_security(chan) ||
......@@ -720,10 +736,9 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
continue;
}
if (!l2cap_mode_supported(chan->mode,
conn->feat_mask)
&& chan->conf_state &
L2CAP_CONF_STATE2_DEVICE) {
if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
&& test_bit(CONF_STATE2_DEVICE,
&chan->conf_state)) {
/* l2cap_chan_close() calls list_del(chan)
* so release the lock */
read_unlock_bh(&conn->chan_lock);
......@@ -737,12 +752,12 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
req.psm = chan->psm;
chan->ident = l2cap_get_ident(conn);
chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
set_bit(CONF_CONNECT_PEND, &chan->conf_state);
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
sizeof(req), &req);
} else if (sk->sk_state == BT_CONNECT2) {
} else if (chan->state == BT_CONNECT2) {
struct l2cap_conn_rsp rsp;
char buf[128];
rsp.scid = cpu_to_le16(chan->dcid);
......@@ -756,7 +771,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
parent->sk_data_ready(parent, 0);
} else {
sk->sk_state = BT_CONFIG;
l2cap_state_change(chan, BT_CONFIG);
rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
}
......@@ -768,13 +783,13 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
sizeof(rsp), &rsp);
if (chan->conf_state & L2CAP_CONF_REQ_SENT ||
if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
rsp.result != L2CAP_CR_SUCCESS) {
bh_unlock_sock(sk);
continue;
}
chan->conf_state |= L2CAP_CONF_REQ_SENT;
set_bit(CONF_REQ_SENT, &chan->conf_state);
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(chan, buf), buf);
chan->num_conf_req++;
......@@ -798,7 +813,7 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdadd
list_for_each_entry(c, &chan_list, global_l) {
struct sock *sk = c->sk;
if (state && sk->sk_state != state)
if (state && c->state != state)
continue;
if (c->scid == cid) {
......@@ -842,24 +857,16 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
goto clean;
}
sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
if (!sk)
goto clean;
chan = l2cap_chan_create(sk);
if (!chan) {
l2cap_sock_kill(sk);
chan = pchan->ops->new_connection(pchan->data);
if (!chan)
goto clean;
}
l2cap_pi(sk)->chan = chan;
sk = chan->sk;
write_lock_bh(&conn->chan_lock);
hci_conn_hold(conn->hcon);
l2cap_sock_init(sk, parent);
bacpy(&bt_sk(sk)->src, conn->src);
bacpy(&bt_sk(sk)->dst, conn->dst);
......@@ -867,9 +874,9 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
__l2cap_chan_add(conn, chan);
l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
__set_chan_timer(chan, sk->sk_sndtimeo);
sk->sk_state = BT_CONNECTED;
l2cap_state_change(chan, BT_CONNECTED);
parent->sk_data_ready(parent, 0);
write_unlock_bh(&conn->chan_lock);
......@@ -878,6 +885,23 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
bh_unlock_sock(parent);
}
static void l2cap_chan_ready(struct sock *sk)
{
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
struct sock *parent = bt_sk(sk)->parent;
BT_DBG("sk %p, parent %p", sk, parent);
chan->conf_state = 0;
__clear_chan_timer(chan);
l2cap_state_change(chan, BT_CONNECTED);
sk->sk_state_change(sk);
if (parent)
parent->sk_data_ready(parent, 0);
}
static void l2cap_conn_ready(struct l2cap_conn *conn)
{
struct l2cap_chan *chan;
......@@ -895,16 +919,15 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
bh_lock_sock(sk);
if (conn->hcon->type == LE_LINK) {
l2cap_chan_clear_timer(chan);
sk->sk_state = BT_CONNECTED;
sk->sk_state_change(sk);
}
if (smp_conn_security(conn, chan->sec_level))
l2cap_chan_ready(sk);
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
l2cap_chan_clear_timer(chan);
sk->sk_state = BT_CONNECTED;
} else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
__clear_chan_timer(chan);
l2cap_state_change(chan, BT_CONNECTED);
sk->sk_state_change(sk);
} else if (sk->sk_state == BT_CONNECT)
} else if (chan->state == BT_CONNECT)
l2cap_do_start(chan);
bh_unlock_sock(sk);
......@@ -942,6 +965,45 @@ static void l2cap_info_timeout(unsigned long arg)
l2cap_conn_start(conn);
}
static void l2cap_conn_del(struct hci_conn *hcon, int err)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct l2cap_chan *chan, *l;
struct sock *sk;
if (!conn)
return;
BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
kfree_skb(conn->rx_skb);
/* Kill channels */
list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
sk = chan->sk;
bh_lock_sock(sk);
l2cap_chan_del(chan, err);
bh_unlock_sock(sk);
chan->ops->close(chan->data);
}
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
del_timer_sync(&conn->info_timer);
if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
del_timer(&conn->security_timer);
hcon->l2cap_data = NULL;
kfree(conn);
}
static void security_timeout(unsigned long arg)
{
struct l2cap_conn *conn = (void *) arg;
l2cap_conn_del(conn->hcon, ETIMEDOUT);
}
static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
{
struct l2cap_conn *conn = hcon->l2cap_data;
......@@ -973,7 +1035,10 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
INIT_LIST_HEAD(&conn->chan_l);
if (hcon->type != LE_LINK)
if (hcon->type == LE_LINK)
setup_timer(&conn->security_timer, security_timeout,
(unsigned long) conn);
else
setup_timer(&conn->info_timer, l2cap_info_timeout,
(unsigned long) conn);
......@@ -982,35 +1047,6 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
return conn;
}
static void l2cap_conn_del(struct hci_conn *hcon, int err)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct l2cap_chan *chan, *l;
struct sock *sk;
if (!conn)
return;
BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
kfree_skb(conn->rx_skb);
/* Kill channels */
list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
sk = chan->sk;
bh_lock_sock(sk);
l2cap_chan_del(chan, err);
bh_unlock_sock(sk);
l2cap_sock_kill(sk);
}
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
del_timer_sync(&conn->info_timer);
hcon->l2cap_data = NULL;
kfree(conn);
}
static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
{
write_lock_bh(&conn->chan_lock);
......@@ -1032,7 +1068,7 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr
list_for_each_entry(c, &chan_list, global_l) {
struct sock *sk = c->sk;
if (state && sk->sk_state != state)
if (state && c->state != state)
continue;
if (c->psm == psm) {
......@@ -1099,14 +1135,14 @@ int l2cap_chan_connect(struct l2cap_chan *chan)
l2cap_chan_add(conn, chan);
sk->sk_state = BT_CONNECT;
l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
l2cap_state_change(chan, BT_CONNECT);
__set_chan_timer(chan, sk->sk_sndtimeo);
if (hcon->state == BT_CONNECTED) {
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
l2cap_chan_clear_timer(chan);
__clear_chan_timer(chan);
if (l2cap_check_security(chan))
sk->sk_state = BT_CONNECTED;
l2cap_state_change(chan, BT_CONNECTED);
} else
l2cap_do_start(chan);
}
......@@ -1166,7 +1202,7 @@ static void l2cap_monitor_timeout(unsigned long arg)
}
chan->retry_count++;
__mod_monitor_timer();
__set_monitor_timer(chan);
l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
bh_unlock_sock(sk);
......@@ -1181,9 +1217,9 @@ static void l2cap_retrans_timeout(unsigned long arg)
bh_lock_sock(sk);
chan->retry_count = 1;
__mod_monitor_timer();
__set_monitor_timer(chan);
chan->conn_state |= L2CAP_CONN_WAIT_F;
set_bit(CONN_WAIT_F, &chan->conn_state);
l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
bh_unlock_sock(sk);
......@@ -1205,7 +1241,7 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
}
if (!chan->unacked_frames)
del_timer(&chan->retrans_timer);
__clear_retrans_timer(chan);
}
void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
......@@ -1274,10 +1310,8 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
control &= L2CAP_CTRL_SAR;
if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
control |= L2CAP_CTRL_FINAL;
chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
}
control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
| (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
......@@ -1295,11 +1329,10 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
int l2cap_ertm_send(struct l2cap_chan *chan)
{
struct sk_buff *skb, *tx_skb;
struct sock *sk = chan->sk;
u16 control, fcs;
int nsent = 0;
if (sk->sk_state != BT_CONNECTED)
if (chan->state != BT_CONNECTED)
return -ENOTCONN;
while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
......@@ -1317,10 +1350,9 @@ int l2cap_ertm_send(struct l2cap_chan *chan)
control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
control &= L2CAP_CTRL_SAR;
if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
control |= L2CAP_CTRL_FINAL;
chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
}
control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
| (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
......@@ -1333,7 +1365,7 @@ int l2cap_ertm_send(struct l2cap_chan *chan)
l2cap_do_send(chan, tx_skb);
__mod_retrans_timer();
__set_retrans_timer(chan);
bt_cb(skb)->tx_seq = chan->next_tx_seq;
chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
......@@ -1372,9 +1404,9 @@ static void l2cap_send_ack(struct l2cap_chan *chan)
control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
control |= L2CAP_SUPER_RCV_NOT_READY;
chan->conn_state |= L2CAP_CONN_RNR_SENT;
set_bit(CONN_RNR_SENT, &chan->conn_state);
l2cap_send_sframe(chan, control);
return;
}
......@@ -1641,8 +1673,8 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
break;
}
if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
(chan->conn_state & L2CAP_CONN_WAIT_F)) {
if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
test_bit(CONN_WAIT_F, &chan->conn_state)) {
err = len;
break;
}
......@@ -1661,30 +1693,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
return err;
}
static void l2cap_chan_ready(struct sock *sk)
{
struct sock *parent = bt_sk(sk)->parent;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
BT_DBG("sk %p, parent %p", sk, parent);
chan->conf_state = 0;
l2cap_chan_clear_timer(chan);
if (!parent) {
/* Outgoing channel.
* Wake up socket sleeping on connect.
*/
sk->sk_state = BT_CONNECTED;
sk->sk_state_change(sk);
} else {
/* Incoming channel.
* Wake up socket sleeping on accept.
*/
parent->sk_data_ready(parent, 0);
}
}
/* Copy frame to all raw sockets on that connection */
static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
{
......@@ -1706,7 +1714,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
if (!nskb)
continue;
if (sock_queue_rcv_skb(sk, nskb))
if (chan->ops->recv(chan->data, nskb))
kfree_skb(nskb);
}
read_unlock(&conn->chan_lock);
......@@ -1901,7 +1909,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
switch (chan->mode) {
case L2CAP_MODE_STREAMING:
case L2CAP_MODE_ERTM:
if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE)
if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
break;
/* fall through */
......@@ -1948,7 +1956,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
break;
if (chan->fcs == L2CAP_FCS_NONE ||
chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
chan->fcs = L2CAP_FCS_NONE;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
}
......@@ -1971,7 +1979,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
break;
if (chan->fcs == L2CAP_FCS_NONE ||
chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
chan->fcs = L2CAP_FCS_NONE;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
}
......@@ -2023,7 +2031,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
case L2CAP_CONF_FCS:
if (val == L2CAP_FCS_NONE)
chan->conf_state |= L2CAP_CONF_NO_FCS_RECV;
set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
break;
......@@ -2043,7 +2051,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
switch (chan->mode) {
case L2CAP_MODE_STREAMING:
case L2CAP_MODE_ERTM:
if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
chan->mode = l2cap_select_mode(rfc.mode,
chan->conn->feat_mask);
break;
......@@ -2076,14 +2084,14 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
result = L2CAP_CONF_UNACCEPT;
else {
chan->omtu = mtu;
chan->conf_state |= L2CAP_CONF_MTU_DONE;
set_bit(CONF_MTU_DONE, &chan->conf_state);
}
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
switch (rfc.mode) {
case L2CAP_MODE_BASIC:
chan->fcs = L2CAP_FCS_NONE;
chan->conf_state |= L2CAP_CONF_MODE_DONE;
set_bit(CONF_MODE_DONE, &chan->conf_state);
break;
case L2CAP_MODE_ERTM:
......@@ -2100,7 +2108,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
rfc.monitor_timeout =
le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
chan->conf_state |= L2CAP_CONF_MODE_DONE;
set_bit(CONF_MODE_DONE, &chan->conf_state);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
sizeof(rfc), (unsigned long) &rfc);
......@@ -2113,7 +2121,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
chan->conf_state |= L2CAP_CONF_MODE_DONE;
set_bit(CONF_MODE_DONE, &chan->conf_state);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
sizeof(rfc), (unsigned long) &rfc);
......@@ -2128,7 +2136,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
}
if (result == L2CAP_CONF_SUCCESS)
chan->conf_state |= L2CAP_CONF_OUTPUT_DONE;
set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
}
rsp->scid = cpu_to_le16(chan->dcid);
rsp->result = cpu_to_le16(result);
......@@ -2170,7 +2178,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
if (olen == sizeof(rfc))
memcpy(&rfc, (void *)val, olen);
if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) &&
if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
rfc.mode != chan->mode)
return -ECONNREFUSED;
......@@ -2232,10 +2240,9 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
l2cap_send_cmd(conn, chan->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
if (chan->conf_state & L2CAP_CONF_REQ_SENT)
if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
return;
chan->conf_state |= L2CAP_CONF_REQ_SENT;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(chan, buf), buf);
chan->num_conf_req++;
......@@ -2335,17 +2342,11 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
goto response;
}
sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
if (!sk)
chan = pchan->ops->new_connection(pchan->data);
if (!chan)
goto response;
chan = l2cap_chan_create(sk);
if (!chan) {
l2cap_sock_kill(sk);
goto response;
}
l2cap_pi(sk)->chan = chan;
sk = chan->sk;
write_lock_bh(&conn->chan_lock);
......@@ -2353,13 +2354,12 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
if (__l2cap_get_chan_by_dcid(conn, scid)) {
write_unlock_bh(&conn->chan_lock);
sock_set_flag(sk, SOCK_ZAPPED);
l2cap_sock_kill(sk);
chan->ops->close(chan->data);
goto response;
}
hci_conn_hold(conn->hcon);
l2cap_sock_init(sk, parent);
bacpy(&bt_sk(sk)->src, conn->src);
bacpy(&bt_sk(sk)->dst, conn->dst);
chan->psm = psm;
......@@ -2371,29 +2371,29 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
dcid = chan->scid;
l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
__set_chan_timer(chan, sk->sk_sndtimeo);
chan->ident = cmd->ident;
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
if (l2cap_check_security(chan)) {
if (bt_sk(sk)->defer_setup) {
sk->sk_state = BT_CONNECT2;
l2cap_state_change(chan, BT_CONNECT2);
result = L2CAP_CR_PEND;
status = L2CAP_CS_AUTHOR_PEND;
parent->sk_data_ready(parent, 0);
} else {
sk->sk_state = BT_CONFIG;
l2cap_state_change(chan, BT_CONFIG);
result = L2CAP_CR_SUCCESS;
status = L2CAP_CS_NO_INFO;
}
} else {
sk->sk_state = BT_CONNECT2;
l2cap_state_change(chan, BT_CONNECT2);
result = L2CAP_CR_PEND;
status = L2CAP_CS_AUTHEN_PEND;
}
} else {
sk->sk_state = BT_CONNECT2;
l2cap_state_change(chan, BT_CONNECT2);
result = L2CAP_CR_PEND;
status = L2CAP_CS_NO_INFO;
}
......@@ -2424,10 +2424,10 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
L2CAP_INFO_REQ, sizeof(info), &info);
}
if (chan && !(chan->conf_state & L2CAP_CONF_REQ_SENT) &&
if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
result == L2CAP_CR_SUCCESS) {
u8 buf[128];
chan->conf_state |= L2CAP_CONF_REQ_SENT;
set_bit(CONF_REQ_SENT, &chan->conf_state);
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(chan, buf), buf);
chan->num_conf_req++;
......@@ -2465,31 +2465,29 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
switch (result) {
case L2CAP_CR_SUCCESS:
sk->sk_state = BT_CONFIG;
l2cap_state_change(chan, BT_CONFIG);
chan->ident = 0;
chan->dcid = dcid;
chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
if (chan->conf_state & L2CAP_CONF_REQ_SENT)
if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
break;
chan->conf_state |= L2CAP_CONF_REQ_SENT;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(chan, req), req);
chan->num_conf_req++;
break;
case L2CAP_CR_PEND:
chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
set_bit(CONF_CONNECT_PEND, &chan->conf_state);
break;
default:
/* don't delete l2cap channel if sk is owned by user */
if (sock_owned_by_user(sk)) {
sk->sk_state = BT_DISCONN;
l2cap_chan_clear_timer(chan);
l2cap_chan_set_timer(chan, HZ / 5);
l2cap_state_change(chan, BT_DISCONN);
__clear_chan_timer(chan);
__set_chan_timer(chan, HZ / 5);
break;
}
......@@ -2503,14 +2501,12 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
static inline void set_default_fcs(struct l2cap_chan *chan)
{
struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
/* FCS is enabled only in ERTM or streaming mode, if one or both
* sides request it.
*/
if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
chan->fcs = L2CAP_FCS_NONE;
else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV))
else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
chan->fcs = L2CAP_FCS_CRC16;
}
......@@ -2534,7 +2530,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
sk = chan->sk;
if (sk->sk_state != BT_CONFIG) {
if (chan->state != BT_CONFIG) {
struct l2cap_cmd_rej rej;
rej.reason = cpu_to_le16(0x0002);
......@@ -2577,13 +2573,13 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
/* Reset config buffer. */
chan->conf_len = 0;
if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE))
if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
goto unlock;
if (chan->conf_state & L2CAP_CONF_INPUT_DONE) {
if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
set_default_fcs(chan);
sk->sk_state = BT_CONNECTED;
l2cap_state_change(chan, BT_CONNECTED);
chan->next_tx_seq = 0;
chan->expected_tx_seq = 0;
......@@ -2595,9 +2591,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
goto unlock;
}
if (!(chan->conf_state & L2CAP_CONF_REQ_SENT)) {
if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
u8 buf[64];
chan->conf_state |= L2CAP_CONF_REQ_SENT;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(chan, buf), buf);
chan->num_conf_req++;
......@@ -2662,7 +2657,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
default:
sk->sk_err = ECONNRESET;
l2cap_chan_set_timer(chan, HZ * 5);
__set_chan_timer(chan, HZ * 5);
l2cap_send_disconn_req(conn, chan, ECONNRESET);
goto done;
}
......@@ -2670,12 +2665,12 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
if (flags & 0x01)
goto done;
chan->conf_state |= L2CAP_CONF_INPUT_DONE;
set_bit(CONF_INPUT_DONE, &chan->conf_state);
if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) {
if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
set_default_fcs(chan);
sk->sk_state = BT_CONNECTED;
l2cap_state_change(chan, BT_CONNECTED);
chan->next_tx_seq = 0;
chan->expected_tx_seq = 0;
skb_queue_head_init(&chan->tx_q);
......@@ -2717,9 +2712,9 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
/* don't delete l2cap channel if sk is owned by user */
if (sock_owned_by_user(sk)) {
sk->sk_state = BT_DISCONN;
l2cap_chan_clear_timer(chan);
l2cap_chan_set_timer(chan, HZ / 5);
l2cap_state_change(chan, BT_DISCONN);
__clear_chan_timer(chan);
__set_chan_timer(chan, HZ / 5);
bh_unlock_sock(sk);
return 0;
}
......@@ -2727,7 +2722,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
l2cap_chan_del(chan, ECONNRESET);
bh_unlock_sock(sk);
l2cap_sock_kill(sk);
chan->ops->close(chan->data);
return 0;
}
......@@ -2751,9 +2746,9 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
/* don't delete l2cap channel if sk is owned by user */
if (sock_owned_by_user(sk)) {
sk->sk_state = BT_DISCONN;
l2cap_chan_clear_timer(chan);
l2cap_chan_set_timer(chan, HZ / 5);
l2cap_state_change(chan,BT_DISCONN);
__clear_chan_timer(chan);
__set_chan_timer(chan, HZ / 5);
bh_unlock_sock(sk);
return 0;
}
......@@ -2761,7 +2756,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
l2cap_chan_del(chan, 0);
bh_unlock_sock(sk);
l2cap_sock_kill(sk);
chan->ops->close(chan->data);
return 0;
}
......@@ -3069,18 +3064,18 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
control |= L2CAP_SUPER_RCV_NOT_READY;
l2cap_send_sframe(chan, control);
chan->conn_state |= L2CAP_CONN_RNR_SENT;
set_bit(CONN_RNR_SENT, &chan->conn_state);
}
if (chan->conn_state & L2CAP_CONN_REMOTE_BUSY)
if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
l2cap_retransmit_frames(chan);
l2cap_ertm_send(chan);
if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
chan->frames_sent == 0) {
control |= L2CAP_SUPER_RCV_READY;
l2cap_send_sframe(chan, control);
......@@ -3136,13 +3131,13 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk
switch (control & L2CAP_CTRL_SAR) {
case L2CAP_SDU_UNSEGMENTED:
if (chan->conn_state & L2CAP_CONN_SAR_SDU)
if (test_bit(CONN_SAR_SDU, &chan->conn_state))
goto drop;
return sock_queue_rcv_skb(chan->sk, skb);
return chan->ops->recv(chan->data, skb);
case L2CAP_SDU_START:
if (chan->conn_state & L2CAP_CONN_SAR_SDU)
if (test_bit(CONN_SAR_SDU, &chan->conn_state))
goto drop;
chan->sdu_len = get_unaligned_le16(skb->data);
......@@ -3161,12 +3156,12 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
chan->conn_state |= L2CAP_CONN_SAR_SDU;
set_bit(CONN_SAR_SDU, &chan->conn_state);
chan->partial_sdu_len = skb->len;
break;
case L2CAP_SDU_CONTINUE:
if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
goto disconnect;
if (!chan->sdu)
......@@ -3181,13 +3176,13 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk
break;
case L2CAP_SDU_END:
if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
goto disconnect;
if (!chan->sdu)
goto disconnect;
if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) {
if (!test_bit(CONN_SAR_RETRY, &chan->conn_state)) {
chan->partial_sdu_len += skb->len;
if (chan->partial_sdu_len > chan->imtu)
......@@ -3201,19 +3196,19 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk
_skb = skb_clone(chan->sdu, GFP_ATOMIC);
if (!_skb) {
chan->conn_state |= L2CAP_CONN_SAR_RETRY;
set_bit(CONN_SAR_RETRY, &chan->conn_state);
return -ENOMEM;
}
err = sock_queue_rcv_skb(chan->sk, _skb);
err = chan->ops->recv(chan->data, _skb);
if (err < 0) {
kfree_skb(_skb);
chan->conn_state |= L2CAP_CONN_SAR_RETRY;
set_bit(CONN_SAR_RETRY, &chan->conn_state);
return err;
}
chan->conn_state &= ~L2CAP_CONN_SAR_RETRY;
chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
clear_bit(CONN_SAR_RETRY, &chan->conn_state);
clear_bit(CONN_SAR_SDU, &chan->conn_state);
kfree_skb(chan->sdu);
break;
......@@ -3249,7 +3244,7 @@ static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
chan->buffer_seq = (chan->buffer_seq + 1) % 64;
}
if (!(chan->conn_state & L2CAP_CONN_RNR_SENT))
if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
goto done;
control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
......@@ -3257,14 +3252,14 @@ static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
l2cap_send_sframe(chan, control);
chan->retry_count = 1;
del_timer(&chan->retrans_timer);
__mod_monitor_timer();
__clear_retrans_timer(chan);
__set_monitor_timer(chan);
chan->conn_state |= L2CAP_CONN_WAIT_F;
set_bit(CONN_WAIT_F, &chan->conn_state);
done:
chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
chan->conn_state &= ~L2CAP_CONN_RNR_SENT;
clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
clear_bit(CONN_RNR_SENT, &chan->conn_state);
BT_DBG("chan %p, Exit local busy", chan);
......@@ -3322,7 +3317,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c
{
int sctrl, err;
if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
__skb_queue_tail(&chan->busy_q, skb);
return l2cap_try_push_rx_skb(chan);
......@@ -3339,7 +3334,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c
/* Busy Condition */
BT_DBG("chan %p, Enter local busy", chan);
chan->conn_state |= L2CAP_CONN_LOCAL_BUSY;
set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
__skb_queue_tail(&chan->busy_q, skb);
......@@ -3347,9 +3342,9 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c
sctrl |= L2CAP_SUPER_RCV_NOT_READY;
l2cap_send_sframe(chan, sctrl);
chan->conn_state |= L2CAP_CONN_RNR_SENT;
set_bit(CONN_RNR_SENT, &chan->conn_state);
del_timer(&chan->ack_timer);
__clear_ack_timer(chan);
queue_work(_busy_wq, &chan->busy_work);
......@@ -3368,19 +3363,19 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf
switch (control & L2CAP_CTRL_SAR) {
case L2CAP_SDU_UNSEGMENTED:
if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
if (test_bit(CONN_SAR_SDU, &chan->conn_state)) {
kfree_skb(chan->sdu);
break;
}
err = sock_queue_rcv_skb(chan->sk, skb);
err = chan->ops->recv(chan->data, skb);
if (!err)
return 0;
break;
case L2CAP_SDU_START:
if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
if (test_bit(CONN_SAR_SDU, &chan->conn_state)) {
kfree_skb(chan->sdu);
break;
}
......@@ -3401,13 +3396,13 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
chan->conn_state |= L2CAP_CONN_SAR_SDU;
set_bit(CONN_SAR_SDU, &chan->conn_state);
chan->partial_sdu_len = skb->len;
err = 0;
break;
case L2CAP_SDU_CONTINUE:
if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
break;
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
......@@ -3421,12 +3416,12 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf
break;
case L2CAP_SDU_END:
if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
break;
memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
clear_bit(CONN_SAR_SDU, &chan->conn_state);
chan->partial_sdu_len += skb->len;
if (chan->partial_sdu_len > chan->imtu)
......@@ -3434,7 +3429,7 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf
if (chan->partial_sdu_len == chan->sdu_len) {
_skb = skb_clone(chan->sdu, GFP_ATOMIC);
err = sock_queue_rcv_skb(chan->sk, _skb);
err = chan->ops->recv(chan->data, _skb);
if (err < 0)
kfree_skb(_skb);
}
......@@ -3517,11 +3512,11 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
tx_seq, rx_control);
if (L2CAP_CTRL_FINAL & rx_control &&
chan->conn_state & L2CAP_CONN_WAIT_F) {
del_timer(&chan->monitor_timer);
test_bit(CONN_WAIT_F, &chan->conn_state)) {
__clear_monitor_timer(chan);
if (chan->unacked_frames > 0)
__mod_retrans_timer();
chan->conn_state &= ~L2CAP_CONN_WAIT_F;
__set_retrans_timer(chan);
clear_bit(CONN_WAIT_F, &chan->conn_state);
}
chan->expected_ack_seq = req_seq;
......@@ -3540,10 +3535,10 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
goto drop;
}
if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY)
if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
goto drop;
if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
struct srej_list *first;
first = list_first_entry(&chan->srej_l,
......@@ -3557,7 +3552,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
if (list_empty(&chan->srej_l)) {
chan->buffer_seq = chan->buffer_seq_srej;
chan->conn_state &= ~L2CAP_CONN_SREJ_SENT;
clear_bit(CONN_SREJ_SENT, &chan->conn_state);
l2cap_send_ack(chan);
BT_DBG("chan %p, Exit SREJ_SENT", chan);
}
......@@ -3586,7 +3581,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
if (tx_seq_offset < expected_tx_seq_offset)
goto drop;
chan->conn_state |= L2CAP_CONN_SREJ_SENT;
set_bit(CONN_SREJ_SENT, &chan->conn_state);
BT_DBG("chan %p, Enter SREJ", chan);
......@@ -3597,18 +3592,18 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
__skb_queue_head_init(&chan->busy_q);
l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
chan->conn_state |= L2CAP_CONN_SEND_PBIT;
set_bit(CONN_SEND_PBIT, &chan->conn_state);
l2cap_send_srejframe(chan, tx_seq);
del_timer(&chan->ack_timer);
__clear_ack_timer(chan);
}
return 0;
expected:
chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
bt_cb(skb)->tx_seq = tx_seq;
bt_cb(skb)->sar = sar;
__skb_queue_tail(&chan->srej_q, skb);
......@@ -3620,13 +3615,11 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
return 0;
if (rx_control & L2CAP_CTRL_FINAL) {
if (chan->conn_state & L2CAP_CONN_REJ_ACT)
chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
else
if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
l2cap_retransmit_frames(chan);
}
__mod_ack_timer();
__set_ack_timer(chan);
chan->num_acked = (chan->num_acked + 1) % num_to_ack;
if (chan->num_acked == num_to_ack - 1)
......@@ -3648,33 +3641,31 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co
l2cap_drop_acked_frames(chan);
if (rx_control & L2CAP_CTRL_POLL) {
chan->conn_state |= L2CAP_CONN_SEND_FBIT;
if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
set_bit(CONN_SEND_FBIT, &chan->conn_state);
if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
(chan->unacked_frames > 0))
__mod_retrans_timer();
__set_retrans_timer(chan);
chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
l2cap_send_srejtail(chan);
} else {
l2cap_send_i_or_rr_or_rnr(chan);
}
} else if (rx_control & L2CAP_CTRL_FINAL) {
chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
if (chan->conn_state & L2CAP_CONN_REJ_ACT)
chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
else
if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
l2cap_retransmit_frames(chan);
} else {
if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
(chan->unacked_frames > 0))
__mod_retrans_timer();
__set_retrans_timer(chan);
chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
if (chan->conn_state & L2CAP_CONN_SREJ_SENT)
clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
l2cap_send_ack(chan);
else
l2cap_ertm_send(chan);
......@@ -3687,21 +3678,19 @@ static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_c
BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
chan->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(chan);
if (rx_control & L2CAP_CTRL_FINAL) {
if (chan->conn_state & L2CAP_CONN_REJ_ACT)
chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
else
if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
l2cap_retransmit_frames(chan);
} else {
l2cap_retransmit_frames(chan);
if (chan->conn_state & L2CAP_CONN_WAIT_F)
chan->conn_state |= L2CAP_CONN_REJ_ACT;
if (test_bit(CONN_WAIT_F, &chan->conn_state))
set_bit(CONN_REJ_ACT, &chan->conn_state);
}
}
static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
......@@ -3710,32 +3699,32 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_
BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
if (rx_control & L2CAP_CTRL_POLL) {
chan->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(chan);
chan->conn_state |= L2CAP_CONN_SEND_FBIT;
set_bit(CONN_SEND_FBIT, &chan->conn_state);
l2cap_retransmit_one_frame(chan, tx_seq);
l2cap_ertm_send(chan);
if (chan->conn_state & L2CAP_CONN_WAIT_F) {
if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
chan->srej_save_reqseq = tx_seq;
chan->conn_state |= L2CAP_CONN_SREJ_ACT;
set_bit(CONN_SREJ_ACT, &chan->conn_state);
}
} else if (rx_control & L2CAP_CTRL_FINAL) {
if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) &&
if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
chan->srej_save_reqseq == tx_seq)
chan->conn_state &= ~L2CAP_CONN_SREJ_ACT;
clear_bit(CONN_SREJ_ACT, &chan->conn_state);
else
l2cap_retransmit_one_frame(chan, tx_seq);
} else {
l2cap_retransmit_one_frame(chan, tx_seq);
if (chan->conn_state & L2CAP_CONN_WAIT_F) {
if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
chan->srej_save_reqseq = tx_seq;
chan->conn_state |= L2CAP_CONN_SREJ_ACT;
set_bit(CONN_SREJ_ACT, &chan->conn_state);
}
}
}
......@@ -3746,15 +3735,15 @@ static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_c
BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
chan->conn_state |= L2CAP_CONN_REMOTE_BUSY;
set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
chan->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(chan);
if (rx_control & L2CAP_CTRL_POLL)
chan->conn_state |= L2CAP_CONN_SEND_FBIT;
set_bit(CONN_SEND_FBIT, &chan->conn_state);
if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) {
del_timer(&chan->retrans_timer);
if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
__clear_retrans_timer(chan);
if (rx_control & L2CAP_CTRL_POLL)
l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
return;
......@@ -3771,11 +3760,11 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont
BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
if (L2CAP_CTRL_FINAL & rx_control &&
chan->conn_state & L2CAP_CONN_WAIT_F) {
del_timer(&chan->monitor_timer);
test_bit(CONN_WAIT_F, &chan->conn_state)) {
__clear_monitor_timer(chan);
if (chan->unacked_frames > 0)
__mod_retrans_timer();
chan->conn_state &= ~L2CAP_CONN_WAIT_F;
__set_retrans_timer(chan);
clear_bit(CONN_WAIT_F, &chan->conn_state);
}
switch (rx_control & L2CAP_CTRL_SUPERVISE) {
......@@ -3888,7 +3877,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
BT_DBG("chan %p, len %d", chan, skb->len);
if (sk->sk_state != BT_CONNECTED)
if (chan->state != BT_CONNECTED)
goto drop;
switch (chan->mode) {
......@@ -3901,7 +3890,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
if (chan->imtu < skb->len)
goto drop;
if (!sock_queue_rcv_skb(sk, skb))
if (!chan->ops->recv(chan->data, skb))
goto done;
break;
......@@ -3973,13 +3962,13 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
BT_DBG("sk %p, len %d", sk, skb->len);
if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
goto drop;
if (l2cap_pi(sk)->chan->imtu < skb->len)
if (chan->imtu < skb->len)
goto drop;
if (!sock_queue_rcv_skb(sk, skb))
if (!chan->ops->recv(chan->data, skb))
goto done;
drop:
......@@ -4006,13 +3995,13 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct
BT_DBG("sk %p, len %d", sk, skb->len);
if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
goto drop;
if (l2cap_pi(sk)->chan->imtu < skb->len)
if (chan->imtu < skb->len)
goto drop;
if (!sock_queue_rcv_skb(sk, skb))
if (!chan->ops->recv(chan->data, skb))
goto done;
drop:
......@@ -4057,6 +4046,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
l2cap_att_channel(conn, cid, skb);
break;
case L2CAP_CID_SMP:
if (smp_sig_channel(conn, skb))
l2cap_conn_del(conn->hcon, EACCES);
break;
default:
l2cap_data_channel(conn, cid, skb);
break;
......@@ -4080,7 +4074,7 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
list_for_each_entry(c, &chan_list, global_l) {
struct sock *sk = c->sk;
if (sk->sk_state != BT_LISTEN)
if (c->state != BT_LISTEN)
continue;
if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
......@@ -4124,7 +4118,7 @@ static int l2cap_disconn_ind(struct hci_conn *hcon)
BT_DBG("hcon %p", hcon);
if (hcon->type != ACL_LINK || !conn)
if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
return 0x13;
return conn->disc_reason;
......@@ -4149,13 +4143,13 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
if (encrypt == 0x00) {
if (chan->sec_level == BT_SECURITY_MEDIUM) {
l2cap_chan_clear_timer(chan);
l2cap_chan_set_timer(chan, HZ * 5);
__clear_chan_timer(chan);
__set_chan_timer(chan, HZ * 5);
} else if (chan->sec_level == BT_SECURITY_HIGH)
l2cap_chan_close(chan, ECONNREFUSED);
} else {
if (chan->sec_level == BT_SECURITY_MEDIUM)
l2cap_chan_clear_timer(chan);
__clear_chan_timer(chan);
}
}
......@@ -4176,50 +4170,72 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
bh_lock_sock(sk);
if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) {
BT_DBG("chan->scid %d", chan->scid);
if (chan->scid == L2CAP_CID_LE_DATA) {
if (!status && encrypt) {
chan->sec_level = hcon->sec_level;
del_timer(&conn->security_timer);
l2cap_chan_ready(sk);
}
bh_unlock_sock(sk);
continue;
}
if (!status && (sk->sk_state == BT_CONNECTED ||
sk->sk_state == BT_CONFIG)) {
if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
bh_unlock_sock(sk);
continue;
}
if (!status && (chan->state == BT_CONNECTED ||
chan->state == BT_CONFIG)) {
l2cap_check_encryption(chan, encrypt);
bh_unlock_sock(sk);
continue;
}
if (sk->sk_state == BT_CONNECT) {
if (chan->state == BT_CONNECT) {
if (!status) {
struct l2cap_conn_req req;
req.scid = cpu_to_le16(chan->scid);
req.psm = chan->psm;
chan->ident = l2cap_get_ident(conn);
chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
set_bit(CONF_CONNECT_PEND, &chan->conf_state);
l2cap_send_cmd(conn, chan->ident,
L2CAP_CONN_REQ, sizeof(req), &req);
} else {
l2cap_chan_clear_timer(chan);
l2cap_chan_set_timer(chan, HZ / 10);
__clear_chan_timer(chan);
__set_chan_timer(chan, HZ / 10);
}
} else if (sk->sk_state == BT_CONNECT2) {
} else if (chan->state == BT_CONNECT2) {
struct l2cap_conn_rsp rsp;
__u16 result;
__u16 res, stat;
if (!status) {
sk->sk_state = BT_CONFIG;
result = L2CAP_CR_SUCCESS;
if (bt_sk(sk)->defer_setup) {
struct sock *parent = bt_sk(sk)->parent;
res = L2CAP_CR_PEND;
stat = L2CAP_CS_AUTHOR_PEND;
parent->sk_data_ready(parent, 0);
} else {
sk->sk_state = BT_DISCONN;
l2cap_chan_set_timer(chan, HZ / 10);
result = L2CAP_CR_SEC_BLOCK;
l2cap_state_change(chan, BT_CONFIG);
res = L2CAP_CR_SUCCESS;
stat = L2CAP_CS_NO_INFO;
}
} else {
l2cap_state_change(chan, BT_DISCONN);
__set_chan_timer(chan, HZ / 10);
res = L2CAP_CR_SEC_BLOCK;
stat = L2CAP_CS_NO_INFO;
}
rsp.scid = cpu_to_le16(chan->dcid);
rsp.dcid = cpu_to_le16(chan->scid);
rsp.result = cpu_to_le16(result);
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
rsp.result = cpu_to_le16(res);
rsp.status = cpu_to_le16(stat);
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
sizeof(rsp), &rsp);
}
......@@ -4355,10 +4371,10 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p)
seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
batostr(&bt_sk(sk)->src),
batostr(&bt_sk(sk)->dst),
sk->sk_state, __le16_to_cpu(c->psm),
c->state, __le16_to_cpu(c->psm),
c->scid, c->dcid, c->imtu, c->omtu,
c->sec_level, c->mode);
}
}
read_unlock_bh(&chan_list_lock);
......
......@@ -29,8 +29,11 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/smp.h>
static const struct proto_ops l2cap_sock_ops;
static void l2cap_sock_init(struct sock *sk, struct sock *parent);
static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio);
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
{
......@@ -87,6 +90,8 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
chan->sec_level = BT_SECURITY_SDP;
bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
chan->state = BT_BOUND;
sk->sk_state = BT_BOUND;
done:
......@@ -212,6 +217,8 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
sk->sk_max_ack_backlog = backlog;
sk->sk_ack_backlog = 0;
chan->state = BT_LISTEN;
sk->sk_state = BT_LISTEN;
done:
......@@ -505,7 +512,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
chan->mode = opts.mode;
switch (chan->mode) {
case L2CAP_MODE_BASIC:
chan->conf_state &= ~L2CAP_CONF_STATE2_DEVICE;
clear_bit(CONF_STATE2_DEVICE, &chan->conf_state);
break;
case L2CAP_MODE_ERTM:
case L2CAP_MODE_STREAMING:
......@@ -556,6 +563,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
struct bt_security sec;
struct bt_power pwr;
struct l2cap_conn *conn;
int len, err = 0;
u32 opt;
......@@ -592,6 +600,20 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
}
chan->sec_level = sec.level;
conn = chan->conn;
if (conn && chan->scid == L2CAP_CID_LE_DATA) {
if (!conn->hcon->out) {
err = -EINVAL;
break;
}
if (smp_conn_security(conn, sec.level))
break;
err = 0;
sk->sk_state = BT_CONFIG;
}
break;
case BT_DEFER_SETUP:
......@@ -711,7 +733,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
/* Kill socket (only if zapped and orphan)
* Must be called on unlocked socket.
*/
void l2cap_sock_kill(struct sock *sk)
static void l2cap_sock_kill(struct sock *sk)
{
if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
return;
......@@ -773,6 +795,49 @@ static int l2cap_sock_release(struct socket *sock)
return err;
}
static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data)
{
struct sock *sk, *parent = data;
sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP,
GFP_ATOMIC);
if (!sk)
return NULL;
l2cap_sock_init(sk, parent);
return l2cap_pi(sk)->chan;
}
static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
{
struct sock *sk = data;
return sock_queue_rcv_skb(sk, skb);
}
static void l2cap_sock_close_cb(void *data)
{
struct sock *sk = data;
l2cap_sock_kill(sk);
}
static void l2cap_sock_state_change_cb(void *data, int state)
{
struct sock *sk = data;
sk->sk_state = state;
}
static struct l2cap_ops l2cap_chan_ops = {
.name = "L2CAP Socket Interface",
.new_connection = l2cap_sock_new_connection_cb,
.recv = l2cap_sock_recv_cb,
.close = l2cap_sock_close_cb,
.state_change = l2cap_sock_state_change_cb,
};
static void l2cap_sock_destruct(struct sock *sk)
{
BT_DBG("sk %p", sk);
......@@ -781,7 +846,7 @@ static void l2cap_sock_destruct(struct sock *sk)
skb_queue_purge(&sk->sk_write_queue);
}
void l2cap_sock_init(struct sock *sk, struct sock *parent)
static void l2cap_sock_init(struct sock *sk, struct sock *parent)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct l2cap_chan *chan = pi->chan;
......@@ -826,7 +891,7 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent)
chan->omtu = 0;
if (!disable_ertm && sk->sk_type == SOCK_STREAM) {
chan->mode = L2CAP_MODE_ERTM;
chan->conf_state |= L2CAP_CONF_STATE2_DEVICE;
set_bit(CONF_STATE2_DEVICE, &chan->conf_state);
} else {
chan->mode = L2CAP_MODE_BASIC;
}
......@@ -838,10 +903,14 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent)
chan->force_reliable = 0;
chan->flushable = BT_FLUSHABLE_OFF;
chan->force_active = BT_POWER_FORCE_ACTIVE_ON;
}
/* Default config options */
chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
chan->data = sk;
chan->ops = &l2cap_chan_ops;
}
static struct proto l2cap_proto = {
......@@ -850,9 +919,10 @@ static struct proto l2cap_proto = {
.obj_size = sizeof(struct l2cap_pinfo)
};
struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
{
struct sock *sk;
struct l2cap_chan *chan;
sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto);
if (!sk)
......@@ -869,6 +939,14 @@ struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, g
sk->sk_protocol = proto;
sk->sk_state = BT_OPEN;
chan = l2cap_chan_create(sk);
if (!chan) {
l2cap_sock_kill(sk);
return NULL;
}
l2cap_pi(sk)->chan = chan;
return sk;
}
......@@ -876,7 +954,6 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
int kern)
{
struct sock *sk;
struct l2cap_chan *chan;
BT_DBG("sock %p", sock);
......@@ -895,14 +972,6 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
if (!sk)
return -ENOMEM;
chan = l2cap_chan_create(sk);
if (!chan) {
l2cap_sock_kill(sk);
return -ENOMEM;
}
l2cap_pi(sk)->chan = chan;
l2cap_sock_init(sk, NULL);
return 0;
}
......
......@@ -990,7 +990,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
put_unaligned_le16(conn->handle, &dc.handle);
dc.reason = 0x13; /* Remote User Terminated Connection */
err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
}
unlock:
......@@ -1666,6 +1666,70 @@ static int stop_discovery(struct sock *sk, u16 index)
return err;
}
static int block_device(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
struct hci_dev *hdev;
struct mgmt_cp_block_device *cp;
int err;
BT_DBG("hci%u", index);
cp = (void *) data;
if (len != sizeof(*cp))
return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
EINVAL);
hdev = hci_dev_get(index);
if (!hdev)
return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
ENODEV);
err = hci_blacklist_add(hdev, &cp->bdaddr);
if (err < 0)
err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
else
err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
NULL, 0);
hci_dev_put(hdev);
return err;
}
static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
struct hci_dev *hdev;
struct mgmt_cp_unblock_device *cp;
int err;
BT_DBG("hci%u", index);
cp = (void *) data;
if (len != sizeof(*cp))
return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
EINVAL);
hdev = hci_dev_get(index);
if (!hdev)
return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
ENODEV);
err = hci_blacklist_del(hdev, &cp->bdaddr);
if (err < 0)
err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
else
err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
NULL, 0);
hci_dev_put(hdev);
return err;
}
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
{
unsigned char *buf;
......@@ -1780,6 +1844,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case MGMT_OP_STOP_DISCOVERY:
err = stop_discovery(sk, index);
break;
case MGMT_OP_BLOCK_DEVICE:
err = block_device(sk, index, buf + sizeof(*hdr), len);
break;
case MGMT_OP_UNBLOCK_DEVICE:
err = unblock_device(sk, index, buf + sizeof(*hdr), len);
break;
default:
BT_DBG("Unknown op %u", opcode);
err = cmd_status(sk, index, opcode, 0x01);
......
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/smp.h>
#include <linux/crypto.h>
#include <crypto/b128ops.h>
#define SMP_TIMEOUT 30000 /* 30 seconds */
static inline void swap128(u8 src[16], u8 dst[16])
{
int i;
for (i = 0; i < 16; i++)
dst[15 - i] = src[i];
}
static inline void swap56(u8 src[7], u8 dst[7])
{
int i;
for (i = 0; i < 7; i++)
dst[6 - i] = src[i];
}
static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
{
struct blkcipher_desc desc;
struct scatterlist sg;
int err, iv_len;
unsigned char iv[128];
if (tfm == NULL) {
BT_ERR("tfm %p", tfm);
return -EINVAL;
}
desc.tfm = tfm;
desc.flags = 0;
err = crypto_blkcipher_setkey(tfm, k, 16);
if (err) {
BT_ERR("cipher setkey failed: %d", err);
return err;
}
sg_init_one(&sg, r, 16);
iv_len = crypto_blkcipher_ivsize(tfm);
if (iv_len) {
memset(&iv, 0xff, iv_len);
crypto_blkcipher_set_iv(tfm, iv, iv_len);
}
err = crypto_blkcipher_encrypt(&desc, &sg, &sg, 16);
if (err)
BT_ERR("Encrypt data error %d", err);
return err;
}
static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia,
u8 _rat, bdaddr_t *ra, u8 res[16])
{
u8 p1[16], p2[16];
int err;
memset(p1, 0, 16);
/* p1 = pres || preq || _rat || _iat */
swap56(pres, p1);
swap56(preq, p1 + 7);
p1[14] = _rat;
p1[15] = _iat;
memset(p2, 0, 16);
/* p2 = padding || ia || ra */
baswap((bdaddr_t *) (p2 + 4), ia);
baswap((bdaddr_t *) (p2 + 10), ra);
/* res = r XOR p1 */
u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
/* res = e(k, res) */
err = smp_e(tfm, k, res);
if (err) {
BT_ERR("Encrypt data error");
return err;
}
/* res = res XOR p2 */
u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
/* res = e(k, res) */
err = smp_e(tfm, k, res);
if (err)
BT_ERR("Encrypt data error");
return err;
}
static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16],
u8 r1[16], u8 r2[16], u8 _r[16])
{
int err;
/* Just least significant octets from r1 and r2 are considered */
memcpy(_r, r1 + 8, 8);
memcpy(_r + 8, r2 + 8, 8);
err = smp_e(tfm, k, _r);
if (err)
BT_ERR("Encrypt data error");
return err;
}
static int smp_rand(u8 *buf)
{
get_random_bytes(buf, 16);
return 0;
}
static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code,
u16 dlen, void *data)
{
struct sk_buff *skb;
struct l2cap_hdr *lh;
int len;
len = L2CAP_HDR_SIZE + sizeof(code) + dlen;
if (len > conn->mtu)
return NULL;
skb = bt_skb_alloc(len, GFP_ATOMIC);
if (!skb)
return NULL;
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
lh->len = cpu_to_le16(sizeof(code) + dlen);
lh->cid = cpu_to_le16(L2CAP_CID_SMP);
memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));
memcpy(skb_put(skb, dlen), data, dlen);
return skb;
}
static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
{
struct sk_buff *skb = smp_build_cmd(conn, code, len, data);
BT_DBG("code 0x%2.2x", code);
if (!skb)
return;
hci_send_acl(conn->hcon, skb, 0);
}
static __u8 seclevel_to_authreq(__u8 level)
{
switch (level) {
case BT_SECURITY_HIGH:
/* Right now we don't support bonding */
return SMP_AUTH_MITM;
default:
return SMP_AUTH_NONE;
}
}
static void build_pairing_cmd(struct l2cap_conn *conn,
struct smp_cmd_pairing *cmd, __u8 authreq)
{
cmd->io_capability = conn->hcon->io_capability;
cmd->oob_flag = SMP_OOB_NOT_PRESENT;
cmd->max_key_size = SMP_MAX_ENC_KEY_SIZE;
cmd->init_key_dist = 0x00;
cmd->resp_key_dist = 0x00;
cmd->auth_req = authreq;
}
static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
{
if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
(max_key_size < SMP_MIN_ENC_KEY_SIZE))
return SMP_ENC_KEY_SIZE;
conn->smp_key_size = max_key_size;
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;
u8 key_size;
BT_DBG("conn %p", conn);
conn->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&conn->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 no requirements */
build_pairing_cmd(conn, &rsp, SMP_AUTH_NONE);
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(conn->tk, 0, sizeof(conn->tk));
conn->prsp[0] = SMP_CMD_PAIRING_RSP;
memcpy(&conn->prsp[1], &rsp, sizeof(rsp));
smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
mod_timer(&conn->security_timer, jiffies +
msecs_to_jiffies(SMP_TIMEOUT));
return 0;
}
static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
struct smp_cmd_pairing_confirm cp;
struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
int ret;
u8 res[16], key_size;
BT_DBG("conn %p", conn);
skb_pull(skb, sizeof(*rsp));
req = (void *) &conn->preq[1];
key_size = min(req->max_key_size, rsp->max_key_size);
if (check_enc_key_size(conn, key_size))
return SMP_ENC_KEY_SIZE;
if (rsp->oob_flag)
return SMP_OOB_NOT_AVAIL;
/* Just works */
memset(conn->tk, 0, sizeof(conn->tk));
conn->prsp[0] = SMP_CMD_PAIRING_RSP;
memcpy(&conn->prsp[1], rsp, sizeof(*rsp));
ret = smp_rand(conn->prnd);
if (ret)
return SMP_UNSPECIFIED;
ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0,
conn->src, conn->hcon->dst_type, conn->dst, res);
if (ret)
return SMP_UNSPECIFIED;
swap128(res, cp.confirm_val);
smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
return 0;
}
static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
memcpy(conn->pcnf, skb->data, sizeof(conn->pcnf));
skb_pull(skb, sizeof(conn->pcnf));
if (conn->hcon->out) {
u8 random[16];
swap128(conn->prnd, random);
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random),
random);
} else {
struct smp_cmd_pairing_confirm cp;
int ret;
u8 res[16];
ret = smp_rand(conn->prnd);
if (ret)
return SMP_UNSPECIFIED;
ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp,
conn->hcon->dst_type, conn->dst,
0, conn->src, res);
if (ret)
return SMP_CONFIRM_FAILED;
swap128(res, cp.confirm_val);
smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
}
mod_timer(&conn->security_timer, jiffies +
msecs_to_jiffies(SMP_TIMEOUT));
return 0;
}
static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct hci_conn *hcon = conn->hcon;
struct crypto_blkcipher *tfm = hcon->hdev->tfm;
int ret;
u8 key[16], res[16], random[16], confirm[16];
swap128(skb->data, random);
skb_pull(skb, sizeof(random));
memset(hcon->ltk, 0, sizeof(hcon->ltk));
if (conn->hcon->out)
ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0,
conn->src, conn->hcon->dst_type, conn->dst,
res);
else
ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp,
conn->hcon->dst_type, conn->dst, 0, conn->src,
res);
if (ret)
return SMP_UNSPECIFIED;
BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
swap128(res, confirm);
if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) {
BT_ERR("Pairing failed (confirmation values mismatch)");
return SMP_CONFIRM_FAILED;
}
if (conn->hcon->out) {
__le16 ediv;
u8 rand[8];
smp_s1(tfm, conn->tk, random, conn->prnd, key);
swap128(key, hcon->ltk);
memset(hcon->ltk + conn->smp_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
memset(rand, 0, sizeof(rand));
ediv = 0;
hci_le_start_enc(hcon, ediv, rand, hcon->ltk);
} else {
u8 r[16];
swap128(conn->prnd, r);
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
smp_s1(tfm, conn->tk, conn->prnd, random, key);
swap128(key, hcon->ltk);
memset(hcon->ltk + conn->smp_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
}
return 0;
}
static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_security_req *rp = (void *) skb->data;
struct smp_cmd_pairing cp;
struct hci_conn *hcon = conn->hcon;
BT_DBG("conn %p", conn);
if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
return 0;
skb_pull(skb, sizeof(*rp));
memset(&cp, 0, sizeof(cp));
build_pairing_cmd(conn, &cp, rp->auth_req);
conn->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&conn->preq[1], &cp, sizeof(cp));
smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
mod_timer(&conn->security_timer, jiffies +
msecs_to_jiffies(SMP_TIMEOUT));
set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
return 0;
}
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
{
struct hci_conn *hcon = conn->hcon;
__u8 authreq;
BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
if (IS_ERR(hcon->hdev->tfm))
return 1;
if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
return 0;
if (sec_level == BT_SECURITY_LOW)
return 1;
if (hcon->sec_level >= sec_level)
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, authreq);
conn->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&conn->preq[1], &cp, sizeof(cp));
mod_timer(&conn->security_timer, jiffies +
msecs_to_jiffies(SMP_TIMEOUT));
smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
} else {
struct smp_cmd_security_req cp;
cp.auth_req = authreq;
smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
}
hcon->pending_sec_level = sec_level;
set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
return 0;
}
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
{
__u8 code = skb->data[0];
__u8 reason;
int err = 0;
if (IS_ERR(conn->hcon->hdev->tfm)) {
err = PTR_ERR(conn->hcon->hdev->tfm);
reason = SMP_PAIRING_NOTSUPP;
goto done;
}
skb_pull(skb, sizeof(code));
switch (code) {
case SMP_CMD_PAIRING_REQ:
reason = smp_cmd_pairing_req(conn, skb);
break;
case SMP_CMD_PAIRING_FAIL:
reason = 0;
err = -EPERM;
break;
case SMP_CMD_PAIRING_RSP:
reason = smp_cmd_pairing_rsp(conn, skb);
break;
case SMP_CMD_SECURITY_REQ:
reason = smp_cmd_security_req(conn, skb);
break;
case SMP_CMD_PAIRING_CONFIRM:
reason = smp_cmd_pairing_confirm(conn, skb);
break;
case SMP_CMD_PAIRING_RANDOM:
reason = smp_cmd_pairing_random(conn, skb);
break;
case SMP_CMD_ENCRYPT_INFO:
case SMP_CMD_MASTER_IDENT:
case SMP_CMD_IDENT_INFO:
case SMP_CMD_IDENT_ADDR_INFO:
case SMP_CMD_SIGN_INFO:
default:
BT_DBG("Unknown command code 0x%2.2x", code);
reason = SMP_CMD_NOTSUPP;
err = -EOPNOTSUPP;
goto done;
}
done:
if (reason)
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
&reason);
kfree_skb(skb);
return err;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册