summaryrefslogtreecommitdiff
path: root/net/bluetooth
diff options
context:
space:
mode:
authorBenn Pörscke <benn.porscke@stericsson.com>2011-10-07 15:31:57 +0200
committerBenn Pörscke <benn.porscke@stericsson.com>2011-10-07 15:31:57 +0200
commit47a4dbf83a75014d6b3467be18997894f1c617db (patch)
tree7f5d116db48205309fbc4ae0954f20ab8a651e46 /net/bluetooth
parentea8a52f9f4bcc3420c38ae07f8378a2f18443970 (diff)
Change-Id: If0ae9fa8067740ab2ede33703c79ec134f204a5e
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/af_bluetooth.c38
-rw-r--r--net/bluetooth/bnep/bnep.h2
-rw-r--r--net/bluetooth/bnep/core.c53
-rw-r--r--net/bluetooth/hci_conn.c182
-rw-r--r--net/bluetooth/hci_core.c36
-rw-r--r--net/bluetooth/hci_event.c50
-rw-r--r--net/bluetooth/hci_sock.c3
-rw-r--r--net/bluetooth/l2cap.c239
-rw-r--r--net/bluetooth/rfcomm/core.c56
-rw-r--r--net/bluetooth/rfcomm/sock.c8
-rw-r--r--net/bluetooth/sco.c55
11 files changed, 536 insertions, 186 deletions
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 421c45bd1b9..9c60673842c 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -40,6 +40,15 @@
#include <net/bluetooth/bluetooth.h>
+#ifdef CONFIG_ANDROID_PARANOID_NETWORK
+#include <linux/android_aid.h>
+#endif
+
+#ifndef CONFIG_BT_SOCK_DEBUG
+#undef BT_DBG
+#define BT_DBG(D...)
+#endif
+
#define VERSION "2.15"
/* Bluetooth sockets */
@@ -125,11 +134,40 @@ int bt_sock_unregister(int proto)
}
EXPORT_SYMBOL(bt_sock_unregister);
+#ifdef CONFIG_ANDROID_PARANOID_NETWORK
+static inline int current_has_bt_admin(void)
+{
+ return (!current_euid() || in_egroup_p(AID_NET_BT_ADMIN));
+}
+
+static inline int current_has_bt(void)
+{
+ return (current_has_bt_admin() || in_egroup_p(AID_NET_BT));
+}
+# else
+static inline int current_has_bt_admin(void)
+{
+ return 1;
+}
+
+static inline int current_has_bt(void)
+{
+ return 1;
+}
+#endif
+
static int bt_sock_create(struct net *net, struct socket *sock, int proto,
int kern)
{
int err;
+ if (proto == BTPROTO_RFCOMM || proto == BTPROTO_SCO ||
+ proto == BTPROTO_L2CAP) {
+ if (!current_has_bt())
+ return -EPERM;
+ } else if (!current_has_bt_admin())
+ return -EPERM;
+
if (net != &init_net)
return -EAFNOSUPPORT;
diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h
index 0d9e506f5d5..7dca83b22a7 100644
--- a/net/bluetooth/bnep/bnep.h
+++ b/net/bluetooth/bnep/bnep.h
@@ -165,6 +165,8 @@ struct bnep_session {
struct socket *sock;
struct net_device *dev;
+
+ unsigned int setup_done;
};
void bnep_net_setup(struct net_device *dev);
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index f10b41fb05a..2c1a0ee0141 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -123,7 +123,8 @@ static inline void bnep_set_default_proto_filter(struct bnep_session *s)
}
#endif
-static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len)
+static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data,
+ int len, int *pkt_size)
{
int n;
@@ -138,6 +139,8 @@ static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len
BT_DBG("filter len %d", n);
+ *pkt_size = 2 + n;
+
#ifdef CONFIG_BT_BNEP_PROTO_FILTER
n /= 4;
if (n <= BNEP_MAX_PROTO_FILTERS) {
@@ -168,7 +171,8 @@ static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len
return 0;
}
-static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
+static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len,
+ int *pkt_size)
{
int n;
@@ -183,6 +187,8 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
BT_DBG("filter len %d", n);
+ *pkt_size = 2 + n;
+
#ifdef CONFIG_BT_BNEP_MC_FILTER
n /= (ETH_ALEN * 2);
@@ -222,13 +228,16 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
return 0;
}
-static int bnep_rx_control(struct bnep_session *s, void *data, int len)
+static int bnep_rx_control(struct bnep_session *s, void *data, int len,
+ int *pkt_size)
{
u8 cmd = *(u8 *)data;
int err = 0;
data++; len--;
+ *pkt_size = 0;
+
switch (cmd) {
case BNEP_CMD_NOT_UNDERSTOOD:
case BNEP_SETUP_CONN_RSP:
@@ -238,15 +247,27 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len)
break;
case BNEP_FILTER_NET_TYPE_SET:
- err = bnep_ctrl_set_netfilter(s, data, len);
+ err = bnep_ctrl_set_netfilter(s, data, len, pkt_size);
break;
case BNEP_FILTER_MULTI_ADDR_SET:
- err = bnep_ctrl_set_mcfilter(s, data, len);
+ err = bnep_ctrl_set_mcfilter(s, data, len, pkt_size);
break;
- case BNEP_SETUP_CONN_REQ:
- err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP, BNEP_CONN_NOT_ALLOWED);
+ case BNEP_SETUP_CONN_REQ: {
+ u8 uuid_size = *(u8 *)data;
+
+ /* First setup connection should be silently discarded,
+ * it was already handled when accepting connection.
+ */
+ if (s->setup_done)
+ err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP,
+ BNEP_CONN_NOT_ALLOWED);
+ else
+ s->setup_done = 1;
+
+ *pkt_size = 1 + 2 * uuid_size;
+ }
break;
default: {
@@ -259,6 +280,10 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len)
break;
}
+ if (*pkt_size > 0)
+ /* Add 1 byte for type field */
+ (*pkt_size)++;
+
return err;
}
@@ -266,6 +291,7 @@ static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
{
struct bnep_ext_hdr *h;
int err = 0;
+ int pkt_size;
do {
h = (void *) skb->data;
@@ -278,7 +304,7 @@ static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
switch (h->type & BNEP_TYPE_MASK) {
case BNEP_EXT_CONTROL:
- bnep_rx_control(s, skb->data, skb->len);
+ bnep_rx_control(s, skb->data, skb->len, &pkt_size);
break;
default:
@@ -318,7 +344,16 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
goto badframe;
if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
- bnep_rx_control(s, skb->data, skb->len);
+ int pkt_size = 0;
+
+ bnep_rx_control(s, skb->data, skb->len, &pkt_size);
+
+ if (pkt_size > 0 && (type & BNEP_EXT_HEADER)) {
+ skb_pull(skb, pkt_size);
+ if (bnep_rx_extension(s, skb) < 0)
+ goto badframe;
+ }
+
kfree_skb(skb);
return 0;
}
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 800b6b9fbba..c009fa4c4a2 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
+ Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -155,6 +155,27 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
}
+/* Device _must_ be locked */
+void hci_sco_setup(struct hci_conn *conn, __u8 status)
+{
+ struct hci_conn *sco = conn->link;
+
+ BT_DBG("%p", conn);
+
+ if (!sco)
+ return;
+
+ if (!status) {
+ if (lmp_esco_capable(conn->hdev))
+ hci_setup_sync(sco, conn->handle);
+ else
+ hci_add_sco(sco, conn->handle);
+ } else {
+ hci_proto_connect_cfm(sco, status);
+ hci_conn_del(sco);
+ }
+}
+
static void hci_conn_timeout(unsigned long arg)
{
struct hci_conn *conn = (void *) arg;
@@ -196,7 +217,8 @@ static void hci_conn_idle(unsigned long arg)
hci_conn_enter_sniff_mode(conn);
}
-struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
+struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type,
+ __u16 pkt_type, bdaddr_t *dst)
{
struct hci_conn *conn;
@@ -212,6 +234,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
conn->mode = HCI_CM_ACTIVE;
conn->state = BT_OPEN;
conn->auth_type = HCI_AT_GENERAL_BONDING;
+ conn->key_type = 0xff;
+ conn->pin_len = 0;
conn->power_save = 1;
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
@@ -221,14 +245,22 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
break;
case SCO_LINK:
- if (lmp_esco_capable(hdev))
- conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
- (hdev->esco_type & EDR_ESCO_MASK);
- else
- conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK;
- break;
+ if (!pkt_type)
+ pkt_type = SCO_ESCO_MASK;
case ESCO_LINK:
- conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK;
+ if (!pkt_type)
+ pkt_type = ALL_ESCO_MASK;
+ if (lmp_esco_capable(hdev)) {
+ /* HCI Setup Synchronous Connection Command uses
+ reverse logic on the EDR_ESCO_MASK bits */
+ conn->pkt_type = (pkt_type ^ EDR_ESCO_MASK) &
+ hdev->esco_type;
+ } else {
+ /* Legacy HCI Add Sco Connection Command uses a
+ shifted bitmask */
+ conn->pkt_type = (pkt_type << 5) & hdev->pkt_type &
+ SCO_PTYPE_MASK;
+ }
break;
}
@@ -340,7 +372,9 @@ EXPORT_SYMBOL(hci_get_route);
/* Create SCO or ACL connection.
* Device _must_ be locked */
-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type)
+struct hci_conn *hci_connect(struct hci_dev *hdev, int type,
+ __u16 pkt_type, bdaddr_t *dst,
+ __u8 sec_level, __u8 auth_type)
{
struct hci_conn *acl;
struct hci_conn *sco;
@@ -348,7 +382,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
BT_DBG("%s dst %s", hdev->name, batostr(dst));
if (!(acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst))) {
- if (!(acl = hci_conn_add(hdev, ACL_LINK, dst)))
+ if (!(acl = hci_conn_add(hdev, ACL_LINK, 0, dst)))
return NULL;
}
@@ -369,7 +403,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
return acl;
if (!(sco = hci_conn_hash_lookup_ba(hdev, type, dst))) {
- if (!(sco = hci_conn_add(hdev, type, dst))) {
+ if (!(sco = hci_conn_add(hdev, type, pkt_type, dst))) {
hci_conn_put(acl);
return NULL;
}
@@ -385,10 +419,13 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
acl->power_save = 1;
hci_conn_enter_active_mode(acl);
- if (lmp_esco_capable(hdev))
- hci_setup_sync(sco, acl->handle);
- else
- hci_add_sco(sco, acl->handle);
+ if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) {
+ /* defer SCO setup until mode change completed */
+ set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->pend);
+ return sco;
+ }
+
+ hci_sco_setup(acl, 0x00);
}
return sco;
@@ -409,15 +446,11 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
EXPORT_SYMBOL(hci_conn_check_link_mode);
/* Authenticate remote device */
-static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
+static void hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
{
BT_DBG("conn %p", conn);
- if (sec_level > conn->sec_level)
- conn->sec_level = sec_level;
- else if (conn->link_mode & HCI_LM_AUTH)
- return 1;
-
+ conn->sec_level = sec_level;
conn->auth_type = auth_type;
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
@@ -426,8 +459,20 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
sizeof(cp), &cp);
}
+}
- return 0;
+/* Encrypt the the link */
+static void hci_conn_encrypt(struct hci_conn *conn)
+{
+ BT_DBG("conn %p", conn);
+
+ if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
+ struct hci_cp_set_conn_encrypt cp;
+ cp.handle = cpu_to_le16(conn->handle);
+ cp.encrypt = 1;
+ hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT,
+ sizeof(cp), &cp);
+ }
}
/* Enable security */
@@ -435,28 +480,51 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
{
BT_DBG("conn %p", conn);
+ /* For sdp we do not need the link key. */
if (sec_level == BT_SECURITY_SDP)
return 1;
+ /* For non 2.1 devices and low security level we do not need the
+ link key. */
if (sec_level == BT_SECURITY_LOW &&
(!conn->ssp_mode || !conn->hdev->ssp_mode))
return 1;
- if (conn->link_mode & HCI_LM_ENCRYPT)
- return hci_conn_auth(conn, sec_level, auth_type);
+ /* For other security levels we need link key. */
+ if (!(conn->link_mode & HCI_LM_AUTH))
+ goto do_auth;
+
+ /* An authenticated combination key has sufficient security for any
+ security level. */
+ if (conn->key_type == HCI_LK_AUTHENTICATED_COMBINATION)
+ goto do_encrypt;
+
+ /* An unauthenticated combination key has sufficient security for
+ any security level other than max (for SAP) */
+ if (conn->key_type == HCI_LK_UNAUTHENTICATED_COMBINATION
+ && sec_level < BT_SECURITY_HIGH)
+ goto do_encrypt;
+
+ /* For max security, combination key should be generated using
+ 16 digits pincode. For pre-2.1 devices. */
+ if (conn->key_type == HCI_LK_COMBINATION)
+ if (sec_level != BT_SECURITY_MAX || conn->pin_len >= 16)
+ goto do_encrypt;
+do_auth:
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
return 0;
- if (hci_conn_auth(conn, sec_level, auth_type)) {
- struct hci_cp_set_conn_encrypt cp;
- cp.handle = cpu_to_le16(conn->handle);
- cp.encrypt = 1;
- hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT,
- sizeof(cp), &cp);
- }
-
+ hci_conn_auth(conn, sec_level, auth_type);
return 0;
+
+do_encrypt:
+ if (conn->link_mode & HCI_LM_ENCRYPT)
+ return 1; /* sufficient link key */
+ else{
+ hci_conn_encrypt(conn);
+ return 0; /* auth pending */
+ }
}
EXPORT_SYMBOL(hci_conn_security);
@@ -505,7 +573,7 @@ void hci_conn_enter_active_mode(struct hci_conn *conn)
if (test_bit(HCI_RAW, &hdev->flags))
return;
- if (conn->mode != HCI_CM_SNIFF || !conn->power_save)
+ if (conn->mode != HCI_CM_SNIFF /* || !conn->power_save */)
goto timer;
if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
@@ -644,6 +712,15 @@ int hci_get_conn_list(void __user *arg)
(ci + n)->out = c->out;
(ci + n)->state = c->state;
(ci + n)->link_mode = c->link_mode;
+ if (c->type == SCO_LINK) {
+ (ci + n)->mtu = hdev->sco_mtu;
+ (ci + n)->cnt = hdev->sco_cnt;
+ (ci + n)->pkts = hdev->sco_pkts;
+ } else {
+ (ci + n)->mtu = hdev->acl_mtu;
+ (ci + n)->cnt = hdev->acl_cnt;
+ (ci + n)->pkts = hdev->acl_pkts;
+ }
if (++n >= req.conn_num)
break;
}
@@ -680,6 +757,15 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
ci.out = conn->out;
ci.state = conn->state;
ci.link_mode = conn->link_mode;
+ if (req.type == SCO_LINK) {
+ ci.mtu = hdev->sco_mtu;
+ ci.cnt = hdev->sco_cnt;
+ ci.pkts = hdev->sco_pkts;
+ } else {
+ ci.mtu = hdev->acl_mtu;
+ ci.cnt = hdev->acl_cnt;
+ ci.pkts = hdev->acl_pkts;
+ }
}
hci_dev_unlock_bh(hdev);
@@ -689,6 +775,30 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
}
+int hci_set_conn_info(struct hci_dev *hdev, void __user *arg)
+{
+ struct hci_set_conn_info_req req;
+ struct hci_conn *conn;
+
+ if (copy_from_user(&req, arg, sizeof(req))) {
+ BT_DBG("copy from user failed");
+ return -EFAULT;
+ }
+
+ hci_dev_lock_bh(hdev);
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr);
+ if (conn) {
+ conn->pin_len = req.pin_len;
+ conn->key_type = req.key_type;
+ }
+ hci_dev_unlock_bh(hdev);
+
+ if (!conn)
+ return -ENOENT;
+
+ return 0;
+}
+
int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
{
struct hci_auth_info_req req;
@@ -699,8 +809,10 @@ int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
hci_dev_lock_bh(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr);
- if (conn)
+ if (conn) {
req.type = conn->auth_type;
+ req.level = conn->sec_level;
+ }
hci_dev_unlock_bh(hdev);
if (!conn)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 2f768de8701..62717e1b451 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -503,6 +503,7 @@ int hci_dev_open(__u16 dev)
if (!test_bit(HCI_RAW, &hdev->flags)) {
atomic_set(&hdev->cmd_cnt, 1);
+ atomic_set(&hdev->cmd_not_ack, 0);
set_bit(HCI_INIT, &hdev->flags);
//__hci_request(hdev, hci_reset_req, 0, HZ);
@@ -572,6 +573,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
/* Reset device */
skb_queue_purge(&hdev->cmd_q);
atomic_set(&hdev->cmd_cnt, 1);
+ atomic_set(&hdev->cmd_not_ack, 0);
if (!test_bit(HCI_RAW, &hdev->flags)) {
set_bit(HCI_INIT, &hdev->flags);
__hci_request(hdev, hci_reset_req, 0,
@@ -645,6 +647,7 @@ int hci_dev_reset(__u16 dev)
hdev->flush(hdev);
atomic_set(&hdev->cmd_cnt, 1);
+ atomic_set(&hdev->cmd_not_ack, 0);
hdev->acl_cnt = 0; hdev->sco_cnt = 0;
if (!test_bit(HCI_RAW, &hdev->flags))
@@ -1283,7 +1286,7 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
skb->dev = (void *) hdev;
bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
- hci_add_acl_hdr(skb, conn->handle, flags | ACL_START);
+ hci_add_acl_hdr(skb, conn->handle, flags);
if (!(list = skb_shinfo(skb)->frag_list)) {
/* Non fragmented */
@@ -1300,12 +1303,14 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
spin_lock_bh(&conn->data_q.lock);
__skb_queue_tail(&conn->data_q, skb);
+ flags &= ~ACL_PB_MASK;
+ flags |= ACL_CONT;
do {
skb = list; list = list->next;
skb->dev = (void *) hdev;
bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
- hci_add_acl_hdr(skb, conn->handle, flags | ACL_CONT);
+ hci_add_acl_hdr(skb, conn->handle, flags);
BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
@@ -1633,24 +1638,31 @@ static void hci_cmd_task(unsigned long arg)
struct hci_dev *hdev = (struct hci_dev *) arg;
struct sk_buff *skb;
- BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
+ BT_DBG("%s cnt %d not_ack %d", hdev->name, atomic_read(&hdev->cmd_cnt),
+ atomic_read(&hdev->cmd_not_ack));
if (!atomic_read(&hdev->cmd_cnt) && time_after(jiffies, hdev->cmd_last_tx + HZ)) {
BT_ERR("%s command tx timeout", hdev->name);
atomic_set(&hdev->cmd_cnt, 1);
+ atomic_add_unless(&hdev->cmd_not_ack, -1, 0);
}
/* Send queued commands */
- if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) {
- kfree_skb(hdev->sent_cmd);
+ if (atomic_read(&hdev->cmd_cnt) > atomic_read(&hdev->cmd_not_ack)) {
+ skb = skb_dequeue(&hdev->cmd_q);
+ if (skb) {
+ kfree_skb(hdev->sent_cmd);
- if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) {
- atomic_dec(&hdev->cmd_cnt);
- hci_send_frame(skb);
- hdev->cmd_last_tx = jiffies;
- } else {
- skb_queue_head(&hdev->cmd_q, skb);
- tasklet_schedule(&hdev->cmd_task);
+ hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
+ if (hdev->sent_cmd) {
+ atomic_dec(&hdev->cmd_cnt);
+ atomic_inc(&hdev->cmd_not_ack);
+ hci_send_frame(skb);
+ hdev->cmd_last_tx = jiffies;
+ } else {
+ skb_queue_head(&hdev->cmd_q, skb);
+ tasklet_schedule(&hdev->cmd_task);
+ }
}
}
}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 786b5de0bac..c56cb5a73a3 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
+ Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -579,7 +579,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
}
} else {
if (!conn) {
- conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr);
+ conn = hci_conn_add(hdev, ACL_LINK, 0, &cp->bdaddr);
if (conn) {
conn->out = 1;
conn->link_mode |= HCI_LM_MASTER;
@@ -785,9 +785,13 @@ static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn)
+ if (conn) {
clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
+ if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
+ hci_sco_setup(conn, status);
+ }
+
hci_dev_unlock(hdev);
}
@@ -808,9 +812,13 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn)
+ if (conn) {
clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
+ if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
+ hci_sco_setup(conn, status);
+ }
+
hci_dev_unlock(hdev);
}
@@ -915,20 +923,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
} else
conn->state = BT_CLOSED;
- if (conn->type == ACL_LINK) {
- struct hci_conn *sco = conn->link;
- if (sco) {
- if (!ev->status) {
- if (lmp_esco_capable(hdev))
- hci_setup_sync(sco, conn->handle);
- else
- hci_add_sco(sco, conn->handle);
- } else {
- hci_proto_connect_cfm(sco, ev->status);
- hci_conn_del(sco);
- }
- }
- }
+ if (conn->type == ACL_LINK)
+ hci_sco_setup(conn, ev->status);
if (ev->status) {
hci_proto_connect_cfm(conn, ev->status);
@@ -964,7 +960,9 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
if (!conn) {
- if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) {
+ /* pkt_type not yet used for incoming connections */
+ if (!(conn = hci_conn_add(hdev, ev->link_type, 0,
+ &ev->bdaddr))) {
BT_ERR("No memmory for new connection");
hci_dev_unlock(hdev);
return;
@@ -1319,6 +1317,9 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
break;
}
+ if (opcode != 0x0000)
+ atomic_add_unless(&hdev->cmd_not_ack, -1, 0);
+
if (ev->ncmd) {
atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q))
@@ -1385,6 +1386,9 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
break;
}
+ if (opcode != 0x0000)
+ atomic_add_unless(&hdev->cmd_not_ack, -1, 0);
+
if (ev->ncmd) {
atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q))
@@ -1481,6 +1485,9 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
else
conn->power_save = 0;
}
+
+ if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
+ hci_sco_setup(conn, ev->status);
}
hci_dev_unlock(hdev);
@@ -1522,6 +1529,10 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (conn) {
hci_conn_hold(conn);
+ /* For Changed Combination Link Key the only link key has
+ * been changed, not link key type. */
+ if (conn->key_type != HCI_LK_CHANGEED_COMBINATION_KEY)
+ conn->key_type = ev->key_type;
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
hci_conn_put(conn);
}
@@ -1700,6 +1711,7 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu
hci_conn_add_sysfs(conn);
break;
+ case 0x10: /* Connection Accept Timeout */
case 0x11: /* Unsupported Feature or Parameter Value */
case 0x1c: /* SCO interval rejected */
case 0x1a: /* Unsupported Remote Feature */
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 38f08f6b86f..063eaafeb3d 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -191,6 +191,9 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
case HCIGETCONNINFO:
return hci_get_conn_info(hdev, (void __user *) arg);
+ case HCISETCONNINFO:
+ return hci_set_conn_info(hdev, (void __user *) arg);
+
case HCIGETAUTHINFO:
return hci_get_auth_info(hdev, (void __user *) arg);
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index cf3c4073a8a..ef9e61b4d71 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -53,7 +53,7 @@
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
-#define VERSION "2.14"
+#define VERSION "2.15"
#ifdef CONFIG_BT_L2CAP_EXT_FEATURES
static int enable_ertm = 1;
@@ -62,6 +62,7 @@ static int enable_ertm = 0;
#endif
static int max_transmit = L2CAP_DEFAULT_MAX_TX;
static int tx_window = L2CAP_DEFAULT_TX_WINDOW;
+static int disable_info_req = 0;
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
static u8 l2cap_fixed_chan[8] = { 0x02, };
@@ -80,6 +81,7 @@ static void __l2cap_sock_close(struct sock *sk, int reason);
static void l2cap_sock_close(struct sock *sk);
static void l2cap_sock_kill(struct sock *sk);
+static int l2cap_build_conf_req(struct sock *sk, void *data);
static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
u8 code, u8 ident, u16 dlen, void *data);
@@ -287,7 +289,8 @@ static inline int l2cap_check_security(struct sock *sk)
__u8 auth_type;
if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
- if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+ if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH
+ || l2cap_pi(sk)->sec_level == BT_SECURITY_MAX)
auth_type = HCI_AT_NO_BONDING_MITM;
else
auth_type = HCI_AT_NO_BONDING;
@@ -297,6 +300,7 @@ static inline int l2cap_check_security(struct sock *sk)
} else {
switch (l2cap_pi(sk)->sec_level) {
case BT_SECURITY_HIGH:
+ case BT_SECURITY_MAX:
auth_type = HCI_AT_GENERAL_BONDING_MITM;
break;
case BT_SECURITY_MEDIUM:
@@ -337,13 +341,19 @@ static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
static inline void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
{
struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
+ u8 flags;
BT_DBG("code 0x%2.2x", code);
if (!skb)
return;
- hci_send_acl(conn->hcon, skb, 0);
+ if (lmp_no_flush_capable(conn->hcon->hdev))
+ flags = ACL_START_NO_FLUSH;
+ else
+ flags = ACL_START;
+
+ hci_send_acl(conn->hcon, skb, flags);
}
static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
@@ -410,8 +420,8 @@ static void l2cap_do_start(struct sock *sk)
{
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
- if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
+ if (disable_info_req || conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
+ if (!disable_info_req && !(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
return;
if (l2cap_check_security(sk) && __l2cap_no_conn_pending(sk)) {
@@ -440,6 +450,22 @@ static void l2cap_do_start(struct sock *sk)
}
}
+static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
+{
+ u32 local_feat_mask = l2cap_feat_mask;
+ if (enable_ertm)
+ local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
+
+ switch (mode) {
+ case L2CAP_MODE_ERTM:
+ return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
+ case L2CAP_MODE_STREAMING:
+ return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
+ default:
+ return 0x00;
+ }
+}
+
static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk)
{
struct l2cap_disconn_req req;
@@ -454,10 +480,13 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk)
static void l2cap_conn_start(struct l2cap_conn *conn)
{
struct l2cap_chan_list *l = &conn->chan_list;
+ struct sock_del_list del, *tmp1, *tmp2;
struct sock *sk;
BT_DBG("conn %p", conn);
+ INIT_LIST_HEAD(&del.list);
+
read_lock(&l->lock);
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
@@ -473,6 +502,19 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
if (l2cap_check_security(sk) &&
__l2cap_no_conn_pending(sk)) {
struct l2cap_conn_req req;
+
+ if (!l2cap_mode_supported(l2cap_pi(sk)->mode,
+ conn->feat_mask)
+ && l2cap_pi(sk)->conf_state &
+ L2CAP_CONF_STATE2_DEVICE) {
+ tmp1 = kzalloc(sizeof(struct srej_list),
+ GFP_ATOMIC);
+ tmp1->sk = sk;
+ list_add_tail(&tmp1->list, &del.list);
+ bh_unlock_sock(sk);
+ continue;
+ }
+
req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
req.psm = l2cap_pi(sk)->psm;
@@ -484,6 +526,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
}
} else if (sk->sk_state == BT_CONNECT2) {
struct l2cap_conn_rsp rsp;
+ char buf[128];
rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
@@ -492,7 +535,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
struct sock *parent = bt_sk(sk)->parent;
rsp.result = cpu_to_le16(L2CAP_CR_PEND);
rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
- parent->sk_data_ready(parent, 0);
+ if (parent)
+ parent->sk_data_ready(parent, 0);
} else {
sk->sk_state = BT_CONFIG;
@@ -506,12 +550,31 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+
+ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT ||
+ rsp.result != L2CAP_CR_SUCCESS) {
+ bh_unlock_sock(sk);
+ continue;
+ }
+
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+ l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
+ l2cap_build_conf_req(sk, buf), buf);
+ l2cap_pi(sk)->num_conf_req++;
}
bh_unlock_sock(sk);
}
read_unlock(&l->lock);
+
+ list_for_each_entry_safe(tmp1, tmp2, &del.list, list) {
+ bh_lock_sock(tmp1->sk);
+ __l2cap_sock_close(tmp1->sk, ECONNRESET);
+ bh_unlock_sock(tmp1->sk);
+ list_del(&tmp1->list);
+ kfree(tmp1);
+ }
}
static void l2cap_conn_ready(struct l2cap_conn *conn)
@@ -560,12 +623,20 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
static void l2cap_info_timeout(unsigned long arg)
{
- struct l2cap_conn *conn = (void *) arg;
+ struct hci_conn *hcon = (void *) arg;
+ struct l2cap_conn *conn;
+
+ spin_lock_bh(&hcon->lock);
+ if (!hcon->l2cap_data)
+ goto unlock;
+ conn = hcon->l2cap_data;
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
conn->info_ident = 0;
l2cap_conn_start(conn);
+unlock:
+ spin_unlock_bh(&hcon->lock);
}
static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
@@ -594,7 +665,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
rwlock_init(&conn->chan_list.lock);
setup_timer(&conn->info_timer, l2cap_info_timeout,
- (unsigned long) conn);
+ (unsigned long) hcon);
conn->disc_reason = 0x13;
@@ -611,6 +682,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
+ spin_lock_bh(&hcon->lock);
kfree_skb(conn->rx_skb);
/* Kill channels */
@@ -622,10 +694,11 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
}
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
- del_timer_sync(&conn->info_timer);
+ del_timer(&conn->info_timer);
hcon->l2cap_data = NULL;
kfree(conn);
+ spin_unlock_bh(&hcon->lock);
}
static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
@@ -802,6 +875,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
pi->imtu = l2cap_pi(parent)->imtu;
pi->omtu = l2cap_pi(parent)->omtu;
+ pi->conf_state = l2cap_pi(parent)->conf_state;
pi->mode = l2cap_pi(parent)->mode;
pi->fcs = l2cap_pi(parent)->fcs;
pi->max_tx = l2cap_pi(parent)->max_tx;
@@ -809,19 +883,24 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
pi->sec_level = l2cap_pi(parent)->sec_level;
pi->role_switch = l2cap_pi(parent)->role_switch;
pi->force_reliable = l2cap_pi(parent)->force_reliable;
+ pi->flushable = l2cap_pi(parent)->flushable;
} else {
pi->imtu = L2CAP_DEFAULT_MTU;
pi->omtu = 0;
- if (enable_ertm && sk->sk_type == SOCK_STREAM)
+ if (enable_ertm && sk->sk_type == SOCK_STREAM) {
pi->mode = L2CAP_MODE_ERTM;
- else
+ pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
+ } else {
pi->mode = L2CAP_MODE_BASIC;
+ }
+
pi->max_tx = max_transmit;
pi->fcs = L2CAP_FCS_CRC16;
pi->tx_win = tx_window;
pi->sec_level = BT_SECURITY_LOW;
pi->role_switch = 0;
pi->force_reliable = 0;
+ pi->flushable = 0;
}
/* Default config options */
@@ -968,6 +1047,7 @@ static int l2cap_do_connect(struct sock *sk)
if (sk->sk_type == SOCK_RAW) {
switch (l2cap_pi(sk)->sec_level) {
case BT_SECURITY_HIGH:
+ case BT_SECURITY_MAX:
auth_type = HCI_AT_DEDICATED_BONDING_MITM;
break;
case BT_SECURITY_MEDIUM:
@@ -978,7 +1058,8 @@ static int l2cap_do_connect(struct sock *sk)
break;
}
} else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
- if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+ if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH
+ || l2cap_pi(sk)->sec_level == BT_SECURITY_MAX)
auth_type = HCI_AT_NO_BONDING_MITM;
else
auth_type = HCI_AT_NO_BONDING;
@@ -988,6 +1069,7 @@ static int l2cap_do_connect(struct sock *sk)
} else {
switch (l2cap_pi(sk)->sec_level) {
case BT_SECURITY_HIGH:
+ case BT_SECURITY_MAX:
auth_type = HCI_AT_GENERAL_BONDING_MITM;
break;
case BT_SECURITY_MEDIUM:
@@ -999,7 +1081,7 @@ static int l2cap_do_connect(struct sock *sk)
}
}
- hcon = hci_connect(hdev, ACL_LINK, dst,
+ hcon = hci_connect(hdev, ACL_LINK, 0, dst,
l2cap_pi(sk)->sec_level, auth_type);
if (!hcon)
goto done;
@@ -1285,6 +1367,8 @@ static void l2cap_monitor_timeout(unsigned long arg)
{
struct sock *sk = (void *) arg;
+ BT_DBG("sk %p", sk);
+
bh_lock_sock(sk);
if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) {
l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk);
@@ -1303,6 +1387,8 @@ static void l2cap_retrans_timeout(unsigned long arg)
{
struct sock *sk = (void *) arg;
+ BT_DBG("sk %p", sk);
+
bh_lock_sock(sk);
l2cap_pi(sk)->retry_count = 1;
__mod_monitor_timer();
@@ -1335,10 +1421,17 @@ static void l2cap_drop_acked_frames(struct sock *sk)
static inline void l2cap_do_send(struct sock *sk, struct sk_buff *skb)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
+ struct hci_conn *hcon = pi->conn->hcon;
+ u16 flags;
BT_DBG("sk %p, skb %p len %d", sk, skb, skb->len);
- hci_send_acl(pi->conn->hcon, skb, 0);
+ if (lmp_no_flush_capable(hcon->hdev) && !l2cap_pi(sk)->flushable)
+ flags = ACL_START_NO_FLUSH;
+ else
+ flags = ACL_START;
+
+ hci_send_acl(hcon, skb, flags);
}
static int l2cap_streaming_send(struct sock *sk)
@@ -1825,6 +1918,8 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
struct l2cap_conn_rsp rsp;
+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+ u8 buf[128];
sk->sk_state = BT_CONFIG;
@@ -1835,6 +1930,16 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) {
+ release_sock(sk);
+ return 0;
+ }
+
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+ l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
+ l2cap_build_conf_req(sk, buf), buf);
+ l2cap_pi(sk)->num_conf_req++;
+
release_sock(sk);
return 0;
}
@@ -1874,6 +1979,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
l2cap_pi(sk)->mode = opts.mode;
switch (l2cap_pi(sk)->mode) {
case L2CAP_MODE_BASIC:
+ l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE;
break;
case L2CAP_MODE_ERTM:
case L2CAP_MODE_STREAMING:
@@ -1904,9 +2010,12 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
l2cap_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
if (opt & L2CAP_LM_SECURE)
l2cap_pi(sk)->sec_level = BT_SECURITY_HIGH;
+ if (opt & L2CAP_LM_SECUREMAX)
+ l2cap_pi(sk)->sec_level = BT_SECURITY_MAX;
l2cap_pi(sk)->role_switch = (opt & L2CAP_LM_MASTER);
l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE);
+ l2cap_pi(sk)->flushable = (opt & L2CAP_LM_FLUSHABLE);
break;
default:
@@ -1952,7 +2061,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
}
if (sec.level < BT_SECURITY_LOW ||
- sec.level > BT_SECURITY_HIGH) {
+ sec.level > BT_SECURITY_MAX) {
err = -EINVAL;
break;
}
@@ -2026,6 +2135,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
L2CAP_LM_SECURE;
break;
+ case BT_SECURITY_MAX:
+ opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
+ L2CAP_LM_SECURE | L2CAP_LM_SECUREMAX;
+ break;
default:
opt = 0;
break;
@@ -2037,6 +2150,9 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
if (l2cap_pi(sk)->force_reliable)
opt |= L2CAP_LM_RELIABLE;
+ if (l2cap_pi(sk)->flushable)
+ opt |= L2CAP_LM_FLUSHABLE;
+
if (put_user(opt, (u32 __user *) optval))
err = -EFAULT;
break;
@@ -2370,22 +2486,6 @@ static inline void l2cap_ertm_init(struct sock *sk)
INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work);
}
-static int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
-{
- u32 local_feat_mask = l2cap_feat_mask;
- if (enable_ertm)
- local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
-
- switch (mode) {
- case L2CAP_MODE_ERTM:
- return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
- case L2CAP_MODE_STREAMING:
- return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
- default:
- return 0x00;
- }
-}
-
static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
{
switch (mode) {
@@ -2414,7 +2514,12 @@ static int l2cap_build_conf_req(struct sock *sk, void *data)
switch (pi->mode) {
case L2CAP_MODE_STREAMING:
case L2CAP_MODE_ERTM:
- pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
+ if (!(pi->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
+ pi->mode = l2cap_select_mode(rfc.mode,
+ pi->conn->feat_mask);
+ break;
+ }
+
if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask))
l2cap_send_disconn_req(pi->conn, sk);
break;
@@ -2541,13 +2646,18 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
}
}
- if (pi->num_conf_rsp || pi->num_conf_req)
+ if (pi->num_conf_rsp || pi->num_conf_req > 1)
goto done;
switch (pi->mode) {
case L2CAP_MODE_STREAMING:
case L2CAP_MODE_ERTM:
- pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
+ if (!(pi->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
+ pi->mode = l2cap_select_mode(rfc.mode,
+ pi->conn->feat_mask);
+ break;
+ }
+
if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask))
return -ECONNREFUSED;
break;
@@ -2778,7 +2888,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
struct l2cap_chan_list *list = &conn->chan_list;
struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
struct l2cap_conn_rsp rsp;
- struct sock *sk, *parent;
+ struct sock *parent, *sk = NULL;
int result, status = L2CAP_CS_NO_INFO;
u16 dcid = 0, scid = __le16_to_cpu(req->scid);
@@ -2838,7 +2948,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
l2cap_pi(sk)->ident = cmd->ident;
- if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
+ if (disable_info_req || conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
if (l2cap_check_security(sk)) {
if (bt_sk(sk)->defer_setup) {
sk->sk_state = BT_CONNECT2;
@@ -2873,7 +2983,8 @@ sendresp:
rsp.status = cpu_to_le16(status);
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
- if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
+ if (!disable_info_req && result == L2CAP_CR_PEND &&
+ status == L2CAP_CS_NO_INFO) {
struct l2cap_info_req info;
info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
@@ -2887,6 +2998,15 @@ sendresp:
L2CAP_INFO_REQ, sizeof(info), &info);
}
+ if (sk && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) &&
+ result == L2CAP_CR_SUCCESS) {
+ u8 buf[128];
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+ l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
+ l2cap_build_conf_req(sk, buf), buf);
+ l2cap_pi(sk)->num_conf_req++;
+ }
+
return 0;
}
@@ -2919,9 +3039,13 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
sk->sk_state = BT_CONFIG;
l2cap_pi(sk)->ident = 0;
l2cap_pi(sk)->dcid = dcid;
- l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
+ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)
+ break;
+
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(sk, req), req);
l2cap_pi(sk)->num_conf_req++;
@@ -3381,8 +3505,8 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk)
pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
}
- if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY && pi->unacked_frames > 0)
- __mod_retrans_timer();
+ if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY)
+ l2cap_retransmit_frames(sk);
pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
@@ -3607,6 +3731,8 @@ done:
pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
pi->conn_state &= ~L2CAP_CONN_RNR_SENT;
+ BT_DBG("sk %p, Exit local busy", sk);
+
set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
@@ -3631,6 +3757,8 @@ static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control)
}
/* Busy Condition */
+ BT_DBG("sk %p, Enter local busy", sk);
+
pi->conn_state |= L2CAP_CONN_LOCAL_BUSY;
bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
__skb_queue_tail(BUSY_QUEUE(sk), skb);
@@ -3806,7 +3934,8 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
int num_to_ack = (pi->tx_win/6) + 1;
int err = 0;
- BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len);
+ BT_DBG("sk %p len %d tx_seq %d rx_control 0x%4.4x", sk, skb->len, tx_seq,
+ rx_control);
if (L2CAP_CTRL_FINAL & rx_control &&
l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) {
@@ -3851,6 +3980,7 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
pi->buffer_seq = pi->buffer_seq_srej;
pi->conn_state &= ~L2CAP_CONN_SREJ_SENT;
l2cap_send_ack(pi);
+ BT_DBG("sk %p, Exit SREJ_SENT", sk);
}
} else {
struct srej_list *l;
@@ -3879,6 +4009,8 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
pi->conn_state |= L2CAP_CONN_SREJ_SENT;
+ BT_DBG("sk %p, Enter SREJ", sk);
+
INIT_LIST_HEAD(SREJ_LIST(sk));
pi->buffer_seq_srej = pi->buffer_seq;
@@ -3902,6 +4034,10 @@ expected:
return 0;
}
+ err = l2cap_push_rx_skb(sk, skb, rx_control);
+ if (err < 0)
+ return 0;
+
if (rx_control & L2CAP_CTRL_FINAL) {
if (pi->conn_state & L2CAP_CONN_REJ_ACT)
pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
@@ -3909,10 +4045,6 @@ expected:
l2cap_retransmit_frames(sk);
}
- err = l2cap_push_rx_skb(sk, skb, rx_control);
- if (err < 0)
- return 0;
-
__mod_ack_timer();
pi->num_acked = (pi->num_acked + 1) % num_to_ack;
@@ -3930,6 +4062,9 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
+ BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, __get_reqseq(rx_control),
+ rx_control);
+
pi->expected_ack_seq = __get_reqseq(rx_control);
l2cap_drop_acked_frames(sk);
@@ -3974,6 +4109,8 @@ static inline void l2cap_data_channel_rejframe(struct sock *sk, u16 rx_control)
struct l2cap_pinfo *pi = l2cap_pi(sk);
u8 tx_seq = __get_reqseq(rx_control);
+ BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
+
pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
pi->expected_ack_seq = tx_seq;
@@ -3996,6 +4133,8 @@ static inline void l2cap_data_channel_srejframe(struct sock *sk, u16 rx_control)
struct l2cap_pinfo *pi = l2cap_pi(sk);
u8 tx_seq = __get_reqseq(rx_control);
+ BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
+
pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
if (rx_control & L2CAP_CTRL_POLL) {
@@ -4031,6 +4170,8 @@ static inline void l2cap_data_channel_rnrframe(struct sock *sk, u16 rx_control)
struct l2cap_pinfo *pi = l2cap_pi(sk);
u8 tx_seq = __get_reqseq(rx_control);
+ BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
+
pi->conn_state |= L2CAP_CONN_REMOTE_BUSY;
pi->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(sk);
@@ -4366,7 +4507,8 @@ static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt)
if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) {
l2cap_sock_clear_timer(sk);
l2cap_sock_set_timer(sk, HZ * 5);
- } else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+ } else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH
+ || l2cap_pi(sk)->sec_level == BT_SECURITY_MAX)
__l2cap_sock_close(sk, ECONNREFUSED);
} else {
if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM)
@@ -4457,7 +4599,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
- if (flags & ACL_START) {
+ if (!(flags & ACL_CONT)) {
struct l2cap_hdr *hdr;
int len;
@@ -4688,6 +4830,9 @@ MODULE_PARM_DESC(max_transmit, "Max transmit value (default = 3)");
module_param(tx_window, uint, 0644);
MODULE_PARM_DESC(tx_window, "Transmission window size value (default = 63)");
+module_param(disable_info_req, bool, 0644);
+MODULE_PARM_DESC(disable_info_req, "Disables l2cap_information_req during channel setup");
+
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
MODULE_VERSION(VERSION);
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 7dca91bb8c5..665ce1421e5 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -234,6 +234,7 @@ static inline int rfcomm_check_security(struct rfcomm_dlc *d)
switch (d->sec_level) {
case BT_SECURITY_HIGH:
+ case BT_SECURITY_MAX:
auth_type = HCI_AT_GENERAL_BONDING_MITM;
break;
case BT_SECURITY_MEDIUM:
@@ -248,32 +249,6 @@ static inline int rfcomm_check_security(struct rfcomm_dlc *d)
auth_type);
}
-static void rfcomm_session_timeout(unsigned long arg)
-{
- struct rfcomm_session *s = (void *) arg;
-
- BT_DBG("session %p state %ld", s, s->state);
-
- set_bit(RFCOMM_TIMED_OUT, &s->flags);
- rfcomm_schedule(RFCOMM_SCHED_TIMEO);
-}
-
-static void rfcomm_session_set_timer(struct rfcomm_session *s, long timeout)
-{
- BT_DBG("session %p state %ld timeout %ld", s, s->state, timeout);
-
- if (!mod_timer(&s->timer, jiffies + timeout))
- rfcomm_session_hold(s);
-}
-
-static void rfcomm_session_clear_timer(struct rfcomm_session *s)
-{
- BT_DBG("session %p state %ld", s, s->state);
-
- if (timer_pending(&s->timer) && del_timer(&s->timer))
- rfcomm_session_put(s);
-}
-
/* ---- RFCOMM DLCs ---- */
static void rfcomm_dlc_timeout(unsigned long arg)
{
@@ -350,7 +325,6 @@ static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d)
rfcomm_session_hold(s);
- rfcomm_session_clear_timer(s);
rfcomm_dlc_hold(d);
list_add(&d->list, &s->dlcs);
d->session = s;
@@ -366,9 +340,6 @@ static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
d->session = NULL;
rfcomm_dlc_put(d);
- if (list_empty(&s->dlcs))
- rfcomm_session_set_timer(s, RFCOMM_IDLE_TIMEOUT);
-
rfcomm_session_put(s);
}
@@ -462,7 +433,6 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
switch (d->state) {
case BT_CONNECT:
- case BT_CONFIG:
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
rfcomm_schedule(RFCOMM_SCHED_AUTH);
@@ -601,8 +571,6 @@ static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
BT_DBG("session %p sock %p", s, sock);
- setup_timer(&s->timer, rfcomm_session_timeout, (unsigned long) s);
-
INIT_LIST_HEAD(&s->dlcs);
s->state = state;
s->sock = sock;
@@ -634,7 +602,6 @@ static void rfcomm_session_del(struct rfcomm_session *s)
if (state == BT_CONNECTED)
rfcomm_send_disc(s, 0);
- rfcomm_session_clear_timer(s);
sock_release(s->sock);
kfree(s);
@@ -676,7 +643,6 @@ static void rfcomm_session_close(struct rfcomm_session *s, int err)
__rfcomm_dlc_close(d, err);
}
- rfcomm_session_clear_timer(s);
rfcomm_session_put(s);
}
@@ -1923,13 +1889,6 @@ static inline void rfcomm_process_sessions(void)
struct rfcomm_session *s;
s = list_entry(p, struct rfcomm_session, list);
- if (test_and_clear_bit(RFCOMM_TIMED_OUT, &s->flags)) {
- s->state = BT_DISCONN;
- rfcomm_send_disc(s, 0);
- rfcomm_session_put(s);
- continue;
- }
-
if (s->state == BT_LISTEN) {
rfcomm_accept_connection(s);
continue;
@@ -2076,7 +2035,8 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
set_bit(RFCOMM_SEC_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
continue;
- } else if (d->sec_level == BT_SECURITY_HIGH) {
+ } else if (d->sec_level == BT_SECURITY_HIGH
+ || d->sec_level == BT_SECURITY_MAX) {
__rfcomm_dlc_close(d, ECONNREFUSED);
continue;
}
@@ -2086,7 +2046,15 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
continue;
if (!status)
- set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
+ if (d->sec_level != BT_SECURITY_MAX)
+ set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
+ else
+ if ((conn->key_type == HCI_LK_AUTHENTICATED_COMBINATION)
+ || (conn->key_type == HCI_LK_COMBINATION
+ && conn->pin_len >= 16))
+ set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
+ else
+ set_bit(RFCOMM_AUTH_REJECT, &d->flags);
else
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
}
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 43fbf6b4b4b..17e2764a6e6 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -757,6 +757,8 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __u
rfcomm_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
if (opt & RFCOMM_LM_SECURE)
rfcomm_pi(sk)->sec_level = BT_SECURITY_HIGH;
+ if (opt & RFCOMM_LM_SECUREMAX)
+ rfcomm_pi(sk)->sec_level = BT_SECURITY_MAX;
rfcomm_pi(sk)->role_switch = (opt & RFCOMM_LM_MASTER);
break;
@@ -802,7 +804,7 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
break;
}
- if (sec.level > BT_SECURITY_HIGH) {
+ if (sec.level > BT_SECURITY_MAX) {
err = -EINVAL;
break;
}
@@ -861,6 +863,10 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
RFCOMM_LM_SECURE;
break;
+ case BT_SECURITY_MAX:
+ opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
+ RFCOMM_LM_SECURE | RFCOMM_LM_SECUREMAX;
+ break;
default:
opt = 0;
break;
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index d0927d1fdad..cb21a785f9d 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -178,6 +178,7 @@ static int sco_connect(struct sock *sk)
{
bdaddr_t *src = &bt_sk(sk)->src;
bdaddr_t *dst = &bt_sk(sk)->dst;
+ __u16 pkt_type = sco_pi(sk)->pkt_type;
struct sco_conn *conn;
struct hci_conn *hcon;
struct hci_dev *hdev;
@@ -194,10 +195,13 @@ static int sco_connect(struct sock *sk)
if (lmp_esco_capable(hdev) && !disable_esco)
type = ESCO_LINK;
- else
+ else {
type = SCO_LINK;
+ pkt_type &= SCO_ESCO_MASK;
+ }
- hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING);
+ hcon = hci_connect(hdev, type, pkt_type, dst,
+ BT_SECURITY_LOW, HCI_AT_NO_BONDING);
if (!hcon)
goto done;
@@ -450,18 +454,22 @@ static int sco_sock_create(struct net *net, struct socket *sock, int protocol,
return 0;
}
-static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
{
- struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
+ struct sockaddr_sco sa;
struct sock *sk = sock->sk;
- bdaddr_t *src = &sa->sco_bdaddr;
- int err = 0;
+ bdaddr_t *src = &sa.sco_bdaddr;
+ int len, err = 0;
- BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));
+ BT_DBG("sk %p %s", sk, batostr(&sa.sco_bdaddr));
if (!addr || addr->sa_family != AF_BLUETOOTH)
return -EINVAL;
+ memset(&sa, 0, sizeof(sa));
+ len = min_t(unsigned int, sizeof(sa), alen);
+ memcpy(&sa, addr, len);
+
lock_sock(sk);
if (sk->sk_state != BT_OPEN) {
@@ -475,7 +483,8 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
err = -EADDRINUSE;
} else {
/* Save source address */
- bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr);
+ bacpy(&bt_sk(sk)->src, &sa.sco_bdaddr);
+ sco_pi(sk)->pkt_type = sa.sco_pkt_type;
sk->sk_state = BT_BOUND;
}
@@ -488,27 +497,34 @@ done:
static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
{
- struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
struct sock *sk = sock->sk;
- int err = 0;
-
+ struct sockaddr_sco sa;
+ int len, err = 0;
BT_DBG("sk %p", sk);
- if (alen < sizeof(struct sockaddr_sco) ||
- addr->sa_family != AF_BLUETOOTH)
+ if (!addr || addr->sa_family != AF_BLUETOOTH)
return -EINVAL;
- if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
- return -EBADFD;
-
- if (sk->sk_type != SOCK_SEQPACKET)
- return -EINVAL;
+ memset(&sa, 0, sizeof(sa));
+ len = min_t(unsigned int, sizeof(sa), alen);
+ memcpy(&sa, addr, len);
lock_sock(sk);
+ if (sk->sk_type != SOCK_SEQPACKET) {
+ err = -EINVAL;
+ goto done;
+ }
+
+ if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
+ err = -EBADFD;
+ goto done;
+ }
+
/* Set destination address and psm */
- bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr);
+ bacpy(&bt_sk(sk)->dst, &sa.sco_bdaddr);
+ sco_pi(sk)->pkt_type = sa.sco_pkt_type;
if ((err = sco_connect(sk)))
goto done;
@@ -614,6 +630,7 @@ static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len
bacpy(&sa->sco_bdaddr, &bt_sk(sk)->dst);
else
bacpy(&sa->sco_bdaddr, &bt_sk(sk)->src);
+ sa->sco_pkt_type = sco_pi(sk)->pkt_type;
return 0;
}