summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/bluetooth/btmtk.c20
-rw-r--r--include/net/bluetooth/bluetooth.h10
-rw-r--r--include/net/bluetooth/hci_core.h108
-rw-r--r--net/bluetooth/hci_core.c10
-rw-r--r--net/bluetooth/hci_event.c33
-rw-r--r--net/bluetooth/hci_sock.c14
-rw-r--r--net/bluetooth/iso.c75
-rw-r--r--net/bluetooth/l2cap_core.c12
-rw-r--r--net/bluetooth/l2cap_sock.c20
-rw-r--r--net/bluetooth/rfcomm/core.c6
-rw-r--r--net/bluetooth/rfcomm/sock.c9
-rw-r--r--net/bluetooth/sco.c52
12 files changed, 215 insertions, 154 deletions
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 8a3f7c3fcfec..7fd9d5ddce02 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -395,6 +395,7 @@ int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
{
struct btmtk_data *data = hci_get_priv(hdev);
int err;
+ bool complete = false;
if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) {
kfree_skb(skb);
@@ -416,19 +417,22 @@ int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
fallthrough;
case HCI_DEVCOREDUMP_ACTIVE:
default:
+ /* Mediatek coredump data would be more than MTK_COREDUMP_NUM */
+ if (data->cd_info.cnt >= MTK_COREDUMP_NUM &&
+ skb->len > MTK_COREDUMP_END_LEN)
+ if (!memcmp((char *)&skb->data[skb->len - MTK_COREDUMP_END_LEN],
+ MTK_COREDUMP_END, MTK_COREDUMP_END_LEN - 1))
+ complete = true;
+
err = hci_devcd_append(hdev, skb);
if (err < 0)
break;
data->cd_info.cnt++;
- /* Mediatek coredump data would be more than MTK_COREDUMP_NUM */
- if (data->cd_info.cnt > MTK_COREDUMP_NUM &&
- skb->len > MTK_COREDUMP_END_LEN)
- if (!memcmp((char *)&skb->data[skb->len - MTK_COREDUMP_END_LEN],
- MTK_COREDUMP_END, MTK_COREDUMP_END_LEN - 1)) {
- bt_dev_info(hdev, "Mediatek coredump end");
- hci_devcd_complete(hdev);
- }
+ if (complete) {
+ bt_dev_info(hdev, "Mediatek coredump end");
+ hci_devcd_complete(hdev);
+ }
break;
}
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index f66bc85c6411..435250c72d56 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -123,6 +123,7 @@ struct bt_voice {
#define BT_VOICE_TRANSPARENT 0x0003
#define BT_VOICE_CVSD_16BIT 0x0060
+#define BT_VOICE_TRANSPARENT_16BIT 0x0063
#define BT_SNDMTU 12
#define BT_RCVMTU 13
@@ -590,15 +591,6 @@ static inline struct sk_buff *bt_skb_sendmmsg(struct sock *sk,
return skb;
}
-static inline int bt_copy_from_sockptr(void *dst, size_t dst_size,
- sockptr_t src, size_t src_size)
-{
- if (dst_size > src_size)
- return -EINVAL;
-
- return copy_from_sockptr(dst, src, dst_size);
-}
-
int bt_to_errno(u16 code);
__u8 bt_status(int err);
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index ea798f07c5a2..ca22ead85dbe 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -804,7 +804,6 @@ struct hci_conn_params {
extern struct list_head hci_dev_list;
extern struct list_head hci_cb_list;
extern rwlock_t hci_dev_list_lock;
-extern struct mutex hci_cb_list_lock;
#define hci_dev_set_flag(hdev, nr) set_bit((nr), (hdev)->dev_flags)
#define hci_dev_clear_flag(hdev, nr) clear_bit((nr), (hdev)->dev_flags)
@@ -2017,24 +2016,47 @@ struct hci_cb {
char *name;
+ bool (*match) (struct hci_conn *conn);
void (*connect_cfm) (struct hci_conn *conn, __u8 status);
void (*disconn_cfm) (struct hci_conn *conn, __u8 status);
void (*security_cfm) (struct hci_conn *conn, __u8 status,
- __u8 encrypt);
+ __u8 encrypt);
void (*key_change_cfm) (struct hci_conn *conn, __u8 status);
void (*role_switch_cfm) (struct hci_conn *conn, __u8 status, __u8 role);
};
+static inline void hci_cb_lookup(struct hci_conn *conn, struct list_head *list)
+{
+ struct hci_cb *cb, *cpy;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(cb, &hci_cb_list, list) {
+ if (cb->match && cb->match(conn)) {
+ cpy = kmalloc(sizeof(*cpy), GFP_ATOMIC);
+ if (!cpy)
+ break;
+
+ *cpy = *cb;
+ INIT_LIST_HEAD(&cpy->list);
+ list_add_rcu(&cpy->list, list);
+ }
+ }
+ rcu_read_unlock();
+}
+
static inline void hci_connect_cfm(struct hci_conn *conn, __u8 status)
{
- struct hci_cb *cb;
+ struct list_head list;
+ struct hci_cb *cb, *tmp;
+
+ INIT_LIST_HEAD(&list);
+ hci_cb_lookup(conn, &list);
- mutex_lock(&hci_cb_list_lock);
- list_for_each_entry(cb, &hci_cb_list, list) {
+ list_for_each_entry_safe(cb, tmp, &list, list) {
if (cb->connect_cfm)
cb->connect_cfm(conn, status);
+ kfree(cb);
}
- mutex_unlock(&hci_cb_list_lock);
if (conn->connect_cfm_cb)
conn->connect_cfm_cb(conn, status);
@@ -2042,43 +2064,55 @@ static inline void hci_connect_cfm(struct hci_conn *conn, __u8 status)
static inline void hci_disconn_cfm(struct hci_conn *conn, __u8 reason)
{
- struct hci_cb *cb;
+ struct list_head list;
+ struct hci_cb *cb, *tmp;
+
+ INIT_LIST_HEAD(&list);
+ hci_cb_lookup(conn, &list);
- mutex_lock(&hci_cb_list_lock);
- list_for_each_entry(cb, &hci_cb_list, list) {
+ list_for_each_entry_safe(cb, tmp, &list, list) {
if (cb->disconn_cfm)
cb->disconn_cfm(conn, reason);
+ kfree(cb);
}
- mutex_unlock(&hci_cb_list_lock);
if (conn->disconn_cfm_cb)
conn->disconn_cfm_cb(conn, reason);
}
-static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
+static inline void hci_security_cfm(struct hci_conn *conn, __u8 status,
+ __u8 encrypt)
{
- struct hci_cb *cb;
- __u8 encrypt;
-
- if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
- return;
+ struct list_head list;
+ struct hci_cb *cb, *tmp;
- encrypt = test_bit(HCI_CONN_ENCRYPT, &conn->flags) ? 0x01 : 0x00;
+ INIT_LIST_HEAD(&list);
+ hci_cb_lookup(conn, &list);
- mutex_lock(&hci_cb_list_lock);
- list_for_each_entry(cb, &hci_cb_list, list) {
+ list_for_each_entry_safe(cb, tmp, &list, list) {
if (cb->security_cfm)
cb->security_cfm(conn, status, encrypt);
+ kfree(cb);
}
- mutex_unlock(&hci_cb_list_lock);
if (conn->security_cfm_cb)
conn->security_cfm_cb(conn, status);
}
+static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
+{
+ __u8 encrypt;
+
+ if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
+ return;
+
+ encrypt = test_bit(HCI_CONN_ENCRYPT, &conn->flags) ? 0x01 : 0x00;
+
+ hci_security_cfm(conn, status, encrypt);
+}
+
static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status)
{
- struct hci_cb *cb;
__u8 encrypt;
if (conn->state == BT_CONFIG) {
@@ -2105,40 +2139,38 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status)
conn->sec_level = conn->pending_sec_level;
}
- mutex_lock(&hci_cb_list_lock);
- list_for_each_entry(cb, &hci_cb_list, list) {
- if (cb->security_cfm)
- cb->security_cfm(conn, status, encrypt);
- }
- mutex_unlock(&hci_cb_list_lock);
-
- if (conn->security_cfm_cb)
- conn->security_cfm_cb(conn, status);
+ hci_security_cfm(conn, status, encrypt);
}
static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status)
{
- struct hci_cb *cb;
+ struct list_head list;
+ struct hci_cb *cb, *tmp;
+
+ INIT_LIST_HEAD(&list);
+ hci_cb_lookup(conn, &list);
- mutex_lock(&hci_cb_list_lock);
- list_for_each_entry(cb, &hci_cb_list, list) {
+ list_for_each_entry_safe(cb, tmp, &list, list) {
if (cb->key_change_cfm)
cb->key_change_cfm(conn, status);
+ kfree(cb);
}
- mutex_unlock(&hci_cb_list_lock);
}
static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
__u8 role)
{
- struct hci_cb *cb;
+ struct list_head list;
+ struct hci_cb *cb, *tmp;
+
+ INIT_LIST_HEAD(&list);
+ hci_cb_lookup(conn, &list);
- mutex_lock(&hci_cb_list_lock);
- list_for_each_entry(cb, &hci_cb_list, list) {
+ list_for_each_entry_safe(cb, tmp, &list, list) {
if (cb->role_switch_cfm)
cb->role_switch_cfm(conn, status, role);
+ kfree(cb);
}
- mutex_unlock(&hci_cb_list_lock);
}
static inline bool hci_bdaddr_is_rpa(bdaddr_t *bdaddr, u8 addr_type)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index f9e19f9cb5a3..18ab5628f85a 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -57,7 +57,6 @@ DEFINE_RWLOCK(hci_dev_list_lock);
/* HCI callback list */
LIST_HEAD(hci_cb_list);
-DEFINE_MUTEX(hci_cb_list_lock);
/* HCI ID Numbering */
static DEFINE_IDA(hci_index_ida);
@@ -2993,9 +2992,7 @@ int hci_register_cb(struct hci_cb *cb)
{
BT_DBG("%p name %s", cb, cb->name);
- mutex_lock(&hci_cb_list_lock);
- list_add_tail(&cb->list, &hci_cb_list);
- mutex_unlock(&hci_cb_list_lock);
+ list_add_tail_rcu(&cb->list, &hci_cb_list);
return 0;
}
@@ -3005,9 +3002,8 @@ int hci_unregister_cb(struct hci_cb *cb)
{
BT_DBG("%p name %s", cb, cb->name);
- mutex_lock(&hci_cb_list_lock);
- list_del(&cb->list);
- mutex_unlock(&hci_cb_list_lock);
+ list_del_rcu(&cb->list);
+ synchronize_rcu();
return 0;
}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 1427d6e2f3c9..2cc7a9306350 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -6870,38 +6870,27 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
return;
hci_dev_lock(hdev);
- rcu_read_lock();
/* Connect all BISes that are bound to the BIG */
- list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
- if (bacmp(&conn->dst, BDADDR_ANY) ||
- conn->type != ISO_LINK ||
- conn->iso_qos.bcast.big != ev->handle)
+ while ((conn = hci_conn_hash_lookup_big_state(hdev, ev->handle,
+ BT_BOUND))) {
+ if (ev->status) {
+ hci_connect_cfm(conn, ev->status);
+ hci_conn_del(conn);
continue;
+ }
if (hci_conn_set_handle(conn,
__le16_to_cpu(ev->bis_handle[i++])))
continue;
- if (!ev->status) {
- conn->state = BT_CONNECTED;
- set_bit(HCI_CONN_BIG_CREATED, &conn->flags);
- rcu_read_unlock();
- hci_debugfs_create_conn(conn);
- hci_conn_add_sysfs(conn);
- hci_iso_setup_path(conn);
- rcu_read_lock();
- continue;
- }
-
- hci_connect_cfm(conn, ev->status);
- rcu_read_unlock();
- hci_conn_del(conn);
- rcu_read_lock();
+ conn->state = BT_CONNECTED;
+ set_bit(HCI_CONN_BIG_CREATED, &conn->flags);
+ hci_debugfs_create_conn(conn);
+ hci_conn_add_sysfs(conn);
+ hci_iso_setup_path(conn);
}
- rcu_read_unlock();
-
if (!ev->status && !i)
/* If no BISes have been connected for the BIG,
* terminate. This is in case all bound connections
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 2272e1849ebd..022b86797acd 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -1926,7 +1926,7 @@ drop:
}
static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname,
- sockptr_t optval, unsigned int len)
+ sockptr_t optval, unsigned int optlen)
{
struct hci_ufilter uf = { .opcode = 0 };
struct sock *sk = sock->sk;
@@ -1943,7 +1943,7 @@ static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname,
switch (optname) {
case HCI_DATA_DIR:
- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, len);
+ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;
@@ -1954,7 +1954,7 @@ static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname,
break;
case HCI_TIME_STAMP:
- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, len);
+ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;
@@ -1974,7 +1974,7 @@ static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname,
uf.event_mask[1] = *((u32 *) f->event_mask + 1);
}
- err = bt_copy_from_sockptr(&uf, sizeof(uf), optval, len);
+ err = copy_safe_from_sockptr(&uf, sizeof(uf), optval, optlen);
if (err)
break;
@@ -2005,7 +2005,7 @@ done:
}
static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
- sockptr_t optval, unsigned int len)
+ sockptr_t optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
int err = 0;
@@ -2015,7 +2015,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
if (level == SOL_HCI)
return hci_sock_setsockopt_old(sock, level, optname, optval,
- len);
+ optlen);
if (level != SOL_BLUETOOTH)
return -ENOPROTOOPT;
@@ -2035,7 +2035,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
goto done;
}
- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, len);
+ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;
diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
index 1b40fd2b2f02..43d0ebe11100 100644
--- a/net/bluetooth/iso.c
+++ b/net/bluetooth/iso.c
@@ -1129,6 +1129,7 @@ static int iso_listen_bis(struct sock *sk)
return -EHOSTUNREACH;
hci_dev_lock(hdev);
+ lock_sock(sk);
/* Fail if user set invalid QoS */
if (iso_pi(sk)->qos_user_set && !check_bcast_qos(&iso_pi(sk)->qos)) {
@@ -1158,10 +1159,10 @@ static int iso_listen_bis(struct sock *sk)
goto unlock;
}
- hci_dev_put(hdev);
-
unlock:
+ release_sock(sk);
hci_dev_unlock(hdev);
+ hci_dev_put(hdev);
return err;
}
@@ -1188,6 +1189,7 @@ static int iso_sock_listen(struct socket *sock, int backlog)
BT_DBG("sk %p backlog %d", sk, backlog);
+ sock_hold(sk);
lock_sock(sk);
if (sk->sk_state != BT_BOUND) {
@@ -1200,10 +1202,16 @@ static int iso_sock_listen(struct socket *sock, int backlog)
goto done;
}
- if (!bacmp(&iso_pi(sk)->dst, BDADDR_ANY))
+ if (!bacmp(&iso_pi(sk)->dst, BDADDR_ANY)) {
err = iso_listen_cis(sk);
- else
+ } else {
+ /* Drop sock lock to avoid potential
+ * deadlock with the hdev lock.
+ */
+ release_sock(sk);
err = iso_listen_bis(sk);
+ lock_sock(sk);
+ }
if (err)
goto done;
@@ -1215,6 +1223,7 @@ static int iso_sock_listen(struct socket *sock, int backlog)
done:
release_sock(sk);
+ sock_put(sk);
return err;
}
@@ -1226,7 +1235,11 @@ static int iso_sock_accept(struct socket *sock, struct socket *newsock,
long timeo;
int err = 0;
- lock_sock(sk);
+ /* Use explicit nested locking to avoid lockdep warnings generated
+ * because the parent socket and the child socket are locked on the
+ * same thread.
+ */
+ lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
timeo = sock_rcvtimeo(sk, arg->flags & O_NONBLOCK);
@@ -1257,7 +1270,7 @@ static int iso_sock_accept(struct socket *sock, struct socket *newsock,
release_sock(sk);
timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
- lock_sock(sk);
+ lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
}
remove_wait_queue(sk_sleep(sk), &wait);
@@ -1398,6 +1411,7 @@ static void iso_conn_big_sync(struct sock *sk)
* change.
*/
hci_dev_lock(hdev);
+ lock_sock(sk);
if (!test_and_set_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags)) {
err = hci_le_big_create_sync(hdev, iso_pi(sk)->conn->hcon,
@@ -1410,6 +1424,7 @@ static void iso_conn_big_sync(struct sock *sk)
err);
}
+ release_sock(sk);
hci_dev_unlock(hdev);
}
@@ -1418,39 +1433,57 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
{
struct sock *sk = sock->sk;
struct iso_pinfo *pi = iso_pi(sk);
+ bool early_ret = false;
+ int err = 0;
BT_DBG("sk %p", sk);
if (test_and_clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
+ sock_hold(sk);
lock_sock(sk);
+
switch (sk->sk_state) {
case BT_CONNECT2:
if (test_bit(BT_SK_PA_SYNC, &pi->flags)) {
+ release_sock(sk);
iso_conn_big_sync(sk);
+ lock_sock(sk);
+
sk->sk_state = BT_LISTEN;
} else {
iso_conn_defer_accept(pi->conn->hcon);
sk->sk_state = BT_CONFIG;
}
- release_sock(sk);
- return 0;
+
+ early_ret = true;
+ break;
case BT_CONNECTED:
if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) {
+ release_sock(sk);
iso_conn_big_sync(sk);
+ lock_sock(sk);
+
sk->sk_state = BT_LISTEN;
- release_sock(sk);
- return 0;
+ early_ret = true;
}
- release_sock(sk);
break;
case BT_CONNECT:
release_sock(sk);
- return iso_connect_cis(sk);
+ err = iso_connect_cis(sk);
+ lock_sock(sk);
+
+ early_ret = true;
+ break;
default:
- release_sock(sk);
break;
}
+
+ release_sock(sk);
+ sock_put(sk);
+
+ if (early_ret)
+ return err;
}
return bt_sock_recvmsg(sock, msg, len, flags);
@@ -1566,7 +1599,7 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
+ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;
@@ -1577,7 +1610,7 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
break;
case BT_PKT_STATUS:
- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
+ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;
@@ -1596,7 +1629,7 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
- err = bt_copy_from_sockptr(&qos, sizeof(qos), optval, optlen);
+ err = copy_safe_from_sockptr(&qos, sizeof(qos), optval, optlen);
if (err)
break;
@@ -1617,8 +1650,8 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
- err = bt_copy_from_sockptr(iso_pi(sk)->base, optlen, optval,
- optlen);
+ err = copy_safe_from_sockptr(iso_pi(sk)->base, optlen, optval,
+ optlen);
if (err)
break;
@@ -2118,6 +2151,11 @@ done:
return HCI_LM_ACCEPT;
}
+static bool iso_match(struct hci_conn *hcon)
+{
+ return hcon->type == ISO_LINK || hcon->type == LE_LINK;
+}
+
static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)
{
if (hcon->type != ISO_LINK) {
@@ -2299,6 +2337,7 @@ drop:
static struct hci_cb iso_cb = {
.name = "ISO",
+ .match = iso_match,
.connect_cfm = iso_connect_cfm,
.disconn_cfm = iso_disconn_cfm,
};
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 6544c1ed7143..27b4c4a2ba1f 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -7217,6 +7217,11 @@ static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c,
return NULL;
}
+static bool l2cap_match(struct hci_conn *hcon)
+{
+ return hcon->type == ACL_LINK || hcon->type == LE_LINK;
+}
+
static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
{
struct hci_dev *hdev = hcon->hdev;
@@ -7224,9 +7229,6 @@ static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
struct l2cap_chan *pchan;
u8 dst_type;
- if (hcon->type != ACL_LINK && hcon->type != LE_LINK)
- return;
-
BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
if (status) {
@@ -7291,9 +7293,6 @@ int l2cap_disconn_ind(struct hci_conn *hcon)
static void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
{
- if (hcon->type != ACL_LINK && hcon->type != LE_LINK)
- return;
-
BT_DBG("hcon %p reason %d", hcon, reason);
l2cap_conn_del(hcon, bt_to_errno(reason));
@@ -7572,6 +7571,7 @@ drop:
static struct hci_cb l2cap_cb = {
.name = "L2CAP",
+ .match = l2cap_match,
.connect_cfm = l2cap_connect_cfm,
.disconn_cfm = l2cap_disconn_cfm,
.security_cfm = l2cap_security_cfm,
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 18e89e764f3b..3d2553dcdb1b 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -755,7 +755,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
opts.max_tx = chan->max_tx;
opts.txwin_size = chan->tx_win;
- err = bt_copy_from_sockptr(&opts, sizeof(opts), optval, optlen);
+ err = copy_safe_from_sockptr(&opts, sizeof(opts), optval,
+ optlen);
if (err)
break;
@@ -800,7 +801,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
break;
case L2CAP_LM:
- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
+ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;
@@ -909,7 +910,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
sec.level = BT_SECURITY_LOW;
- err = bt_copy_from_sockptr(&sec, sizeof(sec), optval, optlen);
+ err = copy_safe_from_sockptr(&sec, sizeof(sec), optval, optlen);
if (err)
break;
@@ -956,7 +957,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
+ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;
@@ -970,7 +971,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
case BT_FLUSHABLE:
- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
+ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;
@@ -1004,7 +1005,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
pwr.force_active = BT_POWER_FORCE_ACTIVE_ON;
- err = bt_copy_from_sockptr(&pwr, sizeof(pwr), optval, optlen);
+ err = copy_safe_from_sockptr(&pwr, sizeof(pwr), optval, optlen);
if (err)
break;
@@ -1015,7 +1016,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
case BT_CHANNEL_POLICY:
- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
+ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;
@@ -1046,7 +1047,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
- err = bt_copy_from_sockptr(&mtu, sizeof(mtu), optval, optlen);
+ err = copy_safe_from_sockptr(&mtu, sizeof(mtu), optval, optlen);
if (err)
break;
@@ -1076,7 +1077,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
- err = bt_copy_from_sockptr(&mode, sizeof(mode), optval, optlen);
+ err = copy_safe_from_sockptr(&mode, sizeof(mode), optval,
+ optlen);
if (err)
break;
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index ad5177e3a69b..4c56ca5a216c 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -2134,6 +2134,11 @@ static int rfcomm_run(void *unused)
return 0;
}
+static bool rfcomm_match(struct hci_conn *hcon)
+{
+ return hcon->type == ACL_LINK;
+}
+
static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
{
struct rfcomm_session *s;
@@ -2180,6 +2185,7 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
static struct hci_cb rfcomm_cb = {
.name = "RFCOMM",
+ .match = rfcomm_match,
.security_cfm = rfcomm_security_cfm
};
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 40766f8119ed..913402806fa0 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -629,10 +629,9 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname,
switch (optname) {
case RFCOMM_LM:
- if (bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen)) {
- err = -EFAULT;
+ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
+ if (err)
break;
- }
if (opt & RFCOMM_LM_FIPS) {
err = -EINVAL;
@@ -685,7 +684,7 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname,
sec.level = BT_SECURITY_LOW;
- err = bt_copy_from_sockptr(&sec, sizeof(sec), optval, optlen);
+ err = copy_safe_from_sockptr(&sec, sizeof(sec), optval, optlen);
if (err)
break;
@@ -703,7 +702,7 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
+ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 78f7bca24487..aa7bfe26cb40 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -319,10 +319,13 @@ static int sco_connect(struct sock *sk)
else
type = SCO_LINK;
- if (sco_pi(sk)->setting == BT_VOICE_TRANSPARENT &&
- (!lmp_transp_capable(hdev) || !lmp_esco_capable(hdev))) {
- err = -EOPNOTSUPP;
- goto unlock;
+ switch (sco_pi(sk)->setting & SCO_AIRMODE_MASK) {
+ case SCO_AIRMODE_TRANSP:
+ if (!lmp_transp_capable(hdev) || !lmp_esco_capable(hdev)) {
+ err = -EOPNOTSUPP;
+ goto unlock;
+ }
+ break;
}
hcon = hci_connect_sco(hdev, type, &sco_pi(sk)->dst,
@@ -896,7 +899,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
+ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;
@@ -915,18 +918,11 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
voice.setting = sco_pi(sk)->setting;
- err = bt_copy_from_sockptr(&voice, sizeof(voice), optval,
- optlen);
+ err = copy_safe_from_sockptr(&voice, sizeof(voice), optval,
+ optlen);
if (err)
break;
- /* Explicitly check for these values */
- if (voice.setting != BT_VOICE_TRANSPARENT &&
- voice.setting != BT_VOICE_CVSD_16BIT) {
- err = -EINVAL;
- break;
- }
-
sco_pi(sk)->setting = voice.setting;
hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
BDADDR_BREDR);
@@ -934,14 +930,19 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
err = -EBADFD;
break;
}
- if (enhanced_sync_conn_capable(hdev) &&
- voice.setting == BT_VOICE_TRANSPARENT)
- sco_pi(sk)->codec.id = BT_CODEC_TRANSPARENT;
+
+ switch (sco_pi(sk)->setting & SCO_AIRMODE_MASK) {
+ case SCO_AIRMODE_TRANSP:
+ if (enhanced_sync_conn_capable(hdev))
+ sco_pi(sk)->codec.id = BT_CODEC_TRANSPARENT;
+ break;
+ }
+
hci_dev_put(hdev);
break;
case BT_PKT_STATUS:
- err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
+ err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
if (err)
break;
@@ -984,7 +985,8 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
- err = bt_copy_from_sockptr(buffer, optlen, optval, optlen);
+ err = copy_struct_from_sockptr(buffer, sizeof(buffer), optval,
+ optlen);
if (err) {
hci_dev_put(hdev);
break;
@@ -1396,11 +1398,13 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
return lm;
}
-static void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
+static bool sco_match(struct hci_conn *hcon)
{
- if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
- return;
+ return hcon->type == SCO_LINK || hcon->type == ESCO_LINK;
+}
+static void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
+{
BT_DBG("hcon %p bdaddr %pMR status %u", hcon, &hcon->dst, status);
if (!status) {
@@ -1415,9 +1419,6 @@ static void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
static void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
{
- if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
- return;
-
BT_DBG("hcon %p reason %d", hcon, reason);
sco_conn_del(hcon, bt_to_errno(reason));
@@ -1443,6 +1444,7 @@ drop:
static struct hci_cb sco_cb = {
.name = "SCO",
+ .match = sco_match,
.connect_cfm = sco_connect_cfm,
.disconn_cfm = sco_disconn_cfm,
};