diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/af_bluetooth.c | 72 | ||||
-rw-r--r-- | net/bluetooth/bnep/core.c | 13 | ||||
-rw-r--r-- | net/bluetooth/bnep/netdev.c | 2 | ||||
-rw-r--r-- | net/bluetooth/cmtp/capi.c | 3 | ||||
-rw-r--r-- | net/bluetooth/cmtp/cmtp.h | 1 | ||||
-rw-r--r-- | net/bluetooth/cmtp/core.c | 30 | ||||
-rw-r--r-- | net/bluetooth/hci_conn.c | 115 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 61 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 97 | ||||
-rw-r--r-- | net/bluetooth/hci_sock.c | 22 | ||||
-rw-r--r-- | net/bluetooth/hci_sysfs.c | 3 | ||||
-rw-r--r-- | net/bluetooth/hidp/core.c | 13 | ||||
-rw-r--r-- | net/bluetooth/l2cap_core.c | 548 | ||||
-rw-r--r-- | net/bluetooth/l2cap_sock.c | 10 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 215 | ||||
-rw-r--r-- | net/bluetooth/rfcomm/core.c | 25 | ||||
-rw-r--r-- | net/bluetooth/rfcomm/sock.c | 13 | ||||
-rw-r--r-- | net/bluetooth/sco.c | 71 | ||||
-rw-r--r-- | net/bluetooth/smp.c | 444 |
19 files changed, 874 insertions, 884 deletions
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 9047512..0938f6b 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -40,15 +40,6 @@ #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.16" /* Bluetooth sockets */ @@ -134,40 +125,11 @@ 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; @@ -283,8 +245,6 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, if (flags & (MSG_OOB)) return -EOPNOTSUPP; - msg->msg_namelen = 0; - skb = skb_recv_datagram(sk, flags, noblock, &err); if (!skb) { if (sk->sk_shutdown & RCV_SHUTDOWN) @@ -349,8 +309,6 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock, if (flags & MSG_OOB) return -EOPNOTSUPP; - msg->msg_namelen = 0; - BT_DBG("sk %p size %zu", sk, size); lock_sock(sk); @@ -387,7 +345,7 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock, } chunk = min_t(unsigned int, skb->len, size); - if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) { + if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, chunk)) { skb_queue_head(&sk->sk_receive_queue, skb); if (!copied) copied = -EFAULT; @@ -399,7 +357,33 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock, sock_recv_ts_and_drops(msg, sk, skb); if (!(flags & MSG_PEEK)) { - skb_pull(skb, chunk); + int skb_len = skb_headlen(skb); + + if (chunk <= skb_len) { + __skb_pull(skb, chunk); + } else { + struct sk_buff *frag; + + __skb_pull(skb, skb_len); + chunk -= skb_len; + + skb_walk_frags(skb, frag) { + if (chunk <= frag->len) { + /* Pulling partial data */ + skb->len -= chunk; + skb->data_len -= chunk; + __skb_pull(frag, chunk); + break; + } else if (frag->len) { + /* Pulling all frag data */ + chunk -= frag->len; + skb->len -= frag->len; + skb->data_len -= frag->len; + __skb_pull(frag, frag->len); + } + } + } + if (skb->len) { skb_queue_head(&sk->sk_receive_queue, skb); break; diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index d9edfe8..1eea820 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -79,17 +79,12 @@ static struct bnep_session *__bnep_get_session(u8 *dst) static void __bnep_link_session(struct bnep_session *s) { - /* It's safe to call __module_get() here because sessions are added - by the socket layer which has to hold the reference to this module. - */ - __module_get(THIS_MODULE); list_add(&s->list, &bnep_session_list); } static void __bnep_unlink_session(struct bnep_session *s) { list_del(&s->list); - module_put(THIS_MODULE); } static int bnep_send(struct bnep_session *s, void *data, size_t len) @@ -492,7 +487,10 @@ static int bnep_session(void *arg) /* RX */ while ((skb = skb_dequeue(&sk->sk_receive_queue))) { skb_orphan(skb); - bnep_rx_frame(s, skb); + if (!skb_linearize(skb)) + bnep_rx_frame(s, skb); + else + kfree_skb(skb); } if (sk->sk_state != BT_CONNECTED) @@ -527,6 +525,7 @@ static int bnep_session(void *arg) up_write(&bnep_session_sem); free_netdev(dev); + module_put_and_exit(0); return 0; } @@ -613,9 +612,11 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) __bnep_link_session(s); + __module_get(THIS_MODULE); s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name); if (IS_ERR(s->task)) { /* Session thread start failed, gotta cleanup. */ + module_put(THIS_MODULE); unregister_netdev(dev); __bnep_unlink_session(s); err = PTR_ERR(s->task); diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c index d4f5dff..bc40864 100644 --- a/net/bluetooth/bnep/netdev.c +++ b/net/bluetooth/bnep/netdev.c @@ -217,7 +217,7 @@ static const struct net_device_ops bnep_netdev_ops = { .ndo_stop = bnep_net_close, .ndo_start_xmit = bnep_net_xmit, .ndo_validate_addr = eth_validate_addr, - .ndo_set_multicast_list = bnep_net_set_mc_list, + .ndo_set_rx_mode = bnep_net_set_mc_list, .ndo_set_mac_address = bnep_net_set_mac_addr, .ndo_tx_timeout = bnep_net_timeout, .ndo_change_mtu = eth_change_mtu, diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index 040f67b..50f0d13 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -386,7 +386,8 @@ static void cmtp_reset_ctr(struct capi_ctr *ctrl) capi_ctr_down(ctrl); - kthread_stop(session->task); + atomic_inc(&session->terminate); + wake_up_process(session->task); } static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp) diff --git a/net/bluetooth/cmtp/cmtp.h b/net/bluetooth/cmtp/cmtp.h index db43b54..c32638d 100644 --- a/net/bluetooth/cmtp/cmtp.h +++ b/net/bluetooth/cmtp/cmtp.h @@ -81,6 +81,7 @@ struct cmtp_session { char name[BTNAMSIZ]; + atomic_t terminate; struct task_struct *task; wait_queue_head_t wait; diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index c5b11af..5a6e634 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -67,14 +67,12 @@ static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr) static void __cmtp_link_session(struct cmtp_session *session) { - __module_get(THIS_MODULE); list_add(&session->list, &cmtp_session_list); } static void __cmtp_unlink_session(struct cmtp_session *session) { list_del(&session->list); - module_put(THIS_MODULE); } static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci) @@ -292,22 +290,27 @@ static int cmtp_session(void *arg) init_waitqueue_entry(&wait, current); add_wait_queue(sk_sleep(sk), &wait); - while (!kthread_should_stop()) { + while (1) { set_current_state(TASK_INTERRUPTIBLE); + if (atomic_read(&session->terminate)) + break; if (sk->sk_state != BT_CONNECTED) break; while ((skb = skb_dequeue(&sk->sk_receive_queue))) { skb_orphan(skb); - cmtp_recv_frame(session, skb); + if (!skb_linearize(skb)) + cmtp_recv_frame(session, skb); + else + kfree_skb(skb); } cmtp_process_transmit(session); schedule(); } - set_current_state(TASK_RUNNING); + __set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(sk), &wait); down_write(&cmtp_session_sem); @@ -322,6 +325,7 @@ static int cmtp_session(void *arg) up_write(&cmtp_session_sem); kfree(session); + module_put_and_exit(0); return 0; } @@ -371,25 +375,28 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) __cmtp_link_session(session); + __module_get(THIS_MODULE); session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d", session->num); if (IS_ERR(session->task)) { + module_put(THIS_MODULE); err = PTR_ERR(session->task); goto unlink; } if (!(session->flags & (1 << CMTP_LOOPBACK))) { err = cmtp_attach_device(session); - if (err < 0) - goto detach; + if (err < 0) { + atomic_inc(&session->terminate); + wake_up_process(session->task); + up_write(&cmtp_session_sem); + return err; + } } up_write(&cmtp_session_sem); return 0; -detach: - cmtp_detach_device(session); - unlink: __cmtp_unlink_session(session); @@ -414,7 +421,8 @@ int cmtp_del_connection(struct cmtp_conndel_req *req) skb_queue_purge(&session->transmit); /* Stop session thread */ - kthread_stop(session->task); + atomic_inc(&session->terminate); + wake_up_process(session->task); } else err = -ENOENT; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 9d8b593..f456645 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -44,6 +44,7 @@ #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> +#include <net/bluetooth/smp.h> static void hci_le_connect(struct hci_conn *conn) { @@ -56,15 +57,15 @@ static void hci_le_connect(struct hci_conn *conn) conn->sec_level = BT_SECURITY_LOW; memset(&cp, 0, sizeof(cp)); - cp.scan_interval = cpu_to_le16(0x0004); - cp.scan_window = cpu_to_le16(0x0004); + cp.scan_interval = cpu_to_le16(0x0060); + cp.scan_window = cpu_to_le16(0x0030); bacpy(&cp.peer_addr, &conn->dst); cp.peer_addr_type = conn->dst_type; - cp.conn_interval_min = cpu_to_le16(0x0008); - cp.conn_interval_max = cpu_to_le16(0x0100); - cp.supervision_timeout = cpu_to_le16(0x0064); - cp.min_ce_len = cpu_to_le16(0x0001); - cp.max_ce_len = cpu_to_le16(0x0001); + cp.conn_interval_min = cpu_to_le16(0x0028); + cp.conn_interval_max = cpu_to_le16(0x0038); + cp.supervision_timeout = cpu_to_le16(0x002a); + cp.min_ce_len = cpu_to_le16(0x0000); + cp.max_ce_len = cpu_to_le16(0x0000); hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); } @@ -218,7 +219,7 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], cp.handle = cpu_to_le16(conn->handle); memcpy(cp.ltk, ltk, sizeof(cp.ltk)); cp.ediv = ediv; - memcpy(cp.rand, rand, sizeof(rand)); + memcpy(cp.rand, rand, sizeof(cp.rand)); hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp); } @@ -333,8 +334,7 @@ static void hci_conn_auto_accept(unsigned long arg) hci_dev_unlock(hdev); } -struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, - __u16 pkt_type, bdaddr_t *dst) +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) { struct hci_conn *conn; @@ -362,22 +362,14 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; break; case SCO_LINK: - if (!pkt_type) - pkt_type = SCO_ESCO_MASK; + 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; case ESCO_LINK: - 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; - } + conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK; break; } @@ -501,14 +493,11 @@ EXPORT_SYMBOL(hci_get_route); /* Create SCO, ACL or LE connection. * Device _must_ be locked */ -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 *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type) { struct hci_conn *acl; struct hci_conn *sco; struct hci_conn *le; - struct inquiry_entry *ie; BT_DBG("%s dst %s", hdev->name, batostr(dst)); @@ -523,7 +512,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, if (!entry) return ERR_PTR(-EHOSTUNREACH); - le = hci_conn_add(hdev, LE_LINK, 0, dst); + le = hci_conn_add(hdev, LE_LINK, dst); if (!le) return ERR_PTR(-ENOMEM); @@ -538,7 +527,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); if (!acl) { - acl = hci_conn_add(hdev, ACL_LINK, 0, dst); + acl = hci_conn_add(hdev, ACL_LINK, dst); if (!acl) return NULL; } @@ -557,7 +546,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, sco = hci_conn_hash_lookup_ba(hdev, type, dst); if (!sco) { - sco = hci_conn_add(hdev, type, pkt_type, dst); + sco = hci_conn_add(hdev, type, dst); if (!sco) { hci_conn_put(acl); return NULL; @@ -621,14 +610,17 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { struct hci_cp_auth_requested cp; - /* encrypt must be pending if auth is also pending */ - set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); - cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); - if (conn->key_type != 0xff) + + /* If we're already encrypted set the REAUTH_PEND flag, + * otherwise set the ENCRYPT_PEND. + */ + if (conn->link_mode & HCI_LM_ENCRYPT) set_bit(HCI_CONN_REAUTH_PEND, &conn->pend); + else + set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); } return 0; @@ -653,6 +645,11 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) { BT_DBG("conn %p", conn); +#ifdef CONFIG_BT_L2CAP + if (conn->type == LE_LINK) + return smp_conn_security(conn, sec_level); +#endif + /* For sdp we don't need the link key. */ if (sec_level == BT_SECURITY_SDP) return 1; @@ -754,34 +751,6 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role) } EXPORT_SYMBOL(hci_conn_switch_role); -/* BEGIN SS_BLUEZ_BT +kjh 2011.06.23 : */ -/* workaround for a2dp chopping in multi connection. */ -/* Change Policy */ -int hci_conn_change_policy(struct hci_conn *conn, __u8 policy) -{ - struct hci_cp_write_link_policy cp; - cp.handle = cpu_to_le16(conn->handle); - cp.policy = policy; - hci_send_cmd(conn->hdev, HCI_OP_WRITE_LINK_POLICY, sizeof(cp), &cp); - - return 0; -} -EXPORT_SYMBOL(hci_conn_change_policy); - -/* Set Encrypt*/ -int hci_conn_set_encrypt(struct hci_conn *conn, __u8 enable) -{ - struct hci_cp_set_conn_encrypt cp; - cp.handle = cpu_to_le16(conn->handle); - cp.encrypt = enable; - hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp); - - return 0; -} -EXPORT_SYMBOL(hci_conn_set_encrypt); -/* END SS_BLUEZ_BT */ - - /* Enter active mode */ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) { @@ -936,15 +905,6 @@ 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; } @@ -981,15 +941,6 @@ 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); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b1b7b3d..857dc88 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1317,59 +1317,41 @@ int hci_blacklist_clear(struct hci_dev *hdev) 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_bh(hdev); - - if (hci_blacklist_lookup(hdev, bdaddr)) { - err = -EEXIST; - goto err; - } + if (hci_blacklist_lookup(hdev, bdaddr)) + return -EEXIST; entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL); - if (!entry) { + if (!entry) return -ENOMEM; - goto err; - } bacpy(&entry->bdaddr, bdaddr); list_add(&entry->list, &hdev->blacklist); - err = 0; - -err: - hci_dev_unlock_bh(hdev); - return err; + return mgmt_device_blocked(hdev->id, bdaddr); } int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr) { struct bdaddr_list *entry; - int err = 0; - - hci_dev_lock_bh(hdev); if (bacmp(bdaddr, BDADDR_ANY) == 0) { - hci_blacklist_clear(hdev); - goto done; + return hci_blacklist_clear(hdev); } entry = hci_blacklist_lookup(hdev, bdaddr); if (!entry) { - err = -ENOENT; - goto done; + return -ENOENT; } list_del(&entry->list); kfree(entry); -done: - hci_dev_unlock_bh(hdev); - return err; + return mgmt_device_unblocked(hdev->id, bdaddr); } static void hci_clear_adv_cache(unsigned long arg) @@ -1528,11 +1510,6 @@ int hci_register_dev(struct hci_dev *hdev) if (!hdev->workqueue) goto nomem; - hdev->tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); - 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, @@ -1579,15 +1556,10 @@ int hci_unregister_dev(struct hci_dev *hdev) for (i = 0; i < NUM_REASSEMBLY; i++) kfree_skb(hdev->reassembly[i]); - cancel_work_sync(&hdev->power_on); - if (!test_bit(HCI_INIT, &hdev->flags) && !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) { @@ -1779,7 +1751,7 @@ int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count) data += (count - rem); count = rem; - }; + } return rem; } @@ -1814,7 +1786,7 @@ int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count) data += (count - rem); count = rem; - }; + } return rem; } @@ -2083,6 +2055,9 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int min = c->sent; conn = c; } + + if (hci_conn_num(hdev, type) == num) + break; } if (conn) { @@ -2140,6 +2115,9 @@ static inline void hci_sched_acl(struct hci_dev *hdev) BT_DBG("%s", hdev->name); + if (!hci_conn_num(hdev, ACL_LINK)) + return; + if (!test_bit(HCI_RAW, &hdev->flags)) { /* ACL tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ @@ -2171,6 +2149,9 @@ static inline void hci_sched_sco(struct hci_dev *hdev) BT_DBG("%s", hdev->name); + if (!hci_conn_num(hdev, SCO_LINK)) + return; + while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, "e))) { while (quote-- && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); @@ -2191,6 +2172,9 @@ static inline void hci_sched_esco(struct hci_dev *hdev) BT_DBG("%s", hdev->name); + if (!hci_conn_num(hdev, ESCO_LINK)) + return; + while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, "e))) { while (quote-- && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); @@ -2211,6 +2195,9 @@ static inline void hci_sched_le(struct hci_dev *hdev) BT_DBG("%s", hdev->name); + if (!hci_conn_num(hdev, LE_LINK)) + return; + if (!test_bit(HCI_RAW, &hdev->flags)) { /* LE tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d8a2d32..d99075a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -545,7 +545,7 @@ static void hci_setup(struct hci_dev *hdev) { hci_setup_event_mask(hdev); - if (hdev->lmp_ver > 1) + if (hdev->hci_ver > 1) hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL); if (hdev->features[6] & LMP_SIMPLE_PAIR) { @@ -898,16 +898,15 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, if (!cp) return; - hci_dev_lock(hdev); - if (cp->enable == 0x01) { del_timer(&hdev->adv_timer); + + hci_dev_lock(hdev); hci_adv_entries_clear(hdev); + hci_dev_unlock(hdev); } else if (cp->enable == 0x00) { mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT); } - - hci_dev_unlock(hdev); } static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb) @@ -992,7 +991,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) } } else { if (!conn) { - conn = hci_conn_add(hdev, ACL_LINK, 0, &cp->bdaddr); + conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr); if (conn) { conn->out = 1; conn->link_mode |= HCI_LM_MASTER; @@ -1103,9 +1102,10 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, return 0; /* Only request authentication for SSP connections or non-SSP - * devices with sec_level HIGH */ + * devices with sec_level HIGH or if MITM protection is requested */ if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) && - conn->pending_sec_level != BT_SECURITY_HIGH) + conn->pending_sec_level != BT_SECURITY_HIGH && + !(conn->auth_type & 0x01)) return 0; return 1; @@ -1315,7 +1315,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) } } else { if (!conn) { - conn = hci_conn_add(hdev, LE_LINK, 0, &cp->peer_addr); + conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr); if (conn) { conn->dst_type = cp->peer_addr_type; conn->out = 1; @@ -1411,8 +1411,14 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s if (conn->type == ACL_LINK) { conn->state = BT_CONFIG; hci_conn_hold(conn); - conn->disc_timeout = HCI_DISCONN_TIMEOUT; - mgmt_connected(hdev->id, &ev->bdaddr); + + if (!conn->out && + !(conn->ssp_mode && conn->hdev->ssp_mode) && + !hci_find_link_key(hdev, &ev->bdaddr)) + conn->disc_timeout = HCI_PAIRING_TIMEOUT; + else + conn->disc_timeout = HCI_DISCONN_TIMEOUT; + mgmt_connected(hdev->id, &ev->bdaddr, conn->type); } else conn->state = BT_CONNECTED; @@ -1462,15 +1468,6 @@ unlock: hci_conn_check_pending(hdev); } -static inline bool is_sco_active(struct hci_dev *hdev) -{ - if (hci_conn_hash_lookup_state(hdev, SCO_LINK, BT_CONNECTED) || - (hci_conn_hash_lookup_state(hdev, ESCO_LINK, - BT_CONNECTED))) - return true; - return false; -} - static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_conn_request *ev = (void *) skb->data; @@ -1495,8 +1492,7 @@ 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) { - /* pkt_type not yet used for incoming connections */ - conn = hci_conn_add(hdev, ev->link_type, 0, &ev->bdaddr); + conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr); if (!conn) { BT_ERR("No memory for new connection"); hci_dev_unlock(hdev); @@ -1514,8 +1510,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk bacpy(&cp.bdaddr, &ev->bdaddr); - if (lmp_rswitch_capable(hdev) && ((mask & HCI_LM_MASTER) - || is_sco_active(hdev))) + if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) cp.role = 0x00; /* Become master */ else cp.role = 0x01; /* Remain slave */ @@ -1590,21 +1585,6 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s if (!conn) goto unlock; - /* SS_BLUETOOTH(gudam.ryu) 2012. 03. 02 - Fixed for opp sending fail, - if the devices were unpaired on the remote end */ - if (ev->status == 0x06 && hdev->ssp_mode > 0 && - conn->ssp_mode > 0) { - struct hci_cp_auth_requested cp; - hci_remove_link_key(hdev, &conn->dst); - cp.handle = cpu_to_le16(conn->handle); - hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, - sizeof(cp), &cp); - hci_dev_unlock(hdev); - BT_DBG("Pin or key missing !!!"); - return; - } - /* SS_Bluetooth(gudam.ryu) End */ - if (!ev->status) { if (!(conn->ssp_mode > 0 && hdev->ssp_mode > 0) && test_bit(HCI_CONN_REAUTH_PEND, &conn->pend)) { @@ -1615,7 +1595,6 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s } } else { mgmt_auth_failed(hdev->id, &conn->dst, ev->status); - conn->disc_timeout = HCI_DISCONN_TIMEOUT/200; /* 0.01 sec */ } clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); @@ -2201,7 +2180,10 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); - if (conn && conn->state == BT_CONNECTED) { + if (!conn) + goto unlock; + + if (conn->state == BT_CONNECTED) { hci_conn_hold(conn); conn->disc_timeout = HCI_PAIRING_TIMEOUT; hci_conn_put(conn); @@ -2221,6 +2203,7 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure); } +unlock: hci_dev_unlock(hdev); } @@ -2506,7 +2489,6 @@ 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 */ @@ -2708,8 +2690,11 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, /* If we're not the initiators request authorization to * proceed from user space (mgmt_user_confirm with - * confirm_hint set to 1). */ - if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + * confirm_hint set to 1). The exception is if neither + * side had MITM in which case we do auto-accept. + */ + if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend) && + (loc_mitm || rem_mitm)) { BT_DBG("Confirming auto-accept as acceptor"); confirm_hint = 1; goto confirm; @@ -2755,11 +2740,9 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_ * initiated the authentication. A traditional auth_complete * event gets always produced as initiator and is also mapped to * the mgmt_auth_failed event */ - if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend) && ev->status != 0) { + if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend) && ev->status != 0) mgmt_auth_failed(hdev->id, &conn->dst, ev->status); - conn->out = 1; - conn->disc_timeout = HCI_DISCONN_TIMEOUT/200; /* 0.01 sec */ - } + hci_conn_put(conn); unlock: @@ -2828,7 +2811,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr); if (!conn) { - conn = hci_conn_add(hdev, LE_LINK, 0, &ev->bdaddr); + conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr); if (!conn) { BT_ERR("No memory for new connection"); hci_dev_unlock(hdev); @@ -2846,7 +2829,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff goto unlock; } - mgmt_connected(hdev->id, &ev->bdaddr); + mgmt_connected(hdev->id, &ev->bdaddr, conn->type); conn->sec_level = BT_SECURITY_LOW; conn->handle = __le16_to_cpu(ev->handle); @@ -2864,19 +2847,17 @@ unlock: static inline void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) { - struct hci_ev_le_advertising_info *ev; - u8 num_reports; - - num_reports = skb->data[0]; - ev = (void *) &skb->data[1]; + u8 num_reports = skb->data[0]; + void *ptr = &skb->data[1]; hci_dev_lock(hdev); - hci_add_adv_entry(hdev, ev); + while (num_reports--) { + struct hci_ev_le_advertising_info *ev = ptr; - while (--num_reports) { - ev = (void *) (ev->data + ev->length + 1); hci_add_adv_entry(hdev, ev); + + ptr += sizeof(*ev) + ev->length + 1; } hci_dev_unlock(hdev); diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index ce1424a..bb78c75 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -183,21 +183,35 @@ static int hci_sock_release(struct socket *sock) static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg) { bdaddr_t bdaddr; + int err; if (copy_from_user(&bdaddr, arg, sizeof(bdaddr))) return -EFAULT; - return hci_blacklist_add(hdev, &bdaddr); + hci_dev_lock_bh(hdev); + + err = hci_blacklist_add(hdev, &bdaddr); + + hci_dev_unlock_bh(hdev); + + return err; } static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg) { bdaddr_t bdaddr; + int err; if (copy_from_user(&bdaddr, arg, sizeof(bdaddr))) return -EFAULT; - return hci_blacklist_del(hdev, &bdaddr); + hci_dev_lock_bh(hdev); + + err = hci_blacklist_del(hdev, &bdaddr); + + hci_dev_unlock_bh(hdev); + + return err; } /* Ioctls that require bound socket */ @@ -434,8 +448,6 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, if (!skb) return err; - msg->msg_namelen = 0; - copied = skb->len; if (len < copied) { msg->msg_flags |= MSG_TRUNC; @@ -587,7 +599,6 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char { struct hci_filter *f = &hci_pi(sk)->filter; - memset(&uf, 0, sizeof(uf)); uf.type_mask = f->type_mask; uf.opcode = f->opcode; uf.event_mask[0] = *((u32 *) f->event_mask + 0); @@ -659,6 +670,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char { struct hci_filter *f = &hci_pi(sk)->filter; + memset(&uf, 0, sizeof(uf)); uf.type_mask = f->type_mask; uf.opcode = f->opcode; uf.event_mask[0] = *((u32 *) f->event_mask + 0); diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index a6c3aa8..661b461 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -5,6 +5,7 @@ #include <linux/init.h> #include <linux/debugfs.h> #include <linux/seq_file.h> +#include <linux/module.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> @@ -23,6 +24,8 @@ static inline char *link_typetostr(int type) return "SCO"; case ESCO_LINK: return "eSCO"; + case LE_LINK: + return "LE"; default: return "UNKNOWN"; } diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 06f1197..0274157 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -716,12 +716,18 @@ static int hidp_session(void *arg) while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) { skb_orphan(skb); - hidp_recv_ctrl_frame(session, skb); + if (!skb_linearize(skb)) + hidp_recv_ctrl_frame(session, skb); + else + kfree_skb(skb); } while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) { skb_orphan(skb); - hidp_recv_intr_frame(session, skb); + if (!skb_linearize(skb)) + hidp_recv_intr_frame(session, skb); + else + kfree_skb(skb); } hidp_process_transmit(session); @@ -872,6 +878,9 @@ static int hidp_start(struct hid_device *hid) struct hidp_session *session = hid->driver_data; struct hid_report *report; + if (hid->quirks & HID_QUIRK_NO_INIT_REPORTS) + return 0; + list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT]. report_list, list) hidp_send_report(session, report); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8d0e801..dd7c019 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -56,24 +56,6 @@ #include <net/bluetooth/l2cap.h> #include <net/bluetooth/smp.h> -/* BEGIN SLP_Bluetooth :: fix av chopping issue. */ -#ifdef CONFIG_SLP -#define HCI_BROADCOMM_QOS_PATCH -#endif - -#ifdef HCI_BROADCOMM_QOS_PATCH -#define L2CAP_PSM_AVDTP 25 -#define HCI_BROADCOM_QOS_CMD 0xFC57 /* For bcm4329/bcm4330 chipset */ -#define PRIORITY_NORMAL 0x00 /* Broadcom ACL priority for bcm4330 chipset */ -#define PRIORITY_HIGH 0x01 - -struct hci_cp_broadcom_cmd { - __le16 handle; - __u8 priority; /* Only for bcm4330 chipset */ -} __attribute__ ((__packed__)); -#endif -/* END SLP_Bluetooth */ - int disable_ertm; static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; @@ -92,14 +74,6 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); -/* BEGIN SS_BLUEZ_BT +kjh 2011.06.23 : */ -/* workaround for a2dp chopping in multi connection. */ -static struct l2cap_conn *av_conn; -static struct l2cap_conn *hid_conn; -static struct l2cap_conn *rfc_conn; -/* END SS_BLUEZ_BT */ - - /* ---- L2CAP channels ---- */ static inline void chan_hold(struct l2cap_chan *c) @@ -277,7 +251,7 @@ static void l2cap_chan_timeout(unsigned long arg) if (sock_owned_by_user(sk)) { /* sk is owned by user. Try again later */ - __set_chan_timer(chan, HZ / 5); + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); bh_unlock_sock(sk); chan_put(chan); return; @@ -336,37 +310,6 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, chan->psm, chan->dcid); -/* BEGIN SS_BLUEZ_BT +kjh 2011.06.23 : */ -/* workaround for a2dp chopping in multi connection.*/ -/* todo : now, we can't check obex properly. */ - switch (chan->psm) { - case 0x03: - rfc_conn = conn; - - if (av_conn != NULL && rfc_conn == av_conn) - rfc_conn = NULL; - break; - case 0x11: - hid_conn = conn; - break; - case 0x17: - av_conn = conn; - if (rfc_conn != NULL && rfc_conn == av_conn) - rfc_conn = NULL; - break; - default: - break; - } - - if (av_conn != NULL && (hid_conn != NULL || rfc_conn != NULL)) { - hci_conn_set_encrypt(av_conn->hcon, 0x00); - hci_conn_switch_role(av_conn->hcon, 0x00); - hci_conn_set_encrypt(av_conn->hcon, 0x01); - hci_conn_change_policy(av_conn->hcon, 0x04); - av_conn = NULL; - } -/* END SS_BLUEZ_BT */ - conn->disc_reason = 0x13; chan->conn = conn; @@ -419,26 +362,6 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) chan_put(chan); chan->conn = NULL; - -/* BEGIN SS_BLUEZ_BT +kjh 2011.06.23 : */ -/* workaround for a2dp chopping in multi connection.*/ - switch (chan->psm) { - case 0x03: - rfc_conn = NULL; - break; - case 0x11: - hid_conn = NULL; - break; - case 0x17: - av_conn = NULL; - break; - default: - break; - } -/* END SS_BLUEZ_BT */ - - if (conn->hcon) - conn->hcon->out = 1; hci_conn_put(conn->hcon); } @@ -939,6 +862,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) write_lock_bh(&conn->chan_lock); hci_conn_hold(conn->hcon); + conn->hcon->disc_timeout = HCI_DISCONN_TIMEOUT; bacpy(&bt_sk(sk)->src, conn->src); bacpy(&bt_sk(sk)->dst, conn->dst); @@ -978,39 +902,25 @@ static void l2cap_chan_ready(struct sock *sk) static void l2cap_conn_ready(struct l2cap_conn *conn) { struct l2cap_chan *chan; + struct hci_conn *hcon = conn->hcon; BT_DBG("conn %p", conn); - if (!conn->hcon->out && conn->hcon->type == LE_LINK) + if (!hcon->out && hcon->type == LE_LINK) l2cap_le_conn_ready(conn); - read_lock(&conn->chan_lock); - -/* This is SBH650 issue. and this is only workaround */ -/* We don not send info request at this time */ -/* somtimes SBH650 will send disconnect */ - if (!conn->hcon->out - && !(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) { - struct l2cap_info_req req; - req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); - - conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; - conn->info_ident = l2cap_get_ident(conn); - - mod_timer(&conn->info_timer, jiffies + - msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); + if (hcon->out && hcon->type == LE_LINK) + smp_conn_security(hcon, hcon->pending_sec_level); - l2cap_send_cmd(conn, conn->info_ident, - L2CAP_INFO_REQ, sizeof(req), &req); - } + read_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; bh_lock_sock(sk); - if (conn->hcon->type == LE_LINK) { - if (smp_conn_security(conn, chan->sec_level)) + if (hcon->type == LE_LINK) { + if (smp_conn_security(hcon, chan->sec_level)) l2cap_chan_ready(sk); } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { @@ -1081,8 +991,10 @@ 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); - if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) + if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) { del_timer(&conn->security_timer); + smp_chan_destroy(conn); + } hcon->l2cap_data = NULL; kfree(conn); @@ -1203,10 +1115,10 @@ int l2cap_chan_connect(struct l2cap_chan *chan) auth_type = l2cap_get_auth_type(chan); if (chan->dcid == L2CAP_CID_LE_DATA) - hcon = hci_connect(hdev, LE_LINK, 0, dst, + hcon = hci_connect(hdev, LE_LINK, dst, chan->sec_level, auth_type); else - hcon = hci_connect(hdev, ACL_LINK, 0, dst, + hcon = hci_connect(hdev, ACL_LINK, dst, chan->sec_level, auth_type); if (IS_ERR(hcon)) { @@ -1335,7 +1247,7 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan) __clear_retrans_timer(chan); } -void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) +static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) { struct hci_conn *hcon = chan->conn->hcon; u16 flags; @@ -1351,7 +1263,7 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) hci_send_acl(hcon, skb, flags); } -void l2cap_streaming_send(struct l2cap_chan *chan) +static void l2cap_streaming_send(struct l2cap_chan *chan) { struct sk_buff *skb; u16 control, fcs; @@ -1417,7 +1329,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) l2cap_do_send(chan, tx_skb); } -int l2cap_ertm_send(struct l2cap_chan *chan) +static int l2cap_ertm_send(struct l2cap_chan *chan) { struct sk_buff *skb, *tx_skb; u16 control, fcs; @@ -1555,7 +1467,7 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in return sent; } -struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) +static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; @@ -1585,7 +1497,7 @@ struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr return skb; } -struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) +static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; @@ -1614,7 +1526,9 @@ struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *m return skb; } -struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen) +static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, + struct msghdr *msg, size_t len, + u16 control, u16 sdulen) { struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; @@ -1660,7 +1574,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr * return skb; } -int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) +static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { struct sk_buff *skb; struct sk_buff_head sar_queue; @@ -2243,7 +2157,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi void *ptr = req->data; int type, olen; unsigned long val; - struct l2cap_conf_rfc rfc; + struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC }; BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data); @@ -2354,14 +2268,26 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); - switch (type) { - case L2CAP_CONF_RFC: - if (olen == sizeof(rfc)) - memcpy(&rfc, (void *)val, olen); - goto done; - } + if (type != L2CAP_CONF_RFC) + continue; + + if (olen != sizeof(rfc)) + break; + + memcpy(&rfc, (void *)val, olen); + goto done; } + /* Use sane default values in case a misbehaving remote device + * did not send an RFC option. + */ + rfc.mode = chan->mode; + rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); + rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); + rfc.max_pdu_size = cpu_to_le16(chan->imtu); + + BT_ERR("Expected RFC option was not found, using defaults"); + done: switch (rfc.mode) { case L2CAP_MODE_ERTM: @@ -2374,11 +2300,16 @@ done: } } -static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +static inline int l2cap_command_rej(struct l2cap_conn *conn, + struct l2cap_cmd_hdr *cmd, u16 cmd_len, + u8 *data) { - struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data; + struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data; + + if (cmd_len < sizeof(*rej)) + return -EPROTO; - if (rej->reason != 0x0000) + if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD) return 0; if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) && @@ -2394,7 +2325,8 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd return 0; } -static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +static int l2cap_connect_req(struct l2cap_conn *conn, + struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) { struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; struct l2cap_conn_rsp rsp; @@ -2402,8 +2334,14 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd struct sock *parent, *sk = NULL; int result, status = L2CAP_CS_NO_INFO; - u16 dcid = 0, scid = __le16_to_cpu(req->scid); - __le16 psm = req->psm; + u16 dcid = 0, scid; + __le16 psm; + + if (cmd_len < sizeof(struct l2cap_conn_req)) + return -EPROTO; + + scid = __le16_to_cpu(req->scid); + psm = req->psm; BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); @@ -2516,13 +2454,6 @@ sendresp: L2CAP_INFO_REQ, sizeof(info), &info); } -/* this is workaround for windows mobile phone. */ -/* maybe, conf negotiation has some problem in wm phone. */ -/* wm phone send first pdu over max size. (we expect 1013, but recved 1014) */ -/* this code is mandatory for SIG CERTI 3.0 */ -/* this code is only for Honeycomb and ICS. */ -/* Gingerbread doesn't have this part. */ -/* if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) && result == L2CAP_CR_SUCCESS) { u8 buf[128]; @@ -2531,12 +2462,13 @@ sendresp: l2cap_build_conf_req(chan, buf), buf); chan->num_conf_req++; } -*/ return 0; } -static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +static int l2cap_connect_rsp(struct l2cap_conn *conn, + struct l2cap_cmd_hdr *cmd, u16 cmd_len, + u8 *data) { struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data; u16 scid, dcid, result, status; @@ -2544,6 +2476,9 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd struct sock *sk; u8 req[128]; + if (cmd_len < sizeof(*rsp)) + return -EPROTO; + scid = __le16_to_cpu(rsp->scid); dcid = __le16_to_cpu(rsp->dcid); result = __le16_to_cpu(rsp->result); @@ -2573,20 +2508,6 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) break; -/* BEGIN SLP_Bluetooth :: fix av chopping issue. */ -#ifdef HCI_BROADCOMM_QOS_PATCH - /* To gurantee the A2DP packet*/ - if (chan->psm == L2CAP_PSM_AVDTP) { - struct hci_cp_broadcom_cmd cp; - cp.handle = cpu_to_le16(conn->hcon->handle); - cp.priority = PRIORITY_HIGH; - - hci_send_cmd(conn->hcon->hdev, HCI_BROADCOM_QOS_CMD, - sizeof(cp), &cp); - } -#endif -/* END SLP_Bluetooth */ - l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(chan, req), req); chan->num_conf_req++; @@ -2601,7 +2522,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd if (sock_owned_by_user(sk)) { l2cap_state_change(chan, BT_DISCONN); __clear_chan_timer(chan); - __set_chan_timer(chan, HZ / 5); + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); break; } @@ -2633,6 +2554,9 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr struct sock *sk; int len; + if (cmd_len < sizeof(*req)) + return -EPROTO; + dcid = __le16_to_cpu(req->dcid); flags = __le16_to_cpu(req->flags); @@ -2644,10 +2568,13 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr sk = chan->sk; - if (sk->sk_state != BT_CONFIG && sk->sk_state != BT_CONNECT2) { - struct l2cap_cmd_rej rej; + if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) { + struct l2cap_cmd_rej_cid rej; + + rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID); + rej.scid = cpu_to_le16(chan->scid); + rej.dcid = cpu_to_le16(chan->dcid); - rej.reason = cpu_to_le16(0x0002); l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej); goto unlock; @@ -2655,7 +2582,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* Reject if config buffer is too small. */ len = cmd_len - sizeof(*req); - if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) { + if (chan->conf_len + len > sizeof(chan->conf_req)) { l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(chan, rsp, L2CAP_CONF_REJECT, flags), rsp); @@ -2717,13 +2644,18 @@ unlock: return 0; } -static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +static inline int l2cap_config_rsp(struct l2cap_conn *conn, + struct l2cap_cmd_hdr *cmd, u16 cmd_len, + u8 *data) { struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data; u16 scid, flags, result; struct l2cap_chan *chan; struct sock *sk; - int len = cmd->len - sizeof(*rsp); + int len = cmd_len - sizeof(*rsp); + + if (cmd_len < sizeof(*rsp)) + return -EPROTO; scid = __le16_to_cpu(rsp->scid); flags = __le16_to_cpu(rsp->flags); @@ -2771,7 +2703,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr default: sk->sk_err = ECONNRESET; - __set_chan_timer(chan, HZ * 5); + __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT); l2cap_send_disconn_req(conn, chan, ECONNRESET); goto done; } @@ -2799,7 +2731,9 @@ done: return 0; } -static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +static inline int l2cap_disconnect_req(struct l2cap_conn *conn, + struct l2cap_cmd_hdr *cmd, u16 cmd_len, + u8 *data) { struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data; struct l2cap_disconn_rsp rsp; @@ -2807,6 +2741,9 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd struct l2cap_chan *chan; struct sock *sk; + if (cmd_len != sizeof(*req)) + return -EPROTO; + scid = __le16_to_cpu(req->scid); dcid = __le16_to_cpu(req->dcid); @@ -2828,7 +2765,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd if (sock_owned_by_user(sk)) { l2cap_state_change(chan, BT_DISCONN); __clear_chan_timer(chan); - __set_chan_timer(chan, HZ / 5); + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); bh_unlock_sock(sk); return 0; } @@ -2840,13 +2777,18 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd return 0; } -static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, + struct l2cap_cmd_hdr *cmd, u16 cmd_len, + u8 *data) { struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data; u16 dcid, scid; struct l2cap_chan *chan; struct sock *sk; + if (cmd_len != sizeof(*rsp)) + return -EPROTO; + scid = __le16_to_cpu(rsp->scid); dcid = __le16_to_cpu(rsp->dcid); @@ -2862,7 +2804,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd if (sock_owned_by_user(sk)) { l2cap_state_change(chan,BT_DISCONN); __clear_chan_timer(chan); - __set_chan_timer(chan, HZ / 5); + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); bh_unlock_sock(sk); return 0; } @@ -2874,11 +2816,16 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd return 0; } -static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +static inline int l2cap_information_req(struct l2cap_conn *conn, + struct l2cap_cmd_hdr *cmd, u16 cmd_len, + u8 *data) { struct l2cap_info_req *req = (struct l2cap_info_req *) data; u16 type; + if (cmd_len != sizeof(*req)) + return -EPROTO; + type = __le16_to_cpu(req->type); BT_DBG("type 0x%4.4x", type); @@ -2914,11 +2861,16 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm return 0; } -static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +static inline int l2cap_information_rsp(struct l2cap_conn *conn, + struct l2cap_cmd_hdr *cmd, u16 cmd_len, + u8 *data) { struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data; u16 type, result; + if (cmd_len < sizeof(*rsp)) + return -EPROTO; + type = __le16_to_cpu(rsp->type); result = __le16_to_cpu(rsp->result); @@ -3037,15 +2989,15 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, switch (cmd->code) { case L2CAP_COMMAND_REJ: - l2cap_command_rej(conn, cmd, data); + l2cap_command_rej(conn, cmd, cmd_len, data); break; case L2CAP_CONN_REQ: - err = l2cap_connect_req(conn, cmd, data); + err = l2cap_connect_req(conn, cmd, cmd_len, data); break; case L2CAP_CONN_RSP: - err = l2cap_connect_rsp(conn, cmd, data); + err = l2cap_connect_rsp(conn, cmd, cmd_len, data); break; case L2CAP_CONF_REQ: @@ -3053,15 +3005,15 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, break; case L2CAP_CONF_RSP: - err = l2cap_config_rsp(conn, cmd, data); + err = l2cap_config_rsp(conn, cmd, cmd_len, data); break; case L2CAP_DISCONN_REQ: - err = l2cap_disconnect_req(conn, cmd, data); + err = l2cap_disconnect_req(conn, cmd, cmd_len, data); break; case L2CAP_DISCONN_RSP: - err = l2cap_disconnect_rsp(conn, cmd, data); + err = l2cap_disconnect_rsp(conn, cmd, cmd_len, data); break; case L2CAP_ECHO_REQ: @@ -3072,11 +3024,11 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, break; case L2CAP_INFO_REQ: - err = l2cap_information_req(conn, cmd, data); + err = l2cap_information_req(conn, cmd, cmd_len, data); break; case L2CAP_INFO_RSP: - err = l2cap_information_rsp(conn, cmd, data); + err = l2cap_information_rsp(conn, cmd, cmd_len, data); break; default: @@ -3138,12 +3090,12 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data); if (err) { - struct l2cap_cmd_rej rej; + struct l2cap_cmd_rej_unk rej; BT_ERR("Wrong link type (%d)", err); /* FIXME: Map err to a valid reason */ - rej.reason = cpu_to_le16(0); + rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD); l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej); } @@ -3238,102 +3190,104 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, return 0; } -static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) +static void append_skb_frag(struct sk_buff *skb, + struct sk_buff *new_frag, struct sk_buff **last_frag) { - struct sk_buff *_skb; - int err; + /* skb->len reflects data in skb as well as all fragments + * skb->data_len reflects only data in fragments + */ + if (!skb_has_frag_list(skb)) + skb_shinfo(skb)->frag_list = new_frag; + + new_frag->next = NULL; + + (*last_frag)->next = new_frag; + *last_frag = new_frag; + + skb->len += new_frag->len; + skb->data_len += new_frag->len; + skb->truesize += new_frag->truesize; +} + +static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) +{ + int err = -EINVAL; switch (control & L2CAP_CTRL_SAR) { case L2CAP_SDU_UNSEGMENTED: - if (test_bit(CONN_SAR_SDU, &chan->conn_state)) - goto drop; + if (chan->sdu) + break; - return chan->ops->recv(chan->data, skb); + err = chan->ops->recv(chan->data, skb); + break; case L2CAP_SDU_START: - if (test_bit(CONN_SAR_SDU, &chan->conn_state)) - goto drop; + if (chan->sdu) + break; chan->sdu_len = get_unaligned_le16(skb->data); + skb_pull(skb, 2); - if (chan->sdu_len > chan->imtu) - goto disconnect; - - chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC); - if (!chan->sdu) - return -ENOMEM; + if (chan->sdu_len > chan->imtu) { + err = -EMSGSIZE; + break; + } - /* pull sdu_len bytes only after alloc, because of Local Busy - * condition we have to be sure that this will be executed - * only once, i.e., when alloc does not fail */ - skb_pull(skb, 2); + if (skb->len >= chan->sdu_len) + break; - memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); + chan->sdu = skb; + chan->sdu_last_frag = skb; - set_bit(CONN_SAR_SDU, &chan->conn_state); - chan->partial_sdu_len = skb->len; + skb = NULL; + err = 0; break; case L2CAP_SDU_CONTINUE: - if (!test_bit(CONN_SAR_SDU, &chan->conn_state)) - goto disconnect; - if (!chan->sdu) - goto disconnect; + break; - chan->partial_sdu_len += skb->len; - if (chan->partial_sdu_len > chan->sdu_len) - goto drop; + append_skb_frag(chan->sdu, skb, + &chan->sdu_last_frag); + skb = NULL; - memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); + if (chan->sdu->len >= chan->sdu_len) + break; + err = 0; break; case L2CAP_SDU_END: - if (!test_bit(CONN_SAR_SDU, &chan->conn_state)) - goto disconnect; - if (!chan->sdu) - goto disconnect; - - chan->partial_sdu_len += skb->len; - - if (chan->partial_sdu_len > chan->imtu) - goto drop; + break; - if (chan->partial_sdu_len != chan->sdu_len) - goto drop; + append_skb_frag(chan->sdu, skb, + &chan->sdu_last_frag); + skb = NULL; - memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); + if (chan->sdu->len != chan->sdu_len) + break; - _skb = skb_clone(chan->sdu, GFP_ATOMIC); - if (!_skb) { - return -ENOMEM; - } + err = chan->ops->recv(chan->data, chan->sdu); - err = chan->ops->recv(chan->data, _skb); - if (err < 0) { - kfree_skb(_skb); - return err; + if (!err) { + /* Reassembly complete */ + chan->sdu = NULL; + chan->sdu_last_frag = NULL; + chan->sdu_len = 0; } - - clear_bit(CONN_SAR_SDU, &chan->conn_state); - - kfree_skb(chan->sdu); break; } - kfree_skb(skb); - return 0; - -drop: - kfree_skb(chan->sdu); - chan->sdu = NULL; + if (err) { + kfree_skb(skb); + kfree_skb(chan->sdu); + chan->sdu = NULL; + chan->sdu_last_frag = NULL; + chan->sdu_len = 0; + } -disconnect: - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); - kfree_skb(skb); - return 0; + return err; } static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan) @@ -3387,99 +3341,6 @@ void l2cap_chan_busy(struct l2cap_chan *chan, int busy) } } -static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) -{ - struct sk_buff *_skb; - int err = -EINVAL; - - /* - * TODO: We have to notify the userland if some data is lost with the - * Streaming Mode. - */ - - switch (control & L2CAP_CTRL_SAR) { - case L2CAP_SDU_UNSEGMENTED: - if (test_bit(CONN_SAR_SDU, &chan->conn_state)) { - kfree_skb(chan->sdu); - break; - } - - err = chan->ops->recv(chan->data, skb); - if (!err) - return 0; - - break; - - case L2CAP_SDU_START: - if (test_bit(CONN_SAR_SDU, &chan->conn_state)) { - kfree_skb(chan->sdu); - break; - } - - chan->sdu_len = get_unaligned_le16(skb->data); - skb_pull(skb, 2); - - if (chan->sdu_len > chan->imtu) { - err = -EMSGSIZE; - break; - } - - chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC); - if (!chan->sdu) { - err = -ENOMEM; - break; - } - - memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); - - set_bit(CONN_SAR_SDU, &chan->conn_state); - chan->partial_sdu_len = skb->len; - err = 0; - break; - - case L2CAP_SDU_CONTINUE: - if (!test_bit(CONN_SAR_SDU, &chan->conn_state)) - break; - - memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); - - chan->partial_sdu_len += skb->len; - if (chan->partial_sdu_len > chan->sdu_len) - kfree_skb(chan->sdu); - else - err = 0; - - break; - - case L2CAP_SDU_END: - if (!test_bit(CONN_SAR_SDU, &chan->conn_state)) - break; - - memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); - - clear_bit(CONN_SAR_SDU, &chan->conn_state); - chan->partial_sdu_len += skb->len; - - if (chan->partial_sdu_len > chan->imtu) - goto drop; - - if (chan->partial_sdu_len == chan->sdu_len) { - _skb = skb_clone(chan->sdu, GFP_ATOMIC); - err = chan->ops->recv(chan->data, _skb); - if (err < 0) - kfree_skb(_skb); - } - err = 0; - -drop: - kfree_skb(chan->sdu); - break; - } - - kfree_skb(skb); - return err; -} - static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) { struct sk_buff *skb; @@ -3494,7 +3355,7 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) skb = skb_dequeue(&chan->srej_q); control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; - err = l2cap_ertm_reassembly_sdu(chan, skb, control); + err = l2cap_reassemble_sdu(chan, skb, control); if (err < 0) { l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); @@ -3654,7 +3515,7 @@ expected: return 0; } - err = l2cap_ertm_reassembly_sdu(chan, skb, rx_control); + err = l2cap_reassemble_sdu(chan, skb, rx_control); chan->buffer_seq = (chan->buffer_seq + 1) % 64; if (err < 0) { l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); @@ -3970,12 +3831,20 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk tx_seq = __get_txseq(control); - if (chan->expected_tx_seq == tx_seq) - chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; - else - chan->expected_tx_seq = (tx_seq + 1) % 64; + if (chan->expected_tx_seq != tx_seq) { + /* Frame(s) missing - must discard partial SDU */ + kfree_skb(chan->sdu); + chan->sdu = NULL; + chan->sdu_last_frag = NULL; + chan->sdu_len = 0; - l2cap_streaming_reassembly_sdu(chan, skb, control); + /* TODO: Notify userland of missing data */ + } + + chan->expected_tx_seq = (tx_seq + 1) % 64; + + if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE) + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto done; @@ -4191,7 +4060,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) if (encrypt == 0x00) { if (chan->sec_level == BT_SECURITY_MEDIUM) { __clear_chan_timer(chan); - __set_chan_timer(chan, HZ * 5); + __set_chan_timer(chan, L2CAP_ENC_TIMEOUT); } else if (chan->sec_level == BT_SECURITY_HIGH) l2cap_chan_close(chan, ECONNREFUSED); } else { @@ -4210,6 +4079,11 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) BT_DBG("conn %p", conn); + if (hcon->type == LE_LINK) { + smp_distribute_keys(conn, 0); + del_timer(&conn->security_timer); + } + read_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { @@ -4222,9 +4096,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) 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); - smp_distribute_keys(conn, 0); } bh_unlock_sock(sk); @@ -4256,7 +4128,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) L2CAP_CONN_REQ, sizeof(req), &req); } else { __clear_chan_timer(chan); - __set_chan_timer(chan, HZ / 10); + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); } } else if (chan->state == BT_CONNECT2) { struct l2cap_conn_rsp rsp; @@ -4276,7 +4148,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) } } else { l2cap_state_change(chan, BT_DISCONN); - __set_chan_timer(chan, HZ / 10); + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); res = L2CAP_CR_SEC_BLOCK; stat = L2CAP_CS_NO_INFO; } @@ -4423,7 +4295,7 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p) 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); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 785e84f..74e59cd 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -26,6 +26,9 @@ /* Bluetooth L2CAP sockets. */ +#include <linux/security.h> +#include <linux/export.h> + #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> #include <net/bluetooth/l2cap.h> @@ -613,7 +616,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch break; } - if (smp_conn_security(conn, sec.level)) + if (smp_conn_security(conn->hcon, sec.level)) break; err = 0; @@ -801,7 +804,8 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) sk->sk_shutdown = SHUTDOWN_MASK; l2cap_chan_close(chan, 0); - if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); } @@ -934,6 +938,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->force_reliable = pchan->force_reliable; chan->flushable = pchan->flushable; chan->force_active = pchan->force_active; + + security_sk_clone(parent, sk); } else { switch (sk->sk_type) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9832721..2c76342 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -23,6 +23,7 @@ /* Bluetooth HCI Management interface */ #include <linux/uaccess.h> +#include <linux/module.h> #include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> @@ -147,8 +148,6 @@ static int read_index_list(struct sock *sk) hci_del_off_timer(d); - set_bit(HCI_MGMT, &d->flags); - if (test_bit(HCI_SETUP, &d->flags)) continue; @@ -908,7 +907,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) struct hci_dev *hdev; struct mgmt_cp_load_keys *cp; u16 key_count, expected_len; - int i, err; + int i; cp = (void *) data; @@ -918,9 +917,9 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) key_count = get_unaligned_le16(&cp->key_count); expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info); - if (expected_len > len) { - BT_ERR("load_keys: expected at least %u bytes, got %u bytes", - expected_len, len); + if (expected_len != len) { + BT_ERR("load_keys: expected %u bytes, got %u bytes", + len, expected_len); return -EINVAL; } @@ -942,36 +941,17 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) else clear_bit(HCI_DEBUG_KEYS, &hdev->flags); - len -= sizeof(*cp); - i = 0; - - while (i < len) { - struct mgmt_key_info *key = (void *) cp->keys + i; - - i += sizeof(*key) + key->dlen; - - if (key->type == HCI_LK_SMP_LTK) { - struct key_master_id *id = (void *) key->data; - - if (key->dlen != sizeof(struct key_master_id)) - continue; - - hci_add_ltk(hdev, 0, &key->bdaddr, key->pin_len, - id->ediv, id->rand, key->val); - - continue; - } + for (i = 0; i < key_count; i++) { + struct mgmt_key_info *key = &cp->keys[i]; hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type, key->pin_len); } - err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0); - hci_dev_unlock_bh(hdev); hci_dev_put(hdev); - return err; + return 0; } static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len) @@ -1347,6 +1327,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) struct hci_dev *hdev; struct mgmt_cp_pair_device *cp; struct pending_cmd *cmd; + struct adv_entry *entry; u8 sec_level, auth_type; struct hci_conn *conn; int err; @@ -1364,15 +1345,20 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) hci_dev_lock_bh(hdev); - if (cp->io_cap == 0x03) { - sec_level = BT_SECURITY_MEDIUM; + sec_level = BT_SECURITY_MEDIUM; + if (cp->io_cap == 0x03) auth_type = HCI_AT_DEDICATED_BONDING; - } else { - sec_level = BT_SECURITY_HIGH; + else auth_type = HCI_AT_DEDICATED_BONDING_MITM; - } - conn = hci_connect(hdev, ACL_LINK, 0, &cp->bdaddr, sec_level, auth_type); + entry = hci_find_adv_entry(hdev, &cp->bdaddr); + if (entry) + conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level, + auth_type); + else + conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, + auth_type); + if (IS_ERR(conn)) { err = PTR_ERR(conn); goto unlock; @@ -1391,7 +1377,10 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) goto unlock; } - conn->connect_cfm_cb = pairing_complete_cb; + /* For LE, just connecting isn't a proof that the pairing finished */ + if (!entry) + conn->connect_cfm_cb = pairing_complete_cb; + conn->security_cfm_cb = pairing_complete_cb; conn->disconn_cfm_cb = pairing_complete_cb; conn->io_capability = cp->io_cap; @@ -1689,13 +1678,12 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_block_device *cp; + struct pending_cmd *cmd; + struct mgmt_cp_block_device *cp = (void *) data; int err; BT_DBG("hci%u", index); - cp = (void *) data; - if (len != sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, EINVAL); @@ -1705,6 +1693,14 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, ENODEV); + hci_dev_lock_bh(hdev); + + cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + err = hci_blacklist_add(hdev, &cp->bdaddr); if (err < 0) @@ -1712,6 +1708,11 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, else err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, NULL, 0); + + mgmt_pending_remove(cmd); + +failed: + hci_dev_unlock_bh(hdev); hci_dev_put(hdev); return err; @@ -1721,13 +1722,12 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_unblock_device *cp; + struct pending_cmd *cmd; + struct mgmt_cp_unblock_device *cp = (void *) data; int err; BT_DBG("hci%u", index); - cp = (void *) data; - if (len != sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, EINVAL); @@ -1737,6 +1737,14 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, ENODEV); + hci_dev_lock_bh(hdev); + + cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + err = hci_blacklist_del(hdev, &cp->bdaddr); if (err < 0) @@ -1744,6 +1752,67 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, else err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, NULL, 0); + + mgmt_pending_remove(cmd); + +failed: + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + + return err; +} + +static int set_fast_connectable(struct sock *sk, u16 index, + unsigned char *data, u16 len) +{ + struct hci_dev *hdev; + struct mgmt_cp_set_fast_connectable *cp = (void *) data; + struct hci_cp_write_page_scan_activity acp; + u8 type; + int err; + + BT_DBG("hci%u", index); + + if (len != sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, + EINVAL); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, + ENODEV); + + hci_dev_lock(hdev); + + if (cp->enable) { + type = PAGE_SCAN_TYPE_INTERLACED; + acp.interval = 0x0024; /* 22.5 msec page scan interval */ + } else { + type = PAGE_SCAN_TYPE_STANDARD; /* default */ + acp.interval = 0x0800; /* default 1.28 sec page scan */ + } + + acp.window = 0x0012; /* default 11.25 msec page scan window */ + + err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, + sizeof(acp), &acp); + if (err < 0) { + err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, + -err); + goto done; + } + + err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type); + if (err < 0) { + err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, + -err); + goto done; + } + + err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, + NULL, 0); +done: + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1869,6 +1938,10 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_UNBLOCK_DEVICE: err = unblock_device(sk, index, buf + sizeof(*hdr), len); break; + case MGMT_OP_SET_FAST_CONNECTABLE: + err = set_fast_connectable(sk, index, buf + sizeof(*hdr), + len); + break; default: BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, 0x01); @@ -1977,35 +2050,25 @@ int mgmt_connectable(u16 index, u8 connectable) int mgmt_new_key(u16 index, struct link_key *key, u8 persistent) { - struct mgmt_ev_new_key *ev; - int err, total; - - total = sizeof(struct mgmt_ev_new_key) + key->dlen; - ev = kzalloc(total, GFP_ATOMIC); - if (!ev) - return -ENOMEM; - - bacpy(&ev->key.bdaddr, &key->bdaddr); - ev->key.type = key->type; - memcpy(ev->key.val, key->val, 16); - ev->key.pin_len = key->pin_len; - ev->key.dlen = key->dlen; - ev->store_hint = persistent; + struct mgmt_ev_new_key ev; - memcpy(ev->key.data, key->data, key->dlen); - - err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL); + memset(&ev, 0, sizeof(ev)); - kfree(ev); + ev.store_hint = persistent; + bacpy(&ev.key.bdaddr, &key->bdaddr); + ev.key.type = key->type; + memcpy(ev.key.val, key->val, 16); + ev.key.pin_len = key->pin_len; - return err; + return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL); } -int mgmt_connected(u16 index, bdaddr_t *bdaddr) +int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type) { struct mgmt_ev_connected ev; bacpy(&ev.bdaddr, bdaddr); + ev.link_type = link_type; return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL); } @@ -2260,12 +2323,14 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, memset(&ev, 0, sizeof(ev)); bacpy(&ev.bdaddr, bdaddr); - memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class)); ev.rssi = rssi; if (eir) memcpy(ev.eir, eir, sizeof(ev.eir)); + if (dev_class) + memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class)); + return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL); } @@ -2286,3 +2351,29 @@ int mgmt_discovering(u16 index, u8 discovering) return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering, sizeof(discovering), NULL); } + +int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr) +{ + struct pending_cmd *cmd; + struct mgmt_ev_device_blocked ev; + + cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index); + + bacpy(&ev.bdaddr, bdaddr); + + return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev), + cmd ? cmd->sk : NULL); +} + +int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr) +{ + struct pending_cmd *cmd; + struct mgmt_ev_device_unblocked ev; + + cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index); + + bacpy(&ev.bdaddr, bdaddr); + + return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev), + cmd ? cmd->sk : NULL); +} diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 754b153..2d28dfe 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -409,19 +409,11 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, return err; } - /* After L2sock created, increase refcnt immediately - * It can make connection drop in rfcomm_security_cfm because of refcnt. - */ - rfcomm_session_hold(s); - dlci = __dlci(!s->initiator, channel); /* Check if DLCI already exists */ - if (rfcomm_dlc_get(s, dlci)) { - /* decrement refcnt */ - rfcomm_session_put(s); + if (rfcomm_dlc_get(s, dlci)) return -EBUSY; - } rfcomm_dlc_clear_state(d); @@ -437,9 +429,6 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, d->mtu = s->mtu; d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc; - /* decrement refcnt */ - rfcomm_session_put(s); - if (s->state == BT_CONNECTED) { if (rfcomm_check_security(d)) rfcomm_send_pn(s, 1, d); @@ -475,6 +464,7 @@ 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(); @@ -1173,7 +1163,7 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) /* When socket is closed and we are not RFCOMM * initiator rfcomm_process_rx already calls * rfcomm_session_put() */ - if (s->sock->sk->sk_state != BT_CLOSED && !s->initiator) + if (s->sock->sk->sk_state != BT_CLOSED) if (list_empty(&s->dlcs)) rfcomm_session_put(s); break; @@ -1813,6 +1803,11 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s) continue; } + if (test_bit(RFCOMM_ENC_DROP, &d->flags)) { + __rfcomm_dlc_close(d, ECONNREFUSED); + continue; + } + if (test_and_clear_bit(RFCOMM_AUTH_ACCEPT, &d->flags)) { rfcomm_dlc_clear_timer(d); if (d->out) { @@ -2088,7 +2083,7 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt) if (test_and_clear_bit(RFCOMM_SEC_PENDING, &d->flags)) { rfcomm_dlc_clear_timer(d); if (status || encrypt == 0x00) { - __rfcomm_dlc_close(d, ECONNREFUSED); + set_bit(RFCOMM_ENC_DROP, &d->flags); continue; } } @@ -2099,7 +2094,7 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt) rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); continue; } else if (d->sec_level == BT_SECURITY_HIGH) { - __rfcomm_dlc_close(d, ECONNREFUSED); + set_bit(RFCOMM_ENC_DROP, &d->flags); continue; } } diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 56fcfd1..93a8241 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -42,6 +42,7 @@ #include <linux/device.h> #include <linux/debugfs.h> #include <linux/seq_file.h> +#include <linux/security.h> #include <net/sock.h> #include <asm/system.h> @@ -264,6 +265,8 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent) pi->sec_level = rfcomm_pi(parent)->sec_level; pi->role_switch = rfcomm_pi(parent)->role_switch; + + security_sk_clone(parent, sk); } else { pi->dlc->defer_setup = 0; @@ -483,7 +486,7 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f long timeo; int err = 0; - lock_sock(sk); + lock_sock_nested(sk, SINGLE_DEPTH_NESTING); if (sk->sk_type != SOCK_STREAM) { err = -EINVAL; @@ -520,7 +523,7 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f release_sock(sk); timeo = schedule_timeout(timeo); - lock_sock(sk); + lock_sock_nested(sk, SINGLE_DEPTH_NESTING); } __set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(sk), &wait); @@ -624,7 +627,6 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock, if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) { rfcomm_dlc_accept(d); - msg->msg_namelen = 0; return 0; } @@ -788,7 +790,6 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u break; } - memset(&cinfo, 0, sizeof(cinfo)); cinfo.hci_handle = conn->hcon->handle; memcpy(cinfo.dev_class, conn->hcon->dev_class, 3); @@ -835,6 +836,7 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c } sec.level = rfcomm_pi(sk)->sec_level; + sec.key_size = 0; len = min_t(unsigned int, len, sizeof(sec)); if (copy_to_user(optval, (char *) &sec, len)) @@ -899,7 +901,8 @@ static int rfcomm_sock_shutdown(struct socket *sock, int how) sk->sk_shutdown = SHUTDOWN_MASK; __rfcomm_sock_close(sk); - if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); } release_sock(sk); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index ac4631d..2e80aee 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -41,6 +41,7 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/list.h> +#include <linux/security.h> #include <net/sock.h> #include <asm/system.h> @@ -177,7 +178,6 @@ 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; @@ -193,12 +193,10 @@ 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, pkt_type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING); + hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto done; @@ -381,7 +379,6 @@ static void __sco_sock_close(struct sock *sk) sco_chan_del(sk, ECONNRESET); break; - case BT_CONNECT2: case BT_CONNECT: case BT_DISCONN: sco_chan_del(sk, ECONNRESET); @@ -407,8 +404,10 @@ static void sco_sock_init(struct sock *sk, struct sock *parent) { BT_DBG("sk %p", sk); - if (parent) + if (parent) { sk->sk_type = parent->sk_type; + security_sk_clone(parent, sk); + } } static struct proto sco_proto = { @@ -464,22 +463,18 @@ 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 alen) +static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) { - struct sockaddr_sco sa; + struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; struct sock *sk = sock->sk; - bdaddr_t *src = &sa.sco_bdaddr; - int len, err = 0; + bdaddr_t *src = &sa->sco_bdaddr; + int 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) { @@ -493,8 +488,7 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) err = -EADDRINUSE; } else { /* Save source address */ - bacpy(&bt_sk(sk)->src, &sa.sco_bdaddr); - sco_pi(sk)->pkt_type = sa.sco_pkt_type; + bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr); sk->sk_state = BT_BOUND; } @@ -507,34 +501,27 @@ 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; - struct sockaddr_sco sa; - int len, err = 0; + int err = 0; + BT_DBG("sk %p", sk); - if (!addr || addr->sa_family != AF_BLUETOOTH) + if (alen < sizeof(struct sockaddr_sco) || + 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 && sk->sk_state != BT_BOUND) + return -EBADFD; - if (sk->sk_type != SOCK_SEQPACKET) { - err = -EINVAL; - goto done; - } + if (sk->sk_type != SOCK_SEQPACKET) + return -EINVAL; - if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) { - err = -EBADFD; - goto done; - } + lock_sock(sk); /* Set destination address and psm */ - bacpy(&bt_sk(sk)->dst, &sa.sco_bdaddr); - sco_pi(sk)->pkt_type = sa.sco_pkt_type; + bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr); err = sco_connect(sk); if (err) @@ -641,7 +628,6 @@ 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; } @@ -788,7 +774,8 @@ static int sco_sock_shutdown(struct socket *sock, int how) sco_sock_clear_timer(sk); __sco_sock_close(sk); - if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); } @@ -808,7 +795,8 @@ static int sco_sock_release(struct socket *sock) sco_sock_close(sk); - if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) { + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) { lock_sock(sk); err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); release_sock(sk); @@ -891,11 +879,6 @@ static void sco_conn_ready(struct sco_conn *conn) bacpy(&bt_sk(sk)->src, conn->src); bacpy(&bt_sk(sk)->dst, conn->dst); - if (!conn->hcon) { - BT_ERR("conn->hcon = NULL"); - /* to do */ - } - hci_conn_hold(conn->hcon); __sco_chan_add(conn, sk, parent); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 391888b..9ab60e6 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -30,6 +30,8 @@ #define SMP_TIMEOUT 30000 /* 30 seconds */ +#define AUTH_REQ_MASK 0x07 + static inline void swap128(u8 src[16], u8 dst[16]) { int i; @@ -182,18 +184,9 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) 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; - } + mod_timer(&conn->security_timer, jiffies + + msecs_to_jiffies(SMP_TIMEOUT)); } static void build_pairing_cmd(struct l2cap_conn *conn, @@ -205,7 +198,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, dist_keys = 0; if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) { - dist_keys = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY | SMP_DIST_SIGN; + dist_keys = SMP_DIST_ENC_KEY; authreq |= SMP_AUTH_BONDING; } @@ -215,7 +208,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, req->max_key_size = SMP_MAX_ENC_KEY_SIZE; req->init_key_dist = dist_keys; req->resp_key_dist = dist_keys; - req->auth_req = authreq; + req->auth_req = (authreq & AUTH_REQ_MASK); return; } @@ -224,29 +217,189 @@ static void build_pairing_cmd(struct l2cap_conn *conn, rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE; rsp->init_key_dist = req->init_key_dist & dist_keys; rsp->resp_key_dist = req->resp_key_dist & dist_keys; - rsp->auth_req = authreq; + rsp->auth_req = (authreq & AUTH_REQ_MASK); } static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) { + struct smp_chan *smp = conn->smp_chan; + 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; + smp->smp_key_size = max_key_size; return 0; } +static void confirm_work(struct work_struct *work) +{ + struct smp_chan *smp = container_of(work, struct smp_chan, confirm); + struct l2cap_conn *conn = smp->conn; + struct crypto_blkcipher *tfm; + struct smp_cmd_pairing_confirm cp; + int ret; + u8 res[16], reason; + + BT_DBG("conn %p", conn); + + tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) { + reason = SMP_UNSPECIFIED; + goto error; + } + + smp->tfm = tfm; + + if (conn->hcon->out) + ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, 0, + conn->src, conn->hcon->dst_type, conn->dst, + res); + else + ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, + conn->hcon->dst_type, conn->dst, 0, conn->src, + res); + if (ret) { + reason = SMP_UNSPECIFIED; + goto error; + } + + swap128(res, cp.confirm_val); + smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); + + return; + +error: + smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); + smp_chan_destroy(conn); +} + +static void random_work(struct work_struct *work) +{ + struct smp_chan *smp = container_of(work, struct smp_chan, random); + struct l2cap_conn *conn = smp->conn; + struct hci_conn *hcon = conn->hcon; + struct crypto_blkcipher *tfm = smp->tfm; + u8 reason, confirm[16], res[16], key[16]; + int ret; + + if (IS_ERR_OR_NULL(tfm)) { + reason = SMP_UNSPECIFIED; + goto error; + } + + BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); + + if (hcon->out) + ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, 0, + conn->src, hcon->dst_type, conn->dst, + res); + else + ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, + hcon->dst_type, conn->dst, 0, conn->src, + res); + if (ret) { + reason = SMP_UNSPECIFIED; + goto error; + } + + swap128(res, confirm); + + if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) { + BT_ERR("Pairing failed (confirmation values mismatch)"); + reason = SMP_CONFIRM_FAILED; + goto error; + } + + if (hcon->out) { + u8 stk[16], rand[8]; + __le16 ediv; + + memset(rand, 0, sizeof(rand)); + ediv = 0; + + smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key); + swap128(key, stk); + + memset(stk + smp->smp_key_size, 0, + SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size); + + if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) { + reason = SMP_UNSPECIFIED; + goto error; + } + + hci_le_start_enc(hcon, ediv, rand, stk); + hcon->enc_key_size = smp->smp_key_size; + } else { + u8 stk[16], r[16], rand[8]; + __le16 ediv; + + memset(rand, 0, sizeof(rand)); + ediv = 0; + + swap128(smp->prnd, r); + smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r); + + smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key); + swap128(key, stk); + + memset(stk + smp->smp_key_size, 0, + SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size); + + hci_add_ltk(hcon->hdev, 0, conn->dst, smp->smp_key_size, + ediv, rand, stk); + } + + return; + +error: + smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); + smp_chan_destroy(conn); +} + +static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) +{ + struct smp_chan *smp; + + smp = kzalloc(sizeof(struct smp_chan), GFP_ATOMIC); + if (!smp) + return NULL; + + INIT_WORK(&smp->confirm, confirm_work); + INIT_WORK(&smp->random, random_work); + + smp->conn = conn; + conn->smp_chan = smp; + + hci_conn_hold(conn->hcon); + + return smp; +} + +void smp_chan_destroy(struct l2cap_conn *conn) +{ + kfree(conn->smp_chan); + hci_conn_put(conn->hcon); +} + static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing rsp, *req = (void *) skb->data; + struct smp_chan *smp; u8 key_size; + int ret; BT_DBG("conn %p", conn); - conn->preq[0] = SMP_CMD_PAIRING_REQ; - memcpy(&conn->preq[1], req, sizeof(*req)); + if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend)) + smp = smp_chan_create(conn); + + smp = conn->smp_chan; + + smp->preq[0] = SMP_CMD_PAIRING_REQ; + memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); if (req->oob_flag) @@ -260,32 +413,33 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) return SMP_ENC_KEY_SIZE; /* Just works */ - memset(conn->tk, 0, sizeof(conn->tk)); + memset(smp->tk, 0, sizeof(smp->tk)); + + ret = smp_rand(smp->prnd); + if (ret) + return SMP_UNSPECIFIED; - conn->prsp[0] = SMP_CMD_PAIRING_RSP; - memcpy(&conn->prsp[1], &rsp, sizeof(rsp)); + smp->prsp[0] = SMP_CMD_PAIRING_RSP; + memcpy(&smp->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; + struct smp_chan *smp = conn->smp_chan; + struct hci_dev *hdev = conn->hcon->hdev; + u8 key_size; int ret; - u8 res[16], key_size; BT_DBG("conn %p", conn); skb_pull(skb, sizeof(*rsp)); - req = (void *) &conn->preq[1]; + req = (void *) &smp->preq[1]; key_size = min(req->max_key_size, rsp->max_key_size); if (check_enc_key_size(conn, key_size)) @@ -295,222 +449,154 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) return SMP_OOB_NOT_AVAIL; /* Just works */ - memset(conn->tk, 0, sizeof(conn->tk)); + memset(smp->tk, 0, sizeof(smp->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); + ret = smp_rand(smp->prnd); if (ret) return SMP_UNSPECIFIED; - swap128(res, cp.confirm_val); + smp->prsp[0] = SMP_CMD_PAIRING_RSP; + memcpy(&smp->prsp[1], rsp, sizeof(*rsp)); - smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); + queue_work(hdev->workqueue, &smp->confirm); return 0; } static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) { - struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm; + struct smp_chan *smp = conn->smp_chan; + struct hci_dev *hdev = conn->hcon->hdev; 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)); + memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf)); + skb_pull(skb, sizeof(smp->pcnf)); if (conn->hcon->out) { u8 random[16]; - swap128(conn->prnd, random); + swap128(smp->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); + queue_work(hdev->workqueue, &smp->confirm); } - 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)); - - 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) { - u8 stk[16], rand[8]; - __le16 ediv; + struct smp_chan *smp = conn->smp_chan; + struct hci_dev *hdev = conn->hcon->hdev; - memset(rand, 0, sizeof(rand)); - ediv = 0; + BT_DBG("conn %p", conn); - smp_s1(tfm, conn->tk, random, conn->prnd, key); - swap128(key, stk); + swap128(skb->data, smp->rrnd); + skb_pull(skb, sizeof(smp->rrnd)); - memset(stk + conn->smp_key_size, 0, - SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size); + queue_work(hdev->workqueue, &smp->random); - hci_le_start_enc(hcon, ediv, rand, stk); - hcon->enc_key_size = conn->smp_key_size; - } else { - u8 stk[16], r[16], rand[8]; - __le16 ediv; + return 0; +} - memset(rand, 0, sizeof(rand)); - ediv = 0; +static u8 smp_ltk_encrypt(struct l2cap_conn *conn) +{ + struct link_key *key; + struct key_master_id *master; + struct hci_conn *hcon = conn->hcon; - swap128(conn->prnd, r); - smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r); + key = hci_find_link_key_type(hcon->hdev, conn->dst, + HCI_LK_SMP_LTK); + if (!key) + return 0; - smp_s1(tfm, conn->tk, conn->prnd, random, key); - swap128(key, stk); + if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, + &hcon->pend)) + return 1; - memset(stk + conn->smp_key_size, 0, - SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size); + master = (void *) key->data; + hci_le_start_enc(hcon, master->ediv, master->rand, + key->val); + hcon->enc_key_size = key->pin_len; - hci_add_ltk(conn->hcon->hdev, 0, conn->dst, conn->smp_key_size, - ediv, rand, stk); - } + return 1; - 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; + struct smp_chan *smp; BT_DBG("conn %p", conn); - if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) + hcon->pending_sec_level = BT_SECURITY_MEDIUM; + + if (smp_ltk_encrypt(conn)) + return 0; + + if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) return 0; + smp = smp_chan_create(conn); + skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); build_pairing_cmd(conn, &cp, NULL, rp->auth_req); - conn->preq[0] = SMP_CMD_PAIRING_REQ; - memcpy(&conn->preq[1], &cp, sizeof(cp)); + smp->preq[0] = SMP_CMD_PAIRING_REQ; + memcpy(&smp->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); - 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) +int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) { - struct hci_conn *hcon = conn->hcon; - __u8 authreq; + struct l2cap_conn *conn = hcon->l2cap_data; + struct smp_chan *smp = conn->smp_chan; BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level); if (!lmp_host_le_capable(hcon->hdev)) return 1; - 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; - struct link_key *key; - - key = hci_find_link_key_type(hcon->hdev, conn->dst, - HCI_LK_SMP_LTK); - if (key) { - struct key_master_id *master = (void *) key->data; + if (hcon->link_mode & HCI_LM_MASTER) + if (smp_ltk_encrypt(conn)) + goto done; - hci_le_start_enc(hcon, master->ediv, master->rand, - key->val); - hcon->enc_key_size = key->pin_len; + if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) + return 0; - goto done; - } + smp = smp_chan_create(conn); - build_pairing_cmd(conn, &cp, NULL, authreq); - conn->preq[0] = SMP_CMD_PAIRING_REQ; - memcpy(&conn->preq[1], &cp, sizeof(cp)); + if (hcon->link_mode & HCI_LM_MASTER) { + struct smp_cmd_pairing cp; - mod_timer(&conn->security_timer, jiffies + - msecs_to_jiffies(SMP_TIMEOUT)); + build_pairing_cmd(conn, &cp, NULL, SMP_AUTH_NONE); + smp->preq[0] = SMP_CMD_PAIRING_REQ; + memcpy(&smp->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); } else { struct smp_cmd_security_req cp; - cp.auth_req = authreq; + cp.auth_req = SMP_AUTH_NONE; smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp); } done: hcon->pending_sec_level = sec_level; - set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); return 0; } @@ -518,10 +604,11 @@ done: static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_encrypt_info *rp = (void *) skb->data; + struct smp_chan *smp = conn->smp_chan; skb_pull(skb, sizeof(*rp)); - memcpy(conn->tk, rp->ltk, sizeof(conn->tk)); + memcpy(smp->tk, rp->ltk, sizeof(smp->tk)); return 0; } @@ -529,11 +616,12 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_master_ident *rp = (void *) skb->data; + struct smp_chan *smp = conn->smp_chan; skb_pull(skb, sizeof(*rp)); - hci_add_ltk(conn->hcon->hdev, 1, conn->src, conn->smp_key_size, - rp->ediv, rp->rand, conn->tk); + hci_add_ltk(conn->hcon->hdev, 1, conn->src, smp->smp_key_size, + rp->ediv, rp->rand, smp->tk); smp_distribute_keys(conn, 1); @@ -552,14 +640,21 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) goto done; } - 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)); + /* + * The SMP context must be initialized for all other PDUs except + * pairing and security requests. If we get any other PDU when + * not initialized simply disconnect (done if this function + * returns an error). + */ + if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ && + !conn->smp_chan) { + BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code); + kfree_skb(skb); + return -ENOTSUPP; + } + switch (code) { case SMP_CMD_PAIRING_REQ: reason = smp_cmd_pairing_req(conn, skb); @@ -621,20 +716,21 @@ done: int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) { struct smp_cmd_pairing *req, *rsp; + struct smp_chan *smp = conn->smp_chan; __u8 *keydist; BT_DBG("conn %p force %d", conn, force); - if (IS_ERR(conn->hcon->hdev->tfm)) - return PTR_ERR(conn->hcon->hdev->tfm); + if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend)) + return 0; - rsp = (void *) &conn->prsp[1]; + rsp = (void *) &smp->prsp[1]; /* The responder sends its keys first */ if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07)) return 0; - req = (void *) &conn->preq[1]; + req = (void *) &smp->preq[1]; if (conn->hcon->out) { keydist = &rsp->init_key_dist; @@ -658,7 +754,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); - hci_add_ltk(conn->hcon->hdev, 1, conn->dst, conn->smp_key_size, + hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size, ediv, ident.rand, enc.ltk); ident.ediv = cpu_to_le16(ediv); @@ -698,5 +794,11 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) *keydist &= ~SMP_DIST_SIGN; } + if (conn->hcon->out || force) { + clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend); + del_timer(&conn->security_timer); + smp_chan_destroy(conn); + } + return 0; } |