From a8746417e864da1ed36dd2432a399fbeb843c2a0 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 14 Jul 2008 20:13:46 +0200 Subject: [Bluetooth] Track connection packet type changes The connection packet type can be changed after the connection has been established and thus needs to be properly tracked to ensure that the host stack has always correct and valid information about it. On incoming connections the Bluetooth core switches the supported packet types to the configured list for this controller. However the usefulness of this feature has been questioned a lot. The general consent is that every Bluetooth host stack should enable as many packet types as the hardware actually supports and leave the decision to the link manager software running on the Bluetooth chip. When running on Bluetooth 2.0 or later hardware, don't change the packet type for incoming connections anymore. This hardware likely supports Enhanced Data Rate and thus leave it completely up to the link manager to pick the best packet type. Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) (limited to 'net/bluetooth/hci_conn.c') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index f8880261da0e..69c64ce054fb 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -59,7 +59,8 @@ void hci_acl_connect(struct hci_conn *conn) BT_DBG("%p", conn); conn->state = BT_CONNECT; - conn->out = 1; + conn->out = 1; + conn->link_mode = HCI_LM_MASTER; conn->attempt++; @@ -76,7 +77,7 @@ void hci_acl_connect(struct hci_conn *conn) memcpy(conn->dev_class, ie->data.dev_class, 3); } - cp.pkt_type = cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK); + cp.pkt_type = cpu_to_le16(conn->pkt_type); if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER)) cp.role_switch = 0x01; else @@ -122,7 +123,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle) conn->out = 1; cp.handle = cpu_to_le16(handle); - cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); + cp.pkt_type = cpu_to_le16(conn->pkt_type); hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp); } @@ -138,7 +139,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle) conn->out = 1; cp.handle = cpu_to_le16(handle); - cp.pkt_type = cpu_to_le16(hdev->esco_type); + cp.pkt_type = cpu_to_le16(conn->pkt_type); cp.tx_bandwidth = cpu_to_le32(0x00001f40); cp.rx_bandwidth = cpu_to_le32(0x00001f40); @@ -199,13 +200,28 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) return NULL; bacpy(&conn->dst, dst); - conn->hdev = hdev; - conn->type = type; - conn->mode = HCI_CM_ACTIVE; - conn->state = BT_OPEN; + conn->hdev = hdev; + conn->type = type; + conn->mode = HCI_CM_ACTIVE; + conn->state = BT_OPEN; conn->power_save = 1; + switch (type) { + case ACL_LINK: + conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; + break; + case SCO_LINK: + if (lmp_esco_capable(hdev)) + conn->pkt_type = hdev->esco_type & SCO_ESCO_MASK; + else + conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK; + break; + case ESCO_LINK: + conn->pkt_type = hdev->esco_type; + break; + } + skb_queue_head_init(&conn->data_q); setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn); -- cgit v1.2.2 From e4e8e37c42bdaaefcb84eeaef0dc1bc3f696f8f6 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 14 Jul 2008 20:13:47 +0200 Subject: [Bluetooth] Make use of the default link policy settings The Bluetooth specification supports the default link policy settings on a per host controller basis. For every new connection the link manager would then use these settings. It is better to use this instead of bothering the controller on every connection setup to overwrite the default settings. Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/bluetooth/hci_conn.c') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 69c64ce054fb..6175ce841e9e 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -65,6 +65,8 @@ void hci_acl_connect(struct hci_conn *conn) conn->attempt++; + conn->link_policy = hdev->link_policy; + memset(&cp, 0, sizeof(cp)); bacpy(&cp.bdaddr, &conn->dst); cp.pscan_rep_mode = 0x02; -- cgit v1.2.2 From 41a96212b3b7b3cd59e8e8d33e6dabf0e21d9778 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 14 Jul 2008 20:13:48 +0200 Subject: [Bluetooth] Track status of remote Simple Pairing mode The Simple Pairing process can only be used if both sides have the support enabled in the host stack. The current Bluetooth specification has three ways to detect this support. If an Extended Inquiry Result has been sent during inquiry then it is safe to assume that Simple Pairing is enabled. It is not allowed to enable Extended Inquiry without Simple Pairing. During the remote name request phase a notification with the remote host supported features will be sent to indicate Simple Pairing support. Also the second page of the remote extended features can indicate support for Simple Pairing. For all three cases the value of remote Simple Pairing mode is stored in the inquiry cache for later use. Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'net/bluetooth/hci_conn.c') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 6175ce841e9e..41351ba692e9 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -71,12 +71,16 @@ void hci_acl_connect(struct hci_conn *conn) bacpy(&cp.bdaddr, &conn->dst); cp.pscan_rep_mode = 0x02; - if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst)) && - inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { - cp.pscan_rep_mode = ie->data.pscan_rep_mode; - cp.pscan_mode = ie->data.pscan_mode; - cp.clock_offset = ie->data.clock_offset | cpu_to_le16(0x8000); + if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst))) { + if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { + cp.pscan_rep_mode = ie->data.pscan_rep_mode; + cp.pscan_mode = ie->data.pscan_mode; + cp.clock_offset = ie->data.clock_offset | + cpu_to_le16(0x8000); + } + memcpy(conn->dev_class, ie->data.dev_class, 3); + conn->ssp_mode = ie->data.ssp_mode; } cp.pkt_type = cpu_to_le16(conn->pkt_type); -- cgit v1.2.2 From 769be974d0c7b4fe1a52f9cdaad22259b60953f7 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 14 Jul 2008 20:13:49 +0200 Subject: [Bluetooth] Use ACL config stage to retrieve remote features The Bluetooth technology introduces new features on a regular basis and for some of them it is important that the hardware on both sides support them. For features like Simple Pairing it is important that the host stacks on both sides have switched this feature on. To make valid decisions, a config stage during ACL link establishment has been introduced that retrieves remote features and if needed also the remote extended features (known as remote host features) before signalling this link as connected. This change introduces full reference counting of incoming and outgoing ACL links and the Bluetooth core will disconnect both if no owner of it is present. To better handle interoperability during the pairing phase the disconnect timeout for incoming connections has been increased to 10 seconds. This is five times more than for outgoing connections. Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/bluetooth/hci_conn.c') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 41351ba692e9..6f22533e7656 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -170,11 +170,13 @@ static void hci_conn_timeout(unsigned long arg) switch (conn->state) { case BT_CONNECT: + case BT_CONNECT2: if (conn->type == ACL_LINK) hci_acl_connect_cancel(conn); else hci_acl_disconn(conn, 0x13); break; + case BT_CONFIG: case BT_CONNECTED: hci_acl_disconn(conn, 0x13); break; -- cgit v1.2.2 From 40be492fe4fab829951681860c2bb26fa1d5fe4a Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 14 Jul 2008 20:13:50 +0200 Subject: [Bluetooth] Export details about authentication requirements With the Simple Pairing support, the authentication requirements are an explicit setting during the bonding process. Track and enforce the requirements and allow higher layers like L2CAP and RFCOMM to increase them if needed. This patch introduces a new IOCTL that allows to query the current authentication requirements. It is also possible to detect Simple Pairing support in the kernel this way. Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) (limited to 'net/bluetooth/hci_conn.c') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 6f22533e7656..0d4b8aeb8e09 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -379,13 +379,21 @@ int hci_conn_auth(struct hci_conn *conn) { BT_DBG("conn %p", conn); + if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0) { + if (!(conn->auth_type & 0x01)) { + conn->auth_type = HCI_AT_GENERAL_BONDING_MITM; + conn->link_mode &= ~HCI_LM_AUTH; + } + } + if (conn->link_mode & HCI_LM_AUTH) return 1; if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { struct hci_cp_auth_requested cp; cp.handle = cpu_to_le16(conn->handle); - hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); + hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, + sizeof(cp), &cp); } return 0; } @@ -397,7 +405,7 @@ int hci_conn_encrypt(struct hci_conn *conn) BT_DBG("conn %p", conn); if (conn->link_mode & HCI_LM_ENCRYPT) - return 1; + return hci_conn_auth(conn); if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) return 0; @@ -406,7 +414,8 @@ int hci_conn_encrypt(struct hci_conn *conn) struct hci_cp_set_conn_encrypt cp; cp.handle = cpu_to_le16(conn->handle); cp.encrypt = 1; - hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp); + hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, + sizeof(cp), &cp); } return 0; } @@ -420,7 +429,8 @@ int hci_conn_change_link_key(struct hci_conn *conn) if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { struct hci_cp_change_conn_link_key cp; cp.handle = cpu_to_le16(conn->handle); - hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp); + hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, + sizeof(cp), &cp); } return 0; } @@ -624,3 +634,23 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg) return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0; } + +int hci_get_auth_info(struct hci_dev *hdev, void __user *arg) +{ + struct hci_auth_info_req req; + struct hci_conn *conn; + + if (copy_from_user(&req, arg, sizeof(req))) + return -EFAULT; + + hci_dev_lock_bh(hdev); + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr); + if (conn) + req.type = conn->auth_type; + hci_dev_unlock_bh(hdev); + + if (!conn) + return -ENOENT; + + return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0; +} -- cgit v1.2.2 From 7d0db0a373195385a2e0b19d1f5e4b186fdcffac Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 14 Jul 2008 20:13:51 +0200 Subject: [Bluetooth] Use a more unique bus name for connections When attaching Bluetooth low-level connections to the bus, the bus name is constructed from the remote address since at that time the connection handle is not assigned yet. This has worked so far, but also caused a lot of troubles. It is better to postpone the creation of the sysfs entry to the time when the connection actually has been established and then use its connection handle as unique identifier. This also fixes the case where two different adapters try to connect to the same remote device. Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'net/bluetooth/hci_conn.c') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 0d4b8aeb8e09..ca8d05245ca0 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -245,8 +245,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); - hci_conn_add_sysfs(conn); - tasklet_enable(&hdev->tx_task); return conn; @@ -278,12 +276,14 @@ int hci_conn_del(struct hci_conn *conn) } tasklet_disable(&hdev->tx_task); + hci_conn_hash_del(hdev, conn); if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); + tasklet_enable(&hdev->tx_task); + skb_queue_purge(&conn->data_q); - hci_conn_del_sysfs(conn); return 0; } @@ -532,6 +532,8 @@ void hci_conn_hash_flush(struct hci_dev *hdev) c->state = BT_CLOSED; + hci_conn_del_sysfs(c); + hci_proto_disconn_ind(c, 0x16); hci_conn_del(c); } -- cgit v1.2.2